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 normal__nop(transform_t const*, vec4_t* c, vec4_t const* o); 55static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o); 56static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o); 57static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o); 58static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o); 59static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o); 60 61// ---------------------------------------------------------------------------- 62#if 0 63#pragma mark - 64#endif 65 66void 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 88void 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 96static 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 113void ogles_invalidate_perspective(ogles_context_t* c) 114{ 115 c->arrays.perspective = validate_perspective; 116} 117 118void 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 172void 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 182static inline 183int notZero(GLfixed v) { 184 return abs(v) & ~0x3; 185} 186 187static inline 188int notOne(GLfixed v) { 189 return notZero(v - 0x10000); 190} 191 192void 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 209void mvui_transform_t::picker() 210{ 211 flags = 0; 212 ops = OP_ALL; 213 point3 = point3__mvui; 214 point4 = point4__mvui; 215} 216 217void transform_t::dump(const char* what) 218{ 219 GLfixed const * const m = matrix.m; 220 ALOGD("%s:", what); 221 for (int i=0 ; i<4 ; i++) 222 ALOGD("[%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 236void 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 252void 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 275void matrixf_t::dump(const char* what) { 276 ALOGD("%s", what); 277 ALOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]); 278 ALOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]); 279 ALOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]); 280 ALOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]); 281} 282 283void matrixf_t::loadIdentity() { 284 memcpy(m, gIdentityf, sizeof(m)); 285} 286 287void matrixf_t::set(const GLfixed* rhs) { 288 load(rhs); 289} 290 291void matrixf_t::set(const GLfloat* rhs) { 292 load(rhs); 293} 294 295void 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 303void matrixf_t::load(const GLfloat* rhs) { 304 memcpy(m, rhs, sizeof(m)); 305} 306 307void matrixf_t::load(const matrixf_t& rhs) { 308 operator = (rhs); 309} 310 311void matrixf_t::multiply(const matrixf_t& rhs) { 312 matrixf_t r; 313 multiply(r, *this, rhs); 314 operator = (r); 315} 316 317void 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 323void 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 331void 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 386void 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 395void matrix_stack_t::uninit() { 396 delete [] stack; 397 delete [] ops; 398} 399 400void matrix_stack_t::loadIdentity() { 401 transform.loadIdentity(); 402 stack[depth].loadIdentity(); 403 ops[depth] = OP_IDENTITY; 404} 405 406void 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 413void 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 419void 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 425void 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 431void 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 441void 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 447void 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 458GLint 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 469GLint 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 484void 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 495void 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 506void 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 527static inline 528GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { 529 return a*d - b*c; 530} 531 532static inline 533GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { 534 return b*c - a*d; 535} 536 537static __attribute__((noinline)) 538void 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 586void 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 599void 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 641int 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 661void 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 680void 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 724void 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 734void 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 745void 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 757void 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 771void 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 786void 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 795void 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 804void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { 805 if (lhs != rhs) 806 *lhs = *rhs; 807} 808 809 810static 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 852static 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 891static 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 907using namespace android; 908 909void 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 931void 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 939void 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 946void 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 954void 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 963void 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 972void 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 983void 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 994void 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 1003void 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 1015void 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 1024void 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 1036void 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 1043void 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 1052void 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 1059void 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 1067void 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 1074void 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 1082void 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 1088void 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 1094void glDepthRangef(GLclampf zNear, GLclampf zFar) 1095{ 1096 ogles_context_t* c = ogles_context_t::get(); 1097 depthRangef(zNear, zFar, c); 1098} 1099 1100void glDepthRangex(GLclampx zNear, GLclampx zFar) 1101{ 1102 ogles_context_t* c = ogles_context_t::get(); 1103 depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c); 1104} 1105 1106void 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 1113void 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 1120GLbitfield 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