Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

RadMesh.cc

Go to the documentation of this file.
00001 /*
00002     File:           RadMesh.cc
00003 
00004     Function:       See header file
00005 
00006     Author(s):      Andrew Willmott
00007 
00008     Copyright:      (c) 1997-2000, Andrew Willmott
00009 
00010     Notes:          A RadElem can represent either a 4-sided parallelogram,
00011                     or a 3-sided triangle.
00012 
00013 */
00014 
00015 #include "RadMesh.h"
00016 #include "RadMethod.h"
00017 #include "cl/String.h"
00018 #include "gcl/VecUtil.h"
00019 #include "Samples.h"
00020 
00021 #ifdef RAD_VIS
00022 #include "gcl/Forms.h"
00023 #include "gcl/ScenePane.h"
00024 #endif
00025 
00072 // --- PatchStats class -------------------------------------------------------
00073 
00074 Void PatchStats::Init()
00075 {
00076     maxArea = 0.0;
00077     minArea = vl_inf;
00078     maxRefl = vl_0;
00079     minRefl.MakeBlock(vl_inf);
00080     maxRefl = vl_0;
00081     maxPower = vl_0;
00082     totalPower = vl_0;
00083 }
00084 
00085 Void PatchStats::Update(RadElem *patch)
00086 {
00087     Colour  powerClr;
00088 
00089     FindMinCmpts(minRefl, patch->props->reflectance, minRefl);
00090     FindMaxCmpts(maxRefl, patch->props->reflectance, maxRefl);
00091     maxArea = Max(patch->area, maxArea);    
00092     minArea = Min(patch->area, maxArea);    
00093 
00094     powerClr = patch->props->emittance * patch->area;
00095     totalPower += powerClr;
00096     FindMaxCmpts(maxPower, powerClr, maxPower);
00097 }
00098 
00099 Void PatchStats::Report(ostream &s)
00100 {
00101     s << "Patch statistics" << endl;
00102     s << "----------------" << endl;
00103     s << "Area range:        [" << minArea << ", " << maxArea << "]" << endl;
00104     s << "Reflectance range: [" << minRefl << ", " << maxRefl << "]" << endl;
00105     s << "Max. Power:         " << maxPower << endl;
00106     s << "Total Power:        " << totalPower << endl;
00107     s << endl;
00108 }
00109 
00110 // --- RadElem class ----------------------------------------------------------
00111 
00112 
00113 Int RadElem::sGridMem = 0;
00114 Int RadElem::sGridChildMem = 0;
00115 
00116 RadElem::RadElem() : props(0),
00117 #ifdef RAD_VIS
00118     highlight(0),
00119 #endif
00120     colour(cPurple)
00121 {
00122 }
00123 
00124 RadElem::~RadElem()
00125 {
00126 }
00127 
00128 NbRadElem::NbRadElem() : RadElem()
00129 {
00130     Int     i;
00131     
00132     for (i = 0; i < 4; i++)
00133     {
00134         nbFace[i] = 0;
00135         nbEdge[i] = 0xFF;       // for debugging only
00136     }
00137 }
00138 
00139 Void RadElem::DrawHighlight(Renderer &r)
00140 {
00141 #ifdef RAD_VIS
00142     if (highlight == 1)
00143         r.C(cRed);
00144     else if (highlight == 2)
00145         r.C(cYellow);
00146     else if (highlight == 3)
00147         r.C(cGreen);
00148     
00149     r.Begin(renPoly);
00150     SendPoints(r);
00151     r.End();
00152 #endif  
00153 }
00154 
00155 Void RadElem::Draw(Renderer &r)
00156 {
00157 #ifdef RAD_VIS
00158     if (highlight)
00159     {
00160         DrawHighlight(r);
00161         if (!gRadControl->funcView)
00162             return;
00163     }   
00164 #endif
00165 
00166     if (gRadControl->wire)
00167     {
00168         if (gRadControl->redWire)
00169             r.Begin(renLineLoop).SetColour(0.5 * (cRed + colour));
00170         else
00171             r.Begin(renLineLoop).SetColour(Mix(cWhite, colour,  0.8));
00172         
00173         SendPoints(r);
00174         r.End();
00175 
00176         return;
00177     }
00178 
00179     if (gRadControl->funcView)
00180     {
00181         r.Begin(renLineLoop).C(cWhite);
00182         SendPoints(r);
00183         r.End();
00184     }
00185     
00186     r.Begin(renPoly);
00187 
00188     if (!gRadControl->funcView)
00189     {
00190         if (props->texCoords && gRadControl->texture)
00191         {
00192             r.T(TexCoord(0)).C(VtxClr(0)).P(Vertex(0));
00193             r.T(TexCoord(1)).C(VtxClr(1)).P(Vertex(1));
00194             r.T(TexCoord(2)).C(VtxClr(2)).P(Vertex(2));
00195             
00196             if (IsQuad())
00197                 r.T(TexCoord(3)).C(VtxClr(3)).P(Vertex(3));
00198         }
00199         else if (gRadControl->gouraud)
00200         {
00201             r.C(VtxClr(0)).P(Vertex(0)).C(VtxClr(1)).P(Vertex(1))
00202                 .C(VtxClr(2)).P(Vertex(2));
00203             if (IsQuad())
00204                 r.C(VtxClr(3)).P(Vertex(3));
00205         }
00206         else
00207         {
00208             r.C(colour);
00209             SendPoints(r);
00210         }
00211     }
00212     else
00213     {
00214         RaiseVertex(r, 0);
00215         RaiseVertex(r, 1);
00216         RaiseVertex(r, 2);
00217         if (IsQuad())
00218             RaiseVertex(r, 3);
00219     }
00220 
00221     r.End();
00222 }
00223 
00224 RadElem *RadElem::FindContainer(Coord &coord)
00225 {
00226     return(this);
00227 }
00228 
00229 Colour RadElem::SampleLeaf(Coord c)
00230 {
00231     if (gRadControl->gouraud)
00232     {   
00233         if (IsTri())
00234         {
00235             Colour      result;
00236             ClrReal     s = c[0];
00237             ClrReal     t = c[1];
00238             ClrReal     u = 1 - s - t;
00239             
00240             result = VtxClr(0) * c[1] + VtxClr(1) * u + VtxClr(2) * c[0];
00241             return(result);
00242         }
00243         else
00244         {
00245             Colour      c1, c2, result;
00246             ClrReal     s = c[0];
00247             ClrReal     t = c[1];
00248             
00249             c1 = (1 - s) * VtxClr(1) + s * VtxClr(2); 
00250             c2 = (1 - s) * VtxClr(0) + s * VtxClr(3); 
00251             result = (1 - t) * c1 + t * c2;
00252             return(result);
00253         }
00254     }
00255     else
00256         return(colour);
00257 }
00258 
00259 Colour RadElem::Sample(Coord c)
00260 {
00261     RadElem *leaf = FindContainer(c);
00262     
00263     if (leaf)
00264         return(leaf->SampleLeaf(c));
00265     else
00266         return(cBlack);
00267 }
00268 
00269 Void RadElem::Compare(RadElem *to, GCLReal edgeLen, CompareStats &stats)
00270 {
00271     // Sample density is controlled by edgelen: sample every edgeLen
00272     // units in either dimension. Same deal as with patchSubdivs.
00273     
00274     Colour  err, c1, c2;
00275     Coord   b,c;
00276     Colour  pcSum, pcSqrSum, pRefSum;
00277     Int     nx, ny, i, j;
00278     GCLReal xlen, ylen, weight;
00279     
00280     // calculate # samples per axis
00281 
00282     xlen = len(Vertex(2) - Vertex(1));
00283     ylen = len(Vertex(0) - Vertex(1));
00284     
00285     nx = (Int) (edgeLen * xlen);
00286     ny = (Int) (edgeLen * ylen);
00287 
00288     if (nx < 1) nx = 1;
00289     if (ny < 1) ny = 1;
00290 
00291     pcSum = vl_0;
00292     pRefSum = vl_0;
00293     pcSqrSum = vl_0;
00294     
00295     // Sample away!!!!
00296     
00297     for (i = 0; i < nx; i++)
00298         for (j = 0; j < ny; j++)
00299         {
00300             
00301             c[0] = (0.5 + i) / GCLReal(nx);
00302             c[1] = (0.5 + j) / GCLReal(ny);
00303             if (IsTri())
00304                 ; // XXX need to resample, handle aniso for tri
00305             
00306             c1 = Sample(c);
00307             c2 = to->Sample(c);
00308     
00309             err = c1 - c2;                  // colour difference
00310             pcSum += err;                   // avg. c diff
00311             pcSqrSum += sqr(err);           // c variance
00312             pRefSum += (c1 - Emittance());  // reference: c1 - E.
00313         }
00314     
00315     weight = area / GCLReal(nx * ny);
00316     pcSum *= weight;
00317     pRefSum *= weight;
00318     pcSqrSum *= weight;
00319 
00320     // update stats, weighted by area-per-sample.
00321 
00322     stats.areaSum += area;
00323     stats.cSum += pcSum;
00324     stats.cSqrSum += pcSqrSum;
00325     stats.refSum += pRefSum;
00326 }
00327 
00328 Void RadElem::SetHighlight(Int h)
00329 {
00330 #ifdef RAD_VIS
00331     highlight = h;
00332 #endif
00333 }
00334 
00335 StrConst RadElem::Name()
00336 {
00337     return("rad");
00338 }
00339 
00340 Void RadElem::Print(ostream &s)
00341 {
00342     s << index[0] << ' ' << index[1] << ' ' << index[2] << ' ' 
00343       << index[3] << ' ';
00344     s << clrIdx[0] << ' ' << clrIdx[1] << ' ' << clrIdx[2] << ' '
00345       << clrIdx[3] << ' ';
00346     s << colour << ' ';         
00347 }
00348 
00349 Void RadElem::Parse(istream &s)
00350 {
00351     s >> index[0] >> index[1] >> index[2] >> index[3];
00352     s >> clrIdx[0] >> clrIdx[1] >> clrIdx[2] >> clrIdx[3];
00353     s >> colour;
00354 }
00355 
00356 
00357 // --- Form factor routines ---------------------------------------------------
00358 
00359 
00360 GCLReal RadElem::EstPatchFactor(const Point &p, const Vector &np)
00361 //  Elemental factor from this patch to p. 
00362 //  essentially cos theta * cos phi * Ap / (pi * r^2)
00363 {
00364     GCLReal result, rad4;
00365     Vector  temp;
00366 
00367     temp = p - Centre();
00368     
00369     result = dot(Normal(), temp);
00370     
00371     if (result <= 0)
00372         result = 0;
00373     else 
00374     {
00375         result *= -dot(np, temp);
00376         
00377         if (result <= 0)
00378             result = 0;
00379         else
00380         {
00381             rad4 = sqr(sqrlen(temp));
00382             result *= area;
00383             result /= (rad4 * vl_pi);
00384         }
00385     }
00386     
00387     return(result);
00388 }
00389 
00390 
00391 GCLReal RadElem::EdgeArea(const Vector &p, const Vector &q, const Vector &n)
00392 { 
00393     // Numerically stable edge-area calculator. (Including degenerate cases.)
00394     // Andrew J. Willmott, 1992
00395 
00396     // 4 dots, 1 cross, 1 atan per edge.
00397 
00398     const GCLReal epsilon = 1e-6;
00399     GCLReal sinFactor, qdotp, projArea;
00400 
00401     qdotp =  dot(p, q);
00402     sinFactor = sqrlen(p) * sqrlen(q) - sqr(qdotp);
00403 
00404     projArea = dot(-cross(p, q), n);
00405 
00406     if (sinFactor > 0)              
00407         // If SinFactor > 0 we may apply the formula without problem 
00408     {
00409         sinFactor = sqrt(sinFactor);
00410         return(projArea * (vl_halfPi - atan(qdotp / sinFactor)) / 
00411                (2 * vl_pi * sinFactor));
00412     }   
00413         // If not, we have three remaining cases... 
00414     else if (qdotp > epsilon)
00415         // CASE 1: p and q point in the same direction }
00416         return(0);
00417     else if (qdotp < -epsilon)
00418         // CASE 2: Viewpoint lies on the edge }
00419         return(0.5);
00420     else
00421         // CASE 3: Viewpoint lies at either end of the edge }
00422         return(0.125);
00423 }
00424 
00425 GCLReal RadElem::PatchFactor(const Point &p, const Vector &np)
00426 // Common terminology for this is the polygon-to-point form factor. 
00427 // The 'form-factor' mentioned in radiosity papers is the average
00428 // patch factor across a patch.
00429 {
00430     Vector  x1, x2, x3;
00431     GCLReal sum;
00432     
00433     x1 = Vertex(0);
00434     x1 -= p;
00435     x3 = x1;
00436     x2 = Vertex(1);
00437     x2 -= p;
00438     
00439     sum = EdgeArea(x1, x2, np);
00440     x1 = Vertex(2);
00441     x1 -= p;
00442     sum += EdgeArea(x2, x1, np);
00443     
00444     if (IsTri())
00445         sum += EdgeArea(x1, x3, np);
00446     else
00447     {
00448         x2 = Vertex(3);
00449         x2 -= p;
00450         sum += EdgeArea(x1, x2, np);
00451         sum += EdgeArea(x2, x3, np);
00452     }
00453 
00454     if (sum > 0.0)
00455         return(sum);
00456     else
00457         return(0.0);
00458 }
00459 
00460 GCLReal RadElem::ApproxPatchFactor(const Point &p, const Vector &np)
00461 // Uses point-to-point PF as default, and swaps to poly-to-point PF
00462 // when necessary.
00463 {
00464     GCLReal result, rad4, npt, res2;
00465     Vector  temp;
00466 
00467     temp = p - Centre();
00468     
00469     result = -dot(np, temp);
00470     
00471     if (result <= 0)
00472         result = 0;
00473     else 
00474     {
00475         npt = dot(Normal(), temp);
00476         
00477         if (npt <= 0)
00478             result = 0;
00479         else
00480         {
00481             rad4 = sqr(sqrlen(temp));
00482             result *= area / vl_pi;
00483             res2 = result * Max(npt, 0.25 * sqrt(area));
00484 
00485             if (gRadControl->quadLevel > 0 && rad4 * gRadControl->dFError < res2)
00486             {
00487                 // result is blowing up!
00488                 // let's bail to the patch factor formula
00489                 return(PatchFactor(p, np));
00490             }
00491             else
00492                 result *= npt / rad4;
00493         }
00494     }
00495     
00496     return(result);
00497 }
00498 
00499 GCLReal RadElem::EstFormFactor(RadElem *to)
00500 {
00501     GCLReal result, rad4, npt, res2;
00502     Vector  temp;
00503 
00504     temp = to->Centre() - Centre();
00505     
00506     result = -dot(to->Normal(), temp);
00507     
00508     if (result <= 0)
00509         result = 0;
00510     else 
00511     {
00512         npt = dot(Normal(), temp);
00513         
00514         if (npt <= 0)
00515             result = 0;
00516         else
00517         {
00518             rad4 = sqr(sqrlen(temp));
00519             result *= area / vl_pi;
00520             res2 = result * Max(npt, 0.25 * sqrt(area));
00521 
00522             if (gRadControl->quadLevel == 0 || rad4 * gRadControl->dFError >= res2)
00523                 result *= npt / rad4;
00524             else
00525             {
00526                 // result is blowing up!
00527                 // let's bail to the patch factor formula
00528 
00529                 GCLReal sum;
00530 
00531                 if (gRadControl->quadLevel > 1)
00532                 {
00533                     // use more-accurate PF estimate:
00534                     // sample corners
00535                     
00536                     sum = PatchFactor(to->Vertex(0), to->Normal());
00537                     sum += PatchFactor(to->Vertex(1), to->Normal());
00538                     sum += PatchFactor(to->Vertex(2), to->Normal());
00539                     sum += PatchFactor(to->Vertex(3), to->Normal());
00540                     
00541                     if (gRadControl->quadLevel > 2)
00542                     {
00543                         // estimate ff from tetrahedron constructed from
00544                         // corner samples and centre. this will
00545                         // underestimate the true ff slightly.
00546                         
00547                         sum += 2.0 * PatchFactor(to->Centre(), to->Normal());
00548                         sum /= 6.0;
00549                     }
00550                     else
00551                     // underestimate curve
00552                         sum /= 4.0;
00553                 }
00554                 else
00555                     sum = PatchFactor(to->Centre(), to->Normal());
00556                 
00557                 return(sum);
00558             }
00559         }
00560     }
00561     
00562     return(result);
00563 }
00564 
00565 GCLReal RadElem::SampledFormFactor(Int n, RadElem *to, GCLReal &error)
00569 {
00570     GCLReal sum, sample, min, max, rn;
00571     Point   destPt;
00572     Vector  dx =     to->Vertex(2) - to->Vertex(1);
00573     Vector  dy =     to->Vertex(0) - to->Vertex(1);
00574     Int     i, j;
00575     
00576     // use most-accurate PF estimate:
00577     // sample in a grid
00578     
00579     min = vl_inf;
00580     max = -vl_inf;
00581     sum = 0;
00582     rn = n;
00583     
00584     for (i = 0; i < n; i++)
00585         for (j = 0; j < n; j++)
00586         {
00587             destPt = to->Vertex(1);
00588             destPt += ((j + 0.5) / rn) * dx;
00589             destPt += ((i + 0.5) / rn) * dy;
00590         
00591             sample = ApproxPatchFactor(destPt, to->Normal());
00592             sum += sample;
00593             min = Min(min, sample);
00594             max = Max(max, sample);
00595         }
00596     
00597     error = max - min;
00598 
00599     return(sum / sqr(n));
00600 }
00601 
00602 Int RadElem::OrientInfo(RadElem *to)
00603 // Returns basic orientation info: 0 = centres of
00604 // patches are obscured, -1 = patches close enough
00605 // to warrant good PF approx, 1 = can use standard approx.
00606 {
00607     GCLReal result, rad4, npt, res2;
00608     Vector  temp;
00609 
00610     temp = to->Centre() - Centre();
00611     result = -dot(to->Normal(), temp);
00612     
00613     if (result <= 0)
00614         return(0);
00615     else 
00616     {
00617         npt = dot(Normal(), temp);
00618         
00619         if (npt <= 0)
00620             return(0);
00621         else
00622         {
00623             rad4 = sqr(sqrlen(temp));
00624             result *= area / vl_pi;
00625             res2 = result * Max(npt, 0.25 * sqrt(area));
00626 
00627             if (gRadControl->quadLevel > 0 &&
00628                 rad4 * gRadControl->dFError < res2)
00629                 return(-1);
00630             else
00631                 return(1);
00632         }
00633     }
00634 }
00635 
00636 Void RadElem::SetProps(RadProps *parentProps)
00637 {
00638     props = parentProps;
00639     Centre().MakeZero();
00640     
00641     centre += Vertex(0);
00642     centre += Vertex(1);
00643     centre += Vertex(2);
00644     if (IsQuad())
00645     {
00646         centre += Vertex(3);
00647         centre /= 4;
00648     }
00649     else
00650         centre /= 3;
00651 
00652     CalcTriAreaNormal(Vertex(0), Vertex(1), Vertex(2), normal);
00653     area = len(normal);
00654     if (area > 0)
00655         normal /= area;
00656     if (IsTri())
00657         area *= 0.5;
00658 
00659 #ifdef RAD_TEXTURE
00660     if (gRadControl->textureRefl && IsTextured())
00661         localRefl = props->texture->FilterBox(TexCoord(0), TexCoord(2));
00662     else
00663         localRefl = props->reflectance;
00664 #endif
00665 }
00666 
00667 Void RadElem::Reanimate(RadElem *parent)
00668 {
00669     if (parent)
00670         SetProps(parent->props);
00671 }
00672 
00673 Void RadElem::ColourVertices(Int weights[])
00674 {
00675     Int j;
00676     
00677     for (j = 0; j < Sides(); j++)
00678     {
00679         VtxClr(j) += colour;
00680         weights[clrIdx[j]] += 1;
00681     }   
00682 }
00683 
00684 Void RadElem::CreatePatches(PatchList &patches)
00685 {
00686     Assert(false, "(RadElem::CreatePatches) need grid for that.");
00687 }
00688 
00689 Void RadElem::RaiseVertex(Renderer &r, Int i)
00690 {
00691     Colour *c;
00692     
00693     if (gRadControl->gouraud)
00694         c = &VtxClr(i);
00695     else
00696         c = &colour;
00697 
00698     r.C(*c);
00699 
00700     if (HasNormals())
00701         r.P(Vertex(i) + dot(kRadRGBToLum, *c) * Normal(i));
00702     else    
00703         r.P(Vertex(i) + dot(kRadRGBToLum, *c) * Normal());
00704 }
00705 
00706 ostream &operator << (ostream &s, RadElem &rq)
00707 {
00708     rq.Print(s);
00709     return(s);
00710 }
00711 
00712 istream &operator >> (istream &s, RadElem &rq)
00713 {
00714     rq.Parse(s);
00715     return(s);
00716 }
00717 
00718 
00719 // --- Inter-elem visibility --------------------------------------------------
00720 
00721 
00722 // utility routines for patches only
00723 
00724 GCLReal RadElem::Visibility16(const Point &p, const Vector &n)
00725 //  Returns the fractional visibility of this patch from p.
00726 {
00727     Vector  temp;
00728     GCLReal d;
00729 
00730     // Is 'p' completely behind this patch?
00731     
00732     d = dot(Normal(), Centre());
00733     
00734     if (dot(p, Normal()) < d)
00735         return(0.0);
00736     
00737     // Is this patch completely behind p's plane?
00738         
00739     d = dot(n, p);
00740 
00741     if ((dot(Vertex(0), n) <= d)
00742             && (dot(Vertex(1), n) <= d)
00743             && (dot(Vertex(2), n) <= d)
00744             && (IsTri() || dot(Vertex(3), n) <= d))
00745         return(0.0);
00746         
00747     //  If neither is the case, we have at least partial
00748     //  visibility, so ray cast to estimate it
00749 
00750     return(RadVis16x1(p, n));   
00751 }
00752 
00753 GCLReal RadElem::CentreVis(const Point &p, const Vector &n)
00754 // Returns visibility of the centre of this patch from p.
00755 {
00756     Vector  temp;
00757     Point   dstPoint, srcPoint;
00758     GCLReal d;
00759     Bool    hit;
00760     
00761     // Is 'p' completely behind this patch?
00762     
00763     d = dot(Normal(), Centre());
00764     
00765     if ((dot(p, Normal())) <= d)
00766         return(0.0);
00767     
00768     // Is the centre of this patch behind p's plane?
00769         
00770     d = dot(n, p);
00771 
00772     if (dot(Centre(), n) <= d)
00773         return(0.0);
00774         
00775     //  If neither is the case, we have at least partial
00776     //  visibility, so ray cast to estimate it
00777 
00778     srcPoint = p;
00779     srcPoint += n * kRaySurfEps;
00780     dstPoint = Centre();
00781     dstPoint += Normal() * kRaySurfEps;
00782 
00783     hit = gRadControl->radObject->IntersectsWithRay(srcPoint, dstPoint);
00784     gRadControl->rays += 1;
00785 
00786 #ifdef RAD_VIS
00787     if (gRadControl->showRays)
00788     {
00789         if (hit)
00790             gRadControl->radObject->display->
00791                 Begin(renLines).C(cRed).P(srcPoint).P(dstPoint).End();
00792         else
00793             gRadControl->radObject->display->
00794                 Begin(renLines).C(cGreen).P(srcPoint).P(dstPoint).End();
00795     }
00796 #endif
00797 
00798     if (hit)
00799         return(0.0);
00800     else
00801         return(1.0);
00802 }
00803 
00804 Bool RadElem::PotentiallyVis(RadElem *to)
00805 // Checks to see whether any part of to is potentially visible
00806 // from this patch, and vice versa. 
00807 // returns true if there is potential visibility, false if not.
00808 {
00809     Vector  temp;
00810     GCLReal dFrom, dTo;
00811 
00812     // Is 'to' completely behind this patch?
00813     
00814     dFrom = dot(Normal(), Vertex(0));
00815     
00816     if ((dot(to->Vertex(0), Normal()) <= dFrom)
00817             && (dot(to->Vertex(1), Normal()) <= dFrom)
00818             && (dot(to->Vertex(2), Normal()) <= dFrom)
00819             && (to->IsTri() || dot(to->Vertex(3), Normal()) <= dFrom))
00820         return(false);
00821     
00822     // Is this patch completely behind 'to'?
00823         
00824     dTo =   dot(to->Normal(), to->Vertex(0));
00825 
00826     if ((dot(Vertex(0), to->Normal()) <= dTo)
00827             && (dot(Vertex(1), to->Normal()) <= dTo)
00828             && (dot(Vertex(2), to->Normal()) <= dTo)
00829             && (IsTri() || dot(Vertex(3), to->Normal()) <= dTo))
00830         return(false);
00831         
00832     //  If neither is the case, we have at least potential
00833     //  visibility.
00834 
00835     return(true);
00836 }
00837 
00838 Bool RadElem::PotentiallyVisAndTouching(RadElem *to, Bool &touching)
00839 // Checks to see whether any part of to is potentially visible
00840 // from this patch, and vice versa. 
00841 // returns true if there is potential visibility, false if not.
00842 // Also sets touching to true if the two patches intersect or touch.
00843 {
00844     Vector  temp;
00845     GCLReal dFrom, dTo, a;
00846     Bool    pvis, touch;
00847     Int     n, z, p;
00848     
00849     touching = false;
00850     dFrom = dot(Normal(), Vertex(0));
00851     n = p = z = 0;
00852 
00853     // we count p=points above plane, z=points on plane, n = points below plane.
00854     // pvis = at least 1 p1 coeff +ve && at least 1 p2 coeff +ve
00855     // touch: p1-touch && p2-touch
00856     // x-touch: x coeffs not all +ve or all -ve.
00857     // 
00858     
00859     // opt: can do early termination of touch as soon as z>0 or p&n
00860     //      can do early termination of pvis as soon as p>0
00861     //      can terminate both iff p>0 && (z>0 | n>0)
00862     //  currently don't do this 'cause extra testing might
00863     //  kill the optimisations, and I'm lazy...
00864     //
00865             
00866     a = dot(to->Vertex(0), Normal()) - dFrom;
00867     if (a > 0) p++; else if (a < 0) n++; else z++;
00868     a = dot(to->Vertex(1), Normal()) - dFrom;
00869     if (a > 0) p++; else if (a < 0) n++; else z++;
00870     a = dot(to->Vertex(2), Normal()) - dFrom;
00871     if (a > 0) p++; else if (a < 0) n++; else z++;
00872     if (to->IsQuad())
00873     {
00874         a = dot(to->Vertex(3), Normal()) - dFrom;
00875         if (a > 0) p++; else if (a < 0) n++; else z++;
00876     }
00877         
00878     pvis = p;
00879     touch = z || (p && n);
00880         
00881     if (!pvis && !touch)
00882         return(false);
00883 
00884     dTo =   dot(to->Normal(), to->Vertex(0));
00885     n = p = z = 0;
00886 
00887     a = dot(Vertex(0), to->Normal()) - dTo;
00888     if (a > 0) p++; else if (a < 0) n++; else z++;
00889     a = dot(Vertex(1), to->Normal()) - dTo;
00890     if (a > 0) p++; else if (a < 0) n++; else z++;
00891     a = dot(Vertex(2), to->Normal()) - dTo;
00892     if (a > 0) p++; else if (a < 0) n++; else z++;
00893     if (IsQuad())
00894     {
00895         a = dot(Vertex(3), to->Normal()) - dTo;
00896         if (a > 0) p++; else if (a < 0) n++; else z++;
00897     }
00898         
00899     if (touch && (z || (p && n)))
00900         touching = true;
00901     return(pvis & p);
00902 }
00903 
00904 GCLReal RadElem::Visibility44(RadElem *to)
00905 {
00906     if (PotentiallyVis(to))
00907         return(RadVis4x4(to));
00908     else
00909         return(0.0);
00910 }
00911 
00912 
00913 // --- Generic element->element visibility method -----------------------------
00914 
00915 GCLReal RadElem::Visibility(RadElem *to)
00916 {
00917     GCLReal result;
00918     
00919 #ifdef RAD_VIS
00920     if (gRadControl->showRays)
00921         RM_DISPLAY_START;
00922 #endif
00923 
00924     switch(gRadControl->visibility)
00925     {
00926     case vis_none:
00927         result = 1.0;
00928         break;
00929     case vis_1:
00930         result = CentreVis(to->Centre(), to->Normal());
00931         break;
00932     case vis_16x1:
00933         result = Visibility16(to->Centre(), to->Normal());
00934         break;
00935     case vis_4x4:
00936         result = Visibility44(to);
00937         break;
00938     default:
00939         Assert(false, "Illegal visibility method specified!");
00940     }
00941     
00942 #ifdef RAD_VIS
00943     if (gRadControl->showRays)
00944     {
00945         RM_DISPLAY_END;
00946         RM_OUT1("Visibility: " << result);
00947         if (RM_PAUSE) return(0);
00948     }
00949 #endif
00950 
00951     return(result);
00952 }
00953 
00954 
00955 // ----------------------------------------------------------------------------
00956 
00957 //  Arrays for jittered sampling; 4 x 4 source, 4 x 4 dest.
00958 
00959 static Int gRotPick = 0;
00960 
00961 /*  
00962     Routine: RadVis4x4
00963     Measures visibility between the patch and q.
00964     Returns visibility factor between 0 and 1. 
00965     Uses magic-square jittered 4x4 pattern, a la HR paper.
00966  */
00967 
00968 Void RadElem::SetVisPoints(Point *pts)
00969 {
00970     Int         i;
00971     Vector      dstHoriz, dstVert;
00972     Coord       *d1;
00973     
00974     dstVert =  Vertex(0) - Vertex(1);
00975     dstHoriz = Vertex(2) - Vertex(1);
00976 
00977     if (IsQuad())
00978         d1 = (Coord *) tSquareSamples16[gRotPick]; 
00979     else
00980         d1 = (Coord *) tTriangleSamples16[gRotPick];
00981 
00982     for (i = 0; i < 16; i++)
00983         pts[i] = Vertex(1);
00984 
00985     for (i = 0; i < 16; i++)
00986         pts[i] += d1[i][0] * dstHoriz +
00987             d1[i][1] * dstVert + kRaySurfEps * Normal();
00988     
00989     if (gRadControl->jitterRot)
00990         if (++gRotPick == kNumSampArrays)
00991             gRotPick = 0;
00992 }
00993 
00994 GCLReal RadElem::RadVis4x4(RadElem *to)
00995 {
00996     Int         i, misses;
00997     Point       srcPoint[16], dstPoint[16];
00998     Bool        hit;
00999             
01000     misses = 0;
01001     SetVisPoints(srcPoint);
01002     to->SetVisPoints(dstPoint);
01003     
01004     gRadControl->rays += 16;
01005     
01006     for (i = 0; i < 16; i++)
01007     {
01008         hit = gRadControl->radObject->IntersectsWithRay(srcPoint[i], dstPoint[i]);
01009         
01010         if (hit)
01011             misses++;
01012 
01013 #ifdef RAD_VIS
01014         if (gRadControl->showRays)
01015         {
01016             if (hit)
01017                 gRadControl->radObject->display->Begin(renLines).C(cRed).P(srcPoint[i]).
01018                     P(dstPoint[i]).End();
01019             else
01020                 gRadControl->radObject->display->Begin(renLines).C(cGreen).P(srcPoint[i]).
01021                     P(dstPoint[i]).End();
01022         }
01023 #endif
01024     }
01025                 
01026     return((16 - misses) * 1.0 / 16.0);
01027 }
01028 
01029 /*  
01030     Routine: RadVis16x1
01031     Measures visibility between the patch and point p by
01032     casting 16 rays between the two.
01033     Returns visibility factor between 0 and 1. 
01034     Uses magic-square jittered 4x4 pattern
01035  */
01036 
01037 GCLReal RadElem::RadVis16x1(const Point &p, const Vector &n)
01038 {
01039     Int         i, misses;
01040     Point       srcPoint[16], dstPoint;
01041     Bool        hit;
01042             
01043     SetVisPoints(srcPoint);
01044     dstPoint = p;
01045     dstPoint += kRaySurfEps * n;
01046     misses = 0;
01047 
01048     gRadControl->rays += 16;
01049     
01050     for (i = 0; i < 16; i++)
01051     {
01052         hit = gRadControl->radObject->IntersectsWithRay(srcPoint[i], dstPoint);
01053         
01054         if (hit)
01055             misses++;
01056 
01057 #ifdef RAD_VIS
01058         if (gRadControl->showRays)
01059         {
01060             if (hit)
01061                 gRadControl->radObject->display->
01062                     Begin(renLines).C(cRed).P(srcPoint[i]).P(dstPoint).End();
01063             else
01064                 gRadControl->radObject->display->
01065                     Begin(renLines).C(cGreen).P(srcPoint[i]).P(dstPoint).End();
01066         }
01067 #endif
01068     }
01069         
01070     return(GCLReal(16 - misses) / 16.0);
01071 }
01072 
01073 Coord RadElem::FindCoord(Point &p)
01074 {
01075     Point       origin;
01076     Vector      r;
01077     Coord       result;
01078     VecTrans    s, t;
01079     
01080     // construct a coordinate system about vertex 1 of the triangle/quad
01081     origin = Vertex(1);
01082     t[2] = Normal();
01083     t[1] = Vertex(0) - origin;
01084     t[0] = Vertex(2) - origin;
01085 
01086     // find transformation into that coord system...
01087     s = inv(t);
01088 
01089     // transform p
01090     r = p - origin;
01091     r *= s;
01092     
01093     // drop height and return
01094     return(Coord(r[0], r[1]));
01095 }
01096 
01097 Void RadElem::SetIndexes(
01098                 Int         dstIdx,       
01099                 RadElem     *src,       
01100                 Int         srcIdx
01101             )
01102 {
01103     index[dstIdx]   = src->index[srcIdx];   
01104     clrIdx[dstIdx]  = src->clrIdx[srcIdx];  
01105     normIdx[dstIdx] = src->normIdx[srcIdx]; 
01106     texIdx[dstIdx]  = src->texIdx[srcIdx];  
01107 }
01108 
01109 Void RadElem::SetAllIndexes(
01110                 RadElem     *s0,
01111                 Int         i0,       
01112                 RadElem     *s1,       
01113                 Int         i1,       
01114                 RadElem     *s2,       
01115                 Int         i2,
01116                 RadElem     *s3,
01117                 Int         i3
01118             )
01119 {
01120     index[0]   = s0->index[i0]; 
01121     index[1]   = s1->index[i1]; 
01122     index[2]   = s2->index[i2]; 
01123     index[3]   = s3->index[i3]; 
01124 
01125     clrIdx[0]  = s0->clrIdx[i0];    
01126     clrIdx[1]  = s1->clrIdx[i1];    
01127     clrIdx[2]  = s2->clrIdx[i2];    
01128     clrIdx[3]  = s3->clrIdx[i3];    
01129 
01130     normIdx[0] = s0->normIdx[i0];   
01131     normIdx[1] = s1->normIdx[i1];   
01132     normIdx[2] = s2->normIdx[i2];   
01133     normIdx[3] = s3->normIdx[i3];   
01134 
01135     texIdx[0]  = s0->texIdx[i0];    
01136     texIdx[1]  = s1->texIdx[i1];    
01137     texIdx[2]  = s2->texIdx[i2];    
01138     texIdx[3]  = s3->texIdx[i3];    
01139 }
01140 
01141 GCLReal RadElem::MemoryUse()
01142 {
01143     return(sizeof(SELF));
01144 }
01145 
01146 GCLReal NbRadElem::MemoryUse()
01147 {
01148     return(sizeof(SELF));
01149 }
01150 
01151 
01152 // --- Grid Subdivision -------------------------------------------------------
01153 
01186 Void GridBase::Mesh(GCLReal density)
01187 // Meshes an element into a grid of similar elements of roughly 
01188 // the given density.
01189 // XXX still need to re-fix non-lin density stuff
01190 {
01191     Int         i, j, in, jn;
01192     RadElem     child, child2, rowEnds;
01193     GCLReal     w, h, dw, dh;
01194     Int         im, jm;
01195     RadElemPtr  *lastRow, upperTri;
01196     Vector      u, v;
01197 
01198     //  Setup increments, step sizes, etc.
01199 
01200     if (gRadControl->mesh == mesh_random)
01201     {
01202         density = (0.1 + 0.9 * drand48()) * density;
01203     }
01204 
01205     u = Vertex(2) - Vertex(1);
01206     v = Vertex(0) - Vertex(1);
01207     
01208     in = (Int) ceil(len(v) * density);
01209     jn = (Int) ceil(len(u) * density);
01210     
01211     // For triangles we must subdivide equally in both directions.
01212     
01213     if (IsTri())            
01214     {
01215         if (jn < in)
01216             jn = in;
01217         else
01218             in = jn;
01219     }
01220     
01221     if (gRadControl->mesh != mesh_nonlin)
01222     {
01223         im = 0;
01224         jm = 0;
01225         w = 1.0 / jn;
01226         h = 1.0 / in;
01227         child.area = len(w) * len(h);
01228         if (IsTri())
01229             child.area *= 0.5;
01230         child2.area = child.area;   
01231         // child2 is always a triangle: it is not used for quad meshing.
01232     }
01233     else
01234     {
01235         if ((jn % 2) == 1)
01236             w = 4.0 / sqr(jn + 1);
01237         else
01238             w = 4.0 / (sqr(jn + 1) - 1);
01239             
01240         if ((in % 2) == 1)
01241             h = 4.0 / sqr(in + 1);
01242         else
01243             h = 4.0 / (sqr(in + 1) - 1);
01244 
01245         jm = jn;
01246         im = in;
01247         dw = w;
01248         dh = h;
01249     }
01250         
01251     // Set up templates for new elements
01252 
01253     lastRow = new RadElemPtr[jn];   
01254     child.index[3] = -1;
01255     child2.index[3] = -1;
01256             
01257     // Add the new quads/tri's to the grid in turn, from left to right,
01258     // and top to bottom. Each new quad or pair of tris will require a
01259     // new bottom-right vertex.         
01260 
01261     for (i = 0; i < in; i++)        
01262     {                               
01263         // find outermost bottom vertices of the row, so we can interpolate
01264         // between them while filling in the row. rowEnds:0 is the left-most
01265         // bottom vertex, rowEnds:1 is the right-most.
01266         rowEnds.props = props;
01267         if (i == in - 1)                
01268         // Special-case original bottom-left and bottom-right vertices.
01269         {
01270             rowEnds.SetIndexes(0, this, 1); 
01271             rowEnds.SetIndexes(1, this, 2); 
01272         }
01273         else
01274         {
01275             props->InterpolateIndexes(this, 0, 1, &rowEnds, 0, 
01276                 GCLReal(i + 1.0) / in);
01277             if (IsQuad())
01278                 props->InterpolateIndexes(this, 3, 2, &rowEnds, 1, 
01279                     GCLReal(i + 1.0) / in);
01280             else
01281                 props->InterpolateIndexes(this, 0, 2, &rowEnds, 1, 
01282                     GCLReal(i + 1.0) / in);
01283         }
01284 
01285         //  copy left-most into first quad/tri in the row
01286         child.SetIndexes(1, &rowEnds, 0);
01287         if (i == 0)
01288             child.SetIndexes(0, this, 0);
01289         else
01290             child.SetIndexes(0, lastRow[0], 1);
01291         
01292         if (jm > 0)
01293             w = dw;
01294         if (IsTri())
01295             jn = i + 1;
01296                 
01297         for (j = 0; j < jn; j++)
01298         //  Add one row of quads/tri's                      
01299         {
01300             // For each quad/tri, we must add the bottom-right corner as a new point.
01301             if (j == jn - 1)        
01302             // Special-case right-most quad/tri
01303                 child.SetIndexes(2, &rowEnds, 1);
01304             else
01305                 props->InterpolateIndexes(&rowEnds, 0, 1, &child, 2, 
01306                     Double(j + 1.0) / jn);
01307             
01308             if (IsTri())
01309             {               
01310                 //  For triangles: we add them in pairs. The first triangle...
01311                 child.SetProps(props);
01312                 if (jm > 0)
01313                 {
01314                     child.area = 0.5 * len(w) * len(h);
01315                     child2.area = child.area;
01316                 }
01317                 upperTri = lastRow[j];
01318                 lastRow[j] = AddChild(child, i, j, in, jn);
01319                 
01320                 if (j == i)         // if we're at the end of a triangle strip
01321                     break;          // break to the outer loop
01322                                 
01323                 //  then the second triangle.
01324 
01325                 // copy upper-right vertex from last row
01326                 child2.SetAllIndexes(&child, 2, upperTri, 2, &child, 0, this, 3);
01327                 child2.SetProps(props);
01328                 AddChild(child2, i, j, in, jn);
01329 
01330                 // Move on to next quad/tri pair: shift the indices left.
01331                 child.SetIndexes(0, &child2, 1);
01332                 child.SetIndexes(1, &child, 2);
01333             }
01334             else
01335             {       
01336                 //  For quads: we first find/copy upper-right vertex
01337 
01338                 if (i == 0)         
01339                 // first row -- can't borrow from row above
01340                 {
01341                     if (j == jn - 1)
01342                     // Special-case original top-right corner
01343                     {
01344                         child.SetIndexes(3, this, 3);
01345                     }
01346                     else
01347                     {
01348                         // interpolate between upper-left & upper right.
01349                         props->InterpolateIndexes(this, 0, 3, &child, 3, 
01350                             Double(j + 1.0) / jn);
01351                     }
01352                 }
01353                 else
01354                 {
01355                     // set to bottom-right vertex of quad above us
01356                     child.SetIndexes(3, lastRow[j], 2);
01357                 }
01358     
01359                 // And add the new quad...
01360     
01361                 if (jm > 0)
01362                     child.area = len(w) * len(h);
01363                 child.SetProps(props);
01364                 lastRow[j] = AddChild(child, i, j, in, jn);             
01365 
01366                 // Move on to next quad/tri pair: shift the indices left.
01367                 child.SetIndexes(0, &child, 3);
01368                 child.SetIndexes(1, &child, 2);
01369             }
01370             
01371             if (jm > 0)
01372             {
01373                 if (2 * (j + 1) < jm)
01374                     w += dw;
01375                 else if (2 * (j + 1) > jm)
01376                     w -= dw;
01377             }
01378         }
01379 
01380         // Move on to next row, resetting necessary variables
01381         
01382         if (im > 0)
01383         {
01384             if (2 * (i + 1) < im)
01385                 h += dh;
01386             else if (2 * (i + 1) > im)
01387                 h -= dh;
01388         }
01389     }
01390     
01391     rows = in;
01392     cols = jn;
01393     delete[] lastRow;
01394 }
01395 
01396 Int GridBase::FindChildIndex(Coord &coord)
01397 // which of the grid elements does the coord fall inside?
01398 // find its index, and modify coord to be in its local coord. system.
01399 {
01400     Int     x, y, xy;
01401     GCLReal rx, ry;
01402 
01403     rx = coord[0];
01404     ry = coord[1];
01405 
01406     // Do some bounds checking...
01407     if (IsTri())
01408     {
01409         if ((rx - ry) > 1 || rx < 0 || ry < 0)
01410             return(-1);
01411     }
01412     else
01413         if (rx < 0 || ry < 0 || rx > 1 || ry > 1)
01414             return(-1);
01415 
01416     // find rectangular grid coords
01417     rx *= cols;
01418     ry *= rows;
01419 
01420     x = (Int) rx;
01421     if (x == cols)
01422         x--;
01423     y = (Int) ry;
01424     if (y == rows)
01425         y--;    
01426 
01427     // find cell coords
01428     // our grid is numbered from the top down, hence the (rows - 1 - y)
01429     // terms below
01430 
01431     if (IsTri())
01432     { 
01433         xy = (Int) (rows * (rx + ry));
01434         if (xy == rows)
01435             xy--;   
01436 
01437         if (xy > x + y)
01438         // flipped triangle
01439         {
01440             coord[0] = x + 1 - rx;
01441             coord[1] = y + 1 - ry;
01442             x = 2 * x + 1;
01443         }
01444         else
01445         // normal triangle
01446         {
01447             coord[0] = rx - x;
01448             coord[1] = ry - y;
01449             x = 2 * x;
01450         }
01451 
01452         // number of picked cell
01453         return(x + sqr(rows - 1 - y));
01454     }
01455     else
01456     {       
01457         // quad case is much easier!
01458         coord[0] = rx - x;
01459         coord[1] = ry - y;
01460         
01461         return(x + (rows - 1 - y) * cols);
01462     }
01463 }
01464 
01465 // --- RadGrid methods ---------------------------------------------------------
01466 
01467 RadElemPtr RadGrid::AddChild(RadElem &elem, Int i, Int j, Int in, Int jn)
01468 {
01469     children.Append(elem);
01470 
01471     return(&children.Last());
01472 }
01473 
01474 Void RadGrid::Draw(Renderer &r)
01475 {   
01476     if (children.NumItems() > 0
01477 #ifdef RAD_VIS
01478          && !highlight
01479 #endif
01480      )
01481     {
01482         Int i;
01483         
01484         for (i = 0; i < children.NumItems(); i++)
01485             children[i].Draw(r);
01486     }
01487     else
01488         RadElem::Draw(r);
01489 }
01490 
01491 Void RadGrid::CreatePatches(PatchList &patches)
01492 {
01493     Int     i;
01494     
01495     if (gRadControl->patchSubdivs == 0.0)
01496     {
01497         patches.Append(this);
01498         rows = cols = 1;
01499         return;
01500     }
01501 
01502     children.Clear();
01503     Mesh(gRadControl->patchSubdivs);    
01504 
01505     for (i = 0; i < children.NumItems(); i++)
01506         patches.Append(&(children[i]));
01507 }
01508 
01509 RadElem *RadGrid::FindContainer(Coord &coord)
01510 {
01511     Int i = FindChildIndex(coord);
01512     
01513     return(children[i].FindContainer(coord));
01514 }
01515 
01516 Void RadGrid::ColourVertices(Int weights[])
01517 {
01518     Int i;
01519     
01520     for (i = 0; i < children.NumItems(); i++)
01521         children[i].ColourVertices(weights);
01522 }
01523 
01524 StrConst RadGrid::Name()
01525 {
01526     return("grid");
01527 }
01528 
01529 Void RadGrid::Print(ostream &s)
01530 {
01531     RadElem::Print(s);
01532     s << rows << ' ' << cols << ' ' << children << ' ';
01533 }
01534 
01535 Void RadGrid::Parse(istream &s)
01536 {
01537     Char c;
01538     Int i;
01539     
01540     RadElem::Parse(s);
01541     
01542     s >> rows >> cols;
01543     
01544     children.SetSize(rows * cols);
01545 
01546     ChompWhiteSpace(s); 
01547     s.get(c);
01548     for (i = 0; i < children.NumItems(); i++)
01549         children[i].Parse(s);
01550     ChompWhiteSpace(s);
01551     s.get(c);
01552 }
01553 
01554 Void RadGrid::Reanimate(RadElem *parent)
01555 {
01556     Int i;
01557 
01558     RadElem::Reanimate(parent);
01559 
01560     for (i = 0; i < children.NumItems(); i++)
01561         children[i].Reanimate(this);
01562 }
01563 
01564 GCLReal RadGrid::MemoryUse()
01565 {
01566     sGridMem += sizeof(SELF);
01567     sGridChildMem += sizeof(RadElem) * children.NumItems();
01568     return(sizeof(SELF) + sizeof(RadElem) * children.NumItems());
01569 }
01570 
01571 
01572 // --- RadProps methods -------------------------------------------------------
01573 
01574 
01575 RadProps::RadProps() : points(0), colours(0), normals(0), texCoords(0),
01576     texture(0)
01577 {
01578 }
01579 
01580 Void RadProps::InterpolateIndexes(
01581                 RadElem *srcElt, 
01582                 Int     srcVtx1, 
01583                 Int     srcVtx2, 
01584                 RadElem *dstElt, 
01585                 Int     dstVtx,
01586                 GCLReal m
01587             )
01588 {
01589     GCLReal     mc = 1.0 - m;
01590 
01591     // do interpolation
01592     
01593     points->Append(srcElt->Vertex(srcVtx1) * mc + srcElt->Vertex(srcVtx2) * m);
01594     dstElt->index[dstVtx] = points->NumItems() - 1;
01595 
01596     colours->Append(srcElt->VtxClr(srcVtx1) * mc + srcElt->VtxClr(srcVtx2) * m);
01597     dstElt->clrIdx[dstVtx] = colours->NumItems() - 1;
01598 
01599     if (normals)
01600     {
01601         normals->Append(srcElt->Normal(srcVtx1) * mc + srcElt->Normal(srcVtx2) * m);
01602         dstElt->normIdx[dstVtx] = normals->NumItems() - 1;
01603     }
01604     
01605     if (texCoords)
01606     {
01607         texCoords->Append(srcElt->TexCoord(srcVtx1) * mc
01608             + srcElt->TexCoord(srcVtx2) * m);
01609         dstElt->texIdx[dstVtx] = texCoords->NumItems() - 1;
01610     }
01611 }

Generated at Sat Aug 5 00:26:53 2000 for Radiator by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000