1 /* $Id: nurbsutl.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-1997 Brian Paul
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * $Log: nurbsutl.c,v $
26 * Revision 1.1 1999/08/19 00:55:42 jtg
29 * Revision 1.8 1999/06/08 00:44:51 brianp
30 * OpenStep updates (pete@ohm.york.ac.uk)
32 * Revision 1.7 1998/07/26 02:07:59 brianp
33 * updated for Windows compilation per Ted Jump
35 * Revision 1.6 1997/10/29 02:02:20 brianp
36 * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver)
38 * Revision 1.5 1997/07/24 01:28:44 brianp
39 * changed precompiled header symbol from PCH to PC_HEADER
41 * Revision 1.4 1997/05/28 02:29:38 brianp
42 * added support for precompiled headers (PCH), inserted APIENTRY keyword
44 * Revision 1.3 1997/05/27 03:19:54 brianp
47 * Revision 1.2 1997/05/27 03:00:16 brianp
48 * incorporated Bogdan's new NURBS code
50 * Revision 1.1 1996/09/27 01:19:39 brianp
57 * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
58 * See README2 for more info.
73 test_knot(GLint nknots
, GLfloat
*knot
, GLint order
)
83 if(knot
[i
] < tmp_knot
)
84 return GLU_NURBS_ERROR4
;
85 if(fabs(tmp_knot
-knot
[i
]) > EPSILON
)
88 return GLU_NURBS_ERROR5
;
100 #if defined(WIN32) && !defined(OPENSTEP)
103 knot_sort(const void *a
, const void *b
)
109 if(fabs(x
-y
) < EPSILON
)
116 /* insert into dest knot all values within the valid range from src knot */
117 /* that do not appear in dest */
119 collect_unified_knot(knot_str_type
*dest
, knot_str_type
*src
,
120 GLfloat maximal_min_knot
, GLfloat minimal_max_knot
)
122 GLfloat
*src_knot
,*dest_knot
;
123 GLint src_t_min
,src_t_max
,dest_t_min
,dest_t_max
;
124 GLint src_nknots
,dest_nknots
;
126 GLboolean not_found_flag
;
128 src_knot
=src
->unified_knot
;
129 dest_knot
=dest
->unified_knot
;
130 src_t_min
=src
->t_min
;
131 src_t_max
=src
->t_max
;
132 dest_t_min
=dest
->t_min
;
133 dest_t_max
=dest
->t_max
;
134 src_nknots
=src
->unified_nknots
;
135 dest_nknots
=dest
->unified_nknots
;
137 k
=new_cnt
=dest_nknots
;
138 for(i
=src_t_min
;i
<=src_t_max
;i
++)
139 if(src_knot
[i
] - maximal_min_knot
> -EPSILON
&&
140 src_knot
[i
] - minimal_max_knot
< EPSILON
)
142 not_found_flag
=GL_TRUE
;
143 for(j
=dest_t_min
;j
<=dest_t_max
;j
++)
144 if(fabs(dest_knot
[j
]-src_knot
[i
]) < EPSILON
)
146 not_found_flag
=GL_FALSE
;
151 /* knot from src is not in dest - add this knot to dest */
152 dest_knot
[k
++]=src_knot
[i
];
154 ++(dest
->t_max
); /* the valid range widens */
155 ++(dest
->delta_nknots
); /* increment the extra knot value counter */
158 dest
->unified_nknots
=new_cnt
;
159 qsort((void *)dest_knot
,(size_t)new_cnt
,(size_t)sizeof(GLfloat
),
163 /* basing on the new common knot range for all attributes set */
164 /* t_min and t_max values for each knot - they will be used later on */
165 /* by explode_knot() and calc_new_ctrl_pts */
167 set_new_t_min_t_max(knot_str_type
*geom_knot
, knot_str_type
*color_knot
,
168 knot_str_type
*normal_knot
, knot_str_type
*texture_knot
,
169 GLfloat maximal_min_knot
, GLfloat minimal_max_knot
)
171 GLuint t_min
,t_max
,cnt
;
173 if(minimal_max_knot
-maximal_min_knot
< EPSILON
)
175 /* knot common range empty */
176 geom_knot
->t_min
=geom_knot
->t_max
=0;
177 color_knot
->t_min
=color_knot
->t_max
=0;
178 normal_knot
->t_min
=normal_knot
->t_max
=0;
179 texture_knot
->t_min
=texture_knot
->t_max
=0;
183 if(geom_knot
->unified_knot
!=NULL
)
185 cnt
=geom_knot
->unified_nknots
;
186 for(t_min
=0;t_min
<cnt
;t_min
++)
187 if(fabs((geom_knot
->unified_knot
)[t_min
] - maximal_min_knot
) <
190 for(t_max
=cnt
-1;t_max
;t_max
--)
191 if(fabs((geom_knot
->unified_knot
)[t_max
] - minimal_max_knot
) <
196 if(geom_knot
->nknots
)
198 cnt
=geom_knot
->nknots
;
199 for(t_min
=0;t_min
<cnt
;t_min
++)
200 if(fabs((geom_knot
->knot
)[t_min
] - maximal_min_knot
) < EPSILON
)
202 for(t_max
=cnt
-1;t_max
;t_max
--)
203 if(fabs((geom_knot
->knot
)[t_max
] - minimal_max_knot
) < EPSILON
)
206 geom_knot
->t_min
=t_min
;
207 geom_knot
->t_max
=t_max
;
208 if(color_knot
->unified_knot
!=NULL
)
210 cnt
=color_knot
->unified_nknots
;
211 for(t_min
=0;t_min
<cnt
;t_min
++)
212 if(fabs((color_knot
->unified_knot
)[t_min
] - maximal_min_knot
) <
215 for(t_max
=cnt
-1;t_max
;t_max
--)
216 if(fabs((color_knot
->unified_knot
)[t_max
] - minimal_max_knot
) <
219 color_knot
->t_min
=t_min
;
220 color_knot
->t_max
=t_max
;
222 if(normal_knot
->unified_knot
!=NULL
)
224 cnt
=normal_knot
->unified_nknots
;
225 for(t_min
=0;t_min
<cnt
;t_min
++)
226 if(fabs((normal_knot
->unified_knot
)[t_min
] - maximal_min_knot
) <
229 for(t_max
=cnt
-1;t_max
;t_max
--)
230 if(fabs((normal_knot
->unified_knot
)[t_max
] - minimal_max_knot
) <
233 normal_knot
->t_min
=t_min
;
234 normal_knot
->t_max
=t_max
;
236 if(texture_knot
->unified_knot
!=NULL
)
238 cnt
=texture_knot
->unified_nknots
;
239 for(t_min
=0;t_min
<cnt
;t_min
++)
240 if(fabs((texture_knot
->unified_knot
)[t_min
] - maximal_min_knot
)
243 for(t_max
=cnt
-1;t_max
;t_max
--)
244 if(fabs((texture_knot
->unified_knot
)[t_max
] - minimal_max_knot
)
247 texture_knot
->t_min
=t_min
;
248 texture_knot
->t_max
=t_max
;
253 /* modify all knot valid ranges in such a way that all have the same */
254 /* range, common to all knots */
255 /* do this by knot insertion */
257 select_knot_working_range(GLUnurbsObj
*nobj
,knot_str_type
*geom_knot
,
258 knot_str_type
*color_knot
, knot_str_type
*normal_knot
,
259 knot_str_type
*texture_knot
)
262 GLfloat maximal_min_knot
,minimal_max_knot
;
265 /* find the maximum modified knot length */
266 max_nknots
=geom_knot
->nknots
;
267 if(color_knot
->unified_knot
)
268 max_nknots
+=color_knot
->nknots
;
269 if(normal_knot
->unified_knot
)
270 max_nknots
+=normal_knot
->nknots
;
271 if(texture_knot
->unified_knot
)
272 max_nknots
+=texture_knot
->nknots
;
273 maximal_min_knot
=(geom_knot
->knot
)[geom_knot
->t_min
];
274 minimal_max_knot
=(geom_knot
->knot
)[geom_knot
->t_max
];
275 /* any attirb data ? */
276 if(max_nknots
!=geom_knot
->nknots
)
278 /* allocate space for the unified knots */
279 if((geom_knot
->unified_knot
=
280 (GLfloat
*)malloc(sizeof(GLfloat
)*max_nknots
))==NULL
)
282 call_user_error(nobj
,GLU_OUT_OF_MEMORY
);
285 /* copy the original knot to the unified one */
286 geom_knot
->unified_nknots
=geom_knot
->nknots
;
287 for(i
=0;i
<geom_knot
->nknots
;i
++)
288 (geom_knot
->unified_knot
)[i
]=(geom_knot
->knot
)[i
];
289 if(color_knot
->unified_knot
)
291 if((color_knot
->knot
)[color_knot
->t_min
] - maximal_min_knot
>
293 maximal_min_knot
=(color_knot
->knot
)[color_knot
->t_min
];
294 if(minimal_max_knot
- (color_knot
->knot
)[color_knot
->t_max
] >
296 minimal_max_knot
=(color_knot
->knot
)[color_knot
->t_max
];
297 if((color_knot
->unified_knot
=
298 (GLfloat
*)malloc(sizeof(GLfloat
)*max_nknots
))==NULL
)
300 free(geom_knot
->unified_knot
);
301 call_user_error(nobj
,GLU_OUT_OF_MEMORY
);
304 /* copy the original knot to the unified one */
305 color_knot
->unified_nknots
=color_knot
->nknots
;
306 for(i
=0;i
<color_knot
->nknots
;i
++)
307 (color_knot
->unified_knot
)[i
]=(color_knot
->knot
)[i
];
309 if(normal_knot
->unified_knot
)
311 if((normal_knot
->knot
)[normal_knot
->t_min
] - maximal_min_knot
>
313 maximal_min_knot
=(normal_knot
->knot
)[normal_knot
->t_min
];
314 if(minimal_max_knot
- (normal_knot
->knot
)[normal_knot
->t_max
] >
316 minimal_max_knot
=(normal_knot
->knot
)[normal_knot
->t_max
];
317 if((normal_knot
->unified_knot
=
318 (GLfloat
*)malloc(sizeof(GLfloat
)*max_nknots
))==NULL
)
320 free(geom_knot
->unified_knot
);
321 free(color_knot
->unified_knot
);
322 call_user_error(nobj
,GLU_OUT_OF_MEMORY
);
325 /* copy the original knot to the unified one */
326 normal_knot
->unified_nknots
=normal_knot
->nknots
;
327 for(i
=0;i
<normal_knot
->nknots
;i
++)
328 (normal_knot
->unified_knot
)[i
]=(normal_knot
->knot
)[i
];
330 if(texture_knot
->unified_knot
)
332 if((texture_knot
->knot
)[texture_knot
->t_min
] - maximal_min_knot
>
334 maximal_min_knot
=(texture_knot
->knot
)[texture_knot
->t_min
];
335 if(minimal_max_knot
- (texture_knot
->knot
)[texture_knot
->t_max
] >
337 minimal_max_knot
=(texture_knot
->knot
)[texture_knot
->t_max
];
338 if((texture_knot
->unified_knot
=
339 (GLfloat
*)malloc(sizeof(GLfloat
)*max_nknots
))==NULL
)
341 free(geom_knot
->unified_knot
);
342 free(color_knot
->unified_knot
);
343 free(normal_knot
->unified_knot
);
344 call_user_error(nobj
,GLU_OUT_OF_MEMORY
);
347 /* copy the original knot to the unified one */
348 texture_knot
->unified_nknots
=texture_knot
->nknots
;
349 for(i
=0;i
<texture_knot
->nknots
;i
++)
350 (texture_knot
->unified_knot
)[i
]=(texture_knot
->knot
)[i
];
352 /* work on the geometry knot with all additional knot values */
353 /* appearing in attirbutive knots */
354 if(minimal_max_knot
-maximal_min_knot
< EPSILON
)
356 /* empty working range */
357 geom_knot
->unified_nknots
=0;
358 color_knot
->unified_nknots
=0;
359 normal_knot
->unified_nknots
=0;
360 texture_knot
->unified_nknots
=0;
364 if(color_knot
->unified_knot
)
365 collect_unified_knot(geom_knot
,color_knot
,maximal_min_knot
,
367 if(normal_knot
->unified_knot
)
368 collect_unified_knot(geom_knot
,normal_knot
,maximal_min_knot
,
370 if(texture_knot
->unified_knot
)
371 collect_unified_knot(geom_knot
,texture_knot
,maximal_min_knot
,
373 /* since we have now built the "unified" geometry knot */
374 /* add same knot values to all attributive knots */
375 if(color_knot
->unified_knot
)
376 collect_unified_knot(color_knot
,geom_knot
,maximal_min_knot
,
378 if(normal_knot
->unified_knot
)
379 collect_unified_knot(normal_knot
,geom_knot
,maximal_min_knot
,
381 if(texture_knot
->unified_knot
)
382 collect_unified_knot(texture_knot
,geom_knot
,maximal_min_knot
,
386 set_new_t_min_t_max(geom_knot
,color_knot
,normal_knot
,texture_knot
,
387 maximal_min_knot
,minimal_max_knot
);
392 free_unified_knots(knot_str_type
*geom_knot
, knot_str_type
*color_knot
,
393 knot_str_type
*normal_knot
, knot_str_type
*texture_knot
)
395 if(geom_knot
->unified_knot
)
396 free(geom_knot
->unified_knot
);
397 if(color_knot
->unified_knot
)
398 free(color_knot
->unified_knot
);
399 if(normal_knot
->unified_knot
)
400 free(normal_knot
->unified_knot
);
401 if(texture_knot
->unified_knot
)
402 free(texture_knot
->unified_knot
);
406 explode_knot(knot_str_type
*the_knot
)
408 GLfloat
*knot
,*new_knot
;
409 GLint nknots
,n_new_knots
=0;
415 if(the_knot
->unified_knot
)
417 knot
=the_knot
->unified_knot
;
418 nknots
=the_knot
->unified_nknots
;
423 nknots
=the_knot
->nknots
;
426 t_min
=the_knot
->t_min
;
427 t_max
=the_knot
->t_max
;
429 for(i
=t_min
;i
<=t_max
;)
432 for(j
=0;j
<ord
&& (i
+j
)<=t_max
;j
++)
433 if(fabs(tmp_float
-knot
[i
+j
])>EPSILON
)
438 /* alloc space for new_knot */
439 if((new_knot
=(GLfloat
*)malloc(sizeof(GLfloat
)*(nknots
+n_new_knots
)))==NULL
)
441 return GLU_OUT_OF_MEMORY
;
443 /* fill in new knot */
446 for(i
=j
;i
<=t_max
;i
++)
451 new_knot
[j
++]=knot
[i
];
452 if(tmp_float
==knot
[i
+1])
456 for(i
=t_max
+1;i
<(int)nknots
;i
++)
457 new_knot
[j
++]=knot
[i
];
458 /* fill in the knot structure */
459 the_knot
->new_knot
=new_knot
;
460 the_knot
->delta_nknots
+=n_new_knots
;
461 the_knot
->t_max
+=n_new_knots
;
466 calc_alphas(knot_str_type
*the_knot
)
471 GLfloat
*alpha
,*alpha_new
,*tmp_alpha
;
473 GLfloat
*knot
,*new_knot
;
477 order
=the_knot
->order
;
478 new_knot
=the_knot
->new_knot
;
479 n
=the_knot
->nknots
-the_knot
->order
;
480 m
=n
+the_knot
->delta_nknots
;
481 if((alpha
=(GLfloat
*)malloc(sizeof(GLfloat
)*n
*m
))==NULL
)
483 return GLU_OUT_OF_MEMORY
;
485 if((alpha_new
=(GLfloat
*)malloc(sizeof(GLfloat
)*n
*m
))==NULL
)
488 return GLU_OUT_OF_MEMORY
;
494 if((knot
[i
] <= new_knot
[j
]) && (new_knot
[j
] < knot
[i
+1]))
498 alpha
[i
+j
*n
]=tmp_float
;
506 denom
=knot
[i
+k
]-knot
[i
];
507 if(fabs(denom
)<EPSILON
)
510 tmp_float
=(new_knot
[j
+k
]-knot
[i
])/denom
*
512 denom
=knot
[i
+k
+1]-knot
[i
+1];
513 if(fabs(denom
)>EPSILON
)
514 tmp_float
+=(knot
[i
+k
+1]-new_knot
[j
+k
])/denom
*
516 alpha_new
[i
+j
*n
]=tmp_float
;
522 the_knot
->alpha
=alpha
;
528 calc_new_ctrl_pts(GLfloat
*ctrl
,GLint stride
,knot_str_type
*the_knot
,
529 GLint dim
,GLfloat
**new_ctrl
,GLint
*ncontrol
)
532 GLsizei index1
,index2
;
536 new_knot
=the_knot
->new_knot
;
537 n
=the_knot
->nknots
-the_knot
->order
;
538 alpha
=the_knot
->alpha
;
540 m
=the_knot
->t_max
+1-the_knot
->t_min
-the_knot
->order
;
542 /* allocate space for new control points */
543 if((*new_ctrl
=(GLfloat
*)malloc(sizeof(GLfloat
)*dim
*m
))==NULL
)
545 return GLU_OUT_OF_MEMORY
;
550 (*new_ctrl
)[j
*dim
+l
]=0.0;
556 (*new_ctrl
)[j
*dim
+l
]+=alpha
[index1
]*ctrl
[index2
+l
];
564 calc_factor(GLfloat
*pts
,GLint order
,GLint indx
,GLint stride
,GLfloat tolerance
,
567 GLdouble model
[16],proj
[16];
569 GLdouble x
,y
,z
,w
,winx1
,winy1
,winz
,winx2
,winy2
;
573 glGetDoublev(GL_MODELVIEW_MATRIX
,model
);
574 glGetDoublev(GL_PROJECTION_MATRIX
,proj
);
575 glGetIntegerv(GL_VIEWPORT
,viewport
);
578 w
=(GLdouble
)pts
[indx
+3];
579 x
=(GLdouble
)pts
[indx
]/w
;
580 y
=(GLdouble
)pts
[indx
+1]/w
;
581 z
=(GLdouble
)pts
[indx
+2]/w
;
582 gluProject(x
,y
,z
,model
,proj
,viewport
,&winx1
,&winy1
,&winz
);
586 w
=(GLdouble
)pts
[indx
+i
*stride
+3];
587 x
=(GLdouble
)pts
[indx
+i
*stride
]/w
;
588 y
=(GLdouble
)pts
[indx
+i
*stride
+1]/w
;
589 z
=(GLdouble
)pts
[indx
+i
*stride
+2]/w
;
590 if(gluProject(x
,y
,z
,model
,proj
,viewport
,&winx2
,&winy2
,&winz
))
594 len
+=sqrt(dx
*dx
+dy
*dy
);
596 winx1
=winx2
; winy1
=winy2
;
601 x
=(GLdouble
)pts
[indx
];
602 y
=(GLdouble
)pts
[indx
+1];
606 z
=(GLdouble
)pts
[indx
+2];
607 gluProject(x
,y
,z
,model
,proj
,viewport
,&winx1
,&winy1
,&winz
);
611 x
=(GLdouble
)pts
[indx
+i
*stride
];
612 y
=(GLdouble
)pts
[indx
+i
*stride
+1];
616 z
=(GLdouble
)pts
[indx
+i
*stride
+2];
617 if(gluProject(x
,y
,z
,model
,proj
,viewport
,&winx2
,&winy2
,&winz
))
621 len
+=sqrt(dx
*dx
+dy
*dy
);
623 winx1
=winx2
; winy1
=winy2
;
627 return ((GLint
)len
+1);
630 /* we can't use the Mesa evaluators - no way to get the point coords */
631 /* so we use our own Bezier point calculus routines */
632 /* because I'm lazy, I reuse the ones from eval.c */
635 bezier_curve(GLfloat
*cp
, GLfloat
*out
, GLfloat t
,
636 GLuint dim
, GLuint order
, GLint offset
)
639 GLuint i
, k
, bincoeff
;
647 out
[k
] = s
*cp
[k
] + bincoeff
*t
*cp
[offset
+k
];
649 for(i
=2, cp
+=2*offset
, powert
=t
*t
; i
<order
; i
++, powert
*=t
, cp
+=offset
)
655 out
[k
] = s
*out
[k
] + bincoeff
*powert
*cp
[k
];
658 else /* order=1 -> constant curve */
666 calc_parametric_factor(GLfloat
*pts
,GLint order
,GLint indx
,GLint stride
,
667 GLfloat tolerance
,GLint dim
)
669 GLdouble model
[16],proj
[16];
671 GLdouble x
,y
,z
,w
,x1
,y1
,z1
,x2
,y2
,z2
,x3
,y3
,z3
;
675 GLdouble len
=0.0,tmp
,z_med
;
678 glGetDoublev(GL_MODELVIEW_MATRIX
,model
);
679 glGetDoublev(GL_PROJECTION_MATRIX
,proj
);
680 glGetIntegerv(GL_VIEWPORT
,viewport
);
681 z_med
= (viewport
[2] + viewport
[3]) * 0.5;
687 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)i
/(GLfloat
)P
, 4,
689 w
= (GLdouble
)bez_pt
[3];
690 x
= (GLdouble
)bez_pt
[0] / w
;
691 y
= (GLdouble
)bez_pt
[1] / w
;
692 z
= (GLdouble
)bez_pt
[2] / w
;
693 gluProject(x
,y
,z
,model
,proj
,viewport
,&x3
,&y3
,&z3
);
695 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)(i
-1)/(GLfloat
)P
, 4,
697 w
= (GLdouble
)bez_pt
[3];
698 x
= (GLdouble
)bez_pt
[0] / w
;
699 y
= (GLdouble
)bez_pt
[1] / w
;
700 z
= (GLdouble
)bez_pt
[2] / w
;
701 gluProject(x
,y
,z
,model
,proj
,viewport
,&x1
,&y1
,&z1
);
703 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)(i
+1)/(GLfloat
)P
, 4,
705 w
= (GLdouble
)bez_pt
[3];
706 x
= (GLdouble
)bez_pt
[0] / w
;
707 y
= (GLdouble
)bez_pt
[1] / w
;
708 z
= (GLdouble
)bez_pt
[2] / w
;
709 gluProject(x
,y
,z
,model
,proj
,viewport
,&x2
,&y2
,&z2
);
711 /* calc distance between point (x3,y3,z3) and line segment */
712 /* <x1,y1,z1><x2,y2,z2> */
716 tmp
= sqrt(x
*x
+y
*y
+z
*z
);
720 tmp
= x3
*x
+y3
*y
+z3
*z
-x1
*x
-y1
*y
-z1
*z
;
724 tmp
= sqrt(x
*x
+y
*y
+z
*z
);
732 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)i
/(GLfloat
)P
, 3,
734 x
= (GLdouble
)bez_pt
[0];
735 y
= (GLdouble
)bez_pt
[1];
736 z
= (GLdouble
)bez_pt
[2];
737 gluProject(x
,y
,z
,model
,proj
,viewport
,&x3
,&y3
,&z3
);
739 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)(i
-1)/(GLfloat
)P
, 3,
741 x
= (GLdouble
)bez_pt
[0];
742 y
= (GLdouble
)bez_pt
[1];
743 z
= (GLdouble
)bez_pt
[2];
744 gluProject(x
,y
,z
,model
,proj
,viewport
,&x1
,&y1
,&z1
);
746 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)(i
+1)/(GLfloat
)P
, 3,
748 x
= (GLdouble
)bez_pt
[0];
749 y
= (GLdouble
)bez_pt
[1];
750 z
= (GLdouble
)bez_pt
[2];
751 gluProject(x
,y
,z
,model
,proj
,viewport
,&x2
,&y2
,&z2
);
753 /* calc distance between point (x3,y3,z3) and line segment */
754 /* <x1,y1,z1><x2,y2,z2> */
758 tmp
= sqrt(x
*x
+y
*y
+z
*z
);
762 tmp
= x3
*x
+y3
*y
+z3
*z
-x1
*x
-y1
*y
-z1
*z
;
766 tmp
= sqrt(x
*x
+y
*y
+z
*z
);
774 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)i
/(GLfloat
)P
, 2,
776 x
= (GLdouble
)bez_pt
[0];
777 y
= (GLdouble
)bez_pt
[1];
779 gluProject(x
,y
,z
,model
,proj
,viewport
,&x3
,&y3
,&z3
);
781 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)(i
-1)/(GLfloat
)P
, 2,
783 x
= (GLdouble
)bez_pt
[0];
784 y
= (GLdouble
)bez_pt
[1];
786 gluProject(x
,y
,z
,model
,proj
,viewport
,&x1
,&y1
,&z1
);
788 bezier_curve(pts
+indx
, bez_pt
, (GLfloat
)(i
+1)/(GLfloat
)P
, 2,
790 x
= (GLdouble
)bez_pt
[0];
791 y
= (GLdouble
)bez_pt
[1];
793 gluProject(x
,y
,z
,model
,proj
,viewport
,&x2
,&y2
,&z2
);
795 /* calc distance between point (x3,y3,z3) and line segment */
796 /* <x1,y1,z1><x2,y2,z2> */
800 tmp
= sqrt(x
*x
+y
*y
+z
*z
);
804 tmp
= x3
*x
+y3
*y
+z3
*z
-x1
*x
-y1
*y
-z1
*z
;
808 tmp
= sqrt(x
*x
+y
*y
+z
*z
);
818 return (GLint
)(sqrt(len
/tolerance
)*(order
+2)+1);
822 calc_sampling_3D(new_ctrl_type
*new_ctrl
, GLfloat tolerance
, GLint dim
,
823 GLint uorder
, GLint vorder
, GLint
**ufactors
, GLint
**vfactors
)
826 GLint tmp_factor1
,tmp_factor2
;
827 GLint ufactor_cnt
,vfactor_cnt
;
828 GLint offset1
,offset2
,offset3
;
831 ufactor_cnt
=new_ctrl
->s_bezier_cnt
;
832 vfactor_cnt
=new_ctrl
->t_bezier_cnt
;
833 if((*ufactors
=(GLint
*)malloc(sizeof(GLint
)*ufactor_cnt
*3))
836 return GLU_OUT_OF_MEMORY
;
838 if((*vfactors
=(GLint
*)malloc(sizeof(GLint
)*vfactor_cnt
*3))
842 return GLU_OUT_OF_MEMORY
;
844 ctrl
=new_ctrl
->geom_ctrl
;
845 offset1
=new_ctrl
->geom_t_stride
*vorder
;
846 offset2
=new_ctrl
->geom_s_stride
*uorder
;
847 for(j
=0;j
<vfactor_cnt
;j
++)
849 *(*vfactors
+j
*3+1)=tmp_factor1
=calc_factor(ctrl
,vorder
,
850 j
*offset1
,dim
,tolerance
,dim
);
851 /* loop ufactor_cnt-1 times */
852 for(i
=1;i
<ufactor_cnt
;i
++)
854 tmp_factor2
=calc_factor(ctrl
,vorder
,
855 j
*offset1
+i
*offset2
,dim
,tolerance
,dim
);
856 if(tmp_factor2
>tmp_factor1
)
857 tmp_factor1
=tmp_factor2
;
859 /* last time for the opposite edge */
860 *(*vfactors
+j
*3+2)=tmp_factor2
=calc_factor(ctrl
,vorder
,
861 j
*offset1
+i
*offset2
-new_ctrl
->geom_s_stride
,
863 if(tmp_factor2
>tmp_factor1
)
864 *(*vfactors
+j
*3)=tmp_factor2
;
866 *(*vfactors
+j
*3)=tmp_factor1
;
868 offset3
=new_ctrl
->geom_s_stride
;
869 offset2
=new_ctrl
->geom_s_stride
*uorder
;
870 for(j
=0;j
<ufactor_cnt
;j
++)
872 *(*ufactors
+j
*3+1)=tmp_factor1
=calc_factor(ctrl
,uorder
,
873 j
*offset2
,offset3
,tolerance
,dim
);
874 /* loop vfactor_cnt-1 times */
875 for(i
=1;i
<vfactor_cnt
;i
++)
877 tmp_factor2
=calc_factor(ctrl
,uorder
,
878 j
*offset2
+i
*offset1
,offset3
,tolerance
,dim
);
879 if(tmp_factor2
>tmp_factor1
)
880 tmp_factor1
=tmp_factor2
;
882 /* last time for the opposite edge */
883 *(*ufactors
+j
*3+2)=tmp_factor2
=calc_factor(ctrl
,uorder
,
884 j
*offset2
+i
*offset1
-new_ctrl
->geom_t_stride
,
885 offset3
,tolerance
,dim
);
886 if(tmp_factor2
>tmp_factor1
)
887 *(*ufactors
+j
*3)=tmp_factor2
;
889 *(*ufactors
+j
*3)=tmp_factor1
;
895 calc_sampling_param_3D(new_ctrl_type
*new_ctrl
, GLfloat tolerance
, GLint dim
,
896 GLint uorder
, GLint vorder
, GLint
**ufactors
, GLint
**vfactors
)
899 GLint tmp_factor1
,tmp_factor2
;
900 GLint ufactor_cnt
,vfactor_cnt
;
901 GLint offset1
,offset2
,offset3
;
904 ufactor_cnt
=new_ctrl
->s_bezier_cnt
;
905 vfactor_cnt
=new_ctrl
->t_bezier_cnt
;
906 if((*ufactors
=(GLint
*)malloc(sizeof(GLint
)*ufactor_cnt
*3))
909 return GLU_OUT_OF_MEMORY
;
911 if((*vfactors
=(GLint
*)malloc(sizeof(GLint
)*vfactor_cnt
*3))
915 return GLU_OUT_OF_MEMORY
;
917 ctrl
=new_ctrl
->geom_ctrl
;
918 offset1
=new_ctrl
->geom_t_stride
*vorder
;
919 offset2
=new_ctrl
->geom_s_stride
*uorder
;
920 for(j
=0;j
<vfactor_cnt
;j
++)
922 *(*vfactors
+j
*3+1)=tmp_factor1
=calc_parametric_factor(ctrl
,vorder
,
923 j
*offset1
,dim
,tolerance
,dim
);
924 /* loop ufactor_cnt-1 times */
925 for(i
=1;i
<ufactor_cnt
;i
++)
927 tmp_factor2
=calc_parametric_factor(ctrl
,vorder
,
928 j
*offset1
+i
*offset2
,dim
,tolerance
,dim
);
929 if(tmp_factor2
>tmp_factor1
)
930 tmp_factor1
=tmp_factor2
;
932 /* last time for the opposite edge */
933 *(*vfactors
+j
*3+2)=tmp_factor2
=calc_parametric_factor(ctrl
,vorder
,
934 j
*offset1
+i
*offset2
-new_ctrl
->geom_s_stride
,
936 if(tmp_factor2
>tmp_factor1
)
937 *(*vfactors
+j
*3)=tmp_factor2
;
939 *(*vfactors
+j
*3)=tmp_factor1
;
941 offset3
=new_ctrl
->geom_s_stride
;
942 offset2
=new_ctrl
->geom_s_stride
*uorder
;
943 for(j
=0;j
<ufactor_cnt
;j
++)
945 *(*ufactors
+j
*3+1)=tmp_factor1
=calc_parametric_factor(ctrl
,uorder
,
946 j
*offset2
,offset3
,tolerance
,dim
);
947 /* loop vfactor_cnt-1 times */
948 for(i
=1;i
<vfactor_cnt
;i
++)
950 tmp_factor2
=calc_parametric_factor(ctrl
,uorder
,
951 j
*offset2
+i
*offset1
,offset3
,tolerance
,dim
);
952 if(tmp_factor2
>tmp_factor1
)
953 tmp_factor1
=tmp_factor2
;
955 /* last time for the opposite edge */
956 *(*ufactors
+j
*3+2)=tmp_factor2
=calc_parametric_factor(ctrl
,uorder
,
957 j
*offset2
+i
*offset1
-new_ctrl
->geom_t_stride
,
958 offset3
,tolerance
,dim
);
959 if(tmp_factor2
>tmp_factor1
)
960 *(*ufactors
+j
*3)=tmp_factor2
;
962 *(*ufactors
+j
*3)=tmp_factor1
;
968 calc_sampling_2D(GLfloat
*ctrl
, GLint cnt
, GLint order
,
969 GLfloat tolerance
, GLint dim
, GLint
**factors
)
976 factor_cnt
=cnt
/order
;
977 if((*factors
=(GLint
*)malloc(sizeof(GLint
)*factor_cnt
))==NULL
)
979 return GLU_OUT_OF_MEMORY
;
982 for(i
=0;i
<factor_cnt
;i
++)
984 tmp_factor
=calc_factor(ctrl
,order
,i
*offset
,dim
,tolerance
,dim
);
988 (*factors
)[i
]=tmp_factor
;
994 set_sampling_and_culling( GLUnurbsObj
*nobj
)
996 if(nobj
->auto_load_matrix
==GL_FALSE
)
1001 glPushAttrib( (GLbitfield
) (GL_VIEWPORT_BIT
| GL_TRANSFORM_BIT
));
1003 m
[i
]=nobj
->sampling_matrices
.viewport
[i
];
1004 glViewport(m
[0],m
[1],m
[2],m
[3]);
1005 glMatrixMode(GL_PROJECTION
);
1007 glLoadMatrixf(nobj
->sampling_matrices
.proj
);
1008 glMatrixMode(GL_MODELVIEW
);
1010 glLoadMatrixf(nobj
->sampling_matrices
.model
);
1015 revert_sampling_and_culling( GLUnurbsObj
*nobj
)
1017 if(nobj
->auto_load_matrix
==GL_FALSE
)
1019 glMatrixMode(GL_MODELVIEW
);
1021 glMatrixMode(GL_PROJECTION
);
1028 glu_do_sampling_3D( GLUnurbsObj
*nobj
, new_ctrl_type
*new_ctrl
,
1029 GLint
**sfactors
, GLint
**tfactors
)
1036 dim
=nobj
->surface
.geom
.dim
;
1037 set_sampling_and_culling(nobj
);
1038 if((err
=calc_sampling_3D(new_ctrl
,nobj
->sampling_tolerance
,dim
,
1039 nobj
->surface
.geom
.sorder
,nobj
->surface
.geom
.torder
,
1040 sfactors
,tfactors
))==GLU_ERROR
)
1042 revert_sampling_and_culling(nobj
);
1043 call_user_error(nobj
,err
);
1046 revert_sampling_and_culling(nobj
);
1047 return GLU_NO_ERROR
;
1051 glu_do_sampling_uv( GLUnurbsObj
*nobj
, new_ctrl_type
*new_ctrl
,
1052 GLint
**sfactors
, GLint
**tfactors
)
1054 GLint s_cnt
, t_cnt
, i
;
1055 GLint u_steps
, v_steps
;
1057 s_cnt
= new_ctrl
->s_bezier_cnt
;
1058 t_cnt
= new_ctrl
->t_bezier_cnt
;
1061 if((*sfactors
=(GLint
*)malloc(sizeof(GLint
)*s_cnt
*3))
1064 return GLU_OUT_OF_MEMORY
;
1066 if((*tfactors
=(GLint
*)malloc(sizeof(GLint
)*t_cnt
*3))
1070 return GLU_OUT_OF_MEMORY
;
1072 u_steps
= nobj
->u_step
;
1073 v_steps
= nobj
->v_step
;
1074 for(i
=0; i
<s_cnt
; i
++)
1076 *(*sfactors
+i
*3) = u_steps
;
1077 *(*sfactors
+i
*3+1) = u_steps
;
1078 *(*sfactors
+i
*3+2) = u_steps
;
1080 for(i
=0; i
<t_cnt
; i
++)
1082 *(*tfactors
+i
*3) = v_steps
;
1083 *(*tfactors
+i
*3+1) = v_steps
;
1084 *(*tfactors
+i
*3+2) = v_steps
;
1086 return GLU_NO_ERROR
;
1090 glu_do_sampling_param_3D( GLUnurbsObj
*nobj
, new_ctrl_type
*new_ctrl
,
1091 GLint
**sfactors
, GLint
**tfactors
)
1098 dim
=nobj
->surface
.geom
.dim
;
1099 set_sampling_and_culling(nobj
);
1100 if((err
=calc_sampling_param_3D(new_ctrl
,nobj
->parametric_tolerance
,dim
,
1101 nobj
->surface
.geom
.sorder
,nobj
->surface
.geom
.torder
,
1102 sfactors
,tfactors
))==GLU_ERROR
)
1104 revert_sampling_and_culling(nobj
);
1105 call_user_error(nobj
,err
);
1108 revert_sampling_and_culling(nobj
);
1109 return GLU_NO_ERROR
;
1113 glu_do_sampling_2D( GLUnurbsObj
*nobj
, GLfloat
*ctrl
, GLint cnt
, GLint order
,
1114 GLint dim
, GLint
**factors
)
1118 set_sampling_and_culling(nobj
);
1119 err
=calc_sampling_2D(ctrl
,cnt
,order
,nobj
->sampling_tolerance
,dim
,
1121 revert_sampling_and_culling(nobj
);
1127 glu_do_sampling_u( GLUnurbsObj
*nobj
, GLfloat
*ctrl
, GLint cnt
, GLint order
,
1128 GLint dim
, GLint
**factors
)
1134 if((*factors
=(GLint
*)malloc(sizeof(GLint
)*cnt
))
1137 return GLU_OUT_OF_MEMORY
;
1139 u_steps
= nobj
->u_step
;
1140 for(i
=0; i
<cnt
; i
++)
1141 (*factors
)[i
] = u_steps
;
1142 return GLU_NO_ERROR
;
1146 glu_do_sampling_param_2D( GLUnurbsObj
*nobj
, GLfloat
*ctrl
, GLint cnt
,
1147 GLint order
, GLint dim
, GLint
**factors
)
1153 set_sampling_and_culling(nobj
);
1154 tolerance
= nobj
->parametric_tolerance
;
1156 if((*factors
=(GLint
*)malloc(sizeof(GLint
)*cnt
))
1159 revert_sampling_and_culling(nobj
);
1160 return GLU_OUT_OF_MEMORY
;
1162 u_steps
= nobj
->u_step
;
1163 for(i
=0; i
<cnt
; i
++)
1165 (*factors
)[i
] = calc_parametric_factor(ctrl
,order
,0,
1169 revert_sampling_and_culling(nobj
);
1170 return GLU_NO_ERROR
;
1174 glu_do_sampling_crv( GLUnurbsObj
*nobj
, GLfloat
*ctrl
, GLint cnt
, GLint order
,
1175 GLint dim
, GLint
**factors
)
1180 switch(nobj
->sampling_method
)
1182 case GLU_PATH_LENGTH
:
1183 if((err
=glu_do_sampling_2D(nobj
,ctrl
,cnt
,order
,dim
,factors
))!=
1186 call_user_error(nobj
,err
);
1190 case GLU_DOMAIN_DISTANCE
:
1191 if((err
=glu_do_sampling_u(nobj
,ctrl
,cnt
,order
,dim
,factors
))!=
1194 call_user_error(nobj
,err
);
1198 case GLU_PARAMETRIC_ERROR
:
1199 if((err
=glu_do_sampling_param_2D(nobj
,ctrl
,cnt
,order
,dim
,factors
))!=
1202 call_user_error(nobj
,err
);
1210 return GLU_NO_ERROR
;
1213 /* TODO - i don't like this culling - this one just tests if at least one */
1214 /* ctrl point lies within the viewport . Also the point_in_viewport() */
1215 /* should be included in the fnctions for efficiency reasons */
1218 point_in_viewport(GLfloat
*pt
, GLint dim
)
1220 GLdouble model
[16],proj
[16];
1222 GLdouble x
,y
,z
,w
,winx
,winy
,winz
;
1224 glGetDoublev(GL_MODELVIEW_MATRIX
,model
);
1225 glGetDoublev(GL_PROJECTION_MATRIX
,proj
);
1226 glGetIntegerv(GL_VIEWPORT
,viewport
);
1232 gluProject(x
,y
,z
,model
,proj
,viewport
,&winx
,&winy
,&winz
);
1237 x
=(GLdouble
)pt
[0]/w
;
1238 y
=(GLdouble
)pt
[1]/w
;
1239 z
=(GLdouble
)pt
[2]/w
;
1240 gluProject(x
,y
,z
,model
,proj
,viewport
,&winx
,&winy
,&winz
);
1242 if((GLint
)winx
>= viewport
[0] && (GLint
)winx
< viewport
[2] &&
1243 (GLint
)winy
>= viewport
[1] && (GLint
)winy
< viewport
[3])
1249 fine_culling_test_3D(GLUnurbsObj
*nobj
,GLfloat
*pts
,GLint s_cnt
,GLint t_cnt
,
1250 GLint s_stride
,GLint t_stride
, GLint dim
)
1254 if(nobj
->culling
==GL_FALSE
)
1256 set_sampling_and_culling(nobj
);
1260 for(i
=0;i
<s_cnt
;i
++)
1261 for(j
=0;j
<t_cnt
;j
++)
1262 if(point_in_viewport(pts
+i
*s_stride
+j
*t_stride
,dim
))
1264 revert_sampling_and_culling(nobj
);
1270 for(i
=0;i
<s_cnt
;i
++)
1271 for(j
=0;j
<t_cnt
;j
++)
1272 if(point_in_viewport(pts
+i
*s_stride
+j
*t_stride
,dim
))
1274 revert_sampling_and_culling(nobj
);
1278 revert_sampling_and_culling(nobj
);
1283 fine_culling_test_3D(GLUnurbsObj *nobj,GLfloat *pts,GLint s_cnt,GLint t_cnt,
1284 GLint s_stride,GLint t_stride, GLint dim)
1287 GLfloat feedback_buffer[5];
1288 GLsizei buffer_size;
1291 if(nobj->culling==GL_FALSE)
1294 set_sampling_and_culling(nobj);
1296 glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer);
1297 glRenderMode(GL_FEEDBACK);
1300 for(i=0;i<s_cnt;i++)
1302 glBegin(GL_LINE_LOOP);
1303 for(j=0;j<t_cnt;j++)
1304 glVertex3fv(pts+i*s_stride+j*t_stride);
1307 for(j=0;j<t_cnt;j++)
1309 glBegin(GL_LINE_LOOP);
1310 for(i=0;i<s_cnt;i++)
1311 glVertex3fv(pts+i*s_stride+j*t_stride);
1317 for(i=0;i<s_cnt;i++)
1319 glBegin(GL_LINE_LOOP);
1320 for(j=0;j<t_cnt;j++)
1321 glVertex4fv(pts+i*s_stride+j*t_stride);
1324 for(j=0;j<t_cnt;j++)
1326 glBegin(GL_LINE_LOOP);
1327 for(i=0;i<s_cnt;i++)
1328 glVertex4fv(pts+i*s_stride+j*t_stride);
1332 visible_cnt=glRenderMode(GL_RENDER);
1334 revert_sampling_and_culling(nobj);
1335 return (GLboolean)(visible_cnt==0);
1339 fine_culling_test_2D(GLUnurbsObj
*nobj
,GLfloat
*pts
,GLint cnt
,
1340 GLint stride
, GLint dim
)
1344 if(nobj
->culling
==GL_FALSE
)
1346 set_sampling_and_culling(nobj
);
1351 if(point_in_viewport(pts
+i
*stride
,dim
))
1353 revert_sampling_and_culling(nobj
);
1360 if(point_in_viewport(pts
+i
*stride
,dim
))
1362 revert_sampling_and_culling(nobj
);
1366 revert_sampling_and_culling(nobj
);
1371 fine_culling_test_2D(GLUnurbsObj *nobj,GLfloat *pts,GLint cnt,
1372 GLint stride, GLint dim)
1375 GLfloat feedback_buffer[5];
1376 GLsizei buffer_size;
1379 if(nobj->culling==GL_FALSE)
1382 set_sampling_and_culling(nobj);
1384 glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer);
1385 glRenderMode(GL_FEEDBACK);
1386 glBegin(GL_LINE_LOOP);
1390 glVertex3fv(pts+i*stride);
1395 glVertex4fv(pts+i*stride);
1398 visible_cnt=glRenderMode(GL_RENDER);
1400 revert_sampling_and_culling(nobj);
1401 return (GLboolean)(visible_cnt==0);