MATERIAL.C

Go to the documentation of this file.
00001 // file material.c  
00002 
00003 #define MODULE_MATERIAL
00004 
00005 /* Calculate the surface colour for given Pixel now that we know which     */
00006 /* face it is on.  Intepolate the PHONG vector first. The ground is an     */
00007 /* independent entity so that its caclulations can be optimised.           */
00008 
00009 /* most shaders have a function to caclulate their value                   */
00010 
00011 #include "render.h"
00012 
00013 extern short mirror_ground;
00014 extern double Rip_Freq;
00015 
00016 #define FLOOR(x) ((x) >= 0.0 ? floor(x) : (0.0 - floor(0.0 - (x)) - 1.0))
00017 
00018 static void Transform_to_Moziac(double, double ,double *, double *);
00019 static void AttenuateGlassSurface(long , long , long ,
00020                                   UCHAR *, UCHAR *, UCHAR *,
00021                                   long *[], long *[], double *[], double *);
00022 static void AttenuateGlass(long, long,
00023                     UCHAR *, UCHAR *, UCHAR *Blue,
00024                     long *[], long *[], double *[], double *);
00025 static void PutBackPlanes(long i, long scanline, double d2,
00026                    UCHAR *Red, UCHAR *Green, UCHAR *Blue,
00027                    double *Zground, long *Zobject, double *Zdepth,
00028                    UCHAR *ZobjChar, long Wsky, double Rsky);
00029 static void GetBackdropValue(long row, long col, vector p, vector d,
00030                              double *colour);
00031 
00032 double spec_pow[16][max_spec+1],spec_gro[max_spec+1];
00033 
00034 static double spec_val[16]={
00035        10.0, 15.0, 20.0, 25.0, 27.0, 30.0, 32.0, 35.0,
00036        40.0, 45.0, 50.0, 55.0, 60.0, 70.0, 80.0, 99.0};
00037 
00038 void init_spec(void){
00039  long i,j; /* use LUT for specular highlight function to speed up rendering */
00040  double d;
00041  for(j=0;j<16;j++){
00042    spec_pow[j][max_spec] = 1.0;
00043    for(i=0;i<max_spec;i++){
00044      d = pow(((double)i/(double)max_spec),spec_val[j]);
00045      spec_pow[j][i]=d;
00046    }
00047  }
00048  for(i=0;i<max_spec;i++)spec_gro[i] = pow((1.0/max_spec*(double)i),200.0);
00049 }
00050 
00051 
00052 /* The functions for Bump and Reflection Mapping  */
00053 
00054 /* Map->bumpX/Y is a scale factor to scale the change in normal            */
00055 /* vector n is unity, max gradient is 255 -> scale factor is               */
00056 /* 1/|x| * max_displ_of normal / 255 * height /100                         */
00057 /* max_displ = tan(a) where a is the max angle the normal is bent          */
00058 /* For Cylinder maps the X axis is defined by n X y which is normalized    */
00059 /* so the appropriate scaling factor is different                          */
00060 
00061 void BumpByCoordinates(imap *Map, short type, long obj, face *f, vector p, vector n){
00062  long  i,j,ialpha,ibeta,k,kl,kr,kt,kb,pixel,ix,iy;
00063  double alpha0,beta0,alpha,beta,a,b,red[3],cc0,cl0,cr0,ct0,cb0,
00064         ve1,ve2,ve3,vp1,vp2,vp3,p1,p2,p3,
00065         detmax,dm,det1,det2,det3,
00066         t1x,t2x,t1y,t2y;
00067  vertex   *V,*v0,*v1,*v2;
00068  static double dalpha_bump[3]={0.0,0.01,0.0},
00069                 dbeta_bump[3]={0.0,0.0,0.01};
00070  vector vv1,vv2;
00071  unsigned char *pP,*pR;
00072  if(Map->bp < 0)return;
00073  j=Map->xmaxbump;
00074  if((V=Object[obj].Vbase) == NULL)return;
00075  v0=(V+(f->V[0]));
00076  v1=(V+(f->V[1]));
00077  v2=(V+(f->V[2]));
00078  ve1=v1->p[0] - v0->p[0]; ve2=v1->p[1] - v0->p[1]; ve3=v1->p[2] - v0->p[2];
00079  vp1=v2->p[0] - v0->p[0]; vp2=v2->p[1] - v0->p[1]; vp3=v2->p[2] - v0->p[2];
00080  p1=p[0]-v0->p[0];
00081  p2=p[1]-v0->p[1];
00082  p3=p[2]-v0->p[2];
00083  det1=ve1*vp2-vp1*ve2;
00084  det2=ve1*vp3-vp1*ve3;
00085  det3=ve2*vp3-vp2*ve3;
00086  k=0; detmax=1.e-3;  /* same as TOL in mirrors */
00087  if((dm=fabs(det1)) > detmax){k=1; detmax=dm;}
00088  if((dm=fabs(det2)) > detmax){k=2; detmax=dm;}
00089  if((dm=fabs(det3)) > detmax){k=3; detmax=dm;}
00090  if(k == 0)return;
00091  else if(k == 1){
00092    a=( vp2*p1-vp1*p2)/det1;
00093    b=(-ve2*p1+ve1*p2)/det1;
00094  }
00095  else if(k == 2){
00096    a=( vp3*p1-vp1*p3)/det2;
00097    b=(-ve3*p1+ve1*p3)/det2;
00098  }
00099  else if(k == 3){
00100    a=( vp3*p2-vp2*p3)/det3;
00101    b=(-ve3*p2+ve2*p3)/det3;
00102  }
00103  // Calculate UV map address of pixel
00104  t1x=f->uu[1] - f->uu[0]; t2x=f->uu[2] - f->uu[0];
00105  t1y=f->vv[1] - f->vv[0]; t2y=f->vv[2] - f->vv[0];
00106  alpha0 = f->uu[0] + a*t1x + b*t2x;
00107  beta0  = f->vv[0] + a*t1y + b*t2y;
00108 
00109  for(i=0;i<3;i++){
00110    alpha = alpha0+dalpha_bump[i];
00111    beta  = beta0+dbeta_bump[i];
00112    if(type == TILE){
00113      if(Map->moziac)Transform_to_Moziac(alpha,beta,&a,&b);
00114      else{
00115        a=(alpha-floor(alpha));
00116        b=(beta-floor(beta));
00117      }
00118      alpha=a*Map->xmaxbump;
00119      beta=b*Map->ymaxbump;
00120    }
00121    else{
00122      alpha=Map->xmaxbump*alpha;
00123      beta =Map->ymaxbump*beta;
00124    }
00125    ialpha = (long)alpha; alpha -= (double)ialpha;
00126    ibeta  = (long)beta;  beta  -= (double)ibeta;
00127    if(ialpha < 0 || ialpha >= Map->xmaxbump)return;
00128    if(ibeta  < 0 || ibeta  >= Map->ymaxbump)return;
00129    k =ibeta*j+ialpha;                       /* do the bi-linear interpolation */
00130    if(type == TILE){
00131      if(Map->moziac){
00132        if(ialpha <   1)kl=1;                     else kl=k-1;
00133        if(ialpha > j-2)kr=k-1;                   else kr=k+1;
00134        if(ibeta  <   1)kb=k+j;                   else kb=k-j;
00135        if(ibeta  > Map->ymaxbump-2)kt=k-j; else kt=k+j;
00136      }
00137      else{
00138        if(ialpha <   1)kl=k+j-1;                            else kl=k-1;
00139        if(ialpha > j-2)kr=ibeta*j;                          else kr=k+1;
00140        if(ibeta  <   1)kb=(Map->ymaxbump-1)*j+ialpha; else kb=k-j;
00141        if(ibeta  > Map->ymaxbump-2)kt=ialpha;         else kt=k+j;
00142      }
00143    }
00144    else{
00145      if(ialpha <   1)kl=k; else kl=k-1;
00146      if(ialpha > j-2)kr=k; else kr=k+1;
00147      if(ibeta  <   1)kb=k; else kb=k-j;
00148      if(ibeta  > Map->ymaxbump-2)kt=k; else kt=k+j;
00149    }
00150 
00151    pR=Map->p24Gbump;
00152    cc0 = (double)pR[k];
00153    cl0 = (double)pR[kl];
00154    cr0 = (double)pR[kr];
00155    ct0 = (double)pR[kt];
00156    cb0 = (double)pR[kb];
00157    if(alpha > 0.5){
00158      alpha = alpha-0.5;
00159      if(beta > 0.5){
00160        beta = beta-0.5;
00161        red[i] = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00162      }
00163      else{
00164        beta = 0.5-beta;
00165        red[i] = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00166      }
00167    }
00168    else{
00169      alpha = 0.5-alpha;
00170      if(beta > 0.5){
00171        beta = beta-0.5;
00172        red[i] = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00173      }
00174      else{
00175        beta = 0.5-beta;
00176        red[i] = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00177      }
00178    }
00179  }
00180  vecscale((red[1]-red[0])*Map->bumpx,Map->x,vv1);
00181  vecscale((red[2]-red[0])*Map->bumpy,Map->y,vv2);
00182  vecsum(n,vv1,n);
00183  vecsum(n,vv2,n);
00184  normalize(n);
00185  return;
00186 }
00187 
00188 void BoxMapIntersect(vector d, long *id, double *alpha, double *beta){
00189  // id 0=front 1=right 2=back 3=left 4=top 5=bottom
00190  double a,b,t=0.1;
00191  long i = -1;   // no hit
00192  normalize(d);
00193  if(d[1] >  t){ // try front
00194    a = d[0]/d[1]; b = d[2]/d[1];
00195    if(-1.0 <= a && a <= 1.0 && -1.0 <= b && b <= 1.0){i=0; goto HIT;}
00196  }
00197  if(d[0] >  t){ // try right
00198    a = d[1]/d[0]; b = d[2]/d[0]; a = -a;
00199    if(-1.0 <= a && a <= 1.0 && -1.0 <= b && b <= 1.0){i=1; goto HIT;}
00200  }
00201  if(d[1] < -t){ // try back
00202    a = -d[0]/d[1]; b = -d[2]/d[1]; a = -a;
00203    if(-1.0 <= a && a <= 1.0 && -1.0 <= b && b <= 1.0){i=2; goto HIT;}
00204  }
00205  if(d[0] < -t){ // try left
00206    a = -d[1]/d[0]; b = -d[2]/d[0];
00207    if(-1.0 <= a && a <= 1.0 && -1.0 <= b && b <= 1.0){i=3; goto HIT;}
00208  }
00209  if(d[2] >  t){ // try top
00210    a = d[0]/d[2]; b = d[1]/d[2];  b= -b;
00211    if(-1.0 <= a && a <= 1.0 && -1.0 <= b && b <= 1.0){i=4; goto HIT;}
00212  }
00213  if(d[2] < -t){ // try bottom
00214    a = -d[0]/d[2]; b = -d[1]/d[2];
00215    if(-1.0 <= a && a <= 1.0 && -1.0 <= b && b <= 1.0){i=5; goto HIT;}
00216  }
00217  HIT:
00218  *id = i;
00219  *alpha = 0.5*(a+1);
00220  *beta = 1.0 - 0.5*(b+1);
00221  return;
00222 }
00223 
00224 void MapMirror(double *R,double *G, double *B, imap *Map, vector p, vector n){
00225  /* p is input direction n is normal  d is reflection direction */
00226  /* map 4 images round the sphere and 2 up down                 */
00227  /* atan2 returns in range -pi to pi                            */
00228 #define FOURDIV2PI 0.318309886     /* 2 images in 360 rotation */
00229 #define TWODIVPI   0.318309886     /* 1 image in -90 to +90    */
00230  
00231  long j,pixel,k,ibeta,ialpha,kl,kr,kt,kb;
00232  double pdotn,alpha,beta,d12;
00233  double cc0,cc1,cc2,cl0,cl1,cl2,cr0,cr1,cr2,ct0,ct1,ct2,cb0,cb1,cb2;
00234  unsigned char *pP,*pR,*pG,*pB;
00235  vector d,dd;
00236  if(Map->rp < 0)return;
00237  pdotn=dot(p,n);
00238  vecscale(2*pdotn,n,d);
00239  vecsub(p,d,dd);   /* un camera the camera transform */
00240  R_m4by1(AntiCamera,dd[0],dd[1],dd[2],&d[0],&d[1],&d[2]);
00241 
00242  BoxMapIntersect(d,&j,&alpha,&beta); if(j < 0)return;
00243 
00244  alpha *= (double)Map->xmaxrefl;
00245  beta *= (double)Map->ymaxrefl;
00246  ialpha = (long)alpha; alpha -= (double)ialpha;
00247  ibeta=(long)beta; beta -= (double)ibeta;
00248  if(ialpha < 0 || ialpha >= Map->xmaxrefl)return;
00249  if(ibeta  < 0 || ibeta  >= Map->ymaxrefl)return;
00250  j=Map->xmaxrefl;
00251  k =ibeta*j+ialpha;
00252 
00253  if(ialpha <   1)kl=1;                 else kl=k-1;
00254  if(ialpha > j-2)kr=k-1;               else kr=k+1;
00255  if(ibeta  <   1)kb=k+j;               else kb=k-j;
00256  if(ibeta  > Map->ymaxrefl-2)kt=k-j;   else kt=k+j;
00257 
00258  pR=Map->p24Rrefl; pG=Map->p24Grefl; pB=Map->p24Brefl;
00259  cc0 = (double)pR[k];  cc1 = (double)pG[k];  cc2 = (double)pB[k];
00260  cl0 = (double)pR[kl]; cl1 = (double)pG[kl]; cl2 = (double)pB[kl];
00261  cr0 = (double)pR[kr]; cr1 = (double)pG[kr]; cr2 = (double)pB[kr];
00262  ct0 = (double)pR[kt]; ct1 = (double)pG[kt]; ct2 = (double)pB[kt];
00263  cb0 = (double)pR[kb]; cb1 = (double)pG[kb]; cb2 = (double)pB[kb];
00264  if(alpha > 0.5){
00265    alpha = alpha-0.5;
00266    if(beta > 0.5){
00267      beta = beta-0.5;
00268      *R   = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00269      *G   = (cr1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00270      *B   = (cr2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00271    }
00272    else{
00273      beta = 0.5-beta;
00274      *R   = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00275      *G   = (cr1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00276      *B   = (cr2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00277    }
00278  }
00279  else{
00280    alpha = 0.5-alpha;
00281    if(beta > 0.5){
00282      beta = beta-0.5;
00283      *R   = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00284      *G   = (cl1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00285      *B   = (cl2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00286    }
00287    else{
00288      beta = 0.5-beta;
00289      *R   = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00290      *G   = (cl1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00291      *B   = (cl2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00292    }
00293  }
00294 }
00295 
00296 void MapEnvironment(long col, long row, UCHAR *r, UCHAR *g, UCHAR *b, imap *Map){
00297  long j,pixel,k,ibeta,ialpha,kl,kr,kt,kb,w,kmin,kmax;
00298  double alpha,beta,R,G,B;
00299  double cc0,cc1,cc2,cl0,cl1,cl2,cr0,cr1,cr2,ct0,ct1,ct2,cb0,cb1,cb2;
00300  unsigned char *pP,*pR,*pG,*pB;
00301  vector d,dd;
00302  if(Map->pp < 0)return;
00303  d[0]=((double)col-(double)Xcentre)/scalex;
00304  d[1]=1.0;
00305  d[2]=((double)Ycentre-(double)row)/scaley;
00306  R_m3by1(CameraRotate,d[0],d[1],d[2],&dd[0],&dd[1],&dd[2]);
00307  BoxMapIntersect(dd,&j,&alpha,&beta); if(j < 0){
00308    *r = 0; *g=255; *b=0;  // for diagnosis
00309    return;
00310  }
00311  w=Map->xmax/6;   // 6 horizontal pictures assumed
00312  alpha = ((double)j+alpha)*(double)w;
00313  beta *= (double)Map->ymax;
00314  ialpha = (long)alpha; alpha -= (double)ialpha;
00315  ibeta=(long)beta; beta -= (double)ibeta;
00316  if(ialpha < 0)ialpha=0;
00317  if(ialpha >= Map->xmax)ialpha=Map->xmax-1;
00318  if(ibeta  < 0)ibeta=0;
00319  if(ibeta  >= Map->ymax)ibeta=Map->ymax-1;
00320  k = ibeta*Map->xmax+ialpha;
00321  kmin = j*w + 1;
00322  kmax = (j+1)*w - 2;
00323  if(ialpha <   kmin)kl=k;       else kl=k-1;
00324  if(ialpha > kmax)  kr=k;       else kr=k+1;
00325  if(ibeta  <   1)kb=k;          else kb=k-Map->xmax;
00326  if(ibeta  > Map->ymax-2)kt=k;  else kt=k+Map->xmax;
00327  pR=Map->p24R; pG=Map->p24G; pB=Map->p24B;
00328  // *r = pR[k];  *g = pG[k];  *b = pB[k]; return; // diagnostic
00329  cc0 = (double)pR[k];  cc1 = (double)pG[k];  cc2 = (double)pB[k];
00330  cl0 = (double)pR[kl]; cl1 = (double)pG[kl]; cl2 = (double)pB[kl];
00331  cr0 = (double)pR[kr]; cr1 = (double)pG[kr]; cr2 = (double)pB[kr];
00332  ct0 = (double)pR[kt]; ct1 = (double)pG[kt]; ct2 = (double)pB[kt];
00333  cb0 = (double)pR[kb]; cb1 = (double)pG[kb]; cb2 = (double)pB[kb];
00334  if(alpha > 0.5){
00335    alpha = alpha-0.5;
00336    if(beta > 0.5){
00337      beta = beta-0.5;
00338      R   = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00339      G   = (cr1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00340      B   = (cr2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00341    }
00342    else{
00343      beta = 0.5-beta;
00344      R   = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00345      G   = (cr1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00346      B   = (cr2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00347    }
00348  }
00349  else{
00350    alpha = 0.5-alpha;
00351    if(beta > 0.5){
00352      beta = beta-0.5;
00353      R   = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00354      G   = (cl1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00355      B   = (cl2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00356    }
00357    else{
00358      beta = 0.5-beta;
00359      R   = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00360      G   = (cl1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00361      B   = (cl2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00362    }
00363  }
00364  *r = (unsigned char)R;
00365  *g = (unsigned char)G;
00366  *b = (unsigned char)B;
00367  return;
00368 }
00369 
00370 void MapEnvironmentInDirection(vector dd, double *r, double *g, double *b, imap *Map){
00371  // this is like a reflection map
00372  long j,pixel,k,ibeta,ialpha,kl,kr,kt,kb,w,kmin,kmax;
00373  double alpha,beta,R,G,B;
00374  double cc0,cc1,cc2,cl0,cl1,cl2,cr0,cr1,cr2,ct0,ct1,ct2,cb0,cb1,cb2;
00375  unsigned char *pP,*pR,*pG,*pB;
00376  vector d;
00377  R_m4by1(AntiCamera,dd[0],dd[1],dd[2],&d[0],&d[1],&d[2]);
00378  if(Map->pp < 0)return; // Map inactive
00379  BoxMapIntersect(d,&j,&alpha,&beta); if(j < 0){
00380    *r = 0; *g=255; *b=0;  // for diagnosis
00381    return;
00382  }
00383  w=Map->xmax/6;   // 6 horizontal pictures assumed
00384  alpha = ((double)j+alpha)*(double)w;
00385  beta *= (double)Map->ymax;
00386  ialpha = (long)alpha; alpha -= (double)ialpha;
00387  ibeta=(long)beta; beta -= (double)ibeta;
00388  if(ialpha < 0)ialpha=0;
00389  if(ialpha >= Map->xmax)ialpha=Map->xmax-1;
00390  if(ibeta  < 0)ibeta=0;
00391  if(ibeta  >= Map->ymax)ibeta=Map->ymax-1;
00392  k = ibeta*Map->xmax+ialpha;
00393  kmin = j*w + 1;
00394  kmax = (j+1)*w - 2;
00395  if(ialpha <   kmin)kl=k;       else kl=k-1;
00396  if(ialpha > kmax)  kr=k;       else kr=k+1;
00397  if(ibeta  <   1)kb=k;          else kb=k-Map->xmax;
00398  if(ibeta  > Map->ymax-2)kt=k;  else kt=k+Map->xmax;
00399  pR=Map->p24R; pG=Map->p24G; pB=Map->p24B;
00400  // *r = pR[k];  *g = pG[k];  *b = pB[k]; return; // diagnostic
00401  cc0 = (double)pR[k];  cc1 = (double)pG[k];  cc2 = (double)pB[k];
00402  cl0 = (double)pR[kl]; cl1 = (double)pG[kl]; cl2 = (double)pB[kl];
00403  cr0 = (double)pR[kr]; cr1 = (double)pG[kr]; cr2 = (double)pB[kr];
00404  ct0 = (double)pR[kt]; ct1 = (double)pG[kt]; ct2 = (double)pB[kt];
00405  cb0 = (double)pR[kb]; cb1 = (double)pG[kb]; cb2 = (double)pB[kb];
00406  if(alpha > 0.5){
00407    alpha = alpha-0.5;
00408    if(beta > 0.5){
00409      beta = beta-0.5;
00410      R   = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00411      G   = (cr1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00412      B   = (cr2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00413    }
00414    else{
00415      beta = 0.5-beta;
00416      R   = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00417      G   = (cr1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00418      B   = (cr2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00419    }
00420  }
00421  else{
00422    alpha = 0.5-alpha;
00423    if(beta > 0.5){
00424      beta = beta-0.5;
00425      R   = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00426      G   = (cl1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00427      B   = (cl2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00428    }
00429    else{
00430      beta = 0.5-beta;
00431      R   = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00432      G   = (cl1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00433      B   = (cl2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00434    }
00435  }
00436  *r = R;
00437  *g = G;
00438  *b = B;
00439  return;
00440 }
00441 
00442 /* end the Bump and reflection Mapping functions  */
00443 
00444 /* The functions for Image mapping and fast       */
00445 /* anti-aliasing line texturing                   */
00446 
00447 /* functions for the image mapping   - some old code is still here (#if 0) */
00448 
00449 static void Transform_to_Moziac(double alpha, double beta,
00450                                 double *a, double *b){
00451  long brkindx,brkindy;
00452  *a=FLOOR(alpha);  *b=FLOOR(beta);
00453  brkindx=((long)(*a) & 1L);
00454  brkindy=((long)(*b) & 1L);
00455  *a=(alpha - *a);  *b=(beta - *b);
00456  if(brkindx){
00457    if(brkindy){ *a = 1.0 - *a;  *b = 1.0 - *b; }
00458    else       { *a = 1.0 - *a; }
00459  }
00460  else if(brkindy){ *b = 1.0 - *b; }
00461  return;
00462 }
00463 
00464 /* Only used by Ground and Sky (when ray-tracing) */
00465 long MapFromProjection(imap *Map, short type, short clear,
00466                         vector p , double *red
00467                                  , double *green
00468                                  , double *blue){
00469  /* return colour for map Map at point p */
00470  long  ialpha,ibeta,i,j,k,kl,kr,kt,kb,pixel;
00471  double alpha,beta,a,b,cc0,cc1,cc2,cl0,cl1,cl2,
00472            cr0,cr1,cr2,ct0,ct1,ct2,cb0,cb1,cb2;
00473  unsigned char *pP,*pR,*pG,*pB;
00474  /* checking for valid map must be done elsewhere */
00475  if(Map->pp < 0)return 0;
00476  j=Map->xmax;
00477  if(Map->map == CYLINDER){
00478    hitcylinder(Map->n,Map->x,Map->y,Map->p
00479               ,p,&alpha,&beta);
00480    alpha *= Map->angle;
00481  }
00482  else if(Map->map == MAP_SPHERICAL){
00483    hitsphere(Map->n,Map->x,Map->y,Map->p
00484               ,p,&alpha,&beta);
00485  }
00486  else    /* assume planar map */
00487    hitpoint(Map->n,Map->x,Map->y,Map->p
00488            ,p,&alpha,&beta);
00489  if(type == TILE){
00490    if(Map->moziac)Transform_to_Moziac(alpha,beta,&a,&b);
00491    else{
00492      a=(alpha-floor(alpha));
00493      b=(beta-floor(beta));
00494    }
00495    alpha=a*Map->xmax;
00496    beta=b*Map->ymax;
00497  }
00498  else{
00499    alpha=Map->xmax*alpha;
00500    beta =Map->ymax*beta;
00501  }
00502  ialpha = (long)alpha; alpha -= (double)ialpha;
00503  ibeta  = (long)beta;  beta  -= (double)ibeta;
00504  if(ialpha < 0 || ialpha >= Map->xmax)return 0;
00505  if(ibeta  < 0 || ibeta  >= Map->ymax)return 0;
00506  k =ibeta*j+ialpha;
00507  if(type == TILE){
00508    if(Map->moziac){
00509      if(ialpha <   1)kl=1;                 else kl=k-1;
00510      if(ialpha > j-2)kr=k-1;               else kr=k+1;
00511      if(ibeta  <   1)kb=k+j;               else kb=k-j;
00512      if(ibeta  > Map->ymax-2)kt=k-j; else kt=k+j;
00513    }
00514    else{
00515      if(ialpha <   1)kl=k+j-1;                        else kl=k-1;
00516      if(ialpha > j-2)kr=ibeta*j;                      else kr=k+1;
00517      if(ibeta  <   1)kb=(Map->ymax-1)*j+ialpha; else kb=k-j;
00518      if(ibeta  > Map->ymax-2)kt=ialpha;         else kt=k+j;
00519    }
00520  }
00521  else{
00522    if(ialpha <   1)kl=k; else kl=k-1;
00523    if(ialpha > j-2)kr=k; else kr=k+1;
00524    if(ibeta  <   1)kb=k; else kb=k-j;
00525    if(ibeta  > Map->ymax-2)kt=k; else kt=k+j;
00526  }
00527  pR=Map->p24R; pG=Map->p24G; pB=Map->p24B;
00528  if(clear == TRANSP){
00529    if(pR[k] == Map->kc[0] && pG[k] == Map->kc[1] &&  pB[k] == Map->kc[2])
00530      return 0;
00531  }
00532  cc0 = (double)pR[k];  cc1 = (double)pG[k];  cc2 = (double)pB[k];
00533  cl0 = (double)pR[kl]; cl1 = (double)pG[kl]; cl2 = (double)pB[kl];
00534  cr0 = (double)pR[kr]; cr1 = (double)pG[kr]; cr2 = (double)pB[kr];
00535  ct0 = (double)pR[kt]; ct1 = (double)pG[kt]; ct2 = (double)pB[kt];
00536  cb0 = (double)pR[kb]; cb1 = (double)pG[kb]; cb2 = (double)pB[kb];
00537  if(alpha > 0.5){
00538    alpha = alpha-0.5;
00539    if(beta > 0.5){
00540      beta = beta-0.5;
00541      *red   = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00542      *green = (cr1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00543      *blue  = (cr2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00544    }
00545    else{
00546      beta = 0.5-beta;
00547      *red   = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00548      *green = (cr1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00549      *blue  = (cr2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00550    }
00551  }
00552  else{
00553    alpha = 0.5-alpha;
00554    if(beta > 0.5){
00555      beta = beta-0.5;
00556      *red   = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00557      *green = (cl1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00558      *blue  = (cl2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00559    }
00560    else{
00561      beta = 0.5-beta;
00562      *red   = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00563      *green = (cl1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00564      *blue  = (cl2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00565    }
00566  }
00567  return 1;
00568 }
00569 
00570 long MapByCoordinates(imap *Map,
00571                         long obj, face *f,
00572                         short type, short clear,
00573                         vector p,
00574                         double *red,
00575                         double *green,
00576                         double *blue){
00577  /* return colour for map pointed to by Map at point p on face f of object # obj */
00578  long  ialpha,ibeta,i,j,k,kl,kr,kt,kb,pixel;
00579  double alpha,beta,a,b,cc0,cc1,cc2,cl0,cl1,cl2,
00580            cr0,cr1,cr2,ct0,ct1,ct2,cb0,cb1,cb2,
00581            ve1,ve2,ve3,vp1,vp2,vp3,p1,p2,p3,
00582            detmax,dm,det1,det2,det3,
00583            t1x,t2x,t1y,t2y;
00584  unsigned char *pP,*pR,*pG,*pB;
00585  vertex   *V,*v0,*v1,*v2;
00586  /* checking for valid map must be done elsewhere */
00587  if(Map->pp < 0)return 0;
00588  j=Map->xmax;
00589  if((V=Object[obj].Vbase) == NULL)return 0;
00590  v0=(V+(f->V[0]));
00591  v1=(V+(f->V[1]));
00592  v2=(V+(f->V[2]));
00593  ve1=v1->p[0] - v0->p[0]; ve2=v1->p[1] - v0->p[1]; ve3=v1->p[2] - v0->p[2];
00594  vp1=v2->p[0] - v0->p[0]; vp2=v2->p[1] - v0->p[1]; vp3=v2->p[2] - v0->p[2];
00595  p1=p[0]-v0->p[0];
00596  p2=p[1]-v0->p[1];
00597  p3=p[2]-v0->p[2];
00598  det1=ve1*vp2-vp1*ve2;
00599  det2=ve1*vp3-vp1*ve3;
00600  det3=ve2*vp3-vp2*ve3;
00601  k=0; detmax=1.e-3;  /* same as TOL in mirrors */
00602  if((dm=fabs(det1)) > detmax){k=1; detmax=dm;}
00603  if((dm=fabs(det2)) > detmax){k=2; detmax=dm;}
00604  if((dm=fabs(det3)) > detmax){k=3; detmax=dm;}
00605  if(k == 0)return 0;
00606  else if(k == 1){
00607    a=( vp2*p1-vp1*p2)/det1;
00608    b=(-ve2*p1+ve1*p2)/det1;
00609  }
00610  else if(k == 2){
00611    a=( vp3*p1-vp1*p3)/det2;
00612    b=(-ve3*p1+ve1*p3)/det2;
00613  }
00614  else if(k == 3){
00615    a=( vp3*p2-vp2*p3)/det3;
00616    b=(-ve3*p2+ve2*p3)/det3;
00617  }
00618  // Calculate UV map address of pixel
00619  t1x=f->uu[1] - f->uu[0]; t2x=f->uu[2] - f->uu[0];
00620  t1y=f->vv[1] - f->vv[0]; t2y=f->vv[2] - f->vv[0];
00621  alpha = f->uu[0] + a*t1x + b*t2x;
00622  beta  = f->vv[0] + a*t1y + b*t2y;
00623  if(type == TILE){
00624    if(Map->moziac)Transform_to_Moziac(alpha,beta,&a,&b);
00625    else{
00626      a=(alpha-floor(alpha));
00627      b=(beta-floor(beta));
00628    }
00629    alpha=a*Map->xmax;
00630    beta=b*Map->ymax;
00631  }
00632  else{
00633    alpha=Map->xmax*alpha;
00634    beta =Map->ymax*beta;
00635  }
00636  ialpha = (long)alpha; alpha -= (double)ialpha;
00637  ibeta  = (long)beta;  beta  -= (double)ibeta;
00638  if(ialpha < 0 || ialpha >= Map->xmax)return 0;
00639  if(ibeta  < 0 || ibeta  >= Map->ymax)return 0;
00640  k =ibeta*j+ialpha;
00641 
00642  if(type == TILE){
00643    if(Map->moziac){
00644      if(ialpha <   1)kl=1;                 else kl=k-1;
00645      if(ialpha > j-2)kr=k-1;               else kr=k+1;
00646      if(ibeta  <   1)kb=k+j;               else kb=k-j;
00647      if(ibeta  > Map->ymax-2)kt=k-j; else kt=k+j;
00648    }
00649    else{
00650      if(ialpha <   1)kl=k+j-1;                        else kl=k-1;
00651      if(ialpha > j-2)kr=ibeta*j;                      else kr=k+1;
00652      if(ibeta  <   1)kb=(Map->ymax-1)*j+ialpha; else kb=k-j;
00653      if(ibeta  > Map->ymax-2)kt=ialpha;         else kt=k+j;
00654    }
00655  }
00656  else{
00657    if(ialpha <   1)kl=k; else kl=k-1;
00658    if(ialpha > j-2)kr=k; else kr=k+1;
00659    if(ibeta  <   1)kb=k; else kb=k-j;
00660    if(ibeta  > Map->ymax-2)kt=k; else kt=k+j;
00661  }
00662 
00663  pR=Map->p24R; pG=Map->p24G; pB=Map->p24B;
00664  if(clear == TRANSP){
00665    if(pR[k] == Map->kc[0] && pG[k] == Map->kc[1] &&  pB[k] == Map->kc[2])
00666      return 0;
00667  }
00668  cc0 = (double)pR[k];  cc1 = (double)pG[k];  cc2 = (double)pB[k];
00669  cl0 = (double)pR[kl]; cl1 = (double)pG[kl]; cl2 = (double)pB[kl];
00670  cr0 = (double)pR[kr]; cr1 = (double)pG[kr]; cr2 = (double)pB[kr];
00671  ct0 = (double)pR[kt]; ct1 = (double)pG[kt]; ct2 = (double)pB[kt];
00672  cb0 = (double)pR[kb]; cb1 = (double)pG[kb]; cb2 = (double)pB[kb];
00673  if(alpha > 0.5){
00674    alpha = alpha-0.5;
00675    if(beta > 0.5){
00676      beta = beta-0.5;
00677      *red   = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00678      *green = (cr1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00679      *blue  = (cr2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00680    }
00681    else{
00682      beta = 0.5-beta;
00683      *red   = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00684      *green = (cr1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00685      *blue  = (cr2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00686    }
00687  }
00688  else{
00689    alpha = 0.5-alpha;
00690    if(beta > 0.5){
00691      beta = beta-0.5;
00692      *red   = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00693      *green = (cl1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00694      *blue  = (cl2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00695    }
00696    else{
00697      beta = 0.5-beta;
00698      *red   = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00699      *green = (cl1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00700      *blue  = (cl2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00701    }
00702  }
00703  return 1;
00704 }
00705 
00706 long MapTransByCoordinates(imap *Map, short type, long obj, face *f,
00707                       vector p , double *trans){
00708  long  ialpha,ibeta,i,j,k,kl,kr,kt,kb,pixel;
00709  double red,green,blue;
00710  double alpha,beta,a,b,cc0,cc1,cc2,cl0,cl1,cl2,
00711            cr0,cr1,cr2,ct0,ct1,ct2,cb0,cb1,cb2,
00712            ve1,ve2,ve3,vp1,vp2,vp3,p1,p2,p3,
00713            detmax,dm,det1,det2,det3,
00714            t1x,t2x,t1y,t2y;
00715  unsigned char *pP,*pR,*pG,*pB;
00716  vertex   *V,*v0,*v1,*v2;
00717  /* checking for valid map must be done elsewhere */
00718  j=Map->xmaxtran;
00719  if((V=Object[obj].Vbase) == NULL)return 0;
00720  v0=(V+(f->V[0]));
00721  v1=(V+(f->V[1]));
00722  v2=(V+(f->V[2]));
00723  ve1=v1->p[0] - v0->p[0]; ve2=v1->p[1] - v0->p[1]; ve3=v1->p[2] - v0->p[2];
00724  vp1=v2->p[0] - v0->p[0]; vp2=v2->p[1] - v0->p[1]; vp3=v2->p[2] - v0->p[2];
00725  p1=p[0]-v0->p[0];
00726  p2=p[1]-v0->p[1];
00727  p3=p[2]-v0->p[2];
00728  det1=ve1*vp2-vp1*ve2;
00729  det2=ve1*vp3-vp1*ve3;
00730  det3=ve2*vp3-vp2*ve3;
00731  k=0; detmax=1.e-3;  /* same as TOL in mirrors */
00732  if((dm=fabs(det1)) > detmax){k=1; detmax=dm;}
00733  if((dm=fabs(det2)) > detmax){k=2; detmax=dm;}
00734  if((dm=fabs(det3)) > detmax){k=3; detmax=dm;}
00735  if(k == 0)return 0;
00736  else if(k == 1){
00737    a=( vp2*p1-vp1*p2)/det1;
00738    b=(-ve2*p1+ve1*p2)/det1;
00739  }
00740  else if(k == 2){
00741    a=( vp3*p1-vp1*p3)/det2;
00742    b=(-ve3*p1+ve1*p3)/det2;
00743  }
00744  else if(k == 3){
00745    a=( vp3*p2-vp2*p3)/det3;
00746    b=(-ve3*p2+ve2*p3)/det3;
00747  }
00748  // Calculate UV map address of pixel
00749  t1x=f->uu[1] - f->uu[0]; t2x=f->uu[2] - f->uu[0];
00750  t1y=f->vv[1] - f->vv[0]; t2y=f->vv[2] - f->vv[0];
00751  alpha = f->uu[0] + a*t1x + b*t2x;
00752  beta  = f->vv[0] + a*t1y + b*t2y;
00753 
00754  if(type == TILE){
00755    if(Map->moziac)Transform_to_Moziac(alpha,beta,&a,&b);
00756    else{
00757      a=(alpha-floor(alpha));
00758      b=(beta-floor(beta));
00759    }
00760    alpha=a*Map->xmaxtran;
00761    beta=b*Map->ymaxtran;
00762  }
00763  else{
00764    alpha=Map->xmaxtran*alpha;
00765    beta =Map->ymaxtran*beta;
00766  }
00767  ialpha = (long)alpha; alpha -= (double)ialpha;
00768  ibeta  = (long)beta;  beta  -= (double)ibeta;
00769 
00770  if(ialpha < 0 || ialpha >= Map->xmaxtran)return 0;
00771  if(ibeta  < 0 || ibeta  >= Map->ymaxtran)return 0;
00772  k =ibeta*j+ialpha;
00773  if(type == TILE){
00774    if(Map->moziac){
00775      if(ialpha <   1)kl=1;                 else kl=k-1;
00776      if(ialpha > j-2)kr=k-1;               else kr=k+1;
00777      if(ibeta  <   1)kb=k+j;               else kb=k-j;
00778      if(ibeta  > Map->ymaxtran-2)kt=k-j; else kt=k+j;
00779    }
00780    else{
00781      if(ialpha <   1)kl=k+j-1;                        else kl=k-1;
00782      if(ialpha > j-2)kr=ibeta*j;                      else kr=k+1;
00783      if(ibeta  <   1)kb=(Map->ymaxtran-1)*j+ialpha; else kb=k-j;
00784      if(ibeta  > Map->ymaxtran-2)kt=ialpha;         else kt=k+j;
00785    }
00786  }
00787  else{
00788    if(ialpha <   1)kl=k; else kl=k-1;
00789    if(ialpha > j-2)kr=k; else kr=k+1;
00790    if(ibeta  <   1)kb=k; else kb=k-j;
00791    if(ibeta  > Map->ymaxtran-2)kt=k; else kt=k+j;
00792  }
00793  pR=Map->p24Rtran; pG=Map->p24Gtran; pB=Map->p24Btran;
00794  cc0 = (double)pR[k];  cc1 = (double)pG[k];  cc2 = (double)pB[k];
00795  cl0 = (double)pR[kl]; cl1 = (double)pG[kl]; cl2 = (double)pB[kl];
00796  cr0 = (double)pR[kr]; cr1 = (double)pG[kr]; cr2 = (double)pB[kr];
00797  ct0 = (double)pR[kt]; ct1 = (double)pG[kt]; ct2 = (double)pB[kt];
00798  cb0 = (double)pR[kb]; cb1 = (double)pG[kb]; cb2 = (double)pB[kb];
00799  if(alpha > 0.5){
00800    alpha = alpha-0.5;
00801    if(beta > 0.5){
00802      beta = beta-0.5;
00803      red   = (cr0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00804      green = (cr1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00805      blue  = (cr2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00806    }
00807    else{
00808      beta = 0.5-beta;
00809      red   = (cr0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00810      green = (cr1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00811      blue  = (cr2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00812    }
00813  }
00814  else{
00815    alpha = 0.5-alpha;
00816    if(beta > 0.5){
00817      beta = beta-0.5;
00818      red   = (cl0-cc0)*alpha+(ct0-cc0)*beta+cc0;
00819      green = (cl1-cc1)*alpha+(ct1-cc1)*beta+cc1;
00820      blue  = (cl2-cc2)*alpha+(ct2-cc2)*beta+cc2;
00821    }
00822    else{
00823      beta = 0.5-beta;
00824      red   = (cl0-cc0)*alpha+(cb0-cc0)*beta+cc0;
00825      green = (cl1-cc1)*alpha+(cb1-cc1)*beta+cc1;
00826      blue  = (cl2-cc2)*alpha+(cb2-cc2)*beta+cc2;
00827    }
00828  }
00829  *trans = (1.0- 1.3071895e-3*(red+green+blue)); /* scaled 0-1 Back is fully opaque white is transp */
00830  return 1;
00831 }
00832 
00833 long MapTextureByCoordinates(long obj,face *f, vector p,
00834      double *alpha, double *beta, double *gamma){
00835  /* return 2 D coords on face f of object # obj */
00836  long k;
00837  double a,b,
00838         ve1,ve2,ve3,vp1,vp2,vp3,p1,p2,p3,
00839         detmax,dm,det1,det2,det3,
00840         t1x,t2x,t1y,t2y,t1w,t2w;
00841  unsigned char *pP,*pR,*pG,*pB;
00842  vertex   *V,*v0,*v1,*v2;
00843  /* checking for valid map must be done elsewhere */
00844  if((V=Object[obj].Vbase) == NULL)return 0;
00845  v0=(V+(f->V[0])); 
00846  v1=(V+(f->V[1])); 
00847  v2=(V+(f->V[2])); 
00848  ve1=v1->p[0] - v0->p[0]; ve2=v1->p[1] - v0->p[1]; ve3=v1->p[2] - v0->p[2];
00849  vp1=v2->p[0] - v0->p[0]; vp2=v2->p[1] - v0->p[1]; vp3=v2->p[2] - v0->p[2];
00850  p1=p[0]-v0->p[0];
00851  p2=p[1]-v0->p[1];
00852  p3=p[2]-v0->p[2];
00853  det1=ve1*vp2-vp1*ve2;
00854  det2=ve1*vp3-vp1*ve3;
00855  det3=ve2*vp3-vp2*ve3;
00856  k=0; detmax=1.e-3;  /* same as TOL in mirrors */
00857  if((dm=fabs(det1)) > detmax){k=1; detmax=dm;}
00858  if((dm=fabs(det2)) > detmax){k=2; detmax=dm;}
00859  if((dm=fabs(det3)) > detmax){k=3; detmax=dm;}
00860  if(k == 0)return 0;
00861  else if(k == 1){
00862    a=( vp2*p1-vp1*p2)/det1;
00863    b=(-ve2*p1+ve1*p2)/det1;
00864  }
00865  else if(k == 2){
00866    a=( vp3*p1-vp1*p3)/det2;
00867    b=(-ve3*p1+ve1*p3)/det2;
00868  }
00869  else if(k == 3){
00870    a=( vp3*p2-vp2*p3)/det3;
00871    b=(-ve3*p2+ve2*p3)/det3;
00872  }
00873  // Calculate UV map address of pixel
00874  t1x=f->uu[1] - f->uu[0]; t2x=f->uu[2] - f->uu[0];
00875  t1y=f->vv[1] - f->vv[0]; t2y=f->vv[2] - f->vv[0];
00876  t1w=f->ww[1] - f->ww[0]; t2w=f->ww[2] - f->ww[0];
00877  *alpha = f->uu[0] + a*t1x + b*t2x;
00878  *beta  = f->vv[0] + a*t1y + b*t2y;
00879  *gamma = f->ww[0] + a*t1w + b*t2w;
00880 // *gamma = 0.5;
00881  return 1;
00882 }
00883 
00885 
00892 long ShadedScanline(
00893                  long scanline ,double d2,
00894                  UCHAR *Red, UCHAR *Green, UCHAR *Blue,
00895                  double *Zground, long Wsky, double Rsky,
00896                  long *Zglass[], long *ZglassO[], double *Zglassd[],
00897                  long *Zbuffer, long *Zobject,
00898                  double *Zdepth, double *Zposn){
00899  face    *f;
00900  vertex  *v;
00901  imap    *Map;
00902  matl    *Mat;
00903  BOOL    bSmooth;
00904  long i,j,k,f1,obj;
00905  double det,alpha,beta;
00906  vector n,nn,dn,v0,v1,v2;
00907  UCHAR *ZobjChar;
00908  if(VGA_screen == NULL)ZobjChar=DummyShadow;
00909  else ZobjChar = &VGA_screen[scanline*XMAX]; /* shadow for this line */
00910  i=XMIN;
00911 LOOP:
00912  f1=Zbuffer[i];
00913  if(f1 >= 0){
00914    obj=Zobject[i];
00915    v=Object[obj].Vbase;
00916    f=Object[obj].Fbase + f1;
00917    if(f->ffmap >= 0){                 /* mapped get map id */
00918      if((long)f->ffmap >= Object[obj].NoMaps)Map=NULL;
00919      else Map=(Object[obj].Mbase+(long)f->ffmap);
00920    }
00921    else Map=NULL;
00922    // Get the material ID or NULL
00923    if(f->ffmat < 0 || f->ffmat >= Object[obj].NoMats)Mat=NULL;
00924    else Mat=(Object[obj].Tbase+(long)f->ffmat);
00925  /* calculate the  alpha and beta for starting value */
00926    if(Mat != NULL)bSmooth=Mat->bSmooth;
00927    else           bSmooth=f->bSmooth;
00928    if(!bSmooth){   /* no smoothing required n is face normal */
00929      VECCOPY(f->n,n)
00930    }
00931    else{ /* interpolate normal over the face */
00932      det=(
00933          (v[f->V[2]].y - v[f->V[0]].y) * (v[f->V[1]].x - v[f->V[0]].x)
00934         -(v[f->V[2]].x - v[f->V[0]].x) * (v[f->V[1]].y - v[f->V[0]].y)
00935           );
00936      if(det == 0){
00937        VECCOPY(f->n,n)
00938      }
00939      else{
00940        VECCOPY(f->pn[0],v0)
00941        VECCOPY(f->pn[1],v1)
00942        VECCOPY(f->pn[2],v2)
00943        det=1.0/det;
00944        alpha= (double)(
00945         (v[f->V[2]].y - v[f->V[0]].y) * (Zposn[i] - v[f->V[0]].x)
00946        -(v[f->V[2]].x - v[f->V[0]].x) * ((double)scanline - v[f->V[0]].y)
00947                       )*det;
00948        beta= (double)(
00949         ((double)scanline - v[f->V[0]].y) * (v[f->V[1]].x - v[f->V[0]].x)
00950        -(Zposn[i] - v[f->V[0]].x) * (v[f->V[1]].y - v[f->V[0]].y)
00951                     )*det;
00952        n[0]=v0[0] + alpha*(v1[0] - v0[0])
00953                   +  beta*(v2[0] - v0[0]);
00954        n[1]=v0[1] + alpha*(v1[1] - v0[1])
00955                   +  beta*(v2[1] - v0[1]);
00956        n[2]=v0[2] + alpha*(v1[2] - v0[2])
00957                   +  beta*(v2[2] - v0[2]);
00958        normalize(n);
00959      }
00960    }
00961    GetRowPixelValue(scanline,i,Map,Mat,f,obj,n,Red,Green,Blue,
00962                       Zdepth,ZobjChar); /* pixel 1*/
00963    if(Zglass[0][i] > -1)AttenuateGlass(scanline,i,Red,Green,Blue,
00964                                        Zglass,ZglassO,Zglassd,Zposn);
00965    j=i+1;  /* interpolate normal over pixels showing same face */
00966    if(j < XMAX){
00967     while((Zbuffer[j] == f1) && (Zobject[j] == Zobject[i]))
00968                                 {j++; if(j == XMAX)break; }   /* how many */
00969     if(j > i+1){ /* more than one pixel */
00970       if(j > i+2){ /* more than 2 pixels */
00971         if((det==0) || !(bSmooth)){
00972           dn[0]=0; dn[1]=0; dn[2]=0;
00973         }
00974         else{
00975           dn[0]=( (v[f->V[1]].y - v[f->V[2]].y) * v0[0]
00976                 + (v[f->V[2]].y - v[f->V[0]].y) * v1[0]
00977                 + (v[f->V[0]].y - v[f->V[1]].y) * v2[0]
00978                 )*det;
00979           dn[1]=( (v[f->V[1]].y - v[f->V[2]].y) * v0[1]
00980                 + (v[f->V[2]].y - v[f->V[0]].y) * v1[1]
00981                 + (v[f->V[0]].y - v[f->V[1]].y) * v2[1]
00982                 )*det;
00983           dn[2]=( (v[f->V[1]].y - v[f->V[2]].y) * v0[2]
00984                 + (v[f->V[2]].y - v[f->V[0]].y) * v1[2]
00985                 + (v[f->V[0]].y - v[f->V[1]].y) * v2[2]
00986                 )*det;
00987         }
00988         for(k=i+1; k<j-1; k++){
00989           VECSUM(n,dn,n)
00990           VECCOPY(n,nn)
00991           normalize(nn);
00992           GetRowPixelValue(scanline,k,Map,Mat,f,obj,nn,Red,Green,Blue,
00993                              Zdepth,ZobjChar);
00994           if(Zglass[0][k] > -1)AttenuateGlass(scanline,k,Red,Green,Blue,
00995                                               Zglass,ZglassO,Zglassd,Zposn);
00996         }
00997       }
00998       /* do last pixel this must be separate - may not be on integer boundary */
00999       if((det==0) || !(bSmooth))VECCOPY(f->n,n)
01000       else{
01001         alpha = (double)(
01002          (v[f->V[2]].y - v[f->V[0]].y) * (Zposn[j-1] - v[f->V[0]].x)
01003         -(v[f->V[2]].x - v[f->V[0]].x) * ((double)scanline - v[f->V[0]].y)
01004                         )*det;
01005         beta = (double)(
01006          ((double)scanline - v[f->V[0]].y) * (v[f->V[1]].x - v[f->V[0]].x)
01007         -(Zposn[j-1] - v[f->V[0]].x) * (v[f->V[1]].y - v[f->V[0]].y)
01008                        )*det;
01009         n[0]=v0[0] + alpha*(v1[0] - v0[0])
01010                    +  beta*(v2[0] - v0[0]);
01011         n[1]=v0[1] + alpha*(v1[1] - v0[1])
01012                    +  beta*(v2[1] - v0[1]);
01013         n[2]=v0[2] + alpha*(v1[2] - v0[2])
01014                    +  beta*(v2[2] - v0[2]);
01015         normalize(n);
01016       }
01017       GetRowPixelValue(scanline,j-1,Map,Mat,f,obj,n,Red,Green,Blue,
01018                          Zdepth,ZobjChar);
01019       if(Zglass[0][j-1] > -1)AttenuateGlass(scanline,j-1,Red,Green,Blue,
01020                                             Zglass,ZglassO,Zglassd,Zposn);
01021     }
01022    }
01023    i=j;
01024  }
01025  else{  /* if no object get back plane values */
01026   PutBackPlanes(i,scanline,d2,Red,Green,Blue,
01027                 Zground,Zobject,Zdepth,
01028                 ZobjChar,Wsky,Rsky);
01029   if(Zglass[0][i] > -1)AttenuateGlass(scanline,i,Red,Green,Blue,
01030                                       Zglass,ZglassO,Zglassd,Zposn);
01031   i++;
01032  }
01033  if(i < XMAX)goto LOOP;
01034  return 0;
01035 }
01036 
01044 long FastAntiAliasShadedScanline(
01045                       long scanline ,long aaline, double d2,
01046                       UCHAR *Red, UCHAR *Green, UCHAR *Blue,
01047                       double *Zground, long Wsky, double Rsky,
01048                       long *Xbuffer, long *Xobject,
01049                       long *Zglass[], long *ZglassO[], double *Zglassd[],
01050                       long *Zbuffer, long *Zobject,
01051                       double *Zdepth, double *Zposn){
01052  face   *f;             /* super sample if faces are different  */
01053  vertex *v;
01054  imap   *Map;
01055  matl   *Mat;
01056  BOOL   bSmooth;
01057  long i,j,k,l,f1,obj,AlreadyCalculated;
01058  double det,alpha,beta;
01059  vector n,v0,v1,v2;
01060  UCHAR  *ZobjChar;
01061  if(VGA_screen == NULL)ZobjChar=DummyShadow;
01062  else ZobjChar = &VGA_screen[scanline*XMAX];
01063  i=0; l=i-1;
01064  for(k=0;k<XMAX;k+=aaXstep){
01065    for(j=0;j<aaXstep;j++){
01066      f1=Zbuffer[i]; obj=Zobject[i];
01067      if(f1 == Xbuffer[i] && obj == Xobject[i])AlreadyCalculated=1;
01068      else if(j == 0)AlreadyCalculated=0;
01069      else if(f1 == Zbuffer[i-1] && obj == Zobject[i-1]){
01070        AlreadyCalculated=1;
01071        Red[i] = Red[l]; Green[i]=Green[l]; Blue[i]=Blue[l];
01072      }
01073      else AlreadyCalculated=0;
01074      if(!AlreadyCalculated){
01075        if(f1 >= 0){
01076          v=Object[obj].Vbase;
01077          f=Object[obj].Fbase + f1;
01078          if(f->ffmap >= 0){ /* mapped */
01079            if((long)f->ffmap >= Object[obj].NoMaps)Map=NULL;
01080            else Map=(Object[obj].Mbase+(long)f->ffmap);
01081          }
01082          else Map=NULL;
01083          if(f->ffmat < 0 || f->ffmat >= Object[obj].NoMats)Mat=NULL;
01084          else Mat=(Object[obj].Tbase+(long)f->ffmat);
01085          if(Mat != NULL)bSmooth=Mat->bSmooth;
01086          else           bSmooth=f->bSmooth;
01087          if(!bSmooth)VECCOPY(f->n,n)
01088          else{
01089            det=(
01090              (v[f->V[2]].y - v[f->V[0]].y) * (v[f->V[1]].x - v[f->V[0]].x)
01091               -(v[f->V[2]].x - v[f->V[0]].x) * (v[f->V[1]].y - v[f->V[0]].y)
01092                );
01093            if(det == 0){ VECCOPY(f->n,n) }
01094            else{
01095              VECCOPY(f->pn[0],v0)
01096              VECCOPY(f->pn[1],v1)
01097              VECCOPY(f->pn[2],v2)
01098              det=1.0/det;
01099              alpha= (double)(
01100                      (v[f->V[2]].y - v[f->V[0]].y) *
01101                          (Zposn[i] - v[f->V[0]].x)
01102                     -(v[f->V[2]].x - v[f->V[0]].x) *
01103                  ((double)scanline - v[f->V[0]].y)
01104                             )*det;
01105              beta= (double)(
01106                   ((double)scanline - v[f->V[0]].y) *
01107                       (v[f->V[1]].x - v[f->V[0]].x)
01108                          -(Zposn[i] - v[f->V[0]].x) *
01109                       (v[f->V[1]].y - v[f->V[0]].y)
01110                            )*det;
01111              n[0]=v0[0] + alpha*(v1[0] - v0[0]) +  beta*(v2[0] - v0[0]);
01112              n[1]=v0[1] + alpha*(v1[1] - v0[1]) +  beta*(v2[1] - v0[1]);
01113              n[2]=v0[2] + alpha*(v1[2] - v0[2]) +  beta*(v2[2] - v0[2]);
01114              normalize(n);
01115            }
01116          }
01117          GetRowPixelValue(scanline,i,Map,Mat,f,obj,n,Red,Green,Blue,
01118                             Zdepth,ZobjChar);
01119          if(Zglass[0][i] > -1)AttenuateGlass(scanline,i,Red,Green,Blue,
01120                                              Zglass,ZglassO,Zglassd,Zposn);
01121        }
01122        else{
01123          PutBackPlanes(i,scanline,d2,Red,Green,Blue,
01124                        Zground,Zobject,Zdepth,ZobjChar,Wsky,Rsky);
01125          if(Zglass[0][i] > -1)AttenuateGlass(scanline,i,Red,Green,Blue,
01126                                              Zglass,ZglassO,Zglassd,Zposn);
01127        }
01128      }
01129      i++; l++;
01130    }
01131  }
01132  return 0;
01133 }
01134 
01135 /* end of Image mapping and fast AA line texturing     */
01136 
01137 /* code for rendering specific elements such as ground */
01138 
01139 void GetSkyLocation(void){
01140  double b;
01141  long i;
01142  for(i=XMIN;i<XMAX;i++){
01143    if(Sky.type == SKYMAPPED){
01144      b= (CamPhi+atan2(D1[i],1.000))/PI*180.0 * 4.0 ; /* 4 maps full rotation */
01145      while(b <  -180.0)b = b + 360.0;
01146      while(b >=  180.0)b = b - 360.0;
01147      ZskyBuffer[XMAX-1-i]=(short)((b+180.0)*skyXscale);
01148    }
01149    else{
01150      ZskyBuffer[XMAX-1-i]=0;
01151    }
01152  }
01153 }
01154 
01155 long PutBackIntersection(long scanline, double d2,
01156                          UCHAR *Alfa, double *Zground,
01157                          long *Zglass[], long *ZglassO[], double *Zglassd[],
01158                          long *Zbuffer, long *Zobject,
01159                          double *Zdepth, double *Zposn, double *Rsky){
01160  long i,j,Wsky;  /* background  setup */
01161  double b,c,mu;
01162  if(Sky.type == SKYGRADED){
01163    //*Rsky=fabs((CamAlpha+atan2(d2,1.000))/PI*2.0);  /* 0 Hor  1 +/- Zenith */
01164    *Rsky=fabs((double)(Ycentre-scanline))/(double)Ycentre;     
01165  }
01166  else if(Sky.type == SKYMAPPED){ /* CamAlpha is 0 on horizontal +90 look up*/
01167   Wsky=0; /* Wsky scanline V pos. in env.bru 0 is brush top*/
01168   b=90.0 - (CamAlpha+atan2(d2,1.000))/PI*180.0 * 2;
01169   while(b <   0.0)b += 90.0;
01170   while(b > 180.0)b -= 90.0;
01171   if(b > 0){          /* b is angle in range 0-180 for view to scanline */
01172     if(b > 90)Wsky=(short)((180-b)*skyYscale);      /* 0 is up 180 down */
01173     else      Wsky=(short)(b*skyYscale);            /* b > 90 picture is */
01174     Wsky = min(Wsky,skyBmax);                       /* inverted */
01175   }
01176  }
01177  for(i=XMIN;i<XMAX;i++){
01178    Zbuffer[i] = -1;
01179    Zdepth [i] = FARAWAY;
01180    Zposn  [i] = (double)i+0.5;
01181    for(j=0;j<NGLASS;j++){
01182      Zglassd[j][i] = FARAWAY;
01183      ZglassO[j][i] = -1;
01184      Zglass [j][i] = -1;  /* this will be non zero if a glass face is on top */
01185    }
01186    Zobject[i] = -2;
01187    Alfa   [i] =  0;
01188    if(R_Nground > 0){
01189      b=Ground.n[0]*D1[i]+Ground.n[1]+Ground.n[2]*d2; // Z buffer
01190 //{
01191 // vector dr;     //  if Z buffer is to contain actual depths
01192 // dr[0]=D1[i]; dr[1]=1.0; dr[2]=d2;
01193 // b=DOT(Ground.n,dr);
01194 //}
01195      if(fabs(b) > 1.e-4){
01196        c=dot(Ground.n,Ground.p);
01197        mu=c/b;
01198        if(mu > 0.0){
01199          Zdepth[i] = mu;
01200          Zground[i]= mu;
01201          Zobject[i]= -1;
01202        }
01203      }
01204    }
01205  }
01206  return Wsky;
01207 }
01208 
01209 void GetGroundLight(vector p0, double *R, double *G ,double *B){
01210 /* the R G B values may exceed 255.0 they must be clipped elsewhere */
01211  long j,brkindx;
01212  double c,cc,alpha,beta,Iab,IsR,IsG,IsB,Bump_Scale,IdR,IdG,IdB,xRGB[3]={0.0,0.0,0.0};
01213  vector p1,p2,ripple,gn,gnn,bv;
01214  double red,green,blue,map;
01215  IdR=IdG=IdB=0.0;
01216     if(Ground.texture > 0 && (Ground.texture < 4 || Ground.texture > 9)){
01217       switch(Ground.texture){
01218       case 1:  /* single wave  */
01219          calcripple(p0,Ground.p,wave_phase,Ground.lengthy,1.0,
01220          Ground.height,ripple); /* typical height 2.0 */
01221          Bump_Scale = - dot(p0,Ground.n)/R_length(p0);
01222          vecscale(Bump_Scale,ripple,ripple);
01223          vecsum(ripple,Ground.n,gn);
01224          normalize(gn);
01225          IsR=IsG=IsB=0.0;
01226          break;
01227       case 2: /* ripples using wave 2 */
01228 // NEED FIXED because of hitpoint
01229 //        waves2(p0,Ground.n,Ground.dx,Ground.dyy,Ground.p,gn,
01230 //        Rip_Freq,wave_phase,Ground.height);  /* 0.2 is good for height */
01231         IsR=IsG=IsB=0.0;
01232         break;
01233       case 3: /* ocean multiple waves texture */
01234         Ocean(p0,Ground.n,gn);
01235         IsR=IsG=IsB=0.0;
01236         break;
01237       case 10: /* rough surface  ie bumpy */
01238         hitpoint(Ground.n,Ground.dx,Ground.dy,Ground.p,p0,&alpha,&beta);
01239         Dnoise2(gn,alpha*10.0,beta*10.0,0.0);                  /* scale bumps into */
01240         Bump_Scale = dot(p0,Ground.n)/R_length(p0);     /* distance*/
01241         Bump_Scale = min(0.5, Bump_Scale*2.0)*Ground.height*0.5;
01242         vecscale(Bump_Scale,gn,gn);
01243         vecsum(Ground.n,gn,gn);
01244         normalize(gn);
01245         break;
01246       case 16: /* external textures  this is not used */ {
01247         }
01248         break;
01249       default:
01250         veccopy(Ground.n,gn);
01251         break;
01252       }
01253     }
01254     else {
01255       veccopy(Ground.n,gn);
01256     }
01257 
01258     for(j=0;j<Nlights;j++)if(Lights[j].type != SHADOWS &&
01259                              Lights[j].type != DUMMYL){
01260       vecsub(Lights[j].p,p0,p1);
01261       cc=R_length(p1);
01262       vecscale(1.0/cc,p1,p2);
01263       Iab = Ground.ambient_light+(1.0-Ground.ambient_light)*fabs(DOT(p2,gn));
01264       if(Lights[j].dc){
01265         cc = DepthCueLight(j,cc);
01266         Iab *= cc;
01267       }
01268       if(Lights[j].type == SPOTLIGHT){
01269         if((alpha=DOT(p2,Lights[j].d)) < Lights[j].dot2)
01270           Iab=Ground.ambient_light;
01271         else if(alpha < Lights[j].dot1){
01272           Iab=Ground.ambient_light+(Iab-Ground.ambient_light)*
01273                (alpha-Lights[j].dot2)*Lights[j].falloff;
01274         }
01275         if(Iab > Ground.ambient_light && Lights[j].shadow_buffer != NULL)
01276             PointInShadow(p0,j,&Iab); /* for spotlights */
01277       }
01278       IdR += Iab*Lights[j].Ire;
01279       IdG += Iab*Lights[j].Igr;
01280       IdB += Iab*Lights[j].Ibl;
01281       if(Ground.shiny){
01282         vecsub(p1,p0,bv);
01283         normalize(bv);
01284         c=fabs(dot(bv,gn));
01285         if(c > 0.0){
01286           Iab = spec_gro[min(max_spec,(long)(c*max_spec))];
01287           if(Lights[j].dc)Iab *= cc;
01288           IsR += Iab*Lights[j].Ire;
01289           IsG += Iab*Lights[j].Igr;
01290           IsB += Iab*Lights[j].Ibl;
01291         }
01292       }
01293     }
01294     switch(Ground.texture){
01295     case 1:  /* waves have specular highlights */
01296     case 2:
01297     case 3:
01298       *R = min( ((double)Ground.color[0]*IdR + IsR*255), 255);
01299       *G = min( ((double)Ground.color[1]*IdG + IsG*255), 255);
01300       *B = min( ((double)Ground.color[2]*IdB + IsB*255), 255);
01301       break;
01302     case 4:  /* checkered ground */
01303       hitpoint2(Ground.n,Ground.dx,Ground.dy,Ground.p,p0,&alpha,&beta);
01304       brkindx = (long)FLOOR(alpha) + (long)FLOOR(beta);
01305       if(brkindx & 1){
01306         *R = (double)Ground.acolor[0]*IdR;
01307         *G = (double)Ground.acolor[1]*IdG;
01308         *B = (double)Ground.acolor[2]*IdB;
01309       }
01310       else{
01311         *R = (double)Ground.color[0]*IdR;
01312         *G = (double)Ground.color[1]*IdG;
01313         *B = (double)Ground.color[2]*IdB;
01314       }
01315       break;
01316     case 5: /* grid texture */
01317       hitpoint(Ground.n,Ground.dx,Ground.dy,Ground.p,p0,&alpha,&beta);
01318       alpha=(alpha-floor(alpha));
01319       beta=(beta-floor(beta));
01320       if(beta < 0.1 || alpha < 0.1){
01321         *R = (double)Ground.acolor[0]*IdR;
01322         *G = (double)Ground.acolor[1]*IdG;
01323         *B = (double)Ground.acolor[2]*IdB;
01324       }
01325       else{
01326         *R = (double)Ground.color[0]*IdR;
01327         *G = (double)Ground.color[1]*IdG;
01328         *B = (double)Ground.color[2]*IdB;
01329       }
01330       break;
01331     case 6: /* stripes texure */
01332       hitpoint(Ground.n,Ground.dx,Ground.dy,Ground.p,p0,&alpha,&beta);
01333       alpha=(alpha-floor(alpha));
01334       beta=(beta-floor(beta));
01335       if(alpha < 0.1){
01336         *R = (double)Ground.acolor[0]*IdR;
01337         *G = (double)Ground.acolor[1]*IdG;
01338         *B = (double)Ground.acolor[2]*IdB;
01339       }
01340       else{
01341         *R = (double)Ground.color[0]*IdR;
01342         *G = (double)Ground.color[1]*IdG;
01343         *B = (double)Ground.color[2]*IdB;
01344       }
01345       break;
01346     case 7: /* dot texture */
01347       hitpoint(Ground.n,Ground.dx,Ground.dyy,Ground.p,p0,&alpha,&beta);
01348       alpha=(alpha-floor(alpha))-0.5;
01349       beta=(beta-floor(beta))-0.5;
01350       if(beta*beta+alpha*alpha < Ground.range){
01351         *R = (double)Ground.acolor[0]*IdR;
01352         *G = (double)Ground.acolor[1]*IdG;
01353         *B = (double)Ground.acolor[2]*IdB;
01354       }
01355       else{
01356         *R = (double)Ground.color[0]*IdR;
01357         *G = (double)Ground.color[1]*IdG;
01358         *B = (double)Ground.color[2]*IdB;
01359       }
01360       break;
01361     case 8: /* cross texture */
01362       hitpoint(Ground.n,Ground.dx,Ground.dyy,Ground.p,p0,&alpha,&beta);
01363       alpha=fabs((alpha-floor(alpha))-0.5);
01364       beta=fabs((beta-floor(beta))-0.5);
01365       if((beta < 0.3 && alpha < 0.1) || (alpha < 0.3 && beta < 0.1)){
01366         *R = (double)Ground.acolor[0]*IdR;
01367         *G = (double)Ground.acolor[1]*IdG;
01368         *B = (double)Ground.acolor[2]*IdB;
01369       }
01370       else{
01371         *R = (double)Ground.color[0]*IdR;
01372         *G = (double)Ground.color[1]*IdG;
01373         *B = (double)Ground.color[2]*IdB;
01374       }
01375       break;
01376     case 9: /* brick texture */
01377       hitpoint(Ground.n,Ground.dx,Ground.dy,Ground.p,p0,&alpha,&beta);
01378       alpha=(alpha-floor(alpha));
01379       beta=(beta-floor(beta));
01380       if((beta > 0.95 || (beta > 0.45 && beta < 0.5)) ||
01381          (beta < 0.5 && ( (alpha > 0.45 && alpha < 0.5) || alpha > 0.95) ) ||
01382          (beta > 0.5 && ((alpha > 0.25 && alpha < 0.3) ||
01383          (alpha > 0.7 && alpha < 0.75)))
01384          ){
01385         *R = (double)Ground.acolor[0]*IdR;
01386         *G = (double)Ground.acolor[1]*IdG;
01387         *B = (double)Ground.acolor[2]*IdB;
01388       }
01389       else{
01390         *R = (double)Ground.color[0]*IdR;
01391         *G = (double)Ground.color[1]*IdG;
01392         *B = (double)Ground.color[2]*IdB;
01393       }
01394       break;
01395     case 10:
01396       *R = (double)Ground.color[0]*IdR;
01397       *G = (double)Ground.color[1]*IdG;
01398       *B = (double)Ground.color[2]*IdB;
01399       break;  /* bumpy */
01400     case 16:  /* external texture */
01401       *R = xRGB[0]*IdR; *G = xRGB[1]*IdG; *B = xRGB[2]*IdB;
01402       break;
01403     default:  /* ground is mapped by a brush               */
01404       map=0;  /* ground brush has been successfully loaded */
01405 
01406       if(Ground.mapped){
01407          map=MapFromProjection(&Ground.map,Ground.maptype,0,
01408                       p0,&red,&green,&blue);
01409       }
01410       if(map == 1){
01411         *R = (red*IdR);
01412         *G = (green*IdG);
01413         *B = (blue*IdB);
01414       }
01415       else{
01416         *R = (double)Ground.color[0]*IdR;
01417         *G = (double)Ground.color[1]*IdG;
01418         *B = (double)Ground.color[2]*IdB;
01419       }
01420     break;
01421     }
01422 }
01423 
01424 /* end of code for ground and other elements           */
01425 
01426 double DepthCueLight(long j, double cc){
01427  double d;
01428  return 1.0/(Lights[j].dc_c + cc*(Lights[j].dc_l + cc*Lights[j].dc_q));
01429 }
01430 
01431 void GetPixelLighting(matl *Mat, vector p, vector n, double pdotn, double ddotn,
01432                       long obj, face *f, 
01433                       double *IdR, double *IdG, double *IdB,
01434                       double *IsR, double *IsG, double *IsB){
01435  long j,matsp;
01436  double cc,alpha,c,ldotn,falloff,Iab,amblight; 
01437  vector bv,pl,pr;
01438  BOOL bShiny;
01439  for(j=0;j<Nlights;j++)if(Lights[j].type != SHADOWS &&
01440                           Lights[j].type != DUMMYL){
01441    VECSUB(Lights[j].p,p,pl)
01442    cc=R_length(pl);
01443    VECSCALE(1.0/cc,pl,pr)
01444 /*   ldotn=DOT(pr,f->n); this was used to try to eliminate fringe pixels
01445      but it appears to cause some faces to de-phong incorrectly */
01446    ldotn=DOT(pr,n);
01447    if((ldotn > 1.e-6)){
01448      amblight=Object[obj].ambient_light;
01449      //c = max(0.0,DOT(pr,n));
01450      c = ldotn;
01451      if(Lights[j].type == SPOTLIGHT){
01452 /* note the < is because DOT is max when pr and n are aligned */
01453 /* dot2 is the outer cone, dot1 is the inner cone             */
01454 /* d of light is in OPPOSITE dirn. to the dirn of the light   */
01455 /* pr is vector from point to light thus if pr.n = 1 light is */
01456 /* pointing straight at the point                             */
01457        if((alpha=DOT(pr,Lights[j].d)) < Lights[j].dot2)falloff=0;
01458        else if(alpha < Lights[j].dot1){ /* in between cones */
01459          falloff=(alpha-Lights[j].dot2)*Lights[j].falloff;
01460        }
01461        else falloff=1.0; /* otherwise inside inner cone and no atten */
01462        c *= falloff;
01463        if(c > 0.0 && Lights[j].shadow_buffer != NULL &&
01464          Object[obj].show_shadow)PointInShadow(p,j,&c);
01465      }
01466      Iab = amblight+(1.0-amblight)*c;
01467    }
01468    else{  // Light backside
01469      Iab=Object[obj].ambient_light;
01470      falloff=1.0;
01471    }
01472    if(Lights[j].dc){
01473      cc = DepthCueLight(j,cc);
01474      Iab *= cc;
01475    }
01476    *IdR += Iab*Lights[j].Ire;
01477    *IdG += Iab*Lights[j].Igr;
01478    *IdB += Iab*Lights[j].Ibl;
01479 
01480    if(Mat != NULL){bShiny=Mat->bShiny; matsp=Mat->gloss;}
01481    else           {bShiny=f->bShiny;;  matsp=8;}
01482    if(bShiny){/* shiny  switch is on  */
01483      VECSUB(pl,p,bv)                /* calculate specular highlight */
01484      normalize(bv);
01485      c=DOT(bv,n);
01486      if(c > 0.0)Iab = spec_pow[matsp][min(max_spec,(long)(c*max_spec))];
01487      else Iab = 0;
01488      if(Lights[j].type == SPOTLIGHT)Iab *= falloff;
01489      if(Lights[j].dc)Iab *= cc;
01490      *IsR += Iab*Lights[j].Ire;
01491      *IsG += Iab*Lights[j].Igr;
01492      *IsB += Iab*Lights[j].Ibl;
01493    }
01494  }
01495 }
01496 
01497 static void PutBackPlanes(long i, long scanline, double d2,
01498                    UCHAR *Red, UCHAR *Green, UCHAR *Blue,
01499                    double *Zground, long *Zobject, double *Zdepth,
01500                    UCHAR *ZobjChar, long Wsky, double Rsky){
01501  vector p0;
01502  double red,green,blue;
01503  long ix;
01504    if(Zobject[i] == -1){   /* ground at this pixel */
01505     p0[0]=(((double)i-(double)Xcentre)/scalex*Zground[i]);
01506     p0[1]=min(FARAWAY,Zdepth[i]);
01507     p0[2]=(((double)Ycentre-(double)scanline)/scaley*Zground[i]);
01508     GetGroundLight(p0,&red,&green,&blue);
01509     Red  [i] = (unsigned char)min(255.0,red);
01510     Green[i] = (unsigned char)min(255.0,green);
01511     Blue [i] = (unsigned char)min(255.0,blue);
01512     if((ZobjChar[i] & 1) == 1){
01513       Red[i]   *= shadow_density;     /* do the shadows before reflections*/
01514       Green[i] *= shadow_density;
01515       Blue[i]  *= shadow_density;
01516     }
01517     if(mirror_ground == 1){
01518       Add_Ground_Mirror(scanline,i,p0,&Red[i],&Green[i],&Blue[i]);
01519     }
01520    }
01521    else if(Nsky > 0){
01522      /* if the map could not be loaded use this as well */
01523      if(Sky.type == SKYGRADED){
01524        Red  [i]=(unsigned char)(
01525                    ((double)Sky.Zenith[0]-(double)Sky.Horizon[0])*Rsky
01526                   + (double)Sky.Horizon[0]);
01527        Green[i]=(unsigned char)(
01528                    ((double)Sky.Zenith[1]-(double)Sky.Horizon[1])*Rsky
01529                   + (double)Sky.Horizon[1]);
01530        Blue [i]=(unsigned char)(
01531                    ((double)Sky.Zenith[2]-(double)Sky.Horizon[2])*Rsky
01532                   + (double)Sky.Horizon[2]);
01533      }
01534      else if(Sky.type <= SKYCOLOUR || !Sky.mapped){
01535        Red  [i]=Sky.Zenith[0];
01536        Green[i]=Sky.Zenith[1];
01537        Blue [i]=Sky.Zenith[2];
01538      }
01539      else if(Sky.type == SKYMAPPED){  /* Map the sky - do it directly */
01540        ix=Wsky*Sky.map.xmax+ZskyBuffer[i];
01541        Red[i]   = Sky.map.p24R[ix];
01542        Green[i] = Sky.map.p24G[ix];
01543        Blue[i]  = Sky.map.p24B[ix];
01544      }
01545      else if(Sky.type == BACKDROP){  /* Put in back drop */
01546        ix=((scanline*Sky.map.ymax)/YMAX)*Sky.map.xmax
01547          +(i*Sky.map.xmax)/XMAX;
01548        Red[i]   = Sky.map.p24R[ix];
01549        Green[i] = Sky.map.p24G[ix];
01550        Blue[i]  = Sky.map.p24B[ix];
01551      }
01552      else if(Sky.type == SKYCUBE){ // use environment map 
01553        MapEnvironment(i,scanline,&Red[i],&Green[i],&Blue[i], &(Sky.map));
01554      }
01555    }
01556    else{ Red[i]=0;   Green[i]=0;   Blue[i]=0; }
01557 }
01558 
01559 static void GetBackdropValue(long row, long col, vector p, vector d,
01560                              double *colour){
01561  /* this is used by the Tracer to get the background */
01562  vector dp,gp;
01563  double pdotn,ddotn,mu,d2,Rsky;
01564  long ix;
01565  if(R_Nground > 0 && fabs(ddotn=dot(Ground.n,d)) > 1.e-3){
01566    VECSUB(Ground.p,p,dp)
01567    pdotn=DOT(Ground.n,dp);
01568    mu=pdotn/ddotn;
01569    if(mu > 0.0){
01570      vecscale(mu,d,gp);
01571      vecsum(p,gp,gp);
01572      GetGroundLight(gp,&colour[0],&colour[1],&colour[2]);
01573    }
01574    else goto NEXTBLOCK;
01575  }
01576  else{
01577    NEXTBLOCK:
01578    if(Sky.type == SKYGRADED){
01579      d2=(double)(Ycentre-row);
01580      d2/=scaley;
01581      //Rsky=fabs((CamAlpha+atan2(d2,1.000))/PI*2.0);  // Replaced to match OpenGL
01582      Rsky=fabs((double)(Ycentre-row))/(double)Ycentre;     
01583      colour[0]=((double)Sky.Zenith[0]-(double)Sky.Horizon[0])*Rsky
01584                +(double)Sky.Horizon[0];
01585      colour[1]=((double)Sky.Zenith[1]-(double)Sky.Horizon[1])*Rsky
01586                +(double)Sky.Horizon[1];
01587      colour[2]=((double)Sky.Zenith[2]-(double)Sky.Horizon[2])*Rsky
01588                +(double)Sky.Horizon[2];
01589    }
01590    else if(Sky.type == SKYMAPPED && Sky.mapped){  // this looks like a cylindrical map
01591      ddotn=d[2];
01592      if(fabs(ddotn) > 1.e-2){
01593        vecsub(Sky.map.p,p,dp);
01594        pdotn=dp[2];
01595        mu=pdotn/ddotn;
01596        vecscale(fabs(mu),d,gp);
01597        vecsum(p,gp,gp);
01598        MapFromProjection(&Sky.map,TILE,EOPAQUE,gp,&colour[0],&colour[1],&colour[2]);
01599      }
01600    }
01601    else if(Sky.type == BACKDROP && Sky.mapped){
01602      ix=((row*Sky.map.ymax)/YMAX)*Sky.map.xmax
01603        +(col*Sky.map.xmax)/XMAX;
01604      colour[0] = Sky.map.p24R[ix];
01605      colour[1] = Sky.map.p24G[ix];
01606      colour[2] = Sky.map.p24B[ix];
01607    }
01608    else if(Sky.type == SKYCUBE && Sky.mapped){ // use environment map 
01609      unsigned char R,G,B;
01610      MapEnvironment(col,row,&R,&G,&B, &(Sky.map));
01611      colour[0]=(double)R; colour[1]=(double)G; colour[2]=(double)B;
01612    }
01613    else{
01614      colour[0] = (double)Sky.Zenith[0];
01615      colour[1] = (double)Sky.Zenith[1];
01616      colour[2] = (double)Sky.Zenith[2];
01617    }
01618  }
01619  return;
01620 }
01621 
01622 void GetMirrorValues(double *color, vector p, vector din, vector n,
01623                      int at_o, face *at_f,
01624                      long trace_reflection_depth,
01625                      long trace_refraction_depth,
01626                      long trace_refractive_flag){
01627   /* p    is point on mirror surface where ray hits   */
01628   /* din  is incident direction                       */
01629   vector d,dp,gp,di;
01630   double pdotn,ddotn,mu,ld;
01631   ddotn = dot(din,n);
01632   vecscale(2*ddotn,n,d);  /* d is reflected direction (same length as din) */
01633   vecsub(din,d,d);        /* d=2(din.n)n-din                               */
01634   if(R_Nground > 0){
01635     ddotn=dot(Ground.n,d);
01636     if(fabs(ddotn) > 1.e-2){
01637       vecsub(Ground.p,p,dp);
01638       pdotn=dot(Ground.n,dp);
01639       mu=pdotn/ddotn;
01640       if(mu > 0.0){
01641         vecscale(mu,d,di);
01642         vecsum(p,di,gp);
01643         GetGroundLight(gp,&color[0],&color[1],&color[2]);
01644         if(trace_reflections == 1){
01645           ld = (double)((di[0]*di[0]) + (di[1]*di[1]) + (di[2]*di[2]));
01646           if(fabs(ld) > 1.e-10){
01647             ld=sqrt(ld);
01648             VECSCALE((1.0/ld),di,di)
01649             trace_reflection_ray(p,di,ld,color,
01650                                  at_o,at_f,
01651                                  trace_reflection_depth,
01652                                  trace_refraction_depth,
01653                                  trace_refractive_flag);
01654           }
01655         }
01656         return;
01657       }
01658     }
01659   }
01660   color[0] = (double)Sky.Zenith[0];
01661   color[1] = (double)Sky.Zenith[1];
01662   color[2] = (double)Sky.Zenith[2];
01663   if(Sky.type == SKYMAPPED){
01664     ddotn=d[2];
01665     if(fabs(ddotn) > 1.e-2){
01666       vecsub(Sky.map.p,p,dp);
01667       pdotn=dp[2];
01668       mu=pdotn/ddotn;
01669       vecscale(fabs(mu),d,gp);
01670       vecsum(p,gp,gp);
01671       /* check for existance of sky map elsewhere */
01672       MapFromProjection(&Sky.map,TILE,EOPAQUE,gp,&color[0],&color[1],&color[2]);
01673     }
01674   }
01675   else if(Sky.type == SKYCUBE){
01676     MapEnvironmentInDirection(d,&color[0],&color[1],&color[2],&Sky.map);
01677   }
01678   if(trace_reflections == 1){
01679     ld= (double)((d[0]*d[0]) + (d[1]*d[1]) + (d[2]*d[2]));
01680     if(fabs(ld) > 1.e-10){
01681       ld=sqrt(ld);
01682       VECSCALE((1.0/ld),d,di)
01683       trace_reflection_ray(p,di,
01684                            (double)BIGP,color,
01685                            at_o,at_f,   
01686                            trace_reflection_depth,
01687                            trace_refraction_depth,
01688                            trace_refractive_flag);
01689     }
01690   }
01691   return;
01692 }
01693 
01694 static void AttenuateGlass(long row, long col,
01695                     UCHAR *Red, UCHAR *Green, UCHAR *Blue,
01696                     long *Zglass[], long *ZglassO[], double *Zglassd[],
01697                     double *Zposn){
01698  long i;                          /* if the face on top is glass */
01699  for(i=NGLASS-1;i>=0;i--){        /* add in its surface attribs  */
01700    if(Zglass[i][col] >= 0)AttenuateGlassSurface(i,row,col,Red,Green,Blue,
01701                                                 Zglass,ZglassO,Zglassd,
01702                                                 Zposn);
01703  }
01704 }
01705 
01706 static void AttenuateGlassSurface(long id, long row, long col,
01707                          UCHAR *Red, UCHAR *Green, UCHAR *Blue,
01708                          long *Zglass[], long *ZglassO[], double *Zglassd[],
01709                          double *Zposn){
01710  double tr,tr1,srf=0.0,srf1=1.0;
01711  double Iab,IdR,IdG,IdB,IsR,IsG,IsB,c,cc,det,alpha,beta,bend,bend1,falloff;
01712  double pdotn,ldotn;
01713  double colorb0=0,colorb1=0,colorb2=0,colorr0=0,colorr1=0,colorr2=0,
01714         colors[3],colorm[3];
01715  vector n,p,pr,pl,bv;
01716  long j,obj;
01717  short clear,type;
01718  face    *f;
01719  vertex  *v;
01720  imap    *Map;
01721  matl    *Mat;
01722  BOOL    bSmooth,xtext=FALSE;
01723  unsigned char mattr,matre;
01724  obj=ZglassO[id][col];
01725  f=Object[obj].Fbase+Zglass[id][col];
01726  v=Object[obj].Vbase;
01727  if(f->ffmap >= 0){
01728    if((long)f->ffmap >= Object[obj].NoMaps)Map=NULL;
01729    else Map=(Object[obj].Mbase+(long)f->ffmap);
01730  }
01731  else Map=NULL;
01732  if(f->ffmat < 0 || f->ffmat >= Object[obj].NoMats)Mat=NULL;
01733  else Mat=(Object[obj].Tbase+(long)f->ffmat);
01734 
01735  if(Mat != NULL)bSmooth=Mat->bSmooth;
01736  else           bSmooth=f->bSmooth;
01737  if(!bSmooth)VECCOPY(f->n,n)  /* phong = NO */
01738  else{
01739    det=(
01740        (v[f->V[2]].y - v[f->V[0]].y) * (v[f->V[1]].x - v[f->V[0]].x)
01741       -(v[f->V[2]].x - v[f->V[0]].x) * (v[f->V[1]].y - v[f->V[0]].y)
01742        );
01743    if(det == 0){
01744      VECCOPY(f->n,n)
01745    }
01746    else{
01747      det=1.0/det;
01748      alpha= (double)(
01749         (v[f->V[2]].y - v[f->V[0]].y) * (Zposn[col] - v[f->V[0]].x)
01750        -(v[f->V[2]].x - v[f->V[0]].x) * ((double)row - v[f->V[0]].y)
01751                     )*det;
01752      beta= (double)(
01753         ((double)row - v[f->V[0]].y) * (v[f->V[1]].x - v[f->V[0]].x)
01754        -(Zposn[col] - v[f->V[0]].x) * (v[f->V[1]].y - v[f->V[0]].y)
01755                    )*det;
01756      n[0]=f->pn[0][0] + alpha*(f->pn[1][0] - f->pn[0][0])
01757                      +  beta*(f->pn[2][0] - f->pn[0][0]);
01758      n[1]=f->pn[0][1] + alpha*(f->pn[1][1] - f->pn[0][1])
01759                      +  beta*(f->pn[2][1] - f->pn[0][1]);
01760      n[2]=f->pn[0][2] + alpha*(f->pn[1][2] - f->pn[0][2])
01761                      +  beta*(f->pn[2][2] - f->pn[0][2]);
01762      normalize(n);
01763    }
01764  }
01765  /* p is the point on the glass face that is seen at this pixel */
01766  p[0]=(((double)col-(double)Xcentre)/scalex*Zglassd[id][col]);
01767  p[1]=Zglassd[id][col];
01768  p[2]=(((double)Ycentre-(double)row)/scaley*Zglassd[id][col]);
01769  if((pdotn=DOT(p,f->n)) > 0){n[0] = -n[0]; n[1] = -n[1]; n[2] = -n[2];}
01770  IdR=IdG=IdB=0.0; IsR=IsG=IsB=0.0;
01771  if(Map != NULL && Map->bp >= 0){
01772    if(Map->bTiled)type=TILE;
01773    else           type=SINGLE;
01774    if(Map->map == MAP_BY_VERTEX)
01775      BumpByCoordinates(Map,type,obj,f,p,n);
01776    else{;}
01777  }
01778  if(Mat != NULL){
01779    VECCOPY((double)Mat->color,colors)
01780    tr=((double)(Mat->transp))*3.92e-3;
01781    if(Mat->bInternalShader)xtext=FALSE; else xtext=TRUE;
01782  }
01783  else{
01784    VECCOPY((double)f->color,colors) 
01785    tr=((double)(8))*3.92e-3;   // shoudn't happen as only materials can be glass
01786    xtext=FALSE;
01787  }
01788  if(xtext){ /* external shader */
01789    double alpha_channel=0.0;
01790    int s;
01791    double beta,gamma;
01792    MapTextureByCoordinates(obj,f,p,&alpha,&beta,&gamma);
01793    for(s=0;s<4;s++){
01794      if(Mat->shaderID[s] >= 0)
01795        RenderExternalTexture(Mat->shaderID[s],
01796            p,n,
01797            alpha,beta,gamma,
01798            (double)(Mat->params[0])*SHSCALE,  
01799            &alpha_channel,
01800            &tr,
01801            Mat->texco,
01802            obj,f,
01803            colors);
01804    }
01805  }
01806  if(Mat != NULL && Mat->bGlassEdge){       /* glass edge is on */
01807    if((bend=DOT(p,n)) < 0)bend = -bend;
01808    bend1=sqrt(bend/R_length(p));
01809    tr1  = 1.0-tr;
01810    tr *= bend1;                 /* to give glass some edge */
01811  }
01812  else{
01813    tr1  = 1.0-tr;
01814  }
01815  GetPixelLighting(Mat,p,n,pdotn,0.0,obj,f,
01816                   &IdR,&IdG,&IdB,&IsR,&IsG,&IsB);
01817  if(Map != NULL){
01818    if(Map->rp >= 0){
01819      MapMirror(&colorr0,&colorr1,&colorr2,Map,p,n);
01820      srf=Map->rd; srf1=(1.0-srf);
01821    }
01822    if(Map->pp < 0)goto MISSBRUSH;
01823    if(Map->bDecal)clear = TRANSP;
01824    else           clear = EOPAQUE;
01825    if(Map->map == MAP_BY_VERTEX){
01826      if(Map->bTiled)type = TILE;
01827      else           type = SINGLE;
01828      if(MapByCoordinates(Map,obj,f,type,clear,p,&colorb0,&colorb1,&colorb2)
01829         == 0)goto MISSBRUSH1;
01830    }
01831    else{;}
01832    if(!(Map->bShaded)){       /* unshaded map required */
01833      IdR=IdG=IdB=1.0; IsR=IsG=IsB=0.0;
01834    }
01835    tr1=Map->pd; tr=(1.0-tr1);    /* tr is 0-1 % of transparency */
01836    *(colors  ) = colorb0;
01837    *(colors+1) = colorb1;
01838    *(colors+2) = colorb2;
01839    MISSBRUSH:
01840    if(Map->tp >= 0){ /* transparency map - white is fully opaque */
01841      if(Map->bTiled)type = TILE;
01842      else           type = SINGLE;
01843      if(Map->map == MAP_BY_VERTEX){
01844        if(MapTransByCoordinates(Map,type,obj,f,p,&tr) != 0)tr1=(1.0-tr);
01845      }
01846      else{;}
01847    }
01848    MISSBRUSH1:
01849    IdR=(double)Red[col]*tr   + (colors[0]*IdR+IsR*255)*tr1;
01850    IdG=(double)Green[col]*tr + (colors[1]*IdG+IsG*255)*tr1;
01851    IdB=(double)Blue[col]*tr  + (colors[2]*IdB+IsB*255)*tr1;
01852    IdR=IdR*srf1 + colorr0*srf;
01853    IdG=IdG*srf1 + colorr1*srf;
01854    IdB=IdB*srf1 + colorr2*srf;
01855  }
01856  else{
01857    IdR=(double)Red[col]*tr   + colors[0]*tr1*IdR+IsR*255;
01858    IdG=(double)Green[col]*tr + colors[1]*tr1*IdG+IsG*255;
01859    IdB=(double)Blue[col]*tr  + colors[2]*tr1*IdB+IsB*255;
01860    if(Mat != NULL)matre=Mat->refl; else matre=0;
01861    if(matre > 0){
01862      GetMirrorValues(colorm,p,p,n,0,NULL,0,0,0);
01863      srf = (double)(matre)/255.0; srf1=(1.0-srf);
01864      IdR=IdR*srf1 + colorm[0]*srf;
01865      IdG=IdG*srf1 + colorm[1]*srf;
01866      IdB=IdB*srf1 + colorm[2]*srf;
01867    }
01868  }
01869  Red[col]  =(unsigned char)min(255.0,IdR);
01870  Green[col]=(unsigned char)min(255.0,IdG);
01871  Blue[col] =(unsigned char)min(255.0,IdB);
01872 }
01873 
01884 void GetPixelValue(vector p, vector dinput, // p is point on surface  dinput is input direction
01885                    vector n, double pdotn, 
01886                    imap *Map, matl *Mat, face *f, long obj,
01887                    long row, long col, BOOL first_trace,
01888                    long trace_relection_depth, long trace_refraction_depth, long refractive_flag,
01889                    double *Red, double *Green, double *Blue){
01890  BOOL     xtext,fullsat=FALSE;
01891  vector   pr,bv,pl,d;
01892  long     j,flag_mirror=0,t,flag_trans=0,refx=1000;
01893  short    type,textID,clear;
01894  double   alpha,beta,gamma;
01895  double   colors[3],colorr[3],colorm[3],colort[3];
01896  double   Iab,IdR,IdG,IdB,IsR,IsG,IsB,c,cc,
01897           ldotn,amblight,falloff;
01898  double   sf,sf1,tr,tr1,rf,rf1;
01899  unsigned char mattr,matre;
01900  
01901  IdR=IdG=IdB=0.0; IsR=IsG=IsB=0.0;
01902  colorr[0]=colorr[1]=colorr[2]=0.0;
01903  colorm[0]=colorm[1]=colorm[2]=0.0;
01904  colort[0]=colort[1]=colort[2]=0.0;
01905 
01906  if(Mat != NULL){
01907    VECCOPY((double)Mat->color,colors)
01908    if(Mat->bInternalShader){textID=Mat->internalShaderID; xtext=FALSE;}
01909    else                    {textID=0; xtext=TRUE;}
01910    tr=((double)(Mat->transp))*3.92e-3;
01911    refx=Mat->refractive_index;
01912  }
01913  else{
01914    VECCOPY((double)f->color,colors)
01915    textID=0; 
01916    xtext=FALSE;
01917    tr=0;
01918    refx=1000;
01919  }
01920  sf=1.0;
01921  /* n is to be normal to surface at that point p */
01922  if(Map != NULL && Map->bp >= 0){
01923    if(Map->bTiled)type=TILE;
01924    else           type=SINGLE;
01925    if(Map->map == MAP_BY_VERTEX)
01926      BumpByCoordinates(Map,type,obj,f,p,n);
01927    else{;}
01928  }
01929  if(textID > 0 || xtext){
01930    MapTextureByCoordinates(obj,f,p,&alpha,&beta,&gamma);
01931    if(xtext){ /* external shader */
01932      double alpha_channel=0.0;
01933      int s; 
01934      for(s=0; s<4;s++){
01935        if(Mat->shaderID[s] >= 0)
01936          fullsat=RenderExternalTexture(Mat->shaderID[s],
01937            p,n,
01938            alpha,beta,gamma,
01939            (double)(Mat->params[0])*SHSCALE,  
01940            &alpha_channel,
01941            &tr,
01942            Mat->texco,
01943            obj,f,
01944            colors);
01945      }
01946    }
01947    else fullsat=GetInternalTexture(Mat,alpha,beta,gamma,textID,p,n,obj,f,colors,
01948                      colort,&flag_trans,tr,&tr1,
01949                      trace_relection_depth,trace_refraction_depth,
01950                      refractive_flag);
01951  }
01952  GetPixelLighting(Mat,p,n,pdotn,0.0,obj,f,
01953                   &IdR,&IdG,&IdB,&IsR,&IsG,&IsB);
01954  colorm[0]=colorm[1]=colorm[2]=0.0;
01955  if(Map != NULL){
01956    if(Map->rp >= 0){
01957      MapMirror(&colorr[0],&colorr[1],&colorr[2],Map,p,n);
01958      flag_mirror=1; rf=Map->rd;
01959    }
01960    if(Map->tp >= 0){ /* transparency map - white is fully transparent */
01961      if(Map->bTiled)type = TILE;
01962      else           type = SINGLE;
01963      if(MapTransByCoordinates(Map,type,obj,f,p,&tr) != 0)tr1=(1.0-tr);
01964      if(trace_refractions && tr > 0.0){
01965        c=(double)((dinput[0]*dinput[0]) + (dinput[1]*dinput[1]) + (dinput[2]*dinput[2]));
01966        c=sqrt(c);
01967        VECSCALE((1.0/c),dinput,d)
01968        if(first_trace && refx == 1000){
01969          GetBackdropValue(row,col,p,d,colort);
01970        }
01971        else {
01972          colort[0]=*Red; colort[1]=*Green; colort[2]=*Blue;
01973        }
01974        if(refx == 1000)trace_transmission_ray(p,d,n,obj,f,(double)BIGP,colort, 
01975          trace_relection_depth,trace_refraction_depth,refractive_flag);
01976        else trace_refraction_ray(p,d,n,obj,f,(double)BIGP,colort,refx,
01977          trace_relection_depth,trace_refraction_depth,refractive_flag);
01978        flag_trans=1;
01979      }
01980    }
01981    if(Map->pp < 0)goto ALGOTEXT;
01982    if(Map->bDecal)clear = TRANSP;
01983    else           clear = EOPAQUE;
01984    if(Map->map == MAP_BY_VERTEX){
01985      if(Map->bTiled)type = TILE;
01986      else           type = SINGLE;
01987      if(MapByCoordinates(Map,obj,f,type,clear,p,
01988                          &colorm[0],&colorm[1],&colorm[2])
01989         == 0)goto ALGOTEXT;
01990      flag_trans=2;
01991    }
01992    if(Map->bShaded){       /* shaded map required */
01993      colorm[0] = colorm[0]*IdR+IsR*255;        /* put spec after mix  */
01994      colorm[1] = colorm[1]*IdG+IsG*255;
01995      colorm[2] = colorm[2]*IdB+IsB*255;
01996    }
01997    sf=(1.0-Map->pd);          /* map "pd" is 0.0-1.0  or pp */
01998    if(Map->pp == 100){        /* make sure only map is used */
01999      colors[0]=colors[1]=colors[2]=0.0;
02000      goto SKIPALGO;
02001    }
02002  }
02003  /* algorithmic shaders */
02004  ALGOTEXT:
02005  if(fullsat){IdR=IdG=IdB=1.0; IsR=IsG=IsB=0.0;}
02006 
02007  SKIPALGO:
02008  /* combine the shader and map with appropriate illimination */
02009  sf1=1.0-sf;
02010  colors[0] = colors[0]*IdR*sf + colorm[0]*sf1;
02011  colors[1] = colors[1]*IdG*sf + colorm[1]*sf1;
02012  colors[2] = colors[2]*IdB*sf + colorm[2]*sf1;
02013  /* colors now is the surface value including diffuse lighting */
02014  if(trace_shadows && Object[obj].show_shadow &&
02015     (j=check_for_shadow(obj,p,f->n)) != 0){
02016    IsR = IsG = IsB = 0.0;
02017    if(j < 0){
02018      colors[0] *= shadow_density;     /* do the shadows */
02019      colors[1] *= shadow_density;
02020      colors[2] *= shadow_density;
02021    }
02022    else{ /* j layers of glass */
02023      colors[0] *= glass_shadow_density;
02024      colors[1] *= glass_shadow_density;
02025      colors[2] *= glass_shadow_density;
02026    }
02027  }
02028  if(Mat != NULL)mattr=Mat->transp;
02029  else           mattr=0;
02030  if(trace_refractions && mattr > 0 && flag_trans == 0){ 
02031    double bend,bend1;
02032    BOOL glass_edge;
02033    if(Mat != NULL)glass_edge=Mat->bGlassEdge;
02034    else           glass_edge=FALSE;
02035      if(glass_edge){       /* glass edge is on */
02036      if((bend=DOT(p,n)) < 0)bend = -bend;
02037      bend1=sqrt(bend/R_length(p));
02038      tr1  = 1.0-tr;
02039      tr *= bend1;                 /* to give glass some edge */
02040    }
02041    else{
02042      tr1  = 1.0-tr;
02043    }
02044    c=(double)((dinput[0]*dinput[0]) + (dinput[1]*dinput[1]) + (dinput[2]*dinput[2]));
02045    c=sqrt(c);
02046    VECSCALE((1.0/c),dinput,d)
02047    if(refx == 1000){ // This not refractive glass
02048      GetBackdropValue(row,col,p,d,colort);
02049      trace_transmission_ray(p,d,n,obj,f,(double)BIGP,colort,
02050          trace_relection_depth,trace_refraction_depth,refractive_flag);
02051   }
02052   else  trace_refraction_ray(p,d,n,obj,f,(double)BIGP,colort,refx,
02053                         trace_relection_depth,trace_refraction_depth,refractive_flag);
02054    flag_trans=1;
02055  }
02056  if(flag_trans == 1){  /* mix any transmissivity */
02057    colors[0] = colort[0]*tr + colors[0]*tr1;
02058    colors[1] = colort[1]*tr + colors[1]*tr1;
02059    colors[2] = colort[2]*tr + colors[2]*tr1;
02060  }
02061  colors[0] += IsR*255; /* mix the specular highlights */
02062  colors[1] += IsG*255;
02063  colors[2] += IsB*255;
02064 
02065  if(Mat != NULL)matre=Mat->refl;
02066  else           matre=0;
02067  if(matre > 0 && ! flag_mirror){    /* mirror added to finish */
02068    GetMirrorValues(colorr,p,dinput,n,obj,f,
02069       trace_relection_depth,trace_refraction_depth,refractive_flag);
02070    rf = (double)(matre)/255.0;
02071    flag_mirror=1;
02072  }
02073 
02074  if(flag_mirror){
02075    rf1=1.0-rf;
02076    *Red  = (unsigned char)min(255,colorr[0]*rf+colors[0]*rf1);
02077    *Green= (unsigned char)min(255,colorr[1]*rf+colors[1]*rf1);
02078    *Blue = (unsigned char)min(255,colorr[2]*rf+colors[2]*rf1);
02079  }
02080  else{
02081    *Red  = (unsigned char)min(255,colors[0]);
02082    *Green= (unsigned char)min(255,colors[1]);
02083    *Blue = (unsigned char)min(255,colors[2]);
02084  }
02085 }
02086 
02087 
02106 void GetRowPixelValue(long row, long col, imap *Map, matl *Mat,
02107                    face *f, long obj, vector nn,  /* obj is object id */
02108                    UCHAR *Red, UCHAR *Green, UCHAR *Blue,
02109                    double *Zdepth,UCHAR *ZobjChar){
02110  double r,g,b,pdotn;
02111  vector p,n;
02112  /* p is the point on the face that is seen at this pixel */
02113  p[0]=(((double)col-(double)Xcentre)/scalex*Zdepth[col]);
02114  p[1]=Zdepth[col];
02115  p[2]=(((double)Ycentre-(double)row)/scaley*Zdepth[col]);
02116  if((pdotn=DOT(p,f->n)) < 0)VECCOPY(nn,n)
02117  else     {n[0] = -nn[0]; n[1] = -nn[1]; n[2] = -nn[2];}
02118  if(trace_refractions){  // if transparent must restart transparent ray because ray does not match Z buffer
02119    double maptr,mattr;
02120    if(Map != NULL)maptr=Map->tp;
02121    else           maptr=0;
02122    if(Mat != NULL)mattr=Mat->transp;
02123    else           mattr=0;
02124    if(mattr > 0.0 || maptr > 0.0){ // Transparent so start ray back at origin
02125      int fc;
02126      vector d; 
02127      d[0]=(((double)col-(double)Xcentre+0.5)/scalex);
02128      d[1]=1.0;
02129      d[2]=(((double)Ycentre-(double)row)/scaley);
02130      normalize(d);
02131      p[0]=p[1]=p[2]=0.0;
02132      if(!trace_starting_ray(d,p,&obj,&fc,&f))return;   // p is output
02133      p[0]=p[1]=p[2]=0.0;   // Get Surface needs (0,0,0) to start 
02134      GetSurfaceValue(obj,f,Object[obj].Vbase,p,d,&r,&g,&b,0,0,0);
02135      goto ENDP;
02136    } 
02137  }
02138  GetPixelValue(p,p,n,pdotn,Map,Mat,f,obj,row,col,TRUE,0,0,0,&r,&g,&b);
02139  ENDP: 
02140  Red[col]  = (unsigned char)min(255,r);
02141  Green[col]= (unsigned char)min(255,g);
02142  Blue[col] = (unsigned char)min(255,b);
02143 }
02144 
02145 void GetSurfaceValue(int obj, face *f, vertex *v,
02146                      vector p, vector dr, double *r, double *g, double *b,
02147                      long trace_reflection_depth, long trace_refraction_depth,
02148                      long refractive_flag){
02149 /* used by ray tracing and reflection               */
02150 /* p is origin point of ray, dr is direction of ray */
02151 /* face ID is known - return RGB                    */
02152  imap *Map;
02153  matl *Mat;
02154  vector d,n,pr,pl,dp,bv,dl,nn;
02155  double ddotn,mu,pdotn,alpha,beta;
02156  BOOL bSmooth;
02157  ddotn=DOT(f->n,dr);
02158  if(fabs(ddotn) > 1.e-3){/* vector will hit face */
02159    VECSUB(v[f->V[0]].p,p,dp)
02160    pdotn=DOT(f->n,dp);
02161    mu=pdotn/ddotn;
02162    VECSCALE(mu,dr,dp)          /* dp is vector from ray origin      */
02163    VECSUM(p,dp,d)              /* d is the point on visible face    */
02164    if(f->ffmat < 0 || f->ffmat >= Object[obj].NoMats)Mat=NULL;
02165    else Mat=(Object[obj].Tbase+(long)f->ffmat);
02166    if(Mat != NULL)bSmooth=Mat->bSmooth;
02167    else           bSmooth=f->bSmooth;
02168    if(!bSmooth)veccopy(f->n,n);
02169    else{                       /* phong smoooth */
02170      VECSUB(v[f->V[1]].p,v[f->V[0]].p,pr)
02171      VECSUB(v[f->V[2]].p,v[f->V[0]].p,pl)
02172      hitpoint(f->n,pr,pl,v[f->V[0]].p,d,&alpha,&beta);
02173      VECSUB(f->pn[1],f->pn[0],pr)
02174      VECSUB(f->pn[2],f->pn[0],pl)
02175      VECSCALE(alpha,pr,pr)
02176      VECSCALE(beta,pl,pl)
02177      VECSUM(f->pn[0],pr,n)
02178      VECSUM(n,pl,n)
02179      normalize(n);
02180    }
02181    if(f->ffmap >= 0){ /* choose map */
02182       if((long)f->ffmap >= Object[obj].NoMaps)Map=NULL;
02183       else Map=(Object[obj].Mbase+(long)f->ffmap);
02184    }
02185    else Map=NULL;
02186    // added to allow for double sided faces in reflection and trace
02187    if(DOT(dp,n) < 0.0)VECCOPY(n,nn)
02188    else    {nn[0] = -n[0]; nn[1] = -n[1]; nn[2] = -n[2];}
02189    // otherwise just use "n" in arguments below
02190    GetPixelValue(d,dr,nn,-1.0,Map,Mat,f,obj,
02191                  0,0,FALSE,        // NOT first hit so no backdrop to get   
02192                  trace_reflection_depth,trace_refraction_depth,refractive_flag,
02193                  r,g,b); // returned values.
02194  }
02195 }

Generated on Sun Apr 27 14:20:11 2014 for OpenFX by  doxygen 1.5.6