1 //////////////////////////////////////////////////////////////////////
2 //
3 // Pixie
4 //
5 // Copyright � 1999 - 2003, Okan Arikan
6 //
7 // Contact: okan@cs.utexas.edu
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 ///////////////////////////////////////////////////////////////////////
24 ///////////////////////////////////////////////////////////////////////
25 //
26 // File : subdivisionCreator.cpp
27 // Classes : CSision
28 // Description : Implements a subdivision surface
29 //
30 ////////////////////////////////////////////////////////////////////////
31 #include <math.h>
32 #include <string.h>
33
34 #include "subdivision.h"
35 #include "subdivisionCreator.h"
36 #include "memory.h"
37 #include "patches.h"
38 #include "stats.h"
39 #include "patchgrid.h"
40 #include "bsplinePatchgrid.h"
41 #include "shading.h"
42 #include "error.h"
43 #include "rendererContext.h"
44 #include "pl.h"
45 #include "renderer.h"
46 #include "ri.h"
47
48 #undef new
49
50 const unsigned int FACE_MOVING = 2; // Set if the face is moving
51 const unsigned int FACE_INTEPOLATEBOUNDARY = 4; // Set if we're interpolating the boundary
52
53 const float bsplineBasis[16] = {
54 (float) (-1.0/6.0), (float) (3.0/6.0), (float) (-3.0/6.0), (float) (1.0/6.0),
55 (float) (3.0/6.0), (float) -(6.0/6.0), (float) (3.0/6.0), (float) (0.0/6.0),
56 (float) (-3.0/6.0), (float) (0.0/6.0), (float) (3.0/6.0), (float) (0.0/6.0),
57 (float) (1.0/6.0), (float) (4.0/6.0), (float) (1.0/6.0), (float) (0.0/6.0)};
58
59 class CSVertex;
60 class CSEdge;
61 class CSFace;
62
63 // This class some transient data we use during the tesselation of the subdivision surface
64 class CSubdivData {
65 public:
66 int vertexSize; // The size of a vertex variable
67 int varyingSize; // The size of a varying variable
68 int facevaryingSize; // The size of a facevarying variable
69 float *vertexData; // The array of vertices
70 float *varyingData; // The array of varyings
71 float *facevaryingData; // The array of facevaryings
72
73 int irregularDepth; // The depth of subdivision in the case of the creases / etc.
74 CSVertex **irregularVertices; // The array of irregular vertices
75 CSVertex **irregularRing; // The ring of irregular vertices about the extraordinary vert
76 CVertexData *vd;
77 CAttributes *currentAttributes;
78 CXform *currentXform;
79 int currentFlags;
80 CPl *parameterList;
81
82 CShadingContext *context;
83 };
84
85
86
87
88 // Some misc functions for computing the vertex / varying coordinates
accumVertex(CSubdivData & data,float * dest,const float * src,float mul=1)89 inline void accumVertex(CSubdivData &data,float *dest,const float *src,float mul = 1) {
90 for (int i=0;i<data.vertexSize;i++) {
91 dest[i] += src[i]*mul;
92 }
93 }
94
scaleVertex(CSubdivData & data,float * dest,float mul=1)95 inline void scaleVertex(CSubdivData &data,float *dest,float mul = 1) {
96 for (int i=0;i<data.vertexSize;i++) {
97 dest[i] *= mul;
98 }
99 }
100
initVertex(CSubdivData & data,float * dest)101 inline void initVertex(CSubdivData &data,float *dest) {
102 for (int i=0;i<data.vertexSize;i++) {
103 dest[i] = 0;
104 }
105 }
106
107 static void gatherData(CSubdivData &data,int numVertex,CSVertex **vertices,CSVertex **varyings,int uniformNumber,float *&vertex,CParameter *¶meters);
108
109
110 ///////////////////////////////////////////////////////////////////////
111 // Class : CSVertex
112 // Description : Encapsulates a subdivision mesh vertex
113 // Comments :
114 class CSVertex {
115
116 ///////////////////////////////////////////////////////////////////////
117 // Class : CVertexFace
118 // Description : Encapsulates a face incident on a vertex
119 // Comments :
120 class CVertexFace {
121 public:
122 CSFace *face;
123 CVertexFace *next;
124 };
125
126 ///////////////////////////////////////////////////////////////////////
127 // Class : CVertexEdge
128 // Description : Encapsulates an edge incident on a vertex
129 // Comments :
130 class CVertexEdge {
131 public:
132 CSEdge *edge;
133 CVertexEdge *next;
134 };
135 public:
136 ///////////////////////////////////////////////////////////////////////
137 // Class : CSVertex
138 // Method : CSVertex
139 // Description : Ctor
140 // Return Value : -
141 // Comments :
CSVertex(CSubdivData & d)142 CSVertex(CSubdivData &d) : data(d) {
143 faces = NULL;
144 edges = NULL;
145 valence = 0;
146 fvalence = 0;
147 vertex = NULL;
148 varying = NULL;
149 facevarying = NULL;
150 parentv = NULL;
151 parente = NULL;
152 parentf = NULL;
153 childVertex = NULL;
154 sharpness = 0;
155 }
156
157 CSubdivData &data;
158 CVertexFace *faces; // Incident faces
159 CVertexEdge *edges; // Incident edges
160 int valence; // Edge valence
161 int fvalence; // Face valence i.e., the number of faces incident on the vertex
162 float *vertex; // The vertex coordinates
163 float *varying,*facevarying; // The varying coordinates
164 CSVertex *parentv; // The parent simplex
165 CSEdge *parente;
166 CSFace *parentf;
167 CSVertex *childVertex; // Child vertex
168 float sharpness;
169
operator new(size_t s,CShadingContext * context)170 void *operator new(size_t s,CShadingContext *context) {
171 return ralloc((int) s,context->threadMemory);
172 }
173
174 ///////////////////////////////////////////////////////////////////////
175 // Class : CSVertex
176 // Method : split
177 // Description : Split a vertex
178 // Return Value : -
179 // Comments :
split()180 void split() {
181 if (childVertex == NULL) {
182 childVertex = new (data.context) CSVertex(data);
183 childVertex->parentv = this;
184 childVertex->sharpness = max(sharpness-1,0);
185 }
186 }
187
188
189 ///////////////////////////////////////////////////////////////////////
190 // Class : CSVertex
191 // Method : addFace
192 // Description : Add an incident face into the vertex
193 // Return Value : -
194 // Comments :
addFace(CSFace * face)195 void addFace(CSFace *face) {
196 CVertexFace *cFace = (CVertexFace *) ralloc(sizeof(CVertexFace),data.context->threadMemory);
197
198 cFace->face = face;
199 cFace->next = faces;
200 faces = cFace;
201
202 fvalence++;
203 }
204
205
206 ///////////////////////////////////////////////////////////////////////
207 // Class : CSVertex
208 // Method : addEdge
209 // Description : Add an incident edge into the vertex
210 // Return Value : -
211 // Comments :
addEdge(CSEdge * edge)212 void addEdge(CSEdge *edge) {
213 CVertexEdge *cEdge = (CVertexEdge *) ralloc(sizeof(CVertexEdge),data.context->threadMemory);
214
215 cEdge->edge = edge;
216 cEdge->next = edges;
217 edges = cEdge;
218
219 valence++;
220 }
221
222 CSEdge *edgeExists(CSVertex *v);
223 void splitIncidentFaces();
224 void sort(CSVertex **,CSEdge *,CSFace *,int);
225 void compute(float *);
226 void computeLimit(float *);
227 void computeVarying(float *,float *);
228 void compute();
229 int funny();
230 int shouldSplit();
231 };
232
233 ///////////////////////////////////////////////////////////////////////
234 // Class : CSEdge
235 // Description : Encapsulates an edge
236 // Comments :
237 class CSEdge {
238 public:
239
240 ///////////////////////////////////////////////////////////////////////
241 // Class : CSEdge
242 // Method : CSEdge
243 // Description : Ctor
244 // Return Value : -
245 // Comments :
CSEdge(CSubdivData & d)246 CSEdge(CSubdivData &d) : data(d) {
247 vertices[0] = NULL;
248 vertices[1] = NULL;
249 faces[0] = NULL;
250 faces[1] = NULL;
251 sharpness = 0;
252 childVertex = NULL;
253 children[0] = NULL;
254 children[1] = NULL;
255 }
256
257
258 CSubdivData &data;
259 CSVertex *vertices[2]; // Incident vertices
260 CSFace *faces[2]; // Incident faces
261 float sharpness; // Edge sharpness
262 CSVertex *childVertex; // The child vertex
263 CSEdge *children[2]; // The child edges
264
operator new(size_t s,CShadingContext * context)265 void *operator new(size_t s,CShadingContext *context) {
266 return ralloc((int) s,context->threadMemory);
267 }
268
269 ///////////////////////////////////////////////////////////////////////
270 // Class : CSEdge
271 // Method : split
272 // Description : Split an edge
273 // Return Value : -
274 // Comments :
split()275 void split() {
276 if (childVertex == NULL) {
277 vertices[0]->split();
278 vertices[1]->split();
279
280 children[0] = new (data.context) CSEdge(data);
281 children[1] = new (data.context) CSEdge(data);
282 childVertex = new (data.context) CSVertex(data);
283
284 childVertex->parente = this;
285
286 children[0]->vertices[0] = vertices[0]->childVertex;
287 children[0]->vertices[1] = childVertex;
288 children[0]->sharpness = max(sharpness-1,0);
289
290 children[1]->vertices[0] = vertices[1]->childVertex;
291 children[1]->vertices[1] = childVertex;
292 children[1]->sharpness = max(sharpness-1,0);
293
294 children[0]->vertices[0]->addEdge(children[0]);
295 children[0]->vertices[1]->addEdge(children[0]);
296 children[1]->vertices[0]->addEdge(children[1]);
297 children[1]->vertices[1]->addEdge(children[1]);
298 }
299 }
300
301 ///////////////////////////////////////////////////////////////////////
302 // Class : CSEdge
303 // Method : addFace
304 // Description : Add a face into an edge
305 // Return Value : -
306 // Comments :
addFace(CSFace * face)307 void addFace(CSFace *face) {
308 if (faces[0] == NULL) faces[0] = face;
309 else {
310 assert(faces[1] == NULL);
311 assert(faces[0] != face);
312 faces[1] = face;
313 }
314 }
315
316 void compute(float *);
317 void computeVarying(float *,float *);
318 };
319
320
321
322
323
324 ///////////////////////////////////////////////////////////////////////
325 // Class : CSFace
326 // Description : Encapsulates a face
327 // Comments :
328 class CSFace {
329 public:
330 ///////////////////////////////////////////////////////////////////////
331 // Class : CSFace
332 // Method : CSFace
333 // Description : Ctor
334 // Return Value : -
335 // Comments :
CSFace(CSubdivData & d,int ui)336 CSFace(CSubdivData &d,int ui) : data(d) {
337 numEdges = 0;
338 edges = NULL;
339 vertices = NULL;
340 uniformIndex = ui;
341 children = NULL;
342 childVertex = NULL;
343 hole = FALSE;
344 }
345
346 CSubdivData &data;
347 int numEdges;
348 CSEdge **edges;
349 CSVertex **vertices;
350 int uniformIndex;
351 int hole;
352 CSFace **children;
353 CSVertex *childVertex;
354
operator new(size_t s,CShadingContext * context)355 void *operator new(size_t s,CShadingContext *context) {
356 return ralloc((int) s,context->threadMemory);
357 }
358
359 ///////////////////////////////////////////////////////////////////////
360 // Class : CSFace
361 // Method : split
362 // Description : Split the face
363 // Return Value : -
364 // Comments :
split()365 void split() {
366 if (childVertex == NULL) {
367 int i;
368 CSEdge **newEdges = (CSEdge **) ralloc(numEdges*sizeof(CSEdge *),data.context->threadMemory);
369
370 children = (CSFace **) ralloc(numEdges*sizeof(CSFace *),data.context->threadMemory);
371 childVertex = new (data.context) CSVertex(data);
372 childVertex->parentf = this;
373
374 // Make sure the incident edges are split
375 for (i=0;i<numEdges;i++) {
376 edges[i]->split();
377 }
378
379 // Create the edges connected to the center
380 for (i=0;i<numEdges;i++) {
381 CSFace *cFace = new (data.context) CSFace(data,uniformIndex);
382 CSEdge *cEdge = new (data.context) CSEdge(data);
383
384 cFace->numEdges = 4;
385 cFace->edges = (CSEdge **) ralloc(4*sizeof(CSEdge *),data.context->threadMemory);
386 cFace->vertices = (CSVertex **) ralloc(4*sizeof(CSVertex *),data.context->threadMemory);
387
388 cEdge->vertices[0] = edges[i]->childVertex;
389 cEdge->vertices[1] = childVertex;
390
391 childVertex->addEdge(cEdge);
392 edges[i]->childVertex->addEdge(cEdge);
393
394 children[i] = cFace;
395 newEdges[i] = cEdge;
396 }
397
398 // Create the children faces
399 for (i=0;i<numEdges;i++) {
400 int t;
401
402 if ( (vertices[i]->childVertex == edges[i]->children[0]->vertices[0]) ||
403 (vertices[i]->childVertex == edges[i]->children[0]->vertices[1])) {
404 children[i]->edges[0] = edges[i]->children[0];
405 } else {
406 assert( (vertices[i]->childVertex == edges[i]->children[1]->vertices[0]) ||
407 (vertices[i]->childVertex == edges[i]->children[1]->vertices[1]));
408 children[i]->edges[0] = edges[i]->children[1];
409 }
410
411 t = (i-1+numEdges) % numEdges;
412
413 children[i]->edges[1] = newEdges[i];
414 children[i]->edges[2] = newEdges[t];
415
416 if ( (vertices[i]->childVertex == edges[t]->children[0]->vertices[0]) ||
417 (vertices[i]->childVertex == edges[t]->children[0]->vertices[1])) {
418 children[i]->edges[3] = edges[t]->children[0];
419 } else {
420 assert( (vertices[i]->childVertex == edges[t]->children[1]->vertices[0]) ||
421 (vertices[i]->childVertex == edges[t]->children[1]->vertices[1]));
422 children[i]->edges[3] = edges[t]->children[1];
423 }
424
425
426 children[i]->vertices[0] = vertices[i]->childVertex;
427 children[i]->vertices[1] = edges[i]->childVertex;
428 children[i]->vertices[2] = childVertex;
429 children[i]->vertices[3] = edges[t]->childVertex;
430
431 assert(children[i]->vertices[0] != NULL);
432 assert(children[i]->vertices[1] != NULL);
433 assert(children[i]->vertices[2] != NULL);
434 assert(children[i]->vertices[3] != NULL);
435 }
436
437 // Manage the connectivity
438 for (i=0;i<numEdges;i++) {
439 children[i]->vertices[0]->addFace(children[i]);
440 children[i]->vertices[1]->addFace(children[i]);
441 children[i]->vertices[2]->addFace(children[i]);
442 children[i]->vertices[3]->addFace(children[i]);
443
444 children[i]->edges[0]->addFace(children[i]);
445 children[i]->edges[1]->addFace(children[i]);
446 children[i]->edges[2]->addFace(children[i]);
447 children[i]->edges[3]->addFace(children[i]);
448 }
449 }
450 }
451
452
453 ///////////////////////////////////////////////////////////////////////
454 // Class : CSFace
455 // Method : Create
456 // Description : Split / create children objects
457 // Return Value : -
458 // Comments :
create(CObject * & children)459 void create(CObject *&children) {
460 int split = FALSE;
461 int funny = FALSE;
462 int funnyBorder = FALSE;
463 int i,j;
464 int numExtraordinary = 0;
465 int extraordinary = 0;
466
467 if (hole == TRUE) return; // If we're a hole, don't create
468
469 if (numEdges != 4) {
470 split = TRUE; // If we're not a quad, we must split (vanilla, no funny patch treatment)
471 } else {
472 // Count the extraordinary vertices
473 for (i=0;i<numEdges;i++) {
474
475 // was: if (vertices[i]->valence != 4 ) {
476 // The following is better as it forces borders to split such that there is
477 // one extraordinart vertex which isn't a natural border point
478 if ( ((vertices[i]->valence != 4) || (vertices[i]->fvalence != 4)) && (!((vertices[i]->valence == 3) && (vertices[i]->fvalence == 2))) ) {
479 numExtraordinary++;
480 extraordinary = i;
481 }
482
483 if (vertices[i]->valence != vertices[i]->fvalence) {
484 if (!(data.currentFlags & FACE_INTEPOLATEBOUNDARY)) {
485 // We're a face adjacent to a boundary and the interpolate boundary flag is not set
486 return;
487 } else {
488 funny = TRUE;
489 funnyBorder = TRUE;
490 }
491 }
492
493 if (vertices[i]->shouldSplit()) split = TRUE;
494 }
495
496
497 // was: if (numExtraordinary > 1) {
498 // prefer to split if possible to enforce above
499 // constraint on extraordinary border vertices
500 if (numExtraordinary > 1) { // If we have more than one ordinary, we must split
501 split = TRUE;
502 funny = FALSE;
503 }
504
505 if (numExtraordinary == 1) {
506 if (vertices[extraordinary]->valence < 3) funny = TRUE;
507 }
508 }
509
510 if ((split == FALSE) || (funny == TRUE)) {
511 // Check if we're a "funny" quad. i.e., have crease edges
512 for (i=0;i<numEdges;i++) {
513 if (vertices[i]->funny() == TRUE) {
514 funny = TRUE;
515 break;
516 }
517 }
518
519 if (funny == FALSE) {
520
521 // We're not a funny patch
522 // We are either:
523 // 1 - A regular patch - Create a bi-cubic patch
524 // 2 - An extraordinary patch - Create an extraordinary patch
525 if (numExtraordinary == 1) {
526 // This is an extraordinary patch
527 CSVertex **v,*va[4];
528 int N = vertices[extraordinary]->valence;
529 int K = 2*N + 8;
530 CSVertex **ring = (CSVertex **) alloca(2*N*sizeof(CSVertex *)); // Holds the ring around the extraordinary vertex (transient)
531 CSVertex *ringt[8];
532 float *vertex;
533 CParameter *parameters;
534
535 v = (CSVertex **) alloca((K+1)*sizeof(CSVertex *)); // Holds the vertices that effect the current patch (transient)
536
537 // First, deal with the vertices around the extraordinary vertex
538 vertices[(extraordinary + 0) & 3]->sort(ring,edges[(extraordinary + 0) & 3],this,2*N);
539 for (i=0;i<(2*N);i++) {
540 v[i + 2] = ring[(i + 2*N - 2) % (2*N)];
541 }
542
543 vertices[(extraordinary + 1) & 3]->sort(ringt,edges[(extraordinary + 1) & 3],this,8);
544 v[2*N+8] = ringt[5];
545 v[2*N+7] = ringt[6];
546 v[2*N+6] = ringt[7];
547
548 vertices[(extraordinary + 2) & 3]->sort(ringt,edges[(extraordinary + 2) & 3],this,8);
549 v[2*N+2] = ringt[5];
550
551 vertices[(extraordinary + 3) & 3]->sort(ringt,edges[(extraordinary + 3) & 3],this,8);
552 v[2*N+5] = ringt[5];
553 v[2*N+4] = ringt[4];
554 v[2*N+3] = ringt[3];
555
556 v[1] = vertices[(extraordinary + 0) & 3];
557 assert(v[4] == vertices[(extraordinary + 1) & 3]);
558 assert(v[5] == vertices[(extraordinary + 2) & 3]);
559 assert(v[6] == vertices[(extraordinary + 3) & 3]);
560
561 va[0] = v[1];
562 va[1] = v[4];
563 va[2] = v[6];
564 va[3] = v[5];
565
566 // Gather the data
567 gatherData(data,K,v+1,va,uniformIndex,vertex,parameters);
568
569 // Create the primitive
570 CObject *nObject = new CSubdivision(data.currentAttributes,data.currentXform,data.vd,parameters,N,0.0f,0.0f,1.0f,1.0f,vertex);
571 nObject->sibling = children;
572 children = nObject;
573 } else {
574 // This is an ordinary patch
575 CSVertex *v[16],*va[4];
576 CSVertex *ring[8];
577 float *vertex;
578 CParameter *parameters;
579
580 // Gather the regular neighborhood
581 vertices[0]->sort(ring,edges[0],this,8);
582 v[0*4+0] = ring[5];
583 v[0*4+1] = ring[6];
584 v[0*4+2] = ring[7];
585 v[1*4+0] = ring[4];
586 v[2*4+0] = ring[3];
587
588 vertices[1]->sort(ring,edges[1],this,8);
589 v[0*4+3] = ring[5];
590 v[1*4+3] = ring[6];
591 v[2*4+3] = ring[7];
592
593 vertices[2]->sort(ring,edges[2],this,8);
594 v[3*4+1] = ring[7];
595 v[3*4+2] = ring[6];
596 v[3*4+3] = ring[5];
597
598 vertices[3]->sort(ring,edges[3],this,8);
599 v[3*4+0] = ring[5];
600
601 v[1*4+1] = vertices[(extraordinary+0)&3];
602 v[1*4+2] = vertices[(extraordinary+1)&3];
603 v[2*4+2] = vertices[(extraordinary+2)&3];
604 v[2*4+1] = vertices[(extraordinary+3)&3];
605
606 va[0] = v[1*4+1];
607 va[1] = v[1*4+2];
608 va[2] = v[2*4+1];
609 va[3] = v[2*4+2];
610
611 // Gather the data
612 gatherData(data,16,v,va,uniformIndex,vertex,parameters);
613
614 // Create the primitive
615 CObject *nObject = new CBicubicPatch(data.currentAttributes,data.currentXform,data.vd,parameters,0,0,1,1,vertex,bsplineBasis,bsplineBasis);
616 nObject->sibling = children;
617 children = nObject;
618 }
619 } else {
620 // Damn, we're a funny patch, deal with it
621 int nv = (1 << data.irregularDepth) + 1;
622 float *vertex;
623 CSVertex *va[4];
624 CParameter *parameters;
625
626 data.irregularVertices = (CSVertex **) ralloc(sizeof(CSVertex *)*(nv+2)*(nv+2),data.context->threadMemory);
627 for (i=0;i<(nv+2)*(nv+2);i++) {
628 data.irregularVertices[i] = NULL;
629 }
630
631 if ( (numExtraordinary > 0) && (vertices[(extraordinary+0)&3]->valence >= 3)) {
632 data.irregularRing = (CSVertex **) ralloc(sizeof(CSVertex *)*(vertices[(extraordinary+0)&3]->valence*2),data.context->threadMemory);
633 }
634
635 // Create irregular patch
636 unconditionalSplit(data.irregularDepth,0,0,vertices[extraordinary]);
637
638 va[0] = vertices[(extraordinary+0)&3];
639 va[1] = vertices[(extraordinary+1)&3];
640 va[2] = vertices[(extraordinary+3)&3];
641 va[3] = vertices[(extraordinary+2)&3];
642
643 if ( funnyBorder == TRUE ) {
644 // We're at the border so it'll have to be a bilinear patch
645
646
647 // Note: At the border, we may not have found all the corner vertices - this is particularly true
648 // if only the corner is at the border. Set these to the nearest point to ensure
649 // gather will succeed (we don't use these points anyway)
650
651 if (data.irregularVertices[0*(nv+2)+0] == NULL) data.irregularVertices[0*(nv+2)+0] = data.irregularVertices[1*(nv+2)+1];
652 if (data.irregularVertices[0*(nv+2)+(nv+1)] == NULL) data.irregularVertices[0*(nv+2)+(nv+1)] = data.irregularVertices[1*(nv+2)+(nv)];
653 if (data.irregularVertices[(nv+1)*(nv+2)+(nv+1)] == NULL) data.irregularVertices[(nv+1)*(nv+2)+(nv+1)] = data.irregularVertices[(nv)*(nv+2)+(nv)];
654 if (data.irregularVertices[(nv+1)*(nv+2)+0] == NULL) data.irregularVertices[(nv+1)*(nv+2)+0] = data.irregularVertices[(nv)*(nv+2)+1];
655
656 // now we gather the grid from neighbors on patches where it exists
657 // pass all available data to the patch grid and flags to indicate which
658 // edges are valid. This is used to create symmetric normals
659 int bTop = (edges[(extraordinary+0)&3]->faces[0] == NULL) || (edges[(extraordinary+0)&3]->faces[1] == NULL);
660 int bRgt = (edges[(extraordinary+1)&3]->faces[0] == NULL) || (edges[(extraordinary+1)&3]->faces[1] == NULL);
661 int bBot = (edges[(extraordinary+2)&3]->faces[0] == NULL) || (edges[(extraordinary+2)&3]->faces[1] == NULL);
662 int bLft = (edges[(extraordinary+3)&3]->faces[0] == NULL) || (edges[(extraordinary+3)&3]->faces[1] == NULL);
663
664 gatherData(data,(nv+2)*(nv+2),data.irregularVertices,va,uniformIndex,vertex,parameters);
665
666 // Create the primitive
667 CObject *nObject = new CPatchGrid(data.currentAttributes,data.currentXform,data.vd,parameters,nv,nv,bTop,bRgt,bBot,bLft,vertex);
668 nObject->sibling = children;
669 children = nObject;
670 } else {
671 if ( (numExtraordinary > 0) && (vertices[(extraordinary+0)&3]->valence >= 3)) {
672 // We're have an extraordinary patch
673 // divide main patch into two side strips which are adjacent
674 // to the extraordinary pathc and a smaller grid
675
676 int N = vertices[extraordinary]->valence;
677 int K = 2*N + 8;
678 CSVertex **v = (CSVertex **) ralloc((K+1)*sizeof(CSVertex *),data.context->threadMemory);
679 CSVertex** strip1Vertices = (CSVertex**) ralloc(sizeof(CSVertex*)*4*(nv+1),data.context->threadMemory);
680 CSVertex** strip2Vertices = (CSVertex**) ralloc(sizeof(CSVertex*)*4*(nv+1),data.context->threadMemory);
681 CSVertex** patchVertices = (CSVertex**) ralloc(sizeof(CSVertex*)*(nv+1)*(nv+1),data.context->threadMemory);
682 const float mult = 1.0f/(nv-1);
683
684 for (i=0;i<(nv+1);i++) {
685 strip1Vertices[4*i+0] = data.irregularVertices[(i+1)*(nv+2)+0];
686 strip1Vertices[4*i+1] = data.irregularVertices[(i+1)*(nv+2)+1];
687 strip1Vertices[4*i+2] = data.irregularVertices[(i+1)*(nv+2)+2];
688 strip1Vertices[4*i+3] = data.irregularVertices[(i+1)*(nv+2)+3];
689
690 strip2Vertices[0*(nv+1)+i] = data.irregularVertices[0*(nv+2)+1+i];
691 strip2Vertices[1*(nv+1)+i] = data.irregularVertices[1*(nv+2)+1+i];
692 strip2Vertices[2*(nv+1)+i] = data.irregularVertices[2*(nv+2)+1+i];
693 strip2Vertices[3*(nv+1)+i] = data.irregularVertices[3*(nv+2)+1+i];
694
695 for (j=0;j<(nv+1);j++) {
696 patchVertices[i*(nv+1)+j] = data.irregularVertices[(i+1)*(nv+2)+j+1];
697 }
698 }
699
700 CObject *nObject;
701
702 // 'left' strip
703 gatherData(data,(nv+1)*(4),strip1Vertices,va,uniformIndex,vertex,parameters);
704 nObject = new CBSplinePatchGrid(data.currentAttributes,data.currentXform,data.vd,parameters,4,nv+1,0.0f,mult,mult,(nv-2)*mult,vertex);
705 nObject->sibling = children;
706 children = nObject;
707
708 // 'top' strip
709 gatherData(data,(4)*(nv+1),strip2Vertices,va,uniformIndex,vertex,parameters);
710 nObject = new CBSplinePatchGrid(data.currentAttributes,data.currentXform,data.vd,parameters,nv+1,4,mult,0.0f,(nv-2)*mult,mult,vertex);
711 nObject->sibling = children;
712 children = nObject;
713
714 // main grid
715 gatherData(data,(nv+1)*(nv+1),patchVertices,va,uniformIndex,vertex,parameters);
716 nObject = new CBSplinePatchGrid(data.currentAttributes,data.currentXform,data.vd,parameters,nv+1,nv+1,mult,mult,(nv-2)*mult,(nv-2)*mult,vertex);
717 nObject->sibling = children;
718 children = nObject;
719
720 // extraordinary patch
721 for (i=0;i<(2*N);i++) {
722 v[i + 2] = data.irregularRing[(i + 2*N - 2) % (2*N)];
723 }
724
725 v[1] = data.irregularVertices[1*(nv+2)+1];
726
727 v[2*N+6] = data.irregularVertices[2*(nv+2)+3];
728 v[2*N+7] = data.irregularVertices[1*(nv+2)+3];
729 v[2*N+8] = data.irregularVertices[0*(nv+2)+3];
730
731 v[2*N+5] = data.irregularVertices[3*(nv+2)+0];
732 v[2*N+4] = data.irregularVertices[3*(nv+2)+1];
733 v[2*N+3] = data.irregularVertices[3*(nv+2)+2];
734 v[2*N+2] = data.irregularVertices[3*(nv+2)+3];
735
736 // Gather the data
737 gatherData(data,K,v+1,va,uniformIndex,vertex,parameters);
738
739 // Create the primitive
740 nObject = new CSubdivision(data.currentAttributes,data.currentXform,data.vd,parameters,N,0.0f,0.0f,mult,mult,vertex);
741 nObject->sibling = children;
742 children = nObject;
743 } else {
744 // No extraordinary patch, use the a bicubic b-spline patch
745
746 // Gather the data
747 gatherData(data,(nv+2)*(nv+2),data.irregularVertices,va,uniformIndex,vertex,parameters);
748
749 // Create the primitive
750 CObject *nObject = new CBSplinePatchGrid(data.currentAttributes,data.currentXform,data.vd,parameters,nv+2,nv+2,0.0f,0.0f,1.0f,1.0f,vertex);
751 nObject->sibling = children;
752 children = nObject;
753 }
754 }
755 }
756 } else {
757 for (i=0;i<numEdges;i++) {
758 vertices[i]->splitIncidentFaces();
759 }
760
761 for (i=0;i<numEdges;i++) {
762 this->children[i]->create(children);
763 }
764 }
765 }
766
767 ///////////////////////////////////////////////////////////////////////
768 // Class : CSFace
769 // Method : unconditionalSplit
770 // Description : Unconditionally split this quad until a predefined depth for table computation
771 // Return Value : -
772 // Comments :
unconditionalSplit(int depth,int x,int y,CSVertex * org)773 void unconditionalSplit(int depth,int x,int y,CSVertex *org) {
774 if (depth > 0) {
775 int i;
776
777 for (i=0;i<numEdges;i++) {
778 vertices[i]->splitIncidentFaces();
779 }
780
781 for (i=0;i<4;i++) {
782 if (vertices[i] == org) {
783 children[(i+0) & 3]->unconditionalSplit(depth-1,(x << 1),(y << 1), vertices[(i+0) & 3]->childVertex);
784 children[(i+1) & 3]->unconditionalSplit(depth-1,(x << 1) + 1,(y << 1), edges[(i+0) & 3]->childVertex);
785 children[(i+2) & 3]->unconditionalSplit(depth-1,(x << 1) + 1,(y << 1) + 1, childVertex);
786 children[(i+3) & 3]->unconditionalSplit(depth-1,(x << 1),(y << 1) + 1, edges[(i+3) & 3]->childVertex);
787 break;
788 }
789 }
790
791 assert(i != 4);
792 } else {
793 int i;
794
795 for (i=0;i<4;i++) {
796 if (vertices[i] == org) {
797 char l = (x==0);
798 char r = (x==(1 << data.irregularDepth)-1);
799 char t = (y==0);
800 char b = (y==(1 << data.irregularDepth)-1);
801 char ml=0,mr=0,mt=0,mb=0;
802
803 data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 1] = vertices[(i + 0) & 3];
804 data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 2] = vertices[(i + 1) & 3];
805 data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 2] = vertices[(i + 2) & 3];
806 data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 1] = vertices[(i + 3) & 3];
807
808 // If we're not at an edge, the rest is not relevant
809 if (!(l||r||t||b)) break;
810
811 // Deal with the edges
812 // either we fetch vertices from a neighboring face or duplicate the edge
813 if (l) {
814 CSVertex *v1 = data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 1];
815 CSVertex *v2 = data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 1];
816 ml = findEdgeVertices((i+3)&3,(i+3)&3,v1,v2);
817 data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x] = v1;
818 data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x] = v2;
819 }
820 if (r) {
821 CSVertex *v1 = data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 2];
822 CSVertex *v2 = data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 2];
823 mr = findEdgeVertices((i+1)&3,(i+2)&3,v1,v2);
824 data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 3] = v1;
825 data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 3] = v2;
826 }
827 if (t) {
828 CSVertex *v1 = data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 1];
829 CSVertex *v2 = data.irregularVertices[(y+1) * ((1 << data.irregularDepth) + 3) + x + 2];
830 mt = findEdgeVertices((i+0)&3,(i+1)&3,v1,v2);
831 data.irregularVertices[(y) * ((1 << data.irregularDepth) + 3) + x + 1] = v1;
832 data.irregularVertices[(y) * ((1 << data.irregularDepth) + 3) + x + 2] = v2;
833 }
834 if (b) {
835 CSVertex *v1 = data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 1];
836 CSVertex *v2 = data.irregularVertices[(y+2) * ((1 << data.irregularDepth) + 3) + x + 2];
837 mb = findEdgeVertices((i+2)&3,(i+2)&3,v1,v2);
838 data.irregularVertices[(y+3) * ((1 << data.irregularDepth) + 3) + x + 1] = v1;
839 data.irregularVertices[(y+3) * ((1 << data.irregularDepth) + 3) + x + 2] = v2;
840 }
841
842 // Deal with the corners
843 // find the corner from an corner-adjacent face if possible, or
844 // duplicate a neighboring point
845 // Note: there's no more than 1 extraordinary vertex here, and its
846 // at vertices[(i+0)&3] in (0,0) if there is such a point
847
848 if (l&&t) {
849 if (((vertices[(i+0)&3]->valence != 4) && (vertices[(i+0)&3]->valence >= 3) && (vertices[(i+0)&3]->valence==vertices[(i+0)&3]->fvalence))) {
850 // We're an extraordinary point and not at the border
851 vertices[(i+0)&3]->sort(data.irregularRing,edges[(i+0)&3],this,2*vertices[(i+0)&3]->valence);
852 } else {
853 CSVertex *v = data.irregularVertices[(y+mt) * ((1 << data.irregularDepth) + 3) + x + ml];
854 if(!findCornerVertex((i+0)&3,(i+0)&3,v))
855 findCornerVertex((i+3)&3,(i+0)&3,v);
856 data.irregularVertices[(y) * ((1 << data.irregularDepth) + 3) + x] = v;
857 }
858 }
859 if (r&&t) {
860 CSVertex *v = data.irregularVertices[(y+mt) * ((1 << data.irregularDepth) + 3) + x + 3 - mr];
861 if(!findCornerVertex((i+1)&3,(i+1)&3,v))
862 findCornerVertex((i+0)&3,(i+1)&3,v);
863 data.irregularVertices[(y) * ((1 << data.irregularDepth) + 3) + x + 3] = v;
864 }
865 if (r&&b) {
866 CSVertex *v = data.irregularVertices[(y+3-mb) * ((1 << data.irregularDepth) + 3) + x + 3 - mr];
867 if(!findCornerVertex((i+2)&3,(i+2)&3,v))
868 findCornerVertex((i+1)&3,(i+2)&3,v);
869 data.irregularVertices[(y+3) * ((1 << data.irregularDepth) + 3) + x + 3] = v;
870 }
871 if (l&&b) {
872 CSVertex *v = data.irregularVertices[(y+3-mb) * ((1 << data.irregularDepth) + 3) + x + ml];
873 if(!findCornerVertex((i+3)&3,(i+3)&3,v))
874 findCornerVertex((i+2)&3,(i+3)&3,v);
875 data.irregularVertices[(y+3) * ((1 << data.irregularDepth) + 3) + x] = v;
876 }
877
878 break;
879 }
880 }
881
882 assert(i != 4);
883 }
884 }
885
886 void compute(float *);
887 void computeVarying(float *,float *);
888 char findEdgeVertices(int,int,CSVertex*&,CSVertex*&);
889 int findCornerVertex(int,int,CSVertex*&);
890 };
891
892
893
894
895
896
897
898
899
900
901 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
902 //
903 // Misc functions related to subdivision surface vertices
904 //
905 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
906
907 ///////////////////////////////////////////////////////////////////////
908 // Class : CSVertex
909 // Method : splitIncidentFaces
910 // Description : Split all the incident faces
911 // Return Value : -
912 // Comments :
splitIncidentFaces()913 void CSVertex::splitIncidentFaces() {
914 CVertexFace *cFace;
915
916 for (cFace=faces;cFace!=NULL;cFace=cFace->next) {
917 cFace->face->split();
918 }
919 }
920
921 ///////////////////////////////////////////////////////////////////////
922 // Class : CSVertex
923 // Method : edgeExists
924 // Description : Figure out if an edge has already been inserted
925 // Return Value : -
926 // Comments :
edgeExists(CSVertex * v)927 CSEdge *CSVertex::edgeExists(CSVertex *v) {
928 CVertexEdge *cEdge;
929
930 for (cEdge=edges;cEdge!=NULL;cEdge=cEdge->next) {
931 if ( (cEdge->edge->vertices[0] == v) ||
932 (cEdge->edge->vertices[1] == v)) return cEdge->edge;
933 }
934
935 return NULL;
936 }
937
938
939 ///////////////////////////////////////////////////////////////////////
940 // Class : CSVertex
941 // Method : sort
942 // Description : Sort 1 ring neighborhood
943 // Return Value : -
944 // Comments :
sort(CSVertex ** v,CSEdge * cEdge,CSFace * cFace,int exp)945 void CSVertex::sort(CSVertex **v,CSEdge *cEdge,CSFace *cFace,int exp) {
946 CSEdge *estart = cEdge;
947 int i;
948
949 do {
950 if (cEdge->vertices[0] == this) *v++ = cEdge->vertices[1];
951 else *v++ = cEdge->vertices[0];
952
953 exp--;
954
955 assert(cFace->numEdges == 4);
956
957 for (i=0;i<4;i++) {
958 if (cFace->vertices[i] == this) {
959 *v++ = cFace->vertices[(i+2) & 3];
960 break;
961 }
962 }
963
964 exp--;
965
966 assert(i != 4);
967
968 cEdge = cFace->edges[(i+1) & 3];
969 if (!((cEdge->vertices[0] == this) || (cEdge->vertices[1] == this))) cEdge = cFace->edges[(i+3) & 3];
970
971 if (cEdge->faces[0] == cFace) cFace = cEdge->faces[1];
972 else cFace = cEdge->faces[0];
973
974 } while(cEdge != estart && exp);
975
976 assert(exp == 0);
977 }
978
979
980
981 ///////////////////////////////////////////////////////////////////////
982 // Class : CSVertex
983 // Method : funny
984 // Description : Figure out if there's something funny in the neighborhood of the vertex
985 // Return Value : TRUE if funny
986 // Comments :
funny()987 int CSVertex::funny() {
988 CVertexEdge *cEdge;
989
990 if (fvalence != valence) {
991 assert(data.currentFlags & FACE_INTEPOLATEBOUNDARY);
992 return TRUE;
993 }
994
995 for (cEdge=edges;cEdge!=NULL;cEdge=cEdge->next) {
996 if (cEdge->edge->sharpness > 0) return TRUE;
997 if (sharpness > 0) return TRUE;
998
999 if (cEdge->edge->faces[1] == NULL) {
1000
1001 return TRUE;
1002 }
1003 }
1004
1005 return FALSE;
1006 }
1007
1008 ///////////////////////////////////////////////////////////////////////
1009 // Class : CSVertex
1010 // Method : shouldSplit
1011 // Description : TRUE if there is a non-quad incident face
1012 // Return Value :
1013 // Comments :
shouldSplit()1014 int CSVertex::shouldSplit() {
1015 CVertexFace *cFace;
1016
1017 for (cFace=faces;cFace!=NULL;cFace=cFace->next) {
1018 if (cFace->face->numEdges != 4) return TRUE;
1019 }
1020
1021 return FALSE;
1022 }
1023
1024 ///////////////////////////////////////////////////////////////////////
1025 // Class : CSFace
1026 // Method : findEdgeVertices
1027 // Description : get the vertex pair bordering an edge
1028 // Return Value : -
1029 // Comments :
findEdgeVertices(int eOrg,int vOrg,CSVertex * & v1,CSVertex * & v2)1030 char CSFace::findEdgeVertices(int eOrg,int vOrg,CSVertex* &v1,CSVertex* &v2) {
1031 CSEdge *cEdge = edges[eOrg];
1032 CSVertex *cVert = vertices[vOrg];
1033 CSFace *cFace = NULL;
1034 int i;
1035
1036 if (cEdge->faces[0] == this) cFace = cEdge->faces[1];
1037 else cFace = cEdge->faces[0];
1038
1039 if (cFace != NULL){
1040 for (i=0;i<4;i++) {
1041 if (cFace->edges[i] == cEdge) {
1042 if (cFace->vertices[i] == cVert) {
1043 v1 = cFace->vertices[(i + 2) & 3];
1044 v2 = cFace->vertices[(i + 3) & 3];
1045 } else {
1046 v1 = cFace->vertices[(i + 3) & 3];
1047 v2 = cFace->vertices[(i + 2) & 3];
1048 //assert(cFace->vertices[(i+1)&3] != cVert);
1049 }
1050 break;
1051 }
1052 }
1053 assert(i!=4);
1054 } else {
1055 return 1;
1056 }
1057 return 0;
1058 }
1059
1060 ///////////////////////////////////////////////////////////////////////
1061 // Class : CSFace
1062 // Method : findCornerVertex
1063 // Description : find the vertex corner-opposite by edge walking
1064 // Return Value : -
1065 // Comments :
findCornerVertex(int eOrg,int vOrg,CSVertex * & v)1066 int CSFace::findCornerVertex(int eOrg,int vOrg,CSVertex *&v) {
1067 CSEdge *cEdge = edges[eOrg];
1068 CSVertex *cVert = vertices[vOrg];
1069 CSFace *cFace = this;
1070 int i,j;
1071
1072 for (j=1;j>=0;j--){
1073 if (cEdge->faces[0] == cFace) cFace = cEdge->faces[1];
1074 else cFace = cEdge->faces[0];
1075
1076 if (cFace == NULL) break;
1077
1078 for (i=0;i<4;i++){
1079 if (cFace->edges[i] == cEdge) {
1080 if (cFace->vertices[(i+0)&3] == cVert) {
1081 cEdge = cFace->edges[(i+3)&3];
1082 if (!j && (cEdge->faces[0] != this) && (cEdge->faces[1] != this) ) {
1083 v = cFace->vertices[(i+2)&3];
1084 return TRUE;
1085 }
1086 } else {
1087 cEdge = cFace->edges[(i+1)&3];
1088 assert(cFace->vertices[(i+1)&3] == cVert);
1089 if (!j && (cEdge->faces[0] != this) && (cEdge->faces[1] != this) ) {
1090 v = cFace->vertices[(i+3)&3];
1091 return TRUE;
1092 }
1093 }
1094 break;
1095 }
1096 }
1097 assert(i!=4);
1098 }
1099 return FALSE;
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
1117 //
1118 // Subdivision rules implementation
1119 //
1120 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133 ///////////////////////////////////////////////////////////////////////
1134 // Class : CSVertex
1135 // Method : compute
1136 // Description : Compute the vertex / varying
1137 // Return Value : -
1138 // Comments :
compute()1139 void CSVertex::compute() {
1140 assert(vertex == NULL);
1141
1142 vertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1143
1144 if (parentv != NULL) parentv->compute(vertex);
1145 else if (parente != NULL) parente->compute(vertex);
1146 else if (parentf != NULL) parentf->compute(vertex);
1147 else {
1148 assert(FALSE);
1149 }
1150 }
1151
1152 ///////////////////////////////////////////////////////////////////////
1153 // Class : CSVertex
1154 // Method : compute
1155 // Description : Compute the vertex / varying
1156 // Return Value : -
1157 // Comments :
compute(float * vertex)1158 void CSVertex::compute(float *vertex) {
1159 CVertexEdge *cEdge;
1160 CVertexFace *cFace;
1161 float *tvertex;
1162 float sharpness;
1163 int numSharp;
1164
1165 if (this->vertex == NULL) compute();
1166
1167 tvertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1168
1169 for (numSharp=0,sharpness=0,cEdge=edges;cEdge!=NULL;cEdge=cEdge->next) {
1170 if (cEdge->edge->sharpness > 0) {
1171 sharpness += cEdge->edge->sharpness;
1172 numSharp++;
1173 }
1174 }
1175
1176 if ((numSharp > 2) || (valence == 2)) { // We're a corner vertex
1177 memcpy(vertex,this->vertex,data.vertexSize*sizeof(float));
1178 } else { // We're not a corner vertex
1179 float *sharpVertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1180 float *smoothVertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1181
1182 sharpness /= (float) numSharp;
1183
1184 // Compute the smooth rule
1185 initVertex(data,smoothVertex);
1186 initVertex(data,sharpVertex);
1187
1188 for (cEdge=edges;cEdge!=NULL;cEdge=cEdge->next) {
1189 CSVertex *oVertex;
1190
1191 if (cEdge->edge->vertices[0] == this) oVertex = cEdge->edge->vertices[1];
1192 else {
1193 assert(cEdge->edge->vertices[1] == this);
1194 oVertex = cEdge->edge->vertices[0];
1195 }
1196
1197 if (oVertex->vertex == NULL) oVertex->compute();
1198
1199 accumVertex(data,smoothVertex,oVertex->vertex);
1200
1201 if (cEdge->edge->sharpness > 0) {
1202 accumVertex(data,sharpVertex,oVertex->vertex);
1203 }
1204 }
1205
1206 for (cFace=faces;cFace!=NULL;cFace=cFace->next) {
1207 cFace->face->compute(tvertex);
1208 accumVertex(data,smoothVertex,tvertex);
1209 }
1210
1211 scaleVertex(data,smoothVertex, 1 / (float) (valence*valence));
1212 accumVertex(data,smoothVertex,this->vertex,(valence - 2) / (float) valence);
1213
1214 scaleVertex(data,sharpVertex, 1.0 / 8.0);
1215 accumVertex(data,sharpVertex,this->vertex,6.0 / 8.0);
1216
1217 if (numSharp == 2) {
1218 // We're a crease vertex
1219 if (sharpness >= 1) {
1220 memcpy(vertex,sharpVertex,data.vertexSize*sizeof(float));
1221 } else if (sharpness <= 0) {
1222 memcpy(vertex,smoothVertex,data.vertexSize*sizeof(float));
1223 } else {
1224 initVertex(data,vertex);
1225 accumVertex(data,vertex,smoothVertex,1-sharpness);
1226 accumVertex(data,vertex,sharpVertex,sharpness);
1227 }
1228 } else {
1229 // We're a dart or a non-crease vertex
1230 memcpy(vertex,smoothVertex,data.vertexSize*sizeof(float));
1231 }
1232 }
1233
1234 if (this->sharpness >= 1) { // sharp corner rule
1235 memcpy(vertex,this->vertex,data.vertexSize*sizeof(float));
1236 }
1237 else if (this->sharpness > 0) { // smooth corner rule
1238 scaleVertex(data,vertex,1 - this->sharpness);
1239 accumVertex(data,vertex,this->vertex,this->sharpness);
1240 }
1241 }
1242
1243
1244 ///////////////////////////////////////////////////////////////////////
1245 // Class : CSVertex
1246 // Method : compute
1247 // Description : Compute the vertex / varying
1248 // Return Value : -
1249 // Comments :
computeVarying(float * varying,float * facevarying)1250 void CSVertex::computeVarying(float *varying,float *facevarying) {
1251 if (parentv != NULL) parentv->computeVarying(varying,facevarying);
1252 else if (parente != NULL) parente->computeVarying(varying,facevarying);
1253 else if (parentf != NULL) parentf->computeVarying(varying,facevarying);
1254 else {
1255 if (this->varying != NULL) {
1256 memcpy(varying,this->varying,sizeof(float)*data.varyingSize);
1257 }
1258
1259 if (this->facevarying != NULL) {
1260 memcpy(facevarying,this->facevarying,sizeof(float)*data.facevaryingSize);
1261 }
1262 }
1263 }
1264
1265 ///////////////////////////////////////////////////////////////////////
1266 // Class : CSVertex
1267 // Method : computeLimit
1268 // Description : Compute the vertex / varying
1269 // Return Value : -
1270 // Comments :
computeLimit(float * vertex)1271 void CSVertex::computeLimit(float *vertex) {
1272 CVertexEdge *cEdge;
1273 CVertexFace *cFace;
1274 float *tvertex;
1275 float sharpness;
1276 int numSharp;
1277
1278 if (this->vertex == NULL) compute();
1279
1280 tvertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1281
1282 for (numSharp=0,sharpness=0,cEdge=edges;cEdge!=NULL;cEdge=cEdge->next) {
1283 if (cEdge->edge->sharpness > 0) {
1284 sharpness += cEdge->edge->sharpness;
1285 numSharp++;
1286 }
1287 }
1288
1289 if ((numSharp > 2) || (valence == 2)) { // We're a corner vertex
1290 memcpy(vertex,this->vertex,data.vertexSize*sizeof(float));
1291 } else { // We're not a corner vertex
1292 float *sharpVertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1293 float *smoothVertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1294
1295 sharpness /= (float) numSharp;
1296
1297 // Compute the smooth rule
1298 initVertex(data,smoothVertex);
1299 initVertex(data,sharpVertex);
1300
1301 for (cEdge=edges;cEdge!=NULL;cEdge=cEdge->next) {
1302 accumVertex(data,smoothVertex,tvertex,4);
1303
1304 if (cEdge->edge->sharpness > 0) {
1305 accumVertex(data,sharpVertex,tvertex);
1306 }
1307 }
1308
1309 for (cFace=faces;cFace!=NULL;cFace=cFace->next) {
1310 accumVertex(data,smoothVertex,tvertex);
1311 }
1312
1313 accumVertex(data,smoothVertex,this->vertex,(float) (valence*valence));
1314 scaleVertex(data,smoothVertex, 1 / (float) (valence*(valence+5)));
1315
1316 scaleVertex(data,sharpVertex, 1.0 / 4.0);
1317 accumVertex(data,sharpVertex,this->vertex,1.0 / 2.0);
1318
1319 if (numSharp == 2) {
1320 // We're a crease vertex
1321 if (sharpness >= 1) {
1322 memcpy(vertex,sharpVertex,data.vertexSize*sizeof(float));
1323 } else if (sharpness <= 0) {
1324 memcpy(vertex,smoothVertex,data.vertexSize*sizeof(float));
1325 } else {
1326 initVertex(data,vertex);
1327 accumVertex(data,vertex,smoothVertex,1-sharpness);
1328 accumVertex(data,vertex,sharpVertex,sharpness);
1329 }
1330 } else {
1331 // We're a dart or a non-crease vertex
1332 memcpy(vertex,smoothVertex,data.vertexSize*sizeof(float));
1333 }
1334 }
1335
1336 if (this->sharpness >= 1) { // sharp corner rule
1337 memcpy(vertex,this->vertex,data.vertexSize*sizeof(float));
1338 }
1339 else if (this->sharpness > 0) { // smooth corner rule
1340 scaleVertex(data,vertex,1 - this->sharpness);
1341 accumVertex(data,vertex,this->vertex,this->sharpness);
1342 }
1343 }
1344
1345 ///////////////////////////////////////////////////////////////////////
1346 // Class : CSEdge
1347 // Method : compute
1348 // Description : Edge subdivision rule
1349 // Return Value : -
1350 // Comments :
compute(float * vertex)1351 void CSEdge::compute(float *vertex) {
1352 float *tvertex;
1353 float *smoothVertex,*sharpVertex;
1354
1355 smoothVertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1356 sharpVertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1357 tvertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1358
1359 if (vertices[0]->vertex == NULL) vertices[0]->compute();
1360 if (vertices[1]->vertex == NULL) vertices[1]->compute();
1361
1362 if ((sharpness > 0) || (faces[1] == NULL)) { // Have to compute the sharp vertex
1363 initVertex(data,sharpVertex);
1364 accumVertex(data,sharpVertex,vertices[0]->vertex);
1365 accumVertex(data,sharpVertex,vertices[1]->vertex);
1366 scaleVertex(data,sharpVertex,0.5f);
1367 }
1368
1369 if ((sharpness < 1) && (faces[1] != NULL)) { // Have to compute the smooth vertex
1370 faces[0]->compute(smoothVertex);
1371 faces[1]->compute(tvertex);
1372 accumVertex(data,smoothVertex,tvertex);
1373 accumVertex(data,smoothVertex,vertices[0]->vertex);
1374 accumVertex(data,smoothVertex,vertices[1]->vertex);
1375 scaleVertex(data,smoothVertex,1 / (float) 4);
1376 }
1377
1378 if ((sharpness >= 1) || (faces[1] == NULL)) memcpy(vertex,sharpVertex,data.vertexSize*sizeof(float));
1379 else if (sharpness <= 0) memcpy(vertex,smoothVertex,data.vertexSize*sizeof(float));
1380 else {
1381 initVertex(data,vertex);
1382 accumVertex(data,vertex,smoothVertex,(1-sharpness));
1383 accumVertex(data,vertex,sharpVertex,sharpness);
1384 }
1385 }
1386
1387 ///////////////////////////////////////////////////////////////////////
1388 // Class : CSEdge
1389 // Method : computeVarying
1390 // Description : Edge subdivision rule
1391 // Return Value : -
1392 // Comments :
computeVarying(float * varying,float * facevarying)1393 void CSEdge::computeVarying(float *varying,float *facevarying) {
1394 float *varying1,*facevarying1;
1395 int i;
1396
1397 varying1 = (float *) ralloc(sizeof(float)*data.varyingSize,data.context->threadMemory);
1398 facevarying1 = (float *) ralloc(sizeof(float)*data.facevaryingSize,data.context->threadMemory);
1399
1400 vertices[0]->computeVarying(varying,facevarying);
1401 vertices[1]->computeVarying(varying1,facevarying1);
1402
1403 for (i=0;i<data.varyingSize;i++) {
1404 varying[i] = (varying[i] + varying1[i])*0.5f;
1405 }
1406
1407 for (i=0;i<data.facevaryingSize;i++) {
1408 facevarying[i] = (facevarying[i] + facevarying1[i])*0.5f;
1409 }
1410 }
1411
1412 ///////////////////////////////////////////////////////////////////////
1413 // Class : CSFace
1414 // Method : compute
1415 // Description : Face subdivision rule
1416 // Return Value : -
1417 // Comments :
compute(float * vertex)1418 void CSFace::compute(float *vertex) {
1419 int i;
1420
1421 initVertex(data,vertex);
1422
1423 for (i=0;i<numEdges;i++) {
1424 if (vertices[i]->vertex == NULL) vertices[i]->compute();
1425
1426 accumVertex(data,vertex,vertices[i]->vertex);
1427 }
1428
1429 scaleVertex(data,vertex,1 / (float) numEdges);
1430 }
1431
1432
1433
1434 ///////////////////////////////////////////////////////////////////////
1435 // Class : CSFace
1436 // Method : computeVarying
1437 // Description : Face subdivision rule
1438 // Return Value : -
1439 // Comments :
computeVarying(float * varying,float * facevarying)1440 void CSFace::computeVarying(float *varying,float *facevarying) {
1441 float *varying1,*facevarying1;
1442 int i,j;
1443 const float scale = 1 / (float) numEdges;
1444
1445 varying1 = (float *) ralloc(sizeof(float)*data.varyingSize,data.context->threadMemory);
1446 facevarying1 = (float *) ralloc(sizeof(float)*data.facevaryingSize,data.context->threadMemory);
1447
1448 for (i=0;i<data.varyingSize;i++) {
1449 varying[i] = 0;
1450 }
1451
1452 for (i=0;i<data.facevaryingSize;i++) {
1453 facevarying[i] = 0;
1454 }
1455
1456 for (j=0;j<numEdges;j++) {
1457 vertices[j]->computeVarying(varying1,facevarying1);
1458
1459 for (i=0;i<data.varyingSize;i++) {
1460 varying[i] += varying1[i];
1461 }
1462
1463 for (i=0;i<data.facevaryingSize;i++) {
1464 facevarying[i] += facevarying1[i];
1465 }
1466 }
1467
1468 for (i=0;i<data.varyingSize;i++) {
1469 varying[i] *= scale;
1470 }
1471
1472 for (i=0;i<data.facevaryingSize;i++) {
1473 facevarying[i] *= scale;
1474 }
1475 }
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
gatherData(CSubdivData & data,int numVertex,CSVertex ** vertices,CSVertex ** varyings,int uniformNumber,float * & vertex,CParameter * & parameters)1525 static void gatherData(CSubdivData &data,int numVertex,CSVertex **vertices,CSVertex **varyings,int uniformNumber,float *&vertex,CParameter *¶meters) {
1526 int i;
1527 float *varyingsT,*facevaryingsT;
1528
1529 assert(data.vertexSize > 0);
1530
1531 vertex = (float *) ralloc(data.vertexSize*numVertex*sizeof(float),data.context->threadMemory);
1532
1533 for (i=0;i<numVertex;i++) {
1534 if (vertices[i]->vertex == NULL) vertices[i]->compute();
1535
1536 memcpy(vertex+i*data.vertexSize,vertices[i]->vertex,sizeof(float)*data.vertexSize);
1537 }
1538
1539
1540 varyingsT = (float *) ralloc(data.varyingSize*4*sizeof(float),data.context->threadMemory);
1541 facevaryingsT = (float *) ralloc(data.facevaryingSize*4*sizeof(float),data.context->threadMemory);
1542
1543 for (i=0;i<4;i++) {
1544 varyings[i]->computeVarying(varyingsT + i*data.varyingSize,facevaryingsT + i*data.facevaryingSize);
1545 }
1546
1547 parameters = data.parameterList->uniform(uniformNumber,NULL);
1548 parameters = data.parameterList->varying( varyingsT+0*data.varyingSize,
1549 varyingsT+1*data.varyingSize,
1550 varyingsT+2*data.varyingSize,
1551 varyingsT+3*data.varyingSize,parameters);
1552 parameters = data.parameterList->facevarying( facevaryingsT+0*data.facevaryingSize,
1553 facevaryingsT+1*data.facevaryingSize,
1554 facevaryingsT+2*data.facevaryingSize,
1555 facevaryingsT+3*data.facevaryingSize,parameters);
1556 }
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572 ///////////////////////////////////////////////////////////////////////
1573 // Class : CSubdivMesh
1574 // Method : CSubdivMesh
1575 // Description : Ctor
1576 // Return Value : -
1577 // Comments :
CSubdivMesh(CAttributes * a,CXform * x,CPl * c,int numFaces,int * numVerticesPerFace,int * vertexIndices,int ntags,const char ** tags,int * nargs,int * intargs,float * floatargs)1578 CSubdivMesh::CSubdivMesh(CAttributes *a,CXform *x,CPl *c,int numFaces,int *numVerticesPerFace,int *vertexIndices,int ntags,const char **tags,int *nargs,int *intargs,float *floatargs) : CObject(a,x) {
1579 int i,j,ias,fas;
1580 const float *P;
1581
1582 atomicIncrement(&stats.numGprims);
1583
1584 this->pl = c;
1585 this->numFaces = numFaces;
1586
1587 // Count the number of faces / vertices
1588 for (i=0,j=0;i<numFaces;j+=numVerticesPerFace[i],i++);
1589
1590 for (numVertices=-1,i=0;i<j;i++) {
1591 if (vertexIndices[i] > numVertices) numVertices = vertexIndices[i];
1592 }
1593 numVertices++;
1594
1595 // Create a fresh copy of the parameters
1596 this->numVerticesPerFace = new int[numFaces]; memcpy(this->numVerticesPerFace,numVerticesPerFace,sizeof(int)*numFaces);
1597 this->vertexIndices = new int[j]; memcpy(this->vertexIndices,vertexIndices,sizeof(int)*j);
1598 this->ntags = ntags;
1599 this->tags = NULL;
1600 this->nargs = NULL;
1601 this->intargs = NULL;
1602 this->floatargs = NULL;
1603
1604 if (ntags > 0) {
1605 this->tags = new char*[ntags];
1606 this->nargs = new int[ntags*2]; memcpy(this->nargs,nargs,sizeof(int)*ntags*2);
1607
1608 for (ias=0,fas=0,i=0;i<ntags;i++) {
1609 this->tags[i] = strdup(tags[i]);
1610 ias += nargs[i*2];
1611 fas += nargs[i*2+1];
1612 }
1613
1614 if (ias > 0) this->intargs = new int[ias]; memcpy(this->intargs,intargs,ias*sizeof(int));
1615 if (fas > 0) this->floatargs = new float[fas]; memcpy(this->floatargs,floatargs,fas*sizeof(float));
1616 }
1617
1618 // Compute the bounding box
1619 initv(bmin,C_INFINITY);
1620 initv(bmax,-C_INFINITY);
1621 for (P=pl->data0,i=0;i<numVertices;i++,P+=3) {
1622 addBox(bmin,bmax,P);
1623 }
1624
1625 if (pl->data1 != NULL) {
1626 for (P=pl->data1,i=0;i<numVertices;i++,P+=3) {
1627 addBox(bmin,bmax,P);
1628 }
1629 }
1630
1631 xform->transformBound(bmin,bmax);
1632 makeBound(bmin,bmax);
1633
1634 // Create the synch. object
1635 osCreateMutex(mutex);
1636 }
1637
1638 ///////////////////////////////////////////////////////////////////////
1639 // Class : CSubdivMesh
1640 // Method : ~CSubdivMesh
1641 // Description : Dtor
1642 // Return Value : -
1643 // Comments :
~CSubdivMesh()1644 CSubdivMesh::~CSubdivMesh() {
1645 int i;
1646
1647 atomicDecrement(&stats.numGprims);
1648
1649 delete pl;
1650 delete [] numVerticesPerFace;
1651 delete [] vertexIndices;
1652
1653 if (ntags > 0) {
1654 for (i=0;i<ntags;i++) {
1655 free(tags[i]);
1656 }
1657 delete [] tags;
1658 delete [] nargs;
1659 if (intargs != NULL) delete [] intargs;
1660 if (floatargs != NULL) delete [] floatargs;
1661 }
1662
1663 // Delete the synch. object
1664 osDeleteMutex(mutex);
1665 }
1666
1667
1668 ///////////////////////////////////////////////////////////////////////
1669 // Class : CSubdivMesh
1670 // Method : intersect
1671 // Description : Intersect the thing
1672 // Return Value : -
1673 // Comments :
intersect(CShadingContext * rasterizer,CRay * cRay)1674 void CSubdivMesh::intersect(CShadingContext *rasterizer,CRay *cRay) {
1675
1676 if (children == NULL) create(rasterizer);
1677 }
1678
1679
1680 ///////////////////////////////////////////////////////////////////////
1681 // Class : CSubdivMesh
1682 // Method : dice
1683 // Description : Dice the primitive
1684 // Return Value : -
1685 // Comments :
dice(CShadingContext * rasterizer)1686 void CSubdivMesh::dice(CShadingContext *rasterizer) {
1687
1688 if (children == NULL) create(rasterizer);
1689
1690 CObject *cObject,*nObject;
1691 for (cObject=children;cObject!=NULL;cObject=nObject) {
1692 nObject = cObject->sibling;
1693
1694 cObject->attach();
1695
1696 rasterizer->drawObject(cObject);
1697
1698 cObject->detach();
1699 }
1700 }
1701
1702 ///////////////////////////////////////////////////////////////////////
1703 // Class : CSubdivMesh
1704 // Method : instantiate
1705 // Description : Clone the primitive
1706 // Return Value : -
1707 // Comments :
instantiate(CAttributes * a,CXform * x,CRendererContext * c) const1708 void CSubdivMesh::instantiate(CAttributes *a,CXform *x,CRendererContext *c) const {
1709 CXform *nx = new CXform(x);
1710
1711 nx->concat(xform); // Concetenate the local xform
1712
1713 if (a == NULL) a = attributes;
1714
1715 c->addObject(new CSubdivMesh(a,nx,pl->clone(a),numFaces,numVerticesPerFace,vertexIndices,ntags,(const char **) tags,nargs,intargs,floatargs));
1716 }
1717
1718
1719 ///////////////////////////////////////////////////////////////////////
1720 // Class : CSubdivMesh
1721 // Method : split
1722 // Description : Split this into smaller primitives
1723 // Return Value : -
1724 // Comments :
create(CShadingContext * context)1725 void CSubdivMesh::create(CShadingContext *context) {
1726 int i;
1727 int j,k;
1728 CSFace **faces;
1729 CSVertex **vertices;
1730 int *cnargs;
1731 int *cintargs;
1732 float *cfloatargs;
1733 int *cvertexIndex;
1734 CSubdivData data;
1735 CObject *allChildren;
1736
1737 osLock(mutex);
1738 if (children != NULL) {
1739 osUnlock(mutex);
1740 return;
1741 }
1742
1743 memBegin(context->threadMemory);
1744
1745 // Transform the core
1746 pl->transform(xform);
1747
1748 data.vertexSize = 0;
1749 data.varyingSize = 0;
1750 data.facevaryingSize = 0;
1751 data.vertexData = NULL;
1752 data.varyingData = NULL;
1753 data.facevaryingData = NULL;
1754
1755 data.irregularDepth = 5;
1756 data.irregularVertices = NULL;
1757 data.irregularRing = NULL;
1758 data.vd = NULL;
1759 data.currentAttributes = NULL;
1760 data.currentXform = NULL;
1761 data.currentFlags = 0;
1762 data.parameterList = NULL;
1763
1764 data.context = context;
1765
1766 data.vd = pl->vertexData();
1767 data.currentFlags = 0;
1768 data.currentAttributes = this->attributes;
1769 data.currentXform = this->xform;
1770 data.parameterList = this->pl;
1771
1772 // Collect the misc data
1773 data.vertexData = NULL; pl->collect(data.vertexSize,data.vertexData,CONTAINER_VERTEX,context->threadMemory);
1774 data.varyingData = NULL; pl->collect(data.varyingSize,data.varyingData,CONTAINER_VARYING,context->threadMemory);
1775 data.facevaryingData = NULL; pl->collect(data.facevaryingSize,data.facevaryingData,CONTAINER_FACEVARYING,context->threadMemory);
1776
1777 faces = (CSFace **) ralloc(numFaces*sizeof(CSFace *),data.context->threadMemory);
1778 vertices = (CSVertex **) ralloc(numVertices*sizeof(CSVertex *),data.context->threadMemory);
1779
1780 // Create the vertices and copy the vertex / varying data over
1781 for (i=0;i<numVertices;i++) {
1782 const float *src = data.vertexData + i*data.vertexSize;
1783 float *dest;
1784 int k;
1785
1786 vertices[i] = new (data.context) CSVertex(data);
1787 dest = vertices[i]->vertex = (float *) ralloc(data.vertexSize*sizeof(float),data.context->threadMemory);
1788
1789 for (k=0;k<data.vertexSize;k++) *dest++ = *src++;
1790 }
1791
1792 if (data.varyingData != NULL) {
1793 for (i=0;i<numVertices;i++) {
1794 vertices[i]->varying = data.varyingData + i*data.varyingSize;
1795 }
1796 }
1797
1798 // Create the faces
1799 for (i=0;i<numFaces;i++) {
1800 faces[i] = new (data.context) CSFace(data,i);
1801 }
1802
1803 // Manage the connectivity
1804 for (i=0,cvertexIndex=vertexIndices;i<numFaces;i++) {
1805 CSFace *cFace = faces[i];
1806 int numEdges = numVerticesPerFace[i];
1807 cFace->numEdges = numEdges;
1808 cFace->vertices = (CSVertex **) ralloc(numEdges*sizeof(CSVertex *),data.context->threadMemory);
1809 cFace->edges = (CSEdge **) ralloc(numEdges*sizeof(CSEdge *),data.context->threadMemory);
1810
1811 // Set the vertices belonging to a face
1812 for (j=0;j<numEdges;j++) {
1813 cFace->vertices[j] = vertices[*cvertexIndex++];
1814 }
1815
1816 // Figure out the edges
1817 for (j=0;j<numEdges;j++) {
1818 CSEdge *cEdge;
1819
1820 if ((cEdge = cFace->vertices[j]->edgeExists(cFace->vertices[(j+1) % numEdges])) == NULL) {
1821 cEdge = new (data.context) CSEdge(data);
1822 cEdge->vertices[0] = cFace->vertices[j];
1823 cEdge->vertices[1] = cFace->vertices[(j+1) % numEdges];
1824 cEdge->vertices[0]->addEdge(cEdge);
1825 cEdge->vertices[1]->addEdge(cEdge);
1826 }
1827
1828 cFace->edges[j] = cEdge;
1829 }
1830
1831 for (j=0;j<cFace->numEdges;j++) {
1832 cFace->vertices[j]->addFace(cFace);
1833 cFace->edges[j]->addFace(cFace);
1834 }
1835 }
1836
1837 // Process the tags
1838 for (i=0,cnargs=nargs,cintargs=intargs,cfloatargs=floatargs;i<ntags;i++) {
1839 if (strcmp(tags[i],RI_HOLE) == 0) {
1840 if (cnargs[1] != 0) error(CODE_RANGE,"Hole takes no floating point arguments\n");
1841 for (j=0;j<cnargs[0];j++) {
1842 faces[cintargs[j]]->hole = TRUE;
1843 }
1844 } else if (strcmp(tags[i],RI_CREASE) == 0) {
1845 for (j=0;j<cnargs[0]-1;j++) {
1846 CSVertex *v0 = vertices[cintargs[j]];
1847 CSVertex *v1 = vertices[cintargs[j+1]];
1848 CSEdge *cEdge;
1849
1850 cEdge = v0->edgeExists(v1);
1851
1852 if (cEdge != NULL) {
1853 cEdge->sharpness = min(cfloatargs[0],10);
1854 } else {
1855 error(CODE_RANGE,"The edge between vertices %d-%d not found\n",cintargs[j],cintargs[j+1]);
1856 }
1857 }
1858 if (cnargs[1] != 1) {
1859 error(CODE_RANGE,"Creases expect exactly 1 float argument\n");
1860 }
1861 } else if (strcmp(tags[i],RI_INTERPOLATEBOUNDARY) == 0) {
1862 data.currentFlags |= FACE_INTEPOLATEBOUNDARY;
1863 } else if (strcmp(tags[i],RI_CORNER) == 0) {
1864 if (cnargs[1] == cnargs[0]) {
1865 for (j=0;j<cnargs[0];j++) {
1866 vertices[cintargs[j]]->sharpness = cfloatargs[j];
1867 }
1868 } else if (cnargs[1] == 1) {
1869 for (j=0;j<cnargs[0];j++) {
1870 vertices[cintargs[j]]->sharpness = cfloatargs[0];
1871 }
1872 } else {
1873 error(CODE_RANGE,"Corner has 1 or n float arguments\n");
1874 }
1875 } else {
1876 error(CODE_BADTOKEN,"Unknown subdivision tag: \"%s\"\n",tags[i]);
1877 }
1878
1879 cintargs += cnargs[0];
1880 cfloatargs += cnargs[1];
1881 cnargs += 2;
1882 }
1883
1884 // Add sharp creases when we've got an interpolateboundary tag
1885 // Note: corner in the literature refers to v.valence == 2,
1886 // whereas the spec overloads corners as tags to mean sharp vertices
1887 if (data.currentFlags & FACE_INTEPOLATEBOUNDARY) {
1888 for (i=0;i<numFaces;i++) {
1889 CSFace *cFace = faces[i];
1890 int numEdges = numVerticesPerFace[i];
1891
1892 // Figure out the edges
1893 for (j=0;j<numEdges;j++) {
1894 CSEdge *cEdge = cFace->edges[j];
1895
1896 if (cEdge->faces[1] == NULL) {
1897 cEdge->sharpness = 10;
1898 }
1899 }
1900 }
1901 }
1902
1903 // Finalize the faces
1904 allChildren = NULL;
1905 for (k=0,i=0;i<numFaces;i++) {
1906
1907 // Set the facevarying parameters
1908 for (j=0;j<faces[i]->numEdges;j++) {
1909 faces[i]->vertices[j]->facevarying = data.facevaryingData + (k+j)*data.facevaryingSize;
1910
1911 // Check for degenerate faces
1912 const int val = faces[i]->vertices[j]->valence;
1913 const int fval = faces[i]->vertices[j]->fvalence;
1914 if((val == 1)) { warning(CODE_CONSISTENCY,"Subdivision mesh has hanging vertex"); k += faces[i]->numEdges; goto skipFace; }
1915 if((val == 2) && (fval != 1)) { warning(CODE_CONSISTENCY,"Subdivision mesh is degenerate (face %d)\n",i); k += faces[i]->numEdges; goto skipFace; }
1916 if((val >= 3) && (fval > val)) { warning(CODE_CONSISTENCY,"Subdivision mesh is degenerate (face %d)\n",i); k += faces[i]->numEdges; goto skipFace; }
1917 }
1918
1919 k += j;
1920
1921 // Finally, create the face
1922 faces[i]->create(allChildren);
1923
1924 skipFace:
1925 ; // intentionally empty
1926 }
1927
1928 // Re-claim the memory
1929 memEnd(context->threadMemory);
1930
1931 // Set the children objects
1932 setChildren(context,allChildren);
1933
1934 if (i==0) warning(CODE_CONSISTENCY,"Subdivision mesh is trivial (skipped)\n");
1935
1936 osUnlock(mutex);
1937 }
1938
1939