t_vb_lighttmp.h revision 22ae633d1ea636e0e07ba044a0f8fa2195c83bc6
1/*
2 * Mesa 3-D graphics library
3 * Version:  5.1
4 *
5 * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 *
25 * Authors:
26 *    Brian Paul
27 *    Keith Whitwell <keith@tungstengraphics.com>
28 */
29
30
31#if IDX & LIGHT_TWOSIDE
32#  define NR_SIDES 2
33#else
34#  define NR_SIDES 1
35#endif
36
37
38/* define TRACE to trace lighting code */
39#define TRACE 1
40
41/*
42 * ctx is the current context
43 * VB is the vertex buffer
44 * stage is the lighting stage-private data
45 * input is the vector of eye or object-space vertex coordinates
46 */
47static void TAG(light_rgba_spec)( GLcontext *ctx,
48				  struct vertex_buffer *VB,
49				  struct tnl_pipeline_stage *stage,
50				  GLvector4f *input )
51{
52   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
53   GLfloat (*base)[3] = ctx->Light._BaseColor;
54   GLfloat sumA[2];
55   GLuint j;
56
57   const GLuint vstride = input->stride;
58   const GLfloat *vertex = (GLfloat *)input->data;
59   const GLuint nstride = VB->NormalPtr->stride;
60   const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
61
62   GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
63   GLfloat (*Fspec)[4] = (GLfloat (*)[4]) store->LitSecondary[0].data;
64#if IDX & LIGHT_TWOSIDE
65   GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
66   GLfloat (*Bspec)[4] = (GLfloat (*)[4]) store->LitSecondary[1].data;
67#endif
68
69   const GLuint nr = VB->Count;
70
71   (void) nstride;
72   (void) vstride;
73
74#ifdef TRACE
75   fprintf(stderr, "%s\n", __FUNCTION__ );
76#endif
77
78   VB->ColorPtr[0] = &store->LitColor[0];
79   VB->SecondaryColorPtr[0] = &store->LitSecondary[0];
80   sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
81
82#if IDX & LIGHT_TWOSIDE
83   VB->ColorPtr[1] = &store->LitColor[1];
84   VB->SecondaryColorPtr[1] = &store->LitSecondary[1];
85   sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
86#endif
87
88   /* Side-effects done, can we finish now?
89    */
90   if (stage->changed_inputs == 0)
91      return;
92
93   for (j = 0; j < nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal,nstride)) {
94      GLfloat sum[2][3], spec[2][3];
95      struct gl_light *light;
96
97#if IDX & LIGHT_MATERIAL
98      update_materials( ctx, store );
99      sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
100#if IDX & LIGHT_TWOSIDE
101      sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
102#endif
103#endif
104
105      COPY_3V(sum[0], base[0]);
106      ZERO_3V(spec[0]);
107
108#if IDX & LIGHT_TWOSIDE
109      COPY_3V(sum[1], base[1]);
110      ZERO_3V(spec[1]);
111#endif
112
113      /* Add contribution from each enabled light source */
114      foreach (light, &ctx->Light.EnabledList) {
115	 GLfloat n_dot_h;
116	 GLfloat correction;
117	 GLint side;
118	 GLfloat contrib[3];
119	 GLfloat attenuation;
120	 GLfloat VP[3];  /* unit vector from vertex to light */
121	 GLfloat n_dot_VP;       /* n dot VP */
122	 GLfloat *h;
123
124	 /* compute VP and attenuation */
125	 if (!(light->_Flags & LIGHT_POSITIONAL)) {
126	    /* directional light */
127	    COPY_3V(VP, light->_VP_inf_norm);
128	    attenuation = light->_VP_inf_spot_attenuation;
129	 }
130	 else {
131	    GLfloat d;     /* distance from vertex to light */
132
133	    SUB_3V(VP, light->_Position, vertex);
134
135	    d = (GLfloat) LEN_3FV( VP );
136
137	    if (d > 1e-6) {
138	       GLfloat invd = 1.0F / d;
139	       SELF_SCALE_SCALAR_3V(VP, invd);
140	    }
141
142	    attenuation = 1.0F / (light->ConstantAttenuation + d *
143				  (light->LinearAttenuation + d *
144				   light->QuadraticAttenuation));
145
146	    /* spotlight attenuation */
147	    if (light->_Flags & LIGHT_SPOT) {
148	       GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
149
150	       if (PV_dot_dir<light->_CosCutoff) {
151		  continue; /* this light makes no contribution */
152	       }
153	       else {
154		  GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
155		  GLint k = (GLint) x;
156		  GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0]
157				    + (x-k)*light->_SpotExpTable[k][1]);
158		  attenuation *= spot;
159	       }
160	    }
161	 }
162
163	 if (attenuation < 1e-3)
164	    continue;		/* this light makes no contribution */
165
166	 /* Compute dot product or normal and vector from V to light pos */
167	 n_dot_VP = DOT3( normal, VP );
168
169	 /* Which side gets the diffuse & specular terms? */
170	 if (n_dot_VP < 0.0F) {
171	    ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]);
172#if IDX & LIGHT_TWOSIDE
173	    side = 1;
174	    correction = -1;
175	    n_dot_VP = -n_dot_VP;
176#else
177            continue;
178#endif
179	 }
180         else {
181#if IDX & LIGHT_TWOSIDE
182            ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]);
183#endif
184	    side = 0;
185	    correction = 1;
186	 }
187
188	 /* diffuse term */
189	 COPY_3V(contrib, light->_MatAmbient[side]);
190	 ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]);
191	 ACC_SCALE_SCALAR_3V(sum[side], attenuation, contrib );
192
193	 /* specular term - cannibalize VP... */
194	 if (ctx->Light.Model.LocalViewer) {
195	    GLfloat v[3];
196	    COPY_3V(v, vertex);
197	    NORMALIZE_3FV(v);
198	    SUB_3V(VP, VP, v);                /* h = VP + VPe */
199	    h = VP;
200	    NORMALIZE_3FV(h);
201	 }
202	 else if (light->_Flags & LIGHT_POSITIONAL) {
203	    h = VP;
204	    ACC_3V(h, ctx->_EyeZDir);
205	    NORMALIZE_3FV(h);
206	 }
207         else {
208	    h = light->_h_inf_norm;
209	 }
210
211	 n_dot_h = correction * DOT3(normal, h);
212
213	 if (n_dot_h > 0.0F) {
214	    GLfloat spec_coef;
215	    struct gl_shine_tab *tab = ctx->_ShineTable[side];
216	    GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef );
217
218	    if (spec_coef > 1.0e-10) {
219	       spec_coef *= attenuation;
220	       ACC_SCALE_SCALAR_3V( spec[side], spec_coef,
221				    light->_MatSpecular[side]);
222	    }
223	 }
224      } /*loop over lights*/
225
226      COPY_3V( Fcolor[j], sum[0] );
227      COPY_3V( Fspec[j], spec[0] );
228      Fcolor[j][3] = sumA[0];
229
230#if IDX & LIGHT_TWOSIDE
231      COPY_3V( Bcolor[j], sum[1] );
232      COPY_3V( Bspec[j], spec[1] );
233      Bcolor[j][3] = sumA[1];
234#endif
235   }
236}
237
238
239static void TAG(light_rgba)( GLcontext *ctx,
240			     struct vertex_buffer *VB,
241			     struct tnl_pipeline_stage *stage,
242			     GLvector4f *input )
243{
244   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
245   GLuint j;
246
247   GLfloat (*base)[3] = ctx->Light._BaseColor;
248   GLfloat sumA[2];
249
250   const GLuint vstride = input->stride;
251   const GLfloat *vertex = (GLfloat *) input->data;
252   const GLuint nstride = VB->NormalPtr->stride;
253   const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
254
255   GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
256#if IDX & LIGHT_TWOSIDE
257   GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
258#endif
259
260   const GLuint nr = VB->Count;
261
262#ifdef TRACE
263   fprintf(stderr, "%s\n", __FUNCTION__ );
264#endif
265
266   (void) nstride;
267   (void) vstride;
268
269   VB->ColorPtr[0] = &store->LitColor[0];
270   sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
271
272#if IDX & LIGHT_TWOSIDE
273   VB->ColorPtr[1] = &store->LitColor[1];
274   sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
275#endif
276
277   if (stage->changed_inputs == 0)
278      return;
279
280   for (j = 0; j < nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal,nstride)) {
281      GLfloat sum[2][3];
282      struct gl_light *light;
283
284#if IDX & LIGHT_MATERIAL
285      update_materials( ctx, store );
286      sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
287#if IDX & LIGHT_TWOSIDE
288      sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
289#endif
290#endif
291
292      COPY_3V(sum[0], base[0]);
293
294#if IDX & LIGHT_TWOSIDE
295      COPY_3V(sum[1], base[1]);
296#endif
297
298      /* Add contribution from each enabled light source */
299      foreach (light, &ctx->Light.EnabledList) {
300
301	 GLfloat n_dot_h;
302	 GLfloat correction;
303	 GLint side;
304	 GLfloat contrib[3];
305	 GLfloat attenuation = 1.0;
306	 GLfloat VP[3];          /* unit vector from vertex to light */
307	 GLfloat n_dot_VP;       /* n dot VP */
308	 GLfloat *h;
309
310	 /* compute VP and attenuation */
311	 if (!(light->_Flags & LIGHT_POSITIONAL)) {
312	    /* directional light */
313	    COPY_3V(VP, light->_VP_inf_norm);
314	    attenuation = light->_VP_inf_spot_attenuation;
315	 }
316	 else {
317	    GLfloat d;     /* distance from vertex to light */
318
319
320	    SUB_3V(VP, light->_Position, vertex);
321
322	    d = (GLfloat) LEN_3FV( VP );
323
324	    if ( d > 1e-6) {
325	       GLfloat invd = 1.0F / d;
326	       SELF_SCALE_SCALAR_3V(VP, invd);
327	    }
328
329            attenuation = 1.0F / (light->ConstantAttenuation + d *
330                                  (light->LinearAttenuation + d *
331                                   light->QuadraticAttenuation));
332
333	    /* spotlight attenuation */
334	    if (light->_Flags & LIGHT_SPOT) {
335	       GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
336
337	       if (PV_dot_dir<light->_CosCutoff) {
338		  continue; /* this light makes no contribution */
339	       }
340	       else {
341		  GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
342		  GLint k = (GLint) x;
343		  GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0]
344				  + (x-k)*light->_SpotExpTable[k][1]);
345		  attenuation *= spot;
346	       }
347	    }
348	 }
349
350	 if (attenuation < 1e-3)
351	    continue;		/* this light makes no contribution */
352
353	 /* Compute dot product or normal and vector from V to light pos */
354	 n_dot_VP = DOT3( normal, VP );
355
356	 /* which side are we lighting? */
357	 if (n_dot_VP < 0.0F) {
358	    ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]);
359#if IDX & LIGHT_TWOSIDE
360	    side = 1;
361	    correction = -1;
362	    n_dot_VP = -n_dot_VP;
363#else
364            continue;
365#endif
366	 }
367         else {
368#if IDX & LIGHT_TWOSIDE
369            ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]);
370#endif
371	    side = 0;
372	    correction = 1;
373	 }
374
375	 COPY_3V(contrib, light->_MatAmbient[side]);
376
377	 /* diffuse term */
378	 ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]);
379
380	 /* specular term - cannibalize VP... */
381	 {
382	    if (ctx->Light.Model.LocalViewer) {
383	       GLfloat v[3];
384	       COPY_3V(v, vertex);
385	       NORMALIZE_3FV(v);
386	       SUB_3V(VP, VP, v);                /* h = VP + VPe */
387	       h = VP;
388	       NORMALIZE_3FV(h);
389	    }
390	    else if (light->_Flags & LIGHT_POSITIONAL) {
391	       h = VP;
392	       ACC_3V(h, ctx->_EyeZDir);
393	       NORMALIZE_3FV(h);
394	    }
395            else {
396	       h = light->_h_inf_norm;
397	    }
398
399	    n_dot_h = correction * DOT3(normal, h);
400
401	    if (n_dot_h > 0.0F)
402	    {
403	       GLfloat spec_coef;
404	       struct gl_shine_tab *tab = ctx->_ShineTable[side];
405
406	       GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef );
407
408	       ACC_SCALE_SCALAR_3V( contrib, spec_coef,
409				    light->_MatSpecular[side]);
410	    }
411	 }
412
413	 ACC_SCALE_SCALAR_3V( sum[side], attenuation, contrib );
414      }
415
416      COPY_3V( Fcolor[j], sum[0] );
417      Fcolor[j][3] = sumA[0];
418
419#if IDX & LIGHT_TWOSIDE
420      COPY_3V( Bcolor[j], sum[1] );
421      Bcolor[j][3] = sumA[1];
422#endif
423   }
424}
425
426
427
428
429/* As below, but with just a single light.
430 */
431static void TAG(light_fast_rgba_single)( GLcontext *ctx,
432					 struct vertex_buffer *VB,
433					 struct tnl_pipeline_stage *stage,
434					 GLvector4f *input )
435
436{
437   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
438   const GLuint nstride = VB->NormalPtr->stride;
439   const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
440   GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
441#if IDX & LIGHT_TWOSIDE
442   GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
443#endif
444   const struct gl_light *light = ctx->Light.EnabledList.next;
445   GLuint j = 0;
446   GLfloat base[2][4];
447   const GLuint nr = VB->Count;
448
449#ifdef TRACE
450   fprintf(stderr, "%s\n", __FUNCTION__ );
451#endif
452
453   (void) input;		/* doesn't refer to Eye or Obj */
454   (void) nr;
455   (void) nstride;
456
457   VB->ColorPtr[0] = &store->LitColor[0];
458#if IDX & LIGHT_TWOSIDE
459   VB->ColorPtr[1] = &store->LitColor[1];
460#endif
461
462   if (stage->changed_inputs == 0)
463      return;
464
465   for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) {
466
467      GLfloat n_dot_VP;
468
469#if IDX & LIGHT_MATERIAL
470      update_materials( ctx, store );
471#endif
472
473      /* No attenuation, so incoporate _MatAmbient into base color.
474       */
475#if !(IDX & LIGHT_MATERIAL)
476      if ( j == 0 )
477#endif
478      {
479	 COPY_3V(base[0], light->_MatAmbient[0]);
480	 ACC_3V(base[0], ctx->Light._BaseColor[0] );
481	 base[0][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
482
483#if IDX & LIGHT_TWOSIDE
484         COPY_3V(base[1], light->_MatAmbient[1]);
485         ACC_3V(base[1], ctx->Light._BaseColor[1]);
486         base[1][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
487#endif
488      }
489
490      n_dot_VP = DOT3(normal, light->_VP_inf_norm);
491
492      if (n_dot_VP < 0.0F) {
493#if IDX & LIGHT_TWOSIDE
494         GLfloat n_dot_h = -DOT3(normal, light->_h_inf_norm);
495         GLfloat sum[3];
496         COPY_3V(sum, base[1]);
497         ACC_SCALE_SCALAR_3V(sum, -n_dot_VP, light->_MatDiffuse[1]);
498         if (n_dot_h > 0.0F) {
499            GLfloat spec;
500            GET_SHINE_TAB_ENTRY( ctx->_ShineTable[1], n_dot_h, spec );
501            ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[1]);
502         }
503         COPY_3V(Bcolor[j], sum );
504         Bcolor[j][3] = base[1][3];
505#endif
506	 COPY_4FV(Fcolor[j], base[0]);
507      }
508      else {
509	 GLfloat n_dot_h = DOT3(normal, light->_h_inf_norm);
510	 GLfloat sum[3];
511	 COPY_3V(sum, base[0]);
512	 ACC_SCALE_SCALAR_3V(sum, n_dot_VP, light->_MatDiffuse[0]);
513	 if (n_dot_h > 0.0F) {
514	    GLfloat spec;
515	    GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
516	    ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[0]);
517
518	 }
519	 COPY_3V(Fcolor[j], sum );
520	 Fcolor[j][3] = base[0][3];
521#if IDX & LIGHT_TWOSIDE
522         COPY_4FV(Bcolor[j], base[1]);
523#endif
524      }
525   }
526}
527
528
529/* Light infinite lights
530 */
531static void TAG(light_fast_rgba)( GLcontext *ctx,
532				  struct vertex_buffer *VB,
533				  struct tnl_pipeline_stage *stage,
534				  GLvector4f *input )
535{
536   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
537   GLfloat sumA[2];
538   const GLuint nstride = VB->NormalPtr->stride;
539   const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
540   GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
541#if IDX & LIGHT_TWOSIDE
542   GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
543#endif
544   GLuint j = 0;
545   const GLuint nr = VB->Count;
546   const struct gl_light *light;
547
548#ifdef TRACE
549   fprintf(stderr, "%s %d\n", __FUNCTION__, nr );
550#endif
551
552   (void) input;
553   (void) nr;
554   (void) nstride;
555
556   sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
557   sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
558
559   VB->ColorPtr[0] = &store->LitColor[0];
560#if IDX & LIGHT_TWOSIDE
561   VB->ColorPtr[1] = &store->LitColor[1];
562#endif
563
564   if (stage->changed_inputs == 0)
565      return;
566
567   for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) {
568
569      GLfloat sum[2][3];
570
571#if IDX & LIGHT_MATERIAL
572      update_materials( ctx, store );
573
574      sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
575#if IDX & LIGHT_TWOSIDE
576      sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
577#endif
578#endif
579
580
581      COPY_3V(sum[0], ctx->Light._BaseColor[0]);
582#if IDX & LIGHT_TWOSIDE
583      COPY_3V(sum[1], ctx->Light._BaseColor[1]);
584#endif
585
586      foreach (light, &ctx->Light.EnabledList) {
587	 GLfloat n_dot_h, n_dot_VP, spec;
588
589	 ACC_3V(sum[0], light->_MatAmbient[0]);
590#if IDX & LIGHT_TWOSIDE
591         ACC_3V(sum[1], light->_MatAmbient[1]);
592#endif
593
594	 n_dot_VP = DOT3(normal, light->_VP_inf_norm);
595
596	 if (n_dot_VP > 0.0F) {
597	    ACC_SCALE_SCALAR_3V(sum[0], n_dot_VP, light->_MatDiffuse[0]);
598	    n_dot_h = DOT3(normal, light->_h_inf_norm);
599	    if (n_dot_h > 0.0F) {
600	       struct gl_shine_tab *tab = ctx->_ShineTable[0];
601	       GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec );
602	       ACC_SCALE_SCALAR_3V( sum[0], spec, light->_MatSpecular[0]);
603	    }
604	 }
605#if IDX & LIGHT_TWOSIDE
606         else {
607	    ACC_SCALE_SCALAR_3V(sum[1], -n_dot_VP, light->_MatDiffuse[1]);
608	    n_dot_h = -DOT3(normal, light->_h_inf_norm);
609	    if (n_dot_h > 0.0F) {
610	       struct gl_shine_tab *tab = ctx->_ShineTable[1];
611	       GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec );
612	       ACC_SCALE_SCALAR_3V( sum[1], spec, light->_MatSpecular[1]);
613	    }
614	 }
615#endif
616      }
617
618      COPY_3V( Fcolor[j], sum[0] );
619      Fcolor[j][3] = sumA[0];
620
621#if IDX & LIGHT_TWOSIDE
622      COPY_3V( Bcolor[j], sum[1] );
623      Bcolor[j][3] = sumA[1];
624#endif
625   }
626}
627
628
629
630
631
632/*
633 * Use current lighting/material settings to compute the color indexes
634 * for an array of vertices.
635 * Input:  n - number of vertices to light
636 *         side - 0=use front material, 1=use back material
637 *         vertex - array of [n] vertex position in eye coordinates
638 *         normal - array of [n] surface normal vector
639 * Output:  indexResult - resulting array of [n] color indexes
640 */
641static void TAG(light_ci)( GLcontext *ctx,
642			   struct vertex_buffer *VB,
643			   struct tnl_pipeline_stage *stage,
644			   GLvector4f *input )
645{
646   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
647   GLuint j;
648   const GLuint vstride = input->stride;
649   const GLfloat *vertex = (GLfloat *) input->data;
650   const GLuint nstride = VB->NormalPtr->stride;
651   const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
652   GLfloat *indexResult[2];
653   const GLuint nr = VB->Count;
654
655#ifdef TRACE
656   fprintf(stderr, "%s\n", __FUNCTION__ );
657#endif
658
659   (void) nstride;
660   (void) vstride;
661
662   VB->IndexPtr[0] = &store->LitIndex[0];
663#if IDX & LIGHT_TWOSIDE
664   VB->IndexPtr[1] = &store->LitIndex[1];
665#endif
666
667   if (stage->changed_inputs == 0)
668      return;
669
670   indexResult[0] = (GLfloat *)VB->IndexPtr[0]->data;
671#if IDX & LIGHT_TWOSIDE
672   indexResult[1] = (GLfloat *)VB->IndexPtr[1]->data;
673#endif
674
675   /* loop over vertices */
676   for (j=0; j<nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal, nstride)) {
677      GLfloat diffuse[2], specular[2];
678      GLuint side = 0;
679      struct gl_light *light;
680
681#if IDX & LIGHT_MATERIAL
682      update_materials( ctx, store );
683#endif
684
685      diffuse[0] = specular[0] = 0.0F;
686
687#if IDX & LIGHT_TWOSIDE
688	 diffuse[1] = specular[1] = 0.0F;
689#endif
690
691      /* Accumulate diffuse and specular from each light source */
692      foreach (light, &ctx->Light.EnabledList) {
693
694	 GLfloat attenuation = 1.0F;
695	 GLfloat VP[3];  /* unit vector from vertex to light */
696	 GLfloat n_dot_VP;  /* dot product of l and n */
697	 GLfloat *h, n_dot_h, correction = 1.0;
698
699	 /* compute l and attenuation */
700	 if (!(light->_Flags & LIGHT_POSITIONAL)) {
701	    /* directional light */
702	    COPY_3V(VP, light->_VP_inf_norm);
703	 }
704	 else {
705	    GLfloat d;     /* distance from vertex to light */
706
707	    SUB_3V(VP, light->_Position, vertex);
708
709	    d = (GLfloat) LEN_3FV( VP );
710	    if ( d > 1e-6) {
711	       GLfloat invd = 1.0F / d;
712	       SELF_SCALE_SCALAR_3V(VP, invd);
713	    }
714
715	    attenuation = 1.0F / (light->ConstantAttenuation + d *
716				  (light->LinearAttenuation + d *
717				   light->QuadraticAttenuation));
718
719	    /* spotlight attenuation */
720	    if (light->_Flags & LIGHT_SPOT) {
721	       GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
722	       if (PV_dot_dir < light->_CosCutoff) {
723		  continue; /* this light makes no contribution */
724	       }
725	       else {
726		  GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
727		  GLint k = (GLint) x;
728		  GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0]
729				  + (x-k)*light->_SpotExpTable[k][1]);
730		  attenuation *= spot;
731	       }
732	    }
733	 }
734
735	 if (attenuation < 1e-3)
736	    continue;		/* this light makes no contribution */
737
738	 n_dot_VP = DOT3( normal, VP );
739
740	 /* which side are we lighting? */
741	 if (n_dot_VP < 0.0F) {
742#if IDX & LIGHT_TWOSIDE
743	    side = 1;
744	    correction = -1;
745	    n_dot_VP = -n_dot_VP;
746#else
747            continue;
748#endif
749	 }
750
751	 /* accumulate diffuse term */
752	 diffuse[side] += n_dot_VP * light->_dli * attenuation;
753
754	 /* specular term */
755	 if (ctx->Light.Model.LocalViewer) {
756	    GLfloat v[3];
757	    COPY_3V(v, vertex);
758	    NORMALIZE_3FV(v);
759	    SUB_3V(VP, VP, v);                /* h = VP + VPe */
760	    h = VP;
761	    NORMALIZE_3FV(h);
762	 }
763	 else if (light->_Flags & LIGHT_POSITIONAL) {
764	    h = VP;
765            /* Strangely, disabling this addition fixes a conformance
766             * problem.  If this code is enabled, l_sed.c fails.
767             */
768	    /*ACC_3V(h, ctx->_EyeZDir);*/
769	    NORMALIZE_3FV(h);
770	 }
771         else {
772	    h = light->_h_inf_norm;
773	 }
774
775	 n_dot_h = correction * DOT3(normal, h);
776	 if (n_dot_h > 0.0F) {
777	    GLfloat spec_coef;
778	    struct gl_shine_tab *tab = ctx->_ShineTable[side];
779	    GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef);
780	    specular[side] += spec_coef * light->_sli * attenuation;
781	 }
782      } /*loop over lights*/
783
784      /* Now compute final color index */
785      for (side = 0 ; side < NR_SIDES ; side++) {
786	 const GLfloat *ind = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_INDEXES + side];
787	 GLfloat index;
788
789	 if (specular[side] > 1.0F) {
790	    index = ind[MAT_INDEX_SPECULAR];
791	 }
792	 else {
793	    GLfloat d_a = ind[MAT_INDEX_DIFFUSE] - ind[MAT_INDEX_AMBIENT];
794	    GLfloat s_a = ind[MAT_INDEX_SPECULAR] - ind[MAT_INDEX_AMBIENT];
795	    index = (ind[MAT_INDEX_AMBIENT]
796		     + diffuse[side] * (1.0F-specular[side]) * d_a
797		     + specular[side] * s_a);
798	    if (index > ind[MAT_INDEX_SPECULAR]) {
799	       index = ind[MAT_INDEX_SPECULAR];
800	    }
801	 }
802	 indexResult[side][j] = index;
803      }
804   } /*for vertex*/
805}
806
807
808
809static void TAG(init_light_tab)( void )
810{
811   _tnl_light_tab[IDX] = TAG(light_rgba);
812   _tnl_light_fast_tab[IDX] = TAG(light_fast_rgba);
813   _tnl_light_fast_single_tab[IDX] = TAG(light_fast_rgba_single);
814   _tnl_light_spec_tab[IDX] = TAG(light_rgba_spec);
815   _tnl_light_ci_tab[IDX] = TAG(light_ci);
816}
817
818
819#undef TAG
820#undef IDX
821#undef NR_SIDES
822