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 33 // $Id: Torus.java 4131 2009-03-19 20:15:28Z blaine.dev $ 34 package com.jme3.scene.shape; 35 36 import com.jme3.export.InputCapsule; 37 import com.jme3.export.JmeExporter; 38 import com.jme3.export.JmeImporter; 39 import com.jme3.export.OutputCapsule; 40 import com.jme3.math.FastMath; 41 import com.jme3.math.Vector3f; 42 import com.jme3.scene.Mesh; 43 import com.jme3.scene.VertexBuffer.Type; 44 import com.jme3.util.BufferUtils; 45 import java.io.IOException; 46 import java.nio.FloatBuffer; 47 import java.nio.ShortBuffer; 48 49 /** 50 * An ordinary (single holed) torus. 51 * <p> 52 * The center is by default the origin. 53 * 54 * @author Mark Powell 55 * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ 56 */ 57 public class Torus extends Mesh { 58 59 private int circleSamples; 60 61 private int radialSamples; 62 63 private float innerRadius; 64 65 private float outerRadius; 66 67 public Torus() { 68 } 69 70 /** 71 * Constructs a new Torus. Center is the origin, but the Torus may be 72 * transformed. 73 * 74 * @param circleSamples 75 * The number of samples along the circles. 76 * @param radialSamples 77 * The number of samples along the radial. 78 * @param innerRadius 79 * The radius of the inner begining of the Torus. 80 * @param outerRadius 81 * The radius of the outter end of the Torus. 82 */ 83 public Torus(int circleSamples, int radialSamples, 84 float innerRadius, float outerRadius) { 85 super(); 86 updateGeometry(circleSamples, radialSamples, innerRadius, outerRadius); 87 } 88 89 public int getCircleSamples() { 90 return circleSamples; 91 } 92 93 public float getInnerRadius() { 94 return innerRadius; 95 } 96 97 public float getOuterRadius() { 98 return outerRadius; 99 } 100 101 public int getRadialSamples() { 102 return radialSamples; 103 } 104 105 @Override 106 public void read(JmeImporter e) throws IOException { 107 super.read(e); 108 InputCapsule capsule = e.getCapsule(this); 109 circleSamples = capsule.readInt("circleSamples", 0); 110 radialSamples = capsule.readInt("radialSamples", 0); 111 innerRadius = capsule.readFloat("innerRadius", 0); 112 outerRadius = capsule.readFloat("outerRaidus", 0); 113 } 114 115 private void setGeometryData() { 116 // allocate vertices 117 int vertCount = (circleSamples + 1) * (radialSamples + 1); 118 FloatBuffer fpb = BufferUtils.createVector3Buffer(vertCount); 119 setBuffer(Type.Position, 3, fpb); 120 121 // allocate normals if requested 122 FloatBuffer fnb = BufferUtils.createVector3Buffer(vertCount); 123 setBuffer(Type.Normal, 3, fnb); 124 125 // allocate texture coordinates 126 FloatBuffer ftb = BufferUtils.createVector2Buffer(vertCount); 127 setBuffer(Type.TexCoord, 2, ftb); 128 129 // generate geometry 130 float inverseCircleSamples = 1.0f / circleSamples; 131 float inverseRadialSamples = 1.0f / radialSamples; 132 int i = 0; 133 // generate the cylinder itself 134 Vector3f radialAxis = new Vector3f(), torusMiddle = new Vector3f(), tempNormal = new Vector3f(); 135 for (int circleCount = 0; circleCount < circleSamples; circleCount++) { 136 // compute center point on torus circle at specified angle 137 float circleFraction = circleCount * inverseCircleSamples; 138 float theta = FastMath.TWO_PI * circleFraction; 139 float cosTheta = FastMath.cos(theta); 140 float sinTheta = FastMath.sin(theta); 141 radialAxis.set(cosTheta, sinTheta, 0); 142 radialAxis.mult(outerRadius, torusMiddle); 143 144 // compute slice vertices with duplication at end point 145 int iSave = i; 146 for (int radialCount = 0; radialCount < radialSamples; radialCount++) { 147 float radialFraction = radialCount * inverseRadialSamples; 148 // in [0,1) 149 float phi = FastMath.TWO_PI * radialFraction; 150 float cosPhi = FastMath.cos(phi); 151 float sinPhi = FastMath.sin(phi); 152 tempNormal.set(radialAxis).multLocal(cosPhi); 153 tempNormal.z += sinPhi; 154 fnb.put(tempNormal.x).put(tempNormal.y).put( 155 tempNormal.z); 156 157 tempNormal.multLocal(innerRadius).addLocal(torusMiddle); 158 fpb.put(tempNormal.x).put(tempNormal.y).put( 159 tempNormal.z); 160 161 ftb.put(radialFraction).put(circleFraction); 162 i++; 163 } 164 165 BufferUtils.copyInternalVector3(fpb, iSave, i); 166 BufferUtils.copyInternalVector3(fnb, iSave, i); 167 168 ftb.put(1.0f).put(circleFraction); 169 170 i++; 171 } 172 173 // duplicate the cylinder ends to form a torus 174 for (int iR = 0; iR <= radialSamples; iR++, i++) { 175 BufferUtils.copyInternalVector3(fpb, iR, i); 176 BufferUtils.copyInternalVector3(fnb, iR, i); 177 BufferUtils.copyInternalVector2(ftb, iR, i); 178 ftb.put(i * 2 + 1, 1.0f); 179 } 180 } 181 182 private void setIndexData() { 183 // allocate connectivity 184 int triCount = 2 * circleSamples * radialSamples; 185 186 ShortBuffer sib = BufferUtils.createShortBuffer(3 * triCount); 187 setBuffer(Type.Index, 3, sib); 188 189 int i; 190 // generate connectivity 191 int connectionStart = 0; 192 int index = 0; 193 for (int circleCount = 0; circleCount < circleSamples; circleCount++) { 194 int i0 = connectionStart; 195 int i1 = i0 + 1; 196 connectionStart += radialSamples + 1; 197 int i2 = connectionStart; 198 int i3 = i2 + 1; 199 for (i = 0; i < radialSamples; i++, index += 6) { 200 // if (true) { 201 sib.put((short)i0++); 202 sib.put((short)i2); 203 sib.put((short)i1); 204 sib.put((short)i1++); 205 sib.put((short)i2++); 206 sib.put((short)i3++); 207 208 // getIndexBuffer().put(i0++); 209 // getIndexBuffer().put(i2); 210 // getIndexBuffer().put(i1); 211 // getIndexBuffer().put(i1++); 212 // getIndexBuffer().put(i2++); 213 // getIndexBuffer().put(i3++); 214 // } else { 215 // getIndexBuffer().put(i0++); 216 // getIndexBuffer().put(i1); 217 // getIndexBuffer().put(i2); 218 // getIndexBuffer().put(i1++); 219 // getIndexBuffer().put(i3++); 220 // getIndexBuffer().put(i2++); 221 // } 222 } 223 } 224 } 225 226 /** 227 * Rebuilds this torus based on a new set of parameters. 228 * 229 * @param circleSamples the number of samples along the circles. 230 * @param radialSamples the number of samples along the radial. 231 * @param innerRadius the radius of the inner begining of the Torus. 232 * @param outerRadius the radius of the outter end of the Torus. 233 */ 234 public void updateGeometry(int circleSamples, int radialSamples, float innerRadius, float outerRadius) { 235 this.circleSamples = circleSamples; 236 this.radialSamples = radialSamples; 237 this.innerRadius = innerRadius; 238 this.outerRadius = outerRadius; 239 setGeometryData(); 240 setIndexData(); 241 updateBound(); 242 updateCounts(); 243 } 244 245 @Override 246 public void write(JmeExporter e) throws IOException { 247 super.write(e); 248 OutputCapsule capsule = e.getCapsule(this); 249 capsule.write(circleSamples, "circleSamples", 0); 250 capsule.write(radialSamples, "radialSamples", 0); 251 capsule.write(innerRadius, "innerRadius", 0); 252 capsule.write(outerRadius, "outerRadius", 0); 253 } 254 255 }