[OPENGL32][MESA] Downgrade Mesa library to version 2.6
[reactos.git] / dll / opengl / mesa / shade.c
1 /* $Id: shade.c,v 1.10 1997/12/18 02:54:48 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 2.6
6 * Copyright (C) 1995-1997 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: shade.c,v $
26 * Revision 1.10 1997/12/18 02:54:48 brianp
27 * now using FloatToInt() macro for better performance on x86
28 *
29 * Revision 1.9 1997/07/24 01:21:56 brianp
30 * changed precompiled header symbol from PCH to PC_HEADER
31 *
32 * Revision 1.8 1997/07/09 03:04:44 brianp
33 * fixed bug in gl_color_shade_vertices() with GL_COLOR_MATERIAL
34 *
35 * Revision 1.7 1997/07/05 16:24:26 brianp
36 * fixed FP underflow problem in pow(). Renamed h[xyz] to h_[xyz].
37 *
38 * Revision 1.6 1997/06/20 04:15:43 brianp
39 * optimized changing of SHININESS (Henk Kok)
40 *
41 * Revision 1.5 1997/06/20 02:28:40 brianp
42 * changed color components from GLfixed to GLubyte
43 *
44 * Revision 1.4 1997/05/28 03:26:29 brianp
45 * added precompiled header (PCH) support
46 *
47 * Revision 1.3 1997/05/23 03:01:18 brianp
48 * commented out a few const keywords because IRIX cc chokes on them
49 *
50 * Revision 1.2 1997/05/09 02:41:08 brianp
51 * call GL_SQRT() instead of sqrt()
52 *
53 * Revision 1.1 1997/04/01 04:11:04 brianp
54 * Initial revision
55 *
56 */
57
58
59 #ifdef PC_HEADER
60 #include "all.h"
61 #else
62 #include <math.h>
63 #include "macros.h"
64 #include "mmath.h"
65 #include "shade.h"
66 #include "types.h"
67 #endif
68
69
70
71 /*
72 * Return x^y.
73 */
74 static GLfloat gl_pow( GLfloat x, GLfloat y )
75 {
76 GLdouble z = pow(x, y);
77 if (z<1.0e-10)
78 return 0.0F;
79 else
80 return (GLfloat) z;
81 }
82
83
84
85 /*
86 * Use current lighting/material settings to compute the RGBA colors of
87 * an array of vertexes.
88 * Input: side - 0=use front material, 1=use back material
89 * n - number of vertexes to process
90 * vertex - array of vertex positions in eye coordinates
91 * normal - array of surface normal vectors
92 * Output: color - array of resulting colors
93 */
94 void gl_color_shade_vertices( GLcontext *ctx,
95 GLuint side,
96 GLuint n,
97 /*const*/ GLfloat vertex[][4],
98 /*const*/ GLfloat normal[][3],
99 GLubyte color[][4] )
100 {
101 GLint j;
102 GLfloat rscale, gscale, bscale, ascale;
103 GLfloat baseR, baseG, baseB, baseA;
104 GLint sumA;
105 struct gl_light *light;
106 struct gl_material *mat;
107
108 /* Compute scale factor to go from floats in [0,1] to integers or fixed
109 * point values:
110 */
111 rscale = ctx->Visual->RedScale;
112 gscale = ctx->Visual->GreenScale;
113 bscale = ctx->Visual->BlueScale;
114 ascale = ctx->Visual->AlphaScale;
115
116 mat = &ctx->Light.Material[side];
117
118 /*** Compute color contribution from global lighting ***/
119 baseR = mat->Emission[0] + ctx->Light.Model.Ambient[0] * mat->Ambient[0];
120 baseG = mat->Emission[1] + ctx->Light.Model.Ambient[1] * mat->Ambient[1];
121 baseB = mat->Emission[2] + ctx->Light.Model.Ambient[2] * mat->Ambient[2];
122 baseA = mat->Diffuse[3]; /* Alpha is simple, same for all vertices */
123
124 sumA = (GLint) (CLAMP( baseA, 0.0F, 1.0F ) * ascale);
125
126 for (j=0;j<n;j++) {
127 GLfloat sumR, sumG, sumB;
128 GLfloat nx, ny, nz;
129
130 if (side==0) {
131 /* shade frontside */
132 nx = normal[j][0];
133 ny = normal[j][1];
134 nz = normal[j][2];
135 }
136 else {
137 /* shade backside */
138 nx = -normal[j][0];
139 ny = -normal[j][1];
140 nz = -normal[j][2];
141 }
142
143 sumR = baseR;
144 sumG = baseG;
145 sumB = baseB;
146
147 /* Add contribution from each enabled light source */
148 for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
149 GLfloat ambientR, ambientG, ambientB;
150 GLfloat attenuation, spot;
151 GLfloat VPx, VPy, VPz; /* unit vector from vertex to light */
152 GLfloat n_dot_VP; /* n dot VP */
153
154 /* compute VP and attenuation */
155 if (light->Position[3]==0.0) {
156 /* directional light */
157 VPx = light->VP_inf_norm[0];
158 VPy = light->VP_inf_norm[1];
159 VPz = light->VP_inf_norm[2];
160 attenuation = 1.0F;
161 }
162 else {
163 /* positional light */
164 GLfloat d; /* distance from vertex to light */
165 VPx = light->Position[0] - vertex[j][0];
166 VPy = light->Position[1] - vertex[j][1];
167 VPz = light->Position[2] - vertex[j][2];
168 d = (GLfloat) GL_SQRT( VPx*VPx + VPy*VPy + VPz*VPz );
169 if (d>0.001F) {
170 GLfloat invd = 1.0F / d;
171 VPx *= invd;
172 VPy *= invd;
173 VPz *= invd;
174 }
175 attenuation = 1.0F / (light->ConstantAttenuation
176 + d * (light->LinearAttenuation
177 + d * light->QuadraticAttenuation));
178 }
179
180 /* spotlight factor */
181 if (light->SpotCutoff==180.0F) {
182 /* not a spot light */
183 spot = 1.0F;
184 }
185 else {
186 GLfloat PVx, PVy, PVz, PV_dot_dir;
187 PVx = -VPx;
188 PVy = -VPy;
189 PVz = -VPz;
190 PV_dot_dir = PVx*light->NormDirection[0]
191 + PVy*light->NormDirection[1]
192 + PVz*light->NormDirection[2];
193 if (PV_dot_dir<=0.0F || PV_dot_dir<light->CosCutoff) {
194 /* outside of cone */
195 spot = 0.0F;
196 }
197 else {
198 double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
199 int k = (int) x;
200 spot = light->SpotExpTable[k][0]
201 + (x-k)*light->SpotExpTable[k][1];
202 }
203 }
204
205 ambientR = mat->Ambient[0] * light->Ambient[0];
206 ambientG = mat->Ambient[1] * light->Ambient[1];
207 ambientB = mat->Ambient[2] * light->Ambient[2];
208
209 /* Compute dot product or normal and vector from V to light pos */
210 n_dot_VP = nx * VPx + ny * VPy + nz * VPz;
211
212 /* diffuse and specular terms */
213 if (n_dot_VP<=0.0F) {
214 /* surface face away from light, no diffuse or specular */
215 GLfloat t = attenuation * spot;
216 sumR += t * ambientR;
217 sumG += t * ambientG;
218 sumB += t * ambientB;
219 /* done with this light */
220 }
221 else {
222 GLfloat diffuseR, diffuseG, diffuseB;
223 GLfloat specularR, specularG, specularB;
224 GLfloat h_x, h_y, h_z, n_dot_h, t;
225
226 /* diffuse term */
227 diffuseR = n_dot_VP * mat->Diffuse[0] * light->Diffuse[0];
228 diffuseG = n_dot_VP * mat->Diffuse[1] * light->Diffuse[1];
229 diffuseB = n_dot_VP * mat->Diffuse[2] * light->Diffuse[2];
230
231 /* specular term */
232 if (ctx->Light.Model.LocalViewer) {
233 GLfloat vx, vy, vz, vlen;
234 vx = vertex[j][0];
235 vy = vertex[j][1];
236 vz = vertex[j][2];
237 vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
238 if (vlen>0.0001F) {
239 GLfloat invlen = 1.0F / vlen;
240 vx *= invlen;
241 vy *= invlen;
242 vz *= invlen;
243 }
244 /* h = VP + VPe */
245 h_x = VPx - vx;
246 h_y = VPy - vy;
247 h_z = VPz - vz;
248 }
249 else {
250 /* h = VP + <0,0,1> */
251 h_x = VPx;
252 h_y = VPy;
253 h_z = VPz + 1.0F;
254 }
255
256 /* attention: h is not normalized, done later if needed */
257 n_dot_h = nx*h_x + ny*h_y + nz*h_z;
258
259 if (n_dot_h<=0.0F) {
260 specularR = 0.0F;
261 specularG = 0.0F;
262 specularB = 0.0F;
263 }
264 else {
265 GLfloat spec_coef;
266 /* now `correct' the dot product */
267 n_dot_h = n_dot_h / GL_SQRT( h_x*h_x + h_y*h_y + h_z*h_z );
268 if (n_dot_h>1.0F) {
269 /* only happens if normal vector length > 1.0 */
270 spec_coef = pow( n_dot_h, mat->Shininess );
271 }
272 else {
273 /* use table lookup approximation */
274 int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
275 if (mat->ShineTable[k] < 0.0F)
276 mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
277 spec_coef = mat->ShineTable[k];
278 }
279 if (spec_coef<1.0e-10) {
280 specularR = 0.0F;
281 specularG = 0.0F;
282 specularB = 0.0F;
283 }
284 else {
285 specularR = spec_coef * mat->Specular[0]*light->Specular[0];
286 specularG = spec_coef * mat->Specular[1]*light->Specular[1];
287 specularB = spec_coef * mat->Specular[2]*light->Specular[2];
288 }
289 }
290
291 t = attenuation * spot;
292 sumR += t * (ambientR + diffuseR + specularR);
293 sumG += t * (ambientG + diffuseG + specularG);
294 sumB += t * (ambientB + diffuseB + specularB);
295 }
296
297 } /*loop over lights*/
298
299 /* clamp and convert to integer or fixed point */
300 color[j][0] = FloatToInt(CLAMP( sumR, 0.0F, 1.0F ) * rscale);
301 color[j][1] = FloatToInt(CLAMP( sumG, 0.0F, 1.0F ) * gscale);
302 color[j][2] = FloatToInt(CLAMP( sumB, 0.0F, 1.0F ) * bscale);
303 color[j][3] = sumA;
304
305 } /*loop over vertices*/
306 }
307
308
309
310 /*
311 * This is an optimized version of the above function.
312 */
313 void gl_color_shade_vertices_fast( GLcontext *ctx,
314 GLuint side,
315 GLuint n,
316 /*const*/ GLfloat normal[][3],
317 GLubyte color[][4] )
318 {
319 GLint j;
320 GLfloat rscale, gscale, bscale, ascale;
321 GLint sumA;
322 GLfloat *baseColor = ctx->Light.BaseColor[side];
323
324 /* Compute scale factor to go from floats in [0,1] to integers or fixed
325 * point values:
326 */
327 rscale = ctx->Visual->RedScale;
328 gscale = ctx->Visual->GreenScale;
329 bscale = ctx->Visual->BlueScale;
330 ascale = ctx->Visual->AlphaScale;
331
332 /* Alpha is easy to compute, same for all vertices */
333 sumA = (GLint) (baseColor[3] * ascale);
334
335 /* Loop over vertices */
336 for (j=0;j<n;j++) {
337 GLfloat sumR, sumG, sumB;
338 GLfloat nx, ny, nz;
339 struct gl_light *light;
340
341 /* the normal vector */
342 if (side==0) {
343 nx = normal[j][0];
344 ny = normal[j][1];
345 nz = normal[j][2];
346 }
347 else {
348 nx = -normal[j][0];
349 ny = -normal[j][1];
350 nz = -normal[j][2];
351 }
352
353 #ifdef SPEED_HACK
354 if (nz<0.0F) {
355 color[j][0] = 0.0F;
356 color[j][1] = 0.0F;
357 color[j][2] = 0.0F;
358 color[j][3] = A;
359 continue;
360 }
361 #endif
362
363 /* base color from global illumination and enabled light's ambient */
364 sumR = baseColor[0];
365 sumG = baseColor[1];
366 sumB = baseColor[2];
367
368 /* Add contribution from each light source */
369 for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
370 GLfloat n_dot_VP; /* n dot VP */
371
372 n_dot_VP = nx * light->VP_inf_norm[0]
373 + ny * light->VP_inf_norm[1]
374 + nz * light->VP_inf_norm[2];
375
376 /* diffuse and specular terms */
377 if (n_dot_VP>0.0F) {
378 GLfloat n_dot_h;
379 GLfloat *lightMatDiffuse = light->MatDiffuse[side];
380
381 /** add diffuse term **/
382 sumR += n_dot_VP * lightMatDiffuse[0];
383 sumG += n_dot_VP * lightMatDiffuse[1];
384 sumB += n_dot_VP * lightMatDiffuse[2];
385
386 /** specular term **/
387 /* dot product of n and h_inf_norm */
388 n_dot_h = nx * light->h_inf_norm[0]
389 + ny * light->h_inf_norm[1]
390 + nz * light->h_inf_norm[2];
391 if (n_dot_h>0.0F) {
392 if (n_dot_h>1.0F) {
393 /* only happens if Magnitude(n) > 1.0 */
394 GLfloat spec_coef = pow( n_dot_h,
395 ctx->Light.Material[side].Shininess );
396 if (spec_coef>1.0e-10F) {
397 sumR += spec_coef * light->MatSpecular[side][0];
398 sumG += spec_coef * light->MatSpecular[side][1];
399 sumB += spec_coef * light->MatSpecular[side][2];
400 }
401 }
402 else {
403 /* use table lookup approximation */
404 int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
405 struct gl_material *m = &ctx->Light.Material[side];
406 GLfloat spec_coef;
407 if (m->ShineTable[k] < 0.0F)
408 m->ShineTable[k] = gl_pow( n_dot_h, m->Shininess );
409 spec_coef = m->ShineTable[k];
410 sumR += spec_coef * light->MatSpecular[side][0];
411 sumG += spec_coef * light->MatSpecular[side][1];
412 sumB += spec_coef * light->MatSpecular[side][2];
413 }
414 }
415 }
416
417 } /*loop over lights*/
418
419 /* clamp and convert to integer or fixed point */
420 color[j][0] = FloatToInt(MIN2( sumR, 1.0F ) * rscale);
421 color[j][1] = FloatToInt(MIN2( sumG, 1.0F ) * gscale);
422 color[j][2] = FloatToInt(MIN2( sumB, 1.0F ) * bscale);
423 color[j][3] = sumA;
424
425 } /*loop over vertices*/
426 }
427
428
429
430 /*
431 * Use current lighting/material settings to compute the color indexes
432 * for an array of vertices.
433 * Input: n - number of vertices to shade
434 * side - 0=use front material, 1=use back material
435 * vertex - array of [n] vertex position in eye coordinates
436 * normal - array of [n] surface normal vector
437 * Output: indexResult - resulting array of [n] color indexes
438 */
439 void gl_index_shade_vertices( GLcontext *ctx,
440 GLuint side,
441 GLuint n,
442 GLfloat vertex[][4],
443 GLfloat normal[][3],
444 GLuint indexResult[] )
445 {
446 struct gl_material *mat = &ctx->Light.Material[side];
447 GLint j;
448
449 /* loop over vertices */
450 for (j=0;j<n;j++) {
451 GLfloat index;
452 GLfloat diffuse, specular; /* accumulated diffuse and specular */
453 GLfloat nx, ny, nz; /* normal vector */
454 struct gl_light *light;
455
456 if (side==0) {
457 /* shade frontside */
458 nx = normal[j][0];
459 ny = normal[j][1];
460 nz = normal[j][2];
461 }
462 else {
463 /* shade backside */
464 nx = -normal[j][0];
465 ny = -normal[j][1];
466 nz = -normal[j][2];
467 }
468
469 diffuse = specular = 0.0F;
470
471 /* Accumulate diffuse and specular from each light source */
472 for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
473 GLfloat attenuation;
474 GLfloat lx, ly, lz; /* unit vector from vertex to light */
475 GLfloat l_dot_norm; /* dot product of l and n */
476
477 /* compute l and attenuation */
478 if (light->Position[3]==0.0) {
479 /* directional light */
480 /* Effectively, l is a vector from the origin to the light. */
481 lx = light->VP_inf_norm[0];
482 ly = light->VP_inf_norm[1];
483 lz = light->VP_inf_norm[2];
484 attenuation = 1.0F;
485 }
486 else {
487 /* positional light */
488 GLfloat d; /* distance from vertex to light */
489 lx = light->Position[0] - vertex[j][0];
490 ly = light->Position[1] - vertex[j][1];
491 lz = light->Position[2] - vertex[j][2];
492 d = (GLfloat) GL_SQRT( lx*lx + ly*ly + lz*lz );
493 if (d>0.001F) {
494 GLfloat invd = 1.0F / d;
495 lx *= invd;
496 ly *= invd;
497 lz *= invd;
498 }
499 attenuation = 1.0F / (light->ConstantAttenuation
500 + d * (light->LinearAttenuation
501 + d * light->QuadraticAttenuation));
502 }
503
504 l_dot_norm = lx*nx + ly*ny + lz*nz;
505
506 if (l_dot_norm>0.0F) {
507 GLfloat spot_times_atten;
508
509 /* spotlight factor */
510 if (light->SpotCutoff==180.0F) {
511 /* not a spot light */
512 spot_times_atten = attenuation;
513 }
514 else {
515 GLfloat v[3], dot;
516 v[0] = -lx; /* v points from light to vertex */
517 v[1] = -ly;
518 v[2] = -lz;
519 dot = DOT3( v, light->NormDirection );
520 if (dot<=0.0F || dot<light->CosCutoff) {
521 /* outside of cone */
522 spot_times_atten = 0.0F;
523 }
524 else {
525 double x = dot * (EXP_TABLE_SIZE-1);
526 int k = (int) x;
527 GLfloat spot = light->SpotExpTable[k][0]
528 + (x-k)*light->SpotExpTable[k][1];
529 spot_times_atten = spot * attenuation;
530 }
531 }
532
533 /* accumulate diffuse term */
534 diffuse += l_dot_norm * light->dli * spot_times_atten;
535
536 /* accumulate specular term */
537 {
538 GLfloat h_x, h_y, h_z, n_dot_h, spec_coef;
539
540 /* specular term */
541 if (ctx->Light.Model.LocalViewer) {
542 GLfloat vx, vy, vz, vlen;
543 vx = vertex[j][0];
544 vy = vertex[j][1];
545 vz = vertex[j][2];
546 vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
547 if (vlen>0.0001F) {
548 GLfloat invlen = 1.0F / vlen;
549 vx *= invlen;
550 vy *= invlen;
551 vz *= invlen;
552 }
553 h_x = lx - vx;
554 h_y = ly - vy;
555 h_z = lz - vz;
556 }
557 else {
558 h_x = lx;
559 h_y = ly;
560 h_z = lz + 1.0F;
561 }
562 /* attention: s is not normalized, done later if necessary */
563 n_dot_h = h_x*nx + h_y*ny + h_z*nz;
564
565 if (n_dot_h <= 0.0F) {
566 spec_coef = 0.0F;
567 }
568 else {
569 /* now `correct' the dot product */
570 n_dot_h = n_dot_h / GL_SQRT(h_x*h_x + h_y*h_y + h_z*h_z);
571 if (n_dot_h>1.0F) {
572 spec_coef = pow( n_dot_h, mat->Shininess );
573 }
574 else {
575 int k = (int) (n_dot_h * (GLfloat)(SHINE_TABLE_SIZE-1));
576 if (mat->ShineTable[k] < 0.0F)
577 mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
578 spec_coef = mat->ShineTable[k];
579 }
580 }
581 specular += spec_coef * light->sli * spot_times_atten;
582 }
583 }
584
585 } /*loop over lights*/
586
587 /* Now compute final color index */
588 if (specular>1.0F) {
589 index = mat->SpecularIndex;
590 }
591 else {
592 GLfloat d_a, s_a;
593 d_a = mat->DiffuseIndex - mat->AmbientIndex;
594 s_a = mat->SpecularIndex - mat->AmbientIndex;
595
596 index = mat->AmbientIndex
597 + diffuse * (1.0F-specular) * d_a
598 + specular * s_a;
599 if (index>mat->SpecularIndex) {
600 index = mat->SpecularIndex;
601 }
602 }
603 indexResult[j] = (GLuint) (GLint) index;
604
605 } /*for vertex*/
606 }
607