00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 #include "vp_global.h"
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 #define NORM_13                 
00094 #undef NORM_15                  
00095 
00096 #ifdef NORM_13                  
00097 #define NORM_N          44      
00098 #define NORM_BITS       13      
00099 
00100 #define MAX_NORMAL      7923    
00101 #endif
00102 
00103 #ifdef NORM_15                  
00104 #define NORM_N          90
00105 #define NORM_BITS       15
00106 #define MAX_NORMAL      16131
00107 #endif
00108 
00109 
00110 
00111 static int NormalTablesInitialized = 0; 
00112 static short *NormalPy; 
00113 
00114 
00115 
00116 static short NormalPyStorage[1+2*NORM_N];       
00117 static short *NormalXLimit;     
00118 static short NormalXLimitStorage[1+2*NORM_N]; 
00119 static void InitNormalTables ANSI_ARGS((void));
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 static void
00128 InitNormalTables()
00129 {
00130     int y, xcount, codepoint;
00131     int sum;
00132     double value;
00133 
00134     
00135     xcount = 1;
00136     codepoint = 2;
00137     NormalPy = &NormalPyStorage[NORM_N];
00138     NormalXLimit = &NormalXLimitStorage[NORM_N];
00139     for (y = -NORM_N; y <= NORM_N; y++) {
00140         NormalPy[y] = codepoint + (((xcount-1)/2) << 1);
00141         codepoint += (xcount << 1);
00142         NormalXLimit[y] = (xcount-1)/2;
00143         if (y < 0)
00144             xcount += 2;
00145         else
00146             xcount -= 2;
00147     }
00148 
00149     NormalTablesInitialized = 1;
00150 }
00151 
00152 
00153 
00154 
00155 
00156 
00157 
00158 int
00159 vpNormalIndex(nx, ny, nz)
00160 double nx, ny, nz;
00161 {
00162     int n, x, y, xlimit;
00163     double denom, denominv;
00164 
00165     if (!NormalTablesInitialized)
00166         InitNormalTables();
00167     denom = (nx < 0) ? -nx : nx;
00168     denom += (ny < 0) ? -ny : ny;
00169     denom += (nz < 0) ? -nz : nz;
00170     denominv = (double)NORM_N / denom;
00171     x = (int)rint(nx * denominv);
00172     y = (int)rint(ny * denominv);
00173 
00174     
00175     xlimit = NormalXLimit[y];
00176     if (x < 0) {
00177         if (-x > xlimit)
00178             x = -xlimit;
00179     } else {
00180         if (x > xlimit)
00181             x = xlimit;
00182     }
00183 
00184     n = NormalPy[y] + (x << 1);
00185     if (nz < 0)
00186         n |= 1;
00187     ASSERT(n >= 0 && n <= VP_NORM_MAX);
00188     return(n);
00189 }
00190 
00191 
00192 
00193 
00194 
00195 
00196 
00197 vpResult
00198 vpNormal(n, nx, ny, nz)
00199 int n;                  
00200 double *nx, *ny, *nz;   
00201 {
00202     int py, px, pz, pxlimit2;
00203     double pxd, pyd, pzd, plength;
00204 
00205     if (!NormalTablesInitialized)
00206         InitNormalTables();
00207     for (py = -NORM_N; py <= NORM_N; py++) {
00208         pxlimit2 = 2 * ((py<0) ? (NORM_N + py) : (NORM_N - py));
00209         if (NormalPy[py] - pxlimit2 <= n &&
00210             NormalPy[py] + pxlimit2 + 1 >= n) {
00211             break;
00212         }
00213     }
00214     if (py > NORM_N) {
00215         return(VPERROR_BAD_VALUE);
00216     } else {
00217         px = (n - NormalPy[py]) >> 1;
00218         pz = NORM_N;
00219         if (px < 0)
00220             pz += px;
00221         else
00222             pz -= px;
00223         if (py < 0)
00224             pz += py;
00225         else
00226             pz -= py;
00227         if (n & 1)
00228             pz = -pz;
00229         pxd = (double)px;
00230         pyd = (double)py;
00231         pzd = (double)pz;
00232         plength = 1. / sqrt(pxd*pxd+pyd*pyd+pzd*pzd);
00233         *nx = pxd * plength;
00234         *ny = pyd * plength;
00235         *nz = pzd * plength;
00236     }
00237     return(VP_OK);
00238 }
00239 
00240 
00241 
00242 
00243 
00244 
00245 
00246 vpResult
00247 vpScanlineNormals(vpc, length, scalar_data, scalar_minus_y,
00248                   scalar_plus_y, scalar_minus_z, scalar_plus_z,
00249                   voxel_data, scalar_field, grad_field, norm_field)
00250 vpContext *vpc;         
00251 int length;             
00252 unsigned char *scalar_data;     
00253 unsigned char *scalar_minus_y;  
00254 unsigned char *scalar_plus_y;   
00255 unsigned char *scalar_minus_z;  
00256 unsigned char *scalar_plus_z;   
00257 void *voxel_data;       
00258 int scalar_field;       
00259 int grad_field;         
00260 int norm_field;         
00261 {
00262     int x;                      
00263     double grad_x;              
00264     double grad_y;
00265     double grad_z;
00266     double twice_grad_mag;      
00267     int grad;                   
00268     int norm;                   
00269     int edge;                   
00270 
00271     int voxel_size;             
00272     int scalar_offset;          
00273     int grad_offset;            
00274     int norm_offset;            
00275     char *voxel;                
00276     int retcode;
00277 
00278     
00279     if ((retcode = VPCheckVoxelFields(vpc)) != VP_OK)
00280         return(retcode);
00281     if (scalar_field != VP_SKIP_FIELD) {
00282         if (scalar_field < 0 || scalar_field >= vpc->num_voxel_fields)
00283             return(VPSetError(vpc, VPERROR_BAD_VALUE));
00284         if (vpc->field_size[scalar_field] != VP_SCALAR_SIZE)
00285             return(VPSetError(vpc, VPERROR_BAD_VALUE));
00286         scalar_offset = vpc->field_offset[scalar_field];
00287     }
00288     if (grad_field != VP_SKIP_FIELD) {
00289         if (grad_field < 0 || grad_field >= vpc->num_voxel_fields)
00290             return(VPSetError(vpc, VPERROR_BAD_VALUE));
00291         if (vpc->field_size[grad_field] != VP_GRAD_SIZE)
00292             return(VPSetError(vpc, VPERROR_BAD_VALUE));
00293         grad_offset = vpc->field_offset[grad_field];
00294     }
00295     if (norm_field != VP_SKIP_FIELD) {
00296         if (norm_field < 0 || norm_field >= vpc->num_voxel_fields)
00297             return(VPSetError(vpc, VPERROR_BAD_VALUE));
00298         if (vpc->field_size[norm_field] != VP_NORM_SIZE)
00299             return(VPSetError(vpc, VPERROR_BAD_VALUE));
00300         norm_offset = vpc->field_offset[norm_field];
00301     }
00302     voxel_size = vpc->raw_bytes_per_voxel;
00303 
00304     
00305     voxel = voxel_data;
00306     if (scalar_minus_y == NULL || scalar_plus_y == NULL ||
00307         scalar_minus_z == NULL || scalar_plus_z == NULL) {
00308         edge = 1;
00309     } else {
00310         edge = 0;
00311     }
00312     for (x = 0; x < length; x++) {
00313         
00314         if (edge || x == 0 || x == length-1) {
00315             if (scalar_field != VP_SKIP_FIELD)
00316                 ByteField(voxel, scalar_offset) = scalar_data[x];
00317             if (grad_field != VP_SKIP_FIELD)
00318                 ByteField(voxel, grad_offset) = 0;
00319             if (norm_field != VP_SKIP_FIELD)
00320                 ShortField(voxel, norm_offset) = 0;
00321         } else {
00322             grad_x = (int)scalar_data[x+1] - (int)scalar_data[x-1];
00323             grad_y = (int)scalar_plus_y[x] - (int)scalar_minus_y[x];
00324             grad_z = (int)scalar_plus_z[x] - (int)scalar_minus_z[x];
00325             twice_grad_mag = sqrt(grad_x*grad_x+grad_y*grad_y+grad_z*grad_z);
00326             if (scalar_field != VP_SKIP_FIELD)
00327                 ByteField(voxel, scalar_offset) = scalar_data[x];
00328             if (grad_field != VP_SKIP_FIELD) {
00329                 grad = (int)rint(0.5 * twice_grad_mag);
00330                 ASSERT(grad >= 0 && grad <= VP_GRAD_MAX);
00331                 ByteField(voxel, grad_offset) = grad;
00332             }
00333             if (norm_field != VP_SKIP_FIELD) {
00334                 if (twice_grad_mag < VP_EPS)
00335                     norm = 0;
00336                 else
00337                     norm = vpNormalIndex(grad_x / twice_grad_mag,
00338                                          grad_y / twice_grad_mag,
00339                                          grad_z / twice_grad_mag);
00340                 ShortField(voxel, norm_offset) = norm;
00341             }
00342         }
00343 
00344         
00345         voxel += voxel_size;
00346     }
00347     return(VP_OK);
00348 }
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 
00357 vpResult
00358 vpVolumeNormals(vpc, scalar_data, length, scalar_field, grad_field, norm_field)
00359 vpContext *vpc;         
00360 unsigned char *scalar_data;     
00361 int length;             
00362 int scalar_field;       
00363 int grad_field;         
00364 int norm_field;         
00365 {
00366     int xlen, ylen, zlen;       
00367     int y, z;                   
00368     unsigned char *scalar;      
00369     int scalar_ystride;         
00370     int scalar_zstride;         
00371     char *voxel;                
00372     int voxel_ystride;          
00373     int voxel_zstride;          
00374     unsigned char *s_py, *s_my, *s_pz, *s_mz; 
00375     int retcode;
00376 
00377     
00378     if ((retcode = VPCheckRawVolume(vpc)) != VP_OK)
00379         return(retcode);
00380     xlen = vpc->xlen;
00381     ylen = vpc->ylen;
00382     zlen = vpc->zlen;
00383     if (xlen * ylen * zlen != length)
00384         return(VPSetError(vpc, VPERROR_BAD_SIZE));
00385 
00386     
00387     scalar = scalar_data;
00388     scalar_ystride = xlen;
00389     scalar_zstride = xlen*ylen;
00390     voxel = vpc->raw_voxels;
00391     voxel_ystride = vpc->ystride;
00392     voxel_zstride = vpc->zstride;
00393 
00394     
00395     for (z = 0; z < zlen; z++) {
00396         ReportStatus(vpc, (double)z / (double)zlen);
00397         for (y = 0; y < ylen; y++) {
00398             s_my = (y == 0)      ? NULL : scalar - scalar_ystride;
00399             s_py = (y == ylen-1) ? NULL : scalar + scalar_ystride;
00400             s_mz = (z == 0)      ? NULL : scalar - scalar_zstride;
00401             s_pz = (z == zlen-1) ? NULL : scalar + scalar_zstride;
00402             retcode = vpScanlineNormals(vpc, xlen, scalar, s_my, s_py,
00403                                         s_mz, s_pz, voxel, scalar_field,
00404                                         grad_field, norm_field);
00405             if (retcode != VP_OK)
00406                 return(retcode);
00407             scalar += scalar_ystride;
00408             voxel += voxel_ystride;
00409         }
00410         scalar += scalar_zstride - ylen*scalar_ystride;
00411         voxel += voxel_zstride - ylen*voxel_ystride;
00412     }
00413     ReportStatus(vpc, 1.0);
00414     return(VP_OK);
00415 }
00416 
00417 
00418 
00419 
00420 
00421 
00422 
00423 
00424 vpResult
00425 vpShadeTable(vpc)
00426 vpContext *vpc;
00427 {
00428     int num_lights;             
00429     vpVector3 light_color[VP_MAX_LIGHTS]; 
00430     vpVector4 obj_light[VP_MAX_LIGHTS]; 
00431     vpVector4 obj_highlight[VP_MAX_LIGHTS]; 
00432     vpVector4 obj_viewpoint;    
00433     vpMatrix4 a;                
00434     double *rhs[VP_MAX_LIGHTS+1];
00435     int px, py, pz;             
00436     double pxd, pyd, pzd;       
00437     double plength;
00438     int pxlimit;                
00439     double nx, ny, nz;          
00440     double n_dot_v_xy;          
00441     double n_dot_v_z;           
00442     double n_dot_v;             
00443     double n_dot_l_xy;          
00444     double n_dot_l_z;           
00445     double n_dot_l;             
00446     double n_dot_h_xy;          
00447     double n_dot_h_z;           
00448     double n_dot_h;             
00449     float r, g, b;              
00450     float *table_row;           
00451     float *table;               
00452     float *shadow_table_row;    
00453     float *shadow_table;        
00454     int surface_side;           
00455     int znegative;              
00456     int light_both_sides;       
00457     int reverse_surface_sides;  
00458     int color_channels;         
00459     int num_materials;          
00460     int retcode;
00461     double *matl_props;         
00462     int enable_shadows;         
00463     int shadow_light;           
00464     int clamp;                  
00465     int c, l, m;
00466 #ifdef DEBUG
00467     vpVector4 tmpv;
00468 #endif
00469     DECLARE_TIME(t0);
00470     DECLARE_TIME(t1);
00471 
00472     
00473     if (vpc->shading_mode != LOOKUP_SHADER)
00474         return(VP_OK);
00475     if ((retcode = VPCheckShader(vpc)) != VP_OK)
00476         return(retcode);
00477     if ((retcode = VPCheckShadows(vpc)) != VP_OK)
00478         return(retcode);
00479     ASSERT(vpc->color_channels == 1 || vpc->color_channels == 3);
00480 
00481     
00482     GET_TIME(vpc, t0);
00483 
00484     
00485     vpSetVector4(obj_viewpoint, 0., 0., 1., 1.);
00486     rhs[0] = obj_viewpoint;
00487     num_lights = 0;
00488     for (c = 0; c < VP_MAX_LIGHTS; c++) {
00489         if (vpc->light_enable[c]) {
00490             bcopy(vpc->light_color[c], light_color[num_lights],
00491                   sizeof(vpVector3));
00492             bcopy(vpc->light_vector[c], obj_light[num_lights],
00493                   sizeof(vpVector4));
00494             rhs[num_lights+1] = obj_light[num_lights];
00495             num_lights++;
00496         }
00497     }
00498     bcopy(vpc->transforms[VP_MODEL], a, sizeof(vpMatrix4));
00499     retcode = vpSolveSystem4(a, rhs, num_lights+1);
00500     if (retcode != VP_OK)
00501         return(retcode);
00502 
00503 #ifdef DEBUG
00504     
00505     vpMatrixVectorMult4(tmpv, vpc->transforms[VP_MODEL], obj_viewpoint);
00506     if (fabs(tmpv[0]) > VP_EPS || fabs(tmpv[1]) > VP_EPS ||
00507         fabs(tmpv[2] - 1.) > VP_EPS || fabs(tmpv[3] - 1.) > VP_EPS) {
00508         printf("\n");
00509         printf("Modelview:\n");
00510         printf("    %12.8f %12.8f %12.8f %12.8f\n",
00511            vpc->transforms[VP_MODEL][0][0], vpc->transforms[VP_MODEL][0][1],
00512            vpc->transforms[VP_MODEL][0][2], vpc->transforms[VP_MODEL][0][3]);
00513         printf("    %12.8f %12.8f %12.8f %12.8f\n",
00514            vpc->transforms[VP_MODEL][1][0], vpc->transforms[VP_MODEL][1][1],
00515            vpc->transforms[VP_MODEL][1][2], vpc->transforms[VP_MODEL][1][3]);
00516         printf("    %12.8f %12.8f %12.8f %12.8f\n",
00517            vpc->transforms[VP_MODEL][2][0], vpc->transforms[VP_MODEL][2][1],
00518            vpc->transforms[VP_MODEL][2][2], vpc->transforms[VP_MODEL][2][3]);
00519         printf("    %12.8f %12.8f %12.8f %12.8f\n",
00520            vpc->transforms[VP_MODEL][3][0], vpc->transforms[VP_MODEL][3][1],
00521            vpc->transforms[VP_MODEL][3][2], vpc->transforms[VP_MODEL][3][3]);
00522         VPBug("SolveSystem failed on viewpoint");
00523     }
00524     l = 0;
00525     for (c = 0; c < VP_MAX_LIGHTS; c++) {
00526         if (vpc->light_enable[c]) {
00527             vpMatrixVectorMult4(tmpv, vpc->transforms[VP_MODEL], obj_light[l]);
00528             if (fabs(tmpv[0] - vpc->light_vector[c][0]) > VP_EPS ||
00529                 fabs(tmpv[1] - vpc->light_vector[c][1]) > VP_EPS ||
00530                 fabs(tmpv[2] - vpc->light_vector[c][2]) > VP_EPS ||
00531                 fabs(tmpv[3] - vpc->light_vector[c][3]) > VP_EPS)
00532                 VPBug("SolveSystem failed on light %d\n", c);
00533             l++;
00534         }
00535     }
00536 #endif
00537 
00538     
00539     for (l = 0; l < num_lights; l++) {
00540         obj_highlight[l][0] = obj_light[l][0] + obj_viewpoint[0];
00541         obj_highlight[l][1] = obj_light[l][1] + obj_viewpoint[1];
00542         obj_highlight[l][2] = obj_light[l][2] + obj_viewpoint[2];
00543         vpNormalize3(obj_highlight[l]);
00544     }
00545 
00546     
00547     light_both_sides = vpc->light_both_sides;
00548     reverse_surface_sides = vpc->reverse_surface_sides;
00549     color_channels = vpc->color_channels;
00550     num_materials = vpc->num_materials;
00551     table = vpc->shade_color_table;
00552     enable_shadows = vpc->enable_shadows;
00553     if (enable_shadows) {
00554         shadow_table = vpc->shadow_color_table;
00555         shadow_light = vpc->shadow_light_num - VP_LIGHT0;
00556         bzero(shadow_table, vpc->shadow_color_table_size);
00557     } else {
00558         shadow_table = NULL;
00559         shadow_light = -1;
00560     }
00561     clamp = vpc->clamp_shade_table;
00562 
00563     
00564     for (znegative = 0; znegative <= 1; znegative++) {
00565         if (znegative) {
00566             if (reverse_surface_sides)
00567                 surface_side = EXT_SURFACE;
00568             else
00569                 surface_side = INT_SURFACE;
00570         } else {
00571             if (reverse_surface_sides)
00572                 surface_side = INT_SURFACE;
00573             else
00574                 surface_side = EXT_SURFACE;
00575         }
00576         for (m = 0; m < num_materials; m++) {
00577             matl_props = vpc->matl_props[m][surface_side];
00578             *table++ = matl_props[MATL_AMB_R];
00579             if (color_channels == 3) {
00580                 *table++ = matl_props[MATL_AMB_G];
00581                 *table++ = matl_props[MATL_AMB_B];
00582             }
00583         }
00584     }
00585     table_row = table;
00586     if (enable_shadows) {
00587         for (znegative = 0; znegative <= 1; znegative++) {
00588             for (m = 0; m < num_materials; m++) {
00589                 *shadow_table++ = 0;
00590                 if (color_channels == 3) {
00591                     *shadow_table++ = 0;
00592                     *shadow_table++ = 0;
00593                 }
00594             }
00595         }
00596     }
00597     shadow_table_row = shadow_table;
00598 
00599     
00600     for (py = -NORM_N; py <= NORM_N; py++) {
00601         pxlimit = (py < 0) ? (NORM_N + py) : (NORM_N - py);
00602         pz = -1;
00603         pxd = (double)(-pxlimit-1);
00604         pyd = (double)py;
00605         pzd = (double)(-1);
00606         for (px = -pxlimit; px <= pxlimit; px++) {
00607             
00608             pxd += 1.0;
00609             if (px <= 0) {
00610                 pz++;
00611                 pzd += 1.0;
00612             } else {
00613                 pz--;
00614                 pzd -= 1.0;
00615             }
00616             plength = 1. / sqrt(pxd*pxd + pyd*pyd + pzd*pzd);
00617             nx = pxd * plength;
00618             ny = pyd * plength;
00619             nz = pzd * plength;
00620 
00621             
00622             n_dot_v_xy = nx*obj_viewpoint[0] + ny*obj_viewpoint[1];
00623             n_dot_v_z = nz*obj_viewpoint[2];
00624 
00625             
00626             table = table_row;
00627             for (znegative = 0; znegative <= 1; znegative++) {
00628                 if (znegative)
00629                     n_dot_v = n_dot_v_xy - n_dot_v_z;
00630                 else
00631                     n_dot_v = n_dot_v_xy + n_dot_v_z;
00632                 if (reverse_surface_sides)
00633                     n_dot_v = -n_dot_v;
00634                 if (n_dot_v >= 0)
00635                     surface_side = EXT_SURFACE;
00636                 else
00637                     surface_side = INT_SURFACE;
00638                 for (m = 0; m < num_materials; m++) {
00639                     matl_props = vpc->matl_props[m][surface_side];
00640                     *table++ = matl_props[MATL_AMB_R];
00641                     if (color_channels == 3) {
00642                         *table++ = matl_props[MATL_AMB_G];
00643                         *table++ = matl_props[MATL_AMB_B];
00644                     }
00645                 }
00646             }
00647 
00648             
00649             for (l = 0; l < num_lights; l++) {
00650                 if (l == shadow_light)
00651                     table = shadow_table_row;
00652                 else
00653                     table = table_row;
00654 
00655                 
00656                 n_dot_l_xy = nx*obj_light[l][0] + ny*obj_light[l][1];
00657                 n_dot_l_z = nz*obj_light[l][2];
00658                 n_dot_h_xy = nx*obj_highlight[l][0] + ny*obj_highlight[l][1];
00659                 n_dot_h_z = nz*obj_highlight[l][2];
00660 
00661                 
00662                 for (znegative = 0; znegative <= 1; znegative++) {
00663                     if (znegative) {
00664                         n_dot_v = n_dot_v_xy - n_dot_v_z;
00665                         n_dot_l = n_dot_l_xy - n_dot_l_z;
00666                         n_dot_h = n_dot_h_xy - n_dot_h_z;
00667                     } else {
00668                         n_dot_v = n_dot_v_xy + n_dot_v_z;
00669                         n_dot_l = n_dot_l_xy + n_dot_l_z;
00670                         n_dot_h = n_dot_h_xy + n_dot_h_z;
00671                     }
00672                     if (reverse_surface_sides) {
00673                         n_dot_v = -n_dot_v;
00674                         n_dot_l = -n_dot_l;
00675                         n_dot_h = -n_dot_h;
00676                     }
00677                     if (n_dot_v >= 0)
00678                         surface_side = EXT_SURFACE;
00679                     else
00680                         surface_side = INT_SURFACE;
00681                     if (light_both_sides) {
00682                         n_dot_l = fabs(n_dot_l);
00683                         n_dot_h = fabs(n_dot_h);
00684                     } else if (surface_side == EXT_SURFACE) {
00685                         n_dot_l = MAX(n_dot_l, 0.0);
00686                         n_dot_h = MAX(n_dot_h, 0.0);
00687                     } else {
00688                         n_dot_l = MAX(-n_dot_l, 0.0);
00689                         n_dot_h = MAX(-n_dot_h, 0.0);
00690                     }
00691 
00692                     
00693                     for (m = 0; m < num_materials; m++) {
00694                         matl_props = vpc->matl_props[m][surface_side];
00695                         *table++ += light_color[l][0]*(matl_props[MATL_DIFF_R]*
00696                                     n_dot_l + matl_props[MATL_SPEC_R]*
00697                                     pow(n_dot_h, matl_props[MATL_SHINY]));
00698                         if (color_channels == 3) {
00699                             *table++ += light_color[l][1]*
00700                                     (matl_props[MATL_DIFF_G]*
00701                                     n_dot_l + matl_props[MATL_SPEC_G]*
00702                                     pow(n_dot_h, matl_props[MATL_SHINY]));
00703                             *table++ += light_color[l][2]*
00704                                     (matl_props[MATL_DIFF_B]*
00705                                     n_dot_l + matl_props[MATL_SPEC_B]*
00706                                     pow(n_dot_h, matl_props[MATL_SHINY]));
00707                         }
00708                     } 
00709                 } 
00710             } 
00711 
00712             
00713             if (clamp) {
00714                 if (enable_shadows) {
00715                     table = table_row;
00716                     shadow_table = shadow_table_row;
00717                     for (znegative = 0; znegative <= 1; znegative++) {
00718                         for (m = 0; m < num_materials; m++) {
00719                             for (c = 0; c < color_channels; c++) {
00720                                 if (*table > 255.)
00721                                     *table = 255.;
00722                                 if (*table + *shadow_table > 255.)
00723                                     *shadow_table = 255. - *table;
00724                                 shadow_table++;
00725                                 table++;
00726                             }
00727                         }
00728                     }
00729                 } else {
00730                     table = table_row;
00731                     for (znegative = 0; znegative <= 1; znegative++) {
00732                         for (m = 0; m < num_materials; m++) {
00733                             for (c = 0; c < color_channels; c++) {
00734                                 if (*table > 255.)
00735                                     *table = 255.;
00736                                 table++;
00737                             }
00738                         }
00739                     }
00740                 }
00741             }
00742 
00743             if (num_materials == 1) {
00744                 table_row += 2*color_channels;
00745             } else {
00746                 if (color_channels == 1)
00747                     table_row += 2*num_materials;
00748                 else
00749                     table_row += 6*num_materials;
00750             }
00751 
00752             if (enable_shadows) {
00753                 if (num_materials == 1) {
00754                     shadow_table_row += 2*color_channels;
00755                 } else {
00756                     if (color_channels == 1)
00757                         shadow_table_row += 2*num_materials;
00758                     else
00759                         shadow_table_row += 6*num_materials;
00760                 }
00761             }
00762         } 
00763     } 
00764 
00765     
00766     GET_TIME(vpc, t1);
00767     STORE_TIME(vpc, VPTIMER_SHADE, t0, t1);
00768 
00769     return(VP_OK);
00770 }