00001 /* 00002 File: MRModel.cc 00003 00004 Function: Implements a multiresolution polygonal model 00005 00006 Author: Andrew Willmott 00007 00008 Notes: 00009 */ 00010 00011 #include "gcl/MRModel.h" 00012 #include "cl/String.h" 00013 #include "gcl/VecUtil.h" 00014 #include "gcl/Draw.h" 00015 #include <stdio.h> 00016 #include <stdlib.h> 00017 #include <errno.h> 00018 00019 #ifdef DEBUG 00020 #define MRV_COUT if (true) cerr 00021 #else 00022 #define MRV_COUT if (false) cerr 00023 #endif 00024 00025 #define MR_MEM_MAP 00026 00027 #ifdef MR_MEM_MAP 00028 #include <unistd.h> 00029 #include <sys/types.h> 00030 #include <sys/stat.h> 00031 #include <fcntl.h> 00032 #include <sys/mman.h> 00033 #endif 00034 00035 #include <new.h> 00036 00037 00058 const Int kMRBVersion = 3; 00059 00060 00061 MRModel::MRModel() : 00062 lastComplexity(1.0), 00063 showMeta(false), 00064 showFaces(true), 00065 colourFaces(false), 00066 currentFaces(0), 00067 currentClusters(0), 00068 clustersPrepped(false), 00069 verticesPrepped(false) 00070 { 00071 colour = scPrimitive::sDefaultColour; 00072 points = 0; 00073 colours = 0; 00074 } 00075 00076 MRModel::~MRModel() 00077 { 00078 } 00079 00080 Bool MRModel::sAvgClusColours = false; 00081 00082 Void MRModel::AddContraction( 00083 Int child0, 00084 Int child1, 00085 Int face0, 00086 Int face1, 00087 GCLReal error, 00088 const Point &p, 00089 Int delta 00090 ) 00092 { 00093 MRVertex newVtx; 00094 00095 if (vertices.NumItems() == 0) 00096 // if this is first contraction, set up all the data structures we'll 00097 // need 00098 { 00099 Int i; 00100 00101 vertices.SetSize(points->NumItems()); 00102 vertices.ClearTo(newVtx); 00103 vtxFlags.SetSize(points->NumItems() * 2 - 1); 00104 vtxFlags.ClearTo(Flags8()); 00105 00106 // make the leaf vertices active 00107 for (i = 0; i < vertices.NumItems(); i++) 00108 vtxFlags[i].Set(MRV_Active); 00109 00110 for (i = 0; i < faces.NumItems(); i++) 00111 vtxFlags[i].Set(MRV_FaceActive); 00112 } 00113 00114 points->Append(p); 00115 00116 if (delta) 00117 points->Last() += points->Item(child0); 00118 00119 // MMF format uses an in-place numbering scheme (a contracted 00120 // vertex replaces its left child in a vertex array) so we 00121 // must walk up to the roots of the indicated vertices to 00122 // find the vertex that's really being referred to. 00123 00124 while (!vertices[child0].IsRoot()) 00125 child0 = vertices[child0].parent; 00126 while (!vertices[child1].IsRoot()) 00127 child1 = vertices[child1].parent; 00128 00129 // Set the contraction! 00130 newVtx.SetContraction(vertices, vertices.NumItems(), vtxFlags, 00131 child0, child1, face0, face1, error); 00132 vertices.Append(newVtx); 00133 00134 Assert(vtxFlags[vertices.NumItems() - 1].IsSet(MRV_Inside), "flag not set"); 00135 00136 Assert(vertices.NumItems() == points->NumItems(), "point/vertex mismatch"); 00137 } 00138 00139 Void MRModel::AddCluster( 00140 Int clusLeft, 00141 Int clusRight, 00142 Point &clusOrig, 00143 VecTrans &clusAxis, 00144 Vector &clusFitNormal, 00145 GCLReal clusD, 00146 Point &clusMin, 00147 Point &clusMax, 00148 Int clusID 00149 ) 00151 { 00152 Point obbOrig; 00153 Vector scales; 00154 Int i; 00155 00156 clusLeft--; 00157 clusRight--; 00158 00159 if (clusters.NumItems() == 0) 00160 { 00161 MRV_COUT << "adding first cluster: preallocating space for " << 00162 faces.NumItems() - 1 << " clusters" << endl; 00163 00164 clusters.SetSize(faces.NumItems() - 1); 00165 firstClusterID = 2 * faces.NumItems() - 2; 00166 lastClusterID = faces.NumItems(); 00167 clustersActive.SetSize(faces.NumItems() * 2 - 1); 00168 for (i = 0; i < faces.NumItems(); i++) 00169 clustersActive[i] = 1; 00170 00171 MRV_COUT << "done." << endl; 00172 } 00173 00174 Assert(clusLeft < clustersActive.NumItems() && clusRight < clustersActive.NumItems(), 00175 "Clusters not in tree order in cmf file."); 00176 00177 FaceCluster &newCluster = Cluster(clusID); 00178 00179 if (clusID & 8191 == 0) 00180 MRV_COUT << "adding cluster " << clusID << endl; 00181 00182 newCluster.child[0] = clusLeft; 00183 newCluster.child[1] = clusRight; 00184 00185 // convert to our storage format. 00186 00187 // Garland's OBB axes are not unit length, and may not be right 00188 // handed. (The smallest evec may have been flipped to point in the 00189 // same direction as the sum-area normal). 00190 00191 scales[0] = len(clusAxis[0]); 00192 scales[1] = len(clusAxis[1]); 00193 scales[2] = len(clusAxis[2]); 00194 // correct if left-handed 00195 if (det(clusAxis) < 0) 00196 { 00197 // flip y axis to correct, 'cause we want to keep z pointing same way 00198 // as normal 00199 scales[1] = -scales[1]; 00200 Swap(clusMin[1], clusMax[1]); 00201 } 00202 clusAxis[0] /= scales[0]; 00203 clusAxis[1] /= scales[1]; 00204 clusAxis[2] /= scales[2]; 00205 clusMin *= scales; 00206 clusMax *= scales; 00207 newCluster.SetAxes(clusAxis); 00208 00209 // transform origin into bbox coords 00210 obbOrig = clusAxis * clusOrig; 00211 clusMin += obbOrig; 00212 clusMax += obbOrig; 00213 00214 newCluster.min = clusMin; 00215 newCluster.max = clusMax; 00216 00217 for (i = 0; i < 6; i++) 00218 newCluster.sideArea[i] = 255; 00219 00220 Assert(clusMin[0] <= clusMax[0], "bad x bb"); 00221 Assert(clusMin[1] <= clusMax[1], "bad y bb"); 00222 Assert(clusMin[2] <= clusMax[2], "bad z bb"); 00223 00224 clustersActive[clusID] = 1; 00225 00226 if (clusLeft >= 0) 00227 { 00228 Assert(clustersActive[clusLeft], "left child not clusterable"); 00229 clustersActive[clusLeft] = 0; 00230 } 00231 if (clusRight >= 0) 00232 { 00233 Assert(clustersActive[clusRight], "right child not clusterable"); 00234 clustersActive[clusRight] = 0; 00235 } 00236 } 00237 00238 static GCLReal ProjectedLength(const Point &p1, const Point &p2, 00239 const Transform &projMat) 00241 { 00242 HPoint hp1(p1, 1.0), hp2(p2, 1.0); 00243 Vector c1, c2; 00244 Coord result; 00245 00246 c1[0] = dot(projMat[0], hp1); 00247 c1[1] = dot(projMat[1], hp1); 00248 c1[2] = dot(projMat[3], hp1); 00249 00250 c2[0] = dot(projMat[0], hp2); 00251 c2[1] = dot(projMat[1], hp2); 00252 c2[2] = dot(projMat[3], hp2); 00253 00254 result = proj(c1) - proj(c2); 00255 00256 return(sqrlen(result)); 00257 } 00258 00259 00260 Void MRModel::AdaptLength( 00261 GCLReal threshold, 00262 const Transform &M, 00263 const Transform &P, 00264 Float timeLimit 00265 ) 00270 { 00271 Transform PM = xform(P, M); 00272 Int i; 00273 00274 // Square the threshold so we can avoid all those sqrt's 00275 threshold = sqr(threshold); 00276 00277 // iterate over active vertices -- brute force for now... 00278 for (i = 0; i < vertices.NumItems(); i++) 00279 if (vtxFlags[i].IsSet(MRV_Active)) 00280 { 00281 Bool canExpand = false; 00282 Bool canContract = false; 00283 MRVertex &v = vertices[i]; 00284 00285 if (v.CanExpand(i, vtxFlags)) 00286 { 00287 if (threshold < ProjectedLength(points->Item(i), 00288 points->Item(v.child[0]), PM)) 00289 canExpand = true; 00290 else if (threshold < ProjectedLength(points->Item(i), 00291 points->Item(v.child[1]), PM)) 00292 canExpand = true; 00293 } 00294 00295 if (!v.IsRoot() && vertices[v.parent].CanContract(v.parent, vtxFlags)) 00296 { 00297 MRVertex &vp = vertices[v.parent]; 00298 00299 if (threshold > ProjectedLength(points->Item(v.parent), 00300 points->Item(vp.child[0]), PM)) 00301 canContract = true; 00302 else if (threshold > ProjectedLength(points->Item(v.parent), 00303 points->Item(vp.child[1]), PM)) 00304 canContract = true; 00305 } 00306 00307 if (canExpand) 00308 v.Expand(i, vtxFlags); 00309 else if (canContract) 00310 vertices[v.parent].Contract(v.parent, vtxFlags); 00311 00312 if (canExpand && canContract) 00313 MRV_COUT << "YOW! Tricky situation." << endl; 00314 } 00315 00316 AdjustLeafFaces(); 00317 } 00318 00319 Void MRModel::AdaptFaces(Int targetFaces) 00320 { 00321 Int i; 00322 00323 MRV_COUT << "Adapting to " << targetFaces << endl; 00324 00325 if (targetFaces > currentFaces) 00326 { 00327 // Search for expansions until we have enough faces 00328 00329 MRV_COUT << "Expanding: " << flush; 00330 00331 for (i = vertices.NumItems() - 1; targetFaces > currentFaces && i >= 0; i--) 00332 { 00333 MRVertex &v = vertices[i]; 00334 00335 if (v.CanExpand(i, vtxFlags)) 00336 { 00337 v.Expand(i, vtxFlags); 00338 if (v.face[0] >= 0) 00339 currentFaces++; 00340 if (v.face[1] >= 0) 00341 currentFaces++; 00342 } 00343 } 00344 } 00345 else if (targetFaces < currentFaces) 00346 { 00347 // Search for contractions 00348 00349 MRV_COUT << "Contracting: " << flush; 00350 00351 for (i = 0; (targetFaces < currentFaces) && i < vertices.NumItems(); i++) 00352 { 00353 MRVertex &v = vertices[i]; 00354 00355 if (v.CanContract(i, vtxFlags)) 00356 { 00357 v.Contract(i, vtxFlags); 00358 if (v.face[0] >= 0) 00359 currentFaces--; 00360 if (v.face[1] >= 0) 00361 currentFaces--; 00362 } 00363 } 00364 } 00365 00366 AdjustLeafFaces(); 00367 00368 MRV_COUT << "Model faces: " << currentFaces << endl; 00369 } 00370 00371 Void MRModel::AdaptClusters(Int targetClusters) 00372 { 00373 Int i; 00374 00375 MRV_COUT << "Adapting to " << targetClusters << endl; 00376 00377 if (clustersActive.NumItems() == 0) 00378 // don't have an active cluster list, so better create one now. 00379 { 00380 MRV_COUT << "Creating active list" << endl; 00381 currentClusters = rootClusters.NumItems(); 00382 clustersActive.SetSize(faces.NumItems() * 2 - 1); 00383 clustersActive.ClearTo(0); 00384 00385 // firstActiveClus = clustersActive.NumItems(); 00386 for (i = 0; i < rootClusters.NumItems(); i++) 00387 { 00388 // firstActiveClus = Min(rootClusters[i], firstClusActive); 00389 clustersActive[rootClusters[i]] = 1; 00390 } 00391 } 00392 00393 if (targetClusters > currentClusters) 00394 { 00395 Int lastExp = 0; 00396 00397 if (flags.IsSet(MRM_Ordered)) 00398 lastExp = lastClusterID; 00399 00400 // Search for expansions until we have enough faces 00401 00402 MRV_COUT << "Expanding: " << flush; 00403 00404 // move through from end of log, expanding active faces 00405 for (i = clustersActive.NumItems() - 1; (targetClusters > currentClusters) 00406 && i >= lastExp; i--) 00407 if (clustersActive[i] && !IsFace(i)) 00408 { 00409 // firstClusActive = i; 00410 clustersActive[i] = 0; 00411 clustersActive[Cluster(i).child[0]] = 1; 00412 clustersActive[Cluster(i).child[1]] = 1; 00413 currentClusters++; 00414 } 00415 } 00416 else if (Max(rootClusters.NumItems(), targetClusters) < currentClusters) 00417 { 00418 // Search for contractions 00419 00420 MRV_COUT << "Contracting: " << flush; 00421 00422 // move through from start of log, contracting active faces 00423 for (i = lastClusterID; (targetClusters < currentClusters) 00424 && i <= firstClusterID; i++) 00425 { 00426 Int left = Cluster(i).child[0]; 00427 Int right = Cluster(i).child[1]; 00428 00429 if (clustersActive[left]) 00430 { 00431 // firstClusActive = i; 00432 clustersActive[i] = 1; 00433 clustersActive[left] = 0; 00434 clustersActive[right] = 0; 00435 currentClusters--; 00436 } 00437 } 00438 } 00439 00440 MRV_COUT << "model clusters: " << currentClusters << endl; 00441 } 00442 00443 Void MRModel::AdaptComplexity(GCLReal complexity) 00449 { 00450 if (complexity != lastComplexity) 00451 { 00452 if (vertices.NumItems() > 0) 00453 AdaptFaces(sqr(complexity) * faces.NumItems()); 00454 if (clusters.NumItems() > 0) 00455 AdaptClusters(sqr(complexity) * faces.NumItems()); 00456 lastComplexity = complexity; 00457 } 00458 } 00459 00460 Void MRModel::AdjustLeafFaces() 00466 { 00467 if (vertices.NumItems() == 0) 00468 currentFaces = faces.NumItems(); 00469 else 00470 { 00471 Int i, numActiveFaces = 0; 00472 00473 for (i = 0; i < vtxFaces.NumItems(); i++) 00474 if (vtxFlags[i].IsSet(MRV_FaceActive)) 00475 { 00476 vtxCodes[i].AdjustVertices(vertices, vtxFlags, vtxFaces[i].v, faces[i].v); 00477 numActiveFaces++; 00478 } 00479 00480 currentFaces = numActiveFaces; 00481 } 00482 } 00483 00484 Void MRModel::DumpFCH(StrConst filename) 00486 { 00487 Int i, group = 0, lastActive; 00488 ofstream s; 00489 IndexList stack; 00490 00491 s.open(filename); 00492 00493 for (i = 0; i < clustersActive.NumItems(); i++) 00494 { 00495 if (clustersActive[i] != group) 00496 { 00497 group = clustersActive[i]; 00498 s << "g " << group << endl; 00499 } 00500 s << "e " << i; 00501 if (!IsFace(i)) 00502 s << ' ' << Cluster(i).child[0] << ' ' << Cluster(i).child[1]; 00503 s << endl; 00504 } 00505 00506 lastActive = -1; 00507 stack.Clear(); 00508 00509 for (i = 0; i < rootClusters.NumItems(); i++) 00510 stack.Push(rootClusters[i]); 00511 00512 while (stack.NumItems() != 0) 00513 { 00514 i = stack.Last(); 00515 stack.Pop(); 00516 if (clustersActive[i]) 00517 { 00518 if (lastActive >= 0) 00519 s << "l " << lastActive << ' ' << i << endl; 00520 lastActive = i; 00521 } 00522 else if (!IsFace(i)) 00523 { 00524 stack.Push(Cluster(i).child[1]); 00525 stack.Push(Cluster(i).child[0]); 00526 } 00527 } 00528 00529 s.close(); 00530 } 00531 00532 Void MRModel::CropClusters(Int numClusters) 00533 { 00534 Int i, cropClusterID; 00535 FaceIdxArray newFaces; 00536 00537 newFaces.PreAllocate(faces.NumItems()); 00538 00539 numClusters = Clip(numClusters, 1, clusters.NumItems()); 00540 00541 cout << "clipping to " << numClusters << " clusters" << endl; 00542 00543 // renumber leaves so that a cluster's leaves are numbered 00544 // consecutively 00545 00546 for (i = 0; i < rootClusters.NumItems(); i++) 00547 ReorderLeafClusters(rootClusters[i], newFaces); 00548 00549 faces.SwapWith(newFaces); 00550 flags.Set(MRM_Ordered); 00551 00552 cropClusterID = firstClusterID - numClusters; 00553 00554 // replace any child IDs that refer to soon-to-be discarded 00555 // clusters with appropriate face IDs. 00556 for (i = clusters.NumItems() - 1; i >= 0; i--) 00557 { 00558 if (!IsFace(clusters[i].child[0]) 00559 && clusters[i].child[0] < cropClusterID) 00560 clusters[i].child[0] = Cluster(clusters[i].child[0]).child[0]; 00561 00562 if (!IsFace(clusters[i].child[1]) 00563 && clusters[i].child[1] < cropClusterID) 00564 clusters[i].child[1] = Cluster(clusters[i].child[1]).child[1]; 00565 } 00566 00567 clusters.SetSize(numClusters); 00568 lastClusterID = firstClusterID - numClusters + 1; 00569 00570 cout << "clusters from " << firstClusterID << " to " << lastClusterID << endl; 00571 00572 if (clustersActive.NumItems() > 0) 00573 { 00574 clustersActive.ClearTo(0); 00575 00576 for (i = 0; i < rootClusters.NumItems(); i++) 00577 clustersActive[rootClusters[i]] = 1; 00578 currentClusters = rootClusters.NumItems(); 00579 } 00580 } 00581 00582 Int MRModel::ReorderLeafClusters(Int ic, FaceIdxArray &newFaces) 00593 { 00594 if (IsFace(ic)) 00595 { 00596 Int newID = newFaces.NumItems(); 00597 00598 newFaces.Append(faces[ic]); 00599 00600 return(newID); 00601 } 00602 else 00603 { 00604 FaceCluster &clus = Cluster(ic); 00605 00606 clus.child[0] = ReorderLeafClusters(clus.child[0], newFaces); 00607 clus.child[1] = ReorderLeafClusters(clus.child[1], newFaces); 00608 00609 return(ic); 00610 } 00611 } 00612 00613 Void MRModel::PrepareClusters() 00614 { 00615 Int i, j; 00616 Vector areaNormal; 00617 00618 if (clustersPrepped) 00619 return; 00620 00621 rootClusters.Clear(); 00622 00623 for (i = 0; i < clustersActive.NumItems(); i++) 00624 if (clustersActive[i]) 00625 rootClusters.Append(i); 00626 00627 // accumulate area normals up from leaves 00628 for (i = lastClusterID; i <= firstClusterID; i++) 00629 { 00630 FaceCluster &fc = Cluster(i); 00631 00632 fc.areaNormal = vl_0; 00633 fc.totArea = 0; 00634 00635 for (j = 0; j < 2; j++) 00636 if (IsFace(fc.child[j])) 00637 { 00638 areaNormal = FaceAreaNormal(fc.child[j]); 00639 fc.areaNormal += areaNormal; 00640 fc.totArea += len(areaNormal); 00641 } 00642 else 00643 { 00644 fc.areaNormal += Cluster(fc.child[j]).areaNormal; 00645 fc.totArea += Cluster(fc.child[j]).totArea; 00646 } 00647 } 00648 00649 currentClusters = rootClusters.NumItems(); 00650 00651 MRV_COUT << "there are " << rootClusters.NumItems() 00652 << " root clusters, total clusters = " 00653 << clustersActive.NumItems() << ", original faces = " << faces.NumItems() << endl; 00654 00655 clustersPrepped = true; 00656 } 00657 00658 Void MRModel::PrepareVertices() 00659 { 00660 GCLVec weights(vertices.NumItems(), vl_0); 00661 Int i, j, k; 00662 Int maxHeight, minHeight, height; 00663 TreeCodes treeCodes(vertices.NumItems()); 00664 VectorList faceANs(faces.NumItems()); 00665 00666 if (verticesPrepped) 00667 return; 00668 00669 maxHeight = 0; 00670 minHeight = 32767; 00671 rootVertices.Clear(); 00672 00673 // find all root vertices, and set up the hierarchies 00674 // corresponding to each one. 00675 for (i = 0; i < vertices.NumItems(); i++) 00676 if (vertices[i].IsRoot()) 00677 { 00678 height = 0; 00679 MRSetupHierarchy(vertices, i, treeCodes, height, 0, 0); 00680 maxHeight = Max(height, maxHeight); 00681 minHeight = Min(height, minHeight); 00682 rootVertices.Append(i); 00683 } 00684 00685 MRV_COUT << rootVertices.NumItems() << " root vertices" << endl; 00686 00687 for (i = 0; i < vertices.NumItems(); i++) 00688 vertices[i].areaNormal = vl_0; 00689 00690 // Set up face info (area, normal, etc.) 00691 vtxCodes.SetSize(faces.NumItems()); 00692 vtxFaces = faces; 00693 00694 for (i = 0; i < vtxFaces.NumItems(); i++) 00695 { 00696 faceANs[i] = FaceAreaNormal(i); 00697 00698 for (j = 0; j < 3; j++) 00699 { 00700 Assert(vertices[faces[i].v[j]].IsLeaf(), "Not at leaf vertices."); 00701 00702 vtxCodes[i].treeCode[j] = treeCodes[faces[i].v[j]]; 00703 vertices[faces[i].v[j]].areaNormal += faceANs[i]; 00704 weights[faces[i].v[j]] += 1.0; 00705 } 00706 } 00707 00708 // calculate vertex normals & equiv. areas. for leaf vertices 00709 for (i = 0; i < vertices.NumItems(); i++) 00710 if (weights[i] > 0.0) 00711 { 00712 GCLReal w = weights[i]; 00713 00714 vertices[i].areaNormal /= w; 00715 } 00716 00717 // calculate aggregate properties for non-leaf vertices. 00718 for (i = 0; i < rootVertices.NumItems(); i++) 00719 vertices[rootVertices[i]].PullProps(vertices); 00720 00721 MRV_COUT << "there are " << rootVertices.NumItems() 00722 << " root vertices, min/max vertex tree height = " 00723 << minHeight << '/' << maxHeight 00724 << ", original vertices = " << points->NumItems() << endl; 00725 00726 SimplestModel(); 00727 00728 verticesPrepped = true; 00729 } 00730 00731 Void MRModel::PrepareModel() 00732 { 00733 MRV_COUT << "processing MR model" << endl; 00734 00735 if (clusters.NumItems() > 0) 00736 PrepareClusters(); 00737 if (vertices.NumItems() > 0) 00738 PrepareVertices(); 00739 00740 MRV_COUT << "done" << endl; 00741 } 00742 00743 #ifdef MR_MEM_MAP 00744 00745 // XXX shift to CL 00746 Byte *MemMap(StrConst filename, Int &size) 00747 { 00748 Int fd, mapPerm; 00749 Byte *result = 0; 00750 00751 fd = open(filename, O_RDWR); 00752 if (fd == -1) 00753 { 00754 mapPerm = PROT_READ; 00755 fd = open(filename, O_RDONLY); 00756 } 00757 else 00758 mapPerm = PROT_READ | PROT_WRITE; 00759 00760 if (fd != -1) 00761 { 00762 Int fsize; 00763 struct stat fstats; 00764 00765 fstat(fd, &fstats); 00766 fsize = fstats.st_size; 00767 00768 result = (Byte*) mmap(0, fsize, mapPerm, MAP_SHARED, fd, 0); 00769 00770 size = fsize; 00771 00772 if (result == MAP_FAILED) 00773 { 00774 perror("mmap"); 00775 _Error("MemMap failed"); 00776 } 00777 close(fd); 00778 } 00779 else 00780 perror("open"); 00781 00782 return(result); 00783 } 00784 00785 Void ReadArray(NBaseArray &a, Byte* &p, Int &size) 00786 { 00787 Int elts, chunk; 00788 00789 elts = *((Int*) p); 00790 p += sizeof(Int); 00791 00792 a.Attach(p, elts, true); 00793 chunk = a.EltSize() * elts; 00794 p += chunk; 00795 size -= chunk; 00796 00797 Assert(size >= 0, "End of mapped memory chunk"); 00798 } 00799 00800 template <class T> Void ReadArray(Array<T> &a, Byte* &p, Int &size) 00801 { 00802 Int elts, chunk; 00803 00804 elts = *((Int*) p); 00805 p += sizeof(Int); 00806 00807 a.Attach((T*) p, elts, true); 00808 chunk = sizeof(T) * elts; 00809 p += chunk; 00810 size -= chunk; 00811 00812 Assert(size >= 0, "End of mapped memory chunk"); 00813 } 00814 00815 #ifdef CL_SGI_INST 00816 #pragma instantiate Void ReadArray(Array<Int> &a, Byte* &p, Int &size) 00817 #endif 00818 #endif 00819 00820 Bool MRModel::ParseBinary() 00821 { 00822 Bool result = false; 00823 Int i, j; 00824 FileName binaryFile(modelFile); 00825 00826 binaryFile.SetPath(modelFile.GetPath()); 00827 binaryFile.SetExtension("mrb"); 00828 MRV_COUT << "checking for " << binaryFile.GetPath() << endl; 00829 00830 if (modelFile.IsReadable()) 00831 do 00832 { 00833 MRV_COUT << "FOUND BINARY MRB" << endl; 00834 00835 #ifdef MR_MEM_MAP 00836 Byte *p; 00837 MRB_Header *header; 00838 Int size = 0; 00839 00840 MRV_COUT << "memmapping cluster file" << endl; 00841 p = MemMap(modelFile.GetPath(), size); 00842 00843 MRV_COUT << "memmapped " << size << " bytes" << endl; 00844 header = (MRB_Header*) p; 00845 p += sizeof(MRB_Header); 00846 size -= sizeof(MRB_Header); 00847 Assert(size >= 0, "End of mapped memory chunk"); 00848 if (header->version > kMRBVersion) 00849 { 00850 _Warning("Newer version"); 00851 } 00852 else if (header->version < kMRBVersion) 00853 { 00854 _Warning("Older version"); 00855 } 00856 00857 MRV_COUT << "version " << header->version 00858 << ", flags " << header->flags << endl; 00859 00860 ReadArray(*points, p, size); 00861 MRV_COUT << points->NumItems() << " points" << endl; 00862 00863 ReadArray(faces, p, size); 00864 MRV_COUT << faces.NumItems() << " faces" << endl; 00865 00866 if (header->flags.IsSet(MRB_HasVH)) 00867 { 00868 ReadArray(rootVertices, p, size); 00869 MRV_COUT << rootVertices.NumItems() << " root vertices" << endl; 00870 ReadArray(vertices, p, size); 00871 MRV_COUT << vertices.NumItems() << " vertices" << endl; 00872 ReadArray(vtxCodes, p, size); 00873 MRV_COUT << vtxCodes.NumItems() << " codes" << endl; 00874 } 00875 00876 if (header->flags.IsSet(MRB_HasFH)) 00877 { 00878 ReadArray(rootClusters, p, size); 00879 MRV_COUT << rootClusters.NumItems() << " root clusters" << endl; 00880 ReadArray(clusters, p, size); 00881 MRV_COUT << clusters.NumItems() << " clusters" << endl; 00882 } 00883 00884 result = true; 00885 flags.Set(MRM_MemMapped); 00886 if (header->flags.IsSet(MRB_Ordered)) 00887 flags.Set(MRM_Ordered); 00888 #else 00889 FILE *file; 00890 MRB_Header header; 00891 00892 file = binaryFile.FOpen("r+b"); 00893 if (!file) 00894 { 00895 _Warning("Couldn't open file"); 00896 break; 00897 } 00898 00899 do { 00900 if (sizeof(MRB_Header) != fread(&header, 1, sizeof(MRB_Header), file)) 00901 { 00902 _Warning("couldn't read header"); 00903 break; 00904 } 00905 00906 if (header.version > kMRBVersion) 00907 { 00908 _Warning("Newer version"); 00909 } 00910 else if (header.version < kMRBVersion) 00911 { 00912 _Warning("Older version"); 00913 } 00914 00915 MRV_COUT << "version " << header.version 00916 << ", flags " << header.flags << endl; 00917 00918 if (points->FRead(file)) break; 00919 MRV_COUT << points->NumItems() << " points" << endl; 00920 00921 if (faces.FRead(file)) break; 00922 MRV_COUT << faces.NumItems() << " faces" << endl; 00923 00924 if (header.flags.IsSet(MRB_HasVH)) 00925 { 00926 if (rootVertices.FRead(file)) break; 00927 MRV_COUT << rootVertices.NumItems() << " root vertices" << endl; 00928 if (vertices.FRead(file)) break; 00929 MRV_COUT << vertices.NumItems() << " vertices" << endl; 00930 if (vtxCodes.FRead(file)) break; 00931 MRV_COUT << vtxCodes.NumItems() << " codes" << endl; 00932 } 00933 if (header.flags.IsSet(MRB_HasFH)) 00934 { 00935 if (rootClusters.FRead(file)) break; 00936 MRV_COUT << rootClusters.NumItems() << " root clusters" << endl; 00937 if (clusters.FRead(file)) break; 00938 MRV_COUT << clusters.NumItems() << " clusters" << endl; 00939 } 00940 00941 if (header.flags.IsSet(MRB_Ordered)) 00942 flags.Set(MRB_Ordered); 00943 00944 result = true; 00945 } while (false); 00946 00947 if (ferror(file)) 00948 { 00949 perror("error reading MRB file"); 00950 break; 00951 } 00952 #endif 00953 00954 if (vertices.NumItems() > 0) 00955 { 00956 Flags8 fa; 00957 fa.Set(MRV_FaceActive | MRV_Inside); 00958 00959 MRV_COUT << "starting contraction prep" << endl; 00960 vtxFaces = faces; 00961 vtxFlags.SetSize(Max(vertices.NumItems(), faces.NumItems())); 00962 vtxFlags.ClearTo(fa); 00963 for (i = 0; i < faces.NumItems(); i++) 00964 for (j = 0; j < 3; j++) 00965 { 00966 vtxFlags[faces[i].v[j]].Set(MRV_Active); 00967 vtxFlags[faces[i].v[j]].UnSet(MRV_Inside); 00968 } 00969 AdjustLeafFaces(); // XXX store ms indexes to avoid? 00970 verticesPrepped = true; 00971 MRV_COUT << "done" << endl; 00972 } 00973 00974 if (clusters.NumItems() > 0) 00975 { 00976 firstClusterID = 2 * faces.NumItems() - 2; 00977 lastClusterID = firstClusterID - clusters.NumItems() + 1; 00978 clustersPrepped = true; 00979 } 00980 } 00981 while (false); 00982 00983 return(result); 00984 } 00985 00986 Void MRModel::WriteBinary() 00987 { 00988 FileName binaryFile; 00989 00990 if (flags.IsSet(MRM_MemMapped) || (clusters.NumItems() == 0 && vertices.NumItems() == 0)) 00991 return; 00992 00993 binaryFile.SetDir("."); 00994 binaryFile.SetFile(modelFile.GetFile()); 00995 binaryFile.SetExtension("mrb"); 00996 00997 cerr << "Writing binary to " << binaryFile.GetPath() << endl; 00998 00999 do 01000 { 01001 FILE *file; 01002 MRB_Header header; 01003 01004 // XXX needs error proofed 01005 01006 header.version = kMRBVersion; 01007 if (vertices.NumItems() > 0) 01008 header.flags.Set(MRB_HasVH); 01009 if (clusters.NumItems() > 0) 01010 header.flags.Set(MRB_HasFH); 01011 if (flags.IsSet(MRM_Ordered)) 01012 header.flags.Set(MRB_Ordered); 01013 01014 #ifdef GCL_FLOAT 01015 head.flags.Set(MRB_Float); 01016 #endif 01017 01018 if (!points) 01019 _Error("Model has no points?"); 01020 01021 MRV_COUT << "WRITING BINARY MRB FILE" << endl; 01022 file = binaryFile.FOpen("wb"); 01023 if (!file) 01024 break; 01025 01026 do 01027 { 01028 MRV_COUT << "ACTIVE: " << currentClusters << endl; 01029 01030 if (sizeof(MRB_Header) != fwrite(&header, 1, sizeof(MRB_Header), file)) break; 01031 MRV_COUT << "points: " << points->NumItems() << endl; 01032 if (points->FWrite(file)) break; 01033 MRV_COUT << "faces: " << faces.NumItems() << endl; 01034 if (faces.FWrite(file)) break; 01035 01036 if (vertices.NumItems() > 0) 01037 { 01038 MRV_COUT << "root vertices: " << rootVertices.NumItems() << endl; 01039 if (rootVertices.FWrite(file)) break; 01040 MRV_COUT << "vertices: " << vertices.NumItems() << endl; 01041 if (vertices.FWrite(file)) break; 01042 MRV_COUT << "codes: " << vtxCodes.NumItems() << endl; 01043 if (vtxCodes.FWrite(file)) break; 01044 } 01045 01046 if (clusters.NumItems() > 0) 01047 { 01048 MRV_COUT << "root clusters: " << rootClusters.NumItems() << endl; 01049 if (rootClusters.FWrite(file)) break; 01050 MRV_COUT << "clusters: " << clusters.NumItems() << endl; 01051 if (clusters.FWrite(file)) break; 01052 } 01053 } 01054 while (false); 01055 01056 if (ferror(file)) 01057 perror("MRB write"); 01058 fclose(file); 01059 MRV_COUT << "done." << endl; 01060 } while (false); 01061 } 01062 01063 Bool MRModel::ParseText() 01064 { 01065 String func; 01066 Point vtx; 01067 Int numVertices; 01068 Int faceIdx = 0, vtxOffset, delta; 01069 01070 Int child[2], depFace[2]; 01071 Int vtxId; 01072 GCLReal cost; 01073 Point place; 01074 01075 Int clusID, clusLeft, clusRight; 01076 Point clusOrig; 01077 VecTrans clusAxis; 01078 Vector clusFitNormal; 01079 Point clusMin(vl_0), clusMax(vl_0); 01080 GCLReal clusD; 01081 01082 ifstream s; 01083 01084 vtxOffset = -1; // default is 1-based indexes 01085 delta = 0; // original mmf format had no delta-encoding 01086 clusID = -1; 01087 child[0] = -1; 01088 clusLeft = -1; 01089 cost = 0.01; 01090 01091 s.open(modelFile.GetPath()); 01092 if (!s) 01093 { 01094 cerr << "Cannot access " << modelFile.GetPath() << endl; 01095 return(false); 01096 } 01097 01098 numVertices = 0; 01099 01100 while (s) 01101 { 01102 if (func.ReadWord(s)) 01103 { 01104 if (func == "#$cost" || func == "ve") 01105 s >> vtxId >> cost; 01106 else if (func[0] == '#') 01107 ; 01108 else if (func == "v") 01109 { 01110 s >> vtx[0] >> vtx[1] >> vtx[2]; 01111 points->Append(vtx); 01112 numVertices++; 01113 } 01114 else if (func == "f" || func == "t") 01115 { 01116 Int a, b, c; 01117 01118 s >> a >> b >> c; 01119 01120 faces.Add(1); 01121 faces.Last().v[0] = a - 1; 01122 faces.Last().v[1] = b - 1; 01123 faces.Last().v[2] = c - 1; 01124 } 01125 else if (func == "set") 01126 { 01127 func.ReadWord(s); 01128 if (func == "vertex_correction") 01129 { 01130 // add vertex_correction to indexes to get 1-based 01131 // indexing. We use 0-based indexing, hence the 01132 // -1. 01133 s >> vtxOffset; 01134 vtxOffset = vtxOffset - 1; 01135 } 01136 else if (func == "delta_encoding") 01137 s >> delta; 01138 else 01139 cerr << "(ParseMMF) *** Ignoring unknown set variable: " 01140 << func << endl; 01141 } 01142 else if (func == "%SMF" || func == "#$SMF") 01143 { 01144 GCLReal version; 01145 s >> version; 01146 if (version < 1.0) 01147 vtxOffset = 0; // version 0 had 0-based offsets 01148 } 01149 01150 // === vertex-cluster stuff 01151 else if (func == "v%") 01152 // a vertex contraction 01153 { 01154 Char gobbleBracket; 01155 01156 // add previous contraction 01157 if (child[0] >= 0) 01158 AddContraction(child[0] + vtxOffset, child[1] + vtxOffset, 01159 depFace[0] - 1, depFace[1] - 1, cost, place, delta); 01160 01161 // read in start of new contraction 01162 ChompWhiteSpace(s); 01163 if (s.peek() == '(') 01164 s >> gobbleBracket; 01165 s >> child[0] >> child[1]; 01166 ChompWhiteSpace(s); 01167 if (s.peek() == ')') 01168 s >> gobbleBracket; 01169 s >> place[0] >> place[1] >> place[2]; 01170 faceIdx = 0; 01171 depFace[0] = depFace[1] = 0; 01172 cost += 0.01; // assume constant cost per contraction if 01173 // none is specified in the file. 01174 } 01175 else if (func == "f-") 01176 { 01177 // dependent face id of current contraction 01178 s >> depFace[faceIdx]; 01179 faceIdx ^= 1; 01180 } 01181 01182 // === face-cluster stuff 01183 else if (func == "f^") 01184 { 01185 if (clusID < 0) 01186 clusID = faces.NumItems(); // first cluster! 01187 01188 // add previous cluster record 01189 if (clusLeft > 0) 01190 { 01191 AddCluster(clusLeft, clusRight, clusOrig, clusAxis, 01192 clusFitNormal, clusD, clusMin, clusMax, clusID++); 01193 } 01194 s >> clusLeft >> clusRight; 01195 } 01196 else if (func == "fo") 01197 s >> clusOrig[0] >> clusOrig[1] >> clusOrig[2]; 01198 else if (func == "fe") 01199 { 01200 s >> clusAxis[0][0] >> clusAxis[0][1] >> clusAxis[0][2]; 01201 s >> clusAxis[1][0] >> clusAxis[1][1] >> clusAxis[1][2]; 01202 s >> clusAxis[2][0] >> clusAxis[2][1] >> clusAxis[2][2]; 01203 } 01204 else if (func == "fd") 01205 s >> clusD; 01206 else if (func == "fn") 01207 s >> clusFitNormal[0] >> clusFitNormal[1] >> clusFitNormal[2]; 01208 else if (func == "fx") 01209 { 01210 s >> clusMin[0] >> clusMin[1] >> clusMin[2]; 01211 s >> clusMax[0] >> clusMax[1] >> clusMax[2]; 01212 } 01213 else if (func == "fc") 01214 ; // cost -- ignore it. 01215 01216 // unrecognized! 01217 else 01218 cerr << "(ParseMMF) *** Ignoring unknown token: " << func << endl; 01219 01220 func.ReadLine(s); // ignore rest of line 01221 } 01222 } 01223 01224 s.close(); 01225 01226 if (child[0] >= 0) 01227 AddContraction(child[0] + vtxOffset, child[1] + vtxOffset, 01228 depFace[0] - 1, depFace[1] - 1, cost, place, delta); 01229 01230 if (clusLeft > 0) 01231 AddCluster(clusLeft, clusRight, clusOrig, clusAxis, 01232 clusFitNormal, clusD, clusMin, clusMax, clusID++); 01233 01234 if (clusID > 0) 01235 clustersActive.SetSize(clusID); 01236 01237 MRV_COUT << "Read " << numVertices << " vertices and " << faces.NumItems() 01238 << " faces." << endl; 01239 01240 return(true); 01241 } 01242 01243 Bool MRModel::Parse(StrConst filename) 01244 { 01245 Bool result; 01246 01247 if (!points) 01248 points = new PointList; 01249 01250 modelFile.SetPath(filename); 01251 01252 if (modelFile.GetExtension() == "mrb") 01253 result = ParseBinary(); 01254 else 01255 result = ParseText(); 01256 01257 if (!result) 01258 return(false); 01259 01260 MRV_COUT << "There are " << vertices.NumItems() << " vertex contractions, " 01261 << clusters.NumItems() << " face clusters." << endl; 01262 01263 MRV_COUT << "MEMORY:" << endl; 01264 if (points) 01265 MRV_COUT << " points " << sizeof(Point) * points->NumItems() / 1024.0 << endl; 01266 if (colours) 01267 MRV_COUT << " colours " << sizeof(Colour) * colours->NumItems() / 1024.0 << endl; 01268 MRV_COUT << " indexes " << sizeof(FaceIdx) * faces.NumItems() / 1024.0 << endl; 01269 MRV_COUT << " vtxFaces " << sizeof(FaceIdx) * vtxFaces.NumItems() / 1024.0 << endl; 01270 MRV_COUT << " vtxCodes " << sizeof(MRCodes) * vtxCodes.NumItems() / 1024.0 << endl; 01271 MRV_COUT << " vertices " << sizeof(MRVertex) * vertices.NumItems() / 1024.0 << endl; 01272 MRV_COUT << " clusters " << sizeof(FaceCluster) * clusters.NumItems() / 1024.0 << endl; 01273 01274 PrepareModel(); 01275 01276 return(true); 01277 } 01278 01279 Void MRModel::DrawClusterFaces(Int ic, Renderer &r) 01280 { 01281 if (IsFace(ic)) 01282 { 01283 PointList &pts = *points; 01284 Int *triIdx = faces[ic].v; 01285 Vector normal; 01286 01287 normal = FaceAreaNormal(ic); 01288 01289 r .Begin(scPrimitive::sRenderStyle) 01290 .N(norm(normal)) 01291 .P(pts[triIdx[0]]) 01292 .P(pts[triIdx[1]]) 01293 .P(pts[triIdx[2]]) 01294 .End(); 01295 } 01296 else 01297 { 01298 FaceCluster &mrf = Cluster(ic); 01299 01300 if (flags.IsSet(MRM_Ordered) && IsFace(mrf.child[0]) && IsFace(mrf.child[1])) 01301 { 01302 for (Int i = mrf.child[0]; i <= mrf.child[1]; i++) 01303 DrawClusterFaces(i, r); 01304 } 01305 01306 DrawClusterFaces(mrf.child[0], r); 01307 DrawClusterFaces(mrf.child[1], r); 01308 } 01309 } 01310 01311 Void MRModel::Draw(Renderer &r) 01312 { 01313 Int i; 01314 Int *idx; 01315 Bool hasVF = (vtxFaces.NumItems() > 0); 01316 01317 if (colourFaces && clusterColours.NumItems() == 0) 01318 CreateClusterColours(); 01319 01320 if (showFaces) 01321 { 01322 if (colourFaces) 01323 { 01324 for (i = 0; i < clustersActive.NumItems(); i++) 01325 if (clustersActive[i]) 01326 { 01327 r.C(clusterColours[i]); 01328 DrawClusterFaces(i, r); 01329 } 01330 } 01331 else 01332 { 01333 r.C(colour); 01334 for (i = 0; i < faces.NumItems(); i++) 01335 { 01336 if (hasVF) 01337 { 01338 if (!vtxFlags[i].IsSet(MRV_FaceActive)) 01339 continue; 01340 idx = vtxFaces[i].v; 01341 } 01342 else 01343 idx = faces[i].v; 01344 01345 // XXX shouldn't need norm()'s here, but MESA has prec. bug with 01346 // very small normals when GL_NORMALIZE... need workaround 01347 01348 r.Begin(scPrimitive::sRenderStyle); 01349 if (vertices.NumItems() > 0) 01350 { 01351 if (colours) 01352 r 01353 .N(norm(vertices[idx[0]].areaNormal)) 01354 .C((*colours)[idx[0]]) 01355 .P((*points)[idx[0]]) 01356 .N(norm(vertices[idx[1]].areaNormal)) 01357 .C((*colours)[idx[1]]) 01358 .P((*points)[idx[1]]) 01359 .N(norm(vertices[idx[2]].areaNormal)) 01360 .C((*colours)[idx[2]]) 01361 .P((*points)[idx[2]]); 01362 else 01363 r 01364 .N(norm(vertices[idx[0]].areaNormal)) 01365 .P((*points)[idx[0]]) 01366 .N(norm(vertices[idx[1]].areaNormal)) 01367 .P((*points)[idx[1]]) 01368 .N(norm(vertices[idx[2]].areaNormal)) 01369 .P((*points)[idx[2]]); 01370 } 01371 else 01372 { 01373 Vector areaNormal; 01374 01375 CalcTriAreaNormal( 01376 (*points)[idx[0]], 01377 (*points)[idx[1]], 01378 (*points)[idx[2]], 01379 areaNormal 01380 ); 01381 01382 r.N(norm(areaNormal)); 01383 01384 if (colours) 01385 r .C((*colours)[idx[0]]) 01386 .P((*points)[idx[0]]) 01387 .C((*colours)[idx[1]]) 01388 .P((*points)[idx[1]]) 01389 .C((*colours)[idx[2]]) 01390 .P((*points)[idx[2]]); 01391 else 01392 { 01393 r .P((*points)[idx[0]]) 01394 .P((*points)[idx[1]]) 01395 .P((*points)[idx[2]]); 01396 } 01397 } 01398 r.End(); 01399 } 01400 } 01401 } 01402 01403 if (showMeta) 01404 { 01405 if (clustersActive.NumItems() > 0) 01406 DrawClusters(r); 01407 else if (vertices.NumItems() > 0) 01408 DrawVertices(r); 01409 } 01410 } 01411 01412 Void MRModel::CreateClusterColours() 01413 { 01414 if (clustersActive.NumItems() > 0) 01415 { 01416 Int i, fc1, fc2; 01417 Colour c; 01418 Double area1, area2; 01419 01420 clusterColours.SetSize(clustersActive.NumItems()); 01421 01422 if (!sAvgClusColours) 01423 { 01424 for (i = 0; i < faces.NumItems(); i++) 01425 clusterColours[i] = HSVCol(drand48() * 360.0, 1.0, 1.0); 01426 for (i = lastClusterID; i <= firstClusterID; i++) 01427 { 01428 fc1 = Cluster(i).child[0]; 01429 fc2 = Cluster(i).child[1]; 01430 // XXX fix when we store face areaNormals 01431 if (IsFace(fc1)) 01432 area1 = len(FaceAreaNormal(fc1)); 01433 else 01434 area1 = Cluster(fc1).totArea; 01435 01436 if (IsFace(fc2)) 01437 area2 = len(FaceAreaNormal(fc2)); 01438 else 01439 area2 = Cluster(fc2).totArea; 01440 01441 if (area1 > area2) 01442 c = clusterColours[fc1]; 01443 else 01444 c = clusterColours[fc2]; 01445 01446 clusterColours[i] = c; 01447 } 01448 } 01449 else 01450 { 01451 for (i = 0; i < faces.NumItems(); i++) 01452 clusterColours[i] = HSVCol(drand48() * 360.0, 1.0, 1.0); 01453 for (i = lastClusterID; i <= firstClusterID; i++) 01454 { 01455 c = clusterColours[Cluster(i).child[0]]; 01456 c += clusterColours[Cluster(i).child[1]]; 01457 c /= 2.0; 01458 clusterColours[i] = c; 01459 } 01460 } 01461 } 01462 } 01463 01464 Void MRModel::DrawClusters(Renderer &r) 01466 { 01467 Int i; 01468 01469 for (i = 0; i < clustersActive.NumItems(); i++) 01470 if (clustersActive[i]) 01471 if (!IsFace(i)) 01472 { 01473 if (!showFaces && colourFaces) 01474 r.C(Colour4(clusterColours[i], 0.5)); 01475 else 01476 r.C(Colour4(colour, 0.5)); 01477 Cluster(i).Draw(r); 01478 } 01479 else if (!showFaces) 01480 { 01481 if (colourFaces) 01482 r.C(clusterColours[i]); 01483 else 01484 r.C(cYellow); 01485 DrawClusterFaces(i, r); 01486 } 01487 } 01488 01489 Void MRModel::DrawVertices(Renderer &r) 01491 { 01492 Int i; 01493 01494 r.C(Colour4(cGreen, 0.5)); 01495 01496 for (i = 0; i < vertices.NumItems(); i++) 01497 if (vtxFlags[i].IsSet(MRV_Active)) 01498 { 01499 r.N(vertices[i].areaNormal); 01500 DrawCircle(r, (*points)[i], 01501 norm(vertices[i].areaNormal), 01502 sqrt(len(vertices[i].areaNormal) / vl_pi) 01503 ); 01504 } 01505 } 01506 01507 Void MRModel::SimplestModel() 01508 { 01509 Int i; 01510 01511 AdaptClusters(0); 01512 01513 for (i = 0; i < vertices.NumItems(); i++) 01514 { 01515 MRVertex &v = vertices[i]; 01516 01517 if (v.CanContract(i, vtxFlags)) 01518 v.Contract(i, vtxFlags); 01519 } 01520 01521 lastComplexity = 0.0; 01522 AdjustLeafFaces(); 01523 } 01524 01525 Void MRModel::MostComplexModel() 01526 { 01527 Int i; 01528 01529 AdaptClusters(faces.NumItems()); 01530 01531 for (i = vertices.NumItems() - 1; i >= 0; i--) 01532 { 01533 MRVertex &v = vertices[i]; 01534 01535 if (v.CanExpand(i, vtxFlags)) 01536 v.Expand(i, vtxFlags); 01537 } 01538 01539 lastComplexity = 1.0; 01540 AdjustLeafFaces(); 01541 } 01542 01543 Vector MRModel::FaceAreaNormal(Int faceIdx) 01544 { 01545 Vector an; 01546 Int *triIdx = faces[faceIdx].v; 01547 01548 CalcTriAreaNormal((*points)[triIdx[0]], 01549 (*points)[triIdx[1]], 01550 (*points)[triIdx[2]], 01551 an); 01552 01553 return(0.5 * an); 01554 } 01555 01556 Void MRModel::UpdateBounds(Point &min, Point &max, 01557 const Transform &t) 01558 { 01559 Int i; 01560 01561 if (vtxFaces.NumItems() > 0) 01562 { 01563 for (i = 0; i < vtxFaces.NumItems(); i++) 01564 if (vtxFlags[i].IsSet(MRV_FaceActive)) 01565 { 01566 ::UpdateBounds(xform(t, points->Item(vtxFaces[i].v[0])), min, max); 01567 ::UpdateBounds(xform(t, points->Item(vtxFaces[i].v[1])), min, max); 01568 ::UpdateBounds(xform(t, points->Item(vtxFaces[i].v[2])), min, max); 01569 } 01570 } 01571 else 01572 for (i = 0; i < points->NumItems(); i++) 01573 ::UpdateBounds(xform(t, points->Item(i)), min, max); 01574 } 01575 01576 // --- scMRModel methods ------------------------------------------------------ 01577 01578 01579 GCLReal scMRModel::complexity = 0.1; 01580 01581 scMRModel::scMRModel() : scPrimitive(pMRModel), model(), currentComplexity(0.0) 01582 { 01583 } 01584 01585 Void scMRModel::Draw(Renderer &r, SLContext *context) 01586 { 01587 Colour *cPtr; 01588 ColourList *cClrs; 01589 01590 if (cPtr = SC_GET(Colour)) 01591 model.colour = *cPtr; 01592 if (!model.colours && (cClrs = SC_GET(Colours))) 01593 { 01594 if (cClrs->NumItems() == model.points->NumItems()) 01595 model.colours = cClrs; 01596 else 01597 cerr << "ignoring bad colours list in MRModel" << endl; 01598 } 01599 01600 model.AdaptComplexity(complexity); 01601 model.Draw(r); 01602 } 01603 01604 Void scMRModel::DecimateSelf(Decimator &dec) 01605 { 01606 if (dec.flags & DecIgnoreMRM) 01607 return; 01608 01609 Int i, j; 01610 FaceIdx fi; 01611 Bool changed; 01612 01613 dec.flags.Set(DecIsMRM); 01614 dec.context->Set(aPoints, (scPoints*) model.points); 01615 01616 changed = true; 01617 01618 if (model.vtxFaces.NumItems() > 0) 01619 { 01620 Index *map = 0; 01621 01622 model.AdaptComplexity(complexity); 01623 01624 if (dec.flags.IsSet(DecUseMaster)) 01625 { 01626 // we want to add only those points that are part of 01627 // the current model, so need to remap... 01628 01629 dec.pointsAccNum = dec.pointsAcc->NumItems(); 01630 01631 map = new Index[model.points->NumItems()]; 01632 for (i = 0; i < model.points->NumItems(); i++) 01633 map[i] = -1; 01634 } 01635 01636 for (i = 0; i < model.faces.NumItems(); i++) 01637 if (model.vtxFlags[i].IsSet(MRV_FaceActive)) 01638 { 01639 fi = model.vtxFaces[i]; 01640 01641 if (map) 01642 for (j = 0; j < 3; j++) 01643 { 01644 if (map[fi.v[j]] < 0) 01645 { 01646 map[fi.v[j]] = dec.pointsAcc->NumItems(); 01647 dec.pointsAcc->Append(xform(dec.transAcc, model.points->Item(fi.v[j]))); 01648 } 01649 fi.v[j] = map[fi.v[j]]; 01650 } 01651 else 01652 { 01653 fi.v[0] += dec.pointsAccNum; 01654 fi.v[1] += dec.pointsAccNum; 01655 fi.v[2] += dec.pointsAccNum; 01656 } 01657 dec.HandlePoly(3, fi.v, changed); 01658 changed = false; 01659 dec.decNum++; 01660 } 01661 01662 delete[] map; 01663 } 01664 else 01665 { 01666 // standard 01667 if (dec.flags.IsSet(DecUseMaster)) 01668 { 01669 dec.pointsAccNum = dec.pointsAcc->NumItems(); 01670 01671 dec.pointsAcc->Add(model.points->NumItems()); 01672 // apply the current model transform to the new points 01673 i = dec.pointsAccNum; 01674 for (j = 0; j < model.points->NumItems(); j++) 01675 dec.pointsAcc->Item(i++) = 01676 xform(dec.transAcc, model.points->Item(j)); 01677 } 01678 01679 for (i = 0; i < model.faces.NumItems(); i++) 01680 { 01681 fi = model.faces[i]; 01682 01683 fi.v[0] += dec.pointsAccNum; 01684 fi.v[1] += dec.pointsAccNum; 01685 fi.v[2] += dec.pointsAccNum; 01686 01687 dec.HandlePoly(3, fi.v, changed); 01688 changed = false; 01689 dec.decNum++; 01690 } 01691 } 01692 01693 dec.context->Set(aPoints, 0); 01694 dec.flags.UnSet(DecIsMRM); 01695 } 01696 01697 Void scMRModel::SetComplexity(GCLReal comp) 01698 { 01699 complexity = comp; 01700 }; 01701 01702 GCLReal scMRModel::GetComplexity() 01703 { 01704 return(complexity); 01705 }; 01706 01707 Void scMRModel::UpdateBounds(Point &min, Point &max, 01708 const Transform &t) 01709 { 01710 model.UpdateBounds(min, max, t); 01711 } 01712 01713 #include "gcl/SceneLang.h" 01714 01715 scScenePtr ParseMMFFile(const Char *filename) 01716 { 01717 scScenePtr result; 01718 scMRModel *model; 01719 01720 result = slBeginObject(filename); 01721 model = (scMRModel*) slObject("mr-model"); 01722 model->model.points = new scPoints; 01723 slEndObject(); 01724 01725 model->model.Parse(filename); 01726 01727 return(result); 01728 } 01729 01730 // --- ModelsFinder methods --------------------------------------------------- 01731 01732 01733 Void MRModelsFinder::Start() 01734 { 01735 scSceneAction::Start(); 01736 models.Clear(); 01737 } 01738 01739 Void MRModelsFinder::Primitive(scPrimitive *sp) 01740 { 01741 if (sp->PrimID() == pMRModel) 01742 models.Append(&((scMRModel*) sp)->model); 01743 }