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