Home | History | Annotate | Download | only in libagl
      1 /* libs/opengles/light.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 "context.h"
     20 #include "fp.h"
     21 #include "light.h"
     22 #include "state.h"
     23 #include "matrix.h"
     24 
     25 
     26 #if defined(__arm__) && defined(__thumb__)
     27 #warning "light.cpp should not be compiled in thumb on ARM."
     28 #endif
     29 
     30 namespace android {
     31 
     32 // ----------------------------------------------------------------------------
     33 
     34 static void invalidate_lighting(ogles_context_t* c);
     35 static void lightVertexValidate(ogles_context_t* c, vertex_t* v);
     36 static void lightVertexNop(ogles_context_t* c, vertex_t* v);
     37 static void lightVertex(ogles_context_t* c, vertex_t* v);
     38 static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
     39 
     40 static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
     41 
     42 static __attribute__((noinline))
     43 void vnorm3(GLfixed* d, const GLfixed* a);
     44 
     45 static inline void vsa3(GLfixed* d,
     46     const GLfixed* m, GLfixed s, const GLfixed* a);
     47 static inline void vss3(GLfixed* d,
     48     const GLfixed* m, GLfixed s, const GLfixed* a);
     49 static inline void vmla3(GLfixed* d,
     50     const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
     51 static inline void vmul3(GLfixed* d,
     52     const GLfixed* m0, const GLfixed* m1);
     53 
     54 static GLfixed fog_linear(ogles_context_t* c, GLfixed z);
     55 static GLfixed fog_exp(ogles_context_t* c, GLfixed z);
     56 static GLfixed fog_exp2(ogles_context_t* c, GLfixed z);
     57 
     58 
     59 // ----------------------------------------------------------------------------
     60 
     61 static void init_white(vec4_t& c) {
     62     c.r = c.g = c.b = c.a = 0x10000;
     63 }
     64 
     65 void ogles_init_light(ogles_context_t* c)
     66 {
     67     for (unsigned int i=0 ; i<OGLES_MAX_LIGHTS ; i++) {
     68         c->lighting.lights[i].ambient.a = 0x10000;
     69         c->lighting.lights[i].position.z = 0x10000;
     70         c->lighting.lights[i].spotDir.z = -0x10000;
     71         c->lighting.lights[i].spotCutoff = gglIntToFixed(180);
     72         c->lighting.lights[i].attenuation[0] = 0x10000;
     73     }
     74     init_white(c->lighting.lights[0].diffuse);
     75     init_white(c->lighting.lights[0].specular);
     76 
     77     c->lighting.front.ambient.r =
     78     c->lighting.front.ambient.g =
     79     c->lighting.front.ambient.b = gglFloatToFixed(0.2f);
     80     c->lighting.front.ambient.a = 0x10000;
     81     c->lighting.front.diffuse.r =
     82     c->lighting.front.diffuse.g =
     83     c->lighting.front.diffuse.b = gglFloatToFixed(0.8f);
     84     c->lighting.front.diffuse.a = 0x10000;
     85     c->lighting.front.specular.a = 0x10000;
     86     c->lighting.front.emission.a = 0x10000;
     87 
     88     c->lighting.lightModel.ambient.r =
     89     c->lighting.lightModel.ambient.g =
     90     c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f);
     91     c->lighting.lightModel.ambient.a = 0x10000;
     92 
     93     c->lighting.colorMaterial.face = GL_FRONT_AND_BACK;
     94     c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE;
     95 
     96     c->fog.mode = GL_EXP;
     97     c->fog.fog = fog_exp;
     98     c->fog.density = 0x10000;
     99     c->fog.end = 0x10000;
    100     c->fog.invEndMinusStart = 0x10000;
    101 
    102     invalidate_lighting(c);
    103 
    104     c->rasterizer.procs.shadeModel(c, GL_SMOOTH);
    105     c->lighting.shadeModel = GL_SMOOTH;
    106 }
    107 
    108 void ogles_uninit_light(ogles_context_t* /*c*/)
    109 {
    110 }
    111 
    112 static inline int32_t clampF(GLfixed f) CONST;
    113 int32_t clampF(GLfixed f) {
    114     f = (f & ~(f>>31));
    115     if (f >= 0x10000)
    116         f = 0x10000;
    117     return f;
    118 }
    119 
    120 static GLfixed fog_linear(ogles_context_t* c, GLfixed z) {
    121     return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart));
    122 }
    123 
    124 static GLfixed fog_exp(ogles_context_t* c, GLfixed z) {
    125     const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z)));
    126     return clampF(gglFloatToFixed(fastexpf(-e)));
    127 }
    128 
    129 static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) {
    130     const float e = fixedToFloat(gglMulx(c->fog.density, z));
    131     return clampF(gglFloatToFixed(fastexpf(-e*e)));
    132 }
    133 
    134 // ----------------------------------------------------------------------------
    135 #if 0
    136 #pragma mark -
    137 #pragma mark math helpers
    138 #endif
    139 
    140 static inline
    141 void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) {
    142     d[0] = gglMulx(m[0], s);
    143     d[1] = gglMulx(m[1], s);
    144     d[2] = gglMulx(m[2], s);
    145 }
    146 
    147 static inline
    148 void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
    149     d[0] = gglMulAddx(m[0], s, a[0]);
    150     d[1] = gglMulAddx(m[1], s, a[1]);
    151     d[2] = gglMulAddx(m[2], s, a[2]);
    152 }
    153 
    154 static inline
    155 void vss3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
    156     d[0] = gglMulSubx(m[0], s, a[0]);
    157     d[1] = gglMulSubx(m[1], s, a[1]);
    158     d[2] = gglMulSubx(m[2], s, a[2]);
    159 }
    160 
    161 static inline
    162 void vmla3(GLfixed* d,
    163         const GLfixed* m0, const GLfixed* m1, const GLfixed* a)
    164 {
    165     d[0] = gglMulAddx(m0[0], m1[0], a[0]);
    166     d[1] = gglMulAddx(m0[1], m1[1], a[1]);
    167     d[2] = gglMulAddx(m0[2], m1[2], a[2]);
    168 }
    169 
    170 static inline
    171 void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) {
    172     d[0] = gglMulx(m0[0], m1[0]);
    173     d[1] = gglMulx(m0[1], m1[1]);
    174     d[2] = gglMulx(m0[2], m1[2]);
    175 }
    176 
    177 void vnorm3(GLfixed* d, const GLfixed* a)
    178 {
    179     // we must take care of overflows when normalizing a vector
    180     GLfixed n;
    181     int32_t x = a[0];   x = x>=0 ? x : -x;
    182     int32_t y = a[1];   y = y>=0 ? y : -y;
    183     int32_t z = a[2];   z = z>=0 ? z : -z;
    184     if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) {
    185         // in this case this will all fit on 32 bits
    186         n = x*x + y*y + z*z;
    187         n = gglSqrtRecipx(n);
    188         n <<= 8;
    189     } else {
    190         // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117)
    191         n = vsquare3(x, y, z);
    192         n = gglSqrtRecipx(n);
    193     }
    194     vscale3(d, a, n);
    195 }
    196 
    197 // ----------------------------------------------------------------------------
    198 #if 0
    199 #pragma mark -
    200 #pragma mark lighting equations
    201 #endif
    202 
    203 static inline void light_picker(ogles_context_t* c)
    204 {
    205     if (ggl_likely(!c->lighting.enable)) {
    206         c->lighting.lightVertex = lightVertexNop;
    207         return;
    208     }
    209     if (c->lighting.colorMaterial.enable) {
    210         c->lighting.lightVertex = lightVertexMaterial;
    211     } else {
    212         c->lighting.lightVertex = lightVertex;
    213     }
    214 }
    215 
    216 static inline void validate_light_mvi(ogles_context_t* c)
    217 {
    218     uint32_t en = c->lighting.enabledLights;
    219     // Vector from object to viewer, in eye coordinates
    220     while (en) {
    221         const int i = 31 - gglClz(en);
    222         en &= ~(1<<i);
    223         light_t& l = c->lighting.lights[i];
    224 #if OBJECT_SPACE_LIGHTING
    225         c->transforms.mvui.point4(&c->transforms.mvui,
    226                 &l.objPosition, &l.position);
    227 #else
    228         l.objPosition = l.position;
    229 #endif
    230         vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
    231     }
    232     const vec4_t eyeViewer = {{{ 0, 0, 0x10000, 0 }}};
    233 #if OBJECT_SPACE_LIGHTING
    234     c->transforms.mvui.point3(&c->transforms.mvui,
    235             &c->lighting.objViewer, &eyeViewer);
    236     vnorm3(c->lighting.objViewer.v, c->lighting.objViewer.v);
    237 #else
    238     c->lighting.objViewer = eyeViewer;
    239 #endif
    240 }
    241 
    242 static inline void validate_light(ogles_context_t* c)
    243 {
    244     // if colorMaterial is enabled, we get the color from the vertex
    245     if (!c->lighting.colorMaterial.enable) {
    246         material_t& material = c->lighting.front;
    247         uint32_t en = c->lighting.enabledLights;
    248         while (en) {
    249             const int i = 31 - gglClz(en);
    250             en &= ~(1<<i);
    251             light_t& l = c->lighting.lights[i];
    252             vmul3(l.implicitAmbient.v,  material.ambient.v,  l.ambient.v);
    253             vmul3(l.implicitDiffuse.v,  material.diffuse.v,  l.diffuse.v);
    254             vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
    255 
    256             // this is just a flag to tell if we have a specular component
    257             l.implicitSpecular.v[3] =
    258                     l.implicitSpecular.r |
    259                     l.implicitSpecular.g |
    260                     l.implicitSpecular.b;
    261 
    262             l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0;
    263             if (l.rConstAttenuation)
    264                 l.rConstAttenuation = gglRecipFast(l.attenuation[0]);
    265         }
    266         // emission and ambient for the whole scene
    267         vmla3(  c->lighting.implicitSceneEmissionAndAmbient.v,
    268                 c->lighting.lightModel.ambient.v,
    269                 material.ambient.v,
    270                 material.emission.v);
    271         c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
    272     }
    273     validate_light_mvi(c);
    274 }
    275 
    276 void invalidate_lighting(ogles_context_t* c)
    277 {
    278     // TODO: pick lightVertexValidate or lightVertexValidateMVI
    279     // instead of systematically the heavier lightVertexValidate()
    280     c->lighting.lightVertex = lightVertexValidate;
    281 }
    282 
    283 void ogles_invalidate_lighting_mvui(ogles_context_t* c)
    284 {
    285     invalidate_lighting(c);
    286 }
    287 
    288 void lightVertexNop(ogles_context_t*, vertex_t* /*v*/)
    289 {
    290     // we should never end-up here
    291 }
    292 
    293 void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v)
    294 {
    295     validate_light_mvi(c);
    296     light_picker(c);
    297     c->lighting.lightVertex(c, v);
    298 }
    299 
    300 void lightVertexValidate(ogles_context_t* c, vertex_t* v)
    301 {
    302     validate_light(c);
    303     light_picker(c);
    304     c->lighting.lightVertex(c, v);
    305 }
    306 
    307 void lightVertexMaterial(ogles_context_t* c, vertex_t* v)
    308 {
    309     // fetch the material color
    310     const GLvoid* cp = c->arrays.color.element(
    311             v->index & vertex_cache_t::INDEX_MASK);
    312     c->arrays.color.fetch(c, v->color.v, cp);
    313 
    314     // acquire the color-material from the vertex
    315     material_t& material = c->lighting.front;
    316     material.ambient =
    317     material.diffuse = v->color;
    318     // implicit arguments need to be computed per/vertex
    319     uint32_t en = c->lighting.enabledLights;
    320     while (en) {
    321         const int i = 31 - gglClz(en);
    322         en &= ~(1<<i);
    323         light_t& l = c->lighting.lights[i];
    324         vmul3(l.implicitAmbient.v,  material.ambient.v,  l.ambient.v);
    325         vmul3(l.implicitDiffuse.v,  material.diffuse.v,  l.diffuse.v);
    326         vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
    327         // this is just a flag to tell if we have a specular component
    328         l.implicitSpecular.v[3] =
    329                 l.implicitSpecular.r |
    330                 l.implicitSpecular.g |
    331                 l.implicitSpecular.b;
    332     }
    333     // emission and ambient for the whole scene
    334     vmla3(  c->lighting.implicitSceneEmissionAndAmbient.v,
    335             c->lighting.lightModel.ambient.v,
    336             material.ambient.v,
    337             material.emission.v);
    338     c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
    339 
    340     // now we can light our vertex as usual
    341     lightVertex(c, v);
    342 }
    343 
    344 void lightVertex(ogles_context_t* c, vertex_t* v)
    345 {
    346     // emission and ambient for the whole scene
    347     vec4_t r = c->lighting.implicitSceneEmissionAndAmbient;
    348     const vec4_t objViewer = c->lighting.objViewer;
    349 
    350     uint32_t en = c->lighting.enabledLights;
    351     if (ggl_likely(en)) {
    352         // since we do the lighting in object-space, we don't need to
    353         // transform each normal. However, we might still have to normalize
    354         // it if GL_NORMALIZE is enabled.
    355         vec4_t n;
    356         c->arrays.normal.fetch(c, n.v,
    357             c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK));
    358 
    359 #if !OBJECT_SPACE_LIGHTING
    360         c->transforms.mvui.point3(&c->transforms.mvui, &n, &n);
    361 #endif
    362 
    363         // TODO: right now we handle GL_RESCALE_NORMALS as if it were
    364         // GL_NORMALIZE. We could optimize this by  scaling mvui
    365         // appropriately instead.
    366         if (c->transforms.rescaleNormals)
    367             vnorm3(n.v, n.v);
    368 
    369         const material_t& material = c->lighting.front;
    370         const int twoSide = c->lighting.lightModel.twoSide;
    371 
    372         while (en) {
    373             const int i = 31 - gglClz(en);
    374             en &= ~(1<<i);
    375             const light_t& l = c->lighting.lights[i];
    376 
    377             vec4_t d, t;
    378             GLfixed s;
    379             GLfixed sqDist = 0x10000;
    380 
    381             // compute vertex-to-light vector
    382             if (ggl_unlikely(l.position.w)) {
    383                 // lightPos/1.0 - vertex/vertex.w == lightPos*vertex.w - vertex
    384 #if !OBJECT_SPACE_LIGHTING
    385                 vec4_t o;
    386                 const transform_t& mv = c->transforms.modelview.transform;
    387                 mv.point4(&mv, &o, &v->obj);
    388                 vss3(d.v, l.objPosition.v, o.w, o.v);
    389 #else
    390                 vss3(d.v, l.objPosition.v, v->obj.w, v->obj.v);
    391 #endif
    392                 sqDist = dot3(d.v, d.v);
    393                 vscale3(d.v, d.v, gglSqrtRecipx(sqDist));
    394             } else {
    395                 // TODO: avoid copy here
    396                 d = l.normalizedObjPosition;
    397             }
    398 
    399             // ambient & diffuse
    400             s = dot3(n.v, d.v);
    401             s = (s<0) ? (twoSide?(-s):0) : s;
    402             vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v);
    403 
    404             // specular
    405             if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
    406                 vec4_t h;
    407                 h.x = d.x + objViewer.x;
    408                 h.y = d.y + objViewer.y;
    409                 h.z = d.z + objViewer.z;
    410                 vnorm3(h.v, h.v);
    411                 s = dot3(n.v, h.v);
    412                 s = (s<0) ? (twoSide?(-s):0) : s;
    413                 if (s > 0) {
    414                     s = gglPowx(s, material.shininess);
    415                     vsa3(t.v, l.implicitSpecular.v, s, t.v);
    416                 }
    417             }
    418 
    419             // spot
    420             if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) {
    421                 GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v);
    422                 if (spotAtt >= l.spotCutoffCosine) {
    423                     vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp));
    424                 }
    425             }
    426 
    427             // attenuation
    428             if (ggl_unlikely(l.position.w)) {
    429                 if (l.rConstAttenuation) {
    430                     s = l.rConstAttenuation;
    431                 } else {
    432                     s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]);
    433                     if (l.attenuation[1])
    434                         s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s);
    435                     s = gglRecipFast(s);
    436                 }
    437                 vscale3(t.v, t.v, s);
    438             }
    439 
    440             r.r += t.r;
    441             r.g += t.g;
    442             r.b += t.b;
    443         }
    444     }
    445     v->color.r = gglClampx(r.r);
    446     v->color.g = gglClampx(r.g);
    447     v->color.b = gglClampx(r.b);
    448     v->color.a = gglClampx(r.a);
    449     v->flags |= vertex_t::LIT;
    450 }
    451 
    452 static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c)
    453 {
    454     if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) {
    455         ogles_error(c, GL_INVALID_ENUM);
    456         return;
    457     }
    458     c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE;
    459     invalidate_lighting(c);
    460 }
    461 
    462 static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c)
    463 {
    464     if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
    465         ogles_error(c, GL_INVALID_ENUM);
    466         return;
    467     }
    468 
    469     light_t& light = c->lighting.lights[i-GL_LIGHT0];
    470     switch (pname) {
    471     case GL_SPOT_EXPONENT:
    472         if (GGLfixed(param) >= gglIntToFixed(128)) {
    473             ogles_error(c, GL_INVALID_VALUE);
    474             return;
    475         }
    476         light.spotExp = param;
    477         break;
    478     case GL_SPOT_CUTOFF:
    479         if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) {
    480             ogles_error(c, GL_INVALID_VALUE);
    481             return;
    482         }
    483         light.spotCutoff = param;
    484         light.spotCutoffCosine =
    485                 gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param));
    486         break;
    487     case GL_CONSTANT_ATTENUATION:
    488         if (param < 0) {
    489             ogles_error(c, GL_INVALID_VALUE);
    490             return;
    491         }
    492         light.attenuation[0] = param;
    493         break;
    494     case GL_LINEAR_ATTENUATION:
    495         if (param < 0) {
    496             ogles_error(c, GL_INVALID_VALUE);
    497             return;
    498         }
    499         light.attenuation[1] = param;
    500         break;
    501     case GL_QUADRATIC_ATTENUATION:
    502         if (param < 0) {
    503             ogles_error(c, GL_INVALID_VALUE);
    504             return;
    505         }
    506         light.attenuation[2] = param;
    507         break;
    508     default:
    509         ogles_error(c, GL_INVALID_ENUM);
    510         return;
    511     }
    512     invalidate_lighting(c);
    513 }
    514 
    515 static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c)
    516 {
    517     if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
    518         ogles_error(c, GL_INVALID_ENUM);
    519         return;
    520     }
    521 
    522     GLfixed* what;
    523     light_t& light = c->lighting.lights[i-GL_LIGHT0];
    524     switch (pname) {
    525     case GL_AMBIENT:
    526         what = light.ambient.v;
    527         break;
    528     case GL_DIFFUSE:
    529         what = light.diffuse.v;
    530         break;
    531     case GL_SPECULAR:
    532         what = light.specular.v;
    533         break;
    534     case GL_POSITION: {
    535         ogles_validate_transform(c, transform_state_t::MODELVIEW);
    536         transform_t& mv = c->transforms.modelview.transform;
    537         mv.point4(&mv, &light.position, reinterpret_cast<vec4_t const*>(params));
    538         invalidate_lighting(c);
    539         return;
    540     }
    541     case GL_SPOT_DIRECTION: {
    542 #if OBJECT_SPACE_LIGHTING
    543         ogles_validate_transform(c, transform_state_t::MVUI);
    544         transform_t& mvui = c->transforms.mvui;
    545         mvui.point3(&mvui, &light.spotDir, reinterpret_cast<vec4_t const*>(params));
    546 #else
    547         light.spotDir = *reinterpret_cast<vec4_t const*>(params);
    548 #endif
    549         vnorm3(light.normalizedSpotDir.v, light.spotDir.v);
    550         invalidate_lighting(c);
    551         return;
    552     }
    553     default:
    554         lightx(i, pname, params[0], c);
    555         return;
    556     }
    557     what[0] = params[0];
    558     what[1] = params[1];
    559     what[2] = params[2];
    560     what[3] = params[3];
    561     invalidate_lighting(c);
    562 }
    563 
    564 static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c)
    565 {
    566     if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
    567         ogles_error(c, GL_INVALID_ENUM);
    568         return;
    569     }
    570     if (ggl_unlikely(pname != GL_SHININESS)) {
    571         ogles_error(c, GL_INVALID_ENUM);
    572         return;
    573     }
    574     c->lighting.front.shininess = param;
    575     invalidate_lighting(c);
    576 }
    577 
    578 static void fogx(GLenum pname, GLfixed param, ogles_context_t* c)
    579 {
    580     switch (pname) {
    581     case GL_FOG_DENSITY:
    582         if (param >= 0) {
    583             c->fog.density = param;
    584             break;
    585         }
    586         ogles_error(c, GL_INVALID_VALUE);
    587         break;
    588     case GL_FOG_START:
    589         c->fog.start = param;
    590         c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
    591         break;
    592     case GL_FOG_END:
    593         c->fog.end = param;
    594         c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
    595         break;
    596     case GL_FOG_MODE:
    597         switch (param) {
    598         case GL_LINEAR:
    599             c->fog.mode = param;
    600             c->fog.fog = fog_linear;
    601             break;
    602         case GL_EXP:
    603             c->fog.mode = param;
    604             c->fog.fog = fog_exp;
    605             break;
    606         case GL_EXP2:
    607             c->fog.mode = param;
    608             c->fog.fog = fog_exp2;
    609             break;
    610         default:
    611             ogles_error(c, GL_INVALID_ENUM);
    612             break;
    613         }
    614         break;
    615     default:
    616         ogles_error(c, GL_INVALID_ENUM);
    617         break;
    618     }
    619 }
    620 
    621 // ----------------------------------------------------------------------------
    622 }; // namespace android
    623 // ----------------------------------------------------------------------------
    624 
    625 using namespace android;
    626 
    627 #if 0
    628 #pragma mark -
    629 #pragma mark lighting APIs
    630 #endif
    631 
    632 void glShadeModel(GLenum mode)
    633 {
    634     ogles_context_t* c = ogles_context_t::get();
    635     if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) {
    636         ogles_error(c, GL_INVALID_ENUM);
    637         return;
    638     }
    639     c->lighting.shadeModel = mode;
    640 }
    641 
    642 void glLightModelf(GLenum pname, GLfloat param)
    643 {
    644     ogles_context_t* c = ogles_context_t::get();
    645     lightModelx(pname, gglFloatToFixed(param), c);
    646 }
    647 
    648 void glLightModelx(GLenum pname, GLfixed param)
    649 {
    650     ogles_context_t* c = ogles_context_t::get();
    651     lightModelx(pname, param, c);
    652 }
    653 
    654 void glLightModelfv(GLenum pname, const GLfloat *params)
    655 {
    656     ogles_context_t* c = ogles_context_t::get();
    657     if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
    658         lightModelx(pname, gglFloatToFixed(params[0]), c);
    659         return;
    660     }
    661 
    662     if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
    663         ogles_error(c, GL_INVALID_ENUM);
    664         return;
    665     }
    666 
    667     c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]);
    668     c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]);
    669     c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]);
    670     c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]);
    671     invalidate_lighting(c);
    672 }
    673 
    674 void glLightModelxv(GLenum pname, const GLfixed *params)
    675 {
    676     ogles_context_t* c = ogles_context_t::get();
    677     if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
    678         lightModelx(pname, params[0], c);
    679         return;
    680     }
    681 
    682     if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
    683         ogles_error(c, GL_INVALID_ENUM);
    684         return;
    685     }
    686 
    687     c->lighting.lightModel.ambient.r = params[0];
    688     c->lighting.lightModel.ambient.g = params[1];
    689     c->lighting.lightModel.ambient.b = params[2];
    690     c->lighting.lightModel.ambient.a = params[3];
    691     invalidate_lighting(c);
    692 }
    693 
    694 // ----------------------------------------------------------------------------
    695 #if 0
    696 #pragma mark -
    697 #endif
    698 
    699 void glLightf(GLenum i, GLenum pname, GLfloat param)
    700 {
    701     ogles_context_t* c = ogles_context_t::get();
    702     lightx(i, pname, gglFloatToFixed(param), c);
    703 }
    704 
    705 void glLightx(GLenum i, GLenum pname, GLfixed param)
    706 {
    707     ogles_context_t* c = ogles_context_t::get();
    708     lightx(i, pname, param, c);
    709 }
    710 
    711 void glLightfv(GLenum i, GLenum pname, const GLfloat *params)
    712 {
    713     ogles_context_t* c = ogles_context_t::get();
    714     switch (pname) {
    715     case GL_SPOT_EXPONENT:
    716     case GL_SPOT_CUTOFF:
    717     case GL_CONSTANT_ATTENUATION:
    718     case GL_LINEAR_ATTENUATION:
    719     case GL_QUADRATIC_ATTENUATION:
    720         lightx(i, pname, gglFloatToFixed(params[0]), c);
    721         return;
    722     }
    723 
    724     GLfixed paramsx[4];
    725     paramsx[0] = gglFloatToFixed(params[0]);
    726     paramsx[1] = gglFloatToFixed(params[1]);
    727     paramsx[2] = gglFloatToFixed(params[2]);
    728     if (pname != GL_SPOT_DIRECTION)
    729         paramsx[3] = gglFloatToFixed(params[3]);
    730 
    731     lightxv(i, pname, paramsx, c);
    732 }
    733 
    734 void glLightxv(GLenum i, GLenum pname, const GLfixed *params)
    735 {
    736     ogles_context_t* c = ogles_context_t::get();
    737     lightxv(i, pname, params, c);
    738 }
    739 
    740 // ----------------------------------------------------------------------------
    741 #if 0
    742 #pragma mark -
    743 #endif
    744 
    745 void glMaterialf(GLenum face, GLenum pname, GLfloat param)
    746 {
    747     ogles_context_t* c = ogles_context_t::get();
    748     materialx(face, pname, gglFloatToFixed(param), c);
    749 }
    750 
    751 void glMaterialx(GLenum face, GLenum pname, GLfixed param)
    752 {
    753     ogles_context_t* c = ogles_context_t::get();
    754     materialx(face, pname, param, c);
    755 }
    756 
    757 void glMaterialfv(
    758     GLenum face, GLenum pname, const GLfloat *params)
    759 {
    760     ogles_context_t* c = ogles_context_t::get();
    761     if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
    762         ogles_error(c, GL_INVALID_ENUM);
    763         return;
    764     }
    765     GLfixed* what=0;
    766     GLfixed* other=0;
    767     switch (pname) {
    768     case GL_AMBIENT:    what = c->lighting.front.ambient.v; break;
    769     case GL_DIFFUSE:    what = c->lighting.front.diffuse.v; break;
    770     case GL_SPECULAR:   what = c->lighting.front.specular.v; break;
    771     case GL_EMISSION:   what = c->lighting.front.emission.v; break;
    772     case GL_AMBIENT_AND_DIFFUSE:
    773         what  = c->lighting.front.ambient.v;
    774         other = c->lighting.front.diffuse.v;
    775         break;
    776     case GL_SHININESS:
    777         c->lighting.front.shininess = gglFloatToFixed(params[0]);
    778         invalidate_lighting(c);
    779         return;
    780     default:
    781         ogles_error(c, GL_INVALID_ENUM);
    782         return;
    783     }
    784     what[0] = gglFloatToFixed(params[0]);
    785     what[1] = gglFloatToFixed(params[1]);
    786     what[2] = gglFloatToFixed(params[2]);
    787     what[3] = gglFloatToFixed(params[3]);
    788     if (other) {
    789         other[0] = what[0];
    790         other[1] = what[1];
    791         other[2] = what[2];
    792         other[3] = what[3];
    793     }
    794     invalidate_lighting(c);
    795 }
    796 
    797 void glMaterialxv(
    798     GLenum face, GLenum pname, const GLfixed *params)
    799 {
    800     ogles_context_t* c = ogles_context_t::get();
    801     if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
    802         ogles_error(c, GL_INVALID_ENUM);
    803         return;
    804     }
    805     GLfixed* what=0;
    806     GLfixed* other=0;
    807     switch (pname) {
    808     case GL_AMBIENT:    what = c->lighting.front.ambient.v; break;
    809     case GL_DIFFUSE:    what = c->lighting.front.diffuse.v; break;
    810     case GL_SPECULAR:   what = c->lighting.front.specular.v; break;
    811     case GL_EMISSION:   what = c->lighting.front.emission.v; break;
    812     case GL_AMBIENT_AND_DIFFUSE:
    813         what  = c->lighting.front.ambient.v;
    814         other = c->lighting.front.diffuse.v;
    815         break;
    816     case GL_SHININESS:
    817         c->lighting.front.shininess = gglFloatToFixed(params[0]);
    818         invalidate_lighting(c);
    819         return;
    820     default:
    821         ogles_error(c, GL_INVALID_ENUM);
    822         return;
    823     }
    824     what[0] = params[0];
    825     what[1] = params[1];
    826     what[2] = params[2];
    827     what[3] = params[3];
    828     if (other) {
    829         other[0] = what[0];
    830         other[1] = what[1];
    831         other[2] = what[2];
    832         other[3] = what[3];
    833     }
    834     invalidate_lighting(c);
    835 }
    836 
    837 // ----------------------------------------------------------------------------
    838 #if 0
    839 #pragma mark -
    840 #pragma mark fog
    841 #endif
    842 
    843 void glFogf(GLenum pname, GLfloat param) {
    844     ogles_context_t* c = ogles_context_t::get();
    845     GLfixed paramx = (GLfixed)param;
    846     if (pname != GL_FOG_MODE)
    847         paramx = gglFloatToFixed(param);
    848     fogx(pname, paramx, c);
    849 }
    850 
    851 void glFogx(GLenum pname, GLfixed param) {
    852     ogles_context_t* c = ogles_context_t::get();
    853     fogx(pname, param, c);
    854 }
    855 
    856 void glFogfv(GLenum pname, const GLfloat *params)
    857 {
    858     ogles_context_t* c = ogles_context_t::get();
    859     if (pname != GL_FOG_COLOR) {
    860         GLfixed paramx = (GLfixed)params[0];
    861         if (pname != GL_FOG_MODE)
    862             paramx = gglFloatToFixed(params[0]);
    863         fogx(pname, paramx, c);
    864         return;
    865     }
    866     GLfixed paramsx[4];
    867     paramsx[0] = gglFloatToFixed(params[0]);
    868     paramsx[1] = gglFloatToFixed(params[1]);
    869     paramsx[2] = gglFloatToFixed(params[2]);
    870     paramsx[3] = gglFloatToFixed(params[3]);
    871     c->rasterizer.procs.fogColor3xv(c, paramsx);
    872 }
    873 
    874 void glFogxv(GLenum pname, const GLfixed *params)
    875 {
    876     ogles_context_t* c = ogles_context_t::get();
    877     if (pname != GL_FOG_COLOR) {
    878         fogx(pname, params[0], c);
    879         return;
    880     }
    881     c->rasterizer.procs.fogColor3xv(c, params);
    882 }
    883