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 package com.jme3.math; 34 35 import com.jme3.export.*; 36 import java.io.IOException; 37 38 /** 39 * Started Date: Jul 16, 2004<br><br> 40 * Represents a translation, rotation and scale in one object. 41 * 42 * @author Jack Lindamood 43 * @author Joshua Slack 44 */ 45 public final class Transform implements Savable, Cloneable, java.io.Serializable { 46 47 static final long serialVersionUID = 1; 48 49 public static final Transform IDENTITY = new Transform(); 50 51 private Quaternion rot = new Quaternion(); 52 private Vector3f translation = new Vector3f(); 53 private Vector3f scale = new Vector3f(1,1,1); 54 55 public Transform(Vector3f translation, Quaternion rot){ 56 this.translation.set(translation); 57 this.rot.set(rot); 58 } 59 60 public Transform(Vector3f translation, Quaternion rot, Vector3f scale){ 61 this(translation, rot); 62 this.scale.set(scale); 63 } 64 65 public Transform(Vector3f translation){ 66 this(translation, Quaternion.IDENTITY); 67 } 68 69 public Transform(Quaternion rot){ 70 this(Vector3f.ZERO, rot); 71 } 72 73 public Transform(){ 74 this(Vector3f.ZERO, Quaternion.IDENTITY); 75 } 76 77 /** 78 * Sets this rotation to the given Quaternion value. 79 * @param rot The new rotation for this matrix. 80 * @return this 81 */ 82 public Transform setRotation(Quaternion rot) { 83 this.rot.set(rot); 84 return this; 85 } 86 87 /** 88 * Sets this translation to the given value. 89 * @param trans The new translation for this matrix. 90 * @return this 91 */ 92 public Transform setTranslation(Vector3f trans) { 93 this.translation.set(trans); 94 return this; 95 } 96 97 /** 98 * Return the translation vector in this matrix. 99 * @return translation vector. 100 */ 101 public Vector3f getTranslation() { 102 return translation; 103 } 104 105 /** 106 * Sets this scale to the given value. 107 * @param scale The new scale for this matrix. 108 * @return this 109 */ 110 public Transform setScale(Vector3f scale) { 111 this.scale.set(scale); 112 return this; 113 } 114 115 /** 116 * Sets this scale to the given value. 117 * @param scale The new scale for this matrix. 118 * @return this 119 */ 120 public Transform setScale(float scale) { 121 this.scale.set(scale, scale, scale); 122 return this; 123 } 124 125 /** 126 * Return the scale vector in this matrix. 127 * @return scale vector. 128 */ 129 public Vector3f getScale() { 130 return scale; 131 } 132 133 /** 134 * Stores this translation value into the given vector3f. If trans is null, a new vector3f is created to 135 * hold the value. The value, once stored, is returned. 136 * @param trans The store location for this matrix's translation. 137 * @return The value of this matrix's translation. 138 */ 139 public Vector3f getTranslation(Vector3f trans) { 140 if (trans==null) trans=new Vector3f(); 141 trans.set(this.translation); 142 return trans; 143 } 144 145 /** 146 * Stores this rotation value into the given Quaternion. If quat is null, a new Quaternion is created to 147 * hold the value. The value, once stored, is returned. 148 * @param quat The store location for this matrix's rotation. 149 * @return The value of this matrix's rotation. 150 */ 151 public Quaternion getRotation(Quaternion quat) { 152 if (quat==null) quat=new Quaternion(); 153 quat.set(rot); 154 return quat; 155 } 156 157 /** 158 * Return the rotation quaternion in this matrix. 159 * @return rotation quaternion. 160 */ 161 public Quaternion getRotation() { 162 return rot; 163 } 164 165 /** 166 * Stores this scale value into the given vector3f. If scale is null, a new vector3f is created to 167 * hold the value. The value, once stored, is returned. 168 * @param scale The store location for this matrix's scale. 169 * @return The value of this matrix's scale. 170 */ 171 public Vector3f getScale(Vector3f scale) { 172 if (scale==null) scale=new Vector3f(); 173 scale.set(this.scale); 174 return scale; 175 } 176 177 /** 178 * Sets this matrix to the interpolation between the first matrix and the second by delta amount. 179 * @param t1 The begining transform. 180 * @param t2 The ending transform. 181 * @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2. 182 */ 183 public void interpolateTransforms(Transform t1, Transform t2, float delta) { 184 this.rot.slerp(t1.rot,t2.rot,delta); 185 this.translation.interpolate(t1.translation,t2.translation,delta); 186 this.scale.interpolate(t1.scale,t2.scale,delta); 187 } 188 189 /** 190 * Changes the values of this matrix acording to it's parent. Very similar to the concept of Node/Spatial transforms. 191 * @param parent The parent matrix. 192 * @return This matrix, after combining. 193 */ 194 public Transform combineWithParent(Transform parent) { 195 scale.multLocal(parent.scale); 196 // rot.multLocal(parent.rot); 197 parent.rot.mult(rot, rot); 198 199 // This here, is evil code 200 // parent 201 // .rot 202 // .multLocal(translation) 203 // .multLocal(parent.scale) 204 // .addLocal(parent.translation); 205 206 translation.multLocal(parent.scale); 207 parent 208 .rot 209 .multLocal(translation) 210 .addLocal(parent.translation); 211 return this; 212 } 213 214 /** 215 * Sets this matrix's translation to the given x,y,z values. 216 * @param x This matrix's new x translation. 217 * @param y This matrix's new y translation. 218 * @param z This matrix's new z translation. 219 * @return this 220 */ 221 public Transform setTranslation(float x,float y, float z) { 222 translation.set(x,y,z); 223 return this; 224 } 225 226 /** 227 * Sets this matrix's scale to the given x,y,z values. 228 * @param x This matrix's new x scale. 229 * @param y This matrix's new y scale. 230 * @param z This matrix's new z scale. 231 * @return this 232 */ 233 public Transform setScale(float x, float y, float z) { 234 scale.set(x,y,z); 235 return this; 236 } 237 238 public Vector3f transformVector(final Vector3f in, Vector3f store){ 239 if (store == null) 240 store = new Vector3f(); 241 242 // multiply with scale first, then rotate, finally translate (cf. 243 // Eberly) 244 return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation); 245 } 246 247 public Vector3f transformInverseVector(final Vector3f in, Vector3f store){ 248 if (store == null) 249 store = new Vector3f(); 250 251 // The author of this code should look above and take the inverse of that 252 // But for some reason, they didnt .. 253 // in.subtract(translation, store).divideLocal(scale); 254 // rot.inverse().mult(store, store); 255 256 in.subtract(translation, store); 257 rot.inverse().mult(store, store); 258 store.divideLocal(scale); 259 260 return store; 261 } 262 263 /** 264 * Loads the identity. Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1. 265 */ 266 public void loadIdentity() { 267 translation.set(0,0,0); 268 scale.set(1,1,1); 269 rot.set(0,0,0,1); 270 } 271 272 @Override 273 public String toString(){ 274 return getClass().getSimpleName() + "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n" 275 + "[ " + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "]\n" 276 + "[ " + scale.x + " , " + scale.y + ", " + scale.z + "]"; 277 } 278 279 /** 280 * Sets this matrix to be equal to the given matrix. 281 * @param matrixQuat The matrix to be equal to. 282 * @return this 283 */ 284 public Transform set(Transform matrixQuat) { 285 this.translation.set(matrixQuat.translation); 286 this.rot.set(matrixQuat.rot); 287 this.scale.set(matrixQuat.scale); 288 return this; 289 } 290 291 public void write(JmeExporter e) throws IOException { 292 OutputCapsule capsule = e.getCapsule(this); 293 capsule.write(rot, "rot", new Quaternion()); 294 capsule.write(translation, "translation", Vector3f.ZERO); 295 capsule.write(scale, "scale", Vector3f.UNIT_XYZ); 296 } 297 298 public void read(JmeImporter e) throws IOException { 299 InputCapsule capsule = e.getCapsule(this); 300 301 rot = (Quaternion)capsule.readSavable("rot", new Quaternion()); 302 translation = (Vector3f)capsule.readSavable("translation", Vector3f.ZERO); 303 scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ); 304 } 305 306 @Override 307 public Transform clone() { 308 try { 309 Transform tq = (Transform) super.clone(); 310 tq.rot = rot.clone(); 311 tq.scale = scale.clone(); 312 tq.translation = translation.clone(); 313 return tq; 314 } catch (CloneNotSupportedException e) { 315 throw new AssertionError(); 316 } 317 } 318 } 319