00001 /*
00002 File: RadMethod.cc
00003
00004 Function: See header file
00005
00006 Author(s): Andrew Willmott
00007
00008 Copyright: (c) 1997-2000, Andrew Willmott
00009
00010 Notes:
00011
00012 */
00013
00014 #include "RadMethod.h"
00015
00016 #include "fstream.h"
00017 #include <stdio.h>
00018 #include <sys/time.h>
00019 #include <sys/resource.h>
00020
00021 #include "cl/String.h"
00022 #include "gcl/VertexJoin.h"
00023 #include "gcl/MRModel.h"
00024 #include "gcl/SceneLang.h"
00025
00026 #include "MeshJoin.h"
00027
00028 #ifdef RAD_VIS
00029 #include "gcl/XGraphicsSystem.h"
00030 #include "RadScene.h"
00031 #endif
00032
00033 #ifdef DEBUG
00034 #define DBG_COUT cerr
00035 //#define RAD_HIST
00036 #else
00037 #define DBG_COUT if (0) cerr
00038 #endif
00039
00041 #define RAD_TLD
00043 #define RAD_TLD_DELTA 1.0
00044
00045 // --- Base radiosity method class --------------------------------------------
00046
00047 RadAttributes::RadAttributes() :
00048 points(0),
00049 colours(0),
00050 normals(0),
00051 texCoords(0)
00052 {
00053 }
00054
00055 RadMethod::RadMethod() :
00056 #ifdef RAD_VIS
00057 doUpdate(false),
00058 display(0),
00059 gsP(0),
00060 #endif
00061 RadAttributes(),
00062 grid(0),
00063 object(0),
00064 props(0),
00065 scene(0)
00066 {
00067 gRadControl->radObject = this;
00068 }
00069
00070 RadMethod::~RadMethod()
00071 {
00072 delete grid;
00073 delete scene;
00074 }
00075
00076 scScenePtr RadMethod::GetScene()
00077 {
00078 #ifdef RAD_VIS
00079 if (!scene)
00080 {
00081 scRadMesh *rm = new scRadMesh;
00082 rm->SetMethod(this);
00083 scene = slBeginObject("rad mesh scene");
00084 slObject(rm);
00085 slEndObject();
00086 }
00087 #endif
00088 return(scene);
00089 }
00090
00091
00092 class RadElemBuilder : public Decimator
00093 {
00094 public:
00095 RadElemBuilder(RadMethod *rm) : method(rm) {};
00096
00097 Void HandlePoly(Int numVertices, Int vertices[], Int changed)
00098 { method->AddQuadTri(numVertices, vertices, changed, this); };
00099
00100 RadMethod *method;
00101 };
00102
00103 Void RadMethod::SetScene(scScenePtr theScene)
00104 {
00105 // We convert the scene into a quad-tri mesh
00106
00107 Int i;
00108 UInt32 decFlags;
00109
00110 DBG_COUT << "setting scene" << endl;
00111
00112 delete props;
00113
00114 baseElems.FreeAll();
00115 baseElems.Clear();
00116
00117 #ifdef RAD_VIS
00118 Field(out1) << "Creating radiosity elements" << endl;
00119 #else
00120 GCLReal saveComplexity = scMRModel::GetComplexity();
00121 scMRModel::SetComplexity(gRadControl->meshComplexity);
00122 #endif
00123
00124 sceneName = theScene->Label();
00125 decFlags = DecTris | DecQuads;
00126 theScene->Decimate(qtInfo, decFlags);
00127
00128 DBG_COUT << "scene has " << qtInfo.numProps << " materials, "
00129 << qtInfo.numPolys << " base elems." << endl;
00130 DBG_COUT << "qtinfo [tqp props]: " << qtInfo.numTris << ' ' << qtInfo.numQuads <<
00131 ' ' << qtInfo.numPolys << ' ' << qtInfo.numProps << endl;
00132
00133 if (!colours)
00134 colours = new ColourList;
00135 // if (!normals)
00136 // normals = new VectorList;
00137 props = new RadProps[qtInfo.numProps];
00138 numProps = 0;
00139 gRadControl->numPolys = qtInfo.numPolys;
00140
00141 // build element list
00142 RadElemBuilder elemBuilder(this);
00143 theScene->Decimate(elemBuilder, decFlags | DecUseMaster);
00144 // set up the mesh!
00145 SetupMesh();
00146
00147 // set up raytracing
00148 #ifndef RAD_VIS
00149 scMRModel::SetComplexity(gRadControl->rtComplexity);
00150 #endif
00151 CreateRTGrid(theScene);
00152 #ifndef RAD_VIS
00153 scMRModel::SetComplexity(saveComplexity);
00154 #endif
00155
00156 // Setup elements and method-specific stuff
00157 ResetOptions();
00158 }
00159
00160 Void RadMethod::ResetOptions()
00161 {
00162 gRadControl->finalPass = false;
00163 CreatePatches();
00164 ColourMeshInitial();
00165 ColourVertices();
00166
00167 #ifdef RAD_VIS
00168 gRadControl->pvData = 0;
00169 Field(out1) << patches.NumItems() << " patches." << show;
00170 #endif
00171 }
00172
00173 Void RadMethod::AddQuadTri(
00174 Int numVertices,
00175 Int vertices[],
00176 Int changed,
00177 Decimator *state
00178 )
00179 {
00180 if (numVertices == DEC_End)
00181 {
00182 // we're cooked: grab the master point list
00183 points = state->pointsAcc;
00184 return;
00185 }
00186 else if (numVertices < 0) return;
00187
00188 Int i;
00189 RadElem *elem = NewMesh();
00190 RadProps *elemProps;
00191
00192 elem->index[3] = -1;
00193 Assert(numVertices <= 4, "too many vertices!");
00194
00195 for (i = 0; i < numVertices; i++)
00196 {
00197 elem->index[i] = vertices[i];
00198 elem->clrIdx[i] = vertices[i];
00199 }
00200
00201 if (changed)
00202 {
00203 SetupProps(props + numProps, state);
00204 numProps++;
00205 }
00206
00207 elemProps = props + (numProps - 1);
00208
00209 if (elemProps->texture && elemProps->texCoords)
00210 {
00211 IndexList *coordIndexes = 0;
00212
00213 // XXX
00214 //DEC_GET(CoordIndexes);
00215
00216 if (coordIndexes)
00217 for (i = 0; i < numVertices; i++)
00218 elem->texIdx[i] = coordIndexes->Item(i);
00219 else
00220 for (i = 0; i < numVertices; i++)
00221 elem->texIdx[i] = i;
00222 }
00223
00224 elem->SetProps(elemProps);
00225 baseElems.Append(elem);
00226 }
00227
00228 // --- Setup routines ---------------------------------------------------------
00229
00230 Void RadMethod::SetupMesh()
00231 {
00232 Int i;
00233
00234 // Given 'baseElems', sets up other necessary stuff.
00235
00236 // Find bounds of our scene...
00237 FindBounds(min, max);
00238
00239 // fix the mesh if necessary. (Make sure that vertices are shared.)
00240 if (gRadControl->fixMesh)
00241 FixMesh();
00242
00243 // Connect up the mesh: find adjacency info & use it to determine
00244 // placement of shared colours & normals.
00245 if (gRadControl->connectMesh)
00246 ConnectMesh();
00247 else
00248 {
00249 colours->SetSize(points->NumItems());
00250 if (normals)
00251 normals->SetSize(points->NumItems());
00252 }
00253
00254 // Now, reset all the prop references...
00255 for (i = 0; i < numProps; i++)
00256 {
00257 props[i].points = points;
00258 props[i].colours = colours;
00259 props[i].normals = normals;
00260 }
00261
00262 // should we be collapsing normIdx/clrIdx?
00263 for (i = 0; i < baseElems.NumItems(); i++)
00264 {
00265 baseElems[i]->normIdx[0] = baseElems[i]->clrIdx[0];
00266 baseElems[i]->normIdx[1] = baseElems[i]->clrIdx[1];
00267 baseElems[i]->normIdx[2] = baseElems[i]->clrIdx[2];
00268 baseElems[i]->normIdx[3] = baseElems[i]->clrIdx[3];
00269 }
00270 AssignNormals();
00271
00272 DBG_COUT << "mesh has " << points->NumItems() << " vertices, "
00273 << colours->NumItems() << " colours";
00274 if (normals)
00275 DBG_COUT << ", " << normals->NumItems() << " vertex normals" << endl;
00276 DBG_COUT << endl;
00277
00278 }
00279
00280 Void RadMethod::FixMesh()
00281 {
00282 VertexJoin joiner;
00283 Int i, m;
00284
00285 DBG_COUT << "sharing vertices..." << endl;
00286
00287 joiner.Init(min, max, points->NumItems());
00288
00289 for (i = 0; i < baseElems.NumItems(); i++)
00290 for (m = 0; m < baseElems[i]->Sides(); m++)
00291 {
00292 baseElems[i]->index[m] = joiner.AddVertex(baseElems[i]->Vertex(m));
00293 baseElems[i]->clrIdx[m] = baseElems[i]->index[m];
00294 }
00295
00296 DBG_COUT << "old points: " << points->NumItems() << endl;
00297 delete points;
00298 points = joiner.GetFinalVertexList();
00299 DBG_COUT << "new points: " << points->NumItems() << endl;
00300
00301 DBG_COUT << "done." << endl;
00302
00303 #ifdef CL_CHECKING
00304 // mesh consistency check...
00305
00306 Int j, k, a, b;
00307 NbRadElem *be, *nb;
00308
00309 DBG_COUT << "checking mesh..." << endl;
00310 for (i = 0; i < baseElems.NumItems(); i++)
00311 {
00312 be = (NbRadElem*) baseElems[i];
00313 for (j = 0; j < 3; j++)
00314 if (be->nbFace[j])
00315 {
00316 nb = be->nbFace[j];
00317 k = (j + 1) % 3;
00318 a = be->nbEdge[j];
00319 b = (a + 1) % 3;
00320
00321 Assert(baseElems[i]->index[j] == nb->index[b], "1st vertices");
00322 Assert(baseElems[i]->index[k] == nb->index[a], "2nd vertices");
00323 }
00324 }
00325 DBG_COUT << "done." << endl;
00326 #endif
00327 }
00328
00329 Void RadMethod::ConnectMesh()
00330 {
00331 MeshJoin meshJoiner;
00332 Int i;
00333
00334 DBG_COUT << "connecting mesh..." << endl;
00335
00336 meshJoiner.Init(points->NumItems());
00337 meshJoiner.StartGroup();
00338 for (i = 0; i < baseElems.NumItems(); i++)
00339 meshJoiner.AddTriangle((NbRadElem*) baseElems[i]);
00340 meshJoiner.EndGroup();
00341 i = meshJoiner.Finished();
00342 colours->SetSize(i);
00343 if (normals)
00344 normals->SetSize(i);
00345
00346 DBG_COUT << "done." << endl;
00347 }
00348
00349 Void RadMethod::FindBounds(Point &min, Point &max)
00350 {
00351 Int i;
00352
00353 min.MakeBlock(HUGE_VAL);
00354 max.MakeBlock(-HUGE_VAL);
00355 for (i = 0; i < points->NumItems(); i++)
00356 UpdateBounds((*points)[i], min, max);
00357 }
00358
00359 Void RadMethod::ColourMeshInitial()
00360 {
00361 // just sets colours to emittance + reflectance...
00362
00363 Int i;
00364
00365 for (i = 0; i < patches.NumItems(); i++)
00366 patches[i]->SetColour(patches[i]->Reflectance()
00367 + patches[i]->Emittance());
00368 }
00369
00370 Void RadMethod::CreatePatches()
00371 {
00372 Int i;
00373
00374 patches.Clear();
00375 stats.Init();
00376
00377 DBG_COUT << "creating patches" << endl;
00378
00379 // Subdivide base poly to initial mesh, accumulate into polys and
00380 // patches lists.
00381
00382 for (i = 0; i < baseElems.NumItems(); i++)
00383 baseElems[i]->CreatePatches(patches);
00384
00385 for (i = 0; i < patches.NumItems(); i++)
00386 stats.Update(patches[i]);
00387
00388 #ifdef DEBUG
00389 stats.Report(cerr);
00390 #endif
00391 }
00392
00393 // --- Ray tracing support ----------------------------------------------------
00394
00395
00396 class RTElemBuilder : public Decimator
00397 {
00398 public:
00399 RTElemBuilder(RadMethod *rm) : method(rm) {};
00400
00401 Void HandlePoly(Int numVertices, Int vertices[], Int changed);
00402
00403 RadMethod *method;
00404 };
00405
00406 Void RTElemBuilder::HandlePoly(
00407 Int numVertices,
00408 Int vertices[],
00409 Int changed
00410 )
00411 {
00412 RT_Tri *tri;
00413
00414 if (numVertices == DEC_End)
00415 {
00416 // we're cooked: attach the master point list to the RT object
00417 method->object->numPoints = pointsAcc->NumItems();
00418 method->object->points = pointsAcc->Detach();
00419 return;
00420 }
00421 else if (numVertices < 0) return;
00422
00423
00424 tri = method->object->tris + method->rtID;
00425 tri->Init(vertices[0], vertices[1],
00426 vertices[2], method->object, method->rtID);
00427 #ifdef RAD_VIS
00428 CheckRange(decNum, 0, method->baseElems.NumItems(),
00429 "mismatch between radiosity and ray-trace triangles");
00430 if (method->rtElemPtrs.NumItems() > 0)
00431 method->rtElemPtrs[method->rtID] = method->baseElems[decNum];
00432 #endif
00433
00434 tri->flags |= TRI_2SIDED_V; // visibility checking is two sided
00435 method->rtID++;
00436
00437 if (numVertices > 3)
00438 // quad! add second triangle
00439 {
00440 tri = method->object->tris + method->rtID;
00441 tri->Init(vertices[2], vertices[3],
00442 vertices[0], method->object, method->rtID);
00443 #ifdef RAD_VIS
00444 if (method->rtElemPtrs.NumItems() > 0)
00445 method->rtElemPtrs[method->rtID] = method->baseElems[decNum];
00446 #endif
00447 method->rtID++;
00448 }
00449 }
00450
00451 Void RadMethod::CreateRTObjects(scScenePtr scene)
00452 {
00453 UInt32 decFlags = DecTris | DecQuads;
00454
00455 if (object)
00456 {
00457 object->Free();
00458 delete object;
00459 object = 0;
00460 }
00461
00462
00463 // add all the triangles...
00464 DBG_COUT << "adding base triangles..." << endl;
00465
00466 if (gRadControl->rtComplexity != gRadControl->meshComplexity)
00467 {
00468 // not guaranteed correspondence between rt & radiosity triangles,
00469 // so recalc.
00470 scene->Decimate(qtInfo, decFlags);
00471 // can't have mapping between rt elems and rad elems
00472 #ifdef RAD_VIS
00473 rtElemPtrs.Clear();
00474 #endif
00475 }
00476 #ifdef RAD_VIS
00477 else
00478 rtElemPtrs.SetSize(qtInfo.numPolys + qtInfo.numQuads);
00479 #endif
00480
00481 rtID = 0;
00482 object = new RT_Object;
00483 object->Init(qtInfo.numPolys + qtInfo.numQuads);
00484
00485 RTElemBuilder elemBuilder(this);
00486 scene->Decimate(elemBuilder, decFlags | DecUseMaster);
00487 object->Setup();
00488 DBG_COUT << rtID << " triangles added." << endl;
00489
00490 grid->AddObject(object);
00491 }
00492
00493 Void RadMethod::CreateRTGrid(scScenePtr scene)
00494 {
00495 if (grid)
00496 {
00497 grid->Free();
00498 delete grid;
00499 grid = 0;
00500 }
00501
00502 if (!gRadControl->gridOn)
00503 return;
00504
00505 #ifdef RAD_VIS
00506 RM_OUT1("Creating ray-trace grid");
00507 #endif
00508 DBG_COUT << "Creating grid..." << endl;
00509
00510 // get the grid ready.
00511 // set up the grid
00512 grid = new RT_Grid();
00513 grid->MasterInit();
00514
00515 CreateRTObjects(scene);
00516
00517 grid->sEpsilon = 1e-6;
00518 grid->PrepareGrid();
00519 #ifdef DEBUG
00520 grid->DumpMemoryUsage();
00521 #endif
00522
00523 DBG_COUT << "done." << endl;
00524 #ifdef RAD_VIS
00525 RM_OUT1("done.");
00526 #endif
00527 }
00528
00529 Bool RadMethod::IntersectsWithRay(const Point &start, const Point &end)
00530 {
00531 if (grid)
00532 return(grid->IntersectionExists(start, end));
00533 else
00534 return(false);
00535 }
00536
00537 RadElem *RadMethod::ClosestIntersection(const Point &start, const Point &dir, Point &p)
00538 {
00539 if (grid)
00540 {
00541 if (grid->ClosestIntersection(start, dir))
00542 {
00543 p = grid->hitT * dir + start;
00544
00545 #ifdef RAD_VIS
00546 if (rtElemPtrs.NumItems() > 0)
00547 return(rtElemPtrs[grid->hitPrim->id]);
00548 else
00549 #endif
00550 return(0);
00551 }
00552 else
00553 return(0);
00554 }
00555 else
00556 return(0);
00557 }
00558
00559 Bool RadMethod::Render()
00560 {
00561 gRadControl->rays = 0;
00562 totTime = 0;
00563 lastTime = 0;
00564 dumpID = 0;
00565
00566 timer.StartTimer(); // Initialise, then suspend timer.
00567 timer.StopTimer();
00568
00569 return(true);
00570 }
00571
00572 Void RadMethod::RemoveDirect()
00573 {
00574 // default is not to do it.
00575 }
00576
00577 // --- Measurement ------------------------------------------------------------
00578
00579 Int RadMethod::Stage(Int stage)
00580 {
00581 return(0);
00582 }
00583
00584 Bool RadMethod::Idle()
00585 {
00586 #ifdef RAD_VIS
00587 if (gsP)
00588 {
00589 gsP->Spin();
00590
00591 return(gRadControl->stop);
00592 }
00593 else
00594 #endif
00595 return(false);
00596 }
00597
00598 Bool RadMethod::Pause()
00600 {
00601 #ifdef RAD_VIS
00602 if (gsP)
00603 {
00604 do
00605 gsP->Spin();
00606 while (gRadControl->pause && !gRadControl->step);
00607
00608 gRadControl->step = 0;
00609
00610 return(gRadControl->stop);
00611 }
00612 else
00613 #endif
00614 return(false);
00615 }
00616
00617 Void RadMethod::DumpScene()
00618 {
00619 ofstream outFile;
00620 String filename;
00621
00622 if (gRadControl->dumpScenes)
00623 {
00624 ColourVertices();
00625
00626 if (dumpID != 0) // don't bother with first one.
00627 {
00628 filename.Printf("%s.%02d.sl", gRadControl->outFile, dumpID);
00629
00630 outFile.open(filename);
00631 if (outFile)
00632 GetScene()->HierPrint(outFile, 0);
00633 outFile.close();
00634 }
00635 }
00636 dumpID++;
00637 }
00638
00639 Bool RadMethod::CheckTime()
00640 {
00641 timer.StopTimer();
00642 totTime = timer.GetTimer();
00643
00644 // if we're out of time, dump stats, and terminate.
00645 if (totTime > gRadControl->limitTime)
00646 {
00647 gRadControl->finalPass = true;
00648 DumpStats();
00649 return(true);
00650 }
00651
00652 // if another time-slice has elapsed, dump stats
00653 if (totTime - lastTime >= gRadControl->sliceTime)
00654 {
00655 while (totTime - lastTime >= gRadControl->sliceTime)
00656 lastTime += gRadControl->sliceTime;
00657
00658 DumpStats();
00659 }
00660
00661 return(false);
00662 }
00663
00664 #ifdef RAD_VIS
00665
00666 Bool RadMethod::Update()
00667 {
00668 #ifndef RAD_TLD
00669 // always update
00670 return(true);
00671 #else
00672
00673 if (utimer.GetTimer() > nextUpdate)
00674 {
00675 nextUpdate = utimer.GetTimer() + RAD_TLD_DELTA;
00676 return(true);
00677 }
00678 return(false);
00679 #endif
00680 }
00681
00682 Void RadMethod::StartUpdate()
00683 {
00684 utimer.StartTimer();
00685 nextUpdate = 0.0;
00686 }
00687
00688 Void RadMethod::UpdateCont()
00689 {
00690 nextUpdate = utimer.GetTimer() + RAD_TLD_DELTA;
00691 }
00692
00693 #endif
00694
00695
00696 // --- Visualisation stuff ----------------------------------------------------
00697
00698 Void RadMethod::Draw(Renderer &r)
00699 {
00700 Int i;
00701
00702 for (i = 0; i < baseElems.NumItems(); i++)
00703 {
00704 if (gRadControl->texture && baseElems[i]->props->texture)
00705 r.SetTexture(baseElems[i]->props->texture->image);
00706 baseElems[i]->Draw(r);
00707 }
00708
00709 if (gRadControl->texture)
00710 r.SetTexture(0);
00711
00712 if (gRadControl->outlineVisGrid)
00713 grid->Draw(r, 0);
00714 }
00715
00716 Void RadMethod::DrawMatrix(Renderer &r)
00717 {
00718 Expect(false, "Radiosity method has no draw matrix method.");
00719 }
00720
00721 #ifdef RAD_VIS
00722
00723 Void RadMethod::RenderMatrix()
00724 {
00725 if (matDisplay)
00726 matDisplay->Redraw();
00727 }
00728
00729 #endif
00730
00731 Void RadMethod::WriteSLFile(StrConst filename)
00732 // Write final mesh as a .sl file
00733 {
00734 Int i;
00735 ofstream s;
00736 PatchList *leaves = GetElements();
00737
00738 s.open(filename);
00739 if (!s)
00740 return;
00741
00742 s << "object \"rad_output\"" << endl;
00743 s << "camera" << endl;
00744 s << "points " << *points << endl;
00745 s << "colours " << *colours << endl;
00746 if (normals)
00747 s << "normals " << *normals << endl;
00748 if (texCoords)
00749 s << "coords " << *texCoords << endl;
00750
00751 for (i = 0; i < leaves->NumItems(); i++)
00752 {
00753 RadElem *elt = (*leaves)[i];
00754 s << "indexes [" << elt->index[0] << ' '
00755 << elt->index[1] << ' '<< elt->index[2];
00756 if (elt->IsQuad())
00757 s << ' ' << elt->index[3];
00758 s << ']' << endl;
00759 s << "surfaces [" << elt->clrIdx[0] << ' '
00760 << elt->clrIdx[1] << ' '<< elt->clrIdx[2];
00761 if (elt->IsQuad())
00762 s << ' ' << elt->clrIdx[3];
00763 s << ']' << endl;
00764
00765 // XXX
00766 if (elt->props->texCoords)
00767 {
00768 s << "coords [";
00769 for (Int j = 0; j < elt->Sides(); j++)
00770 s << elt->TexCoord(j);
00771 s << ']' << endl;
00772 }
00773 s << "poly" << endl;
00774 }
00775 s << "end" << endl;
00776 s.close();
00777 }
00778
00779 Void RadMethod::WriteObjFile(StrConst filename)
00780 // Write final mesh as a wavefront obj file.
00781 {
00782 Int i, j;
00783 FILE *file;
00784 PatchList *leaves = GetElements();
00785 IndexList texOffsets(numProps);
00786 Int texOffset;
00787
00788 file = fopen(filename, "w");
00789
00790 if (!file)
00791 {
00792 _Warning("(WriteObjFile) couldn't open output file for writing");
00793 return;
00794 }
00795
00796 fprintf(file, "# rad output\n");
00797 fprintf(file, "# faces: %d, points: %d, colours: %d\n",
00798 leaves->NumItems(), points->NumItems(), colours->NumItems());
00799 fprintf(file, "\n");
00800 // dump points, colours, and texture coords if we have 'em.
00801
00802 for (i = 0; i < points->NumItems(); i++)
00803 {
00804 GCLReal *v = (*points)[i].Ref();
00805
00806 fprintf(file, "v %g %g %g\n",
00807 (Double) v[0], (Double) v[1], (Double) v[2]);
00808 }
00809
00810 for (i = 0; i < colours->NumItems(); i++)
00811 {
00812 ClrReal *v = (*colours)[i].Ref();
00813
00814 fprintf(file, "vc %g %g %g\n",
00815 (Double) v[0], (Double) v[1], (Double) v[2]);
00816 }
00817
00818 // XXX this could lead to repeated tex coord lists
00819 texOffsets.ClearTo(0);
00820 texOffset = 0;
00821 for (i = 0; i < numProps; i++)
00822 if (props[i].texCoords)
00823 {
00824 texOffsets[i] = texOffset;
00825 texOffset += props[i].texCoords->NumItems();
00826
00827 for (j = 0; j < props[i].texCoords->NumItems(); j++)
00828 {
00829 Coord &vc = props[i].texCoords->Item(j);
00830
00831 fprintf(file, "vt %f %f\n",
00832 (Double) vc[0], (Double) vc[1]);
00833 }
00834 }
00835
00836 // now dump the elements
00837
00838 for (i = 0; i < leaves->NumItems(); i++)
00839 {
00840 RadElem *elt = (*leaves)[i];
00841
00842 if (elt->props->texCoords)
00843 {
00844 texOffset = texOffsets[elt->props - props] + 1;
00845
00846 fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d",
00847 elt->index[0] + 1,
00848 elt->texIdx[0] + texOffset,
00849 elt->clrIdx[0] + 1,
00850 elt->index[1] + 1,
00851 elt->texIdx[1] + texOffset,
00852 elt->clrIdx[1] + 1,
00853 elt->index[2] + 1,
00854 elt->texIdx[2] + texOffset,
00855 elt->clrIdx[2] + 1
00856 );
00857 if (elt->IsQuad())
00858 fprintf(file, " %d/%d/%d",
00859 elt->index[3] + 1,
00860 elt->texIdx[3] + texOffset,
00861 elt->clrIdx[3] + 1
00862 );
00863 }
00864 else
00865 {
00866 fprintf(file, "f %d//%d %d//%d %d//%d",
00867 elt->index[0] + 1,
00868 elt->clrIdx[0] + 1,
00869 elt->index[1] + 1,
00870 elt->clrIdx[1] + 1,
00871 elt->index[2] + 1,
00872 elt->clrIdx[2] + 1
00873 );
00874 if (elt->IsQuad())
00875 fprintf(file, " %d//%d",
00876 elt->index[3] + 1,
00877 elt->clrIdx[3] + 1
00878 );
00879 }
00880 fprintf(file, "\n");
00881 }
00882
00883 fclose(file);
00884 }
00885
00886 Void RadMethod::WriteMRBFile(StrConst filename)
00887 // Write final mesh as a MRB obj file.
00888 // for now we just write geometry
00889 {
00890 Int i, j, totFaces;
00891 FILE *file;
00892 PatchList *leaves = GetElements();
00893 MRB_Header header;
00894 FaceIdxArray faces;
00895
00896 totFaces = leaves->NumItems();
00897 for (i = 0; i < leaves->NumItems(); i++)
00898 if (leaves->Item(i)->IsQuad())
00899 totFaces++;
00900
00901 faces.SetSize(totFaces);
00902
00903 for (i = 0, j = 0; i < leaves->NumItems(); i++)
00904 {
00905 RadElem *elt = leaves->Item(i);
00906
00907 faces[j].v[0] = elt->index[0];
00908 faces[j].v[1] = elt->index[1];
00909 faces[j].v[2] = elt->index[2];
00910 j++;
00911
00912 if (elt->IsQuad())
00913 {
00914 faces[j].v[0] = elt->index[2];
00915 faces[j].v[1] = elt->index[3];
00916 faces[j].v[2] = elt->index[0];
00917 j++;
00918 }
00919 }
00920
00921 file = fopen(filename, "w");
00922
00923 if (!file)
00924 {
00925 _Warning("(WriteMRBFile) couldn't open output file for writing");
00926 return;
00927 }
00928
00929 header.version = 1;
00930 #ifdef GCL_FLOAT
00931 head.flags.Set(MRB_Float);
00932 #endif
00933
00934 do
00935 {
00936 if (sizeof(MRB_Header) != fwrite(&header, 1, sizeof(MRB_Header), file)) break;
00937 if (points->FWrite(file)) break;
00938 if (faces.FWrite(file)) break;
00939 }
00940 while (false);
00941
00942 if (ferror(file))
00943 perror("MRB write");
00944 fclose(file);
00945 }
00946
00947
00948 // --- Utility routines -------------------------------------------------------
00949
00950
00951 #ifdef __linux__
00952
00953 #include <unistd.h>
00954
00955 struct MemStat
00956 {
00957 long size; /* total # of pages of memory */
00958 long resident; /* number of resident set (non-swapped) pages (4k) */
00959 long share; /* number of pages of shared (mmap'd) memory */
00960 long trs; /* text resident set size */
00961 long lrs; /* shared-lib resident set size */
00962 long drs; /* data resident set size */
00963 long dt; /* dirty pages */
00964 };
00965
00966 Int FindLinuxMem(MemStat &stat)
00967 {
00968 FILE *procFile;
00969 Int pageKB = getpagesize() / 1024;
00970 Int num;
00971
00972 procFile = fopen(String().Printf("/proc/%d/statm", getpid()), "r");
00973
00974 if (procFile)
00975 {
00976 num = fscanf(procFile, "%ld %ld %ld %ld %ld %ld %ld",
00977 &stat.size, &stat.resident, &stat.share,
00978 &stat.trs, &stat.lrs, &stat.drs, &stat.dt
00979 );
00980
00981 fclose(procFile);
00982
00983 stat.size *= pageKB;
00984 stat.resident *= pageKB;
00985 stat.share *= pageKB;
00986 stat.trs *= pageKB;
00987 stat.lrs *= pageKB;
00988 stat.drs *= pageKB;
00989 stat.dt *= pageKB;
00990 }
00991 else
00992 _Warning("Error reading /proc/*/statm");
00993 }
00994
00995 #endif
00996
00997 Int RadMethod::TotalMemoryUse()
00998 {
00999 #ifdef __linux__
01000 MemStat stat;
01001
01002 FindLinuxMem(stat);
01003
01004 return(stat.size);
01005 #else
01006 rusage myRusage;
01007
01008 getrusage(RUSAGE_SELF, &myRusage);
01009
01010 return(myRusage.ru_maxrss);
01011 #endif
01012 }
01013
01014 Void RadMethod::SetupProps(RadProps *props, Decimator *state)
01015 {
01016 SLContext *context = state->context;
01017 Colour *reflectancePtr = SC_GET(Colour);
01018 Colour *emittancePtr = SC_GET(Emittance);
01019 CoordList *texCoords = SC_GET(Coords);
01020 Texture *texture = SC_GET(Texture);
01021
01022 // Fill in the properties structure...
01023
01024 props->id = state->decNum;
01025
01026 if (reflectancePtr)
01027 props->reflectance = *reflectancePtr;
01028 else
01029 props->reflectance = cOrange;
01030
01031 if (emittancePtr)
01032 props->emittance = *emittancePtr;
01033 else
01034 props->emittance = cBlack;
01035
01036 props->points = state->pointsAcc;
01037 props->colours = colours;
01038 if (texCoords && texture)
01039 {
01040 props->texCoords = texCoords;
01041 props->texture = texture;
01042 }
01043 }
01044
01045 Void RadMethod::Reanimate()
01046 {
01047 Int i;
01048
01049 numProps = 1;
01050 props = new RadProps[1];
01051 props[0].points = points;
01052 props[0].colours = colours;
01053 props[0].id = 0;
01054 props[0].reflectance = cOrange;
01055 props[0].emittance = cOrange;
01056
01057 for (i = 0; i < baseElems.NumItems(); i++)
01058 {
01059 baseElems[i]->SetProps(props);
01060 baseElems[i]->Reanimate(0);
01061 }
01062
01063 ColourVertices();
01064 }
01065
01066 Void RadMethod::AssignNormals()
01067 {
01068 if (!normals)
01069 return;
01070
01071 Int i, j, n = normals->NumItems();
01072 Int *weights;
01073
01074
01075 DBG_COUT << "creating vertex normals..." << endl;
01076
01077 weights = new Int[n];
01078
01079 for (i = 0; i < n; i++)
01080 {
01081 weights[i] = 0;
01082 normals->Item(i) = vl_0;
01083 }
01084
01085 for (i = 0; i < baseElems.NumItems(); i++)
01086 for (j = 0; j < baseElems[i]->Sides(); j++)
01087 {
01088 baseElems[i]->Normal(j) += baseElems[i]->normal;
01089 weights[baseElems[i]->normIdx[j]] += 1;
01090 }
01091
01092 for (i = 0; i < n; i++)
01093 {
01094 if (weights[i])
01095 normals->Item(i) /= GCLReal(weights[i]);
01096 else
01097 normals->Item(i) = vl_0;
01098 }
01099
01100 delete[] weights;
01101 }
01102
01103 Void RadMethod::ColourVertices()
01106 {
01107 Int i, n = colours->NumItems();
01108 Int *weights;
01109
01110 DBG_COUT << "colouring vertices..." << endl;
01111
01112 weights = new Int[n];
01113 for (i = 0; i < n; i++)
01114 {
01115 weights[i] = 0;
01116 colours->Item(i) = vl_0;
01117 }
01118
01119 for (i = 0; i < baseElems.NumItems(); i++)
01120 baseElems[i]->ColourVertices(weights);
01121
01122 for (i = 0; i < n; i++)
01123 if (weights[i])
01124 colours->Item(i) /= ClrReal(weights[i]);
01125 else
01126 colours->Item(i) = cRed; // mark so we can pick up error
01127
01128 #if defined(RAD_HIST)
01129 Int hist[32];
01130
01131 for (i = 0; i < 32; i++)
01132 hist[i] = 0;
01133 for (i = 0; i < n; i++)
01134 if (weights[i] < 32)
01135 hist[weights[i]]++;
01136 printf("smoothed mesh: %d %d %d %d\n",
01137 hist[0], hist[1], hist[2], hist[3]);
01138 #endif
01139
01140 delete[] weights;
01141 }
01142
01143 PatchList *RadMethod::GetElements()
01144 {
01145 ColourVertices();
01146 return(&patches);
01147 }
01148
01149
01150
01151 // --- I/O --------------------------------------------------------------------
01152
01153 static char *kMethTable[] =
01154 {
01155 "null",
01156 "mat",
01157 "cg",
01158 "prog",
01159 "hprog",
01160 "hier",
01161 "ana"
01162 };
01163
01164 Void RadMethod::Print(ostream &s) const
01165 {
01166 s << kMethTable[gRadControl->method] << endl;
01167 PrintCmds(s);
01168 }
01169
01170 Bool RadMethod::ParseCmd(StrConst str, istream &s)
01171 {
01172 return(false);
01173 }
01174
01175 Void RadMethod::PrintCmds(ostream &s) const
01176 {
01177 Int i;
01178
01179 s << "points " << *points << endl;
01180 s << "colours " << *colours << endl;
01181
01182 if (baseElems.NumItems() > 0)
01183 {
01184 s << " base_elems " << baseElems.NumItems() << endl;
01185 for (i = 0; i < baseElems.NumItems(); i++)
01186 {
01187 baseElems[i]->Print(s);
01188 s << endl;
01189 }
01190 }
01191 }
01192
01193 Void RadMethod::Parse(istream &s)
01194 {
01195 String str;
01196 Bool done = false;
01197
01198 while (!done)
01199 {
01200 str.ReadWord(s);
01201
01202 #ifdef DEBUG
01203 DBG_COUT << "parsing mesh > " << str << endl;
01204 #endif
01205
01206 if (str == "end")
01207 done = true;
01208 else if (str == "base_elems")
01209 {
01210 Int numBEs, i;
01211
01212 s >> numBEs;
01213 baseElems.SetSize(numBEs);
01214 for (i = 0; i < numBEs; i++)
01215 {
01216 // hack XXX
01217 ChompWhiteSpace(s);
01218 if (s.peek() == '+')
01219 {
01220 Char c;
01221 s.get(c);
01222 str.ReadWord(s);
01223 if (str == "haar")
01224 gRadControl->basis = kHaar;
01225 else
01226 cerr << "ignoring unknown basis type "
01227 << str << endl;
01228 }
01229
01230 baseElems[i] = NewMesh();
01231 baseElems[i]->Parse(s);
01232 }
01233 // str.ReadWord(s);
01234 }
01235 else if (str == "points")
01236 {
01237 points = new PointList;
01238 s >> *points;
01239 }
01240 else if (str == "colours")
01241 {
01242 colours = new ColourList;
01243 s >> *colours;
01244 }
01245 else if (str == "normals")
01246 {
01247 normals = new VectorList;
01248 s >> *normals;
01249 }
01250 else if (ParseCmd(str, s))
01251 ;
01252 else
01253 {
01254 cerr << "unknown mesh keyword: " << str << endl;
01255 do
01256 {
01257 str.ReadLine(s);
01258 str.ReadWord(s);
01259 }
01260 while (str != "end");
01261 break;
01262 }
01263 }
01264
01265 Reanimate();
01266 }
01267
01268
01269 // --- Creation ---------------------------------------------------------------
01270
01271
01272 #include "MatRad.h"
01273 #include "ProgRad.h"
01274 #include "HProgRad.h"
01275 #include "HierRad.h"
01276 #include "AnaRad.h"
01277
01278 RadMethod *RadMethod::NewRadMethod()
01279 {
01280 RadMethod *result;
01281
01282 switch (gRadControl->method)
01283 {
01284 case kNoMethod:
01285 _Error("No method selected");
01286 case kMatrix:
01287 result = (RadMethod*) MatRad::New();
01288 break;
01289 case kProgressive:
01290 result = (RadMethod*) ProgRad::New();
01291 break;
01292 case kProgSubstruct:
01293 result = (RadMethod*) HProgRad::New();
01294 break;
01295 case kHierarchical:
01296 result = (RadMethod*) HierRad::New();
01297 break;
01298 case kAnalytical:
01299 result = (RadMethod*) AnaRad::New();
01300 break;
01301 default:
01302 cerr << ">>> " << gRadControl->method << endl;
01303 _Error("Unhandled method");
01304 }
01305
01306 Assert(result != 0, "method not supported");
01307
01308 return(result);
01309 }