| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 54 | static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o); | 
 | 55 | static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o); | 
 | 56 | static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o); | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 57 | static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o); | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 58 | static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 59 |  | 
 | 60 | // ---------------------------------------------------------------------------- | 
 | 61 | #if 0 | 
 | 62 | #pragma mark - | 
 | 63 | #endif | 
 | 64 |  | 
 | 65 | void 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 |  | 
 | 87 | void 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 |  | 
 | 95 | static 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 |  | 
 | 112 | void ogles_invalidate_perspective(ogles_context_t* c) | 
 | 113 | { | 
 | 114 |     c->arrays.perspective = validate_perspective; | 
 | 115 | } | 
 | 116 |  | 
 | 117 | void 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 |  | 
 | 171 | void 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 |  | 
 | 181 | static inline | 
 | 182 | int notZero(GLfixed v) { | 
 | 183 |     return abs(v) & ~0x3; | 
 | 184 | } | 
 | 185 |  | 
 | 186 | static inline | 
 | 187 | int notOne(GLfixed v) { | 
 | 188 |     return notZero(v - 0x10000); | 
 | 189 | } | 
 | 190 |  | 
 | 191 | void 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 |  | 
 | 208 | void mvui_transform_t::picker() | 
 | 209 | { | 
 | 210 |     flags = 0; | 
 | 211 |     ops = OP_ALL; | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 212 |     point3 = point3__mvui; | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 213 |     point4 = point4__mvui; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 214 | } | 
 | 215 |  | 
 | 216 | void transform_t::dump(const char* what) | 
 | 217 | { | 
 | 218 |     GLfixed const * const m = matrix.m; | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 219 |     ALOGD("%s:", what); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 220 |     for (int i=0 ; i<4 ; i++) | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 221 |         ALOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n", | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
 | 235 | void 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 |  | 
 | 251 | void 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++) { | 
| Dan Stoza | c044ae5 | 2016-01-08 10:52:16 -0800 | [diff] [blame] | 255 |         const float rhs_i0 = rhs.m[ I(i,0) ]; | 
 | 256 |         float ri0 = m[ I(0,0) ] * rhs_i0; | 
 | 257 |         float ri1 = m[ I(0,1) ] * rhs_i0; | 
 | 258 |         float ri2 = m[ I(0,2) ] * rhs_i0; | 
 | 259 |         float ri3 = m[ I(0,3) ] * rhs_i0; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 260 |         for (int j=1 ; j<4 ; j++) { | 
| Dan Stoza | c044ae5 | 2016-01-08 10:52:16 -0800 | [diff] [blame] | 261 |             const float rhs_ij = rhs.m[ I(i,j) ]; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
 | 274 | void matrixf_t::dump(const char* what) { | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 275 |     ALOGD("%s", what); | 
 | 276 |     ALOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]); | 
 | 277 |     ALOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]); | 
 | 278 |     ALOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]); | 
 | 279 |     ALOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 280 | } | 
 | 281 |  | 
 | 282 | void matrixf_t::loadIdentity() { | 
 | 283 |     memcpy(m, gIdentityf, sizeof(m)); | 
 | 284 | } | 
 | 285 |  | 
 | 286 | void matrixf_t::set(const GLfixed* rhs) { | 
 | 287 |     load(rhs); | 
 | 288 | } | 
 | 289 |  | 
 | 290 | void matrixf_t::set(const GLfloat* rhs) { | 
 | 291 |     load(rhs); | 
 | 292 | } | 
 | 293 |  | 
 | 294 | void 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 |  | 
 | 302 | void matrixf_t::load(const GLfloat* rhs) { | 
 | 303 |     memcpy(m, rhs, sizeof(m)); | 
 | 304 | } | 
 | 305 |  | 
 | 306 | void matrixf_t::load(const matrixf_t& rhs) { | 
 | 307 |     operator = (rhs); | 
 | 308 | } | 
 | 309 |  | 
 | 310 | void matrixf_t::multiply(const matrixf_t& rhs) { | 
 | 311 |     matrixf_t r; | 
 | 312 |     multiply(r, *this, rhs); | 
 | 313 |     operator = (r); | 
 | 314 | } | 
 | 315 |  | 
 | 316 | void 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 |  | 
 | 322 | void 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 |  | 
 | 330 | void 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 |  | 
 | 385 | void 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 |  | 
 | 394 | void matrix_stack_t::uninit() { | 
 | 395 |     delete [] stack; | 
 | 396 |     delete [] ops; | 
 | 397 | } | 
 | 398 |  | 
 | 399 | void matrix_stack_t::loadIdentity() { | 
 | 400 |     transform.loadIdentity(); | 
 | 401 |     stack[depth].loadIdentity(); | 
 | 402 |     ops[depth] = OP_IDENTITY; | 
 | 403 | } | 
 | 404 |  | 
 | 405 | void 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 |  | 
 | 412 | void 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 |  | 
 | 418 | void 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 |  | 
 | 424 | void 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 |  | 
 | 430 | void 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 |  | 
 | 440 | void 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 |  | 
 | 446 | void 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 |  | 
 | 457 | GLint 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 |  | 
 | 468 | GLint 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 |  | 
 | 483 | void 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 |  | 
 | 494 | void 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 |  | 
 | 505 | void 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 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 526 | static __attribute__((noinline)) | 
 | 527 | void invert(GLfloat* inverse, const GLfloat* src) | 
 | 528 | { | 
 | 529 |     double t; | 
 | 530 |     int i, j, k, swap; | 
 | 531 |     GLfloat tmp[4][4]; | 
 | 532 |      | 
 | 533 |     memcpy(inverse, gIdentityf, sizeof(gIdentityf)); | 
 | 534 |     memcpy(tmp, src, sizeof(GLfloat)*16); | 
 | 535 |      | 
 | 536 |     for (i = 0; i < 4; i++) { | 
 | 537 |         // look for largest element in column | 
 | 538 |         swap = i; | 
 | 539 |         for (j = i + 1; j < 4; j++) { | 
 | 540 |             if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { | 
 | 541 |                 swap = j; | 
 | 542 |             } | 
 | 543 |         } | 
 | 544 |          | 
 | 545 |         if (swap != i) { | 
 | 546 |             /* swap rows. */ | 
 | 547 |             for (k = 0; k < 4; k++) { | 
 | 548 |                 t = tmp[i][k]; | 
 | 549 |                 tmp[i][k] = tmp[swap][k]; | 
 | 550 |                 tmp[swap][k] = t; | 
 | 551 |                  | 
 | 552 |                 t = inverse[i*4+k]; | 
 | 553 |                 inverse[i*4+k] = inverse[swap*4+k]; | 
 | 554 |                 inverse[swap*4+k] = t; | 
 | 555 |             } | 
 | 556 |         } | 
 | 557 |          | 
 | 558 |         t = 1.0f / tmp[i][i]; | 
 | 559 |         for (k = 0; k < 4; k++) { | 
 | 560 |             tmp[i][k] *= t; | 
 | 561 |             inverse[i*4+k] *= t; | 
 | 562 |         } | 
 | 563 |         for (j = 0; j < 4; j++) { | 
 | 564 |             if (j != i) { | 
 | 565 |                 t = tmp[j][i]; | 
 | 566 |                 for (k = 0; k < 4; k++) { | 
 | 567 |                     tmp[j][k] -= tmp[i][k]*t; | 
 | 568 |                     inverse[j*4+k] -= inverse[i*4+k]*t; | 
 | 569 |                 } | 
 | 570 |             } | 
 | 571 |         } | 
 | 572 |     } | 
 | 573 | } | 
 | 574 |  | 
 | 575 | void transform_state_t::update_mvit() | 
 | 576 | { | 
 | 577 |     GLfloat r[16]; | 
 | 578 |     const GLfloat* const mv = modelview.top().elements(); | 
 | 579 |     invert(r, mv); | 
 | 580 |     // convert to fixed-point and transpose | 
 | 581 |     GLfixed* const x = mvit4.matrix.m; | 
 | 582 |     for (int i=0 ; i<4 ; i++) | 
 | 583 |         for (int j=0 ; j<4 ; j++) | 
 | 584 |             x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); | 
 | 585 |     mvit4.picker(); | 
 | 586 | } | 
 | 587 |  | 
 | 588 | void transform_state_t::update_mvui() | 
 | 589 | { | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 590 |     GLfloat r[16]; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 591 |     const GLfloat* const mv = modelview.top().elements(); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 592 |      | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 593 |     /* | 
 | 594 |     When evaluating the lighting equation in eye-space, normals | 
 | 595 |     are transformed by the upper 3x3 modelview inverse-transpose. | 
 | 596 |     http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html | 
 | 597 |  | 
 | 598 |     (note that inverse-transpose is distributive). | 
 | 599 |     Also note that: | 
 | 600 |         l(obj) = inv(modelview).l(eye) for local light | 
 | 601 |         l(obj) =  tr(modelview).l(eye) for infinite light | 
 | 602 |     */ | 
 | 603 |  | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 604 |     invert(r, mv); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 605 |  | 
 | 606 |     GLfixed* const x = mvui.matrix.m; | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 607 |  | 
 | 608 | #if OBJECT_SPACE_LIGHTING | 
 | 609 |     for (int i=0 ; i<4 ; i++) | 
 | 610 |         for (int j=0 ; j<4 ; j++) | 
 | 611 |             x[I(i,j)] = gglFloatToFixed(r[I(i,j)]); | 
 | 612 | #else | 
 | 613 |     for (int i=0 ; i<4 ; i++) | 
 | 614 |         for (int j=0 ; j<4 ; j++) | 
 | 615 |             x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); | 
 | 616 | #endif | 
 | 617 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 618 |     mvui.picker(); | 
 | 619 | } | 
 | 620 |  | 
 | 621 |  | 
 | 622 | // ---------------------------------------------------------------------------- | 
 | 623 | // transformation and matrices API | 
 | 624 | // ---------------------------------------------------------------------------- | 
 | 625 | #if 0 | 
 | 626 | #pragma mark - | 
 | 627 | #pragma mark transformation and matrices API | 
 | 628 | #endif | 
 | 629 |  | 
 | 630 | int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y) | 
 | 631 | { | 
 | 632 |     c->viewport.surfaceport.x = x; | 
 | 633 |     c->viewport.surfaceport.y = y; | 
 | 634 |  | 
 | 635 |     ogles_viewport(c,  | 
 | 636 |             c->viewport.x, | 
 | 637 |             c->viewport.y, | 
 | 638 |             c->viewport.w, | 
 | 639 |             c->viewport.h); | 
 | 640 |  | 
 | 641 |     ogles_scissor(c, | 
 | 642 |             c->viewport.scissor.x, | 
 | 643 |             c->viewport.scissor.y, | 
 | 644 |             c->viewport.scissor.w, | 
 | 645 |             c->viewport.scissor.h); | 
 | 646 |  | 
 | 647 |     return 0; | 
 | 648 | } | 
 | 649 |  | 
 | 650 | void ogles_scissor(ogles_context_t* c,  | 
 | 651 |         GLint x, GLint y, GLsizei w, GLsizei h) | 
 | 652 | { | 
 | 653 |     if ((w|h) < 0) { | 
 | 654 |         ogles_error(c, GL_INVALID_VALUE); | 
 | 655 |         return; | 
 | 656 |     } | 
 | 657 |     c->viewport.scissor.x = x; | 
 | 658 |     c->viewport.scissor.y = y; | 
 | 659 |     c->viewport.scissor.w = w; | 
 | 660 |     c->viewport.scissor.h = h; | 
 | 661 |      | 
 | 662 |     x += c->viewport.surfaceport.x; | 
 | 663 |     y += c->viewport.surfaceport.y; | 
 | 664 |  | 
 | 665 |     y = c->rasterizer.state.buffers.color.height - (y + h); | 
 | 666 |     c->rasterizer.procs.scissor(c, x, y, w, h); | 
 | 667 | } | 
 | 668 |  | 
 | 669 | void ogles_viewport(ogles_context_t* c, | 
 | 670 |         GLint x, GLint y, GLsizei w, GLsizei h) | 
 | 671 | { | 
 | 672 |     if ((w|h)<0) { | 
 | 673 |         ogles_error(c, GL_INVALID_VALUE); | 
 | 674 |         return; | 
 | 675 |     } | 
 | 676 |  | 
 | 677 |     c->viewport.x = x; | 
 | 678 |     c->viewport.y = y; | 
 | 679 |     c->viewport.w = w; | 
 | 680 |     c->viewport.h = h; | 
 | 681 |  | 
 | 682 |     x += c->viewport.surfaceport.x; | 
 | 683 |     y += c->viewport.surfaceport.y; | 
 | 684 |  | 
 | 685 |     GLint H = c->rasterizer.state.buffers.color.height; | 
 | 686 |     GLfloat sx = div2f(w); | 
 | 687 |     GLfloat ox = sx + x; | 
 | 688 |     GLfloat sy = div2f(h); | 
 | 689 |     GLfloat oy = sy - y + (H - h); | 
 | 690 |  | 
 | 691 |     GLfloat near = c->transforms.vpt.zNear; | 
 | 692 |     GLfloat far  = c->transforms.vpt.zFar; | 
 | 693 |     GLfloat A = div2f(far - near); | 
 | 694 |     GLfloat B = div2f(far + near); | 
 | 695 |  | 
 | 696 |     // compute viewport matrix | 
 | 697 |     GLfloat* const f = c->transforms.vpt.matrix.editElements(); | 
 | 698 |     f[0] = sx;  f[4] = 0;   f[ 8] = 0;  f[12] = ox; | 
 | 699 |     f[1] = 0;   f[5] =-sy;  f[ 9] = 0;  f[13] = oy; | 
 | 700 |     f[2] = 0;   f[6] = 0;   f[10] = A;  f[14] = B; | 
 | 701 |     f[3] = 0;   f[7] = 0;   f[11] = 0;  f[15] = 1; | 
 | 702 |     c->transforms.dirty |= transform_state_t::VIEWPORT; | 
| Martin Storsjo | d914215 | 2009-08-10 13:02:28 +0200 | [diff] [blame] | 703 |     if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) | 
 | 704 |         c->transforms.dirty |= transform_state_t::MVP; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 705 | } | 
 | 706 |  | 
 | 707 | // ---------------------------------------------------------------------------- | 
 | 708 | #if 0 | 
 | 709 | #pragma mark - | 
 | 710 | #pragma mark matrix * vertex | 
 | 711 | #endif | 
 | 712 |  | 
 | 713 | void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { | 
 | 714 |     const GLfixed* const m = mx->matrix.m; | 
 | 715 |     const GLfixed rx = rhs->x; | 
 | 716 |     const GLfixed ry = rhs->y; | 
 | 717 |     lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]);  | 
 | 718 |     lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]); | 
 | 719 |     lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]); | 
 | 720 |     lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]); | 
 | 721 | } | 
 | 722 |  | 
 | 723 | void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { | 
 | 724 |     const GLfixed* const m = mx->matrix.m; | 
 | 725 |     const GLfixed rx = rhs->x; | 
 | 726 |     const GLfixed ry = rhs->y; | 
 | 727 |     const GLfixed rz = rhs->z; | 
 | 728 |     lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);  | 
 | 729 |     lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); | 
 | 730 |     lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); | 
 | 731 |     lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); | 
 | 732 | } | 
 | 733 |  | 
 | 734 | void point4__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 |     const GLfixed rw = rhs->w; | 
 | 740 |     lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]);  | 
 | 741 |     lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); | 
 | 742 |     lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); | 
 | 743 |     lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]); | 
 | 744 | } | 
 | 745 |  | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 746 | void point3__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { | 
 | 747 |     // this is used for transforming light positions back to object space. | 
 | 748 |     // w is used as a switch for directional lights, so we need | 
 | 749 |     // to preserve it. | 
 | 750 |     const GLfixed* const m = mx->matrix.m; | 
 | 751 |     const GLfixed rx = rhs->x; | 
 | 752 |     const GLfixed ry = rhs->y; | 
 | 753 |     const GLfixed rz = rhs->z; | 
 | 754 |     lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]); | 
 | 755 |     lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]); | 
 | 756 |     lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]); | 
 | 757 |     lhs->w = 0; | 
 | 758 | } | 
 | 759 |  | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 760 | void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 761 |     // this is used for transforming light positions back to object space. | 
| Mathias Agopian | b44efdc | 2009-11-02 18:33:08 -0800 | [diff] [blame] | 762 |     // w is used as a switch for directional lights, so we need | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 763 |     // to preserve it. | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 764 |     const GLfixed* const m = mx->matrix.m; | 
 | 765 |     const GLfixed rx = rhs->x; | 
 | 766 |     const GLfixed ry = rhs->y; | 
 | 767 |     const GLfixed rz = rhs->z; | 
| Mathias Agopian | b44efdc | 2009-11-02 18:33:08 -0800 | [diff] [blame] | 768 |     const GLfixed rw = rhs->w; | 
 | 769 |     lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); | 
 | 770 |     lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); | 
 | 771 |     lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); | 
 | 772 |     lhs->w = rw; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 773 | } | 
 | 774 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 775 | void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { | 
 | 776 |     lhs->z = 0; | 
 | 777 |     lhs->w = 0x10000; | 
 | 778 |     if (lhs != rhs) { | 
 | 779 |         lhs->x = rhs->x; | 
 | 780 |         lhs->y = rhs->y; | 
 | 781 |     } | 
 | 782 | } | 
 | 783 |  | 
 | 784 | void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { | 
 | 785 |     lhs->w = 0x10000; | 
 | 786 |     if (lhs != rhs) { | 
 | 787 |         lhs->x = rhs->x; | 
 | 788 |         lhs->y = rhs->y; | 
 | 789 |         lhs->z = rhs->z; | 
 | 790 |     } | 
 | 791 | } | 
 | 792 |  | 
 | 793 | void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { | 
 | 794 |     if (lhs != rhs) | 
 | 795 |         *lhs = *rhs; | 
 | 796 | } | 
 | 797 |  | 
 | 798 |  | 
 | 799 | static void frustumf( | 
 | 800 |             GLfloat left, GLfloat right,  | 
 | 801 |             GLfloat bottom, GLfloat top, | 
 | 802 |             GLfloat zNear, GLfloat zFar, | 
 | 803 |             ogles_context_t* c) | 
 | 804 |     { | 
 | 805 |     if (cmpf(left,right) || | 
 | 806 |         cmpf(top, bottom) || | 
 | 807 |         cmpf(zNear, zFar) || | 
 | 808 |         isZeroOrNegativef(zNear) || | 
 | 809 |         isZeroOrNegativef(zFar)) | 
 | 810 |     { | 
 | 811 |         ogles_error(c, GL_INVALID_VALUE); | 
 | 812 |         return; | 
 | 813 |     } | 
 | 814 |     const GLfloat r_width  = reciprocalf(right - left); | 
 | 815 |     const GLfloat r_height = reciprocalf(top - bottom); | 
 | 816 |     const GLfloat r_depth  = reciprocalf(zNear - zFar); | 
 | 817 |     const GLfloat x = mul2f(zNear * r_width); | 
 | 818 |     const GLfloat y = mul2f(zNear * r_height); | 
 | 819 |     const GLfloat A = mul2f((right + left) * r_width); | 
 | 820 |     const GLfloat B = (top + bottom) * r_height; | 
 | 821 |     const GLfloat C = (zFar + zNear) * r_depth; | 
 | 822 |     const GLfloat D = mul2f(zFar * zNear * r_depth); | 
 | 823 |     GLfloat f[16]; | 
 | 824 |     f[ 0] = x; | 
 | 825 |     f[ 5] = y; | 
 | 826 |     f[ 8] = A; | 
 | 827 |     f[ 9] = B; | 
 | 828 |     f[10] = C; | 
 | 829 |     f[14] = D; | 
 | 830 |     f[11] = -1.0f; | 
 | 831 |     f[ 1] = f[ 2] = f[ 3] = | 
 | 832 |     f[ 4] = f[ 6] = f[ 7] = | 
 | 833 |     f[12] = f[13] = f[15] = 0.0f; | 
 | 834 |  | 
 | 835 |     matrixf_t rhs; | 
 | 836 |     rhs.set(f); | 
 | 837 |     c->transforms.current->multiply(rhs); | 
 | 838 |     c->transforms.invalidate(); | 
 | 839 | } | 
 | 840 |  | 
 | 841 | static void orthof(  | 
 | 842 |         GLfloat left, GLfloat right,  | 
 | 843 |         GLfloat bottom, GLfloat top, | 
 | 844 |         GLfloat zNear, GLfloat zFar, | 
 | 845 |         ogles_context_t* c) | 
 | 846 | { | 
 | 847 |     if (cmpf(left,right) || | 
 | 848 |         cmpf(top, bottom) || | 
 | 849 |         cmpf(zNear, zFar)) | 
 | 850 |     { | 
 | 851 |         ogles_error(c, GL_INVALID_VALUE); | 
 | 852 |         return; | 
 | 853 |     } | 
 | 854 |     const GLfloat r_width  = reciprocalf(right - left); | 
 | 855 |     const GLfloat r_height = reciprocalf(top - bottom); | 
 | 856 |     const GLfloat r_depth  = reciprocalf(zFar - zNear); | 
 | 857 |     const GLfloat x =  mul2f(r_width); | 
 | 858 |     const GLfloat y =  mul2f(r_height); | 
 | 859 |     const GLfloat z = -mul2f(r_depth); | 
 | 860 |     const GLfloat tx = -(right + left) * r_width; | 
 | 861 |     const GLfloat ty = -(top + bottom) * r_height; | 
 | 862 |     const GLfloat tz = -(zFar + zNear) * r_depth; | 
 | 863 |     GLfloat f[16]; | 
 | 864 |     f[ 0] = x; | 
 | 865 |     f[ 5] = y; | 
 | 866 |     f[10] = z; | 
 | 867 |     f[12] = tx; | 
 | 868 |     f[13] = ty; | 
 | 869 |     f[14] = tz; | 
 | 870 |     f[15] = 1.0f; | 
 | 871 |     f[ 1] = f[ 2] = f[ 3] = | 
 | 872 |     f[ 4] = f[ 6] = f[ 7] = | 
 | 873 |     f[ 8] = f[ 9] = f[11] = 0.0f; | 
 | 874 |     matrixf_t rhs; | 
 | 875 |     rhs.set(f); | 
 | 876 |     c->transforms.current->multiply(rhs); | 
 | 877 |     c->transforms.invalidate(); | 
 | 878 | } | 
 | 879 |  | 
 | 880 | static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c) | 
 | 881 | { | 
 | 882 |     zNear = clampToZerof(zNear > 1 ? 1 : zNear); | 
 | 883 |     zFar  = clampToZerof(zFar  > 1 ? 1 : zFar); | 
 | 884 |     GLfloat* const f = c->transforms.vpt.matrix.editElements(); | 
 | 885 |     f[10] = div2f(zFar - zNear); | 
 | 886 |     f[14] = div2f(zFar + zNear); | 
 | 887 |     c->transforms.dirty |= transform_state_t::VIEWPORT; | 
 | 888 |     c->transforms.vpt.zNear = zNear; | 
 | 889 |     c->transforms.vpt.zFar  = zFar; | 
 | 890 | } | 
 | 891 |  | 
 | 892 |  | 
 | 893 | // ---------------------------------------------------------------------------- | 
 | 894 | }; // namespace android | 
 | 895 |  | 
 | 896 | using namespace android; | 
 | 897 |  | 
 | 898 | void glMatrixMode(GLenum mode) | 
 | 899 | { | 
 | 900 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 901 |     matrix_stack_t* stack = 0; | 
 | 902 |     switch (mode) { | 
 | 903 |     case GL_MODELVIEW: | 
 | 904 |         stack = &c->transforms.modelview; | 
 | 905 |         break; | 
 | 906 |     case GL_PROJECTION: | 
 | 907 |         stack = &c->transforms.projection; | 
 | 908 |         break; | 
 | 909 |     case GL_TEXTURE: | 
 | 910 |         stack = &c->transforms.texture[c->textures.active]; | 
 | 911 |         break; | 
 | 912 |     default: | 
 | 913 |         ogles_error(c, GL_INVALID_ENUM); | 
 | 914 |         return; | 
 | 915 |     } | 
 | 916 |     c->transforms.matrixMode = mode; | 
 | 917 |     c->transforms.current = stack; | 
 | 918 | } | 
 | 919 |  | 
 | 920 | void glLoadIdentity() | 
 | 921 | { | 
 | 922 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 923 |     c->transforms.current->loadIdentity(); // also loads the GLfixed transform | 
 | 924 |     c->transforms.invalidate(); | 
 | 925 |     c->transforms.current->dirty = 0; | 
 | 926 | } | 
 | 927 |  | 
 | 928 | void glLoadMatrixf(const GLfloat* m) | 
 | 929 | { | 
 | 930 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 931 |     c->transforms.current->load(m); | 
 | 932 |     c->transforms.invalidate(); | 
 | 933 | } | 
 | 934 |  | 
 | 935 | void glLoadMatrixx(const GLfixed* m) | 
 | 936 | { | 
 | 937 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 938 |     c->transforms.current->load(m); // also loads the GLfixed transform | 
 | 939 |     c->transforms.invalidate(); | 
 | 940 |     c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED; | 
 | 941 | } | 
 | 942 |  | 
 | 943 | void glMultMatrixf(const GLfloat* m) | 
 | 944 | { | 
 | 945 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 946 |     matrixf_t rhs; | 
 | 947 |     rhs.set(m); | 
 | 948 |     c->transforms.current->multiply(rhs); | 
 | 949 |     c->transforms.invalidate(); | 
 | 950 | } | 
 | 951 |  | 
 | 952 | void glMultMatrixx(const GLfixed* m) | 
 | 953 | { | 
 | 954 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 955 |     matrixf_t rhs; | 
 | 956 |     rhs.set(m); | 
 | 957 |     c->transforms.current->multiply(rhs); | 
 | 958 |     c->transforms.invalidate(); | 
 | 959 | } | 
 | 960 |  | 
 | 961 | void glPopMatrix() | 
 | 962 | { | 
 | 963 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 964 |     GLint err = c->transforms.current->pop(); | 
 | 965 |     if (ggl_unlikely(err)) { | 
 | 966 |         ogles_error(c, err); | 
 | 967 |         return; | 
 | 968 |     } | 
 | 969 |     c->transforms.invalidate(); | 
 | 970 | } | 
 | 971 |  | 
 | 972 | void glPushMatrix() | 
 | 973 | { | 
 | 974 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 975 |     GLint err = c->transforms.current->push(); | 
 | 976 |     if (ggl_unlikely(err)) { | 
 | 977 |         ogles_error(c, err); | 
 | 978 |         return; | 
 | 979 |     } | 
 | 980 |     c->transforms.invalidate(); | 
 | 981 | } | 
 | 982 |  | 
 | 983 | void glFrustumf( | 
 | 984 |         GLfloat left, GLfloat right,  | 
 | 985 |         GLfloat bottom, GLfloat top, | 
 | 986 |         GLfloat zNear, GLfloat zFar) | 
 | 987 | { | 
 | 988 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 989 |     frustumf(left, right, bottom, top, zNear, zFar, c); | 
 | 990 | } | 
 | 991 |  | 
 | 992 | void glFrustumx(  | 
 | 993 |         GLfixed left, GLfixed right, | 
 | 994 |         GLfixed bottom, GLfixed top, | 
 | 995 |         GLfixed zNear, GLfixed zFar) | 
 | 996 | { | 
 | 997 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 998 |     frustumf( fixedToFloat(left), fixedToFloat(right), | 
 | 999 |               fixedToFloat(bottom), fixedToFloat(top), | 
 | 1000 |               fixedToFloat(zNear), fixedToFloat(zFar), | 
 | 1001 |               c); | 
 | 1002 | } | 
 | 1003 |  | 
 | 1004 | void glOrthof(  | 
 | 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 |     orthof(left, right, bottom, top, zNear, zFar, c); | 
 | 1011 | } | 
 | 1012 |  | 
 | 1013 | void glOrthox( | 
 | 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 |     orthof( fixedToFloat(left), fixedToFloat(right), | 
 | 1020 |             fixedToFloat(bottom), fixedToFloat(top), | 
 | 1021 |             fixedToFloat(zNear), fixedToFloat(zFar), | 
 | 1022 |             c); | 
 | 1023 | } | 
 | 1024 |  | 
 | 1025 | void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z) | 
 | 1026 | { | 
 | 1027 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1028 |     c->transforms.current->rotate(a, x, y, z); | 
 | 1029 |     c->transforms.invalidate(); | 
 | 1030 | } | 
 | 1031 |  | 
 | 1032 | void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z) | 
 | 1033 | { | 
 | 1034 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1035 |     c->transforms.current->rotate(  | 
 | 1036 |             fixedToFloat(a), fixedToFloat(x), | 
 | 1037 |             fixedToFloat(y), fixedToFloat(z)); | 
 | 1038 |     c->transforms.invalidate(); | 
 | 1039 | } | 
 | 1040 |  | 
 | 1041 | void glScalef(GLfloat x, GLfloat y, GLfloat z) | 
 | 1042 | { | 
 | 1043 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1044 |     c->transforms.current->scale(x, y, z); | 
 | 1045 |     c->transforms.invalidate(); | 
 | 1046 | } | 
 | 1047 |  | 
 | 1048 | void glScalex(GLfixed x, GLfixed y, GLfixed z) | 
 | 1049 | { | 
 | 1050 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1051 |     c->transforms.current->scale( | 
 | 1052 |             fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); | 
 | 1053 |     c->transforms.invalidate(); | 
 | 1054 | } | 
 | 1055 |  | 
 | 1056 | void glTranslatef(GLfloat x, GLfloat y, GLfloat z) | 
 | 1057 | { | 
 | 1058 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1059 |     c->transforms.current->translate(x, y, z); | 
 | 1060 |     c->transforms.invalidate(); | 
 | 1061 | } | 
 | 1062 |  | 
 | 1063 | void glTranslatex(GLfixed x, GLfixed y, GLfixed z) | 
 | 1064 | { | 
 | 1065 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1066 |     c->transforms.current->translate( | 
 | 1067 |             fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); | 
 | 1068 |     c->transforms.invalidate(); | 
 | 1069 | } | 
 | 1070 |  | 
 | 1071 | void glScissor(GLint x, GLint y, GLsizei w, GLsizei h) | 
 | 1072 | { | 
 | 1073 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1074 |     ogles_scissor(c, x, y, w, h); | 
 | 1075 | } | 
 | 1076 |  | 
 | 1077 | void glViewport(GLint x, GLint y, GLsizei w, GLsizei h) | 
 | 1078 | { | 
 | 1079 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1080 |     ogles_viewport(c, x, y, w, h); | 
 | 1081 | } | 
 | 1082 |  | 
 | 1083 | void glDepthRangef(GLclampf zNear, GLclampf zFar) | 
 | 1084 | { | 
 | 1085 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1086 |     depthRangef(zNear, zFar, c); | 
 | 1087 | } | 
 | 1088 |  | 
 | 1089 | void glDepthRangex(GLclampx zNear, GLclampx zFar) | 
 | 1090 | { | 
 | 1091 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1092 |     depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c); | 
 | 1093 | } | 
 | 1094 |  | 
 | 1095 | void glPolygonOffsetx(GLfixed factor, GLfixed units) | 
 | 1096 | { | 
 | 1097 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1098 |     c->polygonOffset.factor = factor; | 
 | 1099 |     c->polygonOffset.units = units; | 
 | 1100 | } | 
 | 1101 |  | 
 | 1102 | void glPolygonOffset(GLfloat factor, GLfloat units) | 
 | 1103 | { | 
 | 1104 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1105 |     c->polygonOffset.factor = gglFloatToFixed(factor); | 
 | 1106 |     c->polygonOffset.units = gglFloatToFixed(units); | 
 | 1107 | } | 
 | 1108 |  | 
 | 1109 | GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e) | 
 | 1110 | { | 
 | 1111 |     ogles_context_t* c = ogles_context_t::get(); | 
 | 1112 |     GLbitfield status = 0; | 
 | 1113 |     GLfloat const* f = c->transforms.current->top().elements(); | 
 | 1114 |     for  (int i=0 ; i<16 ; i++) { | 
 | 1115 |         if (isnan(f[i]) || isinf(f[i])) { | 
 | 1116 |             status |= 1<<i; | 
 | 1117 |             continue; | 
 | 1118 |         } | 
 | 1119 |         e[i] = exponent(f[i]) - 7; | 
 | 1120 |         m[i] = mantissa(f[i]); | 
 | 1121 |     } | 
 | 1122 |     return status; | 
 | 1123 | } |