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