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

RadMethod.cc

Go to the documentation of this file.
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 }

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