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