blob: f175cdad6e6a00c3e3d85c96717d84e7155c5107 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* 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 normal__generic(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 = normal__generic;
213}
214
215void transform_t::dump(const char* what)
216{
217 GLfixed const * const m = matrix.m;
218 LOGD("%s:", what);
219 for (int i=0 ; i<4 ; i++)
220 LOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n",
221 m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)],
222 fixedToFloat(m[I(0,i)]),
223 fixedToFloat(m[I(1,i)]),
224 fixedToFloat(m[I(2,i)]),
225 fixedToFloat(m[I(3,i)]));
226}
227
228// ----------------------------------------------------------------------------
229#if 0
230#pragma mark -
231#pragma mark matrixx_t
232#endif
233
234void matrixx_t::load(const matrixf_t& rhs) {
235 GLfixed* xp = m;
236 GLfloat const* fp = rhs.elements();
237 unsigned int i = 16;
238 do {
239 const GLfloat f = *fp++;
240 *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f);
241 } while (--i);
242}
243
244// ----------------------------------------------------------------------------
245#if 0
246#pragma mark -
247#pragma mark matrixf_t
248#endif
249
250void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs)
251{
252 GLfloat const* const m = lhs.m;
253 for (int i=0 ; i<4 ; i++) {
254 register const float rhs_i0 = rhs.m[ I(i,0) ];
255 register float ri0 = m[ I(0,0) ] * rhs_i0;
256 register float ri1 = m[ I(0,1) ] * rhs_i0;
257 register float ri2 = m[ I(0,2) ] * rhs_i0;
258 register float ri3 = m[ I(0,3) ] * rhs_i0;
259 for (int j=1 ; j<4 ; j++) {
260 register const float rhs_ij = rhs.m[ I(i,j) ];
261 ri0 += m[ I(j,0) ] * rhs_ij;
262 ri1 += m[ I(j,1) ] * rhs_ij;
263 ri2 += m[ I(j,2) ] * rhs_ij;
264 ri3 += m[ I(j,3) ] * rhs_ij;
265 }
266 r.m[ I(i,0) ] = ri0;
267 r.m[ I(i,1) ] = ri1;
268 r.m[ I(i,2) ] = ri2;
269 r.m[ I(i,3) ] = ri3;
270 }
271}
272
273void matrixf_t::dump(const char* what) {
274 LOGD("%s", what);
275 LOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]);
276 LOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]);
277 LOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]);
278 LOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]);
279}
280
281void matrixf_t::loadIdentity() {
282 memcpy(m, gIdentityf, sizeof(m));
283}
284
285void matrixf_t::set(const GLfixed* rhs) {
286 load(rhs);
287}
288
289void matrixf_t::set(const GLfloat* rhs) {
290 load(rhs);
291}
292
293void matrixf_t::load(const GLfixed* rhs) {
294 GLfloat* fp = m;
295 unsigned int i = 16;
296 do {
297 *fp++ = fixedToFloat(*rhs++);
298 } while (--i);
299}
300
301void matrixf_t::load(const GLfloat* rhs) {
302 memcpy(m, rhs, sizeof(m));
303}
304
305void matrixf_t::load(const matrixf_t& rhs) {
306 operator = (rhs);
307}
308
309void matrixf_t::multiply(const matrixf_t& rhs) {
310 matrixf_t r;
311 multiply(r, *this, rhs);
312 operator = (r);
313}
314
315void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) {
316 for (int i=0 ; i<4 ; i++) {
317 m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z;
318 }
319}
320
321void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) {
322 for (int i=0 ; i<4 ; i++) {
323 m[ i] *= x;
324 m[4+i] *= y;
325 m[8+i] *= z;
326 }
327}
328
329void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
330{
331 matrixf_t rotation;
332 GLfloat* r = rotation.m;
333 GLfloat c, s;
334 r[3] = 0; r[7] = 0; r[11]= 0;
335 r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1;
336 a *= GLfloat(M_PI / 180.0f);
337 sincosf(a, &s, &c);
338 if (isOnef(x) && isZerof(y) && isZerof(z)) {
339 r[5] = c; r[10]= c;
340 r[6] = s; r[9] = -s;
341 r[1] = 0; r[2] = 0;
342 r[4] = 0; r[8] = 0;
343 r[0] = 1;
344 } else if (isZerof(x) && isOnef(y) && isZerof(z)) {
345 r[0] = c; r[10]= c;
346 r[8] = s; r[2] = -s;
347 r[1] = 0; r[4] = 0;
348 r[6] = 0; r[9] = 0;
349 r[5] = 1;
350 } else if (isZerof(x) && isZerof(y) && isOnef(z)) {
351 r[0] = c; r[5] = c;
352 r[1] = s; r[4] = -s;
353 r[2] = 0; r[6] = 0;
354 r[8] = 0; r[9] = 0;
355 r[10]= 1;
356 } else {
357 const GLfloat len = sqrtf(x*x + y*y + z*z);
358 if (!isOnef(len)) {
359 const GLfloat recipLen = reciprocalf(len);
360 x *= recipLen;
361 y *= recipLen;
362 z *= recipLen;
363 }
364 const GLfloat nc = 1.0f - c;
365 const GLfloat xy = x * y;
366 const GLfloat yz = y * z;
367 const GLfloat zx = z * x;
368 const GLfloat xs = x * s;
369 const GLfloat ys = y * s;
370 const GLfloat zs = z * s;
371 r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys;
372 r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs;
373 r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c;
374 }
375 multiply(rotation);
376}
377
378// ----------------------------------------------------------------------------
379#if 0
380#pragma mark -
381#pragma mark matrix_stack_t
382#endif
383
384void matrix_stack_t::init(int depth) {
385 stack = new matrixf_t[depth];
386 ops = new uint8_t[depth];
387 maxDepth = depth;
388 depth = 0;
389 dirty = 0;
390 loadIdentity();
391}
392
393void matrix_stack_t::uninit() {
394 delete [] stack;
395 delete [] ops;
396}
397
398void matrix_stack_t::loadIdentity() {
399 transform.loadIdentity();
400 stack[depth].loadIdentity();
401 ops[depth] = OP_IDENTITY;
402}
403
404void matrix_stack_t::load(const GLfixed* rhs)
405{
406 memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m));
407 stack[depth].load(rhs);
408 ops[depth] = OP_ALL; // TODO: we should look at the matrix
409}
410
411void matrix_stack_t::load(const GLfloat* rhs)
412{
413 stack[depth].load(rhs);
414 ops[depth] = OP_ALL; // TODO: we should look at the matrix
415}
416
417void matrix_stack_t::multiply(const matrixf_t& rhs)
418{
419 stack[depth].multiply(rhs);
420 ops[depth] = OP_ALL; // TODO: we should look at the matrix
421}
422
423void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z)
424{
425 stack[depth].translate(x,y,z);
426 ops[depth] |= OP_TRANSLATE;
427}
428
429void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z)
430{
431 stack[depth].scale(x,y,z);
432 if (x==y && y==z) {
433 ops[depth] |= OP_UNIFORM_SCALE;
434 } else {
435 ops[depth] |= OP_SCALE;
436 }
437}
438
439void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
440{
441 stack[depth].rotate(a,x,y,z);
442 ops[depth] |= OP_ROTATE;
443}
444
445void matrix_stack_t::validate()
446{
447 if (dirty & DO_FLOAT_TO_FIXED) {
448 transform.matrix.load(top());
449 }
450 if (dirty & DO_PICKER) {
451 transform.picker();
452 }
453 dirty = 0;
454}
455
456GLint matrix_stack_t::push()
457{
458 if (depth >= (maxDepth-1)) {
459 return GL_STACK_OVERFLOW;
460 }
461 stack[depth+1] = stack[depth];
462 ops[depth+1] = ops[depth];
463 depth++;
464 return 0;
465}
466
467GLint matrix_stack_t::pop()
468{
469 if (depth == 0) {
470 return GL_STACK_UNDERFLOW;
471 }
472 depth--;
473 return 0;
474}
475
476// ----------------------------------------------------------------------------
477#if 0
478#pragma mark -
479#pragma mark vp_transform_t
480#endif
481
482void vp_transform_t::loadIdentity() {
483 transform.loadIdentity();
484 matrix.loadIdentity();
485}
486
487// ----------------------------------------------------------------------------
488#if 0
489#pragma mark -
490#pragma mark transform_state_t
491#endif
492
493void transform_state_t::invalidate()
494{
495 switch (matrixMode) {
496 case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break;
497 case GL_PROJECTION: dirty |= PROJECTION | MVP; break;
498 case GL_TEXTURE: dirty |= TEXTURE | MVP; break;
499 }
500 current->dirty = matrix_stack_t::DO_PICKER |
501 matrix_stack_t::DO_FLOAT_TO_FIXED;
502}
503
504void transform_state_t::update_mvp()
505{
506 matrixf_t temp_mvp;
507 matrixf_t::multiply(temp_mvp, projection.top(), modelview.top());
508 mvp4.matrix.load(temp_mvp);
509 mvp4.picker();
510
511 if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) {
512 // the mvp matrix doesn't transform W, in this case we can
513 // premultiply it with the viewport transformation. In addition to
514 // being more efficient, this is also much more accurate and in fact
515 // is needed for 2D drawing with a resulting 1:1 mapping.
516 matrixf_t mvpv;
517 matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp);
518 mvp.matrix.load(mvpv);
519 mvp.picker();
520 } else {
521 mvp = mvp4;
522 }
523}
524
525static inline
526GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
527 return a*d - b*c;
528}
529
530static inline
531GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
532 return b*c - a*d;
533}
534
535static __attribute__((noinline))
536void invert(GLfloat* inverse, const GLfloat* src)
537{
538 double t;
539 int i, j, k, swap;
540 GLfloat tmp[4][4];
541
542 memcpy(inverse, gIdentityf, sizeof(gIdentityf));
543 memcpy(tmp, src, sizeof(GLfloat)*16);
544
545 for (i = 0; i < 4; i++) {
546 // look for largest element in column
547 swap = i;
548 for (j = i + 1; j < 4; j++) {
549 if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
550 swap = j;
551 }
552 }
553
554 if (swap != i) {
555 /* swap rows. */
556 for (k = 0; k < 4; k++) {
557 t = tmp[i][k];
558 tmp[i][k] = tmp[swap][k];
559 tmp[swap][k] = t;
560
561 t = inverse[i*4+k];
562 inverse[i*4+k] = inverse[swap*4+k];
563 inverse[swap*4+k] = t;
564 }
565 }
566
567 t = 1.0f / tmp[i][i];
568 for (k = 0; k < 4; k++) {
569 tmp[i][k] *= t;
570 inverse[i*4+k] *= t;
571 }
572 for (j = 0; j < 4; j++) {
573 if (j != i) {
574 t = tmp[j][i];
575 for (k = 0; k < 4; k++) {
576 tmp[j][k] -= tmp[i][k]*t;
577 inverse[j*4+k] -= inverse[i*4+k]*t;
578 }
579 }
580 }
581 }
582}
583
584void transform_state_t::update_mvit()
585{
586 GLfloat r[16];
587 const GLfloat* const mv = modelview.top().elements();
588 invert(r, mv);
589 // convert to fixed-point and transpose
590 GLfixed* const x = mvit4.matrix.m;
591 for (int i=0 ; i<4 ; i++)
592 for (int j=0 ; j<4 ; j++)
593 x[I(i,j)] = gglFloatToFixed(r[I(j,i)]);
594 mvit4.picker();
595}
596
597void transform_state_t::update_mvui()
598{
599 const GLfloat* const mv = modelview.top().elements();
600
601 /*
602 When transforming normals, we can use the upper 3x3 matrix, see:
603 http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html
604 */
605
606 // Also note that:
607 // l(obj) = tr(M).l(eye) for infinite light
608 // l(obj) = inv(M).l(eye) for local light
609
610 const uint32_t ops = modelview.top_ops() & ~OP_TRANSLATE;
611 if (ggl_likely((!(ops & ~OP_ROTATE)) ||
612 (rescaleNormals && modelview.isRigidBody()))) {
613 // if the modelview matrix is a rigid body transformation
614 // (translation, rotation, uniform scaling), then we can bypass
615 // the inverse by transposing the matrix.
616 GLfloat rescale = 1.0f;
617 if (rescaleNormals == GL_RESCALE_NORMAL) {
618 if (!(ops & ~OP_UNIFORM_SCALE)) {
619 rescale = reciprocalf(mv[I(0,0)]);
620 } else {
621 rescale = rsqrtf(
622 sqrf(mv[I(2,0)]) + sqrf(mv[I(2,1)]) + sqrf(mv[I(2,2)]));
623 }
624 }
625 GLfixed* const x = mvui.matrix.m;
626 for (int i=0 ; i<3 ; i++) {
627 x[I(i,0)] = gglFloatToFixed(mv[I(0,i)] * rescale);
628 x[I(i,1)] = gglFloatToFixed(mv[I(1,i)] * rescale);
629 x[I(i,2)] = gglFloatToFixed(mv[I(2,i)] * rescale);
630 }
631 mvui.picker();
632 return;
633 }
634
635 GLfloat r[3][3];
636 r[0][0] = det22(mv[I(1,1)], mv[I(2,1)], mv[I(1,2)], mv[I(2,2)]);
637 r[0][1] =ndet22(mv[I(0,1)], mv[I(2,1)], mv[I(0,2)], mv[I(2,2)]);
638 r[0][2] = det22(mv[I(0,1)], mv[I(1,1)], mv[I(0,2)], mv[I(1,2)]);
639 r[1][0] =ndet22(mv[I(1,0)], mv[I(2,0)], mv[I(1,2)], mv[I(2,2)]);
640 r[1][1] = det22(mv[I(0,0)], mv[I(2,0)], mv[I(0,2)], mv[I(2,2)]);
641 r[1][2] =ndet22(mv[I(0,0)], mv[I(1,0)], mv[I(0,2)], mv[I(1,2)]);
642 r[2][0] = det22(mv[I(1,0)], mv[I(2,0)], mv[I(1,1)], mv[I(2,1)]);
643 r[2][1] =ndet22(mv[I(0,0)], mv[I(2,0)], mv[I(0,1)], mv[I(2,1)]);
644 r[2][2] = det22(mv[I(0,0)], mv[I(1,0)], mv[I(0,1)], mv[I(1,1)]);
645
646 GLfloat rdet;
647 if (rescaleNormals == GL_RESCALE_NORMAL) {
648 rdet = rsqrtf(sqrf(r[0][2]) + sqrf(r[1][2]) + sqrf(r[2][2]));
649 } else {
650 rdet = reciprocalf(
651 r[0][0]*mv[I(0,0)] + r[0][1]*mv[I(1,0)] + r[0][2]*mv[I(2,0)]);
652 }
653
654 GLfixed* const x = mvui.matrix.m;
655 for (int i=0 ; i<3 ; i++) {
656 x[I(i,0)] = gglFloatToFixed(r[i][0] * rdet);
657 x[I(i,1)] = gglFloatToFixed(r[i][1] * rdet);
658 x[I(i,2)] = gglFloatToFixed(r[i][2] * rdet);
659 }
660 mvui.picker();
661}
662
663
664// ----------------------------------------------------------------------------
665// transformation and matrices API
666// ----------------------------------------------------------------------------
667#if 0
668#pragma mark -
669#pragma mark transformation and matrices API
670#endif
671
672int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y)
673{
674 c->viewport.surfaceport.x = x;
675 c->viewport.surfaceport.y = y;
676
677 ogles_viewport(c,
678 c->viewport.x,
679 c->viewport.y,
680 c->viewport.w,
681 c->viewport.h);
682
683 ogles_scissor(c,
684 c->viewport.scissor.x,
685 c->viewport.scissor.y,
686 c->viewport.scissor.w,
687 c->viewport.scissor.h);
688
689 return 0;
690}
691
692void ogles_scissor(ogles_context_t* c,
693 GLint x, GLint y, GLsizei w, GLsizei h)
694{
695 if ((w|h) < 0) {
696 ogles_error(c, GL_INVALID_VALUE);
697 return;
698 }
699 c->viewport.scissor.x = x;
700 c->viewport.scissor.y = y;
701 c->viewport.scissor.w = w;
702 c->viewport.scissor.h = h;
703
704 x += c->viewport.surfaceport.x;
705 y += c->viewport.surfaceport.y;
706
707 y = c->rasterizer.state.buffers.color.height - (y + h);
708 c->rasterizer.procs.scissor(c, x, y, w, h);
709}
710
711void ogles_viewport(ogles_context_t* c,
712 GLint x, GLint y, GLsizei w, GLsizei h)
713{
714 if ((w|h)<0) {
715 ogles_error(c, GL_INVALID_VALUE);
716 return;
717 }
718
719 c->viewport.x = x;
720 c->viewport.y = y;
721 c->viewport.w = w;
722 c->viewport.h = h;
723
724 x += c->viewport.surfaceport.x;
725 y += c->viewport.surfaceport.y;
726
727 GLint H = c->rasterizer.state.buffers.color.height;
728 GLfloat sx = div2f(w);
729 GLfloat ox = sx + x;
730 GLfloat sy = div2f(h);
731 GLfloat oy = sy - y + (H - h);
732
733 GLfloat near = c->transforms.vpt.zNear;
734 GLfloat far = c->transforms.vpt.zFar;
735 GLfloat A = div2f(far - near);
736 GLfloat B = div2f(far + near);
737
738 // compute viewport matrix
739 GLfloat* const f = c->transforms.vpt.matrix.editElements();
740 f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox;
741 f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy;
742 f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
743 f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
744 c->transforms.dirty |= transform_state_t::VIEWPORT;
745}
746
747// ----------------------------------------------------------------------------
748#if 0
749#pragma mark -
750#pragma mark matrix * vertex
751#endif
752
753void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
754 const GLfixed* const m = mx->matrix.m;
755 const GLfixed rx = rhs->x;
756 const GLfixed ry = rhs->y;
757 lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]);
758 lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]);
759 lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]);
760 lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]);
761}
762
763void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
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 lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
769 lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
770 lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
771 lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
772}
773
774void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
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 = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]);
784}
785
786void normal__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
787 const GLfixed* const m = mx->matrix.m;
788 const GLfixed rx = rhs->x;
789 const GLfixed ry = rhs->y;
790 const GLfixed rz = rhs->z;
791 lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]);
792 lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]);
793 lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]);
794}
795
796
797void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
798 lhs->z = 0;
799 lhs->w = 0x10000;
800 if (lhs != rhs) {
801 lhs->x = rhs->x;
802 lhs->y = rhs->y;
803 }
804}
805
806void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
807 lhs->w = 0x10000;
808 if (lhs != rhs) {
809 lhs->x = rhs->x;
810 lhs->y = rhs->y;
811 lhs->z = rhs->z;
812 }
813}
814
815void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
816 if (lhs != rhs)
817 *lhs = *rhs;
818}
819
820
821static void frustumf(
822 GLfloat left, GLfloat right,
823 GLfloat bottom, GLfloat top,
824 GLfloat zNear, GLfloat zFar,
825 ogles_context_t* c)
826 {
827 if (cmpf(left,right) ||
828 cmpf(top, bottom) ||
829 cmpf(zNear, zFar) ||
830 isZeroOrNegativef(zNear) ||
831 isZeroOrNegativef(zFar))
832 {
833 ogles_error(c, GL_INVALID_VALUE);
834 return;
835 }
836 const GLfloat r_width = reciprocalf(right - left);
837 const GLfloat r_height = reciprocalf(top - bottom);
838 const GLfloat r_depth = reciprocalf(zNear - zFar);
839 const GLfloat x = mul2f(zNear * r_width);
840 const GLfloat y = mul2f(zNear * r_height);
841 const GLfloat A = mul2f((right + left) * r_width);
842 const GLfloat B = (top + bottom) * r_height;
843 const GLfloat C = (zFar + zNear) * r_depth;
844 const GLfloat D = mul2f(zFar * zNear * r_depth);
845 GLfloat f[16];
846 f[ 0] = x;
847 f[ 5] = y;
848 f[ 8] = A;
849 f[ 9] = B;
850 f[10] = C;
851 f[14] = D;
852 f[11] = -1.0f;
853 f[ 1] = f[ 2] = f[ 3] =
854 f[ 4] = f[ 6] = f[ 7] =
855 f[12] = f[13] = f[15] = 0.0f;
856
857 matrixf_t rhs;
858 rhs.set(f);
859 c->transforms.current->multiply(rhs);
860 c->transforms.invalidate();
861}
862
863static void orthof(
864 GLfloat left, GLfloat right,
865 GLfloat bottom, GLfloat top,
866 GLfloat zNear, GLfloat zFar,
867 ogles_context_t* c)
868{
869 if (cmpf(left,right) ||
870 cmpf(top, bottom) ||
871 cmpf(zNear, zFar))
872 {
873 ogles_error(c, GL_INVALID_VALUE);
874 return;
875 }
876 const GLfloat r_width = reciprocalf(right - left);
877 const GLfloat r_height = reciprocalf(top - bottom);
878 const GLfloat r_depth = reciprocalf(zFar - zNear);
879 const GLfloat x = mul2f(r_width);
880 const GLfloat y = mul2f(r_height);
881 const GLfloat z = -mul2f(r_depth);
882 const GLfloat tx = -(right + left) * r_width;
883 const GLfloat ty = -(top + bottom) * r_height;
884 const GLfloat tz = -(zFar + zNear) * r_depth;
885 GLfloat f[16];
886 f[ 0] = x;
887 f[ 5] = y;
888 f[10] = z;
889 f[12] = tx;
890 f[13] = ty;
891 f[14] = tz;
892 f[15] = 1.0f;
893 f[ 1] = f[ 2] = f[ 3] =
894 f[ 4] = f[ 6] = f[ 7] =
895 f[ 8] = f[ 9] = f[11] = 0.0f;
896 matrixf_t rhs;
897 rhs.set(f);
898 c->transforms.current->multiply(rhs);
899 c->transforms.invalidate();
900}
901
902static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c)
903{
904 zNear = clampToZerof(zNear > 1 ? 1 : zNear);
905 zFar = clampToZerof(zFar > 1 ? 1 : zFar);
906 GLfloat* const f = c->transforms.vpt.matrix.editElements();
907 f[10] = div2f(zFar - zNear);
908 f[14] = div2f(zFar + zNear);
909 c->transforms.dirty |= transform_state_t::VIEWPORT;
910 c->transforms.vpt.zNear = zNear;
911 c->transforms.vpt.zFar = zFar;
912}
913
914
915// ----------------------------------------------------------------------------
916}; // namespace android
917
918using namespace android;
919
920void glMatrixMode(GLenum mode)
921{
922 ogles_context_t* c = ogles_context_t::get();
923 matrix_stack_t* stack = 0;
924 switch (mode) {
925 case GL_MODELVIEW:
926 stack = &c->transforms.modelview;
927 break;
928 case GL_PROJECTION:
929 stack = &c->transforms.projection;
930 break;
931 case GL_TEXTURE:
932 stack = &c->transforms.texture[c->textures.active];
933 break;
934 default:
935 ogles_error(c, GL_INVALID_ENUM);
936 return;
937 }
938 c->transforms.matrixMode = mode;
939 c->transforms.current = stack;
940}
941
942void glLoadIdentity()
943{
944 ogles_context_t* c = ogles_context_t::get();
945 c->transforms.current->loadIdentity(); // also loads the GLfixed transform
946 c->transforms.invalidate();
947 c->transforms.current->dirty = 0;
948}
949
950void glLoadMatrixf(const GLfloat* m)
951{
952 ogles_context_t* c = ogles_context_t::get();
953 c->transforms.current->load(m);
954 c->transforms.invalidate();
955}
956
957void glLoadMatrixx(const GLfixed* m)
958{
959 ogles_context_t* c = ogles_context_t::get();
960 c->transforms.current->load(m); // also loads the GLfixed transform
961 c->transforms.invalidate();
962 c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED;
963}
964
965void glMultMatrixf(const GLfloat* m)
966{
967 ogles_context_t* c = ogles_context_t::get();
968 matrixf_t rhs;
969 rhs.set(m);
970 c->transforms.current->multiply(rhs);
971 c->transforms.invalidate();
972}
973
974void glMultMatrixx(const GLfixed* m)
975{
976 ogles_context_t* c = ogles_context_t::get();
977 matrixf_t rhs;
978 rhs.set(m);
979 c->transforms.current->multiply(rhs);
980 c->transforms.invalidate();
981}
982
983void glPopMatrix()
984{
985 ogles_context_t* c = ogles_context_t::get();
986 GLint err = c->transforms.current->pop();
987 if (ggl_unlikely(err)) {
988 ogles_error(c, err);
989 return;
990 }
991 c->transforms.invalidate();
992}
993
994void glPushMatrix()
995{
996 ogles_context_t* c = ogles_context_t::get();
997 GLint err = c->transforms.current->push();
998 if (ggl_unlikely(err)) {
999 ogles_error(c, err);
1000 return;
1001 }
1002 c->transforms.invalidate();
1003}
1004
1005void glFrustumf(
1006 GLfloat left, GLfloat right,
1007 GLfloat bottom, GLfloat top,
1008 GLfloat zNear, GLfloat zFar)
1009{
1010 ogles_context_t* c = ogles_context_t::get();
1011 frustumf(left, right, bottom, top, zNear, zFar, c);
1012}
1013
1014void glFrustumx(
1015 GLfixed left, GLfixed right,
1016 GLfixed bottom, GLfixed top,
1017 GLfixed zNear, GLfixed zFar)
1018{
1019 ogles_context_t* c = ogles_context_t::get();
1020 frustumf( fixedToFloat(left), fixedToFloat(right),
1021 fixedToFloat(bottom), fixedToFloat(top),
1022 fixedToFloat(zNear), fixedToFloat(zFar),
1023 c);
1024}
1025
1026void glOrthof(
1027 GLfloat left, GLfloat right,
1028 GLfloat bottom, GLfloat top,
1029 GLfloat zNear, GLfloat zFar)
1030{
1031 ogles_context_t* c = ogles_context_t::get();
1032 orthof(left, right, bottom, top, zNear, zFar, c);
1033}
1034
1035void glOrthox(
1036 GLfixed left, GLfixed right,
1037 GLfixed bottom, GLfixed top,
1038 GLfixed zNear, GLfixed zFar)
1039{
1040 ogles_context_t* c = ogles_context_t::get();
1041 orthof( fixedToFloat(left), fixedToFloat(right),
1042 fixedToFloat(bottom), fixedToFloat(top),
1043 fixedToFloat(zNear), fixedToFloat(zFar),
1044 c);
1045}
1046
1047void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
1048{
1049 ogles_context_t* c = ogles_context_t::get();
1050 c->transforms.current->rotate(a, x, y, z);
1051 c->transforms.invalidate();
1052}
1053
1054void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z)
1055{
1056 ogles_context_t* c = ogles_context_t::get();
1057 c->transforms.current->rotate(
1058 fixedToFloat(a), fixedToFloat(x),
1059 fixedToFloat(y), fixedToFloat(z));
1060 c->transforms.invalidate();
1061}
1062
1063void glScalef(GLfloat x, GLfloat y, GLfloat z)
1064{
1065 ogles_context_t* c = ogles_context_t::get();
1066 c->transforms.current->scale(x, y, z);
1067 c->transforms.invalidate();
1068}
1069
1070void glScalex(GLfixed x, GLfixed y, GLfixed z)
1071{
1072 ogles_context_t* c = ogles_context_t::get();
1073 c->transforms.current->scale(
1074 fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
1075 c->transforms.invalidate();
1076}
1077
1078void glTranslatef(GLfloat x, GLfloat y, GLfloat z)
1079{
1080 ogles_context_t* c = ogles_context_t::get();
1081 c->transforms.current->translate(x, y, z);
1082 c->transforms.invalidate();
1083}
1084
1085void glTranslatex(GLfixed x, GLfixed y, GLfixed z)
1086{
1087 ogles_context_t* c = ogles_context_t::get();
1088 c->transforms.current->translate(
1089 fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
1090 c->transforms.invalidate();
1091}
1092
1093void glScissor(GLint x, GLint y, GLsizei w, GLsizei h)
1094{
1095 ogles_context_t* c = ogles_context_t::get();
1096 ogles_scissor(c, x, y, w, h);
1097}
1098
1099void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
1100{
1101 ogles_context_t* c = ogles_context_t::get();
1102 ogles_viewport(c, x, y, w, h);
1103}
1104
1105void glDepthRangef(GLclampf zNear, GLclampf zFar)
1106{
1107 ogles_context_t* c = ogles_context_t::get();
1108 depthRangef(zNear, zFar, c);
1109}
1110
1111void glDepthRangex(GLclampx zNear, GLclampx zFar)
1112{
1113 ogles_context_t* c = ogles_context_t::get();
1114 depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c);
1115}
1116
1117void glPolygonOffsetx(GLfixed factor, GLfixed units)
1118{
1119 ogles_context_t* c = ogles_context_t::get();
1120 c->polygonOffset.factor = factor;
1121 c->polygonOffset.units = units;
1122}
1123
1124void glPolygonOffset(GLfloat factor, GLfloat units)
1125{
1126 ogles_context_t* c = ogles_context_t::get();
1127 c->polygonOffset.factor = gglFloatToFixed(factor);
1128 c->polygonOffset.units = gglFloatToFixed(units);
1129}
1130
1131GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e)
1132{
1133 ogles_context_t* c = ogles_context_t::get();
1134 GLbitfield status = 0;
1135 GLfloat const* f = c->transforms.current->top().elements();
1136 for (int i=0 ; i<16 ; i++) {
1137 if (isnan(f[i]) || isinf(f[i])) {
1138 status |= 1<<i;
1139 continue;
1140 }
1141 e[i] = exponent(f[i]) - 7;
1142 m[i] = mantissa(f[i]);
1143 }
1144 return status;
1145}