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 // $Id: Dome.java 4131 2009-03-19 20:15:28Z blaine.dev $ 33 package com.jme3.scene.shape; 34 35 import com.jme3.export.InputCapsule; 36 import com.jme3.export.JmeExporter; 37 import com.jme3.export.JmeImporter; 38 import com.jme3.export.OutputCapsule; 39 import com.jme3.math.FastMath; 40 import com.jme3.math.Vector3f; 41 import com.jme3.scene.Mesh; 42 import com.jme3.scene.VertexBuffer.Type; 43 import com.jme3.util.BufferUtils; 44 import com.jme3.util.TempVars; 45 import java.io.IOException; 46 import java.nio.FloatBuffer; 47 import java.nio.ShortBuffer; 48 49 /** 50 * A hemisphere. 51 * 52 * @author Peter Andersson 53 * @author Joshua Slack (Original sphere code that was adapted) 54 * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ 55 */ 56 public class Dome extends Mesh { 57 58 private int planes; 59 private int radialSamples; 60 /** The radius of the dome */ 61 private float radius; 62 /** The center of the dome */ 63 private Vector3f center; 64 private boolean insideView = true; 65 66 /** 67 * Serialization only. Do not use. 68 */ 69 public Dome() { 70 } 71 72 /** 73 * Constructs a dome for use as a SkyDome. The SkyDome is centered at the origin 74 * and only visible from the inside. 75 * @param planes 76 * The number of planes along the Z-axis. Must be >= 2. 77 * Influences how round the arch of the dome is. 78 * @param radialSamples 79 * The number of samples along the radial. 80 * Influences how round the base of the dome is. 81 * @param radius 82 * Radius of the dome. 83 * @see #Dome(java.lang.String, com.jme.math.Vector3f, int, int, float) 84 */ 85 public Dome(int planes, int radialSamples, float radius) { 86 this(new Vector3f(0, 0, 0), planes, radialSamples, radius); 87 } 88 89 /** 90 * Constructs a dome visible from the inside, e.g. for use as a SkyDome. 91 * All geometry data buffers are updated automatically. <br> 92 * For a cone, set planes=2. For a pyramid, set radialSamples=4 and planes=2. 93 * Increasing planes and radialSamples increase the quality of the dome. 94 * 95 * @param center 96 * Center of the dome. 97 * @param planes 98 * The number of planes along the Z-axis. Must be >= 2. 99 * Influences how round the arch of the dome is. 100 * @param radialSamples 101 * The number of samples along the radial. 102 * Influences how round the base of the dome is. 103 * @param radius 104 * The radius of the dome. 105 */ 106 public Dome(Vector3f center, int planes, int radialSamples, 107 float radius) { 108 super(); 109 updateGeometry(center, planes, radialSamples, radius, true); 110 } 111 112 /** 113 * Constructs a dome. Use this constructor for half-sphere, pyramids, or cones. 114 * All geometry data buffers are updated automatically. <br> 115 * For a cone, set planes=2. For a pyramid, set radialSamples=4 and planes=2. 116 * Setting higher values for planes and radialSamples increases 117 * the quality of the half-sphere. 118 * 119 * @param center 120 * Center of the dome. 121 * @param planes 122 * The number of planes along the Z-axis. Must be >= 2. 123 * Influences how round the arch of the dome is. 124 * @param radialSamples 125 * The number of samples along the radial. 126 * Influences how round the base of the dome is. 127 * @param radius 128 * The radius of the dome. 129 * @param insideView 130 * If true, the dome is only visible from the inside, like a SkyDome. 131 * If false, the dome is only visible from the outside. 132 */ 133 public Dome(Vector3f center, int planes, int radialSamples, 134 float radius, boolean insideView) { 135 super(); 136 updateGeometry(center, planes, radialSamples, radius, insideView); 137 } 138 139 public Vector3f getCenter() { 140 return center; 141 } 142 143 /** 144 * Get the number of planar segments along the z-axis of the dome. 145 */ 146 public int getPlanes() { 147 return planes; 148 } 149 150 /** 151 * Get the number of samples radially around the main axis of the dome. 152 */ 153 public int getRadialSamples() { 154 return radialSamples; 155 } 156 157 /** 158 * Get the radius of the dome. 159 */ 160 public float getRadius() { 161 return radius; 162 } 163 164 /** 165 * Are the triangles connected in such a way as to present a view out from the dome or not. 166 */ 167 public boolean isInsideView() { 168 return insideView; 169 } 170 171 /** 172 * Rebuilds the dome with a new set of parameters. 173 * 174 * @param center the new center of the dome. 175 * @param planes the number of planes along the Z-axis. 176 * @param radialSamples the new number of radial samples of the dome. 177 * @param radius the new radius of the dome. 178 * @param insideView should the dome be set up to be viewed from the inside looking out. 179 */ 180 public void updateGeometry(Vector3f center, int planes, 181 int radialSamples, float radius, boolean insideView) { 182 this.insideView = insideView; 183 this.center = center != null ? center : new Vector3f(0, 0, 0); 184 this.planes = planes; 185 this.radialSamples = radialSamples; 186 this.radius = radius; 187 188 int vertCount = ((planes - 1) * (radialSamples + 1)) + 1; 189 190 // Allocate vertices, allocating one extra in each radial to get the 191 // correct texture coordinates 192 // setVertexCount(); 193 // setVertexBuffer(createVector3Buffer(getVertexCount())); 194 195 // allocate normals 196 // setNormalBuffer(createVector3Buffer(getVertexCount())); 197 198 // allocate texture coordinates 199 // getTextureCoords().set(0, new TexCoords(createVector2Buffer(getVertexCount()))); 200 201 FloatBuffer vb = BufferUtils.createVector3Buffer(vertCount); 202 FloatBuffer nb = BufferUtils.createVector3Buffer(vertCount); 203 FloatBuffer tb = BufferUtils.createVector2Buffer(vertCount); 204 setBuffer(Type.Position, 3, vb); 205 setBuffer(Type.Normal, 3, nb); 206 setBuffer(Type.TexCoord, 2, tb); 207 208 // generate geometry 209 float fInvRS = 1.0f / radialSamples; 210 float fYFactor = 1.0f / (planes - 1); 211 212 // Generate points on the unit circle to be used in computing the mesh 213 // points on a dome slice. 214 float[] afSin = new float[(radialSamples)]; 215 float[] afCos = new float[(radialSamples)]; 216 for (int iR = 0; iR < radialSamples; iR++) { 217 float fAngle = FastMath.TWO_PI * fInvRS * iR; 218 afCos[iR] = FastMath.cos(fAngle); 219 afSin[iR] = FastMath.sin(fAngle); 220 } 221 222 TempVars vars = TempVars.get(); 223 Vector3f tempVc = vars.vect3; 224 Vector3f tempVb = vars.vect2; 225 Vector3f tempVa = vars.vect1; 226 227 // generate the dome itself 228 int i = 0; 229 for (int iY = 0; iY < (planes - 1); iY++, i++) { 230 float fYFraction = fYFactor * iY; // in (0,1) 231 float fY = radius * fYFraction; 232 // compute center of slice 233 Vector3f kSliceCenter = tempVb.set(center); 234 kSliceCenter.y += fY; 235 236 // compute radius of slice 237 float fSliceRadius = FastMath.sqrt(FastMath.abs(radius * radius - fY * fY)); 238 239 // compute slice vertices 240 Vector3f kNormal; 241 int iSave = i; 242 for (int iR = 0; iR < radialSamples; iR++, i++) { 243 float fRadialFraction = iR * fInvRS; // in [0,1) 244 Vector3f kRadial = tempVc.set(afCos[iR], 0, afSin[iR]); 245 kRadial.mult(fSliceRadius, tempVa); 246 vb.put(kSliceCenter.x + tempVa.x).put( 247 kSliceCenter.y + tempVa.y).put( 248 kSliceCenter.z + tempVa.z); 249 250 BufferUtils.populateFromBuffer(tempVa, vb, i); 251 kNormal = tempVa.subtractLocal(center); 252 kNormal.normalizeLocal(); 253 if (insideView) { 254 nb.put(kNormal.x).put(kNormal.y).put(kNormal.z); 255 } else { 256 nb.put(-kNormal.x).put(-kNormal.y).put(-kNormal.z); 257 } 258 259 tb.put(fRadialFraction).put(fYFraction); 260 } 261 BufferUtils.copyInternalVector3(vb, iSave, i); 262 BufferUtils.copyInternalVector3(nb, iSave, i); 263 tb.put(1.0f).put(fYFraction); 264 } 265 266 vars.release(); 267 268 // pole 269 vb.put(center.x).put(center.y + radius).put(center.z); 270 nb.put(0).put(insideView ? 1 : -1).put(0); 271 tb.put(0.5f).put(1.0f); 272 273 // allocate connectivity 274 int triCount = (planes - 2) * radialSamples * 2 + radialSamples; 275 ShortBuffer ib = BufferUtils.createShortBuffer(3 * triCount); 276 setBuffer(Type.Index, 3, ib); 277 278 // generate connectivity 279 int index = 0; 280 // Generate only for middle planes 281 for (int plane = 1; plane < (planes - 1); plane++) { 282 int bottomPlaneStart = ((plane - 1) * (radialSamples + 1)); 283 int topPlaneStart = (plane * (radialSamples + 1)); 284 for (int sample = 0; sample < radialSamples; sample++, index += 6) { 285 if (insideView){ 286 ib.put((short) (bottomPlaneStart + sample)); 287 ib.put((short) (bottomPlaneStart + sample + 1)); 288 ib.put((short) (topPlaneStart + sample)); 289 ib.put((short) (bottomPlaneStart + sample + 1)); 290 ib.put((short) (topPlaneStart + sample + 1)); 291 ib.put((short) (topPlaneStart + sample)); 292 }else{ 293 ib.put((short) (bottomPlaneStart + sample)); 294 ib.put((short) (topPlaneStart + sample)); 295 ib.put((short) (bottomPlaneStart + sample + 1)); 296 ib.put((short) (bottomPlaneStart + sample + 1)); 297 ib.put((short) (topPlaneStart + sample)); 298 ib.put((short) (topPlaneStart + sample + 1)); 299 } 300 } 301 } 302 303 // pole triangles 304 int bottomPlaneStart = (planes - 2) * (radialSamples + 1); 305 for (int samples = 0; samples < radialSamples; samples++, index += 3) { 306 if (insideView){ 307 ib.put((short) (bottomPlaneStart + samples)); 308 ib.put((short) (bottomPlaneStart + samples + 1)); 309 ib.put((short) (vertCount - 1)); 310 }else{ 311 ib.put((short) (bottomPlaneStart + samples)); 312 ib.put((short) (vertCount - 1)); 313 ib.put((short) (bottomPlaneStart + samples + 1)); 314 } 315 } 316 317 updateBound(); 318 } 319 320 @Override 321 public void read(JmeImporter e) throws IOException { 322 super.read(e); 323 InputCapsule capsule = e.getCapsule(this); 324 planes = capsule.readInt("planes", 0); 325 radialSamples = capsule.readInt("radialSamples", 0); 326 radius = capsule.readFloat("radius", 0); 327 center = (Vector3f) capsule.readSavable("center", Vector3f.ZERO.clone()); 328 } 329 330 @Override 331 public void write(JmeExporter e) throws IOException { 332 super.write(e); 333 OutputCapsule capsule = e.getCapsule(this); 334 capsule.write(planes, "planes", 0); 335 capsule.write(radialSamples, "radialSamples", 0); 336 capsule.write(radius, "radius", 0); 337 capsule.write(center, "center", Vector3f.ZERO); 338 } 339 }