Home | History | Annotate | Download | only in libagl
      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     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 
    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     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 
    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