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 }