[774] | 1 | /************************************************************************
|
---|
| 2 |
|
---|
| 3 | Adjacency model representation.
|
---|
| 4 | $Id: AdjModel.cxx,v 1.1 1997/06/25 15:24:52 garland Exp $
|
---|
| 5 |
|
---|
| 6 | Adapted from:
|
---|
| 7 | mlab: (Id: polymodel.cc,v 1.21 1997/02/06 16:34:14 garland Exp)
|
---|
| 8 | via
|
---|
[1025] | 9 | simplif: (Id: polymodel.cc,v 1.5 1997/02/25 20:36:36 garland Exp)
|
---|
[774] | 10 |
|
---|
| 11 | ************************************************************************/
|
---|
| 12 |
|
---|
| 13 | #include "AdjModel.h"
|
---|
| 14 |
|
---|
[1025] | 15 | using namespace simplif;
|
---|
[774] | 16 |
|
---|
| 17 | int Model::in_Vertex(const Vec3& p)
|
---|
| 18 | {
|
---|
[1526] | 19 | Vertex *v = newVertex(p[X], p[Y], p[Z]);
|
---|
| 20 | bounds.addPoint(p);
|
---|
| 21 | return vertCount() - 1;
|
---|
[774] | 22 | }
|
---|
| 23 |
|
---|
| 24 | int Model::in_Normal(const Vec3& n)
|
---|
| 25 | {
|
---|
| 26 | normals.add(n);
|
---|
| 27 | return normCount()-1;
|
---|
| 28 | }
|
---|
| 29 |
|
---|
| 30 | int Model::in_TexCoord(const Vec2& t)
|
---|
| 31 | {
|
---|
| 32 | texcoords.add(t);
|
---|
| 33 | return texcoordCount()-1;
|
---|
| 34 | }
|
---|
| 35 |
|
---|
| 36 | int Model::in_Face(int a, int b, int c, int n1, int n2, int n3, int t1, int t2, int t3)
|
---|
| 37 | {
|
---|
[1526] | 38 | Vertex *v1 = vertices(a-1);
|
---|
| 39 | Vertex *v2 = vertices(b-1);
|
---|
| 40 | Vertex *v3 = vertices(c-1);
|
---|
[774] | 41 |
|
---|
[1526] | 42 | Face *t = newFace(v1, v2, v3);
|
---|
| 43 |
|
---|
[774] | 44 | t->normals[0] = n1;
|
---|
| 45 | t->normals[1] = n2;
|
---|
| 46 | t->normals[2] = n3;
|
---|
| 47 |
|
---|
| 48 | t->texcoords[0] = t1;
|
---|
| 49 | t->texcoords[1] = t2;
|
---|
| 50 | t->texcoords[2] = t3;
|
---|
| 51 |
|
---|
| 52 | return faceCount() - 1;
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | int Model::miin_Face(int a, int b, int c)
|
---|
| 56 | {
|
---|
[1526] | 57 | Vertex *v1 = vertices(a);
|
---|
| 58 | Vertex *v2 = vertices(b);
|
---|
| 59 | Vertex *v3 = vertices(c);
|
---|
[774] | 60 |
|
---|
[1526] | 61 | Face *t = newFace(v1, v2, v3);
|
---|
| 62 |
|
---|
[774] | 63 | t->normals[0] = a;
|
---|
| 64 | t->normals[1] = b;
|
---|
| 65 | t->normals[2] = c;
|
---|
| 66 |
|
---|
| 67 | t->texcoords[0] = a;
|
---|
| 68 | t->texcoords[1] = b;
|
---|
| 69 | t->texcoords[2] = c;
|
---|
| 70 |
|
---|
| 71 | return faceCount() - 1;
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | #ifdef SUPPORT_FCOLOR
|
---|
| 75 | int Model::in_FColor(const Vec3& c)
|
---|
| 76 | {
|
---|
[1526] | 77 | Face *f = faces(faces.length()-1);
|
---|
[774] | 78 |
|
---|
[1526] | 79 | if( !f->props )
|
---|
| 80 | {
|
---|
| 81 | f->props = new FProp;
|
---|
| 82 | }
|
---|
[774] | 83 |
|
---|
[1526] | 84 | f->props->color = c;
|
---|
| 85 |
|
---|
| 86 | return 0;
|
---|
[774] | 87 | }
|
---|
| 88 | #endif
|
---|
| 89 |
|
---|
| 90 | #ifdef SUPPORT_VCOLOR
|
---|
| 91 | int Model::in_VColor(const Vec3& c)
|
---|
| 92 | {
|
---|
[1526] | 93 | Vertex *v = vertices(vertices.length()-1);
|
---|
[774] | 94 |
|
---|
[1526] | 95 | if( !v->props )
|
---|
| 96 | {
|
---|
| 97 | v->props = new VProp;
|
---|
| 98 | }
|
---|
[774] | 99 |
|
---|
[1526] | 100 | v->props->color = c;
|
---|
| 101 | return 0;
|
---|
[774] | 102 | }
|
---|
| 103 | #endif
|
---|
| 104 |
|
---|
| 105 | Vec3 Model::synthesizeNormal(Vertex *v)
|
---|
| 106 | {
|
---|
[1526] | 107 | Vec3 n(0,0,0);
|
---|
| 108 | int n_count = 0;
|
---|
[774] | 109 |
|
---|
[1526] | 110 | edge_buffer& edges = v->edgeUses();
|
---|
| 111 | for(int i=0; i<edges.length(); i++)
|
---|
| 112 | {
|
---|
| 113 | face_buffer& faces = edges(i)->faceUses();
|
---|
[774] | 114 |
|
---|
[1526] | 115 | for(int j=0; j<faces.length(); j++)
|
---|
| 116 | {
|
---|
| 117 | n += faces(j)->plane().normal();
|
---|
| 118 | n_count++;
|
---|
| 119 | }
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | if( n_count )
|
---|
[774] | 123 | {
|
---|
[1526] | 124 | n /= (real)n_count;
|
---|
[774] | 125 | }
|
---|
[1526] | 126 | else
|
---|
| 127 | {
|
---|
[774] | 128 | std::cerr << "Vertex with no normals!!: " << v->uniqID;
|
---|
| 129 | std::cerr << " / " << v->tempID << std::endl;
|
---|
[1526] | 130 | }
|
---|
| 131 | return n;
|
---|
[774] | 132 | }
|
---|
| 133 |
|
---|
| 134 |
|
---|
| 135 | ////////////////////////////////////////////////////////////////////////
|
---|
| 136 | //
|
---|
| 137 | // Model Transmogrification:
|
---|
| 138 | //
|
---|
| 139 | // These routines are the basic model munging procedures.
|
---|
| 140 | // All model simplification is implemented in terms of these
|
---|
| 141 | // transmogrification primitives.
|
---|
| 142 | ////////////////////////////////////////////////////////////////////////
|
---|
| 143 |
|
---|
| 144 |
|
---|
| 145 | Vertex *Model::newVertex(real x, real y, real z)
|
---|
| 146 | {
|
---|
[1526] | 147 | Vertex *v = new Vertex(x, y, z);
|
---|
[774] | 148 |
|
---|
[1526] | 149 | v->vID = v->uniqID = vertices.add(v);
|
---|
[774] | 150 |
|
---|
[1526] | 151 | /* if( logfile && selected_output&OUTPUT_MODEL_DEFN )
|
---|
| 152 | *logfile << "v " << x << " " << y << " " << z << std::endl;
|
---|
| 153 | */
|
---|
| 154 | validVertCount++;
|
---|
[774] | 155 |
|
---|
[1526] | 156 | return v;
|
---|
[774] | 157 | }
|
---|
| 158 |
|
---|
| 159 | Edge *Model::newEdge(Vertex *a, Vertex *b)
|
---|
| 160 | {
|
---|
[1526] | 161 | Edge *e = new Edge(a, b);
|
---|
[774] | 162 |
|
---|
[1526] | 163 | e->uniqID = edges.add(e);
|
---|
| 164 | e->sym()->uniqID = e->uniqID;
|
---|
[774] | 165 |
|
---|
[1526] | 166 | validEdgeCount++;
|
---|
[774] | 167 |
|
---|
[1526] | 168 | return e;
|
---|
[774] | 169 | }
|
---|
| 170 |
|
---|
| 171 | static Edge *get_edge(Model *m, Vertex *org, Vertex *v)
|
---|
| 172 | {
|
---|
[1526] | 173 | edge_buffer& edge_uses = org->edgeUses();
|
---|
[774] | 174 |
|
---|
[1526] | 175 | for (int i=0; i<edge_uses.length(); i++)
|
---|
| 176 | {
|
---|
| 177 | if ( edge_uses(i)->dest() == v )
|
---|
| 178 | {
|
---|
| 179 | return edge_uses(i);
|
---|
| 180 | }
|
---|
| 181 | }
|
---|
[774] | 182 |
|
---|
[1526] | 183 | Edge *e = m->newEdge(org, v);
|
---|
[774] | 184 |
|
---|
[1526] | 185 | return e;
|
---|
[774] | 186 | }
|
---|
| 187 |
|
---|
| 188 | Face *Model::newFace(Vertex *v1, Vertex *v2, Vertex *v3)
|
---|
| 189 | {
|
---|
[1526] | 190 | Edge *e0 = get_edge(this, v1, v2); // v1->edgeTo(m, v2);
|
---|
| 191 | Edge *e1 = get_edge(this, v2, v3); // v2->edgeTo(m, v3);
|
---|
| 192 | Edge *e2 = get_edge(this, v3, v1); // v3->edgeTo(m, v1);
|
---|
[774] | 193 |
|
---|
[1526] | 194 | Face *t = new Face(e0, e1, e2);
|
---|
[774] | 195 |
|
---|
[1526] | 196 | t->uniqID = faces.add(t);
|
---|
[774] | 197 |
|
---|
[1526] | 198 | /* if( logfile && selected_output&OUTPUT_MODEL_DEFN )
|
---|
| 199 | *logfile << "f " << v1->uniqID+1 << " "
|
---|
| 200 | << v2->uniqID+1 << " " << v3->uniqID+1 << std::endl;
|
---|
| 201 | */
|
---|
| 202 | validFaceCount++;
|
---|
| 203 |
|
---|
| 204 | return t;
|
---|
[774] | 205 | }
|
---|
| 206 |
|
---|
| 207 |
|
---|
| 208 | void Model::killVertex(Vertex *v)
|
---|
| 209 | {
|
---|
[1526] | 210 | if( v->isValid() )
|
---|
| 211 | {
|
---|
| 212 | /* if( logfile && selected_output&OUTPUT_CONTRACTIONS )
|
---|
| 213 | *logfile << "v- " << v->uniqID+1 << std::endl;
|
---|
| 214 | */
|
---|
| 215 | v->kill();
|
---|
| 216 | validVertCount--;
|
---|
| 217 | }
|
---|
[774] | 218 | }
|
---|
| 219 |
|
---|
| 220 | void Model::killEdge(Edge *e)
|
---|
| 221 | {
|
---|
[1526] | 222 | if( e->isValid() )
|
---|
| 223 | {
|
---|
| 224 | e->kill();
|
---|
| 225 | validEdgeCount--;
|
---|
| 226 | }
|
---|
[774] | 227 | }
|
---|
| 228 |
|
---|
| 229 | void Model::killFace(Face *f)
|
---|
| 230 | {
|
---|
[1526] | 231 | if( f->isValid() )
|
---|
| 232 | {
|
---|
| 233 | /* if( logfile && selected_output&OUTPUT_CONTRACTIONS )
|
---|
| 234 | *logfile << "f- " << f->uniqID+1 << std::endl;
|
---|
| 235 | */
|
---|
| 236 | f->kill();
|
---|
| 237 | validFaceCount--;
|
---|
| 238 | }
|
---|
[774] | 239 | }
|
---|
| 240 |
|
---|
| 241 | void Model::reshapeVertex(Vertex *v, real x, real y, real z)
|
---|
| 242 | {
|
---|
[1526] | 243 | v->set(x, y, z);
|
---|
[774] | 244 |
|
---|
| 245 | #ifdef LOG_LOWLEVEL_OPS
|
---|
[1526] | 246 | if( logfile )
|
---|
| 247 | {
|
---|
| 248 | *logfile << "v! " << v->uniqID+1 << " "
|
---|
| 249 | << x << " " << y << " " << z << endl;
|
---|
| 250 | }
|
---|
[774] | 251 | #endif
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | void Model::remapVertex(Vertex *from, Vertex *to)
|
---|
| 255 | {
|
---|
[1526] | 256 | from->remapTo(to);
|
---|
[774] | 257 |
|
---|
| 258 | #ifdef LOG_LOWLEVEL_OPS
|
---|
[1526] | 259 | if( logfile )
|
---|
| 260 | {
|
---|
| 261 | *logfile << "v> " << from->uniqID+1 << " " << to->uniqID+1 << endl;
|
---|
| 262 | }
|
---|
[774] | 263 | #endif
|
---|
| 264 | }
|
---|
| 265 |
|
---|
| 266 | void Model::contract(Vertex *v1,
|
---|
| 267 | const vert_buffer& rest,
|
---|
| 268 | const Vec3& to,
|
---|
| 269 | face_buffer& changed)
|
---|
| 270 | {
|
---|
[1526] | 271 | int i;
|
---|
[774] | 272 |
|
---|
[1526] | 273 | /* if( logfile && selected_output&OUTPUT_CONTRACTIONS )
|
---|
| 274 | {
|
---|
| 275 | *logfile << "v% (" << v1->uniqID+1;
|
---|
| 276 | for(i=0; i<rest.length(); i++)
|
---|
| 277 | *logfile << " " << rest(i)->uniqID+1;
|
---|
[774] | 278 |
|
---|
[1526] | 279 | *logfile << ") " << to[X] << " " << to[Y] << " " << to[Z] << std::endl;
|
---|
| 280 | }
|
---|
| 281 | */
|
---|
[774] | 282 |
|
---|
[1526] | 283 | //
|
---|
| 284 | // Collect all the faces that are going to be changed
|
---|
| 285 | //
|
---|
| 286 | contractionRegion(v1, rest, changed);
|
---|
[774] | 287 |
|
---|
[1526] | 288 | reshapeVertex(v1, to[X], to[Y], to[Z]);
|
---|
| 289 |
|
---|
| 290 | for(i=0; i<rest.length(); i++)
|
---|
| 291 | {
|
---|
[774] | 292 | rest(i)->remapTo(v1);
|
---|
[1526] | 293 | }
|
---|
[774] | 294 |
|
---|
[1526] | 295 | removeDegeneracy(changed);
|
---|
[774] | 296 | }
|
---|
| 297 |
|
---|
| 298 | void Model::maybeFixFace(Face *F)
|
---|
| 299 | {
|
---|
[1526] | 300 | //
|
---|
| 301 | // Invalid faces do not need to be fixed.
|
---|
[774] | 302 | #ifdef SAFETY
|
---|
[1526] | 303 | assert( F->isValid() );
|
---|
[774] | 304 | #endif
|
---|
| 305 |
|
---|
[1526] | 306 | Vertex *v0=F->vertex(0); Vertex *v1=F->vertex(1); Vertex *v2=F->vertex(2);
|
---|
| 307 | Edge *e0 = F->edge(0); Edge *e1 = F->edge(1); Edge *e2 = F->edge(2);
|
---|
[774] | 308 |
|
---|
[1526] | 309 | bool a=(v0 == v1), b=(v0 == v2), c=(v1 == v2);
|
---|
[774] | 310 |
|
---|
[1526] | 311 | if( a && c )
|
---|
| 312 | {
|
---|
| 313 | // This triangle has been reduced to a point
|
---|
| 314 | killEdge(e0);
|
---|
| 315 | killEdge(e1);
|
---|
| 316 | killEdge(e2);
|
---|
[774] | 317 |
|
---|
[1526] | 318 | killFace(F);
|
---|
| 319 | }
|
---|
| 320 | //
|
---|
| 321 | // In the following 3 cases, the triangle has become an edge
|
---|
| 322 | else if( a )
|
---|
| 323 | {
|
---|
| 324 | killEdge(e0);
|
---|
| 325 | e1->remapTo(e2->sym());
|
---|
| 326 | killFace(F);
|
---|
| 327 | }
|
---|
| 328 | else if( b )
|
---|
| 329 | {
|
---|
| 330 | killEdge(e2);
|
---|
| 331 | e0->remapTo(e1->sym());
|
---|
| 332 | killFace(F);
|
---|
| 333 | }
|
---|
| 334 | else if( c )
|
---|
| 335 | {
|
---|
| 336 | killEdge(e1);
|
---|
| 337 | e0->remapTo(e2->sym());
|
---|
| 338 | killFace(F);
|
---|
| 339 | }
|
---|
| 340 | else
|
---|
| 341 | {
|
---|
| 342 | // This triangle remains non-degenerate
|
---|
| 343 | /* // SUS: recalcular la normal en los triangulos cambiados no degenerados
|
---|
[774] | 344 |
|
---|
[1526] | 345 | simplif::Vertex * auxv0 = F->vertex(0);
|
---|
| 346 | simplif::Vertex * auxv1 = F->vertex(1);
|
---|
| 347 | simplif::Vertex * auxv2 = F->vertex(2);
|
---|
| 348 | simplif::Vec3 vd1(auxv1->operator[](simplif::X) - auxv0->operator[](simplif::X),
|
---|
| 349 | auxv1->operator[](simplif::Y) - auxv0->operator[](simplif::Y),
|
---|
| 350 | auxv1->operator[](simplif::Z) - auxv0->operator[](simplif::Z));
|
---|
| 351 | simplif::Vec3 vd2(auxv2->operator[](simplif::X) - auxv0->operator[](simplif::X),
|
---|
| 352 | auxv2->operator[](simplif::Y) - auxv0->operator[](simplif::Y),
|
---|
| 353 | auxv2->operator[](simplif::Z) - auxv0->operator[](simplif::Z));
|
---|
[774] | 354 |
|
---|
[1526] | 355 | simplif::unitize(vd1);
|
---|
| 356 | simplif::unitize(vd2);
|
---|
[774] | 357 |
|
---|
[1526] | 358 | simplif::Vec3 vn = vd1 ^ vd2;
|
---|
| 359 | simplif::unitize(vn);
|
---|
| 360 |
|
---|
[774] | 361 | //auxf->vertex_normals[0] = vn;
|
---|
| 362 | //auxf->vertex_normals[1] = vn;
|
---|
| 363 | //auxf->vertex_normals[2] = vn;
|
---|
[1025] | 364 | F->vertex_normals[0][simplif::X] = vn[simplif::X];
|
---|
| 365 | F->vertex_normals[0][simplif::Y] = vn[simplif::Y];
|
---|
| 366 | F->vertex_normals[0][simplif::Z] = vn[simplif::Z];
|
---|
| 367 | F->vertex_normals[1][simplif::X] = vn[simplif::X];
|
---|
| 368 | F->vertex_normals[1][simplif::Y] = vn[simplif::Y];
|
---|
| 369 | F->vertex_normals[1][simplif::Z] = vn[simplif::Z];
|
---|
| 370 | F->vertex_normals[2][simplif::X] = vn[simplif::X];
|
---|
| 371 | F->vertex_normals[2][simplif::Y] = vn[simplif::Y];
|
---|
| 372 | F->vertex_normals[2][simplif::Z] = vn[simplif::Z];*/
|
---|
[774] | 373 |
|
---|
[1526] | 374 | }
|
---|
[774] | 375 | }
|
---|
| 376 |
|
---|
| 377 | void Model::removeDegeneracy(face_buffer& changed)
|
---|
| 378 | {
|
---|
[1526] | 379 | for(int i=0; i<changed.length(); i++)
|
---|
| 380 | {
|
---|
[774] | 381 | maybeFixFace(changed(i));
|
---|
[1526] | 382 | }
|
---|
[774] | 383 | }
|
---|
| 384 |
|
---|
| 385 | void Model::contractionRegion(Vertex *v1,
|
---|
[1526] | 386 | const vert_buffer& vertices,
|
---|
| 387 | face_buffer& changed)
|
---|
[774] | 388 | {
|
---|
[1526] | 389 | changed.reset();
|
---|
[774] | 390 |
|
---|
[1526] | 391 | // First, reset the marks on all reachable vertices
|
---|
| 392 | int i;
|
---|
[774] | 393 |
|
---|
[1526] | 394 | untagFaceLoop(v1);
|
---|
| 395 |
|
---|
| 396 | for(i = 0; i < vertices.length(); i++)
|
---|
| 397 | {
|
---|
[774] | 398 | untagFaceLoop(vertices(i));
|
---|
[1526] | 399 | }
|
---|
[774] | 400 |
|
---|
[1526] | 401 | // Now, pick out all the unique reachable faces
|
---|
| 402 | collectFaceLoop(v1, changed);
|
---|
| 403 |
|
---|
| 404 | for(i = 0; i < vertices.length(); i++)
|
---|
| 405 | {
|
---|
[774] | 406 | collectFaceLoop(vertices(i), changed);
|
---|
[1526] | 407 | }
|
---|
[774] | 408 | }
|
---|
| 409 |
|
---|
| 410 |
|
---|
| 411 | void Model::contractionRegion(Vertex *v1, Vertex *v2, face_buffer& changed)
|
---|
| 412 | {
|
---|
[1526] | 413 | changed.reset();
|
---|
[774] | 414 |
|
---|
[1526] | 415 | //
|
---|
| 416 | // Clear marks on all reachable faces
|
---|
| 417 | untagFaceLoop(v1);
|
---|
| 418 | untagFaceLoop(v2);
|
---|
[774] | 419 |
|
---|
[1526] | 420 | //
|
---|
| 421 | // Collect all the unique reachable faces
|
---|
| 422 | collectFaceLoop(v1, changed);
|
---|
| 423 | collectFaceLoop(v2, changed);
|
---|
[774] | 424 | }
|
---|
| 425 |
|
---|
| 426 | void Model::contract(Vertex *v1, Vertex *v2, const Vec3& to,
|
---|
| 427 | face_buffer& changed)
|
---|
| 428 | {
|
---|
| 429 | #ifdef SAFETY
|
---|
[1526] | 430 | assert( v1 != v2);
|
---|
[774] | 431 | #endif
|
---|
[1526] | 432 | //
|
---|
| 433 | // Collect all the faces that are going to be changed
|
---|
| 434 | //
|
---|
| 435 | contractionRegion(v1, v2, changed);
|
---|
[774] | 436 |
|
---|
[1526] | 437 | reshapeVertex(v1, to[X], to[Y], to[Z]);
|
---|
[774] | 438 |
|
---|
[1526] | 439 | // Map v2 ---> v1. This accomplishes the topological change that we want.
|
---|
| 440 | v2->remapTo(v1);
|
---|
[774] | 441 |
|
---|
[1526] | 442 | // std::cout << "Contract(QslimInds): " << v2->validID() << " --> " << v1->validID() << std::endl;
|
---|
[774] | 443 |
|
---|
[1526] | 444 | removeDegeneracy(changed);
|
---|
[774] | 445 | }
|
---|
| 446 |
|
---|
| 447 | /*
|
---|
| 448 | ostream& operator<<(ostream& out, Model& M)
|
---|
| 449 | {
|
---|
| 450 | int i;
|
---|
| 451 | int uniqVerts = 0;
|
---|
| 452 |
|
---|
| 453 | out << "#$SMF 1.0" << endl;
|
---|
| 454 |
|
---|
| 455 | out_annotate(out, M);
|
---|
| 456 |
|
---|
| 457 | for(i=0; i<M.vertCount(); i++)
|
---|
| 458 | {
|
---|
| 459 | if( M.vertex(i)->isValid() )
|
---|
| 460 | {
|
---|
| 461 | M.vertex(i)->tempID = ++uniqVerts;
|
---|
| 462 |
|
---|
| 463 | out_annotate(out, M.vertex(i));
|
---|
| 464 | const Vertex& v = *M.vertex(i);
|
---|
| 465 | out << "v " << v[X] << " " << v[Y] << " " << v[Z] << endl;
|
---|
| 466 |
|
---|
| 467 | #ifdef SUPPORT_VCOLOR
|
---|
| 468 | if( v.props )
|
---|
| 469 | out << ":vc "
|
---|
| 470 | << v.props->color[X] << " "
|
---|
| 471 | << v.props->color[Y] << " "
|
---|
| 472 | << v.props->color[Z] << endl;
|
---|
| 473 | #endif
|
---|
| 474 | }
|
---|
| 475 | else
|
---|
| 476 | M.vertex(i)->tempID = -1;
|
---|
| 477 |
|
---|
| 478 | }
|
---|
| 479 |
|
---|
| 480 | for(i=0; i<M.faceCount(); i++)
|
---|
| 481 | {
|
---|
| 482 | if( M.face(i)->isValid() )
|
---|
| 483 | {
|
---|
| 484 | Face *f = M.face(i);
|
---|
| 485 | out_annotate(out, f);
|
---|
| 486 | out << "f ";
|
---|
| 487 | Vertex *v0 = (Vertex *)f->vertex(0);
|
---|
| 488 | Vertex *v1 = (Vertex *)f->vertex(1);
|
---|
| 489 | Vertex *v2 = (Vertex *)f->vertex(2);
|
---|
| 490 | #ifdef SAFETY
|
---|
| 491 | assert( v0->tempID >= 0 );
|
---|
| 492 | assert( v1->tempID >= 0 );
|
---|
| 493 | assert( v2->tempID >= 0 );
|
---|
| 494 | #endif
|
---|
| 495 | out<<v0->tempID << " " <<v1->tempID<< " " <<v2->tempID<< endl;
|
---|
| 496 | #ifdef SUPPORT_FCOLOR
|
---|
| 497 | if( f->props )
|
---|
| 498 | out << ":fc "
|
---|
| 499 | << f->props->color[X] << " "
|
---|
| 500 | << f->props->color[Y] << " "
|
---|
| 501 | << f->props->color[Z] << endl;
|
---|
| 502 | #endif
|
---|
| 503 | }
|
---|
| 504 | }
|
---|
| 505 |
|
---|
| 506 | return out;
|
---|
| 507 | }
|
---|
[1526] | 508 | */
|
---|
| 509 |
|
---|