159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/* 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2012 jMonkeyEngine 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved. 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met: 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer. 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer in the 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * documentation and/or other materials provided with the distribution. 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * may be used to endorse or promote products derived from this software 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * without specific prior written permission. 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.terrain.geomipmap; 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingBox; 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingSphere; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingVolume; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.Collidable; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.CollisionResults; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.UnsupportedCollisionException; 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.InputCapsule; 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.JmeExporter; 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.JmeImporter; 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.OutputCapsule; 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.*; 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Geometry; 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Mesh; 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer; 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type; 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.terrain.geomipmap.TerrainQuad.LocationHeight; 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.terrain.geomipmap.lodcalc.util.EntropyComputeUtil; 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils; 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException; 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer; 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.IntBuffer; 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.HashMap; 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List; 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * A terrain patch is a leaf in the terrain quad tree. It has a mesh that can change levels of detail (LOD) 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * whenever the view point, or camera, changes. The actual terrain mesh is created by the LODGeomap class. 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * That uses a geo-mipmapping algorithm to change the index buffer of the mesh. 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The mesh is a triangle strip. In wireframe mode you might notice some strange lines, these are degenerate 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * triangles generated by the geoMipMap algorithm and can be ignored. The video card removes them at almost no cost. 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Each patch needs to know its neighbour's LOD so it can seam its edges with them, in case the neighbour has a different 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LOD. If this doesn't happen, you will see gaps. 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The LOD value is most detailed at zero. It gets less detailed the higher the LOD value until you reach maxLod, which 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * is a mathematical limit on the number of times the 'size' of the patch can be divided by two. However there is a -1 to that 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * for now until I add in a custom index buffer calculation for that max level, the current algorithm does not go that far. 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * You can supply a LodThresholdCalculator for use in determining when the LOD should change. It's API will no doubt change 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * in the near future. Right now it defaults to just changing LOD every two patch sizes. So if a patch has a size of 65, 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * then the LOD changes every 130 units away. 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Brent Owens 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class TerrainPatch extends Geometry { 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected LODGeomap geomap; 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int lod = -1; // this terrain patch's LOD 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int maxLod = -1; 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int previousLod = -1; 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int lodLeft, lodTop, lodRight, lodBottom; // it's neighbour's LODs 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int size; 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int totalSize; 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected short quadrant = 1; 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // x/z step 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected Vector3f stepScale; 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // center of the patch in relation to (0,0,0) 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected Vector2f offset; 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // amount the patch has been shifted. 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected float offsetAmount; 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //protected LodCalculator lodCalculator; 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //protected LodCalculatorFactory lodCalculatorFactory; 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected TerrainPatch leftNeighbour, topNeighbour, rightNeighbour, bottomNeighbour; 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected boolean searchedForNeighboursAlready = false; 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected float[] lodEntropy; 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TerrainPatch() { 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super("TerrainPatch"); 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TerrainPatch(String name) { 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super(name); 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TerrainPatch(String name, int size) { 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this(name, size, new Vector3f(1,1,1), null, new Vector3f(0,0,0)); 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Constructor instantiates a new <code>TerrainPatch</code> object. The 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * parameters and heightmap data are then processed to generate a 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>TriMesh</code> object for rendering. 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param name 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the name of the terrain patch. 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param size 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the size of the heightmap. 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param stepScale 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the scale for the axes. 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param heightMap 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the height data. 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param origin 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the origin offset of the patch. 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TerrainPatch(String name, int size, Vector3f stepScale, 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] heightMap, Vector3f origin) { 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this(name, size, stepScale, heightMap, origin, size, new Vector2f(), 0); 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Constructor instantiates a new <code>TerrainPatch</code> object. The 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * parameters and heightmap data are then processed to generate a 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>TriMesh</code> object for renderering. 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param name 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the name of the terrain patch. 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param size 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the size of the patch. 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param stepScale 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the scale for the axes. 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param heightMap 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the height data. 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param origin 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the origin offset of the patch. 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the total size of the terrain. (Higher if the patch is part of 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * a <code>TerrainQuad</code> tree. 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offset 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the offset for texture coordinates. 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offsetAmount 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the total offset amount. Used for texture coordinates. 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TerrainPatch(String name, int size, Vector3f stepScale, 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] heightMap, Vector3f origin, int totalSize, 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector2f offset, float offsetAmount) { 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super(name); 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.size = size; 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.stepScale = stepScale; 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.totalSize = totalSize; 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.offsetAmount = offsetAmount; 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.offset = offset; 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta setLocalTranslation(origin); 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geomap = new LODGeomap(size, heightMap); 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh m = geomap.createMesh(stepScale, new Vector2f(1,1), offset, offsetAmount, totalSize, false); 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta setMesh(m); 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This calculation is slow, so don't use it often. 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void generateLodEntropies() { 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] entropies = new float[getMaxLod()+1]; 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i <= getMaxLod(); i++){ 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int curLod = (int) Math.pow(2, i); 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta IntBuffer buf = geomap.writeIndexArrayLodDiff(null, curLod, false, false, false, false); 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta entropies[i] = EntropyComputeUtil.computeLodEntropy(mesh, buf); 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta lodEntropy = entropies; 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float[] getLodEntropies(){ 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (lodEntropy == null){ 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta generateLodEntropies(); 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return lodEntropy; 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Deprecated 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public FloatBuffer getHeightmap() { 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return BufferUtils.createFloatBuffer(geomap.getHeightArray()); 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float[] getHeightMap() { 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return geomap.getHeightArray(); 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The maximum lod supported by this terrain patch. 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * If the patch size is 32 then the returned value would be log2(32)-2 = 3 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * You can then use that value, 3, to see how many times you can divide 32 by 2 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * before the terrain gets too un-detailed (can't stitch it any further). 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getMaxLod() { 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (maxLod < 0) 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta maxLod = Math.max(1, (int) (FastMath.log(size-1)/FastMath.log(2)) -1); // -1 forces our minimum of 4 triangles wide 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return maxLod; 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void reIndexGeometry(HashMap<String,UpdatedTerrainPatch> updated, boolean useVariableLod) { 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta UpdatedTerrainPatch utp = updated.get(getName()); 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (utp != null && (utp.isReIndexNeeded() || utp.isFixEdges()) ) { 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int pow = (int) Math.pow(2, utp.getNewLod()); 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean left = utp.getLeftLod() > utp.getNewLod(); 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean top = utp.getTopLod() > utp.getNewLod(); 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean right = utp.getRightLod() > utp.getNewLod(); 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean bottom = utp.getBottomLod() > utp.getNewLod(); 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta IntBuffer ib = null; 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (useVariableLod) 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ib = geomap.writeIndexArrayLodVariable(null, pow, (int) Math.pow(2, utp.getRightLod()), (int) Math.pow(2, utp.getTopLod()), (int) Math.pow(2, utp.getLeftLod()), (int) Math.pow(2, utp.getBottomLod())); 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta else 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ib = geomap.writeIndexArrayLodDiff(null, pow, right, top, left, bottom); 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta utp.setNewIndexBuffer(ib); 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Vector2f getTex(float x, float z, Vector2f store) { 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x < 0 || z < 0 || x >= size || z >= size) { 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta store.set(Vector2f.ZERO); 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return store; 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idx = (int) (z * size + x); 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return store.set(getMesh().getFloatBuffer(Type.TexCoord).get(idx*2), 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().getFloatBuffer(Type.TexCoord).get(idx*2+1) ); 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float getHeightmapHeight(float x, float z) { 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x < 0 || z < 0 || x >= size || z >= size) 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idx = (int) (z * size + x); 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return getMesh().getFloatBuffer(Type.Position).get(idx*3+1); // 3 floats per entry (x,y,z), the +1 is to get the Y 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Get the triangle of this geometry at the specified local coordinate. 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param x local to the terrain patch 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param z local to the terrain patch 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the triangle in world coordinates, or null if the point does intersect this patch on the XZ axis 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Triangle getTriangle(float x, float z) { 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return geomap.getTriangleAtPoint(x, z, getWorldScale() , getWorldTranslation()); 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Get the triangles at the specified grid point. Probably only 2 triangles 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param x local to the terrain patch 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param z local to the terrain patch 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the triangles in world coordinates, or null if the point does intersect this patch on the XZ axis 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Triangle[] getGridTriangles(float x, float z) { 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return geomap.getGridTrianglesAtPoint(x, z, getWorldScale() , getWorldTranslation()); 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void setHeight(List<LocationHeight> locationHeights, boolean overrideHeight) { 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (LocationHeight lh : locationHeights) { 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size) 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idx = lh.z * size + lh.x; 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (overrideHeight) { 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geomap.getHeightArray()[idx] = lh.h; 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float h = getMesh().getFloatBuffer(Type.Position).get(idx*3+1); 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geomap.getHeightArray()[idx] = h+lh.h; 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false); 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().clearBuffer(Type.Position); 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().setBuffer(Type.Position, 3, newVertexBuffer); 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * recalculate all of the normal vectors in this terrain patch 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void updateNormals() { 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer newNormalBuffer = geomap.writeNormalArray(null, getWorldScale()); 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().getBuffer(Type.Normal).updateData(newNormalBuffer); 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer newTangentBuffer = null; 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer newBinormalBuffer = null; 317a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta FloatBuffer[] tb = geomap.writeTangentArray(newNormalBuffer, newTangentBuffer, newBinormalBuffer, (FloatBuffer)getMesh().getBuffer(Type.TexCoord).getData(), getWorldScale()); 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta newTangentBuffer = tb[0]; 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta newBinormalBuffer = tb[1]; 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().getBuffer(Type.Tangent).updateData(newTangentBuffer); 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().getBuffer(Type.Binormal).updateData(newBinormalBuffer); 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 324a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta private void setInBuffer(Mesh mesh, int index, Vector3f normal, Vector3f tangent, Vector3f binormal) { 325a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta VertexBuffer NB = mesh.getBuffer(Type.Normal); 326a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta VertexBuffer TB = mesh.getBuffer(Type.Tangent); 327a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta VertexBuffer BB = mesh.getBuffer(Type.Binormal); 328a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta BufferUtils.setInBuffer(normal, (FloatBuffer)NB.getData(), index); 329a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta BufferUtils.setInBuffer(tangent, (FloatBuffer)TB.getData(), index); 330a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta BufferUtils.setInBuffer(binormal, (FloatBuffer)BB.getData(), index); 331a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta NB.setUpdateNeeded(); 332a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta TB.setUpdateNeeded(); 333a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta BB.setUpdateNeeded(); 334a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta } 335a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Matches the normals along the edge of the patch with the neighbours. 33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Computes the normals for the right, bottom, left, and top edges of the 33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * patch, and saves those normals in the neighbour's edges too. 34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Takes 4 points (if has neighbour on that side) for each 34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * point on the edge of the patch: 34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * 34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * | 34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * *---x---* 34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * | 34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * 34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * It works across the right side of the patch, from the top down to 34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the bottom. Then it works on the bottom side of the patch, from the 35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * left to the right. 35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void fixNormalEdges(TerrainPatch right, 35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch bottom, 35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch top, 35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch left, 35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch bottomRight, 35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch bottomLeft, 35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch topRight, 35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch topLeft) 36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta { 36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f rootPoint = new Vector3f(); 36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f rightPoint = new Vector3f(); 36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f leftPoint = new Vector3f(); 36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f topPoint = new Vector3f(); 36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f bottomPoint = new Vector3f(); 36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f tangent = new Vector3f(); 36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f binormal = new Vector3f(); 37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f normal = new Vector3f(); 37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 372a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int s = this.getSize()-1; 37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (right != null) { // right side, works its way down 37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i=0; i<s+1; i++) { 377a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rootPoint.set(0, this.getHeightmapHeight(s,i), 0); 378a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta leftPoint.set(-1, this.getHeightmapHeight(s-1,i), 0); 379a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rightPoint.set(1, right.getHeightmapHeight(1,i), 0); 38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i == 0) { // top point 382a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1); 383a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (top == null) { 385a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 386a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), s, normal, tangent, binormal); 387a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(right.getMesh(), 0, normal, tangent, binormal); 38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 389a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, top.getHeightmapHeight(s,s-1), -1); 39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 391a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint,normal, tangent, binormal); 392a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), s, normal, tangent, binormal); 393a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(right.getMesh(), 0, normal, tangent, binormal); 394a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(top.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal); 39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (topRight != null) { 397a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta // setInBuffer(topRight.getMesh(), (s+1)*s, normal, tangent, binormal); 39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (i == s) { // bottom point 401a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, this.getHeightmapHeight(s,s-1), -1); 402a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bottom == null) { 404a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal); 405a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal); 406a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(right.getMesh(), (s+1)*(s), normal, tangent, binormal); 40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 408a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, bottom.getHeightmapHeight(s,1), 1); 409a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 410a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal); 411a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(right.getMesh(), (s+1)*s, normal, tangent, binormal); 412a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(bottom.getMesh(), s, normal, tangent, binormal); 41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bottomRight != null) { 415a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta // setInBuffer(bottomRight.getMesh(), 0, normal, tangent, binormal); 41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { // all in the middle 419a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, this.getHeightmapHeight(s,i-1), -1); 420a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1); 421a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 422a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal); 423a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(right.getMesh(), (s+1)*(i), normal, tangent, binormal); 42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (left != null) { // left side, works its way down 42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i=0; i<s+1; i++) { 430a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rootPoint.set(0, this.getHeightmapHeight(0,i), 0); 431a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta leftPoint.set(-1, left.getHeightmapHeight(s-1,i), 0); 432a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rightPoint.set(1, this.getHeightmapHeight(1,i), 0); 43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i == 0) { // top point 435a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1); 436a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (top == null) { 438a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 439a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), 0, normal, tangent, binormal); 440a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(left.getMesh(), s, normal, tangent, binormal); 44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 442a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, top.getHeightmapHeight(0,s-1), -1); 44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 444a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 445a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), 0, normal, tangent, binormal); 446a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(left.getMesh(), s, normal, tangent, binormal); 447a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(top.getMesh(), (s+1)*s, normal, tangent, binormal); 44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (topLeft != null) { 450a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta // setInBuffer(topLeft.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal); 45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (i == s) { // bottom point 454a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, this.getHeightmapHeight(0,i-1), -1); 455a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bottom == null) { 457a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal); 458a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal); 459a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal); 46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 461a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, bottom.getHeightmapHeight(0,1), 1); 46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 463a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 464a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal); 465a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal); 466a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(bottom.getMesh(), 0, normal, tangent, binormal); 46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bottomLeft != null) { 469a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta // setInBuffer(bottomLeft.getMesh(), s, normal, tangent, binormal); 47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { // all in the middle 473a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, this.getHeightmapHeight(0,i-1), -1); 474a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1); 47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 476a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 477a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(i), normal, tangent, binormal); 478a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(left.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal); 47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 482a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (top != null) { // top side, works its way right 48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i=0; i<s+1; i++) { 485a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rootPoint.set(0, this.getHeightmapHeight(i,0), 0); 486a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, top.getHeightmapHeight(i,s-1), -1); 487a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, this.getHeightmapHeight(i,1), 1); 48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i == 0) { // left corner 49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // handled by left side pass 49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (i == s) { // right corner 49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // handled by this patch when it does its right side 49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { // all in the middle 497a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta leftPoint.set(-1, this.getHeightmapHeight(i-1,0), 0); 498a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rightPoint.set(1, this.getHeightmapHeight(i+1,0), 0); 499a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 500a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), i, normal, tangent, binormal); 501a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(top.getMesh(), (s+1)*(s)+i, normal, tangent, binormal); 50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bottom != null) { // bottom side, works its way right 50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i=0; i<s+1; i++) { 509a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rootPoint.set(0, this.getHeightmapHeight(i,s), 0); 510a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta topPoint.set(0, this.getHeightmapHeight(i,s-1), -1); 511a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta bottomPoint.set(0, bottom.getHeightmapHeight(i,1), 1); 51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i == 0) { // left 51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // handled by the left side pass 51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (i == s) { // right 51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 518a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta // handled by the right side pass 51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { // all in the middle 521a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta leftPoint.set(-1, this.getHeightmapHeight(i-1,s), 0); 522a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta rightPoint.set(1, this.getHeightmapHeight(i+1,s), 0); 523a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal); 524a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(this.getMesh(), (s+1)*(s)+i, normal, tangent, binormal); 525a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta setInBuffer(bottom.getMesh(), i, normal, tangent, binormal); 52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void averageNormalsTangents( 53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f topPoint, 53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f rootPoint, 53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f leftPoint, 53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f bottomPoint, 53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f rightPoint, 53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f normal, 53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f tangent, 54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f binormal) 54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta { 54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f scale = getWorldScale(); 54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 544a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta Vector3f n1 = new Vector3f(0,0,0); 54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (topPoint != null && leftPoint != null) { 546a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta n1.set(calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale))); 54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 548a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta Vector3f n2 = new Vector3f(0,0,0); 54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (leftPoint != null && bottomPoint != null) { 550a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta n2.set(calculateNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale))); 55159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 552a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta Vector3f n3 = new Vector3f(0,0,0); 55359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (rightPoint != null && bottomPoint != null) { 554a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta n3.set(calculateNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale))); 55559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 556a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta Vector3f n4 = new Vector3f(0,0,0); 55759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (rightPoint != null && topPoint != null) { 558a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta n4.set(calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale))); 55959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 561a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta //if (bottomPoint != null && rightPoint != null && rootTex != null && rightTex != null && bottomTex != null) 562a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta // LODGeomap.calculateTangent(new Vector3f[]{rootPoint.mult(scale),rightPoint.mult(scale),bottomPoint.mult(scale)}, new Vector2f[]{rootTex,rightTex,bottomTex}, tangent, binormal); 56359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 564a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta normal.set(n1.add(n2).add(n3).add(n4).normalize()); 565a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta 566a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta tangent.set(normal.cross(new Vector3f(0,0,1)).normalize()); 567a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta binormal.set(new Vector3f(1,0,0).cross(normal).normalize()); 56859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 57059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Vector3f calculateNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) { 57159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f normal = new Vector3f(); 57259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normal.set(firstPoint).subtractLocal(rootPoint) 57359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta .crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal(); 57459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return normal; 57559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 57659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 57759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected Vector3f getMeshNormal(int x, int z) { 57859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x >= size || z >= size) 57959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; // out of range 58059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int index = (z*size+x)*3; 58259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer nb = (FloatBuffer)this.getMesh().getBuffer(Type.Normal).getData(); 58359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f normal = new Vector3f(); 58459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normal.x = nb.get(index); 58559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normal.y = nb.get(index+1); 58659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normal.z = nb.get(index+2); 58759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return normal; 58859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 58959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 59059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 59159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Locks the mesh (sets it static) to improve performance. 59259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * But it it not editable then. Set unlock to make it editable. 59359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 59459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void lockMesh() { 59559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().setStatic(); 59659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 59759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 59859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 59959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Unlocks the mesh (sets it dynamic) to make it editable. 60059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * It will be editable but performance will be reduced. 60159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Call lockMesh to improve performance. 60259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 60359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void unlockMesh() { 60459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta getMesh().setDynamic(); 60559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 60659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 60759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 60859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Returns the offset amount this terrain patch uses for textures. 60959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 61059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The current offset amount. 61159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 61259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float getOffsetAmount() { 61359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return offsetAmount; 61459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 61559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 61659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 61759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Returns the step scale that stretches the height map. 61859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 61959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The current step scale. 62059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 62159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Vector3f getStepScale() { 62259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return stepScale; 62359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 62459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 62559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 62659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Returns the total size of the terrain. 62759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 62859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The terrain's total size. 62959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 63059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getTotalSize() { 63159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return totalSize; 63259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 63359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 63459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 63559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Returns the size of this terrain patch. 63659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 63759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The current patch size. 63859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 63959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getSize() { 64059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return size; 64159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 64259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 64359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 64459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Returns the current offset amount. This is used when building texture 64559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * coordinates. 64659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 64759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The current offset amount. 64859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 64959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Vector2f getOffset() { 65059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return offset; 65159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 65259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 65359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 65459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Sets the value for the current offset amount to use when building texture 65559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * coordinates. Note that this does <b>NOT </b> rebuild the terrain at all. 65659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This is mostly used for outside constructors of terrain patches. 65759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 65859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offset 65959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The new texture offset. 66059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 66159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setOffset(Vector2f offset) { 66259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.offset = offset; 66359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 66559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 66659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Sets the size of this terrain patch. Note that this does <b>NOT </b> 66759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * rebuild the terrain at all. This is mostly used for outside constructors 66859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * of terrain patches. 66959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 67059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param size 67159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The new size. 67259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 67359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setSize(int size) { 67459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.size = size; 67559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 67659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta maxLod = -1; // reset it 67759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 67859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 67959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 68059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Sets the total size of the terrain . Note that this does <b>NOT </b> 68159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * rebuild the terrain at all. This is mostly used for outside constructors 68259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * of terrain patches. 68359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 68459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize 68559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The new total size. 68659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 68759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setTotalSize(int totalSize) { 68859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.totalSize = totalSize; 68959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 69059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 69159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 69259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Sets the step scale of this terrain patch's height map. Note that this 69359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * does <b>NOT </b> rebuild the terrain at all. This is mostly used for 69459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * outside constructors of terrain patches. 69559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 69659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param stepScale 69759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The new step scale. 69859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 69959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setStepScale(Vector3f stepScale) { 70059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.stepScale = stepScale; 70159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 70259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 70359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 70459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Sets the offset of this terrain texture map. Note that this does <b>NOT 70559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * </b> rebuild the terrain at all. This is mostly used for outside 70659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * constructors of terrain patches. 70759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 70859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offsetAmount 70959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The new texture offset. 71059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 71159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setOffsetAmount(float offsetAmount) { 71259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.offsetAmount = offsetAmount; 71359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 71459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 71559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 71659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return Returns the quadrant. 71759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 71859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public short getQuadrant() { 71959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return quadrant; 72059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 72159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 72259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 72359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param quadrant 72459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The quadrant to set. 72559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 72659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setQuadrant(short quadrant) { 72759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.quadrant = quadrant; 72859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 72959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 73059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getLod() { 73159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return lod; 73259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 73359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 73459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setLod(int lod) { 73559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.lod = lod; 73659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 73759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 73859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getPreviousLod() { 73959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return previousLod; 74059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 74159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 74259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setPreviousLod(int previousLod) { 74359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.previousLod = previousLod; 74459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 74559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 74659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int getLodLeft() { 74759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return lodLeft; 74859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 74959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 75059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void setLodLeft(int lodLeft) { 75159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.lodLeft = lodLeft; 75259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 75359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 75459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int getLodTop() { 75559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return lodTop; 75659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 75759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 75859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void setLodTop(int lodTop) { 75959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.lodTop = lodTop; 76059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 76159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 76259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int getLodRight() { 76359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return lodRight; 76459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 76559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 76659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void setLodRight(int lodRight) { 76759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.lodRight = lodRight; 76859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 76959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 77059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int getLodBottom() { 77159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return lodBottom; 77259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 77359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 77459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void setLodBottom(int lodBottom) { 77559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.lodBottom = lodBottom; 77659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 77759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 77859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /*public void setLodCalculator(LodCalculatorFactory lodCalculatorFactory) { 77959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.lodCalculatorFactory = lodCalculatorFactory; 78059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta setLodCalculator(lodCalculatorFactory.createCalculator(this)); 78159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }*/ 78259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 78359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 78459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException { 78559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (refreshFlags != 0) 78659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Scene graph must be updated" + 78759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta " before checking collision"); 78859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 78959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (other instanceof BoundingVolume) 79059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!getWorldBound().intersects((BoundingVolume)other)) 79159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 79259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 79359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if(other instanceof Ray) 79459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return collideWithRay((Ray)other, results); 79559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta else if (other instanceof BoundingVolume) 79659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return collideWithBoundingVolume((BoundingVolume)other, results); 79759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta else { 79859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new UnsupportedCollisionException("TerrainPatch cannnot collide with "+other.getClass().getName()); 79959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 80059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 80159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 80259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 80359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int collideWithRay(Ray ray, CollisionResults results) { 80459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // This should be handled in the root terrain quad 80559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 80659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 80759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 80859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int collideWithBoundingVolume(BoundingVolume boundingVolume, CollisionResults results) { 80959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (boundingVolume instanceof BoundingBox) 81059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return collideWithBoundingBox((BoundingBox)boundingVolume, results); 81159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta else if(boundingVolume instanceof BoundingSphere) { 81259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BoundingSphere sphere = (BoundingSphere) boundingVolume; 81359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BoundingBox bbox = new BoundingBox(boundingVolume.getCenter().clone(), sphere.getRadius(), 81459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sphere.getRadius(), 81559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sphere.getRadius()); 81659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return collideWithBoundingBox(bbox, results); 81759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 81859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 81959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 82059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 82159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected Vector3f worldCoordinateToLocal(Vector3f loc) { 82259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f translated = new Vector3f(); 82359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta translated.x = loc.x/getWorldScale().x - getWorldTranslation().x; 82459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta translated.y = loc.y/getWorldScale().y - getWorldTranslation().y; 82559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta translated.z = loc.z/getWorldScale().z - getWorldTranslation().z; 82659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return translated; 82759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 82859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 82959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 83059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This most definitely is not optimized. 83159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 83259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int collideWithBoundingBox(BoundingBox bbox, CollisionResults results) { 83359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 83459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // test the four corners, for cases where the bbox dimensions are less than the terrain grid size, which is probably most of the time 83559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f topLeft = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x-bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent())); 83659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f topRight = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x+bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent())); 83759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f bottomLeft = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x-bbox.getXExtent(), 0, bbox.getCenter().z+bbox.getZExtent())); 83859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f bottomRight = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x+bbox.getXExtent(), 0, bbox.getCenter().z+bbox.getZExtent())); 83959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 84059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Triangle t = getTriangle(topLeft.x, topLeft.z); 84159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (t != null && bbox.collideWith(t, results) > 0) 84259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 1; 84359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta t = getTriangle(topRight.x, topRight.z); 84459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (t != null && bbox.collideWith(t, results) > 0) 84559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 1; 84659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta t = getTriangle(bottomLeft.x, bottomLeft.z); 84759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (t != null && bbox.collideWith(t, results) > 0) 84859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 1; 84959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta t = getTriangle(bottomRight.x, bottomRight.z); 85059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (t != null && bbox.collideWith(t, results) > 0) 85159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 1; 85259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 85359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // box is larger than the points on the terrain, so test against the points 85459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (float z=topLeft.z; z<bottomLeft.z; z+=1) { 85559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (float x=topLeft.x; x<topRight.x; x+=1) { 85659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 85759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x < 0 || z < 0 || x >= size || z >= size) 85859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; 85959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta t = getTriangle(x,z); 86059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (t != null && bbox.collideWith(t, results) > 0) 86159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 1; 86259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 86359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 86459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 86559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 86659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 86759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 86859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 86959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 87059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void write(JmeExporter ex) throws IOException { 87159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // the mesh is removed, and reloaded when read() is called 87259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // this reduces the save size to 10% by not saving the mesh 87359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh temp = getMesh(); 87459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh = null; 87559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 87659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super.write(ex); 87759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta OutputCapsule oc = ex.getCapsule(this); 87859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(size, "size", 16); 87959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(totalSize, "totalSize", 16); 88059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(quadrant, "quadrant", (short)0); 88159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(stepScale, "stepScale", Vector3f.UNIT_XYZ); 88259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(offset, "offset", Vector3f.UNIT_XYZ); 88359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(offsetAmount, "offsetAmount", 0); 88459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //oc.write(lodCalculator, "lodCalculator", null); 88559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //oc.write(lodCalculatorFactory, "lodCalculatorFactory", null); 88659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(lodEntropy, "lodEntropy", null); 88759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(geomap, "geomap", null); 88859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 88959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta setMesh(temp); 89059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 89159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 89259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 89359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void read(JmeImporter im) throws IOException { 89459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super.read(im); 89559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta InputCapsule ic = im.getCapsule(this); 89659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta size = ic.readInt("size", 16); 89759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta totalSize = ic.readInt("totalSize", 16); 89859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta quadrant = ic.readShort("quadrant", (short)0); 89959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta stepScale = (Vector3f) ic.readSavable("stepScale", Vector3f.UNIT_XYZ); 90059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta offset = (Vector2f) ic.readSavable("offset", Vector3f.UNIT_XYZ); 90159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta offsetAmount = ic.readFloat("offsetAmount", 0); 90259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //lodCalculator = (LodCalculator) ic.readSavable("lodCalculator", new DistanceLodCalculator()); 90359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //lodCalculator.setTerrainPatch(this); 90459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //lodCalculatorFactory = (LodCalculatorFactory) ic.readSavable("lodCalculatorFactory", null); 90559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta lodEntropy = ic.readFloatArray("lodEntropy", null); 90659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geomap = (LODGeomap) ic.readSavable("geomap", null); 90759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 90859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh regen = geomap.createMesh(stepScale, new Vector2f(1,1), offset, offsetAmount, totalSize, false); 90959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta setMesh(regen); 91059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //TangentBinormalGenerator.generate(this); // note that this will be removed 91159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ensurePositiveVolumeBBox(); 91259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 91359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 91459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 91559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TerrainPatch clone() { 91659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch clone = new TerrainPatch(); 91759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.name = name.toString(); 91859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.size = size; 91959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.totalSize = totalSize; 92059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.quadrant = quadrant; 92159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.stepScale = stepScale.clone(); 92259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.offset = offset.clone(); 92359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.offsetAmount = offsetAmount; 92459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //clone.lodCalculator = lodCalculator.clone(); 92559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //clone.lodCalculator.setTerrainPatch(clone); 92659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //clone.setLodCalculator(lodCalculatorFactory.clone()); 92759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.geomap = new LODGeomap(size, geomap.getHeightArray()); 92859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.setLocalTranslation(getLocalTranslation().clone()); 92959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh m = clone.geomap.createMesh(clone.stepScale, Vector2f.UNIT_XY, clone.offset, clone.offsetAmount, clone.totalSize, false); 93059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.setMesh(m); 93159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.setMaterial(material.clone()); 93259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return clone; 93359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 93459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 93559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void ensurePositiveVolumeBBox() { 93659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (getModelBound() instanceof BoundingBox) { 93759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (((BoundingBox)getModelBound()).getYExtent() < 0.001f) { 93859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // a correction so the box always has a volume 93959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ((BoundingBox)getModelBound()).setYExtent(0.001f); 94059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta updateWorldBound(); 94159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 94259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 94359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 94459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 94559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 94659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 94759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 948