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