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 point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
     55 static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
     56 static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
     57 static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o);
     58 static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o);
     59 
     60 // ----------------------------------------------------------------------------
     61 #if 0
     62 #pragma mark -
     63 #endif
     64 
     65 void 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 
     87 void 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 
     95 static 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 
    112 void ogles_invalidate_perspective(ogles_context_t* c)
    113 {
    114     c->arrays.perspective = validate_perspective;
    115 }
    116 
    117 void 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 
    171 void 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 
    181 static inline
    182 int notZero(GLfixed v) {
    183     return abs(v) & ~0x3;
    184 }
    185 
    186 static inline
    187 int notOne(GLfixed v) {
    188     return notZero(v - 0x10000);
    189 }
    190 
    191 void 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 
    208 void mvui_transform_t::picker()
    209 {
    210     flags = 0;
    211     ops = OP_ALL;
    212     point3 = point3__mvui;
    213     point4 = point4__mvui;
    214 }
    215 
    216 void 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 
    235 void 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 
    251 void 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 
    274 void 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 
    282 void matrixf_t::loadIdentity() {
    283     memcpy(m, gIdentityf, sizeof(m));
    284 }
    285 
    286 void matrixf_t::set(const GLfixed* rhs) {
    287     load(rhs);
    288 }
    289 
    290 void matrixf_t::set(const GLfloat* rhs) {
    291     load(rhs);
    292 }
    293 
    294 void 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 
    302 void matrixf_t::load(const GLfloat* rhs) {
    303     memcpy(m, rhs, sizeof(m));
    304 }
    305 
    306 void matrixf_t::load(const matrixf_t& rhs) {
    307     operator = (rhs);
    308 }
    309 
    310 void matrixf_t::multiply(const matrixf_t& rhs) {
    311     matrixf_t r;
    312     multiply(r, *this, rhs);
    313     operator = (r);
    314 }
    315 
    316 void 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 
    322 void 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 
    330 void 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 
    385 void 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 
    394 void matrix_stack_t::uninit() {
    395     delete [] stack;
    396     delete [] ops;
    397 }
    398 
    399 void matrix_stack_t::loadIdentity() {
    400     transform.loadIdentity();
    401     stack[depth].loadIdentity();
    402     ops[depth] = OP_IDENTITY;
    403 }
    404 
    405 void 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 
    412 void 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 
    418 void 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 
    424 void 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 
    430 void 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 
    440 void 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 
    446 void 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 
    457 GLint 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 
    468 GLint 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 
    483 void 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 
    494 void 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 
    505 void 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 
    526 static __attribute__((noinline))
    527 void 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 
    575 void 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 
    588 void 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 
    630 int 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 
    650 void 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 
    669 void 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 
    713 void 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 
    723 void 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 
    734 void 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 
    746 void 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 
    760 void 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 
    775 void 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 
    784 void 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 
    793 void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
    794     if (lhs != rhs)
    795         *lhs = *rhs;
    796 }
    797 
    798 
    799 static 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 
    841 static 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 
    880 static 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 
    896 using namespace android;
    897 
    898 void 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 
    920 void 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 
    928 void 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 
    935 void 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 
    943 void 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 
    952 void 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 
    961 void 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 
    972 void 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 
    983 void 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 
    992 void 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 
   1004 void 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 
   1013 void 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 
   1025 void 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 
   1032 void 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 
   1041 void 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 
   1048 void 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 
   1056 void 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 
   1063 void 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 
   1071 void 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 
   1077 void 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 
   1083 void glDepthRangef(GLclampf zNear, GLclampf zFar)
   1084 {
   1085     ogles_context_t* c = ogles_context_t::get();
   1086     depthRangef(zNear, zFar, c);
   1087 }
   1088 
   1089 void glDepthRangex(GLclampx zNear, GLclampx zFar)
   1090 {
   1091     ogles_context_t* c = ogles_context_t::get();
   1092     depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c);
   1093 }
   1094 
   1095 void 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 
   1102 void 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 
   1109 GLbitfield 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