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