1 /* libs/opengles/matrix.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include <stdlib.h> 19 #include <stdio.h> 20 21 #include "context.h" 22 #include "fp.h" 23 #include "state.h" 24 #include "matrix.h" 25 #include "vertex.h" 26 #include "light.h" 27 28 #if defined(__arm__) && defined(__thumb__) 29 #warning "matrix.cpp should not be compiled in thumb on ARM." 30 #endif 31 32 #define I(_i, _j) ((_j)+ 4*(_i)) 33 34 namespace android { 35 36 // ---------------------------------------------------------------------------- 37 38 static const GLfloat gIdentityf[16] = { 1,0,0,0, 39 0,1,0,0, 40 0,0,1,0, 41 0,0,0,1 }; 42 43 static const matrixx_t gIdentityx = { 44 { 0x10000,0,0,0, 45 0,0x10000,0,0, 46 0,0,0x10000,0, 47 0,0,0,0x10000 48 } 49 }; 50 51 static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o); 52 static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o); 53 static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o); 54 static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o); 55 static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o); 56 static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o); 57 static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o); 58 static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o); 59 static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o); 60 61 // ---------------------------------------------------------------------------- 62 #if 0 63 #pragma mark - 64 #endif 65 66 void ogles_init_matrix(ogles_context_t* c) 67 { 68 c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH); 69 c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH); 70 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) 71 c->transforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH); 72 73 c->transforms.current = &c->transforms.modelview; 74 c->transforms.matrixMode = GL_MODELVIEW; 75 c->transforms.dirty = transform_state_t::VIEWPORT | 76 transform_state_t::MVUI | 77 transform_state_t::MVIT | 78 transform_state_t::MVP; 79 c->transforms.mvp.loadIdentity(); 80 c->transforms.mvp4.loadIdentity(); 81 c->transforms.mvit4.loadIdentity(); 82 c->transforms.mvui.loadIdentity(); 83 c->transforms.vpt.loadIdentity(); 84 c->transforms.vpt.zNear = 0.0f; 85 c->transforms.vpt.zFar = 1.0f; 86 } 87 88 void ogles_uninit_matrix(ogles_context_t* c) 89 { 90 c->transforms.modelview.uninit(); 91 c->transforms.projection.uninit(); 92 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) 93 c->transforms.texture[i].uninit(); 94 } 95 96 static void validate_perspective(ogles_context_t* c, vertex_t* v) 97 { 98 const uint32_t enables = c->rasterizer.state.enables; 99 c->arrays.perspective = (c->clipPlanes.enable) ? 100 ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D; 101 if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) { 102 c->arrays.perspective = ogles_vertex_perspective3DZ; 103 if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG)) 104 c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ; 105 } 106 if ((c->arrays.vertex.size != 4) && 107 (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) { 108 c->arrays.perspective = ogles_vertex_perspective2D; 109 } 110 c->arrays.perspective(c, v); 111 } 112 113 void ogles_invalidate_perspective(ogles_context_t* c) 114 { 115 c->arrays.perspective = validate_perspective; 116 } 117 118 void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want) 119 { 120 int dirty = c->transforms.dirty & want; 121 122 // Validate the modelview 123 if (dirty & transform_state_t::MODELVIEW) { 124 c->transforms.modelview.validate(); 125 } 126 127 // Validate the projection stack (in fact, it's never needed) 128 if (dirty & transform_state_t::PROJECTION) { 129 c->transforms.projection.validate(); 130 } 131 132 // Validate the viewport transformation 133 if (dirty & transform_state_t::VIEWPORT) { 134 vp_transform_t& vpt = c->transforms.vpt; 135 vpt.transform.matrix.load(vpt.matrix); 136 vpt.transform.picker(); 137 } 138 139 // We need to update the mvp (used to transform each vertex) 140 if (dirty & transform_state_t::MVP) { 141 c->transforms.update_mvp(); 142 // invalidate perspective (divide by W) and view volume clipping 143 ogles_invalidate_perspective(c); 144 } 145 146 // Validate the mvui (for normal transformation) 147 if (dirty & transform_state_t::MVUI) { 148 c->transforms.update_mvui(); 149 ogles_invalidate_lighting_mvui(c); 150 } 151 152 // Validate the texture stack 153 if (dirty & transform_state_t::TEXTURE) { 154 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) 155 c->transforms.texture[i].validate(); 156 } 157 158 // Validate the mvit4 (user-clip planes) 159 if (dirty & transform_state_t::MVIT) { 160 c->transforms.update_mvit(); 161 } 162 163 c->transforms.dirty &= ~want; 164 } 165 166 // ---------------------------------------------------------------------------- 167 #if 0 168 #pragma mark - 169 #pragma mark transform_t 170 #endif 171 172 void transform_t::loadIdentity() { 173 matrix = gIdentityx; 174 flags = 0; 175 ops = OP_IDENTITY; 176 point2 = point2__nop; 177 point3 = point3__nop; 178 point4 = point4__nop; 179 } 180 181 182 static inline 183 int notZero(GLfixed v) { 184 return abs(v) & ~0x3; 185 } 186 187 static inline 188 int notOne(GLfixed v) { 189 return notZero(v - 0x10000); 190 } 191 192 void transform_t::picker() 193 { 194 const GLfixed* const m = matrix.m; 195 196 // XXX: picker needs to be smarter 197 flags = 0; 198 ops = OP_ALL; 199 point2 = point2__generic; 200 point3 = point3__generic; 201 point4 = point4__generic; 202 203 // find out if this is a 2D projection 204 if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) { 205 flags |= FLAGS_2D_PROJECTION; 206 } 207 } 208 209 void mvui_transform_t::picker() 210 { 211 flags = 0; 212 ops = OP_ALL; 213 point3 = point3__mvui; 214 point4 = point4__mvui; 215 } 216 217 void transform_t::dump(const char* what) 218 { 219 GLfixed const * const m = matrix.m; 220 LOGD("%s:", what); 221 for (int i=0 ; i<4 ; i++) 222 LOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n", 223 m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)], 224 fixedToFloat(m[I(0,i)]), 225 fixedToFloat(m[I(1,i)]), 226 fixedToFloat(m[I(2,i)]), 227 fixedToFloat(m[I(3,i)])); 228 } 229 230 // ---------------------------------------------------------------------------- 231 #if 0 232 #pragma mark - 233 #pragma mark matrixx_t 234 #endif 235 236 void matrixx_t::load(const matrixf_t& rhs) { 237 GLfixed* xp = m; 238 GLfloat const* fp = rhs.elements(); 239 unsigned int i = 16; 240 do { 241 const GLfloat f = *fp++; 242 *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f); 243 } while (--i); 244 } 245 246 // ---------------------------------------------------------------------------- 247 #if 0 248 #pragma mark - 249 #pragma mark matrixf_t 250 #endif 251 252 void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs) 253 { 254 GLfloat const* const m = lhs.m; 255 for (int i=0 ; i<4 ; i++) { 256 register const float rhs_i0 = rhs.m[ I(i,0) ]; 257 register float ri0 = m[ I(0,0) ] * rhs_i0; 258 register float ri1 = m[ I(0,1) ] * rhs_i0; 259 register float ri2 = m[ I(0,2) ] * rhs_i0; 260 register float ri3 = m[ I(0,3) ] * rhs_i0; 261 for (int j=1 ; j<4 ; j++) { 262 register const float rhs_ij = rhs.m[ I(i,j) ]; 263 ri0 += m[ I(j,0) ] * rhs_ij; 264 ri1 += m[ I(j,1) ] * rhs_ij; 265 ri2 += m[ I(j,2) ] * rhs_ij; 266 ri3 += m[ I(j,3) ] * rhs_ij; 267 } 268 r.m[ I(i,0) ] = ri0; 269 r.m[ I(i,1) ] = ri1; 270 r.m[ I(i,2) ] = ri2; 271 r.m[ I(i,3) ] = ri3; 272 } 273 } 274 275 void matrixf_t::dump(const char* what) { 276 LOGD("%s", what); 277 LOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]); 278 LOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]); 279 LOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]); 280 LOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]); 281 } 282 283 void matrixf_t::loadIdentity() { 284 memcpy(m, gIdentityf, sizeof(m)); 285 } 286 287 void matrixf_t::set(const GLfixed* rhs) { 288 load(rhs); 289 } 290 291 void matrixf_t::set(const GLfloat* rhs) { 292 load(rhs); 293 } 294 295 void matrixf_t::load(const GLfixed* rhs) { 296 GLfloat* fp = m; 297 unsigned int i = 16; 298 do { 299 *fp++ = fixedToFloat(*rhs++); 300 } while (--i); 301 } 302 303 void matrixf_t::load(const GLfloat* rhs) { 304 memcpy(m, rhs, sizeof(m)); 305 } 306 307 void matrixf_t::load(const matrixf_t& rhs) { 308 operator = (rhs); 309 } 310 311 void matrixf_t::multiply(const matrixf_t& rhs) { 312 matrixf_t r; 313 multiply(r, *this, rhs); 314 operator = (r); 315 } 316 317 void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) { 318 for (int i=0 ; i<4 ; i++) { 319 m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z; 320 } 321 } 322 323 void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) { 324 for (int i=0 ; i<4 ; i++) { 325 m[ i] *= x; 326 m[4+i] *= y; 327 m[8+i] *= z; 328 } 329 } 330 331 void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z) 332 { 333 matrixf_t rotation; 334 GLfloat* r = rotation.m; 335 GLfloat c, s; 336 r[3] = 0; r[7] = 0; r[11]= 0; 337 r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1; 338 a *= GLfloat(M_PI / 180.0f); 339 sincosf(a, &s, &c); 340 if (isOnef(x) && isZerof(y) && isZerof(z)) { 341 r[5] = c; r[10]= c; 342 r[6] = s; r[9] = -s; 343 r[1] = 0; r[2] = 0; 344 r[4] = 0; r[8] = 0; 345 r[0] = 1; 346 } else if (isZerof(x) && isOnef(y) && isZerof(z)) { 347 r[0] = c; r[10]= c; 348 r[8] = s; r[2] = -s; 349 r[1] = 0; r[4] = 0; 350 r[6] = 0; r[9] = 0; 351 r[5] = 1; 352 } else if (isZerof(x) && isZerof(y) && isOnef(z)) { 353 r[0] = c; r[5] = c; 354 r[1] = s; r[4] = -s; 355 r[2] = 0; r[6] = 0; 356 r[8] = 0; r[9] = 0; 357 r[10]= 1; 358 } else { 359 const GLfloat len = sqrtf(x*x + y*y + z*z); 360 if (!isOnef(len)) { 361 const GLfloat recipLen = reciprocalf(len); 362 x *= recipLen; 363 y *= recipLen; 364 z *= recipLen; 365 } 366 const GLfloat nc = 1.0f - c; 367 const GLfloat xy = x * y; 368 const GLfloat yz = y * z; 369 const GLfloat zx = z * x; 370 const GLfloat xs = x * s; 371 const GLfloat ys = y * s; 372 const GLfloat zs = z * s; 373 r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys; 374 r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs; 375 r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c; 376 } 377 multiply(rotation); 378 } 379 380 // ---------------------------------------------------------------------------- 381 #if 0 382 #pragma mark - 383 #pragma mark matrix_stack_t 384 #endif 385 386 void matrix_stack_t::init(int depth) { 387 stack = new matrixf_t[depth]; 388 ops = new uint8_t[depth]; 389 maxDepth = depth; 390 depth = 0; 391 dirty = 0; 392 loadIdentity(); 393 } 394 395 void matrix_stack_t::uninit() { 396 delete [] stack; 397 delete [] ops; 398 } 399 400 void matrix_stack_t::loadIdentity() { 401 transform.loadIdentity(); 402 stack[depth].loadIdentity(); 403 ops[depth] = OP_IDENTITY; 404 } 405 406 void matrix_stack_t::load(const GLfixed* rhs) 407 { 408 memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m)); 409 stack[depth].load(rhs); 410 ops[depth] = OP_ALL; // TODO: we should look at the matrix 411 } 412 413 void matrix_stack_t::load(const GLfloat* rhs) 414 { 415 stack[depth].load(rhs); 416 ops[depth] = OP_ALL; // TODO: we should look at the matrix 417 } 418 419 void matrix_stack_t::multiply(const matrixf_t& rhs) 420 { 421 stack[depth].multiply(rhs); 422 ops[depth] = OP_ALL; // TODO: we should look at the matrix 423 } 424 425 void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z) 426 { 427 stack[depth].translate(x,y,z); 428 ops[depth] |= OP_TRANSLATE; 429 } 430 431 void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z) 432 { 433 stack[depth].scale(x,y,z); 434 if (x==y && y==z) { 435 ops[depth] |= OP_UNIFORM_SCALE; 436 } else { 437 ops[depth] |= OP_SCALE; 438 } 439 } 440 441 void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z) 442 { 443 stack[depth].rotate(a,x,y,z); 444 ops[depth] |= OP_ROTATE; 445 } 446 447 void matrix_stack_t::validate() 448 { 449 if (dirty & DO_FLOAT_TO_FIXED) { 450 transform.matrix.load(top()); 451 } 452 if (dirty & DO_PICKER) { 453 transform.picker(); 454 } 455 dirty = 0; 456 } 457 458 GLint matrix_stack_t::push() 459 { 460 if (depth >= (maxDepth-1)) { 461 return GL_STACK_OVERFLOW; 462 } 463 stack[depth+1] = stack[depth]; 464 ops[depth+1] = ops[depth]; 465 depth++; 466 return 0; 467 } 468 469 GLint matrix_stack_t::pop() 470 { 471 if (depth == 0) { 472 return GL_STACK_UNDERFLOW; 473 } 474 depth--; 475 return 0; 476 } 477 478 // ---------------------------------------------------------------------------- 479 #if 0 480 #pragma mark - 481 #pragma mark vp_transform_t 482 #endif 483 484 void vp_transform_t::loadIdentity() { 485 transform.loadIdentity(); 486 matrix.loadIdentity(); 487 } 488 489 // ---------------------------------------------------------------------------- 490 #if 0 491 #pragma mark - 492 #pragma mark transform_state_t 493 #endif 494 495 void transform_state_t::invalidate() 496 { 497 switch (matrixMode) { 498 case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break; 499 case GL_PROJECTION: dirty |= PROJECTION | MVP; break; 500 case GL_TEXTURE: dirty |= TEXTURE | MVP; break; 501 } 502 current->dirty = matrix_stack_t::DO_PICKER | 503 matrix_stack_t::DO_FLOAT_TO_FIXED; 504 } 505 506 void transform_state_t::update_mvp() 507 { 508 matrixf_t temp_mvp; 509 matrixf_t::multiply(temp_mvp, projection.top(), modelview.top()); 510 mvp4.matrix.load(temp_mvp); 511 mvp4.picker(); 512 513 if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) { 514 // the mvp matrix doesn't transform W, in this case we can 515 // premultiply it with the viewport transformation. In addition to 516 // being more efficient, this is also much more accurate and in fact 517 // is needed for 2D drawing with a resulting 1:1 mapping. 518 matrixf_t mvpv; 519 matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp); 520 mvp.matrix.load(mvpv); 521 mvp.picker(); 522 } else { 523 mvp = mvp4; 524 } 525 } 526 527 static inline 528 GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { 529 return a*d - b*c; 530 } 531 532 static inline 533 GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { 534 return b*c - a*d; 535 } 536 537 static __attribute__((noinline)) 538 void invert(GLfloat* inverse, const GLfloat* src) 539 { 540 double t; 541 int i, j, k, swap; 542 GLfloat tmp[4][4]; 543 544 memcpy(inverse, gIdentityf, sizeof(gIdentityf)); 545 memcpy(tmp, src, sizeof(GLfloat)*16); 546 547 for (i = 0; i < 4; i++) { 548 // look for largest element in column 549 swap = i; 550 for (j = i + 1; j < 4; j++) { 551 if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { 552 swap = j; 553 } 554 } 555 556 if (swap != i) { 557 /* swap rows. */ 558 for (k = 0; k < 4; k++) { 559 t = tmp[i][k]; 560 tmp[i][k] = tmp[swap][k]; 561 tmp[swap][k] = t; 562 563 t = inverse[i*4+k]; 564 inverse[i*4+k] = inverse[swap*4+k]; 565 inverse[swap*4+k] = t; 566 } 567 } 568 569 t = 1.0f / tmp[i][i]; 570 for (k = 0; k < 4; k++) { 571 tmp[i][k] *= t; 572 inverse[i*4+k] *= t; 573 } 574 for (j = 0; j < 4; j++) { 575 if (j != i) { 576 t = tmp[j][i]; 577 for (k = 0; k < 4; k++) { 578 tmp[j][k] -= tmp[i][k]*t; 579 inverse[j*4+k] -= inverse[i*4+k]*t; 580 } 581 } 582 } 583 } 584 } 585 586 void transform_state_t::update_mvit() 587 { 588 GLfloat r[16]; 589 const GLfloat* const mv = modelview.top().elements(); 590 invert(r, mv); 591 // convert to fixed-point and transpose 592 GLfixed* const x = mvit4.matrix.m; 593 for (int i=0 ; i<4 ; i++) 594 for (int j=0 ; j<4 ; j++) 595 x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); 596 mvit4.picker(); 597 } 598 599 void transform_state_t::update_mvui() 600 { 601 GLfloat r[16]; 602 const GLfloat* const mv = modelview.top().elements(); 603 604 /* 605 When evaluating the lighting equation in eye-space, normals 606 are transformed by the upper 3x3 modelview inverse-transpose. 607 http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html 608 609 (note that inverse-transpose is distributive). 610 Also note that: 611 l(obj) = inv(modelview).l(eye) for local light 612 l(obj) = tr(modelview).l(eye) for infinite light 613 */ 614 615 invert(r, mv); 616 617 GLfixed* const x = mvui.matrix.m; 618 619 #if OBJECT_SPACE_LIGHTING 620 for (int i=0 ; i<4 ; i++) 621 for (int j=0 ; j<4 ; j++) 622 x[I(i,j)] = gglFloatToFixed(r[I(i,j)]); 623 #else 624 for (int i=0 ; i<4 ; i++) 625 for (int j=0 ; j<4 ; j++) 626 x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); 627 #endif 628 629 mvui.picker(); 630 } 631 632 633 // ---------------------------------------------------------------------------- 634 // transformation and matrices API 635 // ---------------------------------------------------------------------------- 636 #if 0 637 #pragma mark - 638 #pragma mark transformation and matrices API 639 #endif 640 641 int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y) 642 { 643 c->viewport.surfaceport.x = x; 644 c->viewport.surfaceport.y = y; 645 646 ogles_viewport(c, 647 c->viewport.x, 648 c->viewport.y, 649 c->viewport.w, 650 c->viewport.h); 651 652 ogles_scissor(c, 653 c->viewport.scissor.x, 654 c->viewport.scissor.y, 655 c->viewport.scissor.w, 656 c->viewport.scissor.h); 657 658 return 0; 659 } 660 661 void ogles_scissor(ogles_context_t* c, 662 GLint x, GLint y, GLsizei w, GLsizei h) 663 { 664 if ((w|h) < 0) { 665 ogles_error(c, GL_INVALID_VALUE); 666 return; 667 } 668 c->viewport.scissor.x = x; 669 c->viewport.scissor.y = y; 670 c->viewport.scissor.w = w; 671 c->viewport.scissor.h = h; 672 673 x += c->viewport.surfaceport.x; 674 y += c->viewport.surfaceport.y; 675 676 y = c->rasterizer.state.buffers.color.height - (y + h); 677 c->rasterizer.procs.scissor(c, x, y, w, h); 678 } 679 680 void ogles_viewport(ogles_context_t* c, 681 GLint x, GLint y, GLsizei w, GLsizei h) 682 { 683 if ((w|h)<0) { 684 ogles_error(c, GL_INVALID_VALUE); 685 return; 686 } 687 688 c->viewport.x = x; 689 c->viewport.y = y; 690 c->viewport.w = w; 691 c->viewport.h = h; 692 693 x += c->viewport.surfaceport.x; 694 y += c->viewport.surfaceport.y; 695 696 GLint H = c->rasterizer.state.buffers.color.height; 697 GLfloat sx = div2f(w); 698 GLfloat ox = sx + x; 699 GLfloat sy = div2f(h); 700 GLfloat oy = sy - y + (H - h); 701 702 GLfloat near = c->transforms.vpt.zNear; 703 GLfloat far = c->transforms.vpt.zFar; 704 GLfloat A = div2f(far - near); 705 GLfloat B = div2f(far + near); 706 707 // compute viewport matrix 708 GLfloat* const f = c->transforms.vpt.matrix.editElements(); 709 f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox; 710 f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy; 711 f[2] = 0; f[6] = 0; f[10] = A; f[14] = B; 712 f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1; 713 c->transforms.dirty |= transform_state_t::VIEWPORT; 714 if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) 715 c->transforms.dirty |= transform_state_t::MVP; 716 } 717 718 // ---------------------------------------------------------------------------- 719 #if 0 720 #pragma mark - 721 #pragma mark matrix * vertex 722 #endif 723 724 void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { 725 const GLfixed* const m = mx->matrix.m; 726 const GLfixed rx = rhs->x; 727 const GLfixed ry = rhs->y; 728 lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]); 729 lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]); 730 lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]); 731 lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]); 732 } 733 734 void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { 735 const GLfixed* const m = mx->matrix.m; 736 const GLfixed rx = rhs->x; 737 const GLfixed ry = rhs->y; 738 const GLfixed rz = rhs->z; 739 lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); 740 lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); 741 lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); 742 lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); 743 } 744 745 void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { 746 const GLfixed* const m = mx->matrix.m; 747 const GLfixed rx = rhs->x; 748 const GLfixed ry = rhs->y; 749 const GLfixed rz = rhs->z; 750 const GLfixed rw = rhs->w; 751 lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); 752 lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); 753 lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); 754 lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]); 755 } 756 757 void point3__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { 758 // this is used for transforming light positions back to object space. 759 // w is used as a switch for directional lights, so we need 760 // to preserve it. 761 const GLfixed* const m = mx->matrix.m; 762 const GLfixed rx = rhs->x; 763 const GLfixed ry = rhs->y; 764 const GLfixed rz = rhs->z; 765 lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]); 766 lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]); 767 lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]); 768 lhs->w = 0; 769 } 770 771 void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { 772 // this is used for transforming light positions back to object space. 773 // w is used as a switch for directional lights, so we need 774 // to preserve it. 775 const GLfixed* const m = mx->matrix.m; 776 const GLfixed rx = rhs->x; 777 const GLfixed ry = rhs->y; 778 const GLfixed rz = rhs->z; 779 const GLfixed rw = rhs->w; 780 lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); 781 lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); 782 lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); 783 lhs->w = rw; 784 } 785 786 void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { 787 lhs->z = 0; 788 lhs->w = 0x10000; 789 if (lhs != rhs) { 790 lhs->x = rhs->x; 791 lhs->y = rhs->y; 792 } 793 } 794 795 void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { 796 lhs->w = 0x10000; 797 if (lhs != rhs) { 798 lhs->x = rhs->x; 799 lhs->y = rhs->y; 800 lhs->z = rhs->z; 801 } 802 } 803 804 void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { 805 if (lhs != rhs) 806 *lhs = *rhs; 807 } 808 809 810 static void frustumf( 811 GLfloat left, GLfloat right, 812 GLfloat bottom, GLfloat top, 813 GLfloat zNear, GLfloat zFar, 814 ogles_context_t* c) 815 { 816 if (cmpf(left,right) || 817 cmpf(top, bottom) || 818 cmpf(zNear, zFar) || 819 isZeroOrNegativef(zNear) || 820 isZeroOrNegativef(zFar)) 821 { 822 ogles_error(c, GL_INVALID_VALUE); 823 return; 824 } 825 const GLfloat r_width = reciprocalf(right - left); 826 const GLfloat r_height = reciprocalf(top - bottom); 827 const GLfloat r_depth = reciprocalf(zNear - zFar); 828 const GLfloat x = mul2f(zNear * r_width); 829 const GLfloat y = mul2f(zNear * r_height); 830 const GLfloat A = mul2f((right + left) * r_width); 831 const GLfloat B = (top + bottom) * r_height; 832 const GLfloat C = (zFar + zNear) * r_depth; 833 const GLfloat D = mul2f(zFar * zNear * r_depth); 834 GLfloat f[16]; 835 f[ 0] = x; 836 f[ 5] = y; 837 f[ 8] = A; 838 f[ 9] = B; 839 f[10] = C; 840 f[14] = D; 841 f[11] = -1.0f; 842 f[ 1] = f[ 2] = f[ 3] = 843 f[ 4] = f[ 6] = f[ 7] = 844 f[12] = f[13] = f[15] = 0.0f; 845 846 matrixf_t rhs; 847 rhs.set(f); 848 c->transforms.current->multiply(rhs); 849 c->transforms.invalidate(); 850 } 851 852 static void orthof( 853 GLfloat left, GLfloat right, 854 GLfloat bottom, GLfloat top, 855 GLfloat zNear, GLfloat zFar, 856 ogles_context_t* c) 857 { 858 if (cmpf(left,right) || 859 cmpf(top, bottom) || 860 cmpf(zNear, zFar)) 861 { 862 ogles_error(c, GL_INVALID_VALUE); 863 return; 864 } 865 const GLfloat r_width = reciprocalf(right - left); 866 const GLfloat r_height = reciprocalf(top - bottom); 867 const GLfloat r_depth = reciprocalf(zFar - zNear); 868 const GLfloat x = mul2f(r_width); 869 const GLfloat y = mul2f(r_height); 870 const GLfloat z = -mul2f(r_depth); 871 const GLfloat tx = -(right + left) * r_width; 872 const GLfloat ty = -(top + bottom) * r_height; 873 const GLfloat tz = -(zFar + zNear) * r_depth; 874 GLfloat f[16]; 875 f[ 0] = x; 876 f[ 5] = y; 877 f[10] = z; 878 f[12] = tx; 879 f[13] = ty; 880 f[14] = tz; 881 f[15] = 1.0f; 882 f[ 1] = f[ 2] = f[ 3] = 883 f[ 4] = f[ 6] = f[ 7] = 884 f[ 8] = f[ 9] = f[11] = 0.0f; 885 matrixf_t rhs; 886 rhs.set(f); 887 c->transforms.current->multiply(rhs); 888 c->transforms.invalidate(); 889 } 890 891 static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c) 892 { 893 zNear = clampToZerof(zNear > 1 ? 1 : zNear); 894 zFar = clampToZerof(zFar > 1 ? 1 : zFar); 895 GLfloat* const f = c->transforms.vpt.matrix.editElements(); 896 f[10] = div2f(zFar - zNear); 897 f[14] = div2f(zFar + zNear); 898 c->transforms.dirty |= transform_state_t::VIEWPORT; 899 c->transforms.vpt.zNear = zNear; 900 c->transforms.vpt.zFar = zFar; 901 } 902 903 904 // ---------------------------------------------------------------------------- 905 }; // namespace android 906 907 using namespace android; 908 909 void glMatrixMode(GLenum mode) 910 { 911 ogles_context_t* c = ogles_context_t::get(); 912 matrix_stack_t* stack = 0; 913 switch (mode) { 914 case GL_MODELVIEW: 915 stack = &c->transforms.modelview; 916 break; 917 case GL_PROJECTION: 918 stack = &c->transforms.projection; 919 break; 920 case GL_TEXTURE: 921 stack = &c->transforms.texture[c->textures.active]; 922 break; 923 default: 924 ogles_error(c, GL_INVALID_ENUM); 925 return; 926 } 927 c->transforms.matrixMode = mode; 928 c->transforms.current = stack; 929 } 930 931 void glLoadIdentity() 932 { 933 ogles_context_t* c = ogles_context_t::get(); 934 c->transforms.current->loadIdentity(); // also loads the GLfixed transform 935 c->transforms.invalidate(); 936 c->transforms.current->dirty = 0; 937 } 938 939 void glLoadMatrixf(const GLfloat* m) 940 { 941 ogles_context_t* c = ogles_context_t::get(); 942 c->transforms.current->load(m); 943 c->transforms.invalidate(); 944 } 945 946 void glLoadMatrixx(const GLfixed* m) 947 { 948 ogles_context_t* c = ogles_context_t::get(); 949 c->transforms.current->load(m); // also loads the GLfixed transform 950 c->transforms.invalidate(); 951 c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED; 952 } 953 954 void glMultMatrixf(const GLfloat* m) 955 { 956 ogles_context_t* c = ogles_context_t::get(); 957 matrixf_t rhs; 958 rhs.set(m); 959 c->transforms.current->multiply(rhs); 960 c->transforms.invalidate(); 961 } 962 963 void glMultMatrixx(const GLfixed* m) 964 { 965 ogles_context_t* c = ogles_context_t::get(); 966 matrixf_t rhs; 967 rhs.set(m); 968 c->transforms.current->multiply(rhs); 969 c->transforms.invalidate(); 970 } 971 972 void glPopMatrix() 973 { 974 ogles_context_t* c = ogles_context_t::get(); 975 GLint err = c->transforms.current->pop(); 976 if (ggl_unlikely(err)) { 977 ogles_error(c, err); 978 return; 979 } 980 c->transforms.invalidate(); 981 } 982 983 void glPushMatrix() 984 { 985 ogles_context_t* c = ogles_context_t::get(); 986 GLint err = c->transforms.current->push(); 987 if (ggl_unlikely(err)) { 988 ogles_error(c, err); 989 return; 990 } 991 c->transforms.invalidate(); 992 } 993 994 void glFrustumf( 995 GLfloat left, GLfloat right, 996 GLfloat bottom, GLfloat top, 997 GLfloat zNear, GLfloat zFar) 998 { 999 ogles_context_t* c = ogles_context_t::get(); 1000 frustumf(left, right, bottom, top, zNear, zFar, c); 1001 } 1002 1003 void glFrustumx( 1004 GLfixed left, GLfixed right, 1005 GLfixed bottom, GLfixed top, 1006 GLfixed zNear, GLfixed zFar) 1007 { 1008 ogles_context_t* c = ogles_context_t::get(); 1009 frustumf( fixedToFloat(left), fixedToFloat(right), 1010 fixedToFloat(bottom), fixedToFloat(top), 1011 fixedToFloat(zNear), fixedToFloat(zFar), 1012 c); 1013 } 1014 1015 void glOrthof( 1016 GLfloat left, GLfloat right, 1017 GLfloat bottom, GLfloat top, 1018 GLfloat zNear, GLfloat zFar) 1019 { 1020 ogles_context_t* c = ogles_context_t::get(); 1021 orthof(left, right, bottom, top, zNear, zFar, c); 1022 } 1023 1024 void glOrthox( 1025 GLfixed left, GLfixed right, 1026 GLfixed bottom, GLfixed top, 1027 GLfixed zNear, GLfixed zFar) 1028 { 1029 ogles_context_t* c = ogles_context_t::get(); 1030 orthof( fixedToFloat(left), fixedToFloat(right), 1031 fixedToFloat(bottom), fixedToFloat(top), 1032 fixedToFloat(zNear), fixedToFloat(zFar), 1033 c); 1034 } 1035 1036 void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z) 1037 { 1038 ogles_context_t* c = ogles_context_t::get(); 1039 c->transforms.current->rotate(a, x, y, z); 1040 c->transforms.invalidate(); 1041 } 1042 1043 void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z) 1044 { 1045 ogles_context_t* c = ogles_context_t::get(); 1046 c->transforms.current->rotate( 1047 fixedToFloat(a), fixedToFloat(x), 1048 fixedToFloat(y), fixedToFloat(z)); 1049 c->transforms.invalidate(); 1050 } 1051 1052 void glScalef(GLfloat x, GLfloat y, GLfloat z) 1053 { 1054 ogles_context_t* c = ogles_context_t::get(); 1055 c->transforms.current->scale(x, y, z); 1056 c->transforms.invalidate(); 1057 } 1058 1059 void glScalex(GLfixed x, GLfixed y, GLfixed z) 1060 { 1061 ogles_context_t* c = ogles_context_t::get(); 1062 c->transforms.current->scale( 1063 fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); 1064 c->transforms.invalidate(); 1065 } 1066 1067 void glTranslatef(GLfloat x, GLfloat y, GLfloat z) 1068 { 1069 ogles_context_t* c = ogles_context_t::get(); 1070 c->transforms.current->translate(x, y, z); 1071 c->transforms.invalidate(); 1072 } 1073 1074 void glTranslatex(GLfixed x, GLfixed y, GLfixed z) 1075 { 1076 ogles_context_t* c = ogles_context_t::get(); 1077 c->transforms.current->translate( 1078 fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); 1079 c->transforms.invalidate(); 1080 } 1081 1082 void glScissor(GLint x, GLint y, GLsizei w, GLsizei h) 1083 { 1084 ogles_context_t* c = ogles_context_t::get(); 1085 ogles_scissor(c, x, y, w, h); 1086 } 1087 1088 void glViewport(GLint x, GLint y, GLsizei w, GLsizei h) 1089 { 1090 ogles_context_t* c = ogles_context_t::get(); 1091 ogles_viewport(c, x, y, w, h); 1092 } 1093 1094 void glDepthRangef(GLclampf zNear, GLclampf zFar) 1095 { 1096 ogles_context_t* c = ogles_context_t::get(); 1097 depthRangef(zNear, zFar, c); 1098 } 1099 1100 void glDepthRangex(GLclampx zNear, GLclampx zFar) 1101 { 1102 ogles_context_t* c = ogles_context_t::get(); 1103 depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c); 1104 } 1105 1106 void glPolygonOffsetx(GLfixed factor, GLfixed units) 1107 { 1108 ogles_context_t* c = ogles_context_t::get(); 1109 c->polygonOffset.factor = factor; 1110 c->polygonOffset.units = units; 1111 } 1112 1113 void glPolygonOffset(GLfloat factor, GLfloat units) 1114 { 1115 ogles_context_t* c = ogles_context_t::get(); 1116 c->polygonOffset.factor = gglFloatToFixed(factor); 1117 c->polygonOffset.units = gglFloatToFixed(units); 1118 } 1119 1120 GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e) 1121 { 1122 ogles_context_t* c = ogles_context_t::get(); 1123 GLbitfield status = 0; 1124 GLfloat const* f = c->transforms.current->top().elements(); 1125 for (int i=0 ; i<16 ; i++) { 1126 if (isnan(f[i]) || isinf(f[i])) { 1127 status |= 1<<i; 1128 continue; 1129 } 1130 e[i] = exponent(f[i]) - 7; 1131 m[i] = mantissa(f[i]); 1132 } 1133 return status; 1134 } 1135