Home | History | Annotate | Download | only in shape
      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 }