Give attributes with zero-stride a count of 1 to make it easier
[mesa.git] / src / mesa / tnl / t_vb_lighttmp.h
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 */
47 static 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 #ifdef TRACE
72 fprintf(stderr, "%s\n", __FUNCTION__ );
73 #endif
74
75 VB->ColorPtr[0] = &store->LitColor[0];
76 VB->SecondaryColorPtr[0] = &store->LitSecondary[0];
77 sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
78
79 #if IDX & LIGHT_TWOSIDE
80 VB->ColorPtr[1] = &store->LitColor[1];
81 VB->SecondaryColorPtr[1] = &store->LitSecondary[1];
82 sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
83 #endif
84
85 /* Side-effects done, can we finish now?
86 */
87 if (stage->changed_inputs == 0)
88 return;
89
90 store->LitColor[0].stride = 16;
91 store->LitColor[1].stride = 16;
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
239 static 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 VB->ColorPtr[0] = &store->LitColor[0];
267 sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
268
269 #if IDX & LIGHT_TWOSIDE
270 VB->ColorPtr[1] = &store->LitColor[1];
271 sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
272 #endif
273
274 if (stage->changed_inputs == 0)
275 return;
276
277 store->LitColor[0].stride = 16;
278 store->LitColor[1].stride = 16;
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 */
431 static 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 #if IDX & LIGHT_MATERIAL
448 const GLuint nr = VB->Count;
449 #else
450 const GLuint nr = VB->NormalPtr->count;
451 #endif
452
453 #ifdef TRACE
454 fprintf(stderr, "%s\n", __FUNCTION__ );
455 #endif
456
457 (void) input; /* doesn't refer to Eye or Obj */
458
459 VB->ColorPtr[0] = &store->LitColor[0];
460 #if IDX & LIGHT_TWOSIDE
461 VB->ColorPtr[1] = &store->LitColor[1];
462 #endif
463
464 if (stage->changed_inputs == 0)
465 return;
466
467 if (nr > 1) {
468 store->LitColor[0].stride = 16;
469 store->LitColor[1].stride = 16;
470 }
471 else {
472 store->LitColor[0].stride = 0;
473 store->LitColor[1].stride = 0;
474 }
475
476 for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) {
477
478 GLfloat n_dot_VP;
479
480 #if IDX & LIGHT_MATERIAL
481 update_materials( ctx, store );
482 #endif
483
484 /* No attenuation, so incoporate _MatAmbient into base color.
485 */
486 #if !(IDX & LIGHT_MATERIAL)
487 if ( j == 0 )
488 #endif
489 {
490 COPY_3V(base[0], light->_MatAmbient[0]);
491 ACC_3V(base[0], ctx->Light._BaseColor[0] );
492 base[0][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
493
494 #if IDX & LIGHT_TWOSIDE
495 COPY_3V(base[1], light->_MatAmbient[1]);
496 ACC_3V(base[1], ctx->Light._BaseColor[1]);
497 base[1][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
498 #endif
499 }
500
501 n_dot_VP = DOT3(normal, light->_VP_inf_norm);
502
503 if (n_dot_VP < 0.0F) {
504 #if IDX & LIGHT_TWOSIDE
505 GLfloat n_dot_h = -DOT3(normal, light->_h_inf_norm);
506 GLfloat sum[3];
507 COPY_3V(sum, base[1]);
508 ACC_SCALE_SCALAR_3V(sum, -n_dot_VP, light->_MatDiffuse[1]);
509 if (n_dot_h > 0.0F) {
510 GLfloat spec;
511 GET_SHINE_TAB_ENTRY( ctx->_ShineTable[1], n_dot_h, spec );
512 ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[1]);
513 }
514 COPY_3V(Bcolor[j], sum );
515 Bcolor[j][3] = base[1][3];
516 #endif
517 COPY_4FV(Fcolor[j], base[0]);
518 }
519 else {
520 GLfloat n_dot_h = DOT3(normal, light->_h_inf_norm);
521 GLfloat sum[3];
522 COPY_3V(sum, base[0]);
523 ACC_SCALE_SCALAR_3V(sum, n_dot_VP, light->_MatDiffuse[0]);
524 if (n_dot_h > 0.0F) {
525 GLfloat spec;
526 GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
527 ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[0]);
528
529 }
530 COPY_3V(Fcolor[j], sum );
531 Fcolor[j][3] = base[0][3];
532 #if IDX & LIGHT_TWOSIDE
533 COPY_4FV(Bcolor[j], base[1]);
534 #endif
535 }
536 }
537 }
538
539
540 /* Light infinite lights
541 */
542 static void TAG(light_fast_rgba)( GLcontext *ctx,
543 struct vertex_buffer *VB,
544 struct tnl_pipeline_stage *stage,
545 GLvector4f *input )
546 {
547 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
548 GLfloat sumA[2];
549 const GLuint nstride = VB->NormalPtr->stride;
550 const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
551 GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
552 #if IDX & LIGHT_TWOSIDE
553 GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
554 #endif
555 GLuint j = 0;
556 #if IDX & LIGHT_MATERIAL
557 const GLuint nr = VB->Count;
558 #else
559 const GLuint nr = VB->NormalPtr->count;
560 #endif
561 const struct gl_light *light;
562
563 #ifdef TRACE
564 fprintf(stderr, "%s %d\n", __FUNCTION__, nr );
565 #endif
566
567 (void) input;
568
569 sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
570 sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
571
572 VB->ColorPtr[0] = &store->LitColor[0];
573 #if IDX & LIGHT_TWOSIDE
574 VB->ColorPtr[1] = &store->LitColor[1];
575 #endif
576
577 if (stage->changed_inputs == 0)
578 return;
579
580 if (nr > 1) {
581 store->LitColor[0].stride = 16;
582 store->LitColor[1].stride = 16;
583 }
584 else {
585 store->LitColor[0].stride = 0;
586 store->LitColor[1].stride = 0;
587 }
588
589 for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) {
590
591 GLfloat sum[2][3];
592
593 #if IDX & LIGHT_MATERIAL
594 update_materials( ctx, store );
595
596 sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
597 #if IDX & LIGHT_TWOSIDE
598 sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
599 #endif
600 #endif
601
602
603 COPY_3V(sum[0], ctx->Light._BaseColor[0]);
604 #if IDX & LIGHT_TWOSIDE
605 COPY_3V(sum[1], ctx->Light._BaseColor[1]);
606 #endif
607
608 foreach (light, &ctx->Light.EnabledList) {
609 GLfloat n_dot_h, n_dot_VP, spec;
610
611 ACC_3V(sum[0], light->_MatAmbient[0]);
612 #if IDX & LIGHT_TWOSIDE
613 ACC_3V(sum[1], light->_MatAmbient[1]);
614 #endif
615
616 n_dot_VP = DOT3(normal, light->_VP_inf_norm);
617
618 if (n_dot_VP > 0.0F) {
619 ACC_SCALE_SCALAR_3V(sum[0], n_dot_VP, light->_MatDiffuse[0]);
620 n_dot_h = DOT3(normal, light->_h_inf_norm);
621 if (n_dot_h > 0.0F) {
622 struct gl_shine_tab *tab = ctx->_ShineTable[0];
623 GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec );
624 ACC_SCALE_SCALAR_3V( sum[0], spec, light->_MatSpecular[0]);
625 }
626 }
627 #if IDX & LIGHT_TWOSIDE
628 else {
629 ACC_SCALE_SCALAR_3V(sum[1], -n_dot_VP, light->_MatDiffuse[1]);
630 n_dot_h = -DOT3(normal, light->_h_inf_norm);
631 if (n_dot_h > 0.0F) {
632 struct gl_shine_tab *tab = ctx->_ShineTable[1];
633 GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec );
634 ACC_SCALE_SCALAR_3V( sum[1], spec, light->_MatSpecular[1]);
635 }
636 }
637 #endif
638 }
639
640 COPY_3V( Fcolor[j], sum[0] );
641 Fcolor[j][3] = sumA[0];
642
643 #if IDX & LIGHT_TWOSIDE
644 COPY_3V( Bcolor[j], sum[1] );
645 Bcolor[j][3] = sumA[1];
646 #endif
647 }
648 }
649
650
651
652
653
654 /*
655 * Use current lighting/material settings to compute the color indexes
656 * for an array of vertices.
657 * Input: n - number of vertices to light
658 * side - 0=use front material, 1=use back material
659 * vertex - array of [n] vertex position in eye coordinates
660 * normal - array of [n] surface normal vector
661 * Output: indexResult - resulting array of [n] color indexes
662 */
663 static void TAG(light_ci)( GLcontext *ctx,
664 struct vertex_buffer *VB,
665 struct tnl_pipeline_stage *stage,
666 GLvector4f *input )
667 {
668 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
669 GLuint j;
670 const GLuint vstride = input->stride;
671 const GLfloat *vertex = (GLfloat *) input->data;
672 const GLuint nstride = VB->NormalPtr->stride;
673 const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
674 GLfloat *indexResult[2];
675 const GLuint nr = VB->Count;
676
677 #ifdef TRACE
678 fprintf(stderr, "%s\n", __FUNCTION__ );
679 #endif
680
681 VB->IndexPtr[0] = &store->LitIndex[0];
682 #if IDX & LIGHT_TWOSIDE
683 VB->IndexPtr[1] = &store->LitIndex[1];
684 #endif
685
686 if (stage->changed_inputs == 0)
687 return;
688
689 indexResult[0] = (GLfloat *)VB->IndexPtr[0]->data;
690 #if IDX & LIGHT_TWOSIDE
691 indexResult[1] = (GLfloat *)VB->IndexPtr[1]->data;
692 #endif
693
694 /* loop over vertices */
695 for (j=0; j<nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal, nstride)) {
696 GLfloat diffuse[2], specular[2];
697 GLuint side = 0;
698 struct gl_light *light;
699
700 #if IDX & LIGHT_MATERIAL
701 update_materials( ctx, store );
702 #endif
703
704 diffuse[0] = specular[0] = 0.0F;
705
706 #if IDX & LIGHT_TWOSIDE
707 diffuse[1] = specular[1] = 0.0F;
708 #endif
709
710 /* Accumulate diffuse and specular from each light source */
711 foreach (light, &ctx->Light.EnabledList) {
712
713 GLfloat attenuation = 1.0F;
714 GLfloat VP[3]; /* unit vector from vertex to light */
715 GLfloat n_dot_VP; /* dot product of l and n */
716 GLfloat *h, n_dot_h, correction = 1.0;
717
718 /* compute l and attenuation */
719 if (!(light->_Flags & LIGHT_POSITIONAL)) {
720 /* directional light */
721 COPY_3V(VP, light->_VP_inf_norm);
722 }
723 else {
724 GLfloat d; /* distance from vertex to light */
725
726 SUB_3V(VP, light->_Position, vertex);
727
728 d = (GLfloat) LEN_3FV( VP );
729 if ( d > 1e-6) {
730 GLfloat invd = 1.0F / d;
731 SELF_SCALE_SCALAR_3V(VP, invd);
732 }
733
734 attenuation = 1.0F / (light->ConstantAttenuation + d *
735 (light->LinearAttenuation + d *
736 light->QuadraticAttenuation));
737
738 /* spotlight attenuation */
739 if (light->_Flags & LIGHT_SPOT) {
740 GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
741 if (PV_dot_dir < light->_CosCutoff) {
742 continue; /* this light makes no contribution */
743 }
744 else {
745 GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
746 GLint k = (GLint) x;
747 GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0]
748 + (x-k)*light->_SpotExpTable[k][1]);
749 attenuation *= spot;
750 }
751 }
752 }
753
754 if (attenuation < 1e-3)
755 continue; /* this light makes no contribution */
756
757 n_dot_VP = DOT3( normal, VP );
758
759 /* which side are we lighting? */
760 if (n_dot_VP < 0.0F) {
761 #if IDX & LIGHT_TWOSIDE
762 side = 1;
763 correction = -1;
764 n_dot_VP = -n_dot_VP;
765 #else
766 continue;
767 #endif
768 }
769
770 /* accumulate diffuse term */
771 diffuse[side] += n_dot_VP * light->_dli * attenuation;
772
773 /* specular term */
774 if (ctx->Light.Model.LocalViewer) {
775 GLfloat v[3];
776 COPY_3V(v, vertex);
777 NORMALIZE_3FV(v);
778 SUB_3V(VP, VP, v); /* h = VP + VPe */
779 h = VP;
780 NORMALIZE_3FV(h);
781 }
782 else if (light->_Flags & LIGHT_POSITIONAL) {
783 h = VP;
784 /* Strangely, disabling this addition fixes a conformance
785 * problem. If this code is enabled, l_sed.c fails.
786 */
787 /*ACC_3V(h, ctx->_EyeZDir);*/
788 NORMALIZE_3FV(h);
789 }
790 else {
791 h = light->_h_inf_norm;
792 }
793
794 n_dot_h = correction * DOT3(normal, h);
795 if (n_dot_h > 0.0F) {
796 GLfloat spec_coef;
797 struct gl_shine_tab *tab = ctx->_ShineTable[side];
798 GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef);
799 specular[side] += spec_coef * light->_sli * attenuation;
800 }
801 } /*loop over lights*/
802
803 /* Now compute final color index */
804 for (side = 0 ; side < NR_SIDES ; side++) {
805 const GLfloat *ind = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_INDEXES + side];
806 GLfloat index;
807
808 if (specular[side] > 1.0F) {
809 index = ind[MAT_INDEX_SPECULAR];
810 }
811 else {
812 GLfloat d_a = ind[MAT_INDEX_DIFFUSE] - ind[MAT_INDEX_AMBIENT];
813 GLfloat s_a = ind[MAT_INDEX_SPECULAR] - ind[MAT_INDEX_AMBIENT];
814 index = (ind[MAT_INDEX_AMBIENT]
815 + diffuse[side] * (1.0F-specular[side]) * d_a
816 + specular[side] * s_a);
817 if (index > ind[MAT_INDEX_SPECULAR]) {
818 index = ind[MAT_INDEX_SPECULAR];
819 }
820 }
821 indexResult[side][j] = index;
822 }
823 } /*for vertex*/
824 }
825
826
827
828 static void TAG(init_light_tab)( void )
829 {
830 _tnl_light_tab[IDX] = TAG(light_rgba);
831 _tnl_light_fast_tab[IDX] = TAG(light_fast_rgba);
832 _tnl_light_fast_single_tab[IDX] = TAG(light_fast_rgba_single);
833 _tnl_light_spec_tab[IDX] = TAG(light_rgba_spec);
834 _tnl_light_ci_tab[IDX] = TAG(light_ci);
835 }
836
837
838 #undef TAG
839 #undef IDX
840 #undef NR_SIDES