1/* 2 * Copyright (C) 2009-2012 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 17package android.renderscript; 18 19import java.lang.Math; 20import android.util.Log; 21 22 23/** 24 * Class for exposing the native RenderScript rs_matrix4x4 type back to the Android system. 25 * 26 **/ 27public class Matrix4f { 28 29 /** 30 * Creates a new identity 4x4 matrix 31 */ 32 public Matrix4f() { 33 mMat = new float[16]; 34 loadIdentity(); 35 } 36 37 /** 38 * Creates a new matrix and sets its values from the given 39 * parameter 40 * 41 * @param dataArray values to set the matrix to, must be 16 42 * floats long 43 */ 44 public Matrix4f(float[] dataArray) { 45 mMat = new float[16]; 46 System.arraycopy(dataArray, 0, mMat, 0, mMat.length); 47 } 48 49 /** 50 * Return a reference to the internal array representing matrix 51 * values. Modifying this array will also change the matrix 52 * 53 * @return internal array representing the matrix 54 */ 55 public float[] getArray() { 56 return mMat; 57 } 58 59 /** 60 * Returns the value for a given row and column 61 * 62 * @param x column of the value to return 63 * @param y row of the value to return 64 * 65 * @return value in the yth row and xth column 66 */ 67 public float get(int x, int y) { 68 return mMat[x*4 + y]; 69 } 70 71 /** 72 * Sets the value for a given row and column 73 * 74 * @param x column of the value to set 75 * @param y row of the value to set 76 */ 77 public void set(int x, int y, float v) { 78 mMat[x*4 + y] = v; 79 } 80 81 /** 82 * Sets the matrix values to identity 83 */ 84 public void loadIdentity() { 85 mMat[0] = 1; 86 mMat[1] = 0; 87 mMat[2] = 0; 88 mMat[3] = 0; 89 90 mMat[4] = 0; 91 mMat[5] = 1; 92 mMat[6] = 0; 93 mMat[7] = 0; 94 95 mMat[8] = 0; 96 mMat[9] = 0; 97 mMat[10] = 1; 98 mMat[11] = 0; 99 100 mMat[12] = 0; 101 mMat[13] = 0; 102 mMat[14] = 0; 103 mMat[15] = 1; 104 } 105 106 /** 107 * Sets the values of the matrix to those of the parameter 108 * 109 * @param src matrix to load the values from 110 */ 111 public void load(Matrix4f src) { 112 System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length); 113 } 114 115 /** 116 * Sets the values of the matrix to those of the parameter 117 * 118 * @param src matrix to load the values from 119 * @hide 120 */ 121 public void load(Matrix3f src) { 122 mMat[0] = src.mMat[0]; 123 mMat[1] = src.mMat[1]; 124 mMat[2] = src.mMat[2]; 125 mMat[3] = 0; 126 127 mMat[4] = src.mMat[3]; 128 mMat[5] = src.mMat[4]; 129 mMat[6] = src.mMat[5]; 130 mMat[7] = 0; 131 132 mMat[8] = src.mMat[6]; 133 mMat[9] = src.mMat[7]; 134 mMat[10] = src.mMat[8]; 135 mMat[11] = 0; 136 137 mMat[12] = 0; 138 mMat[13] = 0; 139 mMat[14] = 0; 140 mMat[15] = 1; 141 } 142 143 /** 144 * Sets current values to be a rotation matrix of certain angle 145 * about a given axis 146 * 147 * @param rot angle of rotation 148 * @param x rotation axis x 149 * @param y rotation axis y 150 * @param z rotation axis z 151 */ 152 public void loadRotate(float rot, float x, float y, float z) { 153 float c, s; 154 mMat[3] = 0; 155 mMat[7] = 0; 156 mMat[11]= 0; 157 mMat[12]= 0; 158 mMat[13]= 0; 159 mMat[14]= 0; 160 mMat[15]= 1; 161 rot *= (float)(java.lang.Math.PI / 180.0f); 162 c = (float)java.lang.Math.cos(rot); 163 s = (float)java.lang.Math.sin(rot); 164 165 float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z); 166 if (!(len != 1)) { 167 float recipLen = 1.f / len; 168 x *= recipLen; 169 y *= recipLen; 170 z *= recipLen; 171 } 172 float nc = 1.0f - c; 173 float xy = x * y; 174 float yz = y * z; 175 float zx = z * x; 176 float xs = x * s; 177 float ys = y * s; 178 float zs = z * s; 179 mMat[ 0] = x*x*nc + c; 180 mMat[ 4] = xy*nc - zs; 181 mMat[ 8] = zx*nc + ys; 182 mMat[ 1] = xy*nc + zs; 183 mMat[ 5] = y*y*nc + c; 184 mMat[ 9] = yz*nc - xs; 185 mMat[ 2] = zx*nc - ys; 186 mMat[ 6] = yz*nc + xs; 187 mMat[10] = z*z*nc + c; 188 } 189 190 /** 191 * Sets current values to be a scale matrix of given dimensions 192 * 193 * @param x scale component x 194 * @param y scale component y 195 * @param z scale component z 196 */ 197 public void loadScale(float x, float y, float z) { 198 loadIdentity(); 199 mMat[0] = x; 200 mMat[5] = y; 201 mMat[10] = z; 202 } 203 204 /** 205 * Sets current values to be a translation matrix of given 206 * dimensions 207 * 208 * @param x translation component x 209 * @param y translation component y 210 * @param z translation component z 211 */ 212 public void loadTranslate(float x, float y, float z) { 213 loadIdentity(); 214 mMat[12] = x; 215 mMat[13] = y; 216 mMat[14] = z; 217 } 218 219 /** 220 * Sets current values to be the result of multiplying two given 221 * matrices 222 * 223 * @param lhs left hand side matrix 224 * @param rhs right hand side matrix 225 */ 226 public void loadMultiply(Matrix4f lhs, Matrix4f rhs) { 227 for (int i=0 ; i<4 ; i++) { 228 float ri0 = 0; 229 float ri1 = 0; 230 float ri2 = 0; 231 float ri3 = 0; 232 for (int j=0 ; j<4 ; j++) { 233 float rhs_ij = rhs.get(i,j); 234 ri0 += lhs.get(j,0) * rhs_ij; 235 ri1 += lhs.get(j,1) * rhs_ij; 236 ri2 += lhs.get(j,2) * rhs_ij; 237 ri3 += lhs.get(j,3) * rhs_ij; 238 } 239 set(i,0, ri0); 240 set(i,1, ri1); 241 set(i,2, ri2); 242 set(i,3, ri3); 243 } 244 } 245 246 /** 247 * Set current values to be an orthographic projection matrix 248 * 249 * @param l location of the left vertical clipping plane 250 * @param r location of the right vertical clipping plane 251 * @param b location of the bottom horizontal clipping plane 252 * @param t location of the top horizontal clipping plane 253 * @param n location of the near clipping plane 254 * @param f location of the far clipping plane 255 */ 256 public void loadOrtho(float l, float r, float b, float t, float n, float f) { 257 loadIdentity(); 258 mMat[0] = 2 / (r - l); 259 mMat[5] = 2 / (t - b); 260 mMat[10]= -2 / (f - n); 261 mMat[12]= -(r + l) / (r - l); 262 mMat[13]= -(t + b) / (t - b); 263 mMat[14]= -(f + n) / (f - n); 264 } 265 266 /** 267 * Set current values to be an orthographic projection matrix 268 * with the right and bottom clipping planes set to the given 269 * values. Left and top clipping planes are set to 0. Near and 270 * far are set to -1, 1 respectively 271 * 272 * @param w location of the right vertical clipping plane 273 * @param h location of the bottom horizontal clipping plane 274 * 275 */ 276 public void loadOrthoWindow(int w, int h) { 277 loadOrtho(0,w, h,0, -1,1); 278 } 279 280 /** 281 * Sets current values to be a perspective projection matrix 282 * 283 * @param l location of the left vertical clipping plane 284 * @param r location of the right vertical clipping plane 285 * @param b location of the bottom horizontal clipping plane 286 * @param t location of the top horizontal clipping plane 287 * @param n location of the near clipping plane, must be positive 288 * @param f location of the far clipping plane, must be positive 289 * 290 */ 291 public void loadFrustum(float l, float r, float b, float t, float n, float f) { 292 loadIdentity(); 293 mMat[0] = 2 * n / (r - l); 294 mMat[5] = 2 * n / (t - b); 295 mMat[8] = (r + l) / (r - l); 296 mMat[9] = (t + b) / (t - b); 297 mMat[10]= -(f + n) / (f - n); 298 mMat[11]= -1; 299 mMat[14]= -2*f*n / (f - n); 300 mMat[15]= 0; 301 } 302 303 /** 304 * Sets current values to be a perspective projection matrix 305 * 306 * @param fovy vertical field of view angle in degrees 307 * @param aspect aspect ratio of the screen 308 * @param near near cliping plane, must be positive 309 * @param far far clipping plane, must be positive 310 */ 311 public void loadPerspective(float fovy, float aspect, float near, float far) { 312 float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f)); 313 float bottom = -top; 314 float left = bottom * aspect; 315 float right = top * aspect; 316 loadFrustum(left, right, bottom, top, near, far); 317 } 318 319 /** 320 * Helper function to set the current values to a perspective 321 * projection matrix with aspect ratio defined by the parameters 322 * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0 323 * 324 * @param w screen width 325 * @param h screen height 326 */ 327 public void loadProjectionNormalized(int w, int h) { 328 // range -1,1 in the narrow axis at z = 0. 329 Matrix4f m1 = new Matrix4f(); 330 Matrix4f m2 = new Matrix4f(); 331 332 if(w > h) { 333 float aspect = ((float)w) / h; 334 m1.loadFrustum(-aspect,aspect, -1,1, 1,100); 335 } else { 336 float aspect = ((float)h) / w; 337 m1.loadFrustum(-1,1, -aspect,aspect, 1,100); 338 } 339 340 m2.loadRotate(180, 0, 1, 0); 341 m1.loadMultiply(m1, m2); 342 343 m2.loadScale(-2, 2, 1); 344 m1.loadMultiply(m1, m2); 345 346 m2.loadTranslate(0, 0, 2); 347 m1.loadMultiply(m1, m2); 348 349 load(m1); 350 } 351 352 /** 353 * Post-multiplies the current matrix by a given parameter 354 * 355 * @param rhs right hand side to multiply by 356 */ 357 public void multiply(Matrix4f rhs) { 358 Matrix4f tmp = new Matrix4f(); 359 tmp.loadMultiply(this, rhs); 360 load(tmp); 361 } 362 /** 363 * Modifies the current matrix by post-multiplying it with a 364 * rotation matrix of certain angle about a given axis 365 * 366 * @param rot angle of rotation 367 * @param x rotation axis x 368 * @param y rotation axis y 369 * @param z rotation axis z 370 */ 371 public void rotate(float rot, float x, float y, float z) { 372 Matrix4f tmp = new Matrix4f(); 373 tmp.loadRotate(rot, x, y, z); 374 multiply(tmp); 375 } 376 377 /** 378 * Modifies the current matrix by post-multiplying it with a 379 * scale matrix of given dimensions 380 * 381 * @param x scale component x 382 * @param y scale component y 383 * @param z scale component z 384 */ 385 public void scale(float x, float y, float z) { 386 Matrix4f tmp = new Matrix4f(); 387 tmp.loadScale(x, y, z); 388 multiply(tmp); 389 } 390 391 /** 392 * Modifies the current matrix by post-multiplying it with a 393 * translation matrix of given dimensions 394 * 395 * @param x translation component x 396 * @param y translation component y 397 * @param z translation component z 398 */ 399 public void translate(float x, float y, float z) { 400 Matrix4f tmp = new Matrix4f(); 401 tmp.loadTranslate(x, y, z); 402 multiply(tmp); 403 } 404 private float computeCofactor(int i, int j) { 405 int c0 = (i+1) % 4; 406 int c1 = (i+2) % 4; 407 int c2 = (i+3) % 4; 408 int r0 = (j+1) % 4; 409 int r1 = (j+2) % 4; 410 int r2 = (j+3) % 4; 411 412 float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] - 413 mMat[c1 + 4*r2] * mMat[c2 + 4*r1])) 414 - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] - 415 mMat[c1 + 4*r2] * mMat[c2 + 4*r0])) 416 + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] - 417 mMat[c1 + 4*r1] * mMat[c2 + 4*r0])); 418 419 float cofactor = ((i+j) & 1) != 0 ? -minor : minor; 420 return cofactor; 421 } 422 423 /** 424 * Sets the current matrix to its inverse 425 */ 426 public boolean inverse() { 427 428 Matrix4f result = new Matrix4f(); 429 430 for (int i = 0; i < 4; ++i) { 431 for (int j = 0; j < 4; ++j) { 432 result.mMat[4*i + j] = computeCofactor(i, j); 433 } 434 } 435 436 // Dot product of 0th column of source and 0th row of result 437 float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] + 438 mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3]; 439 440 if (Math.abs(det) < 1e-6) { 441 return false; 442 } 443 444 det = 1.0f / det; 445 for (int i = 0; i < 16; ++i) { 446 mMat[i] = result.mMat[i] * det; 447 } 448 449 return true; 450 } 451 452 /** 453 * Sets the current matrix to its inverse transpose 454 */ 455 public boolean inverseTranspose() { 456 457 Matrix4f result = new Matrix4f(); 458 459 for (int i = 0; i < 4; ++i) { 460 for (int j = 0; j < 4; ++j) { 461 result.mMat[4*j + i] = computeCofactor(i, j); 462 } 463 } 464 465 float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] + 466 mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12]; 467 468 if (Math.abs(det) < 1e-6) { 469 return false; 470 } 471 472 det = 1.0f / det; 473 for (int i = 0; i < 16; ++i) { 474 mMat[i] = result.mMat[i] * det; 475 } 476 477 return true; 478 } 479 480 /** 481 * Sets the current matrix to its transpose 482 */ 483 public void transpose() { 484 for(int i = 0; i < 3; ++i) { 485 for(int j = i + 1; j < 4; ++j) { 486 float temp = mMat[i*4 + j]; 487 mMat[i*4 + j] = mMat[j*4 + i]; 488 mMat[j*4 + i] = temp; 489 } 490 } 491 } 492 493 final float[] mMat; 494} 495