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