Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
55 | pj | 1 | /* $Id: nurbsutl.c,v 1.1 2003-02-28 11:42:07 pj Exp $ */ |
2 | |||
3 | /* |
||
4 | * Mesa 3-D graphics library |
||
5 | * Version: 3.3 |
||
6 | * Copyright (C) 1995-2000 Brian Paul |
||
7 | * |
||
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. |
||
12 | * |
||
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. |
||
17 | * |
||
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. |
||
21 | */ |
||
22 | |||
23 | |||
24 | /* |
||
25 | * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it) |
||
26 | * See README2 for more info. |
||
27 | */ |
||
28 | |||
29 | |||
30 | #ifdef PC_HEADER |
||
31 | #include "all.h" |
||
32 | #else |
||
33 | #include <math.h> |
||
34 | #include <stdlib.h> |
||
35 | #include "gluP.h" |
||
36 | #include "nurbs.h" |
||
37 | #endif |
||
38 | |||
39 | |||
40 | GLenum test_knot(GLint nknots, GLfloat * knot, GLint order) |
||
41 | { |
||
42 | GLsizei i; |
||
43 | GLint knot_mult; |
||
44 | GLfloat tmp_knot; |
||
45 | |||
46 | tmp_knot = knot[0]; |
||
47 | knot_mult = 1; |
||
48 | for (i = 1; i < nknots; i++) { |
||
49 | if (knot[i] < tmp_knot) |
||
50 | return GLU_NURBS_ERROR4; |
||
51 | if (fabs(tmp_knot - knot[i]) > EPSILON) { |
||
52 | if (knot_mult > order) |
||
53 | return GLU_NURBS_ERROR5; |
||
54 | knot_mult = 1; |
||
55 | tmp_knot = knot[i]; |
||
56 | } |
||
57 | else |
||
58 | ++knot_mult; |
||
59 | } |
||
60 | return GLU_NO_ERROR; |
||
61 | } |
||
62 | |||
63 | static int |
||
64 | /* qsort function */ |
||
65 | #if defined(WIN32) && !defined(OPENSTEP) |
||
66 | __cdecl |
||
67 | #endif |
||
68 | knot_sort(const void *a, const void *b) |
||
69 | { |
||
70 | GLfloat x, y; |
||
71 | |||
72 | x = *((GLfloat *) a); |
||
73 | y = *((GLfloat *) b); |
||
74 | if (fabs(x - y) < EPSILON) |
||
75 | return 0; |
||
76 | if (x > y) |
||
77 | return 1; |
||
78 | return -1; |
||
79 | } |
||
80 | |||
81 | /* insert into dest knot all values within the valid range from src knot */ |
||
82 | /* that do not appear in dest */ |
||
83 | void |
||
84 | collect_unified_knot(knot_str_type * dest, knot_str_type * src, |
||
85 | GLfloat maximal_min_knot, GLfloat minimal_max_knot) |
||
86 | { |
||
87 | GLfloat *src_knot, *dest_knot; |
||
88 | GLint src_t_min, src_t_max, dest_t_min, dest_t_max; |
||
89 | GLint src_nknots, dest_nknots; |
||
90 | GLint i, j, k, new_cnt; |
||
91 | GLboolean not_found_flag; |
||
92 | |||
93 | src_knot = src->unified_knot; |
||
94 | dest_knot = dest->unified_knot; |
||
95 | src_t_min = src->t_min; |
||
96 | src_t_max = src->t_max; |
||
97 | dest_t_min = dest->t_min; |
||
98 | dest_t_max = dest->t_max; |
||
99 | src_nknots = src->unified_nknots; |
||
100 | dest_nknots = dest->unified_nknots; |
||
101 | |||
102 | k = new_cnt = dest_nknots; |
||
103 | for (i = src_t_min; i <= src_t_max; i++) |
||
104 | if (src_knot[i] - maximal_min_knot > -EPSILON && |
||
105 | src_knot[i] - minimal_max_knot < EPSILON) { |
||
106 | not_found_flag = GL_TRUE; |
||
107 | for (j = dest_t_min; j <= dest_t_max; j++) |
||
108 | if (fabs(dest_knot[j] - src_knot[i]) < EPSILON) { |
||
109 | not_found_flag = GL_FALSE; |
||
110 | break; |
||
111 | } |
||
112 | if (not_found_flag) { |
||
113 | /* knot from src is not in dest - add this knot to dest */ |
||
114 | dest_knot[k++] = src_knot[i]; |
||
115 | ++new_cnt; |
||
116 | ++(dest->t_max); /* the valid range widens */ |
||
117 | ++(dest->delta_nknots); /* increment the extra knot value counter */ |
||
118 | } |
||
119 | } |
||
120 | dest->unified_nknots = new_cnt; |
||
121 | qsort((void *) dest_knot, (size_t) new_cnt, (size_t) sizeof(GLfloat), |
||
122 | &knot_sort); |
||
123 | } |
||
124 | |||
125 | /* basing on the new common knot range for all attributes set */ |
||
126 | /* t_min and t_max values for each knot - they will be used later on */ |
||
127 | /* by explode_knot() and calc_new_ctrl_pts */ |
||
128 | static void |
||
129 | set_new_t_min_t_max(knot_str_type * geom_knot, knot_str_type * color_knot, |
||
130 | knot_str_type * normal_knot, knot_str_type * texture_knot, |
||
131 | GLfloat maximal_min_knot, GLfloat minimal_max_knot) |
||
132 | { |
||
133 | GLuint t_min = 0, t_max = 0, cnt = 0; |
||
134 | |||
135 | if (minimal_max_knot - maximal_min_knot < EPSILON) { |
||
136 | /* knot common range empty */ |
||
137 | geom_knot->t_min = geom_knot->t_max = 0; |
||
138 | color_knot->t_min = color_knot->t_max = 0; |
||
139 | normal_knot->t_min = normal_knot->t_max = 0; |
||
140 | texture_knot->t_min = texture_knot->t_max = 0; |
||
141 | } |
||
142 | else { |
||
143 | if (geom_knot->unified_knot != NULL) { |
||
144 | cnt = geom_knot->unified_nknots; |
||
145 | for (t_min = 0; t_min < cnt; t_min++) |
||
146 | if (fabs((geom_knot->unified_knot)[t_min] - maximal_min_knot) < |
||
147 | EPSILON) break; |
||
148 | for (t_max = cnt - 1; t_max; t_max--) |
||
149 | if (fabs((geom_knot->unified_knot)[t_max] - minimal_max_knot) < |
||
150 | EPSILON) break; |
||
151 | } |
||
152 | else if (geom_knot->nknots) { |
||
153 | cnt = geom_knot->nknots; |
||
154 | for (t_min = 0; t_min < cnt; t_min++) |
||
155 | if (fabs((geom_knot->knot)[t_min] - maximal_min_knot) < EPSILON) |
||
156 | break; |
||
157 | for (t_max = cnt - 1; t_max; t_max--) |
||
158 | if (fabs((geom_knot->knot)[t_max] - minimal_max_knot) < EPSILON) |
||
159 | break; |
||
160 | } |
||
161 | geom_knot->t_min = t_min; |
||
162 | geom_knot->t_max = t_max; |
||
163 | if (color_knot->unified_knot != NULL) { |
||
164 | cnt = color_knot->unified_nknots; |
||
165 | for (t_min = 0; t_min < cnt; t_min++) |
||
166 | if (fabs((color_knot->unified_knot)[t_min] - maximal_min_knot) < |
||
167 | EPSILON) break; |
||
168 | for (t_max = cnt - 1; t_max; t_max--) |
||
169 | if (fabs((color_knot->unified_knot)[t_max] - minimal_max_knot) < |
||
170 | EPSILON) break; |
||
171 | color_knot->t_min = t_min; |
||
172 | color_knot->t_max = t_max; |
||
173 | } |
||
174 | if (normal_knot->unified_knot != NULL) { |
||
175 | cnt = normal_knot->unified_nknots; |
||
176 | for (t_min = 0; t_min < cnt; t_min++) |
||
177 | if (fabs((normal_knot->unified_knot)[t_min] - maximal_min_knot) < |
||
178 | EPSILON) break; |
||
179 | for (t_max = cnt - 1; t_max; t_max--) |
||
180 | if (fabs((normal_knot->unified_knot)[t_max] - minimal_max_knot) < |
||
181 | EPSILON) break; |
||
182 | normal_knot->t_min = t_min; |
||
183 | normal_knot->t_max = t_max; |
||
184 | } |
||
185 | if (texture_knot->unified_knot != NULL) { |
||
186 | cnt = texture_knot->unified_nknots; |
||
187 | for (t_min = 0; t_min < cnt; t_min++) |
||
188 | if (fabs((texture_knot->unified_knot)[t_min] - maximal_min_knot) |
||
189 | < EPSILON) |
||
190 | break; |
||
191 | for (t_max = cnt - 1; t_max; t_max--) |
||
192 | if (fabs((texture_knot->unified_knot)[t_max] - minimal_max_knot) |
||
193 | < EPSILON) |
||
194 | break; |
||
195 | texture_knot->t_min = t_min; |
||
196 | texture_knot->t_max = t_max; |
||
197 | } |
||
198 | } |
||
199 | } |
||
200 | |||
201 | /* modify all knot valid ranges in such a way that all have the same */ |
||
202 | /* range, common to all knots */ |
||
203 | /* do this by knot insertion */ |
||
204 | GLenum |
||
205 | select_knot_working_range(GLUnurbsObj * nobj, knot_str_type * geom_knot, |
||
206 | knot_str_type * color_knot, |
||
207 | knot_str_type * normal_knot, |
||
208 | knot_str_type * texture_knot) |
||
209 | { |
||
210 | GLint max_nknots; |
||
211 | GLfloat maximal_min_knot, minimal_max_knot; |
||
212 | GLint i; |
||
213 | |||
214 | /* find the maximum modified knot length */ |
||
215 | max_nknots = geom_knot->nknots; |
||
216 | if (color_knot->unified_knot) |
||
217 | max_nknots += color_knot->nknots; |
||
218 | if (normal_knot->unified_knot) |
||
219 | max_nknots += normal_knot->nknots; |
||
220 | if (texture_knot->unified_knot) |
||
221 | max_nknots += texture_knot->nknots; |
||
222 | maximal_min_knot = (geom_knot->knot)[geom_knot->t_min]; |
||
223 | minimal_max_knot = (geom_knot->knot)[geom_knot->t_max]; |
||
224 | /* any attirb data ? */ |
||
225 | if (max_nknots != geom_knot->nknots) { |
||
226 | /* allocate space for the unified knots */ |
||
227 | if ((geom_knot->unified_knot = |
||
228 | (GLfloat *) malloc(sizeof(GLfloat) * max_nknots)) == NULL) { |
||
229 | call_user_error(nobj, GLU_OUT_OF_MEMORY); |
||
230 | return GLU_ERROR; |
||
231 | } |
||
232 | /* copy the original knot to the unified one */ |
||
233 | geom_knot->unified_nknots = geom_knot->nknots; |
||
234 | for (i = 0; i < geom_knot->nknots; i++) |
||
235 | (geom_knot->unified_knot)[i] = (geom_knot->knot)[i]; |
||
236 | if (color_knot->unified_knot) { |
||
237 | if ((color_knot->knot)[color_knot->t_min] - maximal_min_knot > |
||
238 | EPSILON) |
||
239 | maximal_min_knot = (color_knot->knot)[color_knot->t_min]; |
||
240 | if (minimal_max_knot - (color_knot->knot)[color_knot->t_max] > |
||
241 | EPSILON) |
||
242 | minimal_max_knot = (color_knot->knot)[color_knot->t_max]; |
||
243 | if ((color_knot->unified_knot = |
||
244 | (GLfloat *) malloc(sizeof(GLfloat) * max_nknots)) == NULL) { |
||
245 | free(geom_knot->unified_knot); |
||
246 | call_user_error(nobj, GLU_OUT_OF_MEMORY); |
||
247 | return GLU_ERROR; |
||
248 | } |
||
249 | /* copy the original knot to the unified one */ |
||
250 | color_knot->unified_nknots = color_knot->nknots; |
||
251 | for (i = 0; i < color_knot->nknots; i++) |
||
252 | (color_knot->unified_knot)[i] = (color_knot->knot)[i]; |
||
253 | } |
||
254 | if (normal_knot->unified_knot) { |
||
255 | if ((normal_knot->knot)[normal_knot->t_min] - maximal_min_knot > |
||
256 | EPSILON) |
||
257 | maximal_min_knot = (normal_knot->knot)[normal_knot->t_min]; |
||
258 | if (minimal_max_knot - (normal_knot->knot)[normal_knot->t_max] > |
||
259 | EPSILON) |
||
260 | minimal_max_knot = (normal_knot->knot)[normal_knot->t_max]; |
||
261 | if ((normal_knot->unified_knot = |
||
262 | (GLfloat *) malloc(sizeof(GLfloat) * max_nknots)) == NULL) { |
||
263 | free(geom_knot->unified_knot); |
||
264 | free(color_knot->unified_knot); |
||
265 | call_user_error(nobj, GLU_OUT_OF_MEMORY); |
||
266 | return GLU_ERROR; |
||
267 | } |
||
268 | /* copy the original knot to the unified one */ |
||
269 | normal_knot->unified_nknots = normal_knot->nknots; |
||
270 | for (i = 0; i < normal_knot->nknots; i++) |
||
271 | (normal_knot->unified_knot)[i] = (normal_knot->knot)[i]; |
||
272 | } |
||
273 | if (texture_knot->unified_knot) { |
||
274 | if ((texture_knot->knot)[texture_knot->t_min] - maximal_min_knot > |
||
275 | EPSILON) |
||
276 | maximal_min_knot = (texture_knot->knot)[texture_knot->t_min]; |
||
277 | if (minimal_max_knot - (texture_knot->knot)[texture_knot->t_max] > |
||
278 | EPSILON) |
||
279 | minimal_max_knot = (texture_knot->knot)[texture_knot->t_max]; |
||
280 | if ((texture_knot->unified_knot = |
||
281 | (GLfloat *) malloc(sizeof(GLfloat) * max_nknots)) == NULL) { |
||
282 | free(geom_knot->unified_knot); |
||
283 | free(color_knot->unified_knot); |
||
284 | free(normal_knot->unified_knot); |
||
285 | call_user_error(nobj, GLU_OUT_OF_MEMORY); |
||
286 | return GLU_ERROR; |
||
287 | } |
||
288 | /* copy the original knot to the unified one */ |
||
289 | texture_knot->unified_nknots = texture_knot->nknots; |
||
290 | for (i = 0; i < texture_knot->nknots; i++) |
||
291 | (texture_knot->unified_knot)[i] = (texture_knot->knot)[i]; |
||
292 | } |
||
293 | /* work on the geometry knot with all additional knot values */ |
||
294 | /* appearing in attirbutive knots */ |
||
295 | if (minimal_max_knot - maximal_min_knot < EPSILON) { |
||
296 | /* empty working range */ |
||
297 | geom_knot->unified_nknots = 0; |
||
298 | color_knot->unified_nknots = 0; |
||
299 | normal_knot->unified_nknots = 0; |
||
300 | texture_knot->unified_nknots = 0; |
||
301 | } |
||
302 | else { |
||
303 | if (color_knot->unified_knot) |
||
304 | collect_unified_knot(geom_knot, color_knot, maximal_min_knot, |
||
305 | minimal_max_knot); |
||
306 | if (normal_knot->unified_knot) |
||
307 | collect_unified_knot(geom_knot, normal_knot, maximal_min_knot, |
||
308 | minimal_max_knot); |
||
309 | if (texture_knot->unified_knot) |
||
310 | collect_unified_knot(geom_knot, texture_knot, maximal_min_knot, |
||
311 | minimal_max_knot); |
||
312 | /* since we have now built the "unified" geometry knot */ |
||
313 | /* add same knot values to all attributive knots */ |
||
314 | if (color_knot->unified_knot) |
||
315 | collect_unified_knot(color_knot, geom_knot, maximal_min_knot, |
||
316 | minimal_max_knot); |
||
317 | if (normal_knot->unified_knot) |
||
318 | collect_unified_knot(normal_knot, geom_knot, maximal_min_knot, |
||
319 | minimal_max_knot); |
||
320 | if (texture_knot->unified_knot) |
||
321 | collect_unified_knot(texture_knot, geom_knot, maximal_min_knot, |
||
322 | minimal_max_knot); |
||
323 | } |
||
324 | } |
||
325 | set_new_t_min_t_max(geom_knot, color_knot, normal_knot, texture_knot, |
||
326 | maximal_min_knot, minimal_max_knot); |
||
327 | return GLU_NO_ERROR; |
||
328 | } |
||
329 | |||
330 | void |
||
331 | free_unified_knots(knot_str_type * geom_knot, knot_str_type * color_knot, |
||
332 | knot_str_type * normal_knot, knot_str_type * texture_knot) |
||
333 | { |
||
334 | if (geom_knot->unified_knot) |
||
335 | free(geom_knot->unified_knot); |
||
336 | if (color_knot->unified_knot) |
||
337 | free(color_knot->unified_knot); |
||
338 | if (normal_knot->unified_knot) |
||
339 | free(normal_knot->unified_knot); |
||
340 | if (texture_knot->unified_knot) |
||
341 | free(texture_knot->unified_knot); |
||
342 | } |
||
343 | |||
344 | GLenum explode_knot(knot_str_type * the_knot) |
||
345 | { |
||
346 | GLfloat *knot, *new_knot; |
||
347 | GLint nknots, n_new_knots = 0; |
||
348 | GLint t_min, t_max; |
||
349 | GLint ord; |
||
350 | GLsizei i, j, k; |
||
351 | GLfloat tmp_float; |
||
352 | |||
353 | if (the_knot->unified_knot) { |
||
354 | knot = the_knot->unified_knot; |
||
355 | nknots = the_knot->unified_nknots; |
||
356 | } |
||
357 | else { |
||
358 | knot = the_knot->knot; |
||
359 | nknots = the_knot->nknots; |
||
360 | } |
||
361 | ord = the_knot->order; |
||
362 | t_min = the_knot->t_min; |
||
363 | t_max = the_knot->t_max; |
||
364 | |||
365 | for (i = t_min; i <= t_max;) { |
||
366 | tmp_float = knot[i]; |
||
367 | for (j = 0; j < ord && (i + j) <= t_max; j++) |
||
368 | if (fabs(tmp_float - knot[i + j]) > EPSILON) |
||
369 | break; |
||
370 | n_new_knots += ord - j; |
||
371 | i += j; |
||
372 | } |
||
373 | /* alloc space for new_knot */ |
||
374 | if ( |
||
375 | (new_knot = |
||
376 | (GLfloat *) malloc(sizeof(GLfloat) * (nknots + n_new_knots + 1))) == NULL) { |
||
377 | return GLU_OUT_OF_MEMORY; |
||
378 | } |
||
379 | /* fill in new knot */ |
||
380 | for (j = 0; j < t_min; j++) |
||
381 | new_knot[j] = knot[j]; |
||
382 | for (i = j; i <= t_max; i++) { |
||
383 | tmp_float = knot[i]; |
||
384 | for (k = 0; k < ord; k++) { |
||
385 | new_knot[j++] = knot[i]; |
||
386 | if (tmp_float == knot[i + 1]) |
||
387 | i++; |
||
388 | } |
||
389 | } |
||
390 | for (i = t_max + 1; i < (int) nknots; i++) |
||
391 | new_knot[j++] = knot[i]; |
||
392 | /* fill in the knot structure */ |
||
393 | the_knot->new_knot = new_knot; |
||
394 | the_knot->delta_nknots += n_new_knots; |
||
395 | the_knot->t_max += n_new_knots; |
||
396 | return GLU_NO_ERROR; |
||
397 | } |
||
398 | |||
399 | GLenum calc_alphas(knot_str_type * the_knot) |
||
400 | { |
||
401 | GLfloat tmp_float; |
||
402 | int i, j, k, m, n; |
||
403 | int order; |
||
404 | GLfloat *alpha, *alpha_new, *tmp_alpha; |
||
405 | GLfloat denom; |
||
406 | GLfloat *knot, *new_knot; |
||
407 | |||
408 | |||
409 | knot = the_knot->knot; |
||
410 | order = the_knot->order; |
||
411 | new_knot = the_knot->new_knot; |
||
412 | n = the_knot->nknots - the_knot->order; |
||
413 | m = n + the_knot->delta_nknots; |
||
414 | if ((alpha = (GLfloat *) malloc(sizeof(GLfloat) * n * m)) == NULL) { |
||
415 | return GLU_OUT_OF_MEMORY; |
||
416 | } |
||
417 | if ((alpha_new = (GLfloat *) malloc(sizeof(GLfloat) * n * m)) == NULL) { |
||
418 | free(alpha); |
||
419 | return GLU_OUT_OF_MEMORY; |
||
420 | } |
||
421 | for (j = 0; j < m; j++) { |
||
422 | for (i = 0; i < n; i++) { |
||
423 | if ((knot[i] <= new_knot[j]) && (new_knot[j] < knot[i + 1])) |
||
424 | tmp_float = 1.0; |
||
425 | else |
||
426 | tmp_float = 0.0; |
||
427 | alpha[i + j * n] = tmp_float; |
||
428 | } |
||
429 | } |
||
430 | for (k = 1; k < order; k++) { |
||
431 | for (j = 0; j < m; j++) |
||
432 | for (i = 0; i < n; i++) { |
||
433 | denom = knot[i + k] - knot[i]; |
||
434 | if (fabs(denom) < EPSILON) |
||
435 | tmp_float = 0.0; |
||
436 | else |
||
437 | tmp_float = (new_knot[j + k] - knot[i]) / denom * |
||
438 | alpha[i + j * n]; |
||
439 | denom = knot[i + k + 1] - knot[i + 1]; |
||
440 | if (fabs(denom) > EPSILON) |
||
441 | tmp_float += (knot[i + k + 1] - new_knot[j + k]) / denom * |
||
442 | alpha[(i + 1) + j * n]; |
||
443 | alpha_new[i + j * n] = tmp_float; |
||
444 | } |
||
445 | tmp_alpha = alpha_new; |
||
446 | alpha_new = alpha; |
||
447 | alpha = tmp_alpha; |
||
448 | } |
||
449 | the_knot->alpha = alpha; |
||
450 | free(alpha_new); |
||
451 | return GLU_NO_ERROR; |
||
452 | } |
||
453 | |||
454 | GLenum |
||
455 | calc_new_ctrl_pts(GLfloat * ctrl, GLint stride, knot_str_type * the_knot, |
||
456 | GLint dim, GLfloat ** new_ctrl, GLint * ncontrol) |
||
457 | { |
||
458 | GLsizei i, j, k, l, m, n; |
||
459 | GLsizei index1, index2; |
||
460 | GLfloat *alpha; |
||
461 | GLfloat *new_knot; |
||
462 | |||
463 | new_knot = the_knot->new_knot; |
||
464 | n = the_knot->nknots - the_knot->order; |
||
465 | alpha = the_knot->alpha; |
||
466 | |||
467 | m = the_knot->t_max + 1 - the_knot->t_min - the_knot->order; |
||
468 | k = the_knot->t_min; |
||
469 | /* allocate space for new control points */ |
||
470 | if ((*new_ctrl = (GLfloat *) malloc(sizeof(GLfloat) * dim * m)) == NULL) { |
||
471 | return GLU_OUT_OF_MEMORY; |
||
472 | } |
||
473 | for (j = 0; j < m; j++) { |
||
474 | for (l = 0; l < dim; l++) |
||
475 | (*new_ctrl)[j * dim + l] = 0.0; |
||
476 | for (i = 0; i < n; i++) { |
||
477 | index1 = i + (j + k) * n; |
||
478 | index2 = i * stride; |
||
479 | for (l = 0; l < dim; l++) |
||
480 | (*new_ctrl)[j * dim + l] += alpha[index1] * ctrl[index2 + l]; |
||
481 | } |
||
482 | } |
||
483 | *ncontrol = (GLint) m; |
||
484 | return GLU_NO_ERROR; |
||
485 | } |
||
486 | |||
487 | static GLint |
||
488 | calc_factor(GLfloat * pts, GLint order, GLint indx, GLint stride, |
||
489 | GLfloat tolerance, GLint dim) |
||
490 | { |
||
491 | GLdouble model[16], proj[16]; |
||
492 | GLint viewport[4]; |
||
493 | GLdouble x, y, z, w, winx1, winy1, winz, winx2, winy2; |
||
494 | GLint i; |
||
495 | GLdouble len, dx, dy; |
||
496 | |||
497 | glGetDoublev(GL_MODELVIEW_MATRIX, model); |
||
498 | glGetDoublev(GL_PROJECTION_MATRIX, proj); |
||
499 | glGetIntegerv(GL_VIEWPORT, viewport); |
||
500 | if (dim == 4) { |
||
501 | w = (GLdouble) pts[indx + 3]; |
||
502 | x = (GLdouble) pts[indx] / w; |
||
503 | y = (GLdouble) pts[indx + 1] / w; |
||
504 | z = (GLdouble) pts[indx + 2] / w; |
||
505 | gluProject(x, y, z, model, proj, viewport, &winx1, &winy1, &winz); |
||
506 | len = 0.0; |
||
507 | for (i = 1; i < order; i++) { |
||
508 | w = (GLdouble) pts[indx + i * stride + 3]; |
||
509 | x = (GLdouble) pts[indx + i * stride] / w; |
||
510 | y = (GLdouble) pts[indx + i * stride + 1] / w; |
||
511 | z = (GLdouble) pts[indx + i * stride + 2] / w; |
||
512 | if (gluProject |
||
513 | (x, y, z, model, proj, viewport, &winx2, &winy2, &winz)) { |
||
514 | dx = winx2 - winx1; |
||
515 | dy = winy2 - winy1; |
||
516 | len += sqrt(dx * dx + dy * dy); |
||
517 | } |
||
518 | winx1 = winx2; |
||
519 | winy1 = winy2; |
||
520 | } |
||
521 | } |
||
522 | else { |
||
523 | x = (GLdouble) pts[indx]; |
||
524 | y = (GLdouble) pts[indx + 1]; |
||
525 | if (dim == 2) |
||
526 | z = 0.0; |
||
527 | else |
||
528 | z = (GLdouble) pts[indx + 2]; |
||
529 | gluProject(x, y, z, model, proj, viewport, &winx1, &winy1, &winz); |
||
530 | len = 0.0; |
||
531 | for (i = 1; i < order; i++) { |
||
532 | x = (GLdouble) pts[indx + i * stride]; |
||
533 | y = (GLdouble) pts[indx + i * stride + 1]; |
||
534 | if (dim == 2) |
||
535 | z = 0.0; |
||
536 | else |
||
537 | z = (GLdouble) pts[indx + i * stride + 2]; |
||
538 | if (gluProject |
||
539 | (x, y, z, model, proj, viewport, &winx2, &winy2, &winz)) { |
||
540 | dx = winx2 - winx1; |
||
541 | dy = winy2 - winy1; |
||
542 | len += sqrt(dx * dx + dy * dy); |
||
543 | } |
||
544 | winx1 = winx2; |
||
545 | winy1 = winy2; |
||
546 | } |
||
547 | } |
||
548 | len /= tolerance; |
||
549 | return ((GLint) len + 1); |
||
550 | } |
||
551 | |||
552 | /* we can't use the Mesa evaluators - no way to get the point coords */ |
||
553 | /* so we use our own Bezier point calculus routines */ |
||
554 | /* because I'm lazy, I reuse the ones from eval.c */ |
||
555 | |||
556 | static void |
||
557 | bezier_curve(GLfloat * cp, GLfloat * out, GLfloat t, |
||
558 | GLuint dim, GLuint order, GLint offset) |
||
559 | { |
||
560 | GLfloat s, powert; |
||
561 | GLuint i, k, bincoeff; |
||
562 | |||
563 | if (order >= 2) { |
||
564 | bincoeff = order - 1; |
||
565 | s = 1.0 - t; |
||
566 | |||
567 | for (k = 0; k < dim; k++) |
||
568 | out[k] = s * cp[k] + bincoeff * t * cp[offset + k]; |
||
569 | |||
570 | for (i = 2, cp += 2 * offset, powert = t * t; i < order; |
||
571 | i++, powert *= t, cp += offset) { |
||
572 | bincoeff *= order - i; |
||
573 | bincoeff /= i; |
||
574 | |||
575 | for (k = 0; k < dim; k++) |
||
576 | out[k] = s * out[k] + bincoeff * powert * cp[k]; |
||
577 | } |
||
578 | } |
||
579 | else { /* order=1 -> constant curve */ |
||
580 | |||
581 | for (k = 0; k < dim; k++) |
||
582 | out[k] = cp[k]; |
||
583 | } |
||
584 | } |
||
585 | |||
586 | static GLint |
||
587 | calc_parametric_factor(GLfloat * pts, GLint order, GLint indx, GLint stride, |
||
588 | GLfloat tolerance, GLint dim) |
||
589 | { |
||
590 | GLdouble model[16], proj[16]; |
||
591 | GLint viewport[4]; |
||
592 | GLdouble x, y, z, w, x1, y1, z1, x2, y2, z2, x3, y3, z3; |
||
593 | GLint i; |
||
594 | GLint P; |
||
595 | GLfloat bez_pt[4]; |
||
596 | GLdouble len = 0.0, tmp, z_med; |
||
597 | |||
598 | P = 2 * (order + 2); |
||
599 | glGetDoublev(GL_MODELVIEW_MATRIX, model); |
||
600 | glGetDoublev(GL_PROJECTION_MATRIX, proj); |
||
601 | glGetIntegerv(GL_VIEWPORT, viewport); |
||
602 | z_med = (viewport[2] + viewport[3]) * 0.5; |
||
603 | switch (dim) { |
||
604 | case 4: |
||
605 | for (i = 1; i < P; i++) { |
||
606 | bezier_curve(pts + indx, bez_pt, (GLfloat) i / (GLfloat) P, 4, |
||
607 | order, stride); |
||
608 | w = (GLdouble) bez_pt[3]; |
||
609 | x = (GLdouble) bez_pt[0] / w; |
||
610 | y = (GLdouble) bez_pt[1] / w; |
||
611 | z = (GLdouble) bez_pt[2] / w; |
||
612 | gluProject(x, y, z, model, proj, viewport, &x3, &y3, &z3); |
||
613 | z3 *= z_med; |
||
614 | bezier_curve(pts + indx, bez_pt, (GLfloat) (i - 1) / (GLfloat) P, 4, |
||
615 | order, stride); |
||
616 | w = (GLdouble) bez_pt[3]; |
||
617 | x = (GLdouble) bez_pt[0] / w; |
||
618 | y = (GLdouble) bez_pt[1] / w; |
||
619 | z = (GLdouble) bez_pt[2] / w; |
||
620 | gluProject(x, y, z, model, proj, viewport, &x1, &y1, &z1); |
||
621 | z1 *= z_med; |
||
622 | bezier_curve(pts + indx, bez_pt, (GLfloat) (i + 1) / (GLfloat) P, 4, |
||
623 | order, stride); |
||
624 | w = (GLdouble) bez_pt[3]; |
||
625 | x = (GLdouble) bez_pt[0] / w; |
||
626 | y = (GLdouble) bez_pt[1] / w; |
||
627 | z = (GLdouble) bez_pt[2] / w; |
||
628 | gluProject(x, y, z, model, proj, viewport, &x2, &y2, &z2); |
||
629 | z2 *= z_med; |
||
630 | /* calc distance between point (x3,y3,z3) and line segment */ |
||
631 | /* <x1,y1,z1><x2,y2,z2> */ |
||
632 | x = x2 - x1; |
||
633 | y = y2 - y1; |
||
634 | z = z2 - z1; |
||
635 | tmp = sqrt(x * x + y * y + z * z); |
||
636 | x /= tmp; |
||
637 | y /= tmp; |
||
638 | z /= tmp; |
||
639 | tmp = x3 * x + y3 * y + z3 * z - x1 * x - y1 * y - z1 * z; |
||
640 | x = x1 + x * tmp - x3; |
||
641 | y = y1 + y * tmp - y3; |
||
642 | z = z1 + z * tmp - z3; |
||
643 | tmp = sqrt(x * x + y * y + z * z); |
||
644 | if (tmp > len) |
||
645 | len = tmp; |
||
646 | } |
||
647 | break; |
||
648 | case 3: |
||
649 | for (i = 1; i < P; i++) { |
||
650 | bezier_curve(pts + indx, bez_pt, (GLfloat) i / (GLfloat) P, 3, |
||
651 | order, stride); |
||
652 | x = (GLdouble) bez_pt[0]; |
||
653 | y = (GLdouble) bez_pt[1]; |
||
654 | z = (GLdouble) bez_pt[2]; |
||
655 | gluProject(x, y, z, model, proj, viewport, &x3, &y3, &z3); |
||
656 | z3 *= z_med; |
||
657 | bezier_curve(pts + indx, bez_pt, (GLfloat) (i - 1) / (GLfloat) P, 3, |
||
658 | order, stride); |
||
659 | x = (GLdouble) bez_pt[0]; |
||
660 | y = (GLdouble) bez_pt[1]; |
||
661 | z = (GLdouble) bez_pt[2]; |
||
662 | gluProject(x, y, z, model, proj, viewport, &x1, &y1, &z1); |
||
663 | z1 *= z_med; |
||
664 | bezier_curve(pts + indx, bez_pt, (GLfloat) (i + 1) / (GLfloat) P, 3, |
||
665 | order, stride); |
||
666 | x = (GLdouble) bez_pt[0]; |
||
667 | y = (GLdouble) bez_pt[1]; |
||
668 | z = (GLdouble) bez_pt[2]; |
||
669 | gluProject(x, y, z, model, proj, viewport, &x2, &y2, &z2); |
||
670 | z2 *= z_med; |
||
671 | /* calc distance between point (x3,y3,z3) and line segment */ |
||
672 | /* <x1,y1,z1><x2,y2,z2> */ |
||
673 | x = x2 - x1; |
||
674 | y = y2 - y1; |
||
675 | z = z2 - z1; |
||
676 | tmp = sqrt(x * x + y * y + z * z); |
||
677 | x /= tmp; |
||
678 | y /= tmp; |
||
679 | z /= tmp; |
||
680 | tmp = x3 * x + y3 * y + z3 * z - x1 * x - y1 * y - z1 * z; |
||
681 | x = x1 + x * tmp - x3; |
||
682 | y = y1 + y * tmp - y3; |
||
683 | z = z1 + z * tmp - z3; |
||
684 | tmp = sqrt(x * x + y * y + z * z); |
||
685 | if (tmp > len) |
||
686 | len = tmp; |
||
687 | } |
||
688 | break; |
||
689 | case 2: |
||
690 | for (i = 1; i < P; i++) { |
||
691 | bezier_curve(pts + indx, bez_pt, (GLfloat) i / (GLfloat) P, 2, |
||
692 | order, stride); |
||
693 | x = (GLdouble) bez_pt[0]; |
||
694 | y = (GLdouble) bez_pt[1]; |
||
695 | z = 0.0; |
||
696 | gluProject(x, y, z, model, proj, viewport, &x3, &y3, &z3); |
||
697 | z3 *= z_med; |
||
698 | bezier_curve(pts + indx, bez_pt, (GLfloat) (i - 1) / (GLfloat) P, 2, |
||
699 | order, stride); |
||
700 | x = (GLdouble) bez_pt[0]; |
||
701 | y = (GLdouble) bez_pt[1]; |
||
702 | z = 0.0; |
||
703 | gluProject(x, y, z, model, proj, viewport, &x1, &y1, &z1); |
||
704 | z1 *= z_med; |
||
705 | bezier_curve(pts + indx, bez_pt, (GLfloat) (i + 1) / (GLfloat) P, 2, |
||
706 | order, stride); |
||
707 | x = (GLdouble) bez_pt[0]; |
||
708 | y = (GLdouble) bez_pt[1]; |
||
709 | z = 0.0; |
||
710 | gluProject(x, y, z, model, proj, viewport, &x2, &y2, &z2); |
||
711 | z2 *= z_med; |
||
712 | /* calc distance between point (x3,y3,z3) and line segment */ |
||
713 | /* <x1,y1,z1><x2,y2,z2> */ |
||
714 | x = x2 - x1; |
||
715 | y = y2 - y1; |
||
716 | z = z2 - z1; |
||
717 | tmp = sqrt(x * x + y * y + z * z); |
||
718 | x /= tmp; |
||
719 | y /= tmp; |
||
720 | z /= tmp; |
||
721 | tmp = x3 * x + y3 * y + z3 * z - x1 * x - y1 * y - z1 * z; |
||
722 | x = x1 + x * tmp - x3; |
||
723 | y = y1 + y * tmp - y3; |
||
724 | z = z1 + z * tmp - z3; |
||
725 | tmp = sqrt(x * x + y * y + z * z); |
||
726 | if (tmp > len) |
||
727 | len = tmp; |
||
728 | } |
||
729 | break; |
||
730 | |||
731 | } |
||
732 | if (len < tolerance) |
||
733 | return (order); |
||
734 | else |
||
735 | return (GLint) (sqrt(len / tolerance) * (order + 2) + 1); |
||
736 | } |
||
737 | |||
738 | static GLenum |
||
739 | calc_sampling_3D(new_ctrl_type * new_ctrl, GLfloat tolerance, GLint dim, |
||
740 | GLint uorder, GLint vorder, GLint ** ufactors, |
||
741 | GLint ** vfactors) |
||
742 | { |
||
743 | GLfloat *ctrl; |
||
744 | GLint tmp_factor1, tmp_factor2; |
||
745 | GLint ufactor_cnt, vfactor_cnt; |
||
746 | GLint offset1, offset2, offset3; |
||
747 | GLint i, j; |
||
748 | |||
749 | ufactor_cnt = new_ctrl->s_bezier_cnt; |
||
750 | vfactor_cnt = new_ctrl->t_bezier_cnt; |
||
751 | if ((*ufactors = (GLint *) malloc(sizeof(GLint) * ufactor_cnt * 3)) |
||
752 | == NULL) { |
||
753 | return GLU_OUT_OF_MEMORY; |
||
754 | } |
||
755 | if ((*vfactors = (GLint *) malloc(sizeof(GLint) * vfactor_cnt * 3)) |
||
756 | == NULL) { |
||
757 | free(*ufactors); |
||
758 | return GLU_OUT_OF_MEMORY; |
||
759 | } |
||
760 | ctrl = new_ctrl->geom_ctrl; |
||
761 | offset1 = new_ctrl->geom_t_stride * vorder; |
||
762 | offset2 = new_ctrl->geom_s_stride * uorder; |
||
763 | for (j = 0; j < vfactor_cnt; j++) { |
||
764 | *(*vfactors + j * 3 + 1) = tmp_factor1 = calc_factor(ctrl, vorder, |
||
765 | j * offset1, dim, |
||
766 | tolerance, dim); |
||
767 | /* loop ufactor_cnt-1 times */ |
||
768 | for (i = 1; i < ufactor_cnt; i++) { |
||
769 | tmp_factor2 = calc_factor(ctrl, vorder, |
||
770 | j * offset1 + i * offset2, dim, tolerance, |
||
771 | dim); |
||
772 | if (tmp_factor2 > tmp_factor1) |
||
773 | tmp_factor1 = tmp_factor2; |
||
774 | } |
||
775 | /* last time for the opposite edge */ |
||
776 | *(*vfactors + j * 3 + 2) = tmp_factor2 = calc_factor(ctrl, vorder, |
||
777 | j * offset1 + |
||
778 | i * offset2 - |
||
779 | new_ctrl-> |
||
780 | geom_s_stride, dim, |
||
781 | tolerance, dim); |
||
782 | if (tmp_factor2 > tmp_factor1) |
||
783 | *(*vfactors + j * 3) = tmp_factor2; |
||
784 | else |
||
785 | *(*vfactors + j * 3) = tmp_factor1; |
||
786 | } |
||
787 | offset3 = new_ctrl->geom_s_stride; |
||
788 | offset2 = new_ctrl->geom_s_stride * uorder; |
||
789 | for (j = 0; j < ufactor_cnt; j++) { |
||
790 | *(*ufactors + j * 3 + 1) = tmp_factor1 = calc_factor(ctrl, uorder, |
||
791 | j * offset2, |
||
792 | offset3, tolerance, |
||
793 | dim); |
||
794 | /* loop vfactor_cnt-1 times */ |
||
795 | for (i = 1; i < vfactor_cnt; i++) { |
||
796 | tmp_factor2 = calc_factor(ctrl, uorder, |
||
797 | j * offset2 + i * offset1, offset3, |
||
798 | tolerance, dim); |
||
799 | if (tmp_factor2 > tmp_factor1) |
||
800 | tmp_factor1 = tmp_factor2; |
||
801 | } |
||
802 | /* last time for the opposite edge */ |
||
803 | *(*ufactors + j * 3 + 2) = tmp_factor2 = calc_factor(ctrl, uorder, |
||
804 | j * offset2 + |
||
805 | i * offset1 - |
||
806 | new_ctrl-> |
||
807 | geom_t_stride, |
||
808 | offset3, tolerance, |
||
809 | dim); |
||
810 | if (tmp_factor2 > tmp_factor1) |
||
811 | *(*ufactors + j * 3) = tmp_factor2; |
||
812 | else |
||
813 | *(*ufactors + j * 3) = tmp_factor1; |
||
814 | } |
||
815 | return GL_NO_ERROR; |
||
816 | } |
||
817 | |||
818 | static GLenum |
||
819 | calc_sampling_param_3D(new_ctrl_type * new_ctrl, GLfloat tolerance, GLint dim, |
||
820 | GLint uorder, GLint vorder, GLint ** ufactors, |
||
821 | GLint ** vfactors) |
||
822 | { |
||
823 | GLfloat *ctrl; |
||
824 | GLint tmp_factor1, tmp_factor2; |
||
825 | GLint ufactor_cnt, vfactor_cnt; |
||
826 | GLint offset1, offset2, offset3; |
||
827 | GLint i, j; |
||
828 | |||
829 | ufactor_cnt = new_ctrl->s_bezier_cnt; |
||
830 | vfactor_cnt = new_ctrl->t_bezier_cnt; |
||
831 | if ((*ufactors = (GLint *) malloc(sizeof(GLint) * ufactor_cnt * 3)) |
||
832 | == NULL) { |
||
833 | return GLU_OUT_OF_MEMORY; |
||
834 | } |
||
835 | if ((*vfactors = (GLint *) malloc(sizeof(GLint) * vfactor_cnt * 3)) |
||
836 | == NULL) { |
||
837 | free(*ufactors); |
||
838 | return GLU_OUT_OF_MEMORY; |
||
839 | } |
||
840 | ctrl = new_ctrl->geom_ctrl; |
||
841 | offset1 = new_ctrl->geom_t_stride * vorder; |
||
842 | offset2 = new_ctrl->geom_s_stride * uorder; |
||
843 | for (j = 0; j < vfactor_cnt; j++) { |
||
844 | *(*vfactors + j * 3 + 1) = tmp_factor1 = |
||
845 | calc_parametric_factor(ctrl, vorder, j * offset1, dim, tolerance, |
||
846 | dim); |
||
847 | /* loop ufactor_cnt-1 times */ |
||
848 | for (i = 1; i < ufactor_cnt; i++) { |
||
849 | tmp_factor2 = calc_parametric_factor(ctrl, vorder, |
||
850 | j * offset1 + i * offset2, dim, |
||
851 | tolerance, dim); |
||
852 | if (tmp_factor2 > tmp_factor1) |
||
853 | tmp_factor1 = tmp_factor2; |
||
854 | } |
||
855 | /* last time for the opposite edge */ |
||
856 | *(*vfactors + j * 3 + 2) = tmp_factor2 = |
||
857 | calc_parametric_factor(ctrl, vorder, |
||
858 | j * offset1 + i * offset2 - |
||
859 | new_ctrl->geom_s_stride, dim, tolerance, dim); |
||
860 | if (tmp_factor2 > tmp_factor1) |
||
861 | *(*vfactors + j * 3) = tmp_factor2; |
||
862 | else |
||
863 | *(*vfactors + j * 3) = tmp_factor1; |
||
864 | } |
||
865 | offset3 = new_ctrl->geom_s_stride; |
||
866 | offset2 = new_ctrl->geom_s_stride * uorder; |
||
867 | for (j = 0; j < ufactor_cnt; j++) { |
||
868 | *(*ufactors + j * 3 + 1) = tmp_factor1 = |
||
869 | calc_parametric_factor(ctrl, uorder, j * offset2, offset3, tolerance, |
||
870 | dim); |
||
871 | /* loop vfactor_cnt-1 times */ |
||
872 | for (i = 1; i < vfactor_cnt; i++) { |
||
873 | tmp_factor2 = calc_parametric_factor(ctrl, uorder, |
||
874 | j * offset2 + i * offset1, |
||
875 | offset3, tolerance, dim); |
||
876 | if (tmp_factor2 > tmp_factor1) |
||
877 | tmp_factor1 = tmp_factor2; |
||
878 | } |
||
879 | /* last time for the opposite edge */ |
||
880 | *(*ufactors + j * 3 + 2) = tmp_factor2 = |
||
881 | calc_parametric_factor(ctrl, uorder, |
||
882 | j * offset2 + i * offset1 - |
||
883 | new_ctrl->geom_t_stride, offset3, tolerance, |
||
884 | dim); |
||
885 | if (tmp_factor2 > tmp_factor1) |
||
886 | *(*ufactors + j * 3) = tmp_factor2; |
||
887 | else |
||
888 | *(*ufactors + j * 3) = tmp_factor1; |
||
889 | } |
||
890 | return GL_NO_ERROR; |
||
891 | } |
||
892 | |||
893 | static GLenum |
||
894 | calc_sampling_2D(GLfloat * ctrl, GLint cnt, GLint order, |
||
895 | GLfloat tolerance, GLint dim, GLint ** factors) |
||
896 | { |
||
897 | GLint factor_cnt; |
||
898 | GLint tmp_factor; |
||
899 | GLint offset; |
||
900 | GLint i; |
||
901 | |||
902 | factor_cnt = cnt / order; |
||
903 | if ((*factors = (GLint *) malloc(sizeof(GLint) * factor_cnt)) == NULL) { |
||
904 | return GLU_OUT_OF_MEMORY; |
||
905 | } |
||
906 | offset = order * dim; |
||
907 | for (i = 0; i < factor_cnt; i++) { |
||
908 | tmp_factor = calc_factor(ctrl, order, i * offset, dim, tolerance, dim); |
||
909 | if (tmp_factor == 0) |
||
910 | (*factors)[i] = 1; |
||
911 | else |
||
912 | (*factors)[i] = tmp_factor; |
||
913 | } |
||
914 | return GL_NO_ERROR; |
||
915 | } |
||
916 | |||
917 | static void |
||
918 | set_sampling_and_culling(GLUnurbsObj * nobj) |
||
919 | { |
||
920 | if (nobj->auto_load_matrix == GL_FALSE) { |
||
921 | GLint i; |
||
922 | GLfloat m[4]; |
||
923 | |||
924 | glPushAttrib((GLbitfield) (GL_VIEWPORT_BIT | GL_TRANSFORM_BIT)); |
||
925 | for (i = 0; i < 4; i++) |
||
926 | m[i] = nobj->sampling_matrices.viewport[i]; |
||
927 | glViewport(m[0], m[1], m[2], m[3]); |
||
928 | glMatrixMode(GL_PROJECTION); |
||
929 | glPushMatrix(); |
||
930 | glLoadMatrixf(nobj->sampling_matrices.proj); |
||
931 | glMatrixMode(GL_MODELVIEW); |
||
932 | glPushMatrix(); |
||
933 | glLoadMatrixf(nobj->sampling_matrices.model); |
||
934 | } |
||
935 | } |
||
936 | |||
937 | static void |
||
938 | revert_sampling_and_culling(GLUnurbsObj * nobj) |
||
939 | { |
||
940 | if (nobj->auto_load_matrix == GL_FALSE) { |
||
941 | glMatrixMode(GL_MODELVIEW); |
||
942 | glPopMatrix(); |
||
943 | glMatrixMode(GL_PROJECTION); |
||
944 | glPopMatrix(); |
||
945 | glPopAttrib(); |
||
946 | } |
||
947 | } |
||
948 | |||
949 | GLenum |
||
950 | glu_do_sampling_3D(GLUnurbsObj * nobj, new_ctrl_type * new_ctrl, |
||
951 | GLint ** sfactors, GLint ** tfactors) |
||
952 | { |
||
953 | GLint dim; |
||
954 | GLenum err; |
||
955 | |||
956 | *sfactors = NULL; |
||
957 | *tfactors = NULL; |
||
958 | dim = nobj->surface.geom.dim; |
||
959 | set_sampling_and_culling(nobj); |
||
960 | if ((err = calc_sampling_3D(new_ctrl, nobj->sampling_tolerance, dim, |
||
961 | nobj->surface.geom.sorder, |
||
962 | nobj->surface.geom.torder, sfactors, |
||
963 | tfactors)) == GLU_ERROR) { |
||
964 | revert_sampling_and_culling(nobj); |
||
965 | call_user_error(nobj, err); |
||
966 | return GLU_ERROR; |
||
967 | } |
||
968 | revert_sampling_and_culling(nobj); |
||
969 | return GLU_NO_ERROR; |
||
970 | } |
||
971 | |||
972 | GLenum |
||
973 | glu_do_sampling_uv(GLUnurbsObj * nobj, new_ctrl_type * new_ctrl, |
||
974 | GLint ** sfactors, GLint ** tfactors) |
||
975 | { |
||
976 | GLint s_cnt, t_cnt, i; |
||
977 | GLint u_steps, v_steps; |
||
978 | |||
979 | s_cnt = new_ctrl->s_bezier_cnt; |
||
980 | t_cnt = new_ctrl->t_bezier_cnt; |
||
981 | *sfactors = NULL; |
||
982 | *tfactors = NULL; |
||
983 | if ((*sfactors = (GLint *) malloc(sizeof(GLint) * s_cnt * 3)) |
||
984 | == NULL) { |
||
985 | return GLU_OUT_OF_MEMORY; |
||
986 | } |
||
987 | if ((*tfactors = (GLint *) malloc(sizeof(GLint) * t_cnt * 3)) |
||
988 | == NULL) { |
||
989 | free(*sfactors); |
||
990 | return GLU_OUT_OF_MEMORY; |
||
991 | } |
||
992 | u_steps = nobj->u_step; |
||
993 | v_steps = nobj->v_step; |
||
994 | for (i = 0; i < s_cnt; i++) { |
||
995 | *(*sfactors + i * 3) = u_steps; |
||
996 | *(*sfactors + i * 3 + 1) = u_steps; |
||
997 | *(*sfactors + i * 3 + 2) = u_steps; |
||
998 | } |
||
999 | for (i = 0; i < t_cnt; i++) { |
||
1000 | *(*tfactors + i * 3) = v_steps; |
||
1001 | *(*tfactors + i * 3 + 1) = v_steps; |
||
1002 | *(*tfactors + i * 3 + 2) = v_steps; |
||
1003 | } |
||
1004 | return GLU_NO_ERROR; |
||
1005 | } |
||
1006 | |||
1007 | |||
1008 | GLenum |
||
1009 | glu_do_sampling_param_3D(GLUnurbsObj * nobj, new_ctrl_type * new_ctrl, |
||
1010 | GLint ** sfactors, GLint ** tfactors) |
||
1011 | { |
||
1012 | GLint dim; |
||
1013 | GLenum err; |
||
1014 | |||
1015 | *sfactors = NULL; |
||
1016 | *tfactors = NULL; |
||
1017 | dim = nobj->surface.geom.dim; |
||
1018 | set_sampling_and_culling(nobj); |
||
1019 | if ( |
||
1020 | (err = |
||
1021 | calc_sampling_param_3D(new_ctrl, nobj->parametric_tolerance, dim, |
||
1022 | nobj->surface.geom.sorder, |
||
1023 | nobj->surface.geom.torder, sfactors, |
||
1024 | tfactors)) == GLU_ERROR) { |
||
1025 | revert_sampling_and_culling(nobj); |
||
1026 | call_user_error(nobj, err); |
||
1027 | return GLU_ERROR; |
||
1028 | } |
||
1029 | revert_sampling_and_culling(nobj); |
||
1030 | return GLU_NO_ERROR; |
||
1031 | } |
||
1032 | |||
1033 | |||
1034 | static GLenum |
||
1035 | glu_do_sampling_2D(GLUnurbsObj * nobj, GLfloat * ctrl, GLint cnt, GLint order, |
||
1036 | GLint dim, GLint ** factors) |
||
1037 | { |
||
1038 | GLenum err; |
||
1039 | |||
1040 | set_sampling_and_culling(nobj); |
||
1041 | err = calc_sampling_2D(ctrl, cnt, order, nobj->sampling_tolerance, dim, |
||
1042 | factors); |
||
1043 | revert_sampling_and_culling(nobj); |
||
1044 | return err; |
||
1045 | } |
||
1046 | |||
1047 | |||
1048 | static GLenum |
||
1049 | glu_do_sampling_u(GLUnurbsObj * nobj, GLfloat * ctrl, GLint cnt, GLint order, |
||
1050 | GLint dim, GLint ** factors) |
||
1051 | { |
||
1052 | GLint i; |
||
1053 | GLint u_steps; |
||
1054 | |||
1055 | cnt /= order; |
||
1056 | if ((*factors = (GLint *) malloc(sizeof(GLint) * cnt)) |
||
1057 | == NULL) { |
||
1058 | return GLU_OUT_OF_MEMORY; |
||
1059 | } |
||
1060 | u_steps = nobj->u_step; |
||
1061 | for (i = 0; i < cnt; i++) |
||
1062 | (*factors)[i] = u_steps; |
||
1063 | return GLU_NO_ERROR; |
||
1064 | } |
||
1065 | |||
1066 | |||
1067 | static GLenum |
||
1068 | glu_do_sampling_param_2D(GLUnurbsObj * nobj, GLfloat * ctrl, GLint cnt, |
||
1069 | GLint order, GLint dim, GLint ** factors) |
||
1070 | { |
||
1071 | GLint i; |
||
1072 | GLint u_steps; |
||
1073 | GLfloat tolerance; |
||
1074 | |||
1075 | set_sampling_and_culling(nobj); |
||
1076 | tolerance = nobj->parametric_tolerance; |
||
1077 | cnt /= order; |
||
1078 | if ((*factors = (GLint *) malloc(sizeof(GLint) * cnt)) |
||
1079 | == NULL) { |
||
1080 | revert_sampling_and_culling(nobj); |
||
1081 | return GLU_OUT_OF_MEMORY; |
||
1082 | } |
||
1083 | u_steps = nobj->u_step; |
||
1084 | for (i = 0; i < cnt; i++) { |
||
1085 | (*factors)[i] = calc_parametric_factor(ctrl, order, 0, |
||
1086 | dim, tolerance, dim); |
||
1087 | |||
1088 | } |
||
1089 | revert_sampling_and_culling(nobj); |
||
1090 | return GLU_NO_ERROR; |
||
1091 | } |
||
1092 | |||
1093 | GLenum |
||
1094 | glu_do_sampling_crv(GLUnurbsObj * nobj, GLfloat * ctrl, GLint cnt, |
||
1095 | GLint order, GLint dim, GLint ** factors) |
||
1096 | { |
||
1097 | GLenum err; |
||
1098 | |||
1099 | *factors = NULL; |
||
1100 | switch (nobj->sampling_method) { |
||
1101 | case GLU_PATH_LENGTH: |
||
1102 | if ((err = glu_do_sampling_2D(nobj, ctrl, cnt, order, dim, factors)) != |
||
1103 | GLU_NO_ERROR) { |
||
1104 | call_user_error(nobj, err); |
||
1105 | return GLU_ERROR; |
||
1106 | } |
||
1107 | break; |
||
1108 | case GLU_DOMAIN_DISTANCE: |
||
1109 | if ((err = glu_do_sampling_u(nobj, ctrl, cnt, order, dim, factors)) != |
||
1110 | GLU_NO_ERROR) { |
||
1111 | call_user_error(nobj, err); |
||
1112 | return GLU_ERROR; |
||
1113 | } |
||
1114 | break; |
||
1115 | case GLU_PARAMETRIC_ERROR: |
||
1116 | if ( |
||
1117 | (err = |
||
1118 | glu_do_sampling_param_2D(nobj, ctrl, cnt, order, dim, |
||
1119 | factors)) != GLU_NO_ERROR) { |
||
1120 | call_user_error(nobj, err); |
||
1121 | return GLU_ERROR; |
||
1122 | } |
||
1123 | break; |
||
1124 | default: |
||
1125 | abort(); |
||
1126 | } |
||
1127 | |||
1128 | return GLU_NO_ERROR; |
||
1129 | } |
||
1130 | |||
1131 | /* TODO - i don't like this culling - this one just tests if at least one */ |
||
1132 | /* ctrl point lies within the viewport . Also the point_in_viewport() */ |
||
1133 | /* should be included in the fnctions for efficiency reasons */ |
||
1134 | |||
1135 | static GLboolean |
||
1136 | point_in_viewport(GLfloat * pt, GLint dim) |
||
1137 | { |
||
1138 | GLdouble model[16], proj[16]; |
||
1139 | GLint viewport[4]; |
||
1140 | GLdouble x, y, z, w, winx, winy, winz; |
||
1141 | |||
1142 | glGetDoublev(GL_MODELVIEW_MATRIX, model); |
||
1143 | glGetDoublev(GL_PROJECTION_MATRIX, proj); |
||
1144 | glGetIntegerv(GL_VIEWPORT, viewport); |
||
1145 | if (dim == 3) { |
||
1146 | x = (GLdouble) pt[0]; |
||
1147 | y = (GLdouble) pt[1]; |
||
1148 | z = (GLdouble) pt[2]; |
||
1149 | gluProject(x, y, z, model, proj, viewport, &winx, &winy, &winz); |
||
1150 | } |
||
1151 | else { |
||
1152 | w = (GLdouble) pt[3]; |
||
1153 | x = (GLdouble) pt[0] / w; |
||
1154 | y = (GLdouble) pt[1] / w; |
||
1155 | z = (GLdouble) pt[2] / w; |
||
1156 | gluProject(x, y, z, model, proj, viewport, &winx, &winy, &winz); |
||
1157 | } |
||
1158 | if ((GLint) winx >= viewport[0] && (GLint) winx < viewport[2] && |
||
1159 | (GLint) winy >= viewport[1] && (GLint) winy < viewport[3]) |
||
1160 | return GL_TRUE; |
||
1161 | return GL_FALSE; |
||
1162 | } |
||
1163 | |||
1164 | GLboolean |
||
1165 | fine_culling_test_3D(GLUnurbsObj * nobj, GLfloat * pts, GLint s_cnt, |
||
1166 | GLint t_cnt, GLint s_stride, GLint t_stride, GLint dim) |
||
1167 | { |
||
1168 | GLint i, j; |
||
1169 | |||
1170 | if (nobj->culling == GL_FALSE) |
||
1171 | return GL_FALSE; |
||
1172 | set_sampling_and_culling(nobj); |
||
1173 | |||
1174 | if (dim == 3) { |
||
1175 | for (i = 0; i < s_cnt; i++) |
||
1176 | for (j = 0; j < t_cnt; j++) |
||
1177 | if (point_in_viewport(pts + i * s_stride + j * t_stride, dim)) { |
||
1178 | revert_sampling_and_culling(nobj); |
||
1179 | return GL_FALSE; |
||
1180 | } |
||
1181 | } |
||
1182 | else { |
||
1183 | for (i = 0; i < s_cnt; i++) |
||
1184 | for (j = 0; j < t_cnt; j++) |
||
1185 | if (point_in_viewport(pts + i * s_stride + j * t_stride, dim)) { |
||
1186 | revert_sampling_and_culling(nobj); |
||
1187 | return GL_FALSE; |
||
1188 | } |
||
1189 | } |
||
1190 | revert_sampling_and_culling(nobj); |
||
1191 | return GL_TRUE; |
||
1192 | } |
||
1193 | |||
1194 | /*GLboolean |
||
1195 | fine_culling_test_3D(GLUnurbsObj *nobj,GLfloat *pts,GLint s_cnt,GLint t_cnt, |
||
1196 | GLint s_stride,GLint t_stride, GLint dim) |
||
1197 | { |
||
1198 | GLint visible_cnt; |
||
1199 | GLfloat feedback_buffer[5]; |
||
1200 | GLsizei buffer_size; |
||
1201 | GLint i,j; |
||
1202 | |||
1203 | if(nobj->culling==GL_FALSE) |
||
1204 | return GL_FALSE; |
||
1205 | buffer_size=5; |
||
1206 | set_sampling_and_culling(nobj); |
||
1207 | |||
1208 | glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer); |
||
1209 | glRenderMode(GL_FEEDBACK); |
||
1210 | if(dim==3) |
||
1211 | { |
||
1212 | for(i=0;i<s_cnt;i++) |
||
1213 | { |
||
1214 | glBegin(GL_LINE_LOOP); |
||
1215 | for(j=0;j<t_cnt;j++) |
||
1216 | glVertex3fv(pts+i*s_stride+j*t_stride); |
||
1217 | glEnd(); |
||
1218 | } |
||
1219 | for(j=0;j<t_cnt;j++) |
||
1220 | { |
||
1221 | glBegin(GL_LINE_LOOP); |
||
1222 | for(i=0;i<s_cnt;i++) |
||
1223 | glVertex3fv(pts+i*s_stride+j*t_stride); |
||
1224 | glEnd(); |
||
1225 | } |
||
1226 | } |
||
1227 | else |
||
1228 | { |
||
1229 | for(i=0;i<s_cnt;i++) |
||
1230 | { |
||
1231 | glBegin(GL_LINE_LOOP); |
||
1232 | for(j=0;j<t_cnt;j++) |
||
1233 | glVertex4fv(pts+i*s_stride+j*t_stride); |
||
1234 | glEnd(); |
||
1235 | } |
||
1236 | for(j=0;j<t_cnt;j++) |
||
1237 | { |
||
1238 | glBegin(GL_LINE_LOOP); |
||
1239 | for(i=0;i<s_cnt;i++) |
||
1240 | glVertex4fv(pts+i*s_stride+j*t_stride); |
||
1241 | glEnd(); |
||
1242 | } |
||
1243 | } |
||
1244 | visible_cnt=glRenderMode(GL_RENDER); |
||
1245 | |||
1246 | revert_sampling_and_culling(nobj); |
||
1247 | return (GLboolean)(visible_cnt==0); |
||
1248 | }*/ |
||
1249 | |||
1250 | GLboolean |
||
1251 | fine_culling_test_2D(GLUnurbsObj * nobj, GLfloat * pts, GLint cnt, |
||
1252 | GLint stride, GLint dim) |
||
1253 | { |
||
1254 | GLint i; |
||
1255 | |||
1256 | if (nobj->culling == GL_FALSE) |
||
1257 | return GL_FALSE; |
||
1258 | set_sampling_and_culling(nobj); |
||
1259 | |||
1260 | if (dim == 3) { |
||
1261 | for (i = 0; i < cnt; i++) |
||
1262 | if (point_in_viewport(pts + i * stride, dim)) { |
||
1263 | revert_sampling_and_culling(nobj); |
||
1264 | return GL_FALSE; |
||
1265 | } |
||
1266 | } |
||
1267 | else { |
||
1268 | for (i = 0; i < cnt; i++) |
||
1269 | if (point_in_viewport(pts + i * stride, dim)) { |
||
1270 | revert_sampling_and_culling(nobj); |
||
1271 | return GL_FALSE; |
||
1272 | } |
||
1273 | } |
||
1274 | revert_sampling_and_culling(nobj); |
||
1275 | return GL_TRUE; |
||
1276 | } |
||
1277 | |||
1278 | /*GLboolean |
||
1279 | fine_culling_test_2D(GLUnurbsObj *nobj,GLfloat *pts,GLint cnt, |
||
1280 | GLint stride, GLint dim) |
||
1281 | { |
||
1282 | GLint visible_cnt; |
||
1283 | GLfloat feedback_buffer[5]; |
||
1284 | GLsizei buffer_size; |
||
1285 | GLint i; |
||
1286 | |||
1287 | if(nobj->culling==GL_FALSE) |
||
1288 | return GL_FALSE; |
||
1289 | buffer_size=5; |
||
1290 | set_sampling_and_culling(nobj); |
||
1291 | |||
1292 | glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer); |
||
1293 | glRenderMode(GL_FEEDBACK); |
||
1294 | glBegin(GL_LINE_LOOP); |
||
1295 | if(dim==3) |
||
1296 | { |
||
1297 | for(i=0;i<cnt;i++) |
||
1298 | glVertex3fv(pts+i*stride); |
||
1299 | } |
||
1300 | else |
||
1301 | { |
||
1302 | for(i=0;i<cnt;i++) |
||
1303 | glVertex4fv(pts+i*stride); |
||
1304 | } |
||
1305 | glEnd(); |
||
1306 | visible_cnt=glRenderMode(GL_RENDER); |
||
1307 | |||
1308 | revert_sampling_and_culling(nobj); |
||
1309 | return (GLboolean)(visible_cnt==0); |
||
1310 | }*/ |