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