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 package com.jme3.scene.shape; 33 34 import com.jme3.math.Spline; 35 import com.jme3.math.Vector3f; 36 import com.jme3.scene.Mesh; 37 import com.jme3.scene.VertexBuffer; 38 import java.util.Iterator; 39 import java.util.List; 40 41 /** 42 * A <code>Curve</code> is a visual, line-based representation of a {@link Spline}. 43 * The underlying Spline will be sampled N times where N is the number of 44 * segments as specified in the constructor. Each segment will represent 45 * one line in the generated mesh. 46 * 47 * @author Nehon 48 */ 49 public class Curve extends Mesh { 50 51 private Spline spline; 52 private Vector3f temp = new Vector3f(); 53 54 /** 55 * Serialization only. Do not use. 56 */ Curve()57 public Curve(){ 58 } 59 60 /** 61 * Create a curve mesh. 62 * Use a CatmullRom spline model that does not cycle. 63 * 64 * @param controlPoints the control points to use to create this curve 65 * @param nbSubSegments the number of subsegments between the control points 66 */ Curve(Vector3f[] controlPoints, int nbSubSegments)67 public Curve(Vector3f[] controlPoints, int nbSubSegments) { 68 this(new Spline(Spline.SplineType.CatmullRom, controlPoints, 10, false), nbSubSegments); 69 } 70 71 /** 72 * Create a curve mesh from a Spline 73 * 74 * @param spline the spline to use 75 * @param nbSubSegments the number of subsegments between the control points 76 */ Curve(Spline spline, int nbSubSegments)77 public Curve(Spline spline, int nbSubSegments) { 78 super(); 79 this.spline = spline; 80 switch (spline.getType()) { 81 case CatmullRom: 82 this.createCatmullRomMesh(nbSubSegments); 83 break; 84 case Bezier: 85 this.createBezierMesh(nbSubSegments); 86 break; 87 case Nurb: 88 this.createNurbMesh(nbSubSegments); 89 break; 90 case Linear: 91 default: 92 this.createLinearMesh(); 93 break; 94 } 95 } 96 createCatmullRomMesh(int nbSubSegments)97 private void createCatmullRomMesh(int nbSubSegments) { 98 float[] array = new float[((spline.getControlPoints().size() - 1) * nbSubSegments + 1) * 3]; 99 short[] indices = new short[(spline.getControlPoints().size() - 1) * nbSubSegments * 2]; 100 int i = 0; 101 int cptCP = 0; 102 for (Iterator<Vector3f> it = spline.getControlPoints().iterator(); it.hasNext();) { 103 Vector3f vector3f = it.next(); 104 array[i] = vector3f.x; 105 i++; 106 array[i] = vector3f.y; 107 i++; 108 array[i] = vector3f.z; 109 i++; 110 if (it.hasNext()) { 111 for (int j = 1; j < nbSubSegments; j++) { 112 spline.interpolate((float) j / nbSubSegments, cptCP, temp); 113 array[i] = temp.getX(); 114 i++; 115 array[i] = temp.getY(); 116 i++; 117 array[i] = temp.getZ(); 118 i++; 119 } 120 } 121 cptCP++; 122 } 123 124 i = 0; 125 int k = 0; 126 for (int j = 0; j < (spline.getControlPoints().size() - 1) * nbSubSegments; j++) { 127 k = j; 128 indices[i] = (short) k; 129 i++; 130 k++; 131 indices[i] = (short) k; 132 i++; 133 } 134 135 this.setMode(Mesh.Mode.Lines); 136 this.setBuffer(VertexBuffer.Type.Position, 3, array); 137 this.setBuffer(VertexBuffer.Type.Index, 2, indices);//(spline.getControlPoints().size() - 1) * nbSubSegments * 2 138 this.updateBound(); 139 this.updateCounts(); 140 } 141 142 /** 143 * This method creates the Bezier path for this curve. 144 * 145 * @param nbSubSegments 146 * amount of subsegments between position control points 147 */ createBezierMesh(int nbSubSegments)148 private void createBezierMesh(int nbSubSegments) { 149 if(nbSubSegments==0) { 150 nbSubSegments = 1; 151 } 152 int centerPointsAmount = (spline.getControlPoints().size() + 2) / 3; 153 154 //calculating vertices 155 float[] array = new float[((centerPointsAmount - 1) * nbSubSegments + 1) * 3]; 156 int currentControlPoint = 0; 157 List<Vector3f> controlPoints = spline.getControlPoints(); 158 int lineIndex = 0; 159 for (int i = 0; i < centerPointsAmount - 1; ++i) { 160 Vector3f vector3f = controlPoints.get(currentControlPoint); 161 array[lineIndex++] = vector3f.x; 162 array[lineIndex++] = vector3f.y; 163 array[lineIndex++] = vector3f.z; 164 for (int j = 1; j < nbSubSegments; ++j) { 165 spline.interpolate((float) j / nbSubSegments, currentControlPoint, temp); 166 array[lineIndex++] = temp.getX(); 167 array[lineIndex++] = temp.getY(); 168 array[lineIndex++] = temp.getZ(); 169 } 170 currentControlPoint += 3; 171 } 172 Vector3f vector3f = controlPoints.get(currentControlPoint); 173 array[lineIndex++] = vector3f.x; 174 array[lineIndex++] = vector3f.y; 175 array[lineIndex++] = vector3f.z; 176 177 //calculating indexes 178 int i = 0, k = 0; 179 short[] indices = new short[(centerPointsAmount - 1) * nbSubSegments << 1]; 180 for (int j = 0; j < (centerPointsAmount - 1) * nbSubSegments; ++j) { 181 k = j; 182 indices[i++] = (short) k; 183 ++k; 184 indices[i++] = (short) k; 185 } 186 187 this.setMode(Mesh.Mode.Lines); 188 this.setBuffer(VertexBuffer.Type.Position, 3, array); 189 this.setBuffer(VertexBuffer.Type.Index, 2, indices); 190 this.updateBound(); 191 this.updateCounts(); 192 } 193 194 /** 195 * This method creates the Nurb path for this curve. 196 * @param nbSubSegments 197 * amount of subsegments between position control points 198 */ createNurbMesh(int nbSubSegments)199 private void createNurbMesh(int nbSubSegments) { 200 float minKnot = spline.getMinNurbKnot(); 201 float maxKnot = spline.getMaxNurbKnot(); 202 float deltaU = (maxKnot - minKnot)/nbSubSegments; 203 204 float[] array = new float[(nbSubSegments + 1) * 3]; 205 206 float u = minKnot; 207 Vector3f interpolationResult = new Vector3f(); 208 for(int i=0;i<array.length;i+=3) { 209 spline.interpolate(u, 0, interpolationResult); 210 array[i] = interpolationResult.x; 211 array[i + 1] = interpolationResult.y; 212 array[i + 2] = interpolationResult.z; 213 u += deltaU; 214 } 215 216 //calculating indexes 217 int i = 0; 218 short[] indices = new short[nbSubSegments << 1]; 219 for (int j = 0; j < nbSubSegments; ++j) { 220 indices[i++] = (short) j; 221 indices[i++] = (short) (j + 1); 222 } 223 224 this.setMode(Mesh.Mode.Lines); 225 this.setBuffer(VertexBuffer.Type.Position, 3, array); 226 this.setBuffer(VertexBuffer.Type.Index, 2, indices); 227 this.updateBound(); 228 this.updateCounts(); 229 } 230 createLinearMesh()231 private void createLinearMesh() { 232 float[] array = new float[spline.getControlPoints().size() * 3]; 233 short[] indices = new short[(spline.getControlPoints().size() - 1) * 2]; 234 int i = 0; 235 int cpt = 0; 236 int k = 0; 237 int j = 0; 238 for (Iterator<Vector3f> it = spline.getControlPoints().iterator(); it.hasNext();) { 239 Vector3f vector3f = it.next(); 240 array[i] = vector3f.getX(); 241 i++; 242 array[i] = vector3f.getY(); 243 i++; 244 array[i] = vector3f.getZ(); 245 i++; 246 if (it.hasNext()) { 247 k = j; 248 indices[cpt] = (short) k; 249 cpt++; 250 k++; 251 indices[cpt] = (short) k; 252 cpt++; 253 j++; 254 } 255 } 256 257 this.setMode(Mesh.Mode.Lines); 258 this.setBuffer(VertexBuffer.Type.Position, 3, array); 259 this.setBuffer(VertexBuffer.Type.Index, 2, indices); 260 this.updateBound(); 261 this.updateCounts(); 262 } 263 264 /** 265 * This method returns the length of the curve. 266 * @return the length of the curve 267 */ getLength()268 public float getLength() { 269 return spline.getTotalLength(); 270 } 271 } 272