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

MRModel.cc

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

Generated at Sat Aug 5 00:17:01 2000 for Graphics Class Library by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000