| 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); | 
|  | 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); | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 58 | 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] | 59 | 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] | 60 |  | 
|  | 61 | // ---------------------------------------------------------------------------- | 
|  | 62 | #if 0 | 
|  | 63 | #pragma mark - | 
|  | 64 | #endif | 
|  | 65 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 113 | void ogles_invalidate_perspective(ogles_context_t* c) | 
|  | 114 | { | 
|  | 115 | c->arrays.perspective = validate_perspective; | 
|  | 116 | } | 
|  | 117 |  | 
|  | 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 |  | 
|  | 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 | 
|  | 183 | int notZero(GLfixed v) { | 
|  | 184 | return abs(v) & ~0x3; | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | static inline | 
|  | 188 | int notOne(GLfixed v) { | 
|  | 189 | return notZero(v - 0x10000); | 
|  | 190 | } | 
|  | 191 |  | 
|  | 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 |  | 
|  | 209 | void mvui_transform_t::picker() | 
|  | 210 | { | 
|  | 211 | flags = 0; | 
|  | 212 | ops = OP_ALL; | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 213 | point3 = point3__mvui; | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 214 | point4 = point4__mvui; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 215 | } | 
|  | 216 |  | 
|  | 217 | void transform_t::dump(const char* what) | 
|  | 218 | { | 
|  | 219 | GLfixed const * const m = matrix.m; | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 220 | ALOGD("%s:", what); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 221 | for (int i=0 ; i<4 ; i++) | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 222 | 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] | 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 |  | 
|  | 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 |  | 
|  | 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++) { | 
| Dan Stoza | c044ae5 | 2016-01-08 10:52:16 -0800 | [diff] [blame] | 256 | const float rhs_i0 = rhs.m[ I(i,0) ]; | 
|  | 257 | float ri0 = m[ I(0,0) ] * rhs_i0; | 
|  | 258 | float ri1 = m[ I(0,1) ] * rhs_i0; | 
|  | 259 | float ri2 = m[ I(0,2) ] * rhs_i0; | 
|  | 260 | float ri3 = m[ I(0,3) ] * rhs_i0; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 261 | for (int j=1 ; j<4 ; j++) { | 
| Dan Stoza | c044ae5 | 2016-01-08 10:52:16 -0800 | [diff] [blame] | 262 | const float rhs_ij = rhs.m[ I(i,j) ]; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
|  | 275 | void matrixf_t::dump(const char* what) { | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 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)]); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 281 | } | 
|  | 282 |  | 
|  | 283 | void matrixf_t::loadIdentity() { | 
|  | 284 | memcpy(m, gIdentityf, sizeof(m)); | 
|  | 285 | } | 
|  | 286 |  | 
|  | 287 | void matrixf_t::set(const GLfixed* rhs) { | 
|  | 288 | load(rhs); | 
|  | 289 | } | 
|  | 290 |  | 
|  | 291 | void matrixf_t::set(const GLfloat* rhs) { | 
|  | 292 | load(rhs); | 
|  | 293 | } | 
|  | 294 |  | 
|  | 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 |  | 
|  | 303 | void matrixf_t::load(const GLfloat* rhs) { | 
|  | 304 | memcpy(m, rhs, sizeof(m)); | 
|  | 305 | } | 
|  | 306 |  | 
|  | 307 | void matrixf_t::load(const matrixf_t& rhs) { | 
|  | 308 | operator = (rhs); | 
|  | 309 | } | 
|  | 310 |  | 
|  | 311 | void matrixf_t::multiply(const matrixf_t& rhs) { | 
|  | 312 | matrixf_t r; | 
|  | 313 | multiply(r, *this, rhs); | 
|  | 314 | operator = (r); | 
|  | 315 | } | 
|  | 316 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 395 | void matrix_stack_t::uninit() { | 
|  | 396 | delete [] stack; | 
|  | 397 | delete [] ops; | 
|  | 398 | } | 
|  | 399 |  | 
|  | 400 | void matrix_stack_t::loadIdentity() { | 
|  | 401 | transform.loadIdentity(); | 
|  | 402 | stack[depth].loadIdentity(); | 
|  | 403 | ops[depth] = OP_IDENTITY; | 
|  | 404 | } | 
|  | 405 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 | 
|  | 528 | GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { | 
|  | 529 | return a*d - b*c; | 
|  | 530 | } | 
|  | 531 |  | 
|  | 532 | static inline | 
|  | 533 | GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { | 
|  | 534 | return b*c - a*d; | 
|  | 535 | } | 
|  | 536 |  | 
|  | 537 | static __attribute__((noinline)) | 
|  | 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 |  | 
|  | 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 |  | 
|  | 599 | void transform_state_t::update_mvui() | 
|  | 600 | { | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 601 | GLfloat r[16]; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 602 | const GLfloat* const mv = modelview.top().elements(); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 603 |  | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 615 | invert(r, mv); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 616 |  | 
|  | 617 | GLfixed* const x = mvui.matrix.m; | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 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 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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; | 
| Martin Storsjo | d914215 | 2009-08-10 13:02:28 +0200 | [diff] [blame] | 714 | if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) | 
|  | 715 | c->transforms.dirty |= transform_state_t::MVP; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 716 | } | 
|  | 717 |  | 
|  | 718 | // ---------------------------------------------------------------------------- | 
|  | 719 | #if 0 | 
|  | 720 | #pragma mark - | 
|  | 721 | #pragma mark matrix * vertex | 
|  | 722 | #endif | 
|  | 723 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
| Mathias Agopian | 04a3f57 | 2010-02-02 18:48:15 -0800 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 771 | 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] | 772 | // this is used for transforming light positions back to object space. | 
| Mathias Agopian | b44efdc | 2009-11-02 18:33:08 -0800 | [diff] [blame] | 773 | // w is used as a switch for directional lights, so we need | 
| Mathias Agopian | 69ca17a | 2009-06-02 22:05:04 -0700 | [diff] [blame] | 774 | // to preserve it. | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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; | 
| Mathias Agopian | b44efdc | 2009-11-02 18:33:08 -0800 | [diff] [blame] | 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; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 784 | } | 
|  | 785 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
|  | 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 |  | 
|  | 804 | void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { | 
|  | 805 | if (lhs != rhs) | 
|  | 806 | *lhs = *rhs; | 
|  | 807 | } | 
|  | 808 |  | 
|  | 809 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 1094 | void glDepthRangef(GLclampf zNear, GLclampf zFar) | 
|  | 1095 | { | 
|  | 1096 | ogles_context_t* c = ogles_context_t::get(); | 
|  | 1097 | depthRangef(zNear, zFar, c); | 
|  | 1098 | } | 
|  | 1099 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 | } |