FreeWRL / FreeX3D 4.3.0
Component_NURBS.c
1
2/****************************************************************************
3 This file is part of the FreeWRL/FreeX3D Distribution.
4
5 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
6
7 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
19****************************************************************************/
20
21
22/*******************************************************************
23
24 X3D NURBS Component
25
26*********************************************************************/
27
28#include <config.h>
29#include <system.h>
30#include <display.h>
31#include <internal.h>
32
33#include <libFreeWRL.h>
34
35#include "../vrml_parser/Structs.h"
36#include "../main/headers.h"
37
38#include "Collision.h"
39#include "LinearAlgebra.h"
40#include "../opengl/Frustum.h"
41#include "../opengl/Material.h"
42#include "Component_Geometry3D.h"
43#include "../opengl/OpenGL_Utils.h"
44#include "../opengl/Textures.h"
45
46#include "Component_Shape.h"
47#include "../scenegraph/RenderFuncs.h"
48#include "../vrml_parser/CRoutes.h"
49#include "Polyrep.h"
50#include <float.h>
51#if defined(_MSC_VER) && _MSC_VER < 1500
52#define cosf cos
53#define sinf sin
54#endif
55
56typedef struct pComponent_NURBS{
57 void *nada;// = 0;
58
60void *Component_NURBS_constructor(){
61 void *v = MALLOCV(sizeof(struct pComponent_NURBS));
62 memset(v,0,sizeof(struct pComponent_NURBS));
63 return v;
64}
65void Component_NURBS_init(struct tComponent_NURBS *t){
66 //public
67 //private
68 t->prv = Component_NURBS_constructor();
69 {
71 p->nada = NULL;
72 }
73}
74//ppComponent_NURBS p = (ppComponent_NURBS)gglobal()->Component_NURBS.prv;
75
76/*
77Specs:
78http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/nurbs.html
79Examples:
80http://www.web3d.org/x3d/content/examples/Basic/NURBS/
81
82Book: The NURBS Book
83Piegl, Les and Tiller, Wayne; The NURBS Book, 2nd Edition, Springer-Verlag (Berlin), 1997, ISBN: 3-540-61545-8.
84- about $120 new, softcover or kindle
85- some university libraries have it, you don't absolutely need it, the swept and swung ideas are in it
86
87Nov 2014 - dug9 did some nurbs using libnurbs2, and following The Nurbs Book
88 - didn't finish the component
89 - personal notes say Nurbs Level 1 done
90July 2016
91Not sure what's done and what's not, nothing indicaded on Conformace page:
92http://freewrl.sourceforge.net/conformance.html
93 code
94Level 1 Conformance page review
95CoordinateDouble (not mentioned) DONE
96NurbsCurve Not Implemented DONE
97NurbsOrientationInterpolatorNot Implemented stub
98NurbsPatchSurface Not Implemented DONE
99NurbsPositionInterpolator Not Implemented stub
100NurbsSurfaceInterpolator Not Implemented stub
101NurbsTextureCoordinate Not Implemented -
102Level 2
103NurbsSet Not Implemented -
104Level 3
105NurbsCurve2D Not Implemented DONE
106ContourPolyline2D Not Implemented DONE
107NurbsSweptSurface Not Implemented -
108NurbsSwungSurface Not Implemented -
109Level 4
110Contour2D Not Implemented DONE
111NurbsTrimmedSurface Not Implemented DONE?
112
113Perl: all the above including CoordinateDouble are in perl
114
115Analysis
116dug9, 2016:
117Chapter 12 of Redbook has lots of glu nurbs functions.
118freewrl doesn't use opengl glu.
119There is some source for it:
120 http://mesa3d.org/
121 ftp://ftp.freedesktop.org/pub/mesa/glu/
122 http://oss.sgi.com/projects/ogl-sample/
123So we're left to re-implement the hard way.
124I find nurbs libs are always disappointing in documentation.
125I think that's because there's not a lot to nurbs, mostly plumbing and little meat:
126- Each tesselation point Ci is computed as a weighted blend of control points: Ci = f(Pn,wn)
127- There are a few blending functions: linear, quadratic, cubic - in theory could go higher
128- there's a trick for doing sharp corners: knots (repeating a control point)
129- hard part: adaptive triangulation, might need callback plumbing, libnurbs2 has some of that
130Did I make a mistake trying to use libnurbs in 2014? Is it too much lib plumbing for too little meat?
131Here's a smaller MIT .c
132https://github.com/retuxx/tinyspline
133Or you can just read a bit more and manually implement nurbs.
134
135
136HARD PARTS:
1371. nurbsSet:
138 Q1.how smooth between nurbs 'tiles'? C0, C1, C2 continuity?
139 Q1a. how to find matching/joining/adjacent edges from 2+ patches?
140 Q1b. how to use adjoinging patch info to modify/blend on/near/in-overalap of the join?
141
1422. trimmed surfaces - procedure?
143 Hint: however we triangulate font glyphs in Component_Text would be a good example,
144 - might be able to borrow code from it
145 Terminology:
146 Tesselate: Nurbs term for interpolate/blend a given target interpolation point
147 Triangulate: take cloud of points, and join them with edges to make surface triangles
148
149 Fuzzy guess algo:
150 a) tesselate 2D curve in uv space of surface => A2dtess
151 b) tesselate 3D surface tesselation grid by itself => Btess
152 [option skip points inside A2dtess here instead of c)]
153 c) use point-in-poly test to remove Btess surface tesselation points
154 inside A2dtess tesselated curve: Btess - inside(A2dtess) => Ctess
155 d) go over A2dtess 2D curve point by point, interpolating/blending/tesselating in 3D like they
156 were surface tesselation points A2dtess => Dtess
157 e) add Dtess points to Ctess points => Etess
158 f) triangulate Etess => Etris
159 g) follow A2dtess points in Etris, swapping triangles so triangle edges are along A2dtess
160 h) do point-in-poly of Etris 2D triangle centroids, using A2dtess polygon,
161 to remove triangles inside A2dtess => Ftris
162 Ftris should be a trimmed surface
163
1643. Adaptive triangulation
165 a regular grid in uv space does not transform into a uniform grid in xyz space
166 with nurbs. And so there's a lot of plumbing in glu and other libs for
167 refining the xyz grid a) in xyz space or b) in screenspace (pixels), using some
168 measure of error and/or chordlength.
169
170 http://people.scs.carleton.ca/~c_shu/Publications/stmalo99.pdf
171 - Triangulating Trimmed NURBS Surfaces
172 http://www.saccade.com/writing/graphics/RE-PARAM.PDF
173 - Arc Length Parameterization of Spline Curves
174 - uses yet-another nurbs curve to interpolate XY space regular length chords
175
176
177*/
178void free_polyrep(struct X3D_PolyRep *rep){
179 //see also delete_polyrep - did dug9 duplicate the function or is it different?
180 if(rep){
181 rep->ntri = 0;
182 rep->transparency = 0;
183 //Q. are any of these added to GC tables? If not..
184 glDeleteBuffers(VBO_COUNT, rep->VBO_buffers);
185 FREE_IF_NZ(rep->actualCoord);
186 FREE_IF_NZ(rep->cindex);
187 FREE_IF_NZ(rep->colindex);
188 FREE_IF_NZ(rep->GeneratedTexCoords[0]);
189 FREE_IF_NZ(rep->norindex);
190 FREE_IF_NZ(rep->normal);
191 FREE_IF_NZ(rep->tcindex);
192 FREE_IF_NZ(rep);
193 }
194}
195struct X3D_PolyRep * create_polyrep(){
196 int i;
197 struct X3D_PolyRep *polyrep;
198
199 polyrep = MALLOC(struct X3D_PolyRep *, sizeof(struct X3D_PolyRep));
200 memset(polyrep,0,sizeof(struct X3D_PolyRep));
201 polyrep->ntri = -1;
202 //polyrep->cindex = 0; polyrep->actualCoord = 0; polyrep->colindex = 0; polyrep->color = 0;
203 //polyrep->norindex = 0; polyrep->normal = 0; polyrep->flat_normal = 0; polyrep->GeneratedTexCoords = 0;
204 //polyrep->tri_indices = 0; polyrep->wire_indices = 0; polyrep->actualFog = 0;
205 //polyrep->tcindex = 0;
206 //polyrep->tcoordtype = 0;
207 //polyrep->last_index_type = 0; polyrep->last_normal_type = 0;
208 polyrep->streamed = FALSE;
209
210 /* for Collision, default texture generation */
211 polyrep->minVals[0] = 999999.9f;
212 polyrep->minVals[1] = 999999.9f;
213 polyrep->minVals[2] = 999999.9f;
214 polyrep->maxVals[0] = -999999.9f;
215 polyrep->maxVals[1] = -999999.9f;
216 polyrep->maxVals[2] = -999999.9f;
217
218 for (i=0; i<VBO_COUNT; i++)
219 polyrep->VBO_buffers[i] = 0;
220
221 /* printf ("generating buffers for node %p, type %s\n",p,stringNodeType(p->_nodeType)); */
222 glGenBuffers(1,&polyrep->VBO_buffers[VERTEX_VBO]);
223 glGenBuffers(1,&polyrep->VBO_buffers[INDEX_VBO]);
224 //glGenBuffers(1,&polyrep->VBO_buffers[NORMAL_VBO]);
225 //glGenBuffers(1,&polyrep->VBO_buffers[TEXTURE_VBO0+0]);
226
227
228
229 /* printf ("they are %u %u %u %u\n",polyrep->VBO_buffers[0],polyrep->VBO_buffers[1],polyrep->VBO_buffers[2],polyrep->VBO_buffers[3]); */
230 return polyrep;
231}
232
233
234
235#ifdef NURBS_LIB
236//START MIT LIC >>>>>>>>
237//some algorithms from "The Nurbs Book", Les Piegl et al
238int uniformKnot(int n, int p, float *U){
239 int j, k, m, mm;
240 float uniform;
241 m = n + p + 1;
242 k = 0;
243 uniform = 1.0f/(float)(n-p);
244 for(j=0;j<p;k++,j++){
245 U[k] = 0.0f;
246 }
247 mm = n - p + 1;
248 for(j=0;j<mm;j++,k++){
249 U[k] = j*uniform;
250 }
251 for(j=0;j<p;j++,k++){
252 U[k] = 1.0f;
253 }
254 U[8] = 1.0f;
255 printf("U= ");
256 for(j=0;j<m+1;j++){
257 printf(" U[%d]=%f",j,U[j]);
258 }
259 return 1;
260}
261
262//ALGORITHM A2.1 p.68 Piegl
263int FindSpan(int n, int p, float u, float *U)
264{
265 /* Determine the knot span index: where u is in U[i]
266 Input:
267 n - # of control points == m - p - 1
268 p - degree of curve = power + 1 ie linear 2, quadratic 3, cubic 4
269 U - knot vector [0 ... m-1]
270 u - scalar curve parameter in range u0 - um
271 Return:
272 knot span index ie if u is between U[i] and U[i+1] return i
273 Internal:
274 order = p + 1
275 m = number of knots = n + order
276 Algorithm:
277 limit the search range between p and m - p - 1 (2 and 4 for this example)
278 assume clamped/pinned ends
279 Example:
280 U = { 0,0,0,1,2,3,4,4,5,5,5 } m = 11
281 spnidx 0 1 2 3 4 5 6 7 8 9
282 u = 2.5 ^ span index == 4
283 u = .0001 ^ span index == 2
284 u = 0 ^ span index == 2
285 u = .4999 ^ span index = 4
286 u = 5 ^ span index = 4
287
288 */
289 if(1){
290 //dug9 algo, simpler linear search
291 int i, span, m, order;
292 order = p + 1;
293 m = n + order;
294 span = p;
295 for(i=p;i<n;i++){
296 span = i;
297 if(u >= U[i] && u < U[i+1])
298 break;
299 }
300 return span;
301 }else{
302 int low, high, mid;
303 //if(u == U[n+1]) return n;
304 if(u == U[n]) return n-1; //this prevents divide by zero when u = 1
305 low = p; high = n+1; mid = (low+high)/2;
306 while(u < U[mid] || u >= U[mid+1]){
307 if(u < U[mid]) high = mid;
308 else low = mid;
309 mid = (low + high)/2;
310 }
311 return mid;
312 }
313}
314//ALGORITHM A2.2 p.70 Piegl
315int BasisFuns(int span, float u, int p, float *U, float *N){
316 /* Compute the non-vanishing Basis functions
317 Input:
318 span = knot span: which knots is this u in between: if between U[i] and U[i+1], span == i
319 u - scalar curve parameter in range u0 - um
320 p - degree of curve = power + 1 ie linear 2, quadratic 3, cubic 4
321 U - knot vector [0 ... m-1]
322 Output:
323 N - precomputed rational bernstein basis functions for a given span
324 - these are blending weights that say how much of each surrounding
325 control point is used in a given span
326 */
327 int j, r;
328 float left[5], right[5], saved, temp;
329 //float testzero;
330 N[0] =1.0f;
331 for(j=1;j<=p;j++){
332 left[j] = u - U[span+1 - j];
333 right[j] = U[span+j] - u;
334 saved = 0.0f;
335 for(r=0;r<j;r++){
336 //testzero = right[r+1]+left[j-r];
337 //if(fabs(testzero) < .00001)
338 // printf("ouch divide by zero\n");
339 temp = N[r]/(right[r+1]+left[j-r]);
340 N[r] = saved + right[r+1]*temp;
341 saved = left[j-r]*temp;
342 }
343 N[j] = saved;
344 }
345 return 1;
346}
347
348//ALGORITHM A4.1 p.124 Piegl
349int CurvePoint(int n, int p, float* U, float *Pw, float u, float *C )
350{
351 /* Compute point on rational B-spline curve
352 Input:
353 n - # of control points == m - p - 1
354 p - degree of curve linear 1, quadratic 2, cubic 3
355 U[] - knot vector [0 ... m], m = n + p + 1
356 Pw[] - control point vector
357 where w means rational/homogenous: Pw[i] = {wi*xi,wi*yi,wi*zi,wi}
358 u - scalar curve parameter in range u0 - um
359 Output:
360 C - 3D point = Cw/w
361 Internal:
362 span = knot span: which knots is this u in between: if between U[i] and U[i+1], span == i
363 N[] - precomputed rational bernstein basis functions for a given span
364 - these are blending weights that say how much of each surrounding control point is used in a given span
365 w - weight, assuming it's uniform
366 */
367 int span,i,j;
368 float N[100], w;
369 float Cw[4];
370 span = FindSpan(n,p,u,U);
371 BasisFuns(span,u,p,U,N);
372 w = 1.0f;
373 for(i=0;i<4;i++) Cw[i] = 0.0f;
374 //Cw[3] = w;
375 for(j=0;j<=p;j++){
376 for(i=0;i<4;i++){
377 Cw[i] += N[j]*Pw[(span-p+j)*4 + i];
378 }
379 }
380 for(i=0;i<3;i++)
381 C[i] = Cw[i]/Cw[3];
382
383 return 1;
384}
385
386
387
388
389
390//ALGORITHM A4.3 p.134 Piegl
391/* example call:
392ok = SurfacePoint( node->uDimension,node->uOrder-1,node->uKnot.p,
393 node->vDimension,node->vOrder-1,node->vKnot.p,
394 node->controlPoint.p,uv[0],uv[1],xyz);
395*/
396int SurfacePoint(int n,int p,float *U,
397 int m, int q,float *V,
398 float *Pw,float u,float v,float *S)
399{
400 /* Compute point on rational B-Spline surface S(u,v)
401 Input:
402 u direction:
403 n - # of control points
404 p - degree of curve linear 1, quadratic 2, cubic 3
405 U[] - knot vector [0 ... n + p + 1]
406 u - scalar curve parameter
407 v direction:
408 m - # of control points
409 q - degree of curve linear 1, quadratic 2, cubic 3
410 V[] - knot vector [0 ... m + q + 1]
411 v - scalar curve parameter
412 Pw[] - control point vector
413 where w means rational/homogenous: Pw[i] = {wi*xi,wi*yi,wi*zi,wi}
414 Output:
415 S - output 3D point = Sw/w
416 */
417 int uspan, vspan, i, l, k;
418 float Nu[100], Nv[100], temp[6][4], Sw[4];
419
420 uspan = FindSpan(n,p,u,U);
421 BasisFuns(uspan,u,p,U,Nu);
422 vspan = FindSpan(m,q,v,V);
423 BasisFuns(vspan,v,q,V,Nv);
424 for(l=0;l<=q;l++){
425 for(i=0;i<4;i++)
426 temp[l][i] = 0.0f;
427 for(k=0;k<=p;k++){
428 //temp[l] += Nu[k]*Pw[uspan-p+k][vspan-q+l];
429 for(i=0;i<4;i++)
430 temp[l][i] += Nu[k]*Pw[((uspan-p+k)*n + (vspan-q+l))*4 + i];
431
432 }
433 }
434 for(i=0;i<4;i++) Sw[i] = 0.0f;
435 for(l=0;l<=q;l++){
436 for(i=0;i<4;i++)
437 Sw[i] += Nv[l]*temp[l][i];
438 }
439 for(i=0;i<3;i++)
440 S[i] = Sw[i]/Sw[3];
441 return 1;
442}
443// <<<<< END MIT LIC
444#ifdef AQUA
445#include <OpenGL/gl.h>
446#include <OpenGL/glu.h>
447#define CALLBACK
448#else
449#include <libnurbs2.h>
450#endif
451static int DEBG = 0; //glu nurbs surface and trim calls
452static int DEBGC = 0; //curve calls
453
454//defined in Component_RigidBodyPhysics
455int NNC0(struct X3D_Node* node);
456void MNC0(struct X3D_Node* node);
457void MNX0(struct X3D_Node* node);
458#define NNC(A) NNC0(X3D_NODE(A)) //node needs compiling
459#define MNC(A) MNC0(X3D_NODE(A)) //mark node compiled
460#define MNX(A) MNX0(X3D_NODE(A)) //mark node changed
461#define PPX(A) getTypeNode(X3D_NODE(A)) //possible proto expansion
462
463void CALLBACK nurbsError(GLenum errorCode)
464{
465 //const GLubyte *estring;
466
467 //estring = gluErrorString(errorCode);
468 //fprintf (stderr, "Nurbs Error: %s\n", estring);
469 printf("ouch from nurbsError\n");
470 // exit (0);
471}
472
473//curve
474void CALLBACK nurbscurveBegincb(GLenum type, void *ud)
475{
476 struct X3D_NurbsCurve *node = (struct X3D_NurbsCurve *)ud;
477 if(DEBGC) printf("nurbscurveBegin\n");
478}
479void CALLBACK nurbscurveVertexcb(GLfloat *vertex, void *ud)
480{
481 int i, np,ns;
482 struct SFVec3f *pp;
483 struct X3D_NurbsCurve *node = (struct X3D_NurbsCurve *)ud;
484 ns = node->__points.n;
485 np = node->__numPoints;
486 if(np+1 > ns) {
487 ns = np *2;
488 node->__points.p = REALLOC(node->__points.p,ns * sizeof(struct SFVec3f));
489 node->__points.n = ns;
490 }
491 pp = &node->__points.p[np];
492 for(i=0;i<3;i++)
493 pp->c[i] = vertex[i];
494 node->__numPoints ++;
495 //node->__points.n++;
496 if(DEBGC) printf("nurbscurveVertex\n");
497}
498void CALLBACK nurbscurveNormalcb(GLfloat *nml, void *ud)
499{
500 struct X3D_NurbsCurve *node = (struct X3D_NurbsCurve *)ud;
501 if(DEBGC) printf("nurbscurveNormal\n");
502}
503void CALLBACK nurbscurveEndcb(void *ud)
504{
505 struct X3D_NurbsCurve *node = (struct X3D_NurbsCurve *)ud;
506 //node->__numPoints = node->__points.n;
507 if(DEBGC) printf("nurbscurveEnd\n");
508}
509
510
511
512int generateUniformKnotVector(int order, int ncontrol, float *knots){
513 //produced pinned uniform knot vector
514 //caller: please malloc knots = malloc( (ncontrol + order ) * sizeof(float))
515 // http://www.saccade.com/writing/graphics/KnotVectors.pdf
516 //maximum nuber of equalvalue consecutive knots:
517 // a) in middle of knot vector: <= order-1
518 // b) at start and end of knot vector: <= order (for pinned uniform)
519 // exmple order = 4 + ncontrol = 6 => 10 knots
520 // 0 0 0 0 .33 .66 1 1 1 1
521 // example order = 3 + ncontrol = 3 => 6 knots
522 // 0 0 0 1 1 1
523 // example order = 2 + ncontrol = 2 => 4 knots
524 // 0 0 1 1
525 //number of knots == ncontrol + order
526 int j,k,m;
527 float uniform;
528 m = ncontrol - order;
529 k = 0;
530 uniform = 1.0f/(float)(m + 1);
531 for(j=0;j<order;k++,j++){
532 knots[k] = 0.0f;
533 }
534 for(j=0;j<m;j++,k++){
535 knots[k] =uniform*(float)(j+1);
536 }
537 for(j=0;j<order;j++,k++){
538 knots[k] = 1.0f;
539 }
540 return m;
541}
542int knotsOK(int order, int ncontrol, int nknots, double *knots){
543 int ok = TRUE;
544
545 if(nknots < 2 || nknots != ncontrol + order )
546 ok = FALSE;
547 if(ok){
548 int i,nconsec = 1;
549 double lastval = knots[0];
550 for(i=1;i<nknots;i++){
551 if(lastval == knots[i]) nconsec++;
552 else nconsec = 1;
553 if(nconsec > order)
554 ok = false;
555 if(knots[i] < lastval)
556 ok = false;
557 if(!ok) break;
558 lastval = knots[i];
559 }
560 }
561 return ok;
562}
563int knotsOKf(int order, int ncontrol, int nknots, float *knots){
564 int ok = TRUE;
565
566 if(nknots < 2 || nknots != ncontrol + order )
567 ok = FALSE;
568 if(ok){
569 int i, nconsec = 1;
570 double lastval = knots[0];
571 for(i=1;i<nknots;i++){
572 if(lastval == knots[i]) nconsec++;
573 else nconsec = 1;
574 if(nconsec > order)
575 ok = false;
576 if(knots[i] < lastval)
577 ok = false;
578 if(!ok) break;
579 lastval = knots[i];
580 }
581 }
582 return ok;
583}
584void compile_ContourPolyline2D(struct X3D_ContourPolyline2D *node){
585 MARK_NODE_COMPILED;
586 if(node->point.n && !node->controlPoint.n){
587 int i;
588 //version v3.0 had a mfvec2f point field, version 3.1+ changed to mfvec2d controlPoint field
589 node->controlPoint.p = MALLOC(struct SFVec2d*,node->point.n * sizeof(struct SFVec2d));
590 for(i=0;i<node->point.n;i++)
591 float2double(node->controlPoint.p[i].c,node->point.p[i].c,2);
592 }
593}
594
595void compile_NurbsCurve(struct X3D_NurbsCurve *node){
596 MARK_NODE_COMPILED
597 {
598 int i,j, n, nk;
599 GLfloat *xyzw, *knots;
600 nk = n = 0;
601 xyzw = knots = NULL;
602 if(node->controlPoint){
603 if(node->controlPoint->_nodeType == NODE_CoordinateDouble){
604 struct Multi_Vec3d *mfd;
605 mfd = &((struct X3D_CoordinateDouble *)(node->controlPoint))->point;
606 n = mfd->n;
607 xyzw = MALLOC(void *, n * 4 * sizeof(GLfloat));
608 for(i=0;i<mfd->n;i++){
609 for(j=0;j<3;j++){
610 xyzw[i*4 + j] = (float) mfd->p[i].c[j];
611 }
612 }
613 }else if(node->controlPoint->_nodeType == NODE_Coordinate){
614 struct Multi_Vec3f *mff;
615 mff = &((struct X3D_Coordinate *)(node->controlPoint))->point;
616 n = mff->n;
617 xyzw = MALLOC(void *, n * 4 * sizeof(GLfloat));
618 for(i=0;i<mff->n;i++){
619 for(j=0;j<3;j++){
620 xyzw[i*4 + j] = mff->p[i].c[j];
621 }
622 }
623 }
624 }else{
625 n = 0;
626 }
627 if(node->weight.n && node->weight.n == n){
628 double w;
629 int m,im;
630 m = min(node->weight.n, n);
631 for(i=0;i<n;i++){
632 im = i < m ? i : m-1;
633 w = node->weight.p[im];
634 xyzw[i*4 + 3] = (float)w;
635 }
636 }else{
637 for(i=0;i<n;i++) xyzw[i*4 + 3] = 1.0;
638 }
639 //if(node->knot.n && node->knot.n == n + node->order ){
640 if(knotsOK(node->order,n,node->knot.n,node->knot.p)){
641
642 nk = node->knot.n;
643 knots = MALLOC(void *, nk * sizeof(GLfloat));
644 for(i=0;i<nk;i++){
645 knots[i] = (GLfloat)node->knot.p[i];
646 }
647 //printf("good knot nk=%d\n",nk);
648 //for(int ii=0;ii<nk;ii++)
649 // printf("[%d]=%f \n",ii,knots[ii]);
650
651 }else{
652 static int once = 0;
653 //generate uniform knot vector
654 nk = n + node->order ;
655 //caller: please malloc knots = malloc( (ncontrol + order ) * sizeof(float))
656 knots = MALLOC(void *, nk *sizeof(GLfloat));
657 generateUniformKnotVector(node->order,n, knots);
658 if(!once){
659 int ii;
660 printf("bad knot vector, replacing with:\n");
661 for(ii=0;ii<nk;ii++)
662 printf("[%d]=%f \n",ii,knots[ii]);
663 once = 1;
664 }
665 //nk = 0;
666 }
667
668 if(n && nk && nk >= n){
669 GLUnurbsObj *theNurb;
670 int ntess, mtess;
671 mtess = node->order + 1;
672 ntess = node->tessellation;
673 theNurb = gluNewNurbsRenderer();
674 gluNurbsProperty(theNurb, GLU_NURBS_MODE, GLU_NURBS_TESSELLATOR);
675 gluNurbsCallbackData(theNurb,(GLvoid*)node);
676 if(0){
677 //chord length or automatic - not implemented properly nor tested thoroughly
678 //if you do chord length in pixels, you need to manually pass in sampling matrices
679 //and somehow you need to trigger a recompile: another call to this compile_
680 // as avatar/viewer moves closer (father) from the nurbs node
681 double model[16], proj[16];
682 float modelf[16], projf[16];
683 int viewPort[10];
684 if(ntess > 0)
685 mtess = ntess;
686 else if(ntess < 0)
687 mtess = -ntess;
688 node->__points.p = MALLOC(void *, sizeof(struct SFVec3f)*n*10); // just a guess to get started
689 node->__points.n = n*10; //.n will be used for realloc test in callbacks
690
691 gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, (float)(mtess)); //25.0);
692 if(ntess < 0)
693 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_PATH_LENGTH); //pixels, the default
694 else
695 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_PARAMETRIC_TOLERANCE);
696 gluNurbsProperty(theNurb, GLU_AUTO_LOAD_MATRIX,GL_FALSE);
697
698 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, model);
699 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
700 FW_GL_GETINTEGERV(GL_VIEWPORT, viewPort);
701 for(i=0;i<16;i++){
702 modelf[i] = (float)model[i];
703 projf[i] = (float)proj[i];
704 }
705 gluLoadSamplingMatrices(theNurb,modelf,projf,viewPort);
706 }
707 if(1){
708 //uniform spacing of sampling points in u (or uv) parameter space - works
709 //node must specify tesselation value. see specs for interpretation
710 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/nurbs.html#NurbsCurve
711 if(ntess > 0)
712 mtess = max(mtess,ntess+1);
713 else if(ntess < 0)
714 mtess = max(mtess,(-ntess * n) + 1);
715 else
716 mtess = max(mtess,2*n + 1);
717 mtess = (int)((float)mtess * node->_tscale);
718 node->__points.p = MALLOC(void *, sizeof(struct SFVec3f)*mtess+1);
719 node->__points.n = mtess; //.n will be used for realloc test in callbacks
720 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_DOMAIN_DISTANCE);
721 gluNurbsProperty(theNurb,GLU_U_STEP,(GLfloat)mtess);
722 }
723 gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
724 gluNurbsCallback(theNurb, GLU_ERROR, nurbsError);
725 gluNurbsCallback(theNurb, GLU_NURBS_BEGIN_DATA, nurbscurveBegincb);
726 gluNurbsCallback(theNurb, GLU_NURBS_VERTEX_DATA, nurbscurveVertexcb);
727 gluNurbsCallback(theNurb, GLU_NURBS_NORMAL_DATA, nurbscurveNormalcb);
728 gluNurbsCallback(theNurb, GLU_NURBS_END_DATA, nurbscurveEndcb);
729 gluBeginCurve(theNurb);
730 node->__numPoints = 0;
731 gluNurbsCurve(theNurb,nk,knots,4,xyzw,node->order,GL_MAP1_VERTEX_4);
732 gluEndCurve(theNurb);
733 gluDeleteNurbsRenderer(theNurb);
734 node->__points.n = node->__numPoints;
735 }
736 }
737}
738
739void render_NurbsCurve(struct X3D_NurbsCurve *node){
740 ttglobal tg = gglobal();
741 COMPILE_IF_REQUIRED
742 // from Arc2D
743 if (node->__numPoints>0) {
744 // for BoundingBox calculations
745 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
746 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
747
748 //OLDCODE GET_COLOUR_POINTER
749 LIGHTING_OFF
750 DISABLE_CULL_FACE
751 //OLDCODE DO_COLOUR_POINTER
752
753 FW_GL_VERTEX_POINTER (3,GL_FLOAT,0,(GLfloat *)node->__points.p);
754 sendArraysToGPU (GL_LINE_STRIP, 0, node->__numPoints);
755 tg->Mainloop.trisThisLoop += node->__numPoints;
756 }
757}
758
759void compile_NurbsTextureCoordinate(struct X3D_NurbsTextureCoordinate *node){
760 //get knots from double to float and QC the knots
761 int nc, nu, nku, nkv, nv, i,j;
762 float *knotsu, *knotsv, *xyzw;
763
764 struct Multi_Vec2f *mff;
765 mff = &node->controlPoint;
766 nc = mff->n;
767 xyzw = MALLOC(void *, nc * 4 * sizeof(GLfloat));
768 for(i=0;i<mff->n;i++){
769 for(j=0;j<2;j++){
770 xyzw[i*4 + j] = mff->p[i].c[j];
771 }
772 xyzw[i*4 + 2] = 0.0f; //z == 0 for 2D
773 xyzw[i*4 + 3] = 1.0f; //homogenous 1
774 }
775 nu = node->uDimension;
776 nv = node->vDimension;
777 if(node->weight.n && node->weight.n == nc){
778 double w;
779 int m,im;
780 m = min(node->weight.n, nc);
781 for(i=0;i<nc;i++){
782 im = i < m ? i : m-1;
783 w = node->weight.p[im];
784 xyzw[i*4 + 3] = (float) w;
785 }
786 }else{
787 for(i=0;i<nc;i++) xyzw[i*4 + 3] = 1.0;
788 }
789 nu = node->uDimension;
790 nv = node->vDimension;
791 //int knotsOK(int order, int ncontrol, int nknots, double *knots)
792 //if(node->uKnot.n && node->uKnot.n == nu + node->uOrder ){
793 if(knotsOK(node->uOrder,nu,node->uKnot.n,node->uKnot.p)){
794 //could do another check: max number of consecutive equal value knots == order
795 //could do another check: knot values == or ascending
796 nku = node->uKnot.n;
797 knotsu = MALLOC(void *, nku * sizeof(GLfloat));
798 for(i=0;i<nku;i++){
799 knotsu[i] = (GLfloat)node->uKnot.p[i];
800 }
801 if(DEBG){
802 int ii;
803 printf("good u knot vector nk=%d\n",nku);
804 for(ii=0;ii<nku;ii++)
805 printf("[%d]=%f \n",ii,knotsu[ii]);
806 }
807
808 }else{
809 //generate uniform knot vector
810 static int once = 0;
811 nku = nu + node->uOrder ;
812 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
813 knotsu = MALLOC(void *, nku *sizeof(GLfloat));
814 generateUniformKnotVector(node->uOrder,nu, knotsu);
815 if(!once){
816 int ii;
817 printf("bad u knot vector given, replacing with:\n");
818 for(ii=0;ii<nku;ii++)
819 printf("[%d]=%f \n",ii,knotsu[ii]);
820 once = 1;
821 }
822 //nk = 0;
823 }
824
825 if(knotsOK(node->vOrder,nv,node->vKnot.n,node->vKnot.p)){
826 //if(node->vKnot.n && node->vKnot.n == nv + node->vOrder ){
827 nkv = node->vKnot.n;
828 knotsv = MALLOC(void *, nkv * sizeof(GLfloat));
829 for(i=0;i<nkv;i++){
830 knotsv[i] = (GLfloat)node->vKnot.p[i];
831 }
832 if(DEBG){
833 int ii;
834 printf("good v knot vector nk=%d\n",nkv);
835 for(ii=0;ii<nkv;ii++)
836 printf("[%d]=%f \n",ii,knotsv[ii]);
837 }
838
839 }else{
840 static int once = 0;
841 //generate uniform knot vector
842 nkv = nv + node->vOrder ;
843 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
844 knotsv = MALLOC(void *, nkv *sizeof(GLfloat));
845 generateUniformKnotVector(node->vOrder,nv, knotsv);
846 if(!once){
847 int ii;
848 printf("bad v knot vector given, replacing with:\n");
849 for(ii=0;ii<nkv;ii++)
850 printf("[%d]=%f \n",ii,knotsv[ii]);
851 once = 1;
852 }
853 if(!knotsOKf(node->vOrder,nv,nkv,knotsv))
854 printf("ouch still not right knot vector\n");
855 //nk = 0;
856 }
857 node->_uKnot.p = knotsu;
858 node->_uKnot.n = nku;
859 node->_vKnot.p = knotsv;
860 node->_vKnot.n = nkv;
861 node->_controlPoint.p = (struct SFVec4f*)xyzw;
862 node->_controlPoint.n = nc;
863 MNC(node);
864
865}
866int getNurbsSurfacePoint(struct X3D_Node *nurbsSurfaceNode, float *uv, float *xyz){
867 int ret = 0;
868 if(nurbsSurfaceNode){
869 switch(nurbsSurfaceNode->_nodeType){
870 case NODE_NurbsTextureCoordinate:
871 {
872 struct X3D_NurbsTextureCoordinate *node = (struct X3D_NurbsTextureCoordinate *)PPX(nurbsSurfaceNode);
873 if(NNC(node)) compile_NurbsTextureCoordinate(node);
874 ret = SurfacePoint( node->uDimension,node->uOrder-1,node->_uKnot.p,
875 node->vDimension,node->vOrder-1,node->_vKnot.p,
876 (float *)node->_controlPoint.p,uv[0],uv[1],xyz);
877 }
878 break;
879 case NODE_NurbsPatchSurface:
880 break;
881 case NODE_NurbsTrimmedSurface:
882 break;
883 default:
884 break;
885 }
886 }
887
888 return ret;
889}
890
891/* GenPolyrep functions assume a node inherits from X3DGeometryNode.
892 NurbsPatchSurface inherits from X3DParametricGeometryNode.
893 So we can't use all the genpolyrep stuff, until we have our node compiled into one.
894 Then we can delegate back to generic polyrep functions
895render - can delegate to polyrep
896rendray - can delegate to polyrep
897(x make - we will do a compile instead)
898collide - can delegate to polyrep
899compile - custom: we will convert our parametric surface to a polyrep in here
900
901 */
902
903 //stripstate - used for capturing the callback data when using gluNurbs in TESSELATOR mode
904 //we use TESSELATOR mode instead of RENDER mode because we use GLES2, not desktop GL.
905 //the libnurbs we have has the GL rendering stuff ifdefed out.
906 //so we capture the data in the callbacks, and then we can do what we normally do with
907 //mesh data in GLES2
908
909 struct stripState{
910 int type;
911 struct Vector pv; //vector of vertex points
912 struct Vector nv; //vector of normals
913 struct Vector tv; //vector of texcoords
914};
915
916//surface
917// strategy: on begin, we'll store the gl_ type, and zero __points
918// then accumulate the __points
919// and on end, convert the __points to ->_intern->polyrep points and triangle indices
920// using the stored type as a guide
921void CALLBACK nurbssurfBegincb(GLenum type, void *ud)
922{
923 struct stripState ss;
924 struct Vector * strips = (struct Vector *)ud;
925 if(0) if(DEBG) printf("callback nurbsSurfaceBegin\n");
926 if(0){
927 printf("nurbssurfBegin type = ");
928 switch(type){
929 case GL_QUAD_STRIP: printf("QUAD_STRIP");break;
930 case GL_TRIANGLE_STRIP: printf("TRIANGLE_STRIP");break;
931 case GL_TRIANGLE_FAN: printf("TRIANGLE_FAN");break;
932 case GL_TRIANGLES: printf("TRIANGLES");break;
933 default:
934 printf("not sure %x %d",type,type);
935 }
936 printf("\n");
937 }
938 ss.nv.n = 0;
939 ss.nv.allocn = 0;
940 ss.nv.data = NULL;
941 ss.tv.n = 0;
942 ss.tv.allocn = 0;
943 ss.tv.data = NULL;
944 ss.pv.n = 0;
945 ss.pv.allocn = 0;
946 ss.pv.data = NULL;
947 ss.type = type;
948 vector_pushBack(struct stripState,strips,ss);
949}
950void CALLBACK nurbssurfVertexcb(GLfloat *vertex, void *ud)
951{
952 struct stripState *ss;
953 struct SFVec3f pp;
954 struct Vector * strips = (struct Vector *)ud;
955 ss = vector_get_ptr(struct stripState,strips,strips->n -1);
956 memcpy(&pp,vertex,sizeof(struct SFVec3f));
957 vector_pushBack(struct SFVec3f,&ss->pv,pp);
958 //vector_set(struct stripState,strips,strips->n-1,ss);
959
960 if(0) printf("callback nurbssurfVertex %f %f %f\n",vertex[0],vertex[1],vertex[2]);
961}
962void CALLBACK nurbssurfNormalcb(GLfloat *nml, void *ud)
963{
964 struct stripState *ss;
965 struct SFVec3f pp;
966 struct Vector * strips = (struct Vector *)ud;
967 ss = vector_get_ptr(struct stripState,strips,strips->n -1);
968 memcpy(&pp,nml,sizeof(struct SFVec3f));
969 vector_pushBack(struct SFVec3f,&ss->nv,pp);
970 //vector_set(struct stripState,strips,strips->n-1,ss);
971
972 if(0) printf("callback nurbssurfNormal\n");
973}
974void CALLBACK nurbssurfEndcb(void *ud)
975{
976 struct stripState *ss;
977 struct Vector * strips = (struct Vector *)ud;
978 ss = vector_get_ptr(struct stripState,strips,strips->n -1);
979 if(0){
980 int i;
981 printf("nurbssurfEnd #p %d #n %d\n",ss->pv.n, ss->nv.n);
982 for(i=0;i<ss->pv.n;i++){
983 struct SFVec3f pp = vector_get(struct SFVec3f,&ss->pv,i);
984 printf("%f %f %f\n",pp.c[0],pp.c[1],pp.c[2]);
985 }
986 }
987 if(0) if(DEBG) printf("callback nurbsSurfaceEnd\n");
988
989}
990void CALLBACK nurbssurfTexcoordcb(GLfloat *tCrd, void *ud){
991 static int count = 0;
992 struct stripState *ss;
993 struct SFVec2f tp;
994 struct Vector * strips = (struct Vector *)ud;
995 ss = vector_get_ptr(struct stripState,strips,strips->n -1);
996 memcpy(&tp,tCrd,sizeof(struct SFVec2f));
997 vector_pushBack(struct SFVec2f,&ss->tv,tp);
998 //vector_set(struct stripState,strips,strips->n-1,ss);
999 //printf("%f %f %f\n",tCrd[0],tCrd[1],0.0f);
1000 //count++;
1001 //if(count % 50 == 0)
1002 // printf("\n");
1003 if(0) if(DEBG)
1004 printf("callback nurbssufTexcoordcb\n");
1005}
1006
1007
1008
1009#define GL_QUAD_STRIP 0x0008
1010
1011static int USETXCOORD = 1;
1012void convert_strips_to_polyrep(struct Vector * strips,struct X3D_NurbsTrimmedSurface *node){
1013 //this is a bit like compile_polyrep, except the virt_make is below
1014
1015 int i, j, npoints, np, ni, ntri, nindex, ntc;
1016 struct stripState *ss;
1017 struct X3D_PolyRep *rep_, *polyrep;
1018 struct X3D_TextureCoordinate * tcnode, tcnode0;
1019 GLuint *cindex, *norindex, *tcindex;
1020 float *tcoord = NULL;
1021
1022 //from compile_polyrep:
1023 //node = X3D_NODE(innode);
1024 //virt = virtTable[node->_nodeType];
1025
1026 /* first time through; make the intern structure for this polyrep node */
1027 if(node->_intern){
1028 polyrep = node->_intern;
1029 FREE_IF_NZ(polyrep->cindex);
1030 FREE_IF_NZ(polyrep->actualCoord);
1031 FREE_IF_NZ(polyrep->GeneratedTexCoords[0]);
1032 FREE_IF_NZ(polyrep->colindex);
1033 FREE_IF_NZ(polyrep->color);
1034 FREE_IF_NZ(polyrep->norindex);
1035 FREE_IF_NZ(polyrep->normal);
1036 FREE_IF_NZ(polyrep->flat_normal);
1037 FREE_IF_NZ(polyrep->tcindex);
1038 FREE_IF_NZ(polyrep->wire_indices);
1039 //glDeleteBuffers(VBO_COUNT,polyrep->VBO_buffers); //streampoly checks if 0 before doing a new one
1040 }
1041 if(!node->_intern)
1042 node->_intern = create_polyrep();
1043
1044 rep_ = polyrep = node->_intern;
1045
1046
1047 /* if multithreading, tell the rendering loop that we are regenning this one */
1048 /* if singlethreading, this'll be set to TRUE before it is tested */
1049
1050 //<< END FROM Compile_polyrep
1051
1052 // Start Virt_make_polyrep section >>>
1053 //texcoord
1054 if(USETXCOORD){
1055 rep_->ntexdim[0] = 2;
1056 rep_->tcoordtype = NODE_TextureCoordinate; //??
1057 rep_->ntcoord = 1;
1058 }
1059 tcnode = &tcnode0; //createNewX3DNode(NODE_TextureCoordinate);
1060
1061 npoints = nindex = ntc = 0;
1062 for(i=0;i<strips->n;i++){
1063 ss = vector_get_ptr(struct stripState,strips,i);
1064 npoints += ss->pv.n;
1065 ntc += ss->tv.n;
1066 switch(ss->type){
1067 case GL_QUAD_STRIP: nindex += (ss->pv.n -2)/2 * 5;break;
1068 case GL_TRIANGLE_STRIP: nindex += (ss->pv.n -2);break;
1069 case GL_TRIANGLE_FAN: nindex += (ss->pv.n -2);break;
1070 case GL_TRIANGLES: nindex += (ss->pv.n -2);break;
1071 default:
1072 nindex += (ss->pv.n -2);
1073 }
1074 }
1075 if (npoints > 0)
1076 {
1077 //printf("npoints %d ntc %d\n",npoints,ntc);
1078 rep_->actualCoord = MALLOC(void *, npoints * 3 * sizeof(float));
1079 rep_->normal = MALLOC(void *, npoints * 3 * sizeof(float));
1080 //if(USETXCOORD) rep->GeneratedTexCoords[0] = MALLOC(void *, npoints * 2 * sizeof(float));
1081 //if(USETXCOORD){
1082 // tcnode->point.p = MALLOC(void*, npoints * 2 * sizeof(float));
1083 // tcnode->point.n = npoints;
1084 //}
1085 //rep->t
1086 }
1087 rep_->ntri = ntri = nindex; //we'll over-malloc
1088
1089 if (rep_->ntri > 0)
1090 {
1091 cindex = rep_->cindex = MALLOC(GLuint *, sizeof(GLuint)*3*(ntri));
1092 norindex = rep_->norindex = MALLOC(GLuint *,sizeof(GLuint)*3*ntri);
1093 //if(USETXCOORD) rep_->tcindex = MALLOC(void *, ntri * 4 * sizeof(GLuint));
1094 tcindex = rep_->tcindex = MALLOC(GLuint*, sizeof(GLuint)*3*(ntri));
1095 // colindex = rep_->colindex = MALLOC(GLuint *, sizeof(*(rep_->colindex))*3*(ntri));
1096
1097 //FREE_IF_NZ(rep_->GeneratedTexCoords[0]);
1098 // we'll pass a X3D_TexCoordinate node //rep_->GeneratedTexCoords[0]
1099 tcoord = MALLOC (float *, sizeof (float) * ntri * 2 * 3);
1100
1101 }
1102
1103 np = 0;
1104 ni = 0;
1105 ntri = 0;
1106 for(i=0;i<strips->n;i++){
1107 ss = vector_get_ptr(struct stripState,strips,i);
1108//printf("ss.pv.n=%d nv.n=%d tv.n=%d\n",ss.pv.n,ss.nv.n,ss.tv.n);
1109 memcpy(&rep_->actualCoord[np*3],ss->pv.data,ss->pv.n * 3 * sizeof(float));
1110 memcpy(&rep_->normal[np*3],ss->nv.data,ss->nv.n * 3 * sizeof(float));
1111 if(USETXCOORD && tcoord) memcpy(&tcoord[np*2],ss->tv.data,ss->tv.n * 2 * sizeof(float));
1112 switch(ss->type){
1113 case GL_QUAD_STRIP:
1114 for(j=0;j<ss->pv.n -2;j+=2){
1115 rep_->cindex[ni++] = np+j;
1116 rep_->cindex[ni++] = np+j+1;
1117 rep_->cindex[ni++] = np+j+3;
1118 //rep->cindex[ni++] = -1;
1119 rep_->cindex[ni++] = np+j+3;
1120 rep_->cindex[ni++] = np+j+2;
1121 rep_->cindex[ni++] = np+j;
1122 //rep->cindex[ni++] = -1;
1123 //memcpy(&rep->norindex[ntri*4],&rep->cindex[ntri*4],2*4*sizeof(int));
1124 memcpy(&rep_->norindex[ntri*3],&rep_->cindex[ntri*3],2*3*sizeof(int));
1125 if(USETXCOORD) memcpy(&rep_->tcindex[ntri*3],&rep_->cindex[ntri*3],2*3*sizeof(int));
1126 ntri += 2;
1127 }
1128 break;
1129 case GL_TRIANGLE_STRIP:
1130 nindex += (ss->pv.n -2);
1131 break;
1132 case GL_TRIANGLE_FAN:
1133 //nindex += (ss.pv.n -2);
1134 for(j=0;j<ss->pv.n -2;j+=1){
1135 rep_->cindex[ni++] = np;
1136 rep_->cindex[ni++] = np+j+1;
1137 rep_->cindex[ni++] = np+j+2;
1138 memcpy(&rep_->norindex[ntri*3],&rep_->cindex[ntri*3],3*sizeof(int));
1139 if(USETXCOORD) memcpy(&rep_->tcindex[ntri*3],&rep_->cindex[ntri*3],3*sizeof(int));
1140 ntri += 1;
1141 }
1142 break;
1143 case GL_TRIANGLES:
1144 nindex += (ss->pv.n -2);
1145 break;
1146 default:
1147 nindex += (ss->pv.n -2);
1148 }
1149 np += ss->pv.n;
1150 }
1151 rep_->ntri = ntri;
1152 if(node->texCoord && node->texCoord->_nodeType == NODE_NurbsTextureCoordinate){
1153 static FILE *fp = NULL;
1154 for(i=0;i<np;i++){
1155 float stru[4];
1156 float xyz[4];
1157 //treat above callback texturecoord as uv,
1158 //and do lookup on NurbsTextureCoordinate surface to get new texture coord st
1159 xyz[0] = tcoord[i*2 + 1];
1160 xyz[1] = tcoord[i*2 + 0]; //don't know why but I have to swap xy to match octaga
1161 xyz[2] = 0.0f;
1162 xyz[3] = tcoord[i*2 + 3];
1163 getNurbsSurfacePoint(node->texCoord, xyz, stru);
1164 //memcpy(&tcoord[i*2],stru,2*sizeof(float));
1165 tcoord[i*2 + 0] = stru[0];
1166 tcoord[i*2 + 1] = stru[1];
1167 //if(1){
1168 // static int once = 0;
1169 // if(!once) fp= fopen("nurbstexturecoord.txt","w+");
1170 // once = 1;
1171 // fprintf(fp,"%d uv %f %f st %f %f\n",i,tcoord[i*2 +0],tcoord[i*2 + 1],stru[0],stru[1]);
1172 //}
1173 }
1174 //if(fp) fclose(fp);
1175 }
1176 tcnode->point.p = (struct SFVec2f*)tcoord;
1177 tcnode->point.n = np;
1178 if(0) for(i=0;i<tcnode->point.n;i++){
1179 printf("%d %f %f\n",i,tcnode->point.p[i].c[0],tcnode->point.p[i].c[1]);
1180 if(i % 50 == 0)
1181 printf("\n");
1182 }
1183
1184 //END virt_make_polyrep section <<<<<<
1185
1186 //FROM Compile_polyrep
1187 if (polyrep->ntri != 0) {
1188 //float *fogCoord = NULL;
1189 stream_polyrep(node, NULL,NULL,NULL,NULL, tcnode);
1190 /* and, tell the rendering process that this shape is now compiled */
1191 }
1192 FREE_IF_NZ(tcnode->point.p);
1193 //else wait for set_coordIndex to be converted to coordIndex
1194 //MARK POLYREP COMPILED
1195 polyrep->irep_change = node->_change;
1196
1197 /*
1198 // dump then can copy and paste to x3d or wrl IndexedFaceSet.coordIndex and Coordinate.point fields
1199 FILE * fp = fopen("IFS_DUMP.txt","w+");
1200 fprintf(fp,"#vertices %d\n",np);
1201 for(i=0;i<np;i++){
1202 fprintf(fp,"%f %f %f\n",rep->actualCoord[i*3 +0],rep->actualCoord[i*3 +1],rep->actualCoord[i*3 +2]);
1203 }
1204 fprintf(fp,"#face indices %d\n",ni);
1205 for(i=0;i<ni;i++){
1206 fprintf(fp,"%d ",rep->cindex[i]);
1207 if((ni+1) % 3 == 0)
1208 fprintf(fp,"%d ",-1);
1209 }
1210 fprintf(fp,"\n");
1211 fclose(fp);
1212 */
1213
1214}
1215
1216void compile_NurbsSurface(struct X3D_NurbsPatchSurface *node, struct Multi_Node *trim){
1217 MARK_NODE_COMPILED
1218
1219 {
1220 int i,j, n, nu, nv, nku, nkv;
1221 GLfloat *xyzw, *knotsu, *knotsv;
1222 ppComponent_NURBS p = (ppComponent_NURBS)gglobal()->Component_NURBS.prv;
1223
1224 nku = nkv = nu = nv = n = 0;
1225 xyzw = knotsu = knotsv = NULL;
1226 // I should call something like:
1227 // struct Multi_Vec3f *getCoordinate (struct X3D_Node *innode, char *str);
1228 // to get the control points - it will do proto expansion, compile the coordinate node if needed
1229 // (should do something similar with texcoord when implemented,
1230 // as I think it needs conversion from controlpoint spacing to sampling/tesselation spacing for use in polyrep)
1231 // here's an amature shortcut that returns doubles
1232 if(node->controlPoint){
1233 if(node->controlPoint->_nodeType == NODE_CoordinateDouble){
1234 struct Multi_Vec3d *mfd;
1235 mfd = &((struct X3D_CoordinateDouble *)(node->controlPoint))->point;
1236 n = mfd->n;
1237 xyzw = MALLOC(void *, n * 4 * sizeof(GLfloat));
1238 for(i=0;i<mfd->n;i++){
1239 for(j=0;j<3;j++){
1240 xyzw[i*4 + j] = (float)mfd->p[i].c[j];
1241 }
1242 }
1243 }else if(node->controlPoint->_nodeType == NODE_Coordinate){
1244 struct Multi_Vec3f *mff;
1245 mff = &((struct X3D_Coordinate *)(node->controlPoint))->point;
1246 n = mff->n;
1247 xyzw = MALLOC(void *, n * 4 * sizeof(GLfloat));
1248 for(i=0;i<mff->n;i++){
1249 for(j=0;j<3;j++){
1250 xyzw[i*4 + j] = mff->p[i].c[j];
1251 }
1252 }
1253 }
1254 }else{
1255 n = 0;
1256 }
1257 if(node->weight.n && node->weight.n == n){
1258 double w;
1259 int m,im;
1260 m = min(node->weight.n, n);
1261 for(i=0;i<n;i++){
1262 im = i < m ? i : m-1;
1263 w = node->weight.p[im];
1264 xyzw[i*4 + 3] = (float)w;
1265 }
1266 }else{
1267 for(i=0;i<n;i++) xyzw[i*4 + 3] = 1.0;
1268 }
1269 nu = node->uDimension;
1270 nv = node->vDimension;
1271 //int knotsOK(int order, int ncontrol, int nknots, double *knots)
1272 //if(node->uKnot.n && node->uKnot.n == nu + node->uOrder ){
1273 if(knotsOK(node->uOrder,nu,node->uKnot.n,node->uKnot.p)){
1274 //could do another check: max number of consecutive equal value knots == order
1275 //could do another check: knot values == or ascending
1276 nku = node->uKnot.n;
1277 knotsu = MALLOC(void *, nku * sizeof(GLfloat));
1278 for(i=0;i<nku;i++){
1279 knotsu[i] = (GLfloat)node->uKnot.p[i];
1280 }
1281 if(DEBG){
1282 int ii;
1283 printf("good u knot vector nk=%d\n",nku);
1284 for(ii=0;ii<nku;ii++)
1285 printf("[%d]=%f \n",ii,knotsu[ii]);
1286 }
1287
1288 }else{
1289 //generate uniform knot vector
1290 static int once = 0;
1291 nku = nu + node->uOrder ;
1292 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
1293 knotsu = MALLOC(void *, nku *sizeof(GLfloat));
1294 generateUniformKnotVector(node->uOrder,nu, knotsu);
1295 if(!once){
1296 int ii;
1297 printf("bad u knot vector given, replacing with:\n");
1298 for(ii=0;ii<nku;ii++)
1299 printf("[%d]=%f \n",ii,knotsu[ii]);
1300 once = 1;
1301 }
1302 //nk = 0;
1303 }
1304
1305 if(knotsOK(node->vOrder,nv,node->vKnot.n,node->vKnot.p)){
1306 //if(node->vKnot.n && node->vKnot.n == nv + node->vOrder ){
1307 nkv = node->vKnot.n;
1308 knotsv = MALLOC(void *, nkv * sizeof(GLfloat));
1309 for(i=0;i<nkv;i++){
1310 knotsv[i] = (GLfloat)node->vKnot.p[i];
1311 }
1312 if(DEBG){
1313 int ii;
1314 printf("good v knot vector nk=%d\n",nkv);
1315 for(ii=0;ii<nkv;ii++)
1316 printf("[%d]=%f \n",ii,knotsv[ii]);
1317 }
1318
1319 }else{
1320 static int once = 0;
1321 //generate uniform knot vector
1322 nkv = nv + node->vOrder ;
1323 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
1324 knotsv = MALLOC(void *, nkv *sizeof(GLfloat));
1325 generateUniformKnotVector(node->vOrder,nv, knotsv);
1326 if(!once){
1327 int ii;
1328 printf("bad v knot vector given, replacing with:\n");
1329 for(ii=0;ii<nkv;ii++)
1330 printf("[%d]=%f \n",ii,knotsv[ii]);
1331 once = 1;
1332 }
1333 //nk = 0;
1334 }
1335
1336 if(n && nku && nkv){
1337 static GLUnurbsObj *theNurb = NULL;
1338 int ntessu, ntessv, mtessu, mtessv;
1339 struct Vector * strips;
1340 struct X3D_Node * texCoordNode;
1341 int texcoordnodeIsGenerated;
1342
1343 mtessu = node->uOrder + 1;
1344 ntessu = node->uTessellation;
1345 mtessv = node->vOrder + 1;
1346 ntessv = node->vTessellation;
1347
1348 if(DEBG) printf("gluNewNurbsRenderer\n");
1349 if(!theNurb)
1350 theNurb = gluNewNurbsRenderer();
1351 gluNurbsProperty(theNurb, GLU_NURBS_MODE, GLU_NURBS_TESSELLATOR);
1352 if(0){
1353 //chord length or automatic - not implemented properly nor tested thoroughly
1354 //if you do chord length in pixels, you need to manually pass in sampling matrices
1355 //and somehow you need to trigger a recompile: another call to this compile_
1356 // as avatar/viewer moves closer (father) from the nurbs node
1357 double model[16], proj[16];
1358 float modelf[16], projf[16];
1359 int viewPort[10];
1360 if(ntessu > 0)
1361 mtessu = ntessu;
1362 else if(ntessu < 0)
1363 mtessu = -ntessu;
1364
1365 gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, (float)(mtessu)); //25.0);
1366 if(ntessu < 0)
1367 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_PATH_LENGTH); //pixels, the default
1368 else
1369 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_PARAMETRIC_TOLERANCE);
1370 gluNurbsProperty(theNurb, GLU_AUTO_LOAD_MATRIX,GL_FALSE);
1371
1372 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, model);
1373 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
1374 FW_GL_GETINTEGERV(GL_VIEWPORT, viewPort);
1375 for(i=0;i<16;i++){
1376 modelf[i] = (float)model[i];
1377 projf[i] = (float)proj[i];
1378 }
1379 gluLoadSamplingMatrices(theNurb,modelf,projf,viewPort);
1380 }
1381 if(1){
1382 //uniform spacing of sampling points in u (or uv) parameter space - works
1383 //node must specify tesselation value. see specs for interpretation
1384 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/nurbs.html#NurbsCurve
1385 if(ntessu > 0)
1386 mtessu = max(mtessu,ntessu+1);
1387 else if(ntessu < 0)
1388 mtessu = max(mtessu,(-ntessu * nu) + 1);
1389 else
1390 mtessu = max(mtessu,2*nu + 1);
1391
1392 if(ntessv > 0)
1393 mtessv = max(mtessv,ntessv+1);
1394 else if(ntessv < 0)
1395 mtessv = max(mtessv,(-ntessv * nv) + 1);
1396 else
1397 mtessv = max(mtessv,2*nv + 1);
1398 mtessu = (int)((float)mtessu * node->_tscale);
1399 mtessv = (int)((float)mtessv * node->_tscale);
1400
1401 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_DOMAIN_DISTANCE);
1402 gluNurbsProperty(theNurb,GLU_U_STEP,(GLfloat)mtessu);
1403 gluNurbsProperty(theNurb,GLU_V_STEP,(GLfloat)mtessv);
1404 }
1405 gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
1406
1407 gluNurbsCallback(theNurb, GLU_ERROR, nurbsError);
1408 gluNurbsCallback(theNurb, GLU_NURBS_BEGIN_DATA, nurbssurfBegincb);
1409 gluNurbsCallback(theNurb, GLU_NURBS_VERTEX_DATA, nurbssurfVertexcb);
1410 gluNurbsCallback(theNurb, GLU_NURBS_NORMAL_DATA, nurbssurfNormalcb);
1411 gluNurbsCallback(theNurb, GLU_NURBS_END_DATA, nurbssurfEndcb);
1412 gluNurbsCallback(theNurb, GLU_NURBS_TEXTURE_COORD_DATA, nurbssurfTexcoordcb);
1413
1414 strips = newVector(struct stripState,20);
1415 gluNurbsCallbackData(theNurb,(GLvoid*)strips);
1416
1417 if(DEBG) printf("gluBeginSurface \n");
1418 gluBeginSurface(theNurb);
1419 gluNurbsSurface(theNurb,nku,knotsu,nkv,knotsv,4,4*nu,xyzw,node->uOrder,node->vOrder,GL_MAP2_VERTEX_4);
1420 /*
1421 TextureCoordinate handling
1422 https://www.opengl.org/discussion_boards/showthread.php/127668-Texture-mapping-for-NURBS
1423 https://www.cs.drexel.edu/~david/Classes/ICG/Lectures/Lecture7.pdf p.56 of slides
1424
1425 texture coordinate hypotheses:
1426 1. if regular texture coordinate node supplied,
1427 - H1a: use same order and knot vector as control, or
1428 - H1b: use linear order=2 and knot vector
1429 - specify the texturecoordinate points as control
1430 2. if no texture coordinate node node supplied,
1431 H2a:
1432 - compute defaults using relative spatial distance between xyz control
1433 along u (row) and v (column) directions
1434 - apply #1
1435 H2b:
1436 - compute defaults using equal spacing
1437 along u (row) and v (column) directions
1438 - apply #1
1439 H2c:
1440 - leave texcoords blank and let stream_polyrep supply defaults
1441 3. if nurbstexturecoordinate node supplied,
1442 H3a:
1443 - set texture surface control to 0 0 1 1
1444 - use linear order 2
1445 H3b:
1446 - do H2a or H2b
1447 Both:
1448 - interpret the texturecallback points as uv
1449 - use uv to lookup st using piegl surface interpolator
1450 on separate surface in nurbstexturecoordinate node
1451 options: a) in texture callback b) when converting to polyrep
1452 */
1453 texcoordnodeIsGenerated = FALSE; //for possible garbage collection
1454 texCoordNode = node->texCoord;
1455 if(!texCoordNode){
1456 //2 no texcoord node supplied
1457 switch('b'){
1458 case 'a':
1459 //H2a compute uniform defaults using relative spatial distance of xyz in u and v
1460 break;
1461 case 'b':
1462 // H2b: - compute defaults using equal spacing
1463 {
1464 float du, dv, uu, vv;
1465 int jj,j,k;
1466 struct X3D_TextureCoordinate *texCoord = createNewX3DNode0(NODE_TextureCoordinate);
1467 texcoordnodeIsGenerated = TRUE;
1468 texCoord->point.p = MALLOC(struct SFVec2f*,nu * nv * sizeof(struct SFVec2f));
1469 du = 1.0f / (float)max(1,(nu -1));
1470 dv = 1.0f / (float)max(1,(nv -1));
1471 vv = 0.0f;
1472 jj = 0;
1473 for(k=0;k<nv;k++){
1474 if(k == nv-1) vv = 1.0f; //they like end exact on 1.0f
1475 uu = 0.0f;
1476 for(j=0;j<nu;j++){
1477 if(j == nu-1) uu = 1.0f; //they like end exact on 1.0f
1478 texCoord->point.p[jj].c[0] = uu;
1479 texCoord->point.p[jj].c[1] = vv;
1480 uu += du;
1481 jj++;
1482 }
1483 vv += dv;
1484 }
1485 texCoord->point.n = jj;
1486 texCoordNode = X3D_NODE(texCoord);
1487 }
1488 break;
1489 default:
1490 //H2c skip - nada
1491 break;
1492 }
1493 }
1494 if(texCoordNode){
1495 //USETEXCOORD = TRUE
1496 if(texCoordNode->_nodeType == NODE_TextureCoordinate){
1497 //TEXCOORDTYPE = 1 //interpret nurbsurftexcoordcb coords as texture coords
1498 struct X3D_TextureCoordinate *texCoord = (struct X3D_TextureCoordinate *)texCoordNode;
1499 float *control2D = (float*)texCoord->point.p;
1500 int nctrl = texCoord->point.n;
1501 if(1){
1502 //H1a: use same order and knot vector as controlPoints
1503 // except using texcoord.point as nurbscontrol
1504 //CONFIRMED when using H2b 'b' above to generate missing TexCoord node
1505 gluNurbsSurface(theNurb,nku,knotsu,nkv,knotsv,2,2*nu,control2D,node->uOrder,node->vOrder,GL_MAP2_TEXTURE_COORD_2);
1506 }else{
1507 //H1b: use linear order=2 and knot vectors, order from main surface
1508 //DISCONFIRMED: the texturecoord callback is never called
1509 float *tknotsu, *tknotsv;
1510 int k;
1511
1512 tknotsu = MALLOC(float *, (nu+2) *sizeof(GLfloat));
1513 tknotsv = MALLOC(float *, (nv+2) *sizeof(GLfloat));
1514 generateUniformKnotVector(2,nu,tknotsu);
1515 generateUniformKnotVector(2,nv,tknotsv);
1516 printf("tknotsu = [");
1517 for(k=0;k<nu+2;k++) printf("%f ",tknotsu[k]);
1518 printf("]\ntknotsv = [");
1519 for(k=0;k<nv+2;k++) printf("%f ",tknotsv[k]);
1520 printf("]\n");
1521 gluNurbsSurface(theNurb,nu+2,knotsu,nv+2,knotsv,4,4*nu,control2D,2,2,GL_MAP2_TEXTURE_COORD_2);
1522 }
1523 } else if(texCoordNode->_nodeType == NODE_NurbsTextureCoordinate){
1524 //TEXCOORDTYPE = 2 /interpret nurbsurftexcoordcb coords as uv coords,
1525 // use to lookup st via piegl interpolation of NurbsTextureCoordinate nurbs surface
1526 if(0){
1527 //H3a:
1528 //- set texture surface control to 0 0 1 1
1529 //- use linear order 2
1530 float tknots[4] = {0.0f, 0.0f, 1.0f, 1.0f};
1531 float unit_control2D [8] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
1532 struct X3D_NurbsTextureCoordinate *texCoord = (struct X3D_NurbsTextureCoordinate *)texCoordNode;
1533 gluNurbsSurface(theNurb,4,tknots,4,tknots,2,2*2,unit_control2D,2,2,GL_MAP2_TEXTURE_COORD_2);
1534 }else{
1535 //H3b same as H2a or H2b
1536 // H2b: - compute defaults using equal spacing
1537 {
1538 float du, dv, uu, vv;
1539 int jj,j,k;
1540 float *control2D;
1541 struct X3D_TextureCoordinate *texCoord = createNewX3DNode0(NODE_TextureCoordinate);
1542 texcoordnodeIsGenerated = TRUE;
1543 FREE_IF_NZ(texCoord->point.p);
1544 texCoord->point.p = MALLOC(struct SFVec2f*,nu * nv * sizeof(struct SFVec2f));
1545 du = 1.0f / (float)max(1,(nu -1));
1546 dv = 1.0f / (float)max(1,(nv -1));
1547 vv = 0.0f;
1548 jj = 0;
1549 for(k=0;k<nv;k++){
1550 if(k == nv-1) vv = 1.0f; //they like end exact on 1.0f
1551 uu = 0.0f;
1552 for(j=0;j<nu;j++){
1553 if(j == nu-1) uu = 1.0f; //they like end exact on 1.0f
1554 texCoord->point.p[jj].c[0] = uu;
1555 texCoord->point.p[jj].c[1] = vv;
1556 uu += du;
1557 jj++;
1558 }
1559 vv += dv;
1560 }
1561 texCoord->point.n = jj;
1562 texCoordNode = X3D_NODE(texCoord);
1563 //H1a: use same order and knot vector as controlPoints
1564 // except using texcoord.point as nurbscontrol
1565 //CONFIRMED when using H2b 'b' above to generate missing TexCoord node
1566 control2D = (float*)texCoord->point.p;
1567 gluNurbsSurface(theNurb,nku,knotsu,nkv,knotsv,2,2*nu,control2D,node->uOrder,node->vOrder,GL_MAP2_TEXTURE_COORD_2);
1568
1569 }
1570
1571 }
1572
1573 }
1574 }
1575 if(trim){
1576 int i;
1577
1578 if(0){
1579 if(DEBG) printf("gluBeginTrim \n");
1580 gluBeginTrim (theNurb);
1581 //outside border H: scene author is responsible
1582 if(1){
1583 // counter clockwise, simple 4 corner uv from redbook sample
1584 GLfloat edgePt[5][2] = {{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0}};
1585 if(DEBG) printf("gluPwlCurve 0\n");
1586 gluPwlCurve (theNurb, 5, &edgePt[0][0], 2, GLU_MAP1_TRIM_2);
1587 }else{
1588 // 2 x (node.utessselation u + node.vtesselation v) + 1 edge values
1589 // except I get a nurbs error with the following
1590 GLfloat *edges = MALLOC(void *, (2 * ntessu + 2 * ntessv) *2*sizeof(GLfloat));
1591 GLfloat uspan, vspan;
1592 uspan = 1.0f/(float)(ntessu -1);
1593 vspan = 1.0f/(float)(ntessv -1);
1594 for(i=0;i<ntessu-1;i++){
1595 edges[i*2 +0] = (float)(i)*uspan;
1596 edges[i*2 +1] = 0.0;
1597 edges[(ntessu+ntessv+i)*2 + 0] = (float)(ntessu - 1 - i)*uspan;
1598 edges[(ntessu+ntessv+i)*2 + 1] = 1.0;
1599 }
1600 for(i=0;i<ntessv;i++){
1601 edges[(ntessu+i)*2 + 0] = 1.0;
1602 edges[(ntessu+i)*2 + 1] = (float)(i)*vspan;
1603 edges[(ntessu+ntessv+ntessu+i)*2 + 0] = 0.0;
1604 edges[(ntessu+ntessv+ntessu+i)*2 + 1] = (float)(ntessv - 1 - i)*vspan;
1605 }
1606 //close curve
1607 edges[((ntessu -1)*2 + (ntessv -1)*2)*2 + 0] = 0.0;
1608 edges[((ntessu -1)*2 + (ntessv -1)*2)*2 + 1] = 0.0;
1609 if(DEBG) printf("gluPwlCurve 1\n");
1610 gluPwlCurve (theNurb, 2*(ntessu -1 + ntessv -1) +1, edges, 2, GLU_MAP1_TRIM_2);
1611 }
1612 if(DEBG) printf("gluEndTrim\n");
1613 gluEndTrim (theNurb);
1614 }
1615
1616 //interior cutouts
1617 if(0){
1618 //redbook example trim curves - these work
1619 GLfloat curvePt[4][2] = /* clockwise */
1620 {{0.25, 0.5}, {0.25, 0.75}, {0.75, 0.75}, {0.75, 0.5}};
1621 GLfloat curveKnots[8] =
1622 {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
1623 GLfloat pwlPt[4][2] = /* clockwise */
1624 {{0.75, 0.5}, {0.5, 0.25}, {0.25, 0.5}};
1625
1626 if(DEBG) printf("gluBeginTrim A\n");
1627 gluBeginTrim (theNurb);
1628 if(DEBG) printf("gluNurbsCurve A\n");
1629 gluNurbsCurve (theNurb, 8, curveKnots, 2,
1630 &curvePt[0][0], 4, GLU_MAP1_TRIM_2);
1631 if(DEBG) printf("gluPwlCurve A\n");
1632 gluPwlCurve (theNurb, 3, &pwlPt[0][0], 2, GLU_MAP1_TRIM_2);
1633 if(DEBG) printf("gluEndTrim A\n");
1634 gluEndTrim (theNurb);
1635 }
1636 if(1)
1637 for(i=0;i<trim->n;i++){
1638 int m;
1639 struct X3D_Contour2D * tc = (struct X3D_Contour2D *)trim->p[i];
1640 if(DEBG) printf("gluBeginTrim B\n");
1641 gluBeginTrim (theNurb);
1642 for(m=0;m<tc->children.n;m++)
1643 {
1644 int j,k,nk,dim;
1645 struct X3D_ContourPolyline2D *cp2d;
1646 struct X3D_NurbsCurve2D *nc2d;
1647 struct X3D_Node *ctr = tc->children.p[m]; //trim->p[i];
1648 GLfloat *cknot, *ctrl, *cweight;
1649 cknot = ctrl = cweight = NULL;
1650 switch(ctr->_nodeType){
1651 case NODE_ContourPolyline2D:
1652 cp2d = (struct X3D_ContourPolyline2D *)ctr;
1653 ctrl = MALLOC(void *, cp2d->controlPoint.n * 2*sizeof(GLfloat));
1654 for(j=0;j<cp2d->controlPoint.n;j++) {
1655 for(k=0;k<2;k++)
1656 ctrl[j*2 + k] = (float)cp2d->controlPoint.p[j].c[k];
1657 }
1658 if(DEBG) printf("gluPwlCurve B\n");
1659 gluPwlCurve (theNurb, cp2d->controlPoint.n, ctrl, 2, GLU_MAP1_TRIM_2);
1660 FREE_IF_NZ(ctrl);
1661 break;
1662 case NODE_NurbsCurve2D:
1663 nc2d = (struct X3D_NurbsCurve2D *)ctr;
1664 dim = 2;
1665 nk = nc2d->controlPoint.n + nc2d->order;
1666 if(nk == nc2d->knot.n)
1667
1668 cknot = MALLOC(void *, nk * sizeof(GLfloat));
1669 if(nc2d->weight.n){ // == 3){
1670 dim = 3;
1671 cweight = MALLOC(void *, nc2d->controlPoint.n * sizeof(GLfloat));
1672 if(nc2d->weight.n == nc2d->controlPoint.n){
1673 for(j=0;j<nc2d->weight.n;j++) cweight[j] = (float)nc2d->weight.p[j];
1674 }else{
1675 for(j=0;j<nc2d->controlPoint.n;j++) cweight[j] = 1.0f;
1676 }
1677 }
1678 ctrl = MALLOC(void *, nc2d->controlPoint.n * dim*sizeof(GLfloat));
1679 for(j=0;j<nc2d->controlPoint.n;j++) {
1680 for(k=0;k<2;k++){
1681 ctrl[j*dim + k] = (float)nc2d->controlPoint.p[j].c[k];
1682 if(dim == 3) ctrl[j*dim + k] *= cweight[j];
1683 }
1684 if(dim == 3) ctrl[j*dim + dim-1] = (float)cweight[j];
1685 }
1686 if(knotsOK(nc2d->order,nc2d->controlPoint.n,nc2d->knot.n,nc2d->knot.p)){
1687 //if(nk == nc2d->knot.n){
1688 for(j=0;j<nc2d->knot.n;j++)
1689 cknot[j] = (float)nc2d->knot.p[j];
1690 }else{
1691 generateUniformKnotVector(nc2d->order,nc2d->controlPoint.n,cknot);
1692 printf("replacing nurbscurve2D knotvector with:\n");
1693 for(j=0;j<nk;j++){
1694 printf("%f ",cknot[j]);
1695 }
1696 printf("\n");
1697
1698 }
1699 if(DEBGC) {
1700 printf("knot %d ={",nc2d->knot.n);
1701 for(j=0;j<nc2d->knot.n;j++){
1702 printf("%f ",cknot[j]);
1703 }
1704 printf("}\n");
1705 printf("control %d = {\n",nc2d->controlPoint.n);
1706 for(j=0;j<nc2d->controlPoint.n;j++) {
1707 for(k=0;k<dim;k++) printf("%f \n",ctrl[j*dim +k]);
1708 printf("\n");
1709 }
1710 printf("}\n");
1711 }
1712 if(DEBG) printf("gluNurbsCurve B\n");
1713 if(1){
1714 int mtess, ntess;
1715 mtess = nc2d->order + 1;
1716 ntess = nc2d->tessellation;
1717 if(0){
1718 //chord length or automatic - not implemented properly nor tested thoroughly
1719 //if you do chord length in pixels, you need to manually pass in sampling matrices
1720 //and somehow you need to trigger a recompile: another call to this compile_
1721 // as avatar/viewer moves closer (father) from the nurbs node
1722 double model[16], proj[16];
1723 float modelf[16], projf[16];
1724 int viewPort[10];
1725 if(ntess > 0)
1726 mtess = ntess;
1727 else if(ntess < 0)
1728 mtess = -ntess;
1729
1730 gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, (float)(mtess)); //25.0);
1731 if(ntess < 0)
1732 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_PATH_LENGTH); //pixels, the default
1733 else
1734 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_PARAMETRIC_TOLERANCE);
1735 gluNurbsProperty(theNurb, GLU_AUTO_LOAD_MATRIX,GL_FALSE);
1736
1737 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, model);
1738 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
1739 FW_GL_GETINTEGERV(GL_VIEWPORT, viewPort);
1740 for(i=0;i<16;i++){
1741 modelf[i] = (float)model[i];
1742 projf[i] = (float)proj[i];
1743 }
1744 gluLoadSamplingMatrices(theNurb,modelf,projf,viewPort);
1745 }
1746 if(1){
1747 //uniform spacing of sampling points in u (or uv) parameter space - works
1748 //node must specify tesselation value. see specs for interpretation
1749 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/nurbs.html#NurbsCurve
1750 if(ntess > 0)
1751 mtess = max(mtess,ntess+1);
1752 else if(ntess < 0)
1753 mtess = max(mtess,(-ntess * n) + 1);
1754 else
1755 mtess = max(mtess,2*n + 1);
1756 gluNurbsProperty(theNurb,GLU_SAMPLING_METHOD,GLU_DOMAIN_DISTANCE);
1757 gluNurbsProperty(theNurb,GLU_U_STEP,(GLfloat)mtess);
1758 }
1759 }
1760 gluNurbsCurve (theNurb, nk, cknot, dim, ctrl, nc2d->order, GLU_MAP1_TRIM_2);
1761 break;
1762 default:
1763 ConsoleMessage("%s %d","unknown trimming contour node",ctr->_nodeType);
1764 }
1765 FREE_IF_NZ(ctrl);
1766 FREE_IF_NZ(cknot);
1767 FREE_IF_NZ(cweight);
1768 }
1769 if(DEBG) printf("gluEndTrim B\n");
1770 gluEndTrim (theNurb);
1771 }
1772 }
1773 if(DEBG) printf("gluEndSurface \n");
1774 gluEndSurface(theNurb);
1775 if(DEBG) printf("gluDeleteNurbsRenderer \n");
1776 if(0) gluDeleteNurbsRenderer(theNurb);
1777
1778 //convert points to polyrep
1779 convert_strips_to_polyrep(strips,(struct X3D_NurbsTrimmedSurface*)node);
1780
1781 if(texcoordnodeIsGenerated){
1782 struct X3D_TextureCoordinate *texCoord = (struct X3D_TextureCoordinate *)texCoordNode;
1783 FREE_IF_NZ(texCoord->point.p);
1784 FREE_IF_NZ(texCoordNode);
1785 }
1786 //vector_releaseData(,strips);
1787 if(strips){
1788 for(i=0;i<vectorSize(strips);i++){
1789 struct stripState *ss = vector_get_ptr(struct stripState,strips,i);
1790 FREE_IF_NZ(ss->pv.data); ss->pv.allocn = 0; ss->pv.n = 0;
1791 FREE_IF_NZ(ss->nv.data); ss->nv.allocn = 0; ss->nv.n = 0;
1792 FREE_IF_NZ(ss->tv.data); ss->tv.allocn = 0; ss->tv.n = 0;
1793 }
1794 FREE_IF_NZ(strips->data); strips->allocn = 0; strips->n = 0;
1795 FREE_IF_NZ(strips);
1796 }
1797 FREE_IF_NZ(xyzw);
1798 }
1799 FREE_IF_NZ(knotsv);
1800 FREE_IF_NZ(knotsu);
1801 }
1802
1803}
1804
1805void render_ray_polyrep(void *node);
1806void render_polyrep(void *node);
1807
1808void compile_NurbsPatchSurface(struct X3D_NurbsPatchSurface *node){
1809 MARK_NODE_COMPILED
1810 compile_NurbsSurface(node, NULL);
1811}
1812void rendray_NurbsPatchSurface (struct X3D_NurbsPatchSurface *node) {
1813 COMPILE_IF_REQUIRED
1814 if (!node->_intern) return;
1815 render_ray_polyrep(node);
1816}
1817
1818void collide_NurbsPatchSurface (struct X3D_NurbsPatchSurface *node) {
1819 COMPILE_IF_REQUIRED
1820 if (!node->_intern) return;
1821 collide_genericfaceset(X3D_INDEXEDFACESET(node));
1822}
1823
1824void render_NurbsPatchSurface (struct X3D_NurbsPatchSurface *node) {
1825 COMPILE_IF_REQUIRED
1826 if (!node->_intern) return;
1827 CULL_FACE(node->solid)
1828 render_polyrep(node);
1829}
1830
1831void compile_NurbsTrimmedSurface(struct X3D_NurbsTrimmedSurface *node){
1832 MARK_NODE_COMPILED
1833 compile_NurbsSurface((struct X3D_NurbsPatchSurface *)node, &node->trimmingContour);
1834}
1835
1836void rendray_NurbsTrimmedSurface (struct X3D_NurbsTrimmedSurface *node) {
1837 COMPILE_IF_REQUIRED
1838 if (!node->_intern) return;
1839 render_ray_polyrep(node);
1840}
1841
1842void collide_NurbsTrimmedSurface (struct X3D_NurbsTrimmedSurface *node) {
1843 COMPILE_IF_REQUIRED
1844 if (!node->_intern) return;
1845 collide_genericfaceset(X3D_INDEXEDFACESET(node));
1846}
1847
1848void render_NurbsTrimmedSurface (struct X3D_NurbsTrimmedSurface *node) {
1849 COMPILE_IF_REQUIRED
1850 if (!node->_intern) return;
1851 CULL_FACE(node->solid)
1852 render_polyrep(node);
1853}
1854
1855void do_NurbsPositionInterpolator (void *node) {
1857 struct X3D_Coordinate *control;
1858 float fraction; //knotrange[2],
1859 double *weight;
1860 float cw[4]; //*xyzw,
1861
1862 if (!node) return;
1863 px = (struct X3D_NurbsPositionInterpolator *) PPX(node);
1864 if(NNC(px)){
1865 float *knots;
1866 int i,nk, n;
1867
1868 MNC(px);
1869 if(!px->_OK == TRUE){
1870 px->_OK = FALSE;
1871 if(!(px->knot.n > 1))
1872 return;
1873 if(!px->controlPoint )
1874 return;
1875 if(px->controlPoint->_nodeType != NODE_Coordinate)
1876 return;
1877 control = (struct X3D_Coordinate *) px->controlPoint;
1878 if(control->point.n < 2)
1879 return;
1880 n = control->point.n;
1881 weight = NULL;
1882 if(px->weight.n == n)
1883 weight = px->weight.p;
1884 px->_xyzw.p = MALLOC(struct SFVec4f*,control->point.n * sizeof(struct SFVec4f));
1885 px->_xyzw.n = n;
1886 for(i=0;i<control->point.n;i++){
1887 float xyzw[4], wt;
1888 wt = weight ? (float)weight[i] : 1.0f;
1889 veccopy3f(xyzw,control->point.p[i].c);
1890 vecscale3f(xyzw,xyzw,wt);
1891 xyzw[3] = wt;
1892 veccopy4f(px->_xyzw.p[i].c,xyzw);
1893 }
1894 if(knotsOK(px->order,px->_xyzw.n,px->knot.n,px->knot.p)){
1895
1896 nk = px->knot.n;
1897 knots = MALLOC(void *, nk * sizeof(GLfloat));
1898 for(i=0;i<nk;i++){
1899 knots[i] = (GLfloat)px->knot.p[i];
1900 }
1901 //printf("good knot nk=%d\n",nk);
1902 //for(int ii=0;ii<nk;ii++)
1903 // printf("[%d]=%f \n",ii,knots[ii]);
1904
1905 }else{
1906 static int once = 0;
1907 //generate uniform knot vector
1908 nk = n + px->order ;
1909 //caller: please malloc knots = malloc( (ncontrol + order ) * sizeof(float))
1910 knots = MALLOC(void *, nk *sizeof(GLfloat));
1911 generateUniformKnotVector(px->order,n, knots);
1912 if(!once){
1913 int ii;
1914 printf("bad knot vector, replacing with:\n");
1915 for(ii=0;ii<nk;ii++)
1916 printf("[%d]=%f \n",ii,knots[ii]);
1917 once = 1;
1918 }
1919 //nk = 0;
1920 }
1921 px->_knot.p = knots;
1922 px->_knot.n = nk;
1923 px->_knotrange.c[0] = px->_knot.p[0];
1924 px->_knotrange.c[1] = px->_knot.p[px->_knot.n-1];
1925
1926 px->_OK = TRUE;
1927 }
1928 }
1929 if(!px->_OK)
1930 return;
1931
1932 fraction = max(px->_knotrange.c[0],px->set_fraction);
1933 fraction = min(px->_knotrange.c[1],px->set_fraction);
1934 CurvePoint(px->_xyzw.n, px->order-1, px->_knot.p, (float*)px->_xyzw.p, fraction, cw );
1935 veccopy3f(px->value_changed.c,cw);
1936 MARK_EVENT (node, offsetof (struct X3D_NurbsPositionInterpolator, value_changed));
1937
1938 #ifdef SEVERBOSE
1939 printf("do_PositionInt: Position/Vec3f interp, node %u kin %d kvin %d set_fraction %f\n",
1940 node, kin, kvin, px->set_fraction);
1941 #endif
1942
1943
1944
1945}
1946
1947/* NurbsOrientationInterpolator
1948 Called during the "events_processed" section of the event loop,
1949 so this is called ONLY when there is something required to do, thus
1950 there is no need to look at whether it is active or not
1951 */
1952void do_NurbsOrientationInterpolator (void *node) {
1954 struct X3D_Coordinate *control;
1955 float fraction; //knotrange[2],
1956 double *weight;
1957 //float *xyzw; //, cw[4];
1958
1959 if (!node) return;
1960 px = (struct X3D_NurbsOrientationInterpolator *) PPX(node);
1961 if(NNC(px)){
1962 float *knots;
1963 int i,nk, n;
1964
1965 MNC(px);
1966 if(!px->_OK == TRUE){
1967 px->_OK = FALSE;
1968 if(!(px->knot.n > 1))
1969 return;
1970 if(!px->controlPoint )
1971 return;
1972 if(px->controlPoint->_nodeType != NODE_Coordinate)
1973 return;
1974 control = (struct X3D_Coordinate *) px->controlPoint;
1975 if(control->point.n < 2)
1976 return;
1977 n = control->point.n;
1978 weight = NULL;
1979 if(px->weight.n == n)
1980 weight = px->weight.p;
1981 px->_xyzw.p = MALLOC(struct SFVec4f*,control->point.n * sizeof(struct SFVec4f));
1982 px->_xyzw.n = n;
1983 for(i=0;i<control->point.n;i++){
1984 float xyzw[4], wt;
1985 wt = weight ? (float)weight[i] : 1.0f;
1986 veccopy3f(xyzw,control->point.p[i].c);
1987 vecscale3f(xyzw,xyzw,wt);
1988 xyzw[3] = wt;
1989 veccopy4f(px->_xyzw.p[i].c,xyzw);
1990 }
1991 if(knotsOK(px->order,px->_xyzw.n,px->knot.n,px->knot.p)){
1992
1993 nk = px->knot.n;
1994 knots = MALLOC(void *, nk * sizeof(GLfloat));
1995 for(i=0;i<nk;i++){
1996 knots[i] = (GLfloat)px->knot.p[i];
1997 }
1998 //printf("good knot nk=%d\n",nk);
1999 //for(int ii=0;ii<nk;ii++)
2000 // printf("[%d]=%f \n",ii,knots[ii]);
2001
2002 }else{
2003 static int once = 0;
2004 //generate uniform knot vector
2005 nk = n + px->order ;
2006 //caller: please malloc knots = malloc( (ncontrol + order ) * sizeof(float))
2007 knots = MALLOC(void *, nk *sizeof(GLfloat));
2008 generateUniformKnotVector(px->order,n, knots);
2009 if(!once){
2010 int ii;
2011 printf("bad knot vector, replacing with:\n");
2012 for(ii=0;ii<nk;ii++)
2013 printf("[%d]=%f \n",ii,knots[ii]);
2014 once = 1;
2015 }
2016 //nk = 0;
2017 }
2018 px->_knot.p = knots;
2019 px->_knot.n = nk;
2020 px->_knotrange.c[0] = px->_knot.p[0];
2021 px->_knotrange.c[1] = px->_knot.p[px->_knot.n-1];
2022
2023 px->_OK = TRUE;
2024 }
2025 }
2026 if(!px->_OK)
2027 return;
2028
2029 fraction = max(px->_knotrange.c[0],px->set_fraction);
2030 fraction = min(px->_knotrange.c[1],px->set_fraction);
2031 if(1){
2032 //DELTA METHOD: instead of using a piegl formula for curve derivitive,
2033 //we sample 2 points near the u of interest, and take the difference
2034 //to get a slope vector
2035 float f1, f2, cw1[4], cw2[4], dir[3], rot[4];
2036
2037
2038 f1 = fraction;
2039 f2 = fraction + .01f;
2040 if(f2 > 1.0f){
2041 f1 = fraction - .01f;
2042 f2 = fraction;
2043 }
2044
2045 CurvePoint(px->_xyzw.n, px->order-1, px->_knot.p, (float*)px->_xyzw.p, f1, cw1 );
2046 CurvePoint(px->_xyzw.n, px->order-1, px->_knot.p, (float*)px->_xyzw.p, f2, cw2 );
2047 vecdif3f(dir,cw2,cw1);
2048 vecnormalize3f(dir,dir);
2049
2050 if(1){
2051 //1-direction vector relative to x-axis
2052 //now have 2 direction vectors - one at start, one at end
2053 //do a difference to get relative rotation from start
2054 float perp[3], dirx[3], sine;
2055 memset(dirx,0,3*sizeof(float));
2056 dirx[0] = 1.0f;
2057 veccross3f(perp,dirx,dir);
2058 sine = veclength3f(perp);
2059 if(sine == 0.0f){
2060 //no net rotation from start
2061 float default_direction [4] = {1.0f, 0.0f, 0.0f, 0.0f};
2062 veccopy4f(rot,default_direction);
2063 }else{
2064 float cosine, angle;
2065 vecnormalize3f(perp,perp);
2066 cosine = vecdot3f(dir,dirx);
2067 angle = atan2f(sine,cosine);
2068 veccopy3f(rot,perp);
2069 rot[3] = angle;
2070 }
2071 }else if(0){
2072 //2-direction vector to axis angle method
2073 //now have 2 direction vectors - one at start, one at end
2074 //do a difference to get relative rotation from start
2075 float perp[3],dir0[3];
2076
2077 CurvePoint(px->_xyzw.n, px->order-1, px->_knot.p, (float*)px->_xyzw.p, 0.0f, cw1 );
2078 CurvePoint(px->_xyzw.n, px->order-1, px->_knot.p, (float*)px->_xyzw.p, .001f, cw2 );
2079 vecdif3f(dir0,cw2,cw1);
2080 vecnormalize3f(dir0,dir0);
2081
2082 veccross3f(perp,dir,dir0);
2083 if(veclength3f(perp) == 0.0f){
2084 //no net rotation from start
2085 float default_direction [4] = {1.0f, 0.0f, 0.0f, 0.0f};
2086 veccopy4f(rot,default_direction);
2087 printf(".");
2088 }else{
2089 float cosine,angle;
2090 vecnormalize3f(perp,perp);
2091 cosine = vecdot3f(dir0,dir);
2092 angle = acosf(cosine);
2093 veccopy3f(rot,perp);
2094 rot[3] = -angle;
2095 }
2096 }
2097 veccopy4f(px->value_changed.c,rot);
2098 }else{
2099 float default_direction [4] = {1.0f, 0.0f, 0.0f, 0.0f};
2100 veccopy4f(px->value_changed.c,default_direction);
2101 }
2102 MARK_EVENT (node, offsetof (struct X3D_NurbsOrientationInterpolator, value_changed));
2103
2104 #ifdef SEVERBOSE
2105 printf("do_NurbsOrientInt: set_fraction %f value_changed %f %f %f %f\n",fraction,
2106 px->value_changed.c[0],px->value_changed.c[1],px->value_changed.c[2],px->value_changed.c[3] );
2107 #endif
2108
2109}
2110
2111void do_NurbsSurfaceInterpolator (void *_node) {
2112 float uv[2], xyzw[4];
2113 int ok;
2114 struct X3D_NurbsSurfaceInterpolator *node;
2115
2116 if (!_node) return;
2117 node = (struct X3D_NurbsSurfaceInterpolator *) _node;
2118 if(node->_nodeType != NODE_NurbsSurfaceInterpolator) return;
2119
2120 if(NNC(node)){
2121 MNC(node);
2122 if(node->_OK != TRUE){
2123 int i,j, n, nu, nv, nku, nkv;
2124 GLfloat *xyzw, *knotsu, *knotsv;
2125
2126 nku = nkv = nu = nv = n = 0;
2127 xyzw = knotsu = knotsv = NULL;
2128 if(node->controlPoint){
2129 if(node->controlPoint->_nodeType == NODE_CoordinateDouble){
2130 struct Multi_Vec3d *mfd;
2131 mfd = &((struct X3D_CoordinateDouble *)(node->controlPoint))->point;
2132 n = mfd->n;
2133 xyzw = MALLOC(void *, n * 4 * sizeof(GLfloat));
2134 for(i=0;i<mfd->n;i++){
2135 for(j=0;j<3;j++){
2136 xyzw[i*4 + j] = (float)mfd->p[i].c[j];
2137 }
2138 }
2139 }else if(node->controlPoint->_nodeType == NODE_Coordinate){
2140 struct Multi_Vec3f *mff;
2141 mff = &((struct X3D_Coordinate *)(node->controlPoint))->point;
2142 n = mff->n;
2143 xyzw = MALLOC(void *, n * 4 * sizeof(GLfloat));
2144 for(i=0;i<mff->n;i++){
2145 for(j=0;j<3;j++){
2146 xyzw[i*4 + j] = mff->p[i].c[j];
2147 }
2148 }
2149 }
2150 }else{
2151 n = 0;
2152 }
2153
2154 if(node->weight.n && node->weight.n == n){
2155 double w;
2156 int m,im;
2157 m = min(node->weight.n, n);
2158 for(i=0;i<n;i++){
2159 im = i < m ? i : m-1;
2160 w = node->weight.p[im];
2161 xyzw[i*4 + 3] = (float)w;
2162 }
2163 }else{
2164 for(i=0;i<n;i++) xyzw[i*4 + 3] = 1.0;
2165 }
2166 nu = node->uDimension;
2167 nv = node->vDimension;
2168 if(nu * nv != n) return;
2169 if(nu < node->uOrder) return;
2170 if(nv < node->vOrder) return;
2171 //int knotsOK(int order, int ncontrol, int nknots, double *knots)
2172 //if(node->uKnot.n && node->uKnot.n == nu + node->uOrder ){
2173 if(knotsOK(node->uOrder,nu,node->uKnot.n,node->uKnot.p)){
2174 //could do another check: max number of consecutive equal value knots == order
2175 //could do another check: knot values == or ascending
2176 nku = node->uKnot.n;
2177 knotsu = MALLOC(void *, nku * sizeof(GLfloat));
2178 for(i=0;i<nku;i++){
2179 knotsu[i] = (GLfloat)node->uKnot.p[i];
2180 }
2181 if(DEBG){
2182 int ii;
2183 printf("good u knot vector nk=%d\n",nku);
2184 for(ii=0;ii<nku;ii++)
2185 printf("[%d]=%f \n",ii,knotsu[ii]);
2186 }
2187
2188 }else{
2189 //generate uniform knot vector
2190 static int once = 0;
2191 nku = nu + node->uOrder ;
2192 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
2193 knotsu = MALLOC(void *, nku *sizeof(GLfloat));
2194 generateUniformKnotVector(node->uOrder,nu, knotsu);
2195 if(!once){
2196 int ii;
2197 printf("bad u knot vector given, replacing with:\n");
2198 for(ii=0;ii<nku;ii++)
2199 printf("[%d]=%f \n",ii,knotsu[ii]);
2200 once = 1;
2201 }
2202 //nk = 0;
2203 }
2204
2205 if(knotsOK(node->vOrder,nv,node->vKnot.n,node->vKnot.p)){
2206 //if(node->vKnot.n && node->vKnot.n == nv + node->vOrder ){
2207 nkv = node->vKnot.n;
2208 knotsv = MALLOC(void *, nkv * sizeof(GLfloat));
2209 for(i=0;i<nkv;i++){
2210 knotsv[i] = (GLfloat)node->vKnot.p[i];
2211 }
2212 if(DEBG){
2213 int ii;
2214 printf("good v knot vector nk=%d\n",nkv);
2215 for(ii=0;ii<nkv;ii++)
2216 printf("[%d]=%f \n",ii,knotsv[ii]);
2217 }
2218
2219 }else{
2220 static int once = 0;
2221 //generate uniform knot vector
2222 nkv = nv + node->vOrder ;
2223 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
2224 knotsv = MALLOC(void *, nkv *sizeof(GLfloat));
2225 generateUniformKnotVector(node->vOrder,nv, knotsv);
2226 if(!once){
2227 int ii;
2228 printf("bad v knot vector given, replacing with:\n");
2229 for(ii=0;ii<nkv;ii++)
2230 printf("[%d]=%f \n",ii,knotsv[ii]);
2231 once = 1;
2232 }
2233 //nk = 0;
2234 }
2235 node->_controlPoint.p = (struct SFVec4f*)xyzw;
2236 node->_controlPoint.n = n;
2237 node->_uKnot.p = knotsu;
2238 node->_uKnot.n = nku;
2239 node->_vKnot.p = knotsv;
2240 node->_vKnot.n = nkv;
2241 node->_OK = TRUE;
2242 }
2243
2244 }
2245
2246 if(!node->_OK) return;
2247
2248 veccopy2f(uv,node->set_fraction.c);
2249
2250 ok = SurfacePoint(node->uDimension,node->uOrder-1,node->_uKnot.p,
2251 node->vDimension,node->vOrder-1,node->_vKnot.p,
2252 (float *)node->_controlPoint.p,uv[1],uv[0],xyzw);
2253
2254 veccopy3f(node->position_changed.c,xyzw);
2255 if(1){
2256 //DELTA method to get normal
2257 //u direction
2258 float udir[3], vdir[3], normal[3], xyz1[4];
2259 ok = SurfacePoint(node->uDimension,node->uOrder-1,node->_uKnot.p,
2260 node->vDimension,node->vOrder-1,node->_vKnot.p,
2261 (float *)node->_controlPoint.p,uv[1],uv[0]+.01f,xyz1);
2262 vecdif3f(udir,xyz1,xyzw);
2263 ok = SurfacePoint(node->uDimension,node->uOrder-1,node->_uKnot.p,
2264 node->vDimension,node->vOrder-1,node->_vKnot.p,
2265 (float *)node->_controlPoint.p,uv[1]+.01f,uv[0],xyz1);
2266 vecdif3f(vdir,xyz1,xyzw);
2267 veccross3f(normal,udir,vdir);
2268 vecnormalize3f(normal,normal);
2269 veccopy3f(node->normal_changed.c,normal);
2270
2271
2272 }
2273
2274 MARK_EVENT (_node, offsetof (struct X3D_NurbsSurfaceInterpolator, position_changed));
2275 MARK_EVENT (_node, offsetof (struct X3D_NurbsSurfaceInterpolator, normal_changed));
2276
2277 #ifdef SEVERBOSE
2278 printf ("Pos/Col, new value (%f %f %f)\n",
2279 px->value_changed.c[0],px->value_changed.c[1],px->value_changed.c[2]);
2280 #endif
2281
2282}
2283
2284//SWUNG
2285
2286void compile_NurbsSwungSurface(struct X3D_NurbsSwungSurface *node){
2287 struct X3D_NurbsPatchSurface *patch;
2288 struct X3D_Coordinate *controlPoint;
2289 struct X3D_NurbsCurve2D *trajectoryxz;
2290 struct X3D_NurbsCurve2D *profileyz;
2291 int nt, np,ic,j,i,k;
2292 double *xyzp, *xyzt;
2293 float *xyz;
2294
2295 MARK_NODE_COMPILED
2296 //strategy: generate 3D control net from curves,
2297 // then delegate to NurbsPatchSurface
2298 //Swung:
2299 patch = (struct X3D_NurbsPatchSurface*) node->_patch;
2300 if(!patch){
2301 patch = (struct X3D_NurbsPatchSurface*)createNewX3DNode(NODE_NurbsPatchSurface);
2302 controlPoint = (struct X3D_Coordinate*)createNewX3DNode(NODE_Coordinate);
2303 node->_patch = X3D_NODE(patch);
2304 patch->controlPoint = X3D_NODE(controlPoint);
2305 }else{
2306 controlPoint = (struct X3D_Coordinate*)patch->controlPoint;
2307 }
2308
2309 trajectoryxz = (struct X3D_NurbsCurve2D *)node->trajectoryCurve;
2310 profileyz = (struct X3D_NurbsCurve2D *)node->profileCurve;
2311
2312 nt = trajectoryxz->controlPoint.n;
2313 np = profileyz->controlPoint.n;
2314 xyzp = (double*)profileyz->controlPoint.p;
2315 xyzt = (double*)trajectoryxz->controlPoint.p;
2316 xyz = MALLOC(float*,nt * np * 3 * sizeof(float));
2317 controlPoint->point.p = (struct SFVec3f*)xyz;
2318 controlPoint->point.n = nt * np;
2319 ic = 0;
2320 for(j=0;j<nt;j++){
2321 float pt[3];
2322 double2float(pt,&xyzt[j*2],2);
2323 for(i=0;i<np;i++){
2324 float pp[3];
2325 float cosine, sine, swingangle;
2326 double2float(pp,&xyzp[2*i],2);
2327 swingangle = atan2f(pt[1],pt[0]);
2328 cosine = cosf(swingangle);
2329 sine = sinf(swingangle);
2330 xyz[ic*3 + 0] = pt[0] + cosine * pp[0];
2331 xyz[ic*3 + 1] = pp[1];
2332 xyz[ic*3 + 2] = pt[1] + sine * pp[0];
2333 ic++;
2334 }
2335 }
2336 patch->solid = node->solid;
2337 //u will be profile,
2338 patch->uDimension = np;
2339 patch->uKnot.p = malloc(profileyz->knot.n * sizeof(double));
2340 memcpy(patch->uKnot.p,profileyz->knot.p,profileyz->knot.n * sizeof(double));
2341 patch->uKnot.n = profileyz->knot.n;
2342 patch->uOrder = profileyz->order;
2343 patch->uTessellation = (int)((float)profileyz->tessellation * profileyz->_tscale);
2344 //v will be trajectory
2345 patch->vDimension = nt;
2346 patch->vKnot.p = malloc(trajectoryxz->knot.n * sizeof(double));
2347 memcpy(patch->vKnot.p,trajectoryxz->knot.p,trajectoryxz->knot.n * sizeof(double));
2348 patch->vKnot.n = trajectoryxz->knot.n;
2349 patch->vOrder = trajectoryxz->order;
2350 patch->vTessellation = (int)((float)trajectoryxz->tessellation * profileyz->_tscale);
2351 if(0){
2352 int ic = 0;
2353 for(j=0;j<nt;j++){
2354 for(k=0;k<np;k++){
2355 printf("%f %f %f,",xyz[ic*3 + 0], xyz[ic*3 +1], xyz[ic*3 +2]);
2356 ic++;
2357 }
2358 printf("\n");
2359 }
2360 printf("uDimension=%d vDimension=%d nc=%d\n",np,nt,ic);
2361 }
2362 compile_NurbsPatchSurface((struct X3D_NurbsPatchSurface*)node->_patch);
2363}
2364void rendray_NurbsSwungSurface (struct X3D_NurbsSwungSurface *node) {
2365 COMPILE_IF_REQUIRED
2366 if (!node->_intern) return;
2367 render_ray_polyrep(node->_patch);
2368}
2369
2370void collide_NurbsSwungSurface (struct X3D_NurbsSwungSurface *node) {
2371 COMPILE_IF_REQUIRED
2372 if (!node->_intern) return;
2373 collide_genericfaceset(X3D_INDEXEDFACESET(node->_patch));
2374}
2375
2376void render_NurbsSwungSurface (struct X3D_NurbsSwungSurface *node) {
2377 struct X3D_NurbsPatchSurface *patch;
2378 COMPILE_IF_REQUIRED
2379 if (!node->_patch->_intern)
2380 return;
2381 patch = (struct X3D_NurbsPatchSurface*) node->_patch;
2382 CULL_FACE(patch->solid)
2383 render_polyrep(X3D_NODE(patch));
2384}
2385
2386
2387//SWEPT
2388int compute_tessellation(int tessellation, int order, int ncontrol ){
2389 /* for a given axis on a nurbs surface or nurbs curve,
2390 and given the node->tesselation value, order and nDimension or ncontrol for the axis
2391 return a computed tesselation value
2392 */
2393 int mtessu, ntessu; //mtessv, ntessv,
2394 mtessu = order + 1;
2395 ntessu = tessellation;
2396
2397 if(ntessu > 0)
2398 mtessu = max(mtessu,ntessu+1);
2399 else if(ntessu < 0)
2400 mtessu = max(mtessu,(-ntessu * ncontrol) + 1);
2401 else
2402 mtessu = max(mtessu,2*ncontrol + 1);
2403 return mtessu;
2404}
2405void compute_knotvector(int order, int ncontrol, int nknots, double *knots, int *newnknots, float **newknots, float *range){
2406 //for a given axis, QCs the knot vector, and replaces if necessary
2407 //will malloc the necessary newknot vector - caller responsible
2408 //range: pass in float[2] already allocated
2409 int nku,i,ii;
2410 float *knotsu;
2411 if(knotsOK(order,ncontrol,nknots,knots)){
2412 //could do another check: max number of consecutive equal value knots == order
2413 //could do another check: knot values == or ascending
2414 nku = nknots;
2415 knotsu = MALLOC(void *, nku * sizeof(GLfloat));
2416 for(i=0;i<nku;i++){
2417 knotsu[i] = (GLfloat)knots[i];
2418 }
2419 if(DEBG){
2420 printf("good u knot vector nk=%d\n",nku);
2421 for(ii=0;ii<nku;ii++)
2422 printf("[%d]=%f \n",ii,knotsu[ii]);
2423 }
2424 *newknots = knotsu;
2425 *newnknots = nku;
2426 }else{
2427 //generate uniform knot vector
2428 static int once = 0;
2429 nku = ncontrol + order ;
2430 //caller: please malloc knots = MALLOC(void *, (ncontrol + order ) * sizeof(float))
2431 knotsu = MALLOC(void *, nku *sizeof(GLfloat));
2432 generateUniformKnotVector(order,ncontrol, knotsu);
2433 if(!once){
2434 printf("bad u knot vector given, replacing with:\n");
2435 for(ii=0;ii<nku;ii++)
2436 printf("[%d]=%f \n",ii,knotsu[ii]);
2437 once = 1;
2438 }
2439 *newknots = knotsu;
2440 *newnknots= nku;
2441 //nk = 0;
2442 }
2443 range[0] = knotsu[0];
2444 range[1] = knotsu[nku-1];
2445}
2446void compute_weightedcontrol(double *xyz, int dim, int nc, int nweight, double *weights, float **cxyzw){
2447/* will malloc xyzw the right size, and return, caller responsible
2448 the opengl and piegl functions take floats
2449 dim = 3 for incoming xyz control
2450 dim = 2 for incoming xy (2D) control
2451 outgoing is [w*x,w*y,w*z,w]
2452*/
2453 int i,j;
2454 float *xyzw;
2455
2456 xyzw = MALLOC(float *, nc * 4 * sizeof(GLfloat));
2457 for(i=0;i<nc;i++)
2458 xyzw[i*4 +0] = xyzw[i*4 +1] =xyzw[i*4 +2] =xyzw[i*4 +3] = 0.0f;
2459 for(i=0;i<nc;i++){
2460 for(j=0;j<dim;j++){
2461 xyzw[i*4 + j] = (float)xyz[i*dim + j];
2462 }
2463 xyzw[i*4 + 3] = 1.0f;
2464 }
2465 if(nweight && nweight == nc ){
2466 for(i=0;i<nc;i++){
2467 float wt = (float)weights[i];
2468 xyzw[i*4 + 3] = wt;
2469 vecscale3f(&xyzw[i*4],&xyzw[i*4],wt);
2470 }
2471 }
2472 *cxyzw = xyzw;
2473}
2474void compute_doublecontrol(struct X3D_Node *controlPoint, int *nc, double** xyz ){
2475 /* rather than switch-casing elsewhere in the code, we'll get both types into double here
2476
2477 */
2478 int n,i;
2479 double *xyzd = NULL;
2480 n = 0;
2481 switch(controlPoint->_nodeType){
2482 case NODE_Coordinate:
2483 {
2484 struct X3D_Coordinate *tcoord = (struct X3D_Coordinate*) controlPoint;
2485 n = tcoord->point.n;
2486 xyzd = MALLOC(double *,n * 3 * sizeof(double));
2487 for(i=0;i<tcoord->point.n;i++)
2488 float2double(&xyzd[i*3],tcoord->point.p[i].c,3);
2489 }
2490 break;
2491 case NODE_CoordinateDouble:
2492 {
2493 struct X3D_CoordinateDouble *tcoord = (struct X3D_CoordinateDouble *)controlPoint;
2494 n = tcoord->point.n;
2495 xyzd = MALLOC(double *,n * 3 * sizeof(double));
2496 for(i=0;i<tcoord->point.n;i++)
2497 veccopyd(&xyzd[i*3],tcoord->point.p[i].c);
2498
2499 }
2500 break;
2501 default:
2502 break;
2503 }
2504 *nc = n;
2505 *xyz = xyzd;
2506
2507}
2508float *vecabs3f(float *res, float *p){
2509 int i;
2510 for(i=0;i<3;i++)
2511 res[i] = fabsf(p[i]);
2512 return res;
2513}
2514int ivecdominantdirection3f(int *irank, float *p){
2515 float rmax, rmin, vabs[3];
2516 int i,iret = 0;
2517 vecabs3f(vabs,p);
2518 rmax = max(vabs[0],max(vabs[1],vabs[2]));
2519 rmin = min(vabs[0],min(vabs[1],vabs[2]));
2520 for(i=0;i<3;i++){
2521 irank[i] = 1;
2522 if(vabs[i] == rmax) {
2523 irank[i] = 2;
2524 iret = i;
2525 }
2526 if(vabs[i] == rmin) irank[i] = 0;
2527 }
2528 return iret;
2529}
2530void convert_mesh_to_polyrep(float *xyz, int npts, float *nxyz, int* tindex, int ntri, struct X3D_Node *node){
2531 //this is a bit like compile_polyrep, except the virt_make is below
2532
2533 struct X3D_PolyRep *rep_, *polyrep;
2534 GLuint *norindex; //*cindex,
2535
2536 //from compile_polyrep:
2537 //node = X3D_NODE(innode);
2538 //virt = virtTable[node->_nodeType];
2539
2540 /* first time through; make the intern structure for this polyrep node */
2541 if(node->_intern){
2542 polyrep = node->_intern;
2543 FREE_IF_NZ(polyrep->cindex);
2544 FREE_IF_NZ(polyrep->actualCoord);
2545 FREE_IF_NZ(polyrep->GeneratedTexCoords[0]);
2546 FREE_IF_NZ(polyrep->colindex);
2547 FREE_IF_NZ(polyrep->color);
2548 FREE_IF_NZ(polyrep->norindex);
2549 FREE_IF_NZ(polyrep->normal);
2550 FREE_IF_NZ(polyrep->flat_normal);
2551 FREE_IF_NZ(polyrep->tcindex);
2552 }
2553 if(!node->_intern)
2554 node->_intern = create_polyrep();
2555
2556 rep_ = polyrep = node->_intern;
2557
2558
2559 /* if multithreading, tell the rendering loop that we are regenning this one */
2560 /* if singlethreading, this'll be set to TRUE before it is tested */
2561
2562 //<< END FROM Compile_polyrep
2563
2564 // Start Virt_make_polyrep section >>>
2565
2566 if (npts > 0)
2567 {
2568 //printf("npoints %d ntc %d\n",npoints,ntc);
2569 rep_->actualCoord = xyz;
2570 rep_->normal = nxyz;
2571 }
2572 rep_->ntri = ntri;
2573
2574 if (rep_->ntri > 0)
2575 {
2576 rep_->cindex = tindex;
2577 norindex = rep_->norindex = MALLOC(GLuint *,sizeof(GLuint)*3*ntri);
2578 memcpy(norindex,tindex,sizeof(GLuint)*3*ntri);
2579 }
2580
2581
2582 //END virt_make_polyrep section <<<<<<
2583
2584 //FROM Compile_polyrep
2585 if (polyrep->ntri != 0) {
2586 //float *fogCoord = NULL;
2587 stream_polyrep(node, NULL,NULL,NULL,NULL, NULL);
2588 /* and, tell the rendering process that this shape is now compiled */
2589 }
2590 //else wait for set_coordIndex to be converted to coordIndex
2591 polyrep->irep_change = node->_change;
2592
2593 /*
2594 // dump then can copy and paste to x3d or wrl IndexedFaceSet.coordIndex and Coordinate.point fields
2595 FILE * fp = fopen("IFS_DUMP.txt","w+");
2596 fprintf(fp,"#vertices %d\n",np);
2597 for(i=0;i<np;i++){
2598 fprintf(fp,"%f %f %f\n",rep->actualCoord[i*3 +0],rep->actualCoord[i*3 +1],rep->actualCoord[i*3 +2]);
2599 }
2600 fprintf(fp,"#face indices %d\n",ni);
2601 for(i=0;i<ni;i++){
2602 fprintf(fp,"%d ",rep->cindex[i]);
2603 if((ni+1) % 3 == 0)
2604 fprintf(fp,"%d ",-1);
2605 }
2606 fprintf(fp,"\n");
2607 fclose(fp);
2608 */
2609
2610}
2611void compile_NurbsSweptSurface(struct X3D_NurbsSweptSurface *node){
2612 int nt, np;
2613 double *xyzx;
2614 double *xyzt;
2615 struct X3D_NurbsCurve *trajectory;
2616 struct X3D_NurbsCurve2D *xsection;
2617 MARK_NODE_COMPILED
2618 //Swept:
2619
2620 trajectory = (struct X3D_NurbsCurve *)node->trajectoryCurve;
2621 xyzt = NULL;
2622 nt = 0;
2623 /*
2624 switch(trajectory->controlPoint->_nodeType){
2625 case NODE_Coordinate:
2626 {
2627 struct X3D_Coordinate *tcoord = (struct X3D_Coordinate*) trajectory->controlPoint;
2628 nt = tcoord->point.n;
2629 xyzt = MALLOC(double *,nt * sizeof(double));
2630 for(int i=0;i<tcoord->point.n;i++)
2631 float2double(&xyzt[i*3],tcoord->point.p[i].c,3);
2632 }
2633 break;
2634 case NODE_CoordinateDouble:
2635 {
2636 struct X3D_CoordinateDouble *tcoord = (struct X3D_CoordinateDouble *)trajectory->controlPoint;
2637 nt = tcoord->point.n;
2638 xyzt = MALLOC(double *,nt * sizeof(double));
2639 for(int i=0;i<tcoord->point.n;i++)
2640 veccopyd(&xyzt[i*3],tcoord->point.p[i].c);
2641
2642 }
2643 break;
2644 default:
2645 break;
2646 }
2647 */
2648 compute_doublecontrol(trajectory->controlPoint,&nt,&xyzt);
2649 xsection = (struct X3D_NurbsCurve2D *)node->crossSectionCurve;
2650
2651 np = xsection->controlPoint.n;
2652 xyzx = (double*)xsection->controlPoint.p;
2653
2654 // "The Nurbs Book", Les Piegl, Wayne Tiller, 2nd, 1997, Springer
2655 // piegl p.472 10.4 Swept Surfaces
2656 //ALGO Method 1.
2657 // method 1. S(u,v) = T(v) + C(u)
2658 // - has a precise NURBS definition
2659 // - (no need for spine, B up vector, planes, skinning)
2660 // - just set up the Suv control net and weights, and delegate to Patch
2661 // P(i,j) = Tj + Qi (control points)
2662 // w(i,j) = wT(j) x wC(i) (weights)
2663 // - but piegl Figure 10.11 p.474 shows the results of this sweep:
2664 // * its good for nearly linear trajectories
2665 // x but not good if you turn a 90 corner
2666 // - the profile isn't rotated with the trajectory
2667 // - so the 'tube' will flatten
2668 //ALGO 2 Method 2.
2669 // if you want the tube to stay open ie profile rotates with trajectory curve,
2670 // then you need to implement method 2. and for that
2671 // 1. compute tesselation points along trajectory curve (use piegl CurvePoint)
2672 // - get direction vector aka Tangent T of curve using Delta or Derivs, as xsection normal
2673 // - project up vector from last profile (1st profile up is arbitrary)
2674 // Piegl p.483 formula 10.27:
2675 // B0 - arbitrary unit vector perpendicular/orthogonal to trajectory tangent vector at v0
2676 // Ti = T'(vi)/|T'(vi)| //get the tangent vector along the trajectory curve, can use delta or Derivs
2677 // bi = Bi-1 - (Bi-1 * Ti)Ti
2678 // Bi = bi/|bi|
2679 // 2. comupte tesselated cross section aka xsection aka profile (use piegl CurvePoint)
2680 // 3. for each trajectory tesselation point:
2681 // a) insert up- and tangent- oriented xsection points
2682 // b) skin: join current xsection points with last with triangles
2683 //
2684 if(!strcmp(node->method->strptr,"FULL"))
2685 node->_method = 2;
2686 if(!strcmp(node->method->strptr,"TRANSLATE"))
2687 node->_method = 1;
2688 if(node->_method == 1){
2689 //ALGO 1 Suv = T(v) + C(u)
2690 struct X3D_NurbsPatchSurface *patch;
2691 struct X3D_Coordinate *controlPoint;
2692 float *xyz;
2693 int ic,j,i;
2694 double *weight;
2695
2696 patch = (struct X3D_NurbsPatchSurface*)node->_patch;
2697 controlPoint = (struct X3D_Coordinate*)patch->controlPoint;
2698 if(!patch){
2699 patch = (struct X3D_NurbsPatchSurface*) createNewX3DNode(NODE_NurbsPatchSurface);
2700 controlPoint = (struct X3D_Coordinate*) createNewX3DNode(NODE_Coordinate);
2701 node->_patch = X3D_NODE(patch);
2702 patch->controlPoint = X3D_NODE(controlPoint);
2703 }
2704 xyz = MALLOC(float*,nt * np * 3 * sizeof(float));
2705 controlPoint->point.p = (struct SFVec3f*) xyz;
2706 controlPoint->point.n = nt * np;
2707
2708 ic = 0;
2709 for(j=0;j<nt;j++){
2710 float pt[3];
2711 double2float(pt,&xyzt[j*3],3);
2712 for(i=0;i<np;i++){
2713 float pp[3];
2714 double2float(pp,&xyzx[2*i],2);
2715 xyz[ic*3 + 0] = pt[0] + pp[0];
2716 xyz[ic*3 + 1] = pt[1] + pp[1];
2717 xyz[ic*3 + 2] = pt[2];
2718 ic++;
2719 }
2720 }
2721
2722 weight = NULL;
2723 if((trajectory->weight.n && trajectory->weight.n == nt) ||
2724 (xsection->weight.n && xsection->weight.n == np)){
2725 //we have some non-default weights, so apply the piegl formula p.473
2726 // w(i,j) = wT(j) x wC(i) (weights)
2727 weight = MALLOC(double*,nt * np * sizeof(double));
2728 for(j=0;j<nt;j++){
2729 double wtTj = trajectory->weight.p[j];
2730 for(i=0;i<np;i++)
2731 weight[j*np + i] = wtTj * xsection->weight.p[i];
2732 }
2733 }
2734
2735
2736 if(weight){
2737 patch->weight.p = weight;
2738 patch->weight.n = nt * np;
2739 }
2740 patch->solid = node->solid;
2741 //u will be profile,
2742 patch->uDimension = np;
2743 patch->uKnot.p = malloc(xsection->knot.n * sizeof(double));
2744 memcpy(patch->uKnot.p,xsection->knot.p,xsection->knot.n * sizeof(double));
2745 patch->uKnot.n = xsection->knot.n;
2746 patch->uOrder = xsection->order;
2747 patch->uTessellation = (int)((float)xsection->tessellation * xsection->_tscale);
2748 //v will be trajectory
2749 patch->vDimension = nt;
2750 patch->vKnot.p = malloc(xsection->knot.n * sizeof(double));
2751 memcpy(patch->vKnot.p,trajectory->knot.p,trajectory->knot.n * sizeof(double));
2752 patch->vKnot.n = trajectory->knot.n;
2753 patch->vOrder = trajectory->order;
2754 patch->vTessellation = (int)((float)trajectory->tessellation * trajectory->_tscale);
2755 if(0){
2756 int j,k,ic = 0;
2757 for(j=0;j<nt;j++){
2758 for(k=0;k<np;k++){
2759 printf("%f %f %f,",xyz[ic*3 + 0], xyz[ic*3 +1], xyz[ic*3 +2]);
2760 ic++;
2761 }
2762 printf("\n");
2763 }
2764 printf("uDimension=%d vDimension=%d nc=%d\n",np,nt,ic);
2765 }
2766 compile_NurbsPatchSurface((struct X3D_NurbsPatchSurface*)node->_patch);
2767 } //end method == 1
2768 if(node->_method == 2){
2769 //ALGO 2 skinning like extrusion
2770 int mtessv, mtessu, nku, nkv;
2771 int i,DBGSW;
2772 float *knotsu,*knotsv,*xyzwu,*xyzwv, urange[2],vrange[2];
2773 float *Tv, *Tangentv, *Bup, *pts;
2774 float *Qu, *Nu;
2775 float *normals;
2776 int *idx;
2777 int ic, it;
2778 float matB0[9];
2779 int ntri;
2780
2781
2782 int mtessu1, mtessv1;
2783
2784 mtessu = compute_tessellation(xsection->tessellation,xsection->order,np);
2785 mtessu = (int)((float)mtessu * xsection->_tscale);
2786 mtessv = compute_tessellation(trajectory->tessellation,trajectory->order,nt);
2787 mtessv = (int)((float)mtessv * trajectory->_tscale);
2788 compute_knotvector(xsection->order,np,xsection->knot.n,xsection->knot.p,&nku,&knotsu,urange);
2789 compute_knotvector(trajectory->order,nt,trajectory->knot.n,trajectory->knot.p,&nkv,&knotsv,vrange);
2790 compute_weightedcontrol(xyzt,3,nt, trajectory->weight.n, trajectory->weight.p, &xyzwv);
2791 compute_weightedcontrol(xyzx,2,np, xsection->weight.n, xsection->weight.p, &xyzwu);
2792 DBGSW = FALSE;
2793 if(DBGSW){
2794 int i;
2795 printf("np %d mtessu %d nku %d, nt %d mtessv %d, nkv %d",np,mtessu,nku,nt,mtessv,nkv);
2796 printf("trajectory nt %d points:\n",nt);
2797 for(i=0;i<nt;i++)
2798 printf("%d %f %f %f %f\n",i,xyzwv[i*4 + 0],xyzwv[i*4 + 1],xyzwv[i*4 + 2],xyzwv[i*4 + 3]);
2799 printf("xsection np %d points:\n",np);
2800 for(i=0;i<np;i++)
2801 printf("%d %f %f %f %f\n",i,xyzwu[i*4 + 0],xyzwu[i*4 + 1],xyzwu[i*4 + 2],xyzwu[i*4 + 3]);
2802 }
2803 // 1. compute tesselation points along trajectory curve (use piegl CurvePoint)
2804 // - get direction vector aka Tangent T of curve using Delta or Derivs, as xsection normal
2805 // - project up-vector from last profile (1st profile up is arbitrary)
2806 // Piegl p.483 formula 10.27:
2807 // B0 - arbitrary unit vector perpendicular/orthogonal to trajectory tangent vector at v0
2808 // Ti = T'(vi)/|T'(vi)| //get the tangent vector Tangentv along the trajectory curve, can use delta or Derivs
2809 // bi = Bi-1 - (Bi-1 dot Ti)Ti //where dot is the dot product
2810 // Bi = bi/|bi|
2811 mtessu1 = mtessu + 1;
2812 mtessv1 = mtessv + 1;
2813 Tv = MALLOC(float*,(mtessv1)*3*sizeof(float));
2814 Tangentv = MALLOC(float*,(mtessv1)*3*sizeof(float));
2815 Bup = MALLOC(float*,(mtessv1)*3*sizeof(float));
2816 for(i=0;i<mtessv1;i++){
2817 float cw[4], cw1[4], delta[3], v;
2818 v = (float)i*(vrange[1]-vrange[0])/(float)mtessv;
2819 CurvePoint(nt, trajectory->order-1, knotsv, xyzwv, v, cw );
2820 veccopy3f(&Tv[i*3],cw);
2821 //- get direction vector aka Tangent T of curve using Delta or Derivs, as xsection normal
2822 CurvePoint(nt, trajectory->order-1, knotsv, xyzwv, v+.01f, cw1 );
2823 vecdif3f(delta,cw1,cw);
2824 // Ti = T'(vi)/|T'(vi)| //get the tangent vector Tangentv along the trajectory curve, can use delta or Derivs
2825 vecnormalize3f(delta,delta);
2826 veccopy3f(&Tangentv[i*3],delta);
2827 //- project up-vector from last profile (1st profile up is arbitrary)
2828 if(i==0){
2829 // B0 - arbitrary unit vector perpendicular/orthogonal to trajectory tangent vector at v0
2830 int k,irank[3],idom, inondom;
2831 float perp[3], perp2[3];
2832 idom = ivecdominantdirection3f(irank,delta);
2833 inondom = idom + 1 > 2 ? 0 : idom + 1;
2834 for(k=0;k<3;k++) if(irank[k] == 0) inondom = k;
2835 memset(perp,0,3*sizeof(float));
2836 perp[inondom] = 1.0; //close to perpendicular, but not quite
2837 veccross3f(perp2,delta,perp); //perp2 perpendicular to perp and delta
2838 veccross3f(perp,perp2,delta); //another cross to get perp exactly perpendicular
2839 //perp should be perpendicular to delta[0]
2840 veccopy3f(&Bup[i*3],perp);
2841 }else{
2842 // bi = Bi-1 - (Bi-1 dot Ti)Ti
2843 // Bi = bi/|bi|
2844 float bi[3], bi1dotti, tiscaled[3];
2845 bi1dotti = vecdot3f(&Bup[(i-1)*3],&Tangentv[i*3]);
2846 vecdif3f(bi,&Bup[(i-1)*3],vecscale3f(tiscaled,&Tangentv[i*3],bi1dotti));
2847 vecnormalize3f(&Bup[i*3],bi);
2848 }
2849 }
2850 if(DBGSW){
2851 printf("trajectory T:\n");
2852 for(i=0;i<mtessv1;i++){
2853 printf("%d [%f %f %f] \n",i,
2854 Tv[i*3 +0],Tv[i*3 +1],Tv[i*3 +2]);
2855 }
2856 printf("trajectory T', B:\n");
2857 for(i=0;i<mtessv1;i++){
2858 printf("%d [%f %f %f] [%f %f %f] \n",i,
2859 Tangentv[i*3 +0],Tangentv[i*3 +1],Tangentv[i*3 +2],
2860 Bup[i*3 +0],Bup[i*3 +1],Bup[i*3 +2]);
2861 }
2862
2863 }
2864 //if(trajectory->closed){
2865 // //compute backward Bup, and average fore and aft Bup
2866 //}
2867 // 2. comupte tesselated cross section aka xsection aka profile (use piegl CurvePoint)
2868 Qu = MALLOC(float*,(mtessu+1)*3*sizeof(float)); //cross section points
2869 Nu = MALLOC(float*,(mtessu+1)*3*sizeof(float)); //cross section normals
2870 if(DBGSW) printf("Xsection tess pts:\n");
2871 for(i=0;i<mtessu1;i++){
2872 float u, cw[4], cw1[4], delta[3], normal[3];
2873 float zzz[3] = {0.0f,0.0f,1.0f};
2874 u = (float)i*(urange[1]-urange[0])/(float)mtessu;
2875 CurvePoint(np, xsection->order-1, knotsu, xyzwu, u, cw );
2876 veccopy3f(&Qu[i*3],cw);
2877 CurvePoint(np, xsection->order-1, knotsu, xyzwu, u+.01f, cw1 );
2878 vecdif3f(delta,cw1,cw);
2879 vecnormalize3f(delta,delta);
2880 veccross3f(normal,zzz,delta);
2881 veccopy3f(&Nu[i*3],normal);
2882 if(DBGSW) printf("%d %f %f %f\n",i,Qu[i*3 +0],Qu[i*3 +1],Qu[i*3 +2]);
2883
2884 }
2885 // 3. for each trajectory tesselation point:
2886 // a) insert up- and tangent- oriented xsection points
2887 // b) skin: join current xsection points with last with triangles
2888 pts = MALLOC(float*,mtessu1 * mtessv1 * 3 * sizeof(float));
2889 normals = MALLOC(float*,mtessu1 * mtessv1 * 3 * sizeof(float));
2890 idx = MALLOC(int *, mtessu * mtessv * 2 * 3 * sizeof(int));
2891 ic = 0;
2892 it = 0;
2893 for(i=0;i<mtessv1;i++){
2894 //insert oriented xsection at T(v)
2895 float mat [9], matt[9];
2896 int j;
2897 //set up 3x3 rotation by using 3 perpendicular local unit vectors as rot mat rows
2898 //http://renderdan.blogspot.ca/2006/05/rotation-matrix-from-axis-vectors.html
2899
2900 veccross3f(&mat[0],&Bup[i*3],&Tangentv[i*3]);
2901 veccopy3f(&mat[3],&Bup[i*3]);
2902 veccopy3f(&mat[6],&Tangentv[i*3]);
2903 mattranspose3f(matt,mat); //seems like I need columns, not rows, by experimentation
2904 if(i==0){
2905 //not sure but I think we should take off the
2906 //arbitrary rotation of the first crossection from all subsequent
2907 //so first xsection not rotated (you need to design with
2908 //your crosssection plane perpendicular to the start of your trajectory)
2909 //and subsequent are rotated with respect to first
2910 //Looks good
2911 memcpy(matB0,mat,9*sizeof(float));
2912 }
2913 matmultiply3f(mat,matt,matB0);
2914 for(j=0;j<mtessu1;j++){
2915 float pp[3], norm[3];
2916 matmultvec3f(pp, mat, &Qu[j*3] ); //orient profile point
2917 vecadd3f(pp,pp,&Tv[i*3]); //add on trajectory point
2918 veccopy3f(&pts[ic*3],pp);
2919 matmultvec3f(norm,mat,&Nu[j*3]);
2920 veccopy3f(&normals[ic*3],norm);
2921 ic++;
2922 }
2923 //connect to last xsection with triangles
2924 if(i > 0){
2925 int j,kk,mm;
2926 kk = (i-1)*mtessu1;
2927 mm = i*mtessu1;
2928 for(j=0;j<mtessu;j++){
2929 // 1 1 3
2930 // 0 2 2
2931 //first triangle
2932 idx[it++] = kk+j;
2933 idx[it++] = mm+j;
2934 idx[it++] = kk+j+1;
2935 //second triangle
2936 idx[it++] = kk+j+1;
2937 idx[it++] = mm+j;
2938 idx[it++] = mm+j+1;
2939 }
2940 }
2941 }
2942 //assign to something
2943 ntri = it/3;
2944 if(DBGSW){
2945 printf("ntri %d triangle indexes:\n",ntri);
2946 for(i=0;i<ntri;i++){
2947 int j;
2948 printf("%d [",i);
2949 for(j=0;j<3;j++){
2950 printf("%d ",idx[i*3 +j]);
2951 }
2952 printf("\n");
2953 }
2954 printf("triangle vertices:\n");
2955 for(i=0;i<ntri;i++){
2956 int j;
2957 for(j=0;j<3;j++){
2958 float pt[3];
2959 int ix = idx[i*3 +j];
2960 veccopy3f(pt,&pts[ix*3]);
2961 printf("%d %d %f %f %f\n",i,ix,pt[0],pt[1],pt[2]);
2962 }
2963 }
2964 }
2965
2966 //send to polyrep
2967 convert_mesh_to_polyrep(pts,ic,normals,idx,ntri,X3D_NODE(node));
2968 }
2969
2970}
2971void rendray_NurbsSweptSurface (struct X3D_NurbsSweptSurface *node) {
2972 COMPILE_IF_REQUIRED
2973 if(node->_method == 1){
2974 if (!node->_patch) return;
2975 render_ray_polyrep(node->_patch);
2976 }
2977 if(node->_method == 2){
2978 if(!node->_intern) return;
2979 render_ray_polyrep(node);
2980 }
2981}
2982
2983void collide_NurbsSweptSurface (struct X3D_NurbsSweptSurface *node) {
2984 COMPILE_IF_REQUIRED
2985 if(node->_method == 1){
2986 if (!node->_patch) return;
2987 collide_genericfaceset(X3D_INDEXEDFACESET(node->_patch));
2988 }
2989 if(node->_method == 2){
2990 if (!node->_intern) return;
2991 collide_genericfaceset(X3D_INDEXEDFACESET(node));
2992 }
2993}
2994
2995void render_NurbsSweptSurface (struct X3D_NurbsSweptSurface *node) {
2996 COMPILE_IF_REQUIRED
2997 if(node->_method == 1){
2998 struct X3D_NurbsPatchSurface *patch;
2999 if (!node->_patch->_intern)
3000 return;
3001 patch = (struct X3D_NurbsPatchSurface *)node->_patch;
3002 CULL_FACE(patch->solid)
3003 render_polyrep(patch);
3004 }
3005 if(node->_method == 2){
3006 if (!node->_intern)
3007 return;
3008 //CULL_FACE(node->solid)
3009 render_polyrep(node);
3010
3011 }
3012}
3013void compile_NurbsSet(struct X3D_NurbsSet *node){
3014 int i;
3015 MARK_NODE_COMPILED
3016 //tessellationScale
3017 for(i=0;i<node->geometry.n;i++){
3018 struct X3D_Node *gn = (struct X3D_Node*)node->geometry.p[i];
3019 switch(gn->_nodeType){
3020 case NODE_NurbsCurve:
3021 {
3022 struct X3D_NurbsCurve* g = (struct X3D_NurbsCurve*)gn;
3023 g->_tscale = node->tessellationScale;
3024 MNX(g);
3025 }
3026 break;
3027 case NODE_NurbsCurve2D:
3028 {
3029 struct X3D_NurbsCurve2D* g = (struct X3D_NurbsCurve2D*)gn;
3030 g->_tscale = node->tessellationScale;
3031 MNX(g);
3032 }
3033 break;
3034 case NODE_NurbsPatchSurface:
3035 {
3036 struct X3D_NurbsPatchSurface* g = (struct X3D_NurbsPatchSurface*)gn;
3037 g->_tscale = node->tessellationScale;
3038 MNX(g);
3039 }
3040 break;
3041 case NODE_NurbsTrimmedSurface:
3042 {
3043 struct X3D_NurbsTrimmedSurface* g = (struct X3D_NurbsTrimmedSurface*)gn;
3044 g->_tscale = node->tessellationScale;
3045 MNX(g);
3046 }
3047 break;
3048 case NODE_NurbsSweptSurface:
3049 {
3050 struct X3D_NurbsSweptSurface* g = (struct X3D_NurbsSweptSurface*)gn;
3051 if(g->_method == 1){
3052 if(g->_patch){
3053 struct X3D_NurbsPatchSurface *patch = (struct X3D_NurbsPatchSurface *)g->_patch;
3054 patch->_tscale = node->tessellationScale;
3055 MNX(g);
3056 }
3057 }
3058 if(g->_method == 2){
3059 struct X3D_NurbsCurve2D *curve = (struct X3D_NurbsCurve2D *)g->crossSectionCurve;
3060 curve->_tscale = node->tessellationScale;
3061 MNX(g->crossSectionCurve);
3062 curve = (struct X3D_NurbsCurve2D *)g->trajectoryCurve;
3063 curve->_tscale = node->tessellationScale;
3064 MNX(g->trajectoryCurve);
3065 }
3066 }
3067 break;
3068 case NODE_NurbsSwungSurface:
3069 {
3070 struct X3D_NurbsSwungSurface* g = (struct X3D_NurbsSwungSurface*)gn;
3071 if(g->_patch){
3072 struct X3D_NurbsPatchSurface *patch = (struct X3D_NurbsPatchSurface *)g->_patch;
3073 patch->_tscale = node->tessellationScale;
3074 MNX(g);
3075 }
3076 }
3077 break;
3078 }
3079 }
3080}
3081void render_NurbsSet(struct X3D_NurbsSet *node){
3082 COMPILE_IF_REQUIRED
3083}
3084#else //LIB_NURBS
3085void compile_ContourPolyline2D(struct X3D_ContourPolyline2D *node){}
3086void compile_NurbsCurve(struct X3D_NurbsCurve *node){}
3087void render_NurbsCurve(struct X3D_NurbsCurve *node){}
3088void compile_NurbsPatchSurface(struct X3D_NurbsPatchSurface *node){}
3089void rendray_NurbsPatchSurface (struct X3D_NurbsPatchSurface *node) {}
3090void collide_NurbsPatchSurface (struct X3D_NurbsPatchSurface *node) {}
3091void render_NurbsPatchSurface (struct X3D_NurbsPatchSurface *node) {}
3092void compile_NurbsTrimmedSurface(struct X3D_NurbsTrimmedSurface *node){}
3093void rendray_NurbsTrimmedSurface (struct X3D_NurbsTrimmedSurface *node) {}
3094void collide_NurbsTrimmedSurface (struct X3D_NurbsTrimmedSurface *node) {}
3095void render_NurbsTrimmedSurface (struct X3D_NurbsTrimmedSurface *node) {}
3096void do_NurbsPositionInterpolator (void *node) {}
3097void do_NurbsOrientationInterpolator (void *node){}
3098void do_NurbsSurfaceInterpolator (void *_node){}
3099void compile_NurbsSwungSurface(struct X3D_NurbsSwungSurface *node){}
3100void rendray_NurbsSwungSurface (struct X3D_NurbsSwungSurface *node) {}
3101void collide_NurbsSwungSurface (struct X3D_NurbsSwungSurface *node) {}
3102void render_NurbsSwungSurface (struct X3D_NurbsSwungSurface *node) {}
3103void compile_NurbsSweptSurface(struct X3D_NurbsSweptSurface *node){}
3104void rendray_NurbsSweptSurface (struct X3D_NurbsSweptSurface *node) {}
3105void collide_NurbsSweptSurface (struct X3D_NurbsSweptSurface *node) {}
3106void render_NurbsSweptSurface (struct X3D_NurbsSweptSurface *node){}
3107void compile_NurbsSet(struct X3D_NurbsSet *node){}
3108void render_NurbsSet(struct X3D_NurbsSet *node){}
3109#endif //LIB_NURBS