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