JmeCloneable related changes to TerrainQuad and TerrainPatch. Fixed

something I missed in NormalRecalcControl.
cleanup_build_scripts
Paul Speed 9 years ago
parent eda92656dd
commit 7b29c58fe0
  1. 19
      jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/NormalRecalcControl.java
  2. 142
      jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java
  3. 101
      jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java

@ -69,12 +69,23 @@ public class NormalRecalcControl extends AbstractControl {
}
@Override
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public Object jmeClone() {
NormalRecalcControl control = (NormalRecalcControl)super.jmeClone();
control.setEnabled(true);
return control;
}
return control;
}
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.terrain = cloner.clone(terrain);
}
@Override
public Control cloneForSpatial(Spatial spatial) {
@ -83,7 +94,7 @@ public class NormalRecalcControl extends AbstractControl {
control.setEnabled(true);
return control;
}
@Override
public void setSpatial(Spatial spatial) {
super.setSpatial(spatial);

@ -50,6 +50,7 @@ import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.terrain.geomipmap.TerrainQuad.LocationHeight;
import com.jme3.terrain.geomipmap.lodcalc.util.EntropyComputeUtil;
import com.jme3.util.BufferUtils;
import com.jme3.util.clone.Cloner;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.FloatBuffer;
@ -65,18 +66,18 @@ import java.util.List;
* That uses a geo-mipmapping algorithm to change the index buffer of the mesh.
* The mesh is a triangle strip. In wireframe mode you might notice some strange lines, these are degenerate
* triangles generated by the geoMipMap algorithm and can be ignored. The video card removes them at almost no cost.
*
*
* Each patch needs to know its neighbour's LOD so it can seam its edges with them, in case the neighbour has a different
* LOD. If this doesn't happen, you will see gaps.
*
*
* The LOD value is most detailed at zero. It gets less detailed the higher the LOD value until you reach maxLod, which
* 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
* for now until I add in a custom index buffer calculation for that max level, the current algorithm does not go that far.
*
* You can supply a LodThresholdCalculator for use in determining when the LOD should change. It's API will no doubt change
* 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,
*
* You can supply a LodThresholdCalculator for use in determining when the LOD should change. It's API will no doubt change
* 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,
* then the LOD changes every 130 units away.
*
*
* @author Brent Owens
*/
public class TerrainPatch extends Geometry {
@ -118,7 +119,7 @@ public class TerrainPatch extends Geometry {
super("TerrainPatch");
setBatchHint(BatchHint.Never);
}
public TerrainPatch(String name) {
super(name);
setBatchHint(BatchHint.Never);
@ -221,7 +222,7 @@ public class TerrainPatch extends Geometry {
public FloatBuffer getHeightmap() {
return BufferUtils.createFloatBuffer(geomap.getHeightArray());
}
public float[] getHeightMap() {
return geomap.getHeightArray();
}
@ -256,7 +257,7 @@ public class TerrainPatch extends Geometry {
idxB = geomap.writeIndexArrayLodVariable(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()), totalSize);
else
idxB = geomap.writeIndexArrayLodDiff(pow, right, top, left, bottom, totalSize);
Buffer b;
if (idxB.getBuffer() instanceof IntBuffer)
b = (IntBuffer)idxB.getBuffer();
@ -277,14 +278,14 @@ public class TerrainPatch extends Geometry {
return store.set(getMesh().getFloatBuffer(Type.TexCoord).get(idx*2),
getMesh().getFloatBuffer(Type.TexCoord).get(idx*2+1) );
}
public float getHeightmapHeight(float x, float z) {
if (x < 0 || z < 0 || x >= size || z >= size)
return 0;
int idx = (int) (z * size + x);
return getMesh().getFloatBuffer(Type.Position).get(idx*3+1); // 3 floats per entry (x,y,z), the +1 is to get the Y
}
/**
* Get the triangle of this geometry at the specified local coordinate.
* @param x local to the terrain patch
@ -306,7 +307,7 @@ public class TerrainPatch extends Geometry {
}
protected void setHeight(List<LocationHeight> locationHeights, boolean overrideHeight) {
for (LocationHeight lh : locationHeights) {
if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size)
continue;
@ -317,7 +318,7 @@ public class TerrainPatch extends Geometry {
float h = getMesh().getFloatBuffer(Type.Position).get(idx*3+1);
geomap.getHeightArray()[idx] = h+lh.h;
}
}
FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
@ -351,7 +352,7 @@ public class TerrainPatch extends Geometry {
TB.setUpdateNeeded();
BB.setUpdateNeeded();
}
/**
* Matches the normals along the edge of the patch with the neighbours.
* Computes the normals for the right, bottom, left, and top edges of the
@ -364,7 +365,7 @@ public class TerrainPatch extends Geometry {
* *---x---*
* |
* *
* It works across the right side of the patch, from the top down to
* It works across the right side of the patch, from the top down to
* the bottom. Then it works on the bottom side of the patch, from the
* left to the right.
*/
@ -388,9 +389,9 @@ public class TerrainPatch extends Geometry {
Vector3f binormal = new Vector3f();
Vector3f normal = new Vector3f();
int s = this.getSize()-1;
if (right != null) { // right side, works its way down
for (int i=0; i<s+1; i++) {
rootPoint.set(0, this.getHeightmapHeight(s,i), 0);
@ -399,26 +400,26 @@ public class TerrainPatch extends Geometry {
if (i == 0) { // top point
bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1);
if (top == null) {
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), s, normal, tangent, binormal);
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
} else {
topPoint.set(0, top.getHeightmapHeight(s,s-1), -1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint,normal, tangent, binormal);
setInBuffer(this.getMesh(), s, normal, tangent, binormal);
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
setInBuffer(top.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
if (topRight != null) {
// setInBuffer(topRight.getMesh(), (s+1)*s, normal, tangent, binormal);
}
}
} else if (i == s) { // bottom point
topPoint.set(0, this.getHeightmapHeight(s,s-1), -1);
if (bottom == null) {
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
@ -429,7 +430,7 @@ public class TerrainPatch extends Geometry {
setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
setInBuffer(right.getMesh(), (s+1)*s, normal, tangent, binormal);
setInBuffer(bottom.getMesh(), s, normal, tangent, binormal);
if (bottomRight != null) {
// setInBuffer(bottomRight.getMesh(), 0, normal, tangent, binormal);
}
@ -449,41 +450,41 @@ public class TerrainPatch extends Geometry {
rootPoint.set(0, this.getHeightmapHeight(0,i), 0);
leftPoint.set(-1, left.getHeightmapHeight(s-1,i), 0);
rightPoint.set(1, this.getHeightmapHeight(1,i), 0);
if (i == 0) { // top point
bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
if (top == null) {
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
} else {
topPoint.set(0, top.getHeightmapHeight(0,s-1), -1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
setInBuffer(top.getMesh(), (s+1)*s, normal, tangent, binormal);
if (topLeft != null) {
// setInBuffer(topLeft.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
}
}
} else if (i == s) { // bottom point
topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
if (bottom == null) {
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
} else {
bottomPoint.set(0, bottom.getHeightmapHeight(0,1), 1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
setInBuffer(bottom.getMesh(), 0, normal, tangent, binormal);
if (bottomLeft != null) {
// setInBuffer(bottomLeft.getMesh(), s, normal, tangent, binormal);
}
@ -491,7 +492,7 @@ public class TerrainPatch extends Geometry {
} else { // all in the middle
topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(this.getMesh(), (s+1)*(i), normal, tangent, binormal);
setInBuffer(left.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
@ -504,14 +505,14 @@ public class TerrainPatch extends Geometry {
rootPoint.set(0, this.getHeightmapHeight(i,0), 0);
topPoint.set(0, top.getHeightmapHeight(i,s-1), -1);
bottomPoint.set(0, this.getHeightmapHeight(i,1), 1);
if (i == 0) { // left corner
// handled by left side pass
} else if (i == s) { // right corner
// handled by this patch when it does its right side
} else { // all in the middle
leftPoint.set(-1, this.getHeightmapHeight(i-1,0), 0);
rightPoint.set(1, this.getHeightmapHeight(i+1,0), 0);
@ -520,9 +521,9 @@ public class TerrainPatch extends Geometry {
setInBuffer(top.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
}
}
}
if (bottom != null) { // bottom side, works its way right
for (int i=0; i<s+1; i++) {
rootPoint.set(0, this.getHeightmapHeight(i,s), 0);
@ -531,11 +532,11 @@ public class TerrainPatch extends Geometry {
if (i == 0) { // left
// handled by the left side pass
} else if (i == s) { // right
// handled by the right side pass
} else { // all in the middle
leftPoint.set(-1, this.getHeightmapHeight(i-1,s), 0);
rightPoint.set(1, this.getHeightmapHeight(i+1,s), 0);
@ -544,22 +545,22 @@ public class TerrainPatch extends Geometry {
setInBuffer(bottom.getMesh(), i, normal, tangent, binormal);
}
}
}
}
protected void averageNormalsTangents(
Vector3f topPoint,
Vector3f rootPoint,
Vector3f leftPoint,
Vector3f bottomPoint,
Vector3f leftPoint,
Vector3f bottomPoint,
Vector3f rightPoint,
Vector3f normal,
Vector3f tangent,
Vector3f binormal)
{
Vector3f scale = getWorldScale();
Vector3f n1 = new Vector3f(0,0,0);
if (topPoint != null && leftPoint != null) {
n1.set(calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale)));
@ -576,12 +577,12 @@ public class TerrainPatch extends Geometry {
if (rightPoint != null && topPoint != null) {
n4.set(calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale)));
}
//if (bottomPoint != null && rightPoint != null && rootTex != null && rightTex != null && bottomTex != null)
// LODGeomap.calculateTangent(new Vector3f[]{rootPoint.mult(scale),rightPoint.mult(scale),bottomPoint.mult(scale)}, new Vector2f[]{rootTex,rightTex,bottomTex}, tangent, binormal);
normal.set(n1.add(n2).add(n3).add(n4).normalize());
tangent.set(normal.cross(new Vector3f(0,0,1)).normalize());
binormal.set(new Vector3f(1,0,0).cross(normal).normalize());
}
@ -592,11 +593,11 @@ public class TerrainPatch extends Geometry {
.crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
return normal;
}
protected Vector3f getMeshNormal(int x, int z) {
if (x >= size || z >= size)
return null; // out of range
int index = (z*size+x)*3;
FloatBuffer nb = (FloatBuffer)this.getMesh().getBuffer(Type.Normal).getData();
Vector3f normal = new Vector3f();
@ -609,7 +610,7 @@ public class TerrainPatch extends Geometry {
protected float getHeight(int x, int z, float xm, float zm) {
return geomap.getHeight(x,z,xm,zm);
}
/**
* Locks the mesh (sets it static) to improve performance.
* But it it not editable then. Set unlock to make it editable.
@ -626,7 +627,7 @@ public class TerrainPatch extends Geometry {
public void unlockMesh() {
getMesh().setDynamic();
}
/**
* Returns the offset amount this terrain patch uses for textures.
*
@ -797,7 +798,7 @@ public class TerrainPatch extends Geometry {
protected void setLodBottom(int lodBottom) {
this.lodBottom = lodBottom;
}
/*public void setLodCalculator(LodCalculatorFactory lodCalculatorFactory) {
this.lodCalculatorFactory = lodCalculatorFactory;
setLodCalculator(lodCalculatorFactory.createCalculator(this));
@ -812,7 +813,7 @@ public class TerrainPatch extends Geometry {
if (other instanceof BoundingVolume)
if (!getWorldBound().intersects((BoundingVolume)other))
return 0;
if(other instanceof Ray)
return collideWithRay((Ray)other, results);
else if (other instanceof BoundingVolume)
@ -853,7 +854,7 @@ public class TerrainPatch extends Geometry {
* This most definitely is not optimized.
*/
private int collideWithBoundingBox(BoundingBox bbox, CollisionResults results) {
// test the four corners, for cases where the bbox dimensions are less than the terrain grid size, which is probably most of the time
Vector3f topLeft = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x-bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent()));
Vector3f topRight = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x+bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent()));
@ -872,11 +873,11 @@ public class TerrainPatch extends Geometry {
t = getTriangle(bottomRight.x, bottomRight.z);
if (t != null && bbox.collideWith(t, results) > 0)
return 1;
// box is larger than the points on the terrain, so test against the points
for (float z=topLeft.z; z<bottomLeft.z; z+=1) {
for (float x=topLeft.x; x<topRight.x; x+=1) {
if (x < 0 || z < 0 || x >= size || z >= size)
continue;
t = getTriangle(x,z);
@ -895,7 +896,7 @@ public class TerrainPatch extends Geometry {
// this reduces the save size to 10% by not saving the mesh
Mesh temp = getMesh();
mesh = null;
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(size, "size", 16);
@ -908,7 +909,7 @@ public class TerrainPatch extends Geometry {
//oc.write(lodCalculatorFactory, "lodCalculatorFactory", null);
oc.write(lodEntropy, "lodEntropy", null);
oc.write(geomap, "geomap", null);
setMesh(temp);
}
@ -927,7 +928,7 @@ public class TerrainPatch extends Geometry {
//lodCalculatorFactory = (LodCalculatorFactory) ic.readSavable("lodCalculatorFactory", null);
lodEntropy = ic.readFloatArray("lodEntropy", null);
geomap = (LODGeomap) ic.readSavable("geomap", null);
Mesh regen = geomap.createMesh(stepScale, new Vector2f(1,1), offset, offsetAmount, totalSize, false);
setMesh(regen);
//TangentBinormalGenerator.generate(this); // note that this will be removed
@ -955,6 +956,33 @@ public class TerrainPatch extends Geometry {
return clone;
}
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.stepScale = cloner.clone(stepScale);
this.offset = cloner.clone(offset);
this.leftNeighbour = null;
this.topNeighbour = null;
this.rightNeighbour = null;
this.bottomNeighbour = null;
// Don't feel like making geomap cloneable tonight
// so I'll copy the old logic.
this.geomap = new LODGeomap(size, geomap.getHeightArray());
Mesh m = geomap.createMesh(stepScale, Vector2f.UNIT_XY, offset, offsetAmount, totalSize, false);
this.setMesh(m);
// In this case, we always clone material even if the cloner is setup
// not to clone it. Terrain uses mutable textures and stuff so it's important
// to clone it. (At least that's my understanding and is evidenced by the old
// clone code specifically cloning material.) -pspeed
this.material = material.clone();
}
protected void ensurePositiveVolumeBBox() {
if (getModelBound() instanceof BoundingBox) {
if (((BoundingBox)getModelBound()).getYExtent() < 0.001f) {

@ -55,6 +55,7 @@ import com.jme3.terrain.geomipmap.picking.BresenhamTerrainPicker;
import com.jme3.terrain.geomipmap.picking.TerrainPickData;
import com.jme3.terrain.geomipmap.picking.TerrainPicker;
import com.jme3.util.TangentBinormalGenerator;
import com.jme3.util.clone.Cloner;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@ -126,7 +127,7 @@ public class TerrainQuad extends Node implements Terrain {
private Vector3f lastScale = Vector3f.UNIT_XYZ;
protected NeighbourFinder neighbourFinder;
public TerrainQuad() {
super("Terrain");
}
@ -144,24 +145,24 @@ public class TerrainQuad extends Node implements Terrain {
* </p>
* @param name the name of the scene element. This is required for
* identification and comparison purposes.
* @param patchSize size of the individual patches (geometry). Power of 2 plus 1,
* @param patchSize size of the individual patches (geometry). Power of 2 plus 1,
* must be smaller than totalSize. (eg. 33, 65...)
* @param totalSize the size of this entire terrain (on one side). Power of 2 plus 1
* @param totalSize the size of this entire terrain (on one side). Power of 2 plus 1
* (eg. 513, 1025, 2049...)
* @param heightMap The height map to generate the terrain from (a flat
* height map will be generated if this is null). The size of one side of the heightmap
* height map will be generated if this is null). The size of one side of the heightmap
* must match the totalSize. So a 513x513 heightmap is needed for a terrain with totalSize of 513.
*/
public TerrainQuad(String name, int patchSize, int totalSize, float[] heightMap) {
this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMap);
affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), size*2, Float.MAX_VALUE, size*2);
fixNormalEdges(affectedAreaBBox);
addControl(new NormalRecalcControl(this));
}
/**
*
*
* @param name the name of the scene element. This is required for
* identification and comparison purposes.
* @param patchSize size of the individual patches
@ -176,7 +177,7 @@ public class TerrainQuad extends Node implements Terrain {
}
/**
*
*
* @param name the name of the scene element. This is required for
* identification and comparison purposes.
* @param patchSize size of the individual patches
@ -192,9 +193,9 @@ public class TerrainQuad extends Node implements Terrain {
//fixNormalEdges(affectedAreaBBox);
//addControl(new NormalRecalcControl(this));
}
/**
*
*
* @param name the name of the scene element. This is required for
* identification and comparison purposes.
* @param patchSize size of the individual patches
@ -217,17 +218,17 @@ public class TerrainQuad extends Node implements Terrain {
Vector2f offset, float offsetAmount)
{
super(name);
if (heightMap == null)
heightMap = generateDefaultHeightMap(quadSize);
if (!FastMath.isPowerOfTwo(quadSize - 1)) {
throw new RuntimeException("size given: " + quadSize + " Terrain quad sizes may only be (2^N + 1)");
}
if (FastMath.sqrt(heightMap.length) > quadSize) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Heightmap size is larger than the terrain size. Make sure your heightmap image is the same size as the terrain!");
}
this.offset = offset;
this.offsetAmount = offsetAmount;
this.totalSize = totalSize;
@ -248,7 +249,7 @@ public class TerrainQuad extends Node implements Terrain {
public void recalculateAllNormals() {
affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), totalSize*2, Float.MAX_VALUE, totalSize*2);
}
/**
* Create just a flat heightmap
*/
@ -267,11 +268,11 @@ public class TerrainQuad extends Node implements Terrain {
//TODO background-thread this if it ends up being expensive
fixNormals(affectedAreaBBox); // the affected patches
fixNormalEdges(affectedAreaBBox); // the edges between the patches
setNormalRecalcNeeded(null); // set to false
}
}
/**
* Caches the transforms (except rotation) so the LOD calculator,
* which runs on a separate thread, can access them safely.
@ -343,7 +344,7 @@ public class TerrainQuad extends Node implements Terrain {
public Material getMaterial() {
return getMaterial(null);
}
public Material getMaterial(Vector3f worldLocation) {
// get the material from one of the children. They all share the same material
if (children != null) {
@ -362,7 +363,7 @@ public class TerrainQuad extends Node implements Terrain {
public int getNumMajorSubdivisions() {
return 1;
}
protected boolean calculateLod(List<Vector3f> location, HashMap<String,UpdatedTerrainPatch> updates, LodCalculator lodCalculator) {
@ -434,7 +435,7 @@ public class TerrainQuad extends Node implements Terrain {
utp.setBottomLod(utpD.getNewLod());
utpD.setTopLod(utp.getNewLod());
}
if (left != null) {
UpdatedTerrainPatch utpL = updated.get(left.getName());
if (utpL == null) {
@ -478,7 +479,7 @@ public class TerrainQuad extends Node implements Terrain {
}
}
}
/**
* Find any neighbours that should have their edges seamed because another neighbour
* changed its LOD to a greater value (less detailed)
@ -587,10 +588,10 @@ public class TerrainQuad extends Node implements Terrain {
/**
* Quadrants, world coordinates, and heightmap coordinates (Y-up):
*
*
* -z
* -u |
* -v 1|3
* -u |
* -v 1|3
* -x ----+---- x
* 2|4 u
* | v
@ -668,7 +669,7 @@ public class TerrainQuad extends Node implements Terrain {
quad3.setLocalTranslation(origin3);
quad3.quadrant = 3;
this.attachChild(quad3);
// 4 lower right of heightmap, lower right quad
float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
split - 1, split);
@ -892,7 +893,7 @@ public class TerrainQuad extends Node implements Terrain {
}
return false;
}
/**
* This will cause all normals for this terrain quad to be recalculated
*/
@ -1024,14 +1025,14 @@ public class TerrainQuad extends Node implements Terrain {
int col;
int row;
Spatial child;
QuadrantChild(int col, int row, Spatial child) {
this.col = col;
this.row = row;
this.child = child;
}
}
private QuadrantChild findMatchingChild(int x, int z) {
int quad = findQuadrant(x, z);
int split = (size + 1) >> 1;
@ -1069,7 +1070,7 @@ public class TerrainQuad extends Node implements Terrain {
}
return null;
}
/**
* Get the interpolated height of the terrain at the specified point.
* @param xz the location to get the height for
@ -1090,7 +1091,7 @@ public class TerrainQuad extends Node implements Terrain {
* gets an interpolated value at the specified point
*/
protected float getHeight(int x, int z, float xm, float zm) {
QuadrantChild match = findMatchingChild(x,z);
if (match != null) {
if (match.child instanceof TerrainQuad) {
@ -1107,10 +1108,10 @@ public class TerrainQuad extends Node implements Terrain {
float x = (float)(((xz.x - getWorldTranslation().x) / getWorldScale().x) + (float)(totalSize-1) / 2f);
float z = (float)(((xz.y - getWorldTranslation().z) / getWorldScale().z) + (float)(totalSize-1) / 2f);
Vector3f normal = getNormal(x, z, xz);
return normal;
}
protected Vector3f getNormal(float x, float z, Vector2f xz) {
x-=0.5f;
z-=0.5f;
@ -1125,15 +1126,15 @@ public class TerrainQuad extends Node implements Terrain {
// v3--v4 | Z
// |
// <-------Y
// X
// X
Vector3f n1 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.ceil(z));
Vector3f n2 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.ceil(z));
Vector3f n3 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.floor(z));
Vector3f n4 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.floor(z));
return n1.add(n2).add(n3).add(n4).normalize();
}
public void setHeight(Vector2f xz, float height) {
List<Vector2f> coord = new ArrayList<Vector2f>();
coord.add(xz);
@ -1291,7 +1292,7 @@ public class TerrainQuad extends Node implements Terrain {
return (x >= 0 && x <= totalSize && z >= 0 && z <= totalSize);
}
public int getTerrainSize() {
return totalSize;
}
@ -1750,7 +1751,7 @@ public class TerrainQuad extends Node implements Terrain {
totalSize = c.readInt("totalSize", 0);
//lodCalculator = (LodCalculator) c.readSavable("lodCalculator", createDefaultLodCalculator());
//lodCalculatorFactory = (LodCalculatorFactory) c.readSavable("lodCalculatorFactory", null);
if ( !(getParent() instanceof TerrainQuad) ) {
BoundingBox all = new BoundingBox(getWorldTranslation(), totalSize, totalSize, totalSize);
affectedAreaBBox = all;
@ -1793,10 +1794,10 @@ public class TerrainQuad extends Node implements Terrain {
quadClone.quadrant = quadrant;
//quadClone.lodCalculatorFactory = lodCalculatorFactory.clone();
//quadClone.lodCalculator = lodCalculator.clone();
TerrainLodControl lodControlCloned = this.getControl(TerrainLodControl.class);
TerrainLodControl lodControl = quadClone.getControl(TerrainLodControl.class);
if (lodControlCloned != null && !(getParent() instanceof TerrainQuad)) {
//lodControlCloned.setLodCalculator(lodControl.getLodCalculator().clone());
}
@ -1806,7 +1807,25 @@ public class TerrainQuad extends Node implements Terrain {
return quadClone;
}
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.stepScale = cloner.clone(stepScale);
this.offset = cloner.clone(offset);
// This was not cloned before... I think that's a mistake.
this.affectedAreaBBox = cloner.clone(affectedAreaBBox);
// picker is not cloneable and not cloned. This also seems like
// a mistake if you ever load the same terrain twice.
// this.picker = cloner.clone(picker);
// neighbourFinder is also not cloned. Maybe that's ok.
}
@Override
protected void setParent(Node parent) {
super.setParent(parent);
@ -1815,7 +1834,7 @@ public class TerrainQuad extends Node implements Terrain {
clearCaches();
}
}
/**
* Removes any cached references this terrain is holding, in particular
* the TerrainPatch's neighbour references.
@ -1834,7 +1853,7 @@ public class TerrainQuad extends Node implements Terrain {
}
}
}
public int getMaxLod() {
if (maxLod < 0)
maxLod = Math.max(1, (int) (FastMath.log(size-1)/FastMath.log(2)) -1); // -1 forces our minimum of 4 triangles wide

Loading…
Cancel
Save