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