OSDN Git Service

9a25a0cd8b999cc986f50ea76076f2a6733abaad
[mikumikustudio/MikuMikuStudio.git] / src / com / jme / scene / shape / PQTorus.java
1 /*
2  * Copyright (c) 2003-2009 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$
33 package com.jme.scene.shape;
34
35 import static com.jme.util.geom.BufferUtils.*;
36
37 import java.io.IOException;
38 import java.nio.IntBuffer;
39
40 import com.jme.math.FastMath;
41 import com.jme.math.Vector3f;
42 import com.jme.scene.TexCoords;
43 import com.jme.scene.TriMesh;
44 import com.jme.util.export.InputCapsule;
45 import com.jme.util.export.JMEExporter;
46 import com.jme.util.export.JMEImporter;
47 import com.jme.util.export.OutputCapsule;
48
49 /**
50  * A parameterized torus, also known as a <em>pq</em> torus.
51  * 
52  * @author Joshua Slack, Eric Woroshow
53  * @version $Revision$, $Date$
54  */
55 public class PQTorus extends TriMesh {
56
57     private static final long serialVersionUID = 1L;
58
59     private float p, q;
60
61     private float radius, width;
62
63     private int steps, radialSamples;
64
65     public PQTorus() {
66     }
67
68     /**
69      * Creates a parameterized torus.
70      * <p>
71      * Steps and radialSamples are both degree of accuracy values.
72      * 
73      * @param name the name of the torus.
74      * @param p the x/z oscillation.
75      * @param q the y oscillation.
76      * @param radius the radius of the PQTorus.
77      * @param width the width of the torus.
78      * @param steps the steps along the torus.
79      * @param radialSamples radial samples for the torus.
80      */
81     public PQTorus(String name, float p, float q, float radius, float width,
82             int steps, int radialSamples) {
83         super(name);
84         updateGeometry(p, q, radius, width, steps, radialSamples);
85     }
86
87     public float getP() {
88         return p;
89     }
90
91     public float getQ() {
92         return q;
93     }
94
95     public int getRadialSamples() {
96         return radialSamples;
97     }
98
99     public float getRadius() {
100         return radius;
101     }
102
103     public int getSteps() {
104         return steps;
105     }
106
107     public float getWidth() {
108         return width;
109     }
110
111     public void read(JMEImporter e) throws IOException {
112         super.read(e);
113         InputCapsule capsule = e.getCapsule(this);
114         p = capsule.readFloat("p", 0);
115         q = capsule.readFloat("q", 0);
116         radius = capsule.readFloat("radius", 0);
117         width = capsule.readFloat("width", 0);
118         steps = capsule.readInt("steps", 0);
119         radialSamples = capsule.readInt("radialSamples", 0);
120     }
121
122     /**
123      * Rebuilds this torus based on a new set of parameters.
124      * 
125      * @param p the x/z oscillation.
126      * @param q the y oscillation.
127      * @param radius the radius of the PQTorus.
128      * @param width the width of the torus.
129      * @param steps the steps along the torus.
130      * @param radialSamples radial samples for the torus.
131      */
132     public void updateGeometry(float p, float q, float radius, float width, int steps, int radialSamples) {
133         this.p = p;
134         this.q = q;
135         this.radius = radius;
136         this.width = width;
137         this.steps = steps;
138         this.radialSamples = radialSamples;
139
140         final float thetaStep = (FastMath.TWO_PI / steps);
141         final float betaStep = (FastMath.TWO_PI / radialSamples);
142         Vector3f[] torusPoints = new Vector3f[steps];
143
144         // Allocate all of the required buffers
145         setVertexCount(radialSamples * steps);
146         setVertexBuffer(createVector3Buffer(getVertexCount()));
147         setNormalBuffer(createVector3Buffer(getVertexCount()));
148         getTextureCoords().set(0, new TexCoords(createVector2Buffer(getVertexCount())));
149
150         Vector3f pointB = new Vector3f(), T = new Vector3f(), N = new Vector3f(), B = new Vector3f();
151         Vector3f tempNorm = new Vector3f();
152         float r, x, y, z, theta = 0.0f, beta = 0.0f;
153         int nvertex = 0;
154
155         // Move along the length of the pq torus
156         for (int i = 0; i < steps; i++) {
157             theta += thetaStep;
158             float circleFraction = ((float) i) / (float) steps;
159
160             // Find the point on the torus
161             r = (0.5f * (2.0f + FastMath.sin(q * theta)) * radius);
162             x = (r * FastMath.cos(p * theta) * radius);
163             y = (r * FastMath.sin(p * theta) * radius);
164             z = (r * FastMath.cos(q * theta) * radius);
165             torusPoints[i] = new Vector3f(x, y, z);
166
167             // Now find a point slightly farther along the torus
168             r = (0.5f * (2.0f + FastMath.sin(q * (theta + 0.01f))) * radius);
169             x = (r * FastMath.cos(p * (theta + 0.01f)) * radius);
170             y = (r * FastMath.sin(p * (theta + 0.01f)) * radius);
171             z = (r * FastMath.cos(q * (theta + 0.01f)) * radius);
172             pointB = new Vector3f(x, y, z);
173
174             // Approximate the Frenet Frame
175             T = pointB.subtract(torusPoints[i]);
176             N = torusPoints[i].add(pointB);
177             B = T.cross(N);
178             N = B.cross(T);
179
180             // Normalise the two vectors and then use them to create an oriented circle
181             N = N.normalize();
182             B = B.normalize();
183             beta = 0.0f;
184             for (int j = 0; j < radialSamples; j++, nvertex++) {
185                 beta += betaStep;
186                 float cx = FastMath.cos(beta) * width;
187                 float cy = FastMath.sin(beta) * width;
188                 float radialFraction = ((float) j) / radialSamples;
189                 tempNorm.x = (cx * N.x + cy * B.x);
190                 tempNorm.y = (cx * N.y + cy * B.y);
191                 tempNorm.z = (cx * N.z + cy * B.z);
192                 getNormalBuffer().put(tempNorm.x).put(tempNorm.y).put(tempNorm.z);
193                 tempNorm.addLocal(torusPoints[i]);
194                 getVertexBuffer().put(tempNorm.x).put(tempNorm.y).put(tempNorm.z);
195                 getTextureCoords().get(0).coords.put(radialFraction).put(circleFraction);
196             }
197         }
198
199         // Update the indices data
200         IntBuffer indices = createIntBuffer(6 * getVertexCount());
201         for (int i = 0; i < getVertexCount(); i++) {
202             indices.put(new int[] {
203                     i, i - radialSamples, i + 1, i + 1, i - radialSamples, i - radialSamples + 1
204             });
205         }
206         for (int i = 0, len = indices.capacity(); i < len; i++) {
207             int ind = indices.get(i);
208             if (ind < 0) {
209                 ind += getVertexCount();
210                 indices.put(i, ind);
211             } else if (ind >= getVertexCount()) {
212                 ind -= getVertexCount();
213                 indices.put(i, ind);
214             }
215         }
216         indices.rewind();
217         setIndexBuffer(indices);
218     }
219
220     public void write(JMEExporter e) throws IOException {
221         super.write(e);
222         OutputCapsule capsule = e.getCapsule(this);
223         capsule.write(p, "p", 0);
224         capsule.write(q, "q", 0);
225         capsule.write(radius, "radius", 0);
226         capsule.write(width, "width", 0);
227         capsule.write(steps, "steps", 0);
228         capsule.write(radialSamples, "radialSamples", 0);
229     }
230
231 }