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