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
30namespace android {
31
32// ----------------------------------------------------------------------------
33
34static void invalidate_lighting(ogles_context_t* c);
35static void lightVertexValidate(ogles_context_t* c, vertex_t* v);
36static void lightVertexNop(ogles_context_t* c, vertex_t* v);
37static void lightVertex(ogles_context_t* c, vertex_t* v);
38static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
39
40static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
41
42static __attribute__((noinline))
43void vnorm3(GLfixed* d, const GLfixed* a);
44
45static inline void vsa3(GLfixed* d,
46    const GLfixed* m, GLfixed s, const GLfixed* a);
47static inline void vss3(GLfixed* d,
48    const GLfixed* m, GLfixed s, const GLfixed* a);
49static inline void vmla3(GLfixed* d,
50    const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
51static inline void vmul3(GLfixed* d,
52    const GLfixed* m0, const GLfixed* m1);
53
54static GLfixed fog_linear(ogles_context_t* c, GLfixed z);
55static GLfixed fog_exp(ogles_context_t* c, GLfixed z);
56static GLfixed fog_exp2(ogles_context_t* c, GLfixed z);
57
58
59// ----------------------------------------------------------------------------
60
61static void init_white(vec4_t& c) {
62    c.r = c.g = c.b = c.a = 0x10000;
63}
64
65void 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
108void ogles_uninit_light(ogles_context_t* /*c*/)
109{
110}
111
112static inline int32_t clampF(GLfixed f) CONST;
113int32_t clampF(GLfixed f) {
114    f = (f & ~(f>>31));
115    if (f >= 0x10000)
116        f = 0x10000;
117    return f;
118}
119
120static 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
124static 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
129static 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
140static inline
141void 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
147static inline
148void 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
154static inline
155void 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
161static inline
162void 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
170static inline
171void 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
177void 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
203static 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
216static 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
242static 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
276void 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
283void ogles_invalidate_lighting_mvui(ogles_context_t* c)
284{
285    invalidate_lighting(c);
286}
287
288void lightVertexNop(ogles_context_t*, vertex_t* /*v*/)
289{
290    // we should never end-up here
291}
292
293void 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
300void 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
307void 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
344void 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
452static 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
462static 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
515static 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
564static 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
578static 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
625using namespace android;
626
627#if 0
628#pragma mark -
629#pragma mark lighting APIs
630#endif
631
632void 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
642void glLightModelf(GLenum pname, GLfloat param)
643{
644    ogles_context_t* c = ogles_context_t::get();
645    lightModelx(pname, gglFloatToFixed(param), c);
646}
647
648void glLightModelx(GLenum pname, GLfixed param)
649{
650    ogles_context_t* c = ogles_context_t::get();
651    lightModelx(pname, param, c);
652}
653
654void 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
674void 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
699void 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
705void 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
711void 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
734void 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
745void 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
751void 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
757void 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
797void 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
843void 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
851void glFogx(GLenum pname, GLfixed param) {
852    ogles_context_t* c = ogles_context_t::get();
853    fogx(pname, param, c);
854}
855
856void 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
874void 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