1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.jme3.terrain.geomipmap; 33 34 import com.jme3.export.InputCapsule; 35 import com.jme3.export.JmeExporter; 36 import com.jme3.export.JmeImporter; 37 import com.jme3.export.OutputCapsule; 38 import com.jme3.math.Vector3f; 39 import com.jme3.renderer.Camera; 40 import com.jme3.renderer.RenderManager; 41 import com.jme3.renderer.ViewPort; 42 import com.jme3.scene.Node; 43 import com.jme3.scene.Spatial; 44 import com.jme3.scene.control.AbstractControl; 45 import com.jme3.scene.control.Control; 46 import com.jme3.terrain.Terrain; 47 import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; 48 import com.jme3.terrain.geomipmap.lodcalc.LodCalculator; 49 import java.io.IOException; 50 import java.util.ArrayList; 51 import java.util.List; 52 53 /** 54 * Tells the terrain to update its Level of Detail. 55 * It needs the cameras to do this, and there could possibly 56 * be several cameras in the scene, so it accepts a list 57 * of cameras. 58 * NOTE: right now it just uses the first camera passed in, 59 * in the future it will use all of them to determine what 60 * LOD to set. 61 * 62 * This control serializes, but it does not save the Camera reference. 63 * This camera reference has to be manually added in when you load the 64 * terrain to the scene! 65 * 66 * @author Brent Owens 67 */ 68 public class TerrainLodControl extends AbstractControl { 69 70 private Terrain terrain; 71 private List<Camera> cameras; 72 private List<Vector3f> cameraLocations = new ArrayList<Vector3f>(); 73 private LodCalculator lodCalculator; 74 private boolean hasResetLod = false; // used when enabled is set to false 75 76 public TerrainLodControl() { 77 } 78 79 public TerrainLodControl(Terrain terrain, Camera camera) { 80 List<Camera> cams = new ArrayList<Camera>(); 81 cams.add(camera); 82 this.terrain = terrain; 83 this.cameras = cams; 84 lodCalculator = new DistanceLodCalculator(65, 2.7f); // a default calculator 85 } 86 87 /** 88 * Only uses the first camera right now. 89 * @param terrain to act upon (must be a Spatial) 90 * @param cameras one or more cameras to reference for LOD calc 91 */ 92 public TerrainLodControl(Terrain terrain, List<Camera> cameras) { 93 this.terrain = terrain; 94 this.cameras = cameras; 95 lodCalculator = new DistanceLodCalculator(65, 2.7f); // a default calculator 96 } 97 98 @Override 99 protected void controlRender(RenderManager rm, ViewPort vp) { 100 } 101 102 @Override 103 public void update(float tpf) { 104 controlUpdate(tpf); 105 } 106 107 @Override 108 protected void controlUpdate(float tpf) { 109 //list of cameras for when terrain supports multiple cameras (ie split screen) 110 111 if (lodCalculator == null) 112 return; 113 114 if (!enabled) { 115 if (!hasResetLod) { 116 // this will get run once 117 hasResetLod = true; 118 lodCalculator.turnOffLod(); 119 } 120 } 121 122 if (cameras != null) { 123 if (cameraLocations.isEmpty() && !cameras.isEmpty()) { 124 for (Camera c : cameras) // populate them 125 { 126 cameraLocations.add(c.getLocation()); 127 } 128 } 129 terrain.update(cameraLocations, lodCalculator); 130 } 131 } 132 133 public Control cloneForSpatial(Spatial spatial) { 134 if (spatial instanceof Terrain) { 135 List<Camera> cameraClone = new ArrayList<Camera>(); 136 if (cameras != null) { 137 for (Camera c : cameras) { 138 cameraClone.add(c); 139 } 140 } 141 TerrainLodControl cloned = new TerrainLodControl((Terrain) spatial, cameraClone); 142 cloned.setLodCalculator(lodCalculator.clone()); 143 return cloned; 144 } 145 return null; 146 } 147 148 public void setCamera(Camera camera) { 149 List<Camera> cams = new ArrayList<Camera>(); 150 cams.add(camera); 151 setCameras(cams); 152 } 153 154 public void setCameras(List<Camera> cameras) { 155 this.cameras = cameras; 156 cameraLocations.clear(); 157 for (Camera c : cameras) { 158 cameraLocations.add(c.getLocation()); 159 } 160 } 161 162 @Override 163 public void setSpatial(Spatial spatial) { 164 super.setSpatial(spatial); 165 if (spatial instanceof Terrain) { 166 this.terrain = (Terrain) spatial; 167 } 168 } 169 170 public void setTerrain(Terrain terrain) { 171 this.terrain = terrain; 172 } 173 174 public LodCalculator getLodCalculator() { 175 return lodCalculator; 176 } 177 178 public void setLodCalculator(LodCalculator lodCalculator) { 179 this.lodCalculator = lodCalculator; 180 } 181 182 @Override 183 public void setEnabled(boolean enabled) { 184 this.enabled = enabled; 185 if (!enabled) { 186 // reset the lod levels to max detail for the terrain 187 hasResetLod = false; 188 } else { 189 hasResetLod = true; 190 lodCalculator.turnOnLod(); 191 } 192 } 193 194 @Override 195 public void write(JmeExporter ex) throws IOException { 196 super.write(ex); 197 OutputCapsule oc = ex.getCapsule(this); 198 oc.write((Node)terrain, "terrain", null); 199 oc.write(lodCalculator, "lodCalculator", null); 200 } 201 202 @Override 203 public void read(JmeImporter im) throws IOException { 204 super.read(im); 205 InputCapsule ic = im.getCapsule(this); 206 terrain = (Terrain) ic.readSavable("terrain", null); 207 lodCalculator = (LodCalculator) ic.readSavable("lodCalculator", new DistanceLodCalculator()); 208 } 209 210 } 211