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