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 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      */
     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      */
     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      */
     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 
     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 	 */
    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 	 */
    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 
    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      */
    268     public float getLength() {
    269     	return spline.getTotalLength();
    270     }
    271 }
    272