1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.opengl; 18 19 /** 20 * Matrix math utilities. These methods operate on OpenGL ES format 21 * matrices and vectors stored in float arrays. 22 * <p> 23 * Matrices are 4 x 4 column-vector matrices stored in column-major 24 * order: 25 * <pre> 26 * m[offset + 0] m[offset + 4] m[offset + 8] m[offset + 12] 27 * m[offset + 1] m[offset + 5] m[offset + 9] m[offset + 13] 28 * m[offset + 2] m[offset + 6] m[offset + 10] m[offset + 14] 29 * m[offset + 3] m[offset + 7] m[offset + 11] m[offset + 15]</pre> 30 * 31 * Vectors are 4 x 1 column vectors stored in order: 32 * <pre> 33 * v[offset + 0] 34 * v[offset + 1] 35 * v[offset + 2] 36 * v[offset + 3]</pre> 37 */ 38 public class Matrix { 39 40 /** Temporary memory for operations that need temporary matrix data. */ 41 private final static float[] sTemp = new float[32]; 42 43 /** 44 * @deprecated All methods are static, do not instantiate this class. 45 */ 46 @Deprecated 47 public Matrix() {} 48 49 /** 50 * Multiplies two 4x4 matrices together and stores the result in a third 4x4 51 * matrix. In matrix notation: result = lhs x rhs. Due to the way 52 * matrix multiplication works, the result matrix will have the same 53 * effect as first multiplying by the rhs matrix, then multiplying by 54 * the lhs matrix. This is the opposite of what you might expect. 55 * <p> 56 * The same float array may be passed for result, lhs, and/or rhs. However, 57 * the result element values are undefined if the result elements overlap 58 * either the lhs or rhs elements. 59 * 60 * @param result The float array that holds the result. 61 * @param resultOffset The offset into the result array where the result is 62 * stored. 63 * @param lhs The float array that holds the left-hand-side matrix. 64 * @param lhsOffset The offset into the lhs array where the lhs is stored 65 * @param rhs The float array that holds the right-hand-side matrix. 66 * @param rhsOffset The offset into the rhs array where the rhs is stored. 67 * 68 * @throws IllegalArgumentException if result, lhs, or rhs are null, or if 69 * resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or 70 * rhsOffset + 16 > rhs.length. 71 */ 72 public static native void multiplyMM(float[] result, int resultOffset, 73 float[] lhs, int lhsOffset, float[] rhs, int rhsOffset); 74 75 /** 76 * Multiplies a 4 element vector by a 4x4 matrix and stores the result in a 77 * 4-element column vector. In matrix notation: result = lhs x rhs 78 * <p> 79 * The same float array may be passed for resultVec, lhsMat, and/or rhsVec. 80 * However, the resultVec element values are undefined if the resultVec 81 * elements overlap either the lhsMat or rhsVec elements. 82 * 83 * @param resultVec The float array that holds the result vector. 84 * @param resultVecOffset The offset into the result array where the result 85 * vector is stored. 86 * @param lhsMat The float array that holds the left-hand-side matrix. 87 * @param lhsMatOffset The offset into the lhs array where the lhs is stored 88 * @param rhsVec The float array that holds the right-hand-side vector. 89 * @param rhsVecOffset The offset into the rhs vector where the rhs vector 90 * is stored. 91 * 92 * @throws IllegalArgumentException if resultVec, lhsMat, 93 * or rhsVec are null, or if resultVecOffset + 4 > resultVec.length 94 * or lhsMatOffset + 16 > lhsMat.length or 95 * rhsVecOffset + 4 > rhsVec.length. 96 */ 97 public static native void multiplyMV(float[] resultVec, 98 int resultVecOffset, float[] lhsMat, int lhsMatOffset, 99 float[] rhsVec, int rhsVecOffset); 100 101 /** 102 * Transposes a 4 x 4 matrix. 103 * <p> 104 * mTrans and m must not overlap. 105 * 106 * @param mTrans the array that holds the output transposed matrix 107 * @param mTransOffset an offset into mTrans where the transposed matrix is 108 * stored. 109 * @param m the input array 110 * @param mOffset an offset into m where the input matrix is stored. 111 */ 112 public static void transposeM(float[] mTrans, int mTransOffset, float[] m, 113 int mOffset) { 114 for (int i = 0; i < 4; i++) { 115 int mBase = i * 4 + mOffset; 116 mTrans[i + mTransOffset] = m[mBase]; 117 mTrans[i + 4 + mTransOffset] = m[mBase + 1]; 118 mTrans[i + 8 + mTransOffset] = m[mBase + 2]; 119 mTrans[i + 12 + mTransOffset] = m[mBase + 3]; 120 } 121 } 122 123 /** 124 * Inverts a 4 x 4 matrix. 125 * <p> 126 * mInv and m must not overlap. 127 * 128 * @param mInv the array that holds the output inverted matrix 129 * @param mInvOffset an offset into mInv where the inverted matrix is 130 * stored. 131 * @param m the input array 132 * @param mOffset an offset into m where the input matrix is stored. 133 * @return true if the matrix could be inverted, false if it could not. 134 */ 135 public static boolean invertM(float[] mInv, int mInvOffset, float[] m, 136 int mOffset) { 137 // Invert a 4 x 4 matrix using Cramer's Rule 138 139 // transpose matrix 140 final float src0 = m[mOffset + 0]; 141 final float src4 = m[mOffset + 1]; 142 final float src8 = m[mOffset + 2]; 143 final float src12 = m[mOffset + 3]; 144 145 final float src1 = m[mOffset + 4]; 146 final float src5 = m[mOffset + 5]; 147 final float src9 = m[mOffset + 6]; 148 final float src13 = m[mOffset + 7]; 149 150 final float src2 = m[mOffset + 8]; 151 final float src6 = m[mOffset + 9]; 152 final float src10 = m[mOffset + 10]; 153 final float src14 = m[mOffset + 11]; 154 155 final float src3 = m[mOffset + 12]; 156 final float src7 = m[mOffset + 13]; 157 final float src11 = m[mOffset + 14]; 158 final float src15 = m[mOffset + 15]; 159 160 // calculate pairs for first 8 elements (cofactors) 161 final float atmp0 = src10 * src15; 162 final float atmp1 = src11 * src14; 163 final float atmp2 = src9 * src15; 164 final float atmp3 = src11 * src13; 165 final float atmp4 = src9 * src14; 166 final float atmp5 = src10 * src13; 167 final float atmp6 = src8 * src15; 168 final float atmp7 = src11 * src12; 169 final float atmp8 = src8 * src14; 170 final float atmp9 = src10 * src12; 171 final float atmp10 = src8 * src13; 172 final float atmp11 = src9 * src12; 173 174 // calculate first 8 elements (cofactors) 175 final float dst0 = (atmp0 * src5 + atmp3 * src6 + atmp4 * src7) 176 - (atmp1 * src5 + atmp2 * src6 + atmp5 * src7); 177 final float dst1 = (atmp1 * src4 + atmp6 * src6 + atmp9 * src7) 178 - (atmp0 * src4 + atmp7 * src6 + atmp8 * src7); 179 final float dst2 = (atmp2 * src4 + atmp7 * src5 + atmp10 * src7) 180 - (atmp3 * src4 + atmp6 * src5 + atmp11 * src7); 181 final float dst3 = (atmp5 * src4 + atmp8 * src5 + atmp11 * src6) 182 - (atmp4 * src4 + atmp9 * src5 + atmp10 * src6); 183 final float dst4 = (atmp1 * src1 + atmp2 * src2 + atmp5 * src3) 184 - (atmp0 * src1 + atmp3 * src2 + atmp4 * src3); 185 final float dst5 = (atmp0 * src0 + atmp7 * src2 + atmp8 * src3) 186 - (atmp1 * src0 + atmp6 * src2 + atmp9 * src3); 187 final float dst6 = (atmp3 * src0 + atmp6 * src1 + atmp11 * src3) 188 - (atmp2 * src0 + atmp7 * src1 + atmp10 * src3); 189 final float dst7 = (atmp4 * src0 + atmp9 * src1 + atmp10 * src2) 190 - (atmp5 * src0 + atmp8 * src1 + atmp11 * src2); 191 192 // calculate pairs for second 8 elements (cofactors) 193 final float btmp0 = src2 * src7; 194 final float btmp1 = src3 * src6; 195 final float btmp2 = src1 * src7; 196 final float btmp3 = src3 * src5; 197 final float btmp4 = src1 * src6; 198 final float btmp5 = src2 * src5; 199 final float btmp6 = src0 * src7; 200 final float btmp7 = src3 * src4; 201 final float btmp8 = src0 * src6; 202 final float btmp9 = src2 * src4; 203 final float btmp10 = src0 * src5; 204 final float btmp11 = src1 * src4; 205 206 // calculate second 8 elements (cofactors) 207 final float dst8 = (btmp0 * src13 + btmp3 * src14 + btmp4 * src15) 208 - (btmp1 * src13 + btmp2 * src14 + btmp5 * src15); 209 final float dst9 = (btmp1 * src12 + btmp6 * src14 + btmp9 * src15) 210 - (btmp0 * src12 + btmp7 * src14 + btmp8 * src15); 211 final float dst10 = (btmp2 * src12 + btmp7 * src13 + btmp10 * src15) 212 - (btmp3 * src12 + btmp6 * src13 + btmp11 * src15); 213 final float dst11 = (btmp5 * src12 + btmp8 * src13 + btmp11 * src14) 214 - (btmp4 * src12 + btmp9 * src13 + btmp10 * src14); 215 final float dst12 = (btmp2 * src10 + btmp5 * src11 + btmp1 * src9 ) 216 - (btmp4 * src11 + btmp0 * src9 + btmp3 * src10); 217 final float dst13 = (btmp8 * src11 + btmp0 * src8 + btmp7 * src10) 218 - (btmp6 * src10 + btmp9 * src11 + btmp1 * src8 ); 219 final float dst14 = (btmp6 * src9 + btmp11 * src11 + btmp3 * src8 ) 220 - (btmp10 * src11 + btmp2 * src8 + btmp7 * src9 ); 221 final float dst15 = (btmp10 * src10 + btmp4 * src8 + btmp9 * src9 ) 222 - (btmp8 * src9 + btmp11 * src10 + btmp5 * src8 ); 223 224 // calculate determinant 225 final float det = 226 src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3; 227 228 if (det == 0.0f) { 229 return false; 230 } 231 232 // calculate matrix inverse 233 final float invdet = 1.0f / det; 234 mInv[ mInvOffset] = dst0 * invdet; 235 mInv[ 1 + mInvOffset] = dst1 * invdet; 236 mInv[ 2 + mInvOffset] = dst2 * invdet; 237 mInv[ 3 + mInvOffset] = dst3 * invdet; 238 239 mInv[ 4 + mInvOffset] = dst4 * invdet; 240 mInv[ 5 + mInvOffset] = dst5 * invdet; 241 mInv[ 6 + mInvOffset] = dst6 * invdet; 242 mInv[ 7 + mInvOffset] = dst7 * invdet; 243 244 mInv[ 8 + mInvOffset] = dst8 * invdet; 245 mInv[ 9 + mInvOffset] = dst9 * invdet; 246 mInv[10 + mInvOffset] = dst10 * invdet; 247 mInv[11 + mInvOffset] = dst11 * invdet; 248 249 mInv[12 + mInvOffset] = dst12 * invdet; 250 mInv[13 + mInvOffset] = dst13 * invdet; 251 mInv[14 + mInvOffset] = dst14 * invdet; 252 mInv[15 + mInvOffset] = dst15 * invdet; 253 254 return true; 255 } 256 257 /** 258 * Computes an orthographic projection matrix. 259 * 260 * @param m returns the result 261 * @param mOffset 262 * @param left 263 * @param right 264 * @param bottom 265 * @param top 266 * @param near 267 * @param far 268 */ 269 public static void orthoM(float[] m, int mOffset, 270 float left, float right, float bottom, float top, 271 float near, float far) { 272 if (left == right) { 273 throw new IllegalArgumentException("left == right"); 274 } 275 if (bottom == top) { 276 throw new IllegalArgumentException("bottom == top"); 277 } 278 if (near == far) { 279 throw new IllegalArgumentException("near == far"); 280 } 281 282 final float r_width = 1.0f / (right - left); 283 final float r_height = 1.0f / (top - bottom); 284 final float r_depth = 1.0f / (far - near); 285 final float x = 2.0f * (r_width); 286 final float y = 2.0f * (r_height); 287 final float z = -2.0f * (r_depth); 288 final float tx = -(right + left) * r_width; 289 final float ty = -(top + bottom) * r_height; 290 final float tz = -(far + near) * r_depth; 291 m[mOffset + 0] = x; 292 m[mOffset + 5] = y; 293 m[mOffset +10] = z; 294 m[mOffset +12] = tx; 295 m[mOffset +13] = ty; 296 m[mOffset +14] = tz; 297 m[mOffset +15] = 1.0f; 298 m[mOffset + 1] = 0.0f; 299 m[mOffset + 2] = 0.0f; 300 m[mOffset + 3] = 0.0f; 301 m[mOffset + 4] = 0.0f; 302 m[mOffset + 6] = 0.0f; 303 m[mOffset + 7] = 0.0f; 304 m[mOffset + 8] = 0.0f; 305 m[mOffset + 9] = 0.0f; 306 m[mOffset + 11] = 0.0f; 307 } 308 309 310 /** 311 * Defines a projection matrix in terms of six clip planes. 312 * 313 * @param m the float array that holds the output perspective matrix 314 * @param offset the offset into float array m where the perspective 315 * matrix data is written 316 * @param left 317 * @param right 318 * @param bottom 319 * @param top 320 * @param near 321 * @param far 322 */ 323 public static void frustumM(float[] m, int offset, 324 float left, float right, float bottom, float top, 325 float near, float far) { 326 if (left == right) { 327 throw new IllegalArgumentException("left == right"); 328 } 329 if (top == bottom) { 330 throw new IllegalArgumentException("top == bottom"); 331 } 332 if (near == far) { 333 throw new IllegalArgumentException("near == far"); 334 } 335 if (near <= 0.0f) { 336 throw new IllegalArgumentException("near <= 0.0f"); 337 } 338 if (far <= 0.0f) { 339 throw new IllegalArgumentException("far <= 0.0f"); 340 } 341 final float r_width = 1.0f / (right - left); 342 final float r_height = 1.0f / (top - bottom); 343 final float r_depth = 1.0f / (near - far); 344 final float x = 2.0f * (near * r_width); 345 final float y = 2.0f * (near * r_height); 346 final float A = (right + left) * r_width; 347 final float B = (top + bottom) * r_height; 348 final float C = (far + near) * r_depth; 349 final float D = 2.0f * (far * near * r_depth); 350 m[offset + 0] = x; 351 m[offset + 5] = y; 352 m[offset + 8] = A; 353 m[offset + 9] = B; 354 m[offset + 10] = C; 355 m[offset + 14] = D; 356 m[offset + 11] = -1.0f; 357 m[offset + 1] = 0.0f; 358 m[offset + 2] = 0.0f; 359 m[offset + 3] = 0.0f; 360 m[offset + 4] = 0.0f; 361 m[offset + 6] = 0.0f; 362 m[offset + 7] = 0.0f; 363 m[offset + 12] = 0.0f; 364 m[offset + 13] = 0.0f; 365 m[offset + 15] = 0.0f; 366 } 367 368 /** 369 * Defines a projection matrix in terms of a field of view angle, an 370 * aspect ratio, and z clip planes. 371 * 372 * @param m the float array that holds the perspective matrix 373 * @param offset the offset into float array m where the perspective 374 * matrix data is written 375 * @param fovy field of view in y direction, in degrees 376 * @param aspect width to height aspect ratio of the viewport 377 * @param zNear 378 * @param zFar 379 */ 380 public static void perspectiveM(float[] m, int offset, 381 float fovy, float aspect, float zNear, float zFar) { 382 float f = 1.0f / (float) Math.tan(fovy * (Math.PI / 360.0)); 383 float rangeReciprocal = 1.0f / (zNear - zFar); 384 385 m[offset + 0] = f / aspect; 386 m[offset + 1] = 0.0f; 387 m[offset + 2] = 0.0f; 388 m[offset + 3] = 0.0f; 389 390 m[offset + 4] = 0.0f; 391 m[offset + 5] = f; 392 m[offset + 6] = 0.0f; 393 m[offset + 7] = 0.0f; 394 395 m[offset + 8] = 0.0f; 396 m[offset + 9] = 0.0f; 397 m[offset + 10] = (zFar + zNear) * rangeReciprocal; 398 m[offset + 11] = -1.0f; 399 400 m[offset + 12] = 0.0f; 401 m[offset + 13] = 0.0f; 402 m[offset + 14] = 2.0f * zFar * zNear * rangeReciprocal; 403 m[offset + 15] = 0.0f; 404 } 405 406 /** 407 * Computes the length of a vector. 408 * 409 * @param x x coordinate of a vector 410 * @param y y coordinate of a vector 411 * @param z z coordinate of a vector 412 * @return the length of a vector 413 */ 414 public static float length(float x, float y, float z) { 415 return (float) Math.sqrt(x * x + y * y + z * z); 416 } 417 418 /** 419 * Sets matrix m to the identity matrix. 420 * 421 * @param sm returns the result 422 * @param smOffset index into sm where the result matrix starts 423 */ 424 public static void setIdentityM(float[] sm, int smOffset) { 425 for (int i=0 ; i<16 ; i++) { 426 sm[smOffset + i] = 0; 427 } 428 for(int i = 0; i < 16; i += 5) { 429 sm[smOffset + i] = 1.0f; 430 } 431 } 432 433 /** 434 * Scales matrix m by x, y, and z, putting the result in sm. 435 * <p> 436 * m and sm must not overlap. 437 * 438 * @param sm returns the result 439 * @param smOffset index into sm where the result matrix starts 440 * @param m source matrix 441 * @param mOffset index into m where the source matrix starts 442 * @param x scale factor x 443 * @param y scale factor y 444 * @param z scale factor z 445 */ 446 public static void scaleM(float[] sm, int smOffset, 447 float[] m, int mOffset, 448 float x, float y, float z) { 449 for (int i=0 ; i<4 ; i++) { 450 int smi = smOffset + i; 451 int mi = mOffset + i; 452 sm[ smi] = m[ mi] * x; 453 sm[ 4 + smi] = m[ 4 + mi] * y; 454 sm[ 8 + smi] = m[ 8 + mi] * z; 455 sm[12 + smi] = m[12 + mi]; 456 } 457 } 458 459 /** 460 * Scales matrix m in place by sx, sy, and sz. 461 * 462 * @param m matrix to scale 463 * @param mOffset index into m where the matrix starts 464 * @param x scale factor x 465 * @param y scale factor y 466 * @param z scale factor z 467 */ 468 public static void scaleM(float[] m, int mOffset, 469 float x, float y, float z) { 470 for (int i=0 ; i<4 ; i++) { 471 int mi = mOffset + i; 472 m[ mi] *= x; 473 m[ 4 + mi] *= y; 474 m[ 8 + mi] *= z; 475 } 476 } 477 478 /** 479 * Translates matrix m by x, y, and z, putting the result in tm. 480 * <p> 481 * m and tm must not overlap. 482 * 483 * @param tm returns the result 484 * @param tmOffset index into sm where the result matrix starts 485 * @param m source matrix 486 * @param mOffset index into m where the source matrix starts 487 * @param x translation factor x 488 * @param y translation factor y 489 * @param z translation factor z 490 */ 491 public static void translateM(float[] tm, int tmOffset, 492 float[] m, int mOffset, 493 float x, float y, float z) { 494 for (int i=0 ; i<12 ; i++) { 495 tm[tmOffset + i] = m[mOffset + i]; 496 } 497 for (int i=0 ; i<4 ; i++) { 498 int tmi = tmOffset + i; 499 int mi = mOffset + i; 500 tm[12 + tmi] = m[mi] * x + m[4 + mi] * y + m[8 + mi] * z + 501 m[12 + mi]; 502 } 503 } 504 505 /** 506 * Translates matrix m by x, y, and z in place. 507 * 508 * @param m matrix 509 * @param mOffset index into m where the matrix starts 510 * @param x translation factor x 511 * @param y translation factor y 512 * @param z translation factor z 513 */ 514 public static void translateM( 515 float[] m, int mOffset, 516 float x, float y, float z) { 517 for (int i=0 ; i<4 ; i++) { 518 int mi = mOffset + i; 519 m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z; 520 } 521 } 522 523 /** 524 * Rotates matrix m by angle a (in degrees) around the axis (x, y, z). 525 * <p> 526 * m and rm must not overlap. 527 * 528 * @param rm returns the result 529 * @param rmOffset index into rm where the result matrix starts 530 * @param m source matrix 531 * @param mOffset index into m where the source matrix starts 532 * @param a angle to rotate in degrees 533 * @param x X axis component 534 * @param y Y axis component 535 * @param z Z axis component 536 */ 537 public static void rotateM(float[] rm, int rmOffset, 538 float[] m, int mOffset, 539 float a, float x, float y, float z) { 540 synchronized(sTemp) { 541 setRotateM(sTemp, 0, a, x, y, z); 542 multiplyMM(rm, rmOffset, m, mOffset, sTemp, 0); 543 } 544 } 545 546 /** 547 * Rotates matrix m in place by angle a (in degrees) 548 * around the axis (x, y, z). 549 * 550 * @param m source matrix 551 * @param mOffset index into m where the matrix starts 552 * @param a angle to rotate in degrees 553 * @param x X axis component 554 * @param y Y axis component 555 * @param z Z axis component 556 */ 557 public static void rotateM(float[] m, int mOffset, 558 float a, float x, float y, float z) { 559 synchronized(sTemp) { 560 setRotateM(sTemp, 0, a, x, y, z); 561 multiplyMM(sTemp, 16, m, mOffset, sTemp, 0); 562 System.arraycopy(sTemp, 16, m, mOffset, 16); 563 } 564 } 565 566 /** 567 * Creates a matrix for rotation by angle a (in degrees) 568 * around the axis (x, y, z). 569 * <p> 570 * An optimized path will be used for rotation about a major axis 571 * (e.g. x=1.0f y=0.0f z=0.0f). 572 * 573 * @param rm returns the result 574 * @param rmOffset index into rm where the result matrix starts 575 * @param a angle to rotate in degrees 576 * @param x X axis component 577 * @param y Y axis component 578 * @param z Z axis component 579 */ 580 public static void setRotateM(float[] rm, int rmOffset, 581 float a, float x, float y, float z) { 582 rm[rmOffset + 3] = 0; 583 rm[rmOffset + 7] = 0; 584 rm[rmOffset + 11]= 0; 585 rm[rmOffset + 12]= 0; 586 rm[rmOffset + 13]= 0; 587 rm[rmOffset + 14]= 0; 588 rm[rmOffset + 15]= 1; 589 a *= (float) (Math.PI / 180.0f); 590 float s = (float) Math.sin(a); 591 float c = (float) Math.cos(a); 592 if (1.0f == x && 0.0f == y && 0.0f == z) { 593 rm[rmOffset + 5] = c; rm[rmOffset + 10]= c; 594 rm[rmOffset + 6] = s; rm[rmOffset + 9] = -s; 595 rm[rmOffset + 1] = 0; rm[rmOffset + 2] = 0; 596 rm[rmOffset + 4] = 0; rm[rmOffset + 8] = 0; 597 rm[rmOffset + 0] = 1; 598 } else if (0.0f == x && 1.0f == y && 0.0f == z) { 599 rm[rmOffset + 0] = c; rm[rmOffset + 10]= c; 600 rm[rmOffset + 8] = s; rm[rmOffset + 2] = -s; 601 rm[rmOffset + 1] = 0; rm[rmOffset + 4] = 0; 602 rm[rmOffset + 6] = 0; rm[rmOffset + 9] = 0; 603 rm[rmOffset + 5] = 1; 604 } else if (0.0f == x && 0.0f == y && 1.0f == z) { 605 rm[rmOffset + 0] = c; rm[rmOffset + 5] = c; 606 rm[rmOffset + 1] = s; rm[rmOffset + 4] = -s; 607 rm[rmOffset + 2] = 0; rm[rmOffset + 6] = 0; 608 rm[rmOffset + 8] = 0; rm[rmOffset + 9] = 0; 609 rm[rmOffset + 10]= 1; 610 } else { 611 float len = length(x, y, z); 612 if (1.0f != len) { 613 float recipLen = 1.0f / len; 614 x *= recipLen; 615 y *= recipLen; 616 z *= recipLen; 617 } 618 float nc = 1.0f - c; 619 float xy = x * y; 620 float yz = y * z; 621 float zx = z * x; 622 float xs = x * s; 623 float ys = y * s; 624 float zs = z * s; 625 rm[rmOffset + 0] = x*x*nc + c; 626 rm[rmOffset + 4] = xy*nc - zs; 627 rm[rmOffset + 8] = zx*nc + ys; 628 rm[rmOffset + 1] = xy*nc + zs; 629 rm[rmOffset + 5] = y*y*nc + c; 630 rm[rmOffset + 9] = yz*nc - xs; 631 rm[rmOffset + 2] = zx*nc - ys; 632 rm[rmOffset + 6] = yz*nc + xs; 633 rm[rmOffset + 10] = z*z*nc + c; 634 } 635 } 636 637 /** 638 * Converts Euler angles to a rotation matrix. 639 * 640 * @param rm returns the result 641 * @param rmOffset index into rm where the result matrix starts 642 * @param x angle of rotation, in degrees 643 * @param y angle of rotation, in degrees 644 * @param z angle of rotation, in degrees 645 */ 646 public static void setRotateEulerM(float[] rm, int rmOffset, 647 float x, float y, float z) { 648 x *= (float) (Math.PI / 180.0f); 649 y *= (float) (Math.PI / 180.0f); 650 z *= (float) (Math.PI / 180.0f); 651 float cx = (float) Math.cos(x); 652 float sx = (float) Math.sin(x); 653 float cy = (float) Math.cos(y); 654 float sy = (float) Math.sin(y); 655 float cz = (float) Math.cos(z); 656 float sz = (float) Math.sin(z); 657 float cxsy = cx * sy; 658 float sxsy = sx * sy; 659 660 rm[rmOffset + 0] = cy * cz; 661 rm[rmOffset + 1] = -cy * sz; 662 rm[rmOffset + 2] = sy; 663 rm[rmOffset + 3] = 0.0f; 664 665 rm[rmOffset + 4] = cxsy * cz + cx * sz; 666 rm[rmOffset + 5] = -cxsy * sz + cx * cz; 667 rm[rmOffset + 6] = -sx * cy; 668 rm[rmOffset + 7] = 0.0f; 669 670 rm[rmOffset + 8] = -sxsy * cz + sx * sz; 671 rm[rmOffset + 9] = sxsy * sz + sx * cz; 672 rm[rmOffset + 10] = cx * cy; 673 rm[rmOffset + 11] = 0.0f; 674 675 rm[rmOffset + 12] = 0.0f; 676 rm[rmOffset + 13] = 0.0f; 677 rm[rmOffset + 14] = 0.0f; 678 rm[rmOffset + 15] = 1.0f; 679 } 680 681 /** 682 * Defines a viewing transformation in terms of an eye point, a center of 683 * view, and an up vector. 684 * 685 * @param rm returns the result 686 * @param rmOffset index into rm where the result matrix starts 687 * @param eyeX eye point X 688 * @param eyeY eye point Y 689 * @param eyeZ eye point Z 690 * @param centerX center of view X 691 * @param centerY center of view Y 692 * @param centerZ center of view Z 693 * @param upX up vector X 694 * @param upY up vector Y 695 * @param upZ up vector Z 696 */ 697 public static void setLookAtM(float[] rm, int rmOffset, 698 float eyeX, float eyeY, float eyeZ, 699 float centerX, float centerY, float centerZ, float upX, float upY, 700 float upZ) { 701 702 // See the OpenGL GLUT documentation for gluLookAt for a description 703 // of the algorithm. We implement it in a straightforward way: 704 705 float fx = centerX - eyeX; 706 float fy = centerY - eyeY; 707 float fz = centerZ - eyeZ; 708 709 // Normalize f 710 float rlf = 1.0f / Matrix.length(fx, fy, fz); 711 fx *= rlf; 712 fy *= rlf; 713 fz *= rlf; 714 715 // compute s = f x up (x means "cross product") 716 float sx = fy * upZ - fz * upY; 717 float sy = fz * upX - fx * upZ; 718 float sz = fx * upY - fy * upX; 719 720 // and normalize s 721 float rls = 1.0f / Matrix.length(sx, sy, sz); 722 sx *= rls; 723 sy *= rls; 724 sz *= rls; 725 726 // compute u = s x f 727 float ux = sy * fz - sz * fy; 728 float uy = sz * fx - sx * fz; 729 float uz = sx * fy - sy * fx; 730 731 rm[rmOffset + 0] = sx; 732 rm[rmOffset + 1] = ux; 733 rm[rmOffset + 2] = -fx; 734 rm[rmOffset + 3] = 0.0f; 735 736 rm[rmOffset + 4] = sy; 737 rm[rmOffset + 5] = uy; 738 rm[rmOffset + 6] = -fy; 739 rm[rmOffset + 7] = 0.0f; 740 741 rm[rmOffset + 8] = sz; 742 rm[rmOffset + 9] = uz; 743 rm[rmOffset + 10] = -fz; 744 rm[rmOffset + 11] = 0.0f; 745 746 rm[rmOffset + 12] = 0.0f; 747 rm[rmOffset + 13] = 0.0f; 748 rm[rmOffset + 14] = 0.0f; 749 rm[rmOffset + 15] = 1.0f; 750 751 translateM(rm, rmOffset, -eyeX, -eyeY, -eyeZ); 752 } 753 } 754