home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / sharewar / quake106 / utils / light / ltface.c < prev    next >
C/C++ Source or Header  |  1996-09-12  |  12KB  |  589 lines

  1.  
  2. #include "light.h"
  3.  
  4. /*
  5. ============
  6. CastRay
  7.  
  8. Returns the distance between the points, or -1 if blocked
  9. =============
  10. */
  11. vec_t CastRay (vec3_t p1, vec3_t p2)
  12. {
  13.     int        i;
  14.     vec_t    t;
  15.     qboolean    trace;
  16.         
  17.     trace = TestLine (p1, p2);
  18.         
  19.     if (!trace)
  20.         return -1;        // ray was blocked
  21.         
  22.     t = 0;
  23.     for (i=0 ; i< 3 ; i++)
  24.         t += (p2[i]-p1[i]) * (p2[i]-p1[i]);
  25.         
  26.     if (t == 0)
  27.         t = 1;        // don't blow up...
  28.     return sqrt(t);
  29. }
  30.  
  31. /*
  32. ===============================================================================
  33.  
  34. SAMPLE POINT DETERMINATION
  35.  
  36. void SetupBlock (dface_t *f) Returns with surfpt[] set
  37.  
  38. This is a little tricky because the lightmap covers more area than the face.
  39. If done in the straightforward fashion, some of the
  40. sample points will be inside walls or on the other side of walls, causing
  41. false shadows and light bleeds.
  42.  
  43. To solve this, I only consider a sample point valid if a line can be drawn
  44. between it and the exact midpoint of the face.  If invalid, it is adjusted
  45. towards the center until it is valid.
  46.  
  47. (this doesn't completely work)
  48.  
  49. ===============================================================================
  50. */
  51.  
  52. #define    SINGLEMAP    (18*18*4)
  53.  
  54. typedef struct
  55. {
  56.     vec_t    lightmaps[MAXLIGHTMAPS][SINGLEMAP];
  57.     int        numlightstyles;
  58.     vec_t    *light;
  59.     vec_t    facedist;
  60.     vec3_t    facenormal;
  61.  
  62.     int        numsurfpt;
  63.     vec3_t    surfpt[SINGLEMAP];
  64.  
  65.     vec3_t    texorg;
  66.     vec3_t    worldtotex[2];    // s = (world - texorg) . worldtotex[0]
  67.     vec3_t    textoworld[2];    // world = texorg + s * textoworld[0]
  68.  
  69.     vec_t    exactmins[2], exactmaxs[2];
  70.     
  71.     int        texmins[2], texsize[2];
  72.     int        lightstyles[256];
  73.     int        surfnum;
  74.     dface_t    *face;
  75. } lightinfo_t;
  76.  
  77.  
  78. /*
  79. ================
  80. CalcFaceVectors
  81.  
  82. Fills in texorg, worldtotex. and textoworld
  83. ================
  84. */
  85. void CalcFaceVectors (lightinfo_t *l)
  86. {
  87.     texinfo_t    *tex;
  88.     int            i, j;
  89.     vec3_t    texnormal;
  90.     float    distscale;
  91.     vec_t    dist, len;
  92.  
  93.     tex = &texinfo[l->face->texinfo];
  94.     
  95. // convert from float to vec_t
  96.     for (i=0 ; i<2 ; i++)
  97.         for (j=0 ; j<3 ; j++)
  98.             l->worldtotex[i][j] = tex->vecs[i][j];
  99.  
  100. // calculate a normal to the texture axis.  points can be moved along this
  101. // without changing their S/T
  102.     texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2]
  103.         - tex->vecs[1][2]*tex->vecs[0][1];
  104.     texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0]
  105.         - tex->vecs[1][0]*tex->vecs[0][2];
  106.     texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1]
  107.         - tex->vecs[1][1]*tex->vecs[0][0];
  108.     VectorNormalize (texnormal);
  109.  
  110. // flip it towards plane normal
  111.     distscale = DotProduct (texnormal, l->facenormal);
  112.     if (!distscale)
  113.         Error ("Texture axis perpendicular to face");
  114.     if (distscale < 0)
  115.     {
  116.         distscale = -distscale;
  117.         VectorSubtract (vec3_origin, texnormal, texnormal);
  118.     }    
  119.  
  120. // distscale is the ratio of the distance along the texture normal to
  121. // the distance along the plane normal
  122.     distscale = 1/distscale;
  123.  
  124.     for (i=0 ; i<2 ; i++)
  125.     {
  126.         len = VectorLength (l->worldtotex[i]);
  127.         dist = DotProduct (l->worldtotex[i], l->facenormal);
  128.         dist *= distscale;
  129.         VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]);
  130.         VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]);
  131.     }
  132.  
  133.  
  134. // calculate texorg on the texture plane
  135.     for (i=0 ; i<3 ; i++)
  136.         l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
  137.  
  138. // project back to the face plane
  139.     dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
  140.     dist *= distscale;
  141.     VectorMA (l->texorg, -dist, texnormal, l->texorg);
  142.     
  143. }
  144.  
  145. /*
  146. ================
  147. CalcFaceExtents
  148.  
  149. Fills in s->texmins[] and s->texsize[]
  150. also sets exactmins[] and exactmaxs[]
  151. ================
  152. */
  153. void CalcFaceExtents (lightinfo_t *l)
  154. {
  155.     dface_t *s;
  156.     vec_t    mins[2], maxs[2], val;
  157.     int        i,j, e;
  158.     dvertex_t    *v;
  159.     texinfo_t    *tex;
  160.     
  161.     s = l->face;
  162.  
  163.     mins[0] = mins[1] = 999999;
  164.     maxs[0] = maxs[1] = -99999;
  165.  
  166.     tex = &texinfo[s->texinfo];
  167.     
  168.     for (i=0 ; i<s->numedges ; i++)
  169.     {
  170.         e = dsurfedges[s->firstedge+i];
  171.         if (e >= 0)
  172.             v = dvertexes + dedges[e].v[0];
  173.         else
  174.             v = dvertexes + dedges[-e].v[1];
  175.         
  176.         for (j=0 ; j<2 ; j++)
  177.         {
  178.             val = v->point[0] * tex->vecs[j][0] + 
  179.                 v->point[1] * tex->vecs[j][1] +
  180.                 v->point[2] * tex->vecs[j][2] +
  181.                 tex->vecs[j][3];
  182.             if (val < mins[j])
  183.                 mins[j] = val;
  184.             if (val > maxs[j])
  185.                 maxs[j] = val;
  186.         }
  187.     }
  188.  
  189.     for (i=0 ; i<2 ; i++)
  190.     {    
  191.         l->exactmins[i] = mins[i];
  192.         l->exactmaxs[i] = maxs[i];
  193.         
  194.         mins[i] = floor(mins[i]/16);
  195.         maxs[i] = ceil(maxs[i]/16);
  196.  
  197.         l->texmins[i] = mins[i];
  198.         l->texsize[i] = maxs[i] - mins[i];
  199.         if (l->texsize[i] > 17)
  200.             Error ("Bad surface extents");
  201.     }
  202. }
  203.  
  204. /*
  205. =================
  206. CalcPoints
  207.  
  208. For each texture aligned grid point, back project onto the plane
  209. to get the world xyz value of the sample point
  210. =================
  211. */
  212. int c_bad;
  213. void CalcPoints (lightinfo_t *l)
  214. {
  215.     int        i;
  216.     int        s, t, j;
  217.     int        w, h, step;
  218.     vec_t    starts, startt, us, ut;
  219.     vec_t    *surf;
  220.     vec_t    mids, midt;
  221.     vec3_t    facemid, move;
  222.  
  223. //
  224. // fill in surforg
  225. // the points are biased towards the center of the surface
  226. // to help avoid edge cases just inside walls
  227. //
  228.     surf = l->surfpt[0];
  229.     mids = (l->exactmaxs[0] + l->exactmins[0])/2;
  230.     midt = (l->exactmaxs[1] + l->exactmins[1])/2;
  231.  
  232.     for (j=0 ; j<3 ; j++)
  233.         facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt;
  234.  
  235.     if (extrasamples)
  236.     {    // extra filtering
  237.         h = (l->texsize[1]+1)*2;
  238.         w = (l->texsize[0]+1)*2;
  239.         starts = (l->texmins[0]-0.5)*16;
  240.         startt = (l->texmins[1]-0.5)*16;
  241.         step = 8;
  242.     }
  243.     else
  244.     {
  245.         h = l->texsize[1]+1;
  246.         w = l->texsize[0]+1;
  247.         starts = l->texmins[0]*16;
  248.         startt = l->texmins[1]*16;
  249.         step = 16;
  250.     }
  251.  
  252.     l->numsurfpt = w * h;
  253.     for (t=0 ; t<h ; t++)
  254.     {
  255.         for (s=0 ; s<w ; s++, surf+=3)
  256.         {
  257.             us = starts + s*step;
  258.             ut = startt + t*step;
  259.  
  260.         // if a line can be traced from surf to facemid, the point is good
  261.             for (i=0 ; i<6 ; i++)
  262.             {
  263.             // calculate texture point
  264.                 for (j=0 ; j<3 ; j++)
  265.                     surf[j] = l->texorg[j] + l->textoworld[0][j]*us
  266.                     + l->textoworld[1][j]*ut;
  267.  
  268.                 if (CastRay (facemid, surf) != -1)
  269.                     break;    // got it
  270.                 if (i & 1)
  271.                 {
  272.                     if (us > mids)
  273.                     {
  274.                         us -= 8;
  275.                         if (us < mids)
  276.                             us = mids;
  277.                     }
  278.                     else
  279.                     {
  280.                         us += 8;
  281.                         if (us > mids)
  282.                             us = mids;
  283.                     }
  284.                 }
  285.                 else
  286.                 {
  287.                     if (ut > midt)
  288.                     {
  289.                         ut -= 8;
  290.                         if (ut < midt)
  291.                             ut = midt;
  292.                     }
  293.                     else
  294.                     {
  295.                         ut += 8;
  296.                         if (ut > midt)
  297.                             ut = midt;
  298.                     }
  299.                 }
  300.                 
  301.                 // move surf 8 pixels towards the center
  302.                 VectorSubtract (facemid, surf, move);
  303.                 VectorNormalize (move);
  304.                 VectorMA (surf, 8, move, surf);
  305.             }
  306.             if (i == 2)
  307.                 c_bad++;
  308.         }
  309.     }
  310.     
  311. }
  312.  
  313.  
  314. /*
  315. ===============================================================================
  316.  
  317. FACE LIGHTING
  318.  
  319. ===============================================================================
  320. */
  321.  
  322. int        c_culldistplane, c_proper;
  323.  
  324. /*
  325. ================
  326. SingleLightFace
  327. ================
  328. */
  329. void SingleLightFace (entity_t *light, lightinfo_t *l)
  330. {
  331.     vec_t    dist;
  332.     vec3_t    incoming;
  333.     vec_t    angle;
  334.     vec_t    add;
  335.     vec_t    *surf;
  336.     qboolean    hit;
  337.     int        mapnum;
  338.     int        size;
  339.     int        c, i;
  340.     vec3_t    rel;
  341.     vec3_t    spotvec;
  342.     vec_t    falloff;
  343.     vec_t    *lightsamp;
  344.     
  345.     VectorSubtract (light->origin, bsp_origin, rel);
  346.     dist = scaledist * (DotProduct (rel, l->facenormal) - l->facedist);
  347.     
  348. // don't bother with lights behind the surface
  349.     if (dist <= 0)
  350.         return;
  351.         
  352. // don't bother with light too far away
  353.     if (dist > light->light)
  354.     {
  355.         c_culldistplane++;
  356.         return;
  357.     }
  358.  
  359.     if (light->targetent)
  360.     {
  361.         VectorSubtract (light->targetent->origin, light->origin, spotvec);
  362.         VectorNormalize (spotvec);
  363.         if (!light->angle)
  364.             falloff = -cos(20*Q_PI/180);    
  365.         else
  366.             falloff = -cos(light->angle/2*Q_PI/180);
  367.     }
  368.     else
  369.         falloff = 0;    // shut up compiler warnings
  370.     
  371.     mapnum = 0;
  372.     for (mapnum=0 ; mapnum<l->numlightstyles ; mapnum++)
  373.         if (l->lightstyles[mapnum] == light->style)
  374.             break;
  375.     lightsamp = l->lightmaps[mapnum];
  376.     if (mapnum == l->numlightstyles)
  377.     {    // init a new light map
  378.         if (mapnum == MAXLIGHTMAPS)
  379.         {
  380.             printf ("WARNING: Too many light styles on a face\n");
  381.             return;
  382.         }
  383.         size = (l->texsize[1]+1)*(l->texsize[0]+1);
  384.         for (i=0 ; i<size ; i++)
  385.             lightsamp[i] = 0;
  386.     }
  387.  
  388. //
  389. // check it for real
  390. //
  391.     hit = false;
  392.     c_proper++;
  393.     
  394.     surf = l->surfpt[0];
  395.     for (c=0 ; c<l->numsurfpt ; c++, surf+=3)
  396.     {
  397.         dist = CastRay(light->origin, surf)*scaledist;
  398.         if (dist < 0)
  399.             continue;    // light doesn't reach
  400.  
  401.         VectorSubtract (light->origin, surf, incoming);
  402.         VectorNormalize (incoming);
  403.         angle = DotProduct (incoming, l->facenormal);
  404.         if (light->targetent)
  405.         {    // spotlight cutoff
  406.             if (DotProduct (spotvec, incoming) > falloff)
  407.                 continue;
  408.         }
  409.  
  410.         angle = (1.0-scalecos) + scalecos*angle;
  411.         add = light->light - dist;
  412.         add *= angle;
  413.         if (add < 0)
  414.             continue;
  415.         lightsamp[c] += add;
  416.         if (lightsamp[c] > 1)        // ignore real tiny lights
  417.             hit = true;
  418.     }
  419.         
  420.     if (mapnum == l->numlightstyles && hit)
  421.     {
  422.         l->lightstyles[mapnum] = light->style;
  423.         l->numlightstyles++;    // the style has some real data now
  424.     }
  425. }
  426.  
  427. /*
  428. ============
  429. FixMinlight
  430. ============
  431. */
  432. void FixMinlight (lightinfo_t *l)
  433. {
  434.     int        i, j;
  435.     float    minlight;
  436.     
  437.     minlight = minlights[l->surfnum];
  438.  
  439. // if minlight is set, there must be a style 0 light map
  440.     if (!minlight)
  441.         return;
  442.     
  443.     for (i=0 ; i< l->numlightstyles ; i++)
  444.     {
  445.         if (l->lightstyles[i] == 0)
  446.             break;
  447.     }
  448.     if (i == l->numlightstyles)
  449.     {
  450.         if (l->numlightstyles == MAXLIGHTMAPS)
  451.             return;        // oh well..
  452.         for (j=0 ; j<l->numsurfpt ; j++)
  453.             l->lightmaps[i][j] = minlight;
  454.         l->lightstyles[i] = 0;
  455.         l->numlightstyles++;
  456.     }
  457.     else
  458.     {
  459.         for (j=0 ; j<l->numsurfpt ; j++)
  460.             if ( l->lightmaps[i][j] < minlight)
  461.                 l->lightmaps[i][j] = minlight;
  462.     }
  463. }
  464.  
  465.  
  466. /*
  467. ============
  468. LightFace
  469. ============
  470. */
  471. void LightFace (int surfnum)
  472. {
  473.     dface_t *f;
  474.     lightinfo_t    l;
  475.     int        s, t;
  476.     int        i,j,c;
  477.     vec_t    total;
  478.     int        size;
  479.     int        lightmapwidth, lightmapsize;
  480.     byte    *out;
  481.     vec_t    *light;
  482.     int        w, h;
  483.     
  484.     f = dfaces + surfnum;
  485.  
  486. //
  487. // some surfaces don't need lightmaps
  488. //
  489.     f->lightofs = -1;
  490.     for (j=0 ; j<MAXLIGHTMAPS ; j++)
  491.         f->styles[j] = 255;
  492.  
  493.     if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
  494.     {    // non-lit texture
  495.         return;
  496.     }
  497.  
  498.     memset (&l, 0, sizeof(l));
  499.     l.surfnum = surfnum;
  500.     l.face = f;
  501.  
  502. //
  503. // rotate plane
  504. //
  505.     VectorCopy (dplanes[f->planenum].normal, l.facenormal);
  506.     l.facedist = dplanes[f->planenum].dist;
  507.     if (f->side)
  508.     {
  509.         VectorSubtract (vec3_origin, l.facenormal, l.facenormal);
  510.         l.facedist = -l.facedist;
  511.     }
  512.     
  513.  
  514.     
  515.     CalcFaceVectors (&l);
  516.     CalcFaceExtents (&l);
  517.     CalcPoints (&l);
  518.  
  519.     lightmapwidth = l.texsize[0]+1;
  520.  
  521.     size = lightmapwidth*(l.texsize[1]+1);
  522.     if (size > SINGLEMAP)
  523.         Error ("Bad lightmap size");
  524.  
  525.     for (i=0 ; i<MAXLIGHTMAPS ; i++)
  526.         l.lightstyles[i] = 255;
  527.     
  528. //
  529. // cast all lights
  530. //    
  531.     l.numlightstyles = 0;
  532.     for (i=0 ; i<num_entities ; i++)
  533.     {
  534.         if (entities[i].light)
  535.             SingleLightFace (&entities[i], &l);
  536.     }
  537.  
  538.     FixMinlight (&l);
  539.         
  540.     if (!l.numlightstyles)
  541.     {    // no light hitting it
  542.         return;
  543.     }
  544.     
  545. //
  546. // save out the values
  547. //
  548.     for (i=0 ; i <MAXLIGHTMAPS ; i++)
  549.         f->styles[i] = l.lightstyles[i];
  550.  
  551.     lightmapsize = size*l.numlightstyles;
  552.  
  553.     out = GetFileSpace (lightmapsize);
  554.     f->lightofs = out - filebase;
  555.     
  556. // extra filtering
  557.     h = (l.texsize[1]+1)*2;
  558.     w = (l.texsize[0]+1)*2;
  559.  
  560.     for (i=0 ; i< l.numlightstyles ; i++)
  561.     {
  562.         if (l.lightstyles[i] == 0xff)
  563.             Error ("Wrote empty lightmap");
  564.         light = l.lightmaps[i];
  565.         c = 0;
  566.         for (t=0 ; t<=l.texsize[1] ; t++)
  567.             for (s=0 ; s<=l.texsize[0] ; s++, c++)
  568.             {
  569.                 if (extrasamples)
  570.                 {    // filtered sample
  571.                     total = light[t*2*w+s*2] + light[t*2*w+s*2+1]
  572.                     + light[(t*2+1)*w+s*2] + light[(t*2+1)*w+s*2+1];
  573.                     total *= 0.25;
  574.                 }
  575.                 else
  576.                     total = light[c];
  577.                 total *= rangescale;    // scale before clamping
  578.                 if (total > 255)
  579.                     total = 255;
  580.                 if (total < 0)
  581.                     Error ("light < 0");
  582.                 *out++ = total;
  583.             }
  584.     }
  585.  
  586.     
  587. }
  588.  
  589.