The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* libs/opengles/vertex.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 <stdio.h> |
| 19 | #include <stdlib.h> |
| 20 | #include "context.h" |
| 21 | #include "fp.h" |
| 22 | #include "vertex.h" |
| 23 | #include "state.h" |
| 24 | #include "matrix.h" |
| 25 | |
| 26 | namespace android { |
| 27 | |
| 28 | // ---------------------------------------------------------------------------- |
| 29 | |
| 30 | void ogles_init_vertex(ogles_context_t* c) |
| 31 | { |
| 32 | c->cull.enable = GL_FALSE; |
| 33 | c->cull.cullFace = GL_BACK; |
| 34 | c->cull.frontFace = GL_CCW; |
| 35 | |
| 36 | c->current.color.r = 0x10000; |
| 37 | c->current.color.g = 0x10000; |
| 38 | c->current.color.b = 0x10000; |
| 39 | c->current.color.a = 0x10000; |
| 40 | |
| 41 | c->currentNormal.z = 0x10000; |
| 42 | } |
| 43 | |
| 44 | void ogles_uninit_vertex(ogles_context_t* c) |
| 45 | { |
| 46 | } |
| 47 | |
| 48 | // ---------------------------------------------------------------------------- |
| 49 | // vertex processing |
| 50 | // ---------------------------------------------------------------------------- |
| 51 | |
| 52 | // Divides a vertex clip coordinates by W |
| 53 | static inline |
| 54 | void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables) |
| 55 | { |
| 56 | // [x,y,z]window = vpt * ([x,y,z]clip / clip.w) |
| 57 | // [w]window = 1/w |
| 58 | |
| 59 | // With a regular projection generated by glFrustum(), |
| 60 | // we have w=-z, therefore, w is in [zNear, zFar]. |
| 61 | // Also, zNear and zFar are stricly positive, |
| 62 | // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this |
| 63 | // means ]0, +inf[ -- however, it is always recommended |
| 64 | // to use as large values as possible for zNear. |
| 65 | // All in all, w is usually smaller than 1.0 (assuming |
| 66 | // zNear is at least 1.0); and even if zNear is smaller than 1.0 |
| 67 | // values of w won't be too big. |
| 68 | |
| 69 | const int32_t rw = gglRecip28(v->clip.w); |
| 70 | const GLfixed* const m = c->transforms.vpt.transform.matrix.m; |
| 71 | v->window.w = rw; |
| 72 | v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28); |
| 73 | v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28); |
| 74 | v->window.x = TRI_FROM_FIXED(v->window.x); |
| 75 | v->window.y = TRI_FROM_FIXED(v->window.y); |
| 76 | if (enables & GGL_ENABLE_DEPTH_TEST) { |
| 77 | v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | // frustum clipping and W-divide |
| 82 | static inline |
| 83 | void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) |
| 84 | { |
| 85 | // ndc = clip / W |
| 86 | // window = ncd * viewport |
| 87 | |
| 88 | // clip to the view-volume |
| 89 | uint32_t clip = v->flags & vertex_t::CLIP_ALL; |
| 90 | const GLfixed w = v->clip.w; |
| 91 | if (v->clip.x < -w) clip |= vertex_t::CLIP_L; |
| 92 | if (v->clip.x > w) clip |= vertex_t::CLIP_R; |
| 93 | if (v->clip.y < -w) clip |= vertex_t::CLIP_B; |
| 94 | if (v->clip.y > w) clip |= vertex_t::CLIP_T; |
| 95 | if (v->clip.z < -w) clip |= vertex_t::CLIP_N; |
| 96 | if (v->clip.z > w) clip |= vertex_t::CLIP_F; |
| 97 | |
| 98 | v->flags |= clip; |
| 99 | c->arrays.cull &= clip; |
| 100 | |
| 101 | if (ggl_likely(!clip)) { |
| 102 | // if the vertex is clipped, we don't do the perspective |
| 103 | // divide, since we don't need its window coordinates. |
| 104 | perspective(c, v, enables); |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | // frustum clipping, user clipping and W-divide |
| 109 | static inline |
| 110 | void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) |
| 111 | { |
| 112 | // compute eye coordinates |
| 113 | c->arrays.mv_transform( |
| 114 | &c->transforms.modelview.transform, &v->eye, &v->obj); |
| 115 | v->flags |= vertex_t::EYE; |
| 116 | |
| 117 | // clip this vertex against each user clip plane |
| 118 | uint32_t clip = 0; |
| 119 | int planes = c->clipPlanes.enable; |
| 120 | while (planes) { |
| 121 | const int i = 31 - gglClz(planes); |
| 122 | planes &= ~(1<<i); |
| 123 | // XXX: we should have a special dot() for 2,3,4 coords vertices |
| 124 | GLfixed d = dot4(c->clipPlanes.plane[i].equation.v, v->eye.v); |
| 125 | if (d < 0) { |
| 126 | clip |= 0x100<<i; |
| 127 | } |
| 128 | } |
| 129 | v->flags |= clip; |
| 130 | |
| 131 | clipFrustumPerspective(c, v, enables); |
| 132 | } |
| 133 | |
| 134 | // ---------------------------------------------------------------------------- |
| 135 | |
| 136 | void ogles_vertex_project(ogles_context_t* c, vertex_t* v) { |
| 137 | perspective(c, v, c->rasterizer.state.enables); |
| 138 | } |
| 139 | |
| 140 | void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v) |
| 141 | { |
| 142 | // here we assume w=1.0 and the viewport transformation |
| 143 | // has been applied already. |
| 144 | c->arrays.cull = 0; |
| 145 | v->window.x = TRI_FROM_FIXED(v->clip.x); |
| 146 | v->window.y = TRI_FROM_FIXED(v->clip.y); |
| 147 | v->window.z = v->clip.z; |
| 148 | v->window.w = v->clip.w << 12; |
| 149 | } |
| 150 | |
| 151 | void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) { |
| 152 | clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST); |
| 153 | } |
| 154 | void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) { |
| 155 | clipFrustumPerspective(c, v, 0); |
| 156 | } |
| 157 | void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) { |
| 158 | clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST); |
| 159 | } |
| 160 | void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) { |
| 161 | clipAllPerspective(c, v, 0); |
| 162 | } |
| 163 | |
| 164 | static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c) |
| 165 | { |
| 166 | const int p = plane - GL_CLIP_PLANE0; |
| 167 | if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) { |
| 168 | ogles_error(c, GL_INVALID_ENUM); |
| 169 | return; |
| 170 | } |
| 171 | |
| 172 | vec4_t& equation = c->clipPlanes.plane[p].equation; |
| 173 | memcpy(equation.v, equ, sizeof(vec4_t)); |
| 174 | |
| 175 | ogles_validate_transform(c, transform_state_t::MVIT); |
| 176 | transform_t& mvit = c->transforms.mvit4; |
| 177 | mvit.point4(&mvit, &equation, &equation); |
| 178 | } |
| 179 | |
| 180 | // ---------------------------------------------------------------------------- |
| 181 | }; // namespace android |
| 182 | // ---------------------------------------------------------------------------- |
| 183 | |
| 184 | using namespace android; |
| 185 | |
| 186 | |
| 187 | void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) |
| 188 | { |
| 189 | ogles_context_t* c = ogles_context_t::get(); |
| 190 | c->current.color.r = gglFloatToFixed(r); |
| 191 | c->currentColorClamped.r = gglClampx(c->current.color.r); |
| 192 | c->current.color.g = gglFloatToFixed(g); |
| 193 | c->currentColorClamped.g = gglClampx(c->current.color.g); |
| 194 | c->current.color.b = gglFloatToFixed(b); |
| 195 | c->currentColorClamped.b = gglClampx(c->current.color.b); |
| 196 | c->current.color.a = gglFloatToFixed(a); |
| 197 | c->currentColorClamped.a = gglClampx(c->current.color.a); |
| 198 | } |
| 199 | |
| 200 | void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a) |
| 201 | { |
| 202 | ogles_context_t* c = ogles_context_t::get(); |
| 203 | c->current.color.r = r; |
| 204 | c->current.color.g = g; |
| 205 | c->current.color.b = b; |
| 206 | c->current.color.a = a; |
| 207 | c->currentColorClamped.r = gglClampx(r); |
| 208 | c->currentColorClamped.g = gglClampx(g); |
| 209 | c->currentColorClamped.b = gglClampx(b); |
| 210 | c->currentColorClamped.a = gglClampx(a); |
| 211 | } |
| 212 | |
| 213 | void glNormal3f(GLfloat x, GLfloat y, GLfloat z) |
| 214 | { |
| 215 | ogles_context_t* c = ogles_context_t::get(); |
| 216 | c->currentNormal.x = gglFloatToFixed(x); |
| 217 | c->currentNormal.y = gglFloatToFixed(y); |
| 218 | c->currentNormal.z = gglFloatToFixed(z); |
| 219 | } |
| 220 | |
| 221 | void glNormal3x(GLfixed x, GLfixed y, GLfixed z) |
| 222 | { |
| 223 | ogles_context_t* c = ogles_context_t::get(); |
| 224 | c->currentNormal.x = x; |
| 225 | c->currentNormal.y = y; |
| 226 | c->currentNormal.z = z; |
| 227 | } |
| 228 | |
| 229 | // ---------------------------------------------------------------------------- |
| 230 | |
| 231 | void glClipPlanef(GLenum plane, const GLfloat* equ) |
| 232 | { |
| 233 | const GLfixed equx[4] = { |
| 234 | gglFloatToFixed(equ[0]), |
| 235 | gglFloatToFixed(equ[1]), |
| 236 | gglFloatToFixed(equ[2]), |
| 237 | gglFloatToFixed(equ[3]) |
| 238 | }; |
| 239 | ogles_context_t* c = ogles_context_t::get(); |
| 240 | clipPlanex(plane, equx, c); |
| 241 | } |
| 242 | |
| 243 | void glClipPlanex(GLenum plane, const GLfixed* equ) |
| 244 | { |
| 245 | ogles_context_t* c = ogles_context_t::get(); |
| 246 | clipPlanex(plane, equ, c); |
| 247 | } |