Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.terrain.geomipmap;
import com.jme3.bounding.BoundingBox;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.UpdateControl;
import com.jme3.terrain.Terrain;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* TerrainGrid itself is an actual TerrainQuad. Its four children are the visible four tiles.
*
* The grid is indexed by cells. Each cell has an integer XZ coordinate originating at 0,0.
* TerrainGrid will piggyback on the TerrainLodControl so it can use the camera for its
* updates as well. It does this in the overwritten update() method.
*
* It uses an LRU (Least Recently Used) cache of 16 terrain tiles (full TerrainQuadTrees). The
* center 4 are the ones that are visible. As the camera moves, it checks what camera cell it is in
* and will attach the now visible tiles.
*
* The 'quadIndex' variable is a 4x4 array that represents the tiles. The center
* four (index numbers: 5, 6, 9, 10) are what is visible. Each quadIndex value is an
* offset vector. The vector contains whole numbers and represents how many tiles in offset
* this location is from the center of the map. So for example the index 11 [Vector3f(2, 0, 1)]
* is located 2*terrainSize in X axis and 1*terrainSize in Z axis.
*
* As the camera moves, it tests what cameraCell it is in. Each camera cell covers four quad tiles
* and is half way inside each one.
*
* +-------+-------+
* | 1 | 3 | Four terrainQuads that make up the grid
* | *..|..* | with the cameraCell in the middle, covering
* |----|--|--|----| all four quads.
* | *..|..* |
* | 2 | 4 |
* +-------+-------+
*
* This results in the effect of when the camera gets half way across one of the sides of a quad to
* an empty (non-loaded) area, it will trigger the system to load in the next tiles.
*
* The tile loading is done on a background thread, and once the tile is loaded, then it is
* attached to the grid quad tree, back on the OGL thread. It will grab the terrain quad from
* the LRU cache if it exists. If it does not exist, it will load in the new TerrainQuad tile.
*
* The loading of new tiles triggers events for any TerrainGridListeners. The events are:
*
*
tile Attached
*
tile Detached
*
grid moved.
*
*
* These allow physics to update, and other operation (often needed for loading the terrain) to occur
* at the right time.
*
* @author Anthyon
*/
public class TerrainGrid extends TerrainQuad {
protected static final Logger log = Logger.getLogger(TerrainGrid.class.getCanonicalName());
protected Vector3f currentCamCell = Vector3f.ZERO;
protected int quarterSize; // half of quadSize
protected int quadSize;
private TerrainGridTileLoader gridTileLoader;
protected Vector3f[] quadIndex;
protected Set listeners = new HashSet<>();
protected Material material;
//cache needs to be 1 row (4 cells) larger than what we care is cached
protected LRUCache cache = new LRUCache<>(20);
protected int cellsLoaded = 0;
protected int[] gridOffset;
protected boolean runOnce = false;
protected ExecutorService cacheExecutor;
protected class UpdateQuadCache implements Runnable {
protected final Vector3f location;
public UpdateQuadCache(Vector3f location) {
this.location = location;
}
/**
* This is executed if the camera has moved into a new CameraCell and will load in
* the new TerrainQuad tiles to be children of this TerrainGrid parent.
* It will first check the LRU cache to see if the terrain tile is already there,
* if it is not there, it will load it in and then cache that tile.
* The terrain tiles get added to the quad tree back on the OGL thread using the
* attachQuadAt() method. It also resets any cached values in TerrainQuad (such as
* neighbours).
*/
@Override
public void run() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int quadIdx = i * 4 + j;
final Vector3f quadCell = location.add(quadIndex[quadIdx]);
TerrainQuad q = cache.get(quadCell);
if (q == null) {
if (gridTileLoader != null) {
q = gridTileLoader.getTerrainQuadAt(quadCell);
// only clone the material to the quad if it doesn't have a material of its own
if(q.getMaterial()==null) q.setMaterial(material.clone());
log.log(Level.FINE, "Loaded TerrainQuad {0} from TerrainQuadGrid", q.getName());
}
}
cache.put(quadCell, q);
final int quadrant = getQuadrant(quadIdx);
final TerrainQuad newQuad = q;
if (isCenter(quadIdx)) {
// if it should be attached as a child right now, attach it
getControl(UpdateControl.class).enqueue(new Callable