00001 /*
00002 File: HRElem.cc
00003
00004 Function: Defines the element type used by the various hierarchical
00005 radiosity methods.
00006
00007 Author: Andrew Willmott
00008
00009 Notes:
00010 */
00011
00012 #include "HRElem.h"
00013 #include "RadMethod.h"
00014 #include "gcl/SceneLang.h"
00015 #include "gcl/GLRenderer.h"
00016
00017 #ifdef RAD_VIS
00018 #include "gcl/ScenePane.h"
00019 #endif
00020
00021 // --- HRElem methods ---------------------------------------------------------
00022
00023 UInt32 HRElem::gID = 0;
00024
00025 HRElem::HRElem() :
00026 #ifdef RAD_VIS
00027 eltParent(0),
00028 eltHighlight(0),
00029 #endif
00030 id(gID++),
00031 flags()
00032 {
00033 }
00034
00035 HRElem::~HRElem()
00036 {
00037 Reset();
00038 }
00039
00040 Void HRElem::Reset()
00041 {
00042 links.Free();
00043 }
00044
00045 Void HRElem::DrawElem(Renderer &r)
00046 {
00047 DrawNodeElem(r);
00048 }
00049
00050 // XXX shift?
00051
00052 Void DrawArrow(Renderer &r, Point start, Point end)
00053 {
00054 static scPrimitive *sCone = 0;
00055 static scPrimitive *sShaft = 0;
00056 const Double ac = 0.1;
00057 const Double as = ac / 5.0;
00058
00059 GCLReal al = len(end - start);
00060 GLRenderer &glr = (GLRenderer &) r;
00061 Transform trans;
00062
00063 if (al < 1e-15)
00064 return;
00065
00066 if (!sCone)
00067 {
00068 sCone = slGetLibrary()->Member("cone");
00069 sShaft = slGetLibrary()->Member("cylinder");
00070 }
00071
00072 glr.SetHeadlight(true);
00073
00074 #ifdef OFF
00075 r.C(cYellow).Begin(renLines);
00076 r.P(start).P(end);
00077 r.End();
00078 #endif
00079
00080 r.C(cWhite);
00081 r.Push();
00082 trans = Shift(end) * AlignToDir(end - start);
00083 r.SetTransform(trans);
00084
00085 r.Push();
00086 trans = Shift(-ac * Vector(vl_y)) * Scale(Vector(as, al - ac, as)) * Shift(-0.5 * Vector(vl_y));
00087 r.SetTransform(trans);
00088 sShaft->Draw(r);
00089 r.Pop();
00090
00091 r.Push();
00092 trans = Scalef(ac) * Shift(-Vector(vl_y));
00093 r.SetTransform(trans);
00094 sCone->Draw(r);
00095 r.Pop();
00096
00097 r.Pop();
00098 glr.SetHeadlight(false);
00099 }
00100
00101 Void HRElem::DrawContributors(Renderer &r)
00102 {
00103 HRLinkIter iter;
00104
00105 for (iter.Begin(links); !iter.AtEnd(); iter.Inc())
00106 DrawArrow(r, iter.Data().from->EltCentre(), iter.Data().to->EltCentre());
00107
00108 for (iter.Begin(links); !iter.AtEnd(); iter.Inc())
00109 {
00110 iter.Data().from->DrawLeafElem(r);
00111 iter.Data().from->flags.Set(hrMark);
00112 }
00113 }
00114
00115 Void HRElem::DrawContributorsRec(Void *r)
00116 {
00117 Int i;
00118
00119 DrawContributors(*(Renderer*) r);
00120 ApplyToChildren(&HRElem::DrawContributorsRec, r);
00121 }
00122
00123 Void HRElem::DrawMatrix(Renderer &r, Int baseNum)
00124 {
00125 DMInfo info;
00126
00127 info.r = &r;
00128 info.baseNum = baseNum;
00129 DrawMatrixRec(&info);
00130 }
00131
00132 Void HRElem::DrawMatrixRec(Void *dmi)
00133 {
00134 }
00135
00136 Void HRElem::DistributeColours()
00137 {
00138 }
00139
00140 Void HRElem::DistributeColoursBest(ShadeInfo &shadeInfo)
00141 {
00142 }
00143
00144 // --- Link Refinement --------------------------------------------------------
00145
00146 //#define RAD_VIS_LINKS
00147 // doesn't seem to have turned out to be all that useful?
00148
00149 Bool HRElem::RefineLink(HRLink *link, Int levels)
00152 {
00153 Int i, j, which;
00154 GCLReal factor, visibility;
00155
00156 // CreateSubLink() returns null if the link carries no energy, so
00157 // return if that's the case.
00158 if (link == 0)
00159 return(false);
00160
00161 if (levels-- == 0)
00162 {
00163 links.Prepend(link);
00164 return(false);
00165 }
00166
00167 which = link->RefineOracle();
00168
00169 #ifdef RAD_VIS_LINKS
00170 if (gRadControl->showLinks)
00171 {
00172 RM_DISPLAY_START;
00173 gRadControl->radObject->display->Begin(renLines);
00174 }
00175 #endif
00176
00177 if (which == kSubNone) // Form link here.
00178 {
00179 links.Prepend(link);
00180
00181 #ifdef RAD_VIS_LINKS
00182 if (gRadControl->showLinks)
00183 {
00184 gRadControl->radObject->display->
00185 C(cRed).P(EltCentre()).P(link->from->EltCentre()).End();
00186 RM_DISPLAY_END;
00187 RM_OUT1("Forming link here.");
00188 if (RM_PAUSE) return(false);
00189 }
00190 #endif
00191 return(false);
00192 }
00193 else if (which == kSubTo) // Subdivide 'to' patch (this one!)
00194 {
00195 #ifdef RAD_VIS_LINKS
00196 if (gRadControl->showLinks)
00197 {
00198 gRadControl->radObject->display->
00199 C(cGreen).P(EltCentre()).P(link->from->EltCentre());
00200 RM_DISPLAY_END;
00201 RM_OUT1("Pushing link down to children of receiver");
00202 if (RM_PAUSE) return(false);
00203 }
00204 #endif
00205 MakeChildLinks(link->from, link, which, levels);
00206 }
00207 else if (which == kSubFrom) // Subdivide 'from' patch
00208 {
00209 #ifdef RAD_VIS_LINKS
00210 if (gRadControl->showLinks)
00211 {
00212 gRadControl->radObject->display->
00213 C(cBlue).P(EltCentre()).P(link->from->EltCentre()).End();
00214 RM_DISPLAY_END;
00215 RM_OUT1("Pushing link down to children of source");
00216 if (RM_PAUSE) return(false);
00217 }
00218 #endif
00219 link->from->MakeChildLinks(this, link, which, levels);
00220 }
00221 else if (which == kSubBoth) // Subdivide both patches
00222 {
00223 #ifdef RAD_VIS_LINKS
00224 if (gRadControl->showLinks)
00225 {
00226 gRadControl->radObject->display->
00227 C(cYellow).P(EltCentre()).P(link->from->EltCentre()).End();
00228 RM_DISPLAY_END;
00229 RM_OUT1("Pushing link down to children of source & dest");
00230 if (RM_PAUSE) return(false);
00231 }
00232 #endif
00233 MakeChildLinks(link->from, link, which, levels);
00234 }
00235
00236 link->FreeLink(link);
00237
00238 return(true);
00239 }
00240
00241 Bool HRElem::Refine()
00244 {
00245 Bool result = false;
00246 RefineFurther(&result);
00247 return(result);
00248 }
00249
00250 Void HRElem::RefineFurther(Void *result)
00251 {
00252 HRLinkIter i;
00253 Int j, which;
00254 Bool split;
00255 HRLinkList oldLinks;
00256 HRLink *tempLink, *rlink;
00257
00258 // bottom-up traversal to avoid refining a link more than once.
00259 ApplyToChildren(&HRElem::RefineFurther, result);
00260
00261 rlink = (HRLink*) links.first;
00262 links.first = 0;
00263
00264 // Step through links, see whether any should be pushed down the hierarchy.
00265 while (rlink)
00266 {
00267 tempLink = rlink;
00268 rlink = (HRLink*) rlink->next;
00269 if (RefineLink(tempLink, gRadControl->refineLevels))
00270 *(Bool*) result = true;
00271 }
00272 }
00273
00274 Void HRStats::Init()
00275 {
00276 numLinks = 0;
00277 numPatches = 0;
00278 numVolClusters = 0;
00279 numFaceClusters = 0;
00280 numAliens = 0;
00281 }
00282
00283 Void HRElem::CalcStats(Void *statsIn)
00284 {
00285 HRLinkIter i;
00286 HRStats *stats = (HRStats*) statsIn;
00287
00288 for (i.Begin(links); !i.AtEnd(); i.Inc())
00289 stats->numLinks++;
00290
00291 if (IsPatch())
00292 stats->numPatches++;
00293 else if (IsCluster())
00294 stats->numVolClusters++;
00295 else if (IsFaceClus())
00296 stats->numFaceClusters++;
00297 else
00298 stats->numAliens++;
00299
00300 ApplyToChildren(&HRElem::CalcStats, statsIn);
00301 }
00302
00303 ostream *HRElem::out = &cout;
00304
00305 Void HRElem::DumpHierarchy(Void *v)
00306 // dump the element hierarchy
00307 {
00308 if (v)
00309 {
00310 // just printing a list of child IDs
00311 *out << id << ' ';
00312 return;
00313 }
00314
00315 // dump from leaves to root
00316 ApplyToChildren(&HRElem::DumpHierarchy);
00317
00318 HRLinkIter i;
00319 // elt. format: e ID [childID1 childID2...]
00320 *out << "e " << id << ' ';
00321 ApplyToChildren(&HRElem::DumpHierarchy, this);
00322 *out << endl;
00323 // link format: L toEltID fromEltID transferCoeff
00324 for (i.Begin(links); !i.AtEnd(); i.Inc())
00325 *out << "L " << id << " " << i.Data().from->id
00326 << ' ' << i.Data().Strength() << endl;
00327 }
00328
00329 Void HRElem::Gather()
00330 {
00331 HRLinkIter i;
00332
00333 ClearR();
00334
00335 for (i.Begin(links); !i.AtEnd(); i.Inc())
00336 {
00337 i.Data().Gather();
00338
00339 #ifdef RAD_VIS_LINKS
00340 // YYY replace with arrow sometime?
00341 if (gRadControl->showLinks)
00342 gRadControl->radObject->display->Begin(renLines)
00343 .C(cRed).P(EltCentre()).P(i.Data().from->EltCentre())
00344 .End();
00345 #endif
00346 }
00347 }
00348
00349 Void HRElem::GatherAll(Void *)
00350 {
00351 ApplyToChildren(&HRElem::GatherAll);
00352 Gather(); // Gather radiosity across all links to this patch into R
00353 }
00354
00355 #ifdef RAD_VIS
00356
00357 Void HRElem::PushPull(Void *)
00358 {
00359 Int i;
00360
00361 if (gRadControl->animate)
00362 {
00363 SetHighlight(0);
00364 if (RM_PAUSE) return;
00365 }
00366
00367 Add();
00368
00369 if (gRadControl->animate)
00370 RM_DISPLAY_SCENE;
00371
00372 if (!IsLeaf())
00373 {
00374 if (gRadControl->animate)
00375 {
00376 if (RM_PAUSE) return;
00377 }
00378
00379 Push();
00380
00381 ApplyToChildren(&HRElem::PushPull);
00382
00383 if (gRadControl->animate)
00384 {
00385 SetHighlight(1);
00386 SetHighlight(0);
00387
00388 if (RM_PAUSE) return;
00389 }
00390
00391 Pull();
00392
00393 if (gRadControl->animate)
00394 RM_DISPLAY_SCENE;
00395 }
00396 else
00397 CalcLeafRadiosity();
00398 }
00399
00400 #else
00401
00402 Void HRElem::PushPull(Void *)
00403 {
00404 Int i;
00405
00406 // Add R in to B: accumulated radiosity from this and higher levels
00407 Add();
00408
00409 if (!IsLeaf())
00410 {
00411 // Push B down to children's B's
00412 Push();
00413 // recurse
00414 ApplyToChildren(&HRElem::PushPull);
00415 // Pull radiosity back up
00416 Pull();
00417 }
00418 else
00419 CalcLeafRadiosity();
00420 }
00421 #endif
00422
00423 GCLReal HRElem::EltVisToPoint(Point &p)
00424 {
00425 Int i, misses;
00426 Point srcPoint[16];
00427 Bool hit;
00428
00429 if (gRadControl->visibility == vis_none)
00430 return(1.0);
00431
00432 misses = 0;
00433 EltSetVisPoints(0, srcPoint);
00434
00435 #ifdef RAD_VIS
00436 if (gRadControl->showRays)
00437 RM_DISPLAY_START;
00438 #endif
00439
00440 gRadControl->rays += 16;
00441
00442 for (i = 0; i < 16; i++)
00443 {
00444 hit = gRadControl->radObject->IntersectsWithRay(srcPoint[i], p);
00445
00446 if (hit)
00447 misses++;
00448
00449 #ifdef RAD_VIS
00450 if (gRadControl->showRays)
00451 {
00452 if (hit)
00453 gRadControl->radObject->display->Begin(renLines).C(cRed).P(srcPoint[i]).
00454 P(p).End();
00455 else
00456 gRadControl->radObject->display->Begin(renLines).C(cGreen).P(srcPoint[i]).
00457 P(p).End();
00458 }
00459 #endif
00460 }
00461
00462 #ifdef RAD_VIS
00463 if (gRadControl->showRays)
00464 {
00465 RM_DISPLAY_END;
00466 RM_OUT1("Visibility: " << GCLReal(16 - misses) * 1.0 / 16.0);
00467 if (RM_PAUSE) return(0);
00468 }
00469 #endif
00470
00471 return((16 - misses) * (1.0 / 16.0));
00472 }
00473
00474 GCLReal HRElem::EltVis(HRElem *to)
00475 {
00476 Int i, misses;
00477 Point srcPoint[16], dstPoint[16];
00478 Bool hit;
00479
00480 if (gRadControl->visibility == vis_none || to == this)
00481 return(1.0);
00482
00483 misses = 0;
00484 EltSetVisPoints(to, srcPoint);
00485 to->EltSetVisPoints(this, dstPoint);
00486
00487 #ifdef RAD_VIS
00488 if (gRadControl->showRays)
00489 RM_DISPLAY_START;
00490 #endif
00491
00492 gRadControl->rays += 16;
00493
00494 for (i = 0; i < 16; i++)
00495 {
00496 hit = gRadControl->radObject->IntersectsWithRay(srcPoint[i], dstPoint[i]);
00497
00498 if (hit)
00499 misses++;
00500
00501 #ifdef RAD_VIS
00502 if (gRadControl->showRays)
00503 {
00504 if (hit)
00505 gRadControl->radObject->display->Begin(renLines).C(cRed).P(srcPoint[i]).
00506 P(dstPoint[i]).End();
00507 else
00508 gRadControl->radObject->display->Begin(renLines).C(cGreen).P(srcPoint[i]).
00509 P(dstPoint[i]).End();
00510 }
00511 #endif
00512 }
00513
00514 #ifdef RAD_VIS
00515 if (gRadControl->showRays)
00516 {
00517 RM_DISPLAY_END;
00518 RM_OUT1("Visibility: " << GCLReal(16 - misses) * 1.0 / 16.0);
00519 if (RM_PAUSE) return(0);
00520 }
00521 #endif
00522
00523 return((16 - misses) * (1.0 / 16.0));
00524 }
00525
00526 Colour HRElem::EltBA()
00528 {
00529 return(B_Coeffs()[0] * EltArea());
00530 }
00531
00532 Void HRElem::InitRad()
00533 {
00534 ClearB();
00535 CalcLeafRadiosity();
00536 }
00537
00538 Void HRElem::AddChanIrradiance(const Colour &E, Int chan)
00539 {
00540 Colour c(vl_0);
00541 Vector m;
00542
00543 c[chan] = 1.0;
00544 ConvertVec(E, m);
00545
00546 AddIrradiance(c, m);
00547 }
00548
00549 GCLReal HRElem::EltMaxProjArea(const Vector &v)
00550 {
00551 return(EltProjArea(v));
00552 }
00553
00554 Void HRElem::DebugInfo()
00555 {
00556 HRLinkIter i;
00557
00558 cout << "radiosity = " << B_Coeffs()[0] << endl;
00559 cout << "rho = " << EltRho() << endl;
00560 cout << "flags = " << flags << endl;
00561 for (i.Begin(links); !i.AtEnd(); i.Inc())
00562 i.Data().DebugInfo();
00563 }
00564
00565
00566 GCLReal VecError(const SubVecd &v)
00567 {
00568 GCLReal min, max;
00569 Int i;
00570
00571 if (v[0] < v[1])
00572 {
00573 min = v[0];
00574 max = v[1];
00575 }
00576 else
00577 {
00578 min = v[1];
00579 max = v[0];
00580 }
00581
00582 for (i = 2; i < v.Elts(); i++)
00583 if (v[i] < min)
00584 min = v[i];
00585 else if (v[i] > max)
00586 max = v[i];
00587
00588 return(max - min);
00589 }
00590
00591
00592 ShadeInfo::ShadeInfo() : linkStack(), level(0), data(0)
00593 {
00594 }
00595