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 
ogles_init_matrix(ogles_context_t * c)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 
ogles_uninit_matrix(ogles_context_t * c)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 
validate_perspective(ogles_context_t * c,vertex_t * v)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 
ogles_invalidate_perspective(ogles_context_t * c)112 void ogles_invalidate_perspective(ogles_context_t* c)
113 {
114     c->arrays.perspective = validate_perspective;
115 }
116 
ogles_validate_transform_impl(ogles_context_t * c,uint32_t want)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 
loadIdentity()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
notZero(GLfixed v)182 int notZero(GLfixed v) {
183     return abs(v) & ~0x3;
184 }
185 
186 static inline
notOne(GLfixed v)187 int notOne(GLfixed v) {
188     return notZero(v - 0x10000);
189 }
190 
picker()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 
picker()208 void mvui_transform_t::picker()
209 {
210     flags = 0;
211     ops = OP_ALL;
212     point3 = point3__mvui;
213     point4 = point4__mvui;
214 }
215 
dump(const char * what)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 
load(const matrixf_t & rhs)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 
multiply(matrixf_t & r,const matrixf_t & lhs,const matrixf_t & rhs)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 
dump(const char * what)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 
loadIdentity()282 void matrixf_t::loadIdentity() {
283     memcpy(m, gIdentityf, sizeof(m));
284 }
285 
set(const GLfixed * rhs)286 void matrixf_t::set(const GLfixed* rhs) {
287     load(rhs);
288 }
289 
set(const GLfloat * rhs)290 void matrixf_t::set(const GLfloat* rhs) {
291     load(rhs);
292 }
293 
load(const GLfixed * rhs)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 
load(const GLfloat * rhs)302 void matrixf_t::load(const GLfloat* rhs) {
303     memcpy(m, rhs, sizeof(m));
304 }
305 
load(const matrixf_t & rhs)306 void matrixf_t::load(const matrixf_t& rhs) {
307     operator = (rhs);
308 }
309 
multiply(const matrixf_t & rhs)310 void matrixf_t::multiply(const matrixf_t& rhs) {
311     matrixf_t r;
312     multiply(r, *this, rhs);
313     operator = (r);
314 }
315 
translate(GLfloat x,GLfloat y,GLfloat z)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 
scale(GLfloat x,GLfloat y,GLfloat z)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 
rotate(GLfloat a,GLfloat x,GLfloat y,GLfloat z)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 
init(int depth)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 
uninit()394 void matrix_stack_t::uninit() {
395     delete [] stack;
396     delete [] ops;
397 }
398 
loadIdentity()399 void matrix_stack_t::loadIdentity() {
400     transform.loadIdentity();
401     stack[depth].loadIdentity();
402     ops[depth] = OP_IDENTITY;
403 }
404 
load(const GLfixed * rhs)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 
load(const GLfloat * rhs)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 
multiply(const matrixf_t & rhs)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 
translate(GLfloat x,GLfloat y,GLfloat z)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 
scale(GLfloat x,GLfloat y,GLfloat z)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 
rotate(GLfloat a,GLfloat x,GLfloat y,GLfloat z)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 
validate()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 
push()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 
pop()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 
loadIdentity()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 
invalidate()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 
update_mvp()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))
invert(GLfloat * inverse,const GLfloat * src)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 
update_mvit()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 
update_mvui()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 
ogles_surfaceport(ogles_context_t * c,GLint x,GLint y)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 
ogles_scissor(ogles_context_t * c,GLint x,GLint y,GLsizei w,GLsizei h)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 
ogles_viewport(ogles_context_t * c,GLint x,GLint y,GLsizei w,GLsizei h)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 
point2__generic(transform_t const * mx,vec4_t * lhs,vec4_t const * rhs)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 
point3__generic(transform_t const * mx,vec4_t * lhs,vec4_t const * rhs)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 
point4__generic(transform_t const * mx,vec4_t * lhs,vec4_t const * rhs)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 
point3__mvui(transform_t const * mx,vec4_t * lhs,vec4_t const * rhs)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 
point4__mvui(transform_t const * mx,vec4_t * lhs,vec4_t const * rhs)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 
point2__nop(transform_t const *,vec4_t * lhs,vec4_t const * rhs)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 
point3__nop(transform_t const *,vec4_t * lhs,vec4_t const * rhs)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 
point4__nop(transform_t const *,vec4_t * lhs,vec4_t const * rhs)793 void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
794     if (lhs != rhs)
795         *lhs = *rhs;
796 }
797 
798 
frustumf(GLfloat left,GLfloat right,GLfloat bottom,GLfloat top,GLfloat zNear,GLfloat zFar,ogles_context_t * c)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 
orthof(GLfloat left,GLfloat right,GLfloat bottom,GLfloat top,GLfloat zNear,GLfloat zFar,ogles_context_t * c)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 
depthRangef(GLclampf zNear,GLclampf zFar,ogles_context_t * c)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 
glMatrixMode(GLenum mode)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 
glLoadIdentity()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 
glLoadMatrixf(const GLfloat * m)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 
glLoadMatrixx(const GLfixed * m)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 
glMultMatrixf(const GLfloat * m)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 
glMultMatrixx(const GLfixed * m)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 
glPopMatrix()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 
glPushMatrix()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 
glFrustumf(GLfloat left,GLfloat right,GLfloat bottom,GLfloat top,GLfloat zNear,GLfloat zFar)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 
glFrustumx(GLfixed left,GLfixed right,GLfixed bottom,GLfixed top,GLfixed zNear,GLfixed zFar)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 
glOrthof(GLfloat left,GLfloat right,GLfloat bottom,GLfloat top,GLfloat zNear,GLfloat zFar)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 
glOrthox(GLfixed left,GLfixed right,GLfixed bottom,GLfixed top,GLfixed zNear,GLfixed zFar)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 
glRotatef(GLfloat a,GLfloat x,GLfloat y,GLfloat z)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 
glRotatex(GLfixed a,GLfixed x,GLfixed y,GLfixed z)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 
glScalef(GLfloat x,GLfloat y,GLfloat z)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 
glScalex(GLfixed x,GLfixed y,GLfixed z)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 
glTranslatef(GLfloat x,GLfloat y,GLfloat z)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 
glTranslatex(GLfixed x,GLfixed y,GLfixed z)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 
glScissor(GLint x,GLint y,GLsizei w,GLsizei h)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 
glViewport(GLint x,GLint y,GLsizei w,GLsizei h)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 
glDepthRangef(GLclampf zNear,GLclampf zFar)1083 void glDepthRangef(GLclampf zNear, GLclampf zFar)
1084 {
1085     ogles_context_t* c = ogles_context_t::get();
1086     depthRangef(zNear, zFar, c);
1087 }
1088 
glDepthRangex(GLclampx zNear,GLclampx zFar)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 
glPolygonOffsetx(GLfixed factor,GLfixed units)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 
glPolygonOffset(GLfloat factor,GLfloat units)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 
glQueryMatrixxOES(GLfixed * m,GLint * e)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