159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/* 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 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.picking; 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.CollisionResult; 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.collision.CollisionResults; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Ray; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Triangle; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector2f; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f; 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.terrain.geomipmap.TerrainPatch; 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.terrain.geomipmap.TerrainQuad; 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.terrain.geomipmap.picking.BresenhamYUpGridTracer.Direction; 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList; 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Collections; 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List; 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * It basically works by casting a pick ray 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * against the bounding volumes of the TerrainQuad and its children, gathering 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * all of the TerrainPatches hit (in distance order.) The triangles of each patch 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * are then tested using the BresenhamYUpGridTracer to determine which triangles 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * to test and in what order. When a hit is found, it is guaranteed to be the 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * first such hit and can immediately be returned. 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Joshua Slack 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Brent Owens 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class BresenhamTerrainPicker implements TerrainPicker { 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final Triangle gridTriA = new Triangle(new Vector3f(), new Vector3f(), new Vector3f()); 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final Triangle gridTriB = new Triangle(new Vector3f(), new Vector3f(), new Vector3f()); 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final Vector3f calcVec1 = new Vector3f(); 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final Ray workRay = new Ray(); 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final Ray worldPickRay = new Ray(); 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final TerrainQuad root; 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final BresenhamYUpGridTracer tracer = new BresenhamYUpGridTracer(); 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public BresenhamTerrainPicker(TerrainQuad root) { 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.root = root; 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Vector3f getTerrainIntersection(Ray worldPick, CollisionResults results) { 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta worldPickRay.set(worldPick); 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<TerrainPickData> pickData = new ArrayList<TerrainPickData>(); 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta root.findPick(worldPick.clone(), pickData); 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Collections.sort(pickData); 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pickData.isEmpty()) 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta workRay.set(worldPick); 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (TerrainPickData pd : pickData) { 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TerrainPatch patch = pd.targetPatch; 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tracer.getGridSpacing().set(patch.getWorldScale()); 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tracer.setGridOrigin(patch.getWorldTranslation()); 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta workRay.getOrigin().set(worldPick.getDirection()).multLocal(pd.cr.getDistance()-.1f).addLocal(worldPick.getOrigin()); 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tracer.startWalk(workRay); 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta final Vector3f intersection = new Vector3f(); 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta final Vector2f loc = tracer.getGridLocation(); 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (tracer.isRayPerpendicularToGrid()) { 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Triangle hit = new Triangle(); 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta checkTriangles(loc.x, loc.y, workRay, intersection, patch, hit); 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float distance = worldPickRay.origin.distance(intersection); 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta CollisionResult cr = new CollisionResult(intersection, distance); 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cr.setGeometry(patch); 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cr.setContactNormal(hit.getNormal()); 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta results.addCollision(cr); 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return intersection; 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta while (loc.x >= -1 && loc.x <= patch.getSize() && 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta loc.y >= -1 && loc.y <= patch.getSize()) { 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //System.out.print(loc.x+","+loc.y+" : "); 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // check the triangles of main square for intersection. 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Triangle hit = new Triangle(); 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (checkTriangles(loc.x, loc.y, workRay, intersection, patch, hit)) { 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // we found an intersection, so return that! 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float distance = worldPickRay.origin.distance(intersection); 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta CollisionResult cr = new CollisionResult(intersection, distance); 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cr.setGeometry(patch); 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta results.addCollision(cr); 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cr.setContactNormal(hit.getNormal()); 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return intersection; 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // because of how we get our height coords, we will 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // sometimes be off by a grid spot, so we check the next 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // grid space up. 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int dx = 0, dz = 0; 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Direction d = tracer.getLastStepDirection(); 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta switch (d) { 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PositiveX: 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case NegativeX: 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dx = 0; 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dz = 1; 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PositiveZ: 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case NegativeZ: 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dx = 1; 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dz = 0; 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (checkTriangles(loc.x + dx, loc.y + dz, workRay, intersection, patch, hit)) { 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // we found an intersection, so return that! 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float distance = worldPickRay.origin.distance(intersection); 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta CollisionResult cr = new CollisionResult(intersection, distance); 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta results.addCollision(cr); 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cr.setGeometry(patch); 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cr.setContactNormal(hit.getNormal()); 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return intersection; 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tracer.next(); 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected boolean checkTriangles(float gridX, float gridY, Ray pick, Vector3f intersection, TerrainPatch patch, Triangle store) { 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!getTriangles(gridX, gridY, patch)) 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pick.intersectWhere(gridTriA, intersection)) { 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta store.set(gridTriA.get1(), gridTriA.get2(), gridTriA.get3()); 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pick.intersectWhere(gridTriB, intersection)) { 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta store.set(gridTriB.get1(), gridTriB.get2(), gridTriB.get3()); 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Request the triangles (in world coord space) of a TerrainBlock that 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * correspond to the given grid location. The triangles are stored in the 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * class fields _gridTriA and _gridTriB. 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param gridX 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * grid row 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param gridY 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * grid column 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param block 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the TerrainBlock we are working with 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return true if the grid point is valid for the given block, false if it 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * is off the block. 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected boolean getTriangles(float gridX, float gridY, TerrainPatch patch) { 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta calcVec1.set(gridX, 0, gridY); 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int index = findClosestHeightIndex(calcVec1, patch); 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (index == -1) 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Triangle[] t = patch.getGridTriangles(gridX, gridY); 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (t == null || t.length == 0) 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gridTriA.set1(t[0].get1()); 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gridTriA.set2(t[0].get2()); 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gridTriA.set3(t[0].get3()); 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gridTriB.set1(t[1].get1()); 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gridTriB.set2(t[1].get2()); 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gridTriB.set3(t[1].get3()); 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Finds the closest height point to a position. Will always be left/above 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * that position. 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param position 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the position to check at 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param block 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the block to get height values from 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return an index to the height position of the given block. 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int findClosestHeightIndex(Vector3f position, TerrainPatch patch) { 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int x = (int) position.x; 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int z = (int) position.z; 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x < 0 || x >= patch.getSize() - 1) { 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return -1; 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (z < 0 || z >= patch.getSize() - 1) { 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return -1; 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return z * patch.getSize() + x; 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 244