• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
Dome()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      */
Dome(int planes, int radialSamples, float radius)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      */
Dome(Vector3f center, int planes, int radialSamples, float radius)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      */
Dome(Vector3f center, int planes, int radialSamples, float radius, boolean insideView)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 
getCenter()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      */
getPlanes()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      */
getRadialSamples()153     public int getRadialSamples() {
154         return radialSamples;
155     }
156 
157     /**
158      * Get the radius of the dome.
159      */
getRadius()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      */
isInsideView()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      */
updateGeometry(Vector3f center, int planes, int radialSamples, float radius, boolean insideView)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
read(JmeImporter e)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
write(JmeExporter e)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 }