Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: nurbscrv.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
static int
41
get_curve_dim(GLenum type)
42
{
43
   switch (type) {
44
   case GL_MAP1_VERTEX_3:
45
      return 3;
46
   case GL_MAP1_VERTEX_4:
47
      return 4;
48
   case GL_MAP1_INDEX:
49
      return 1;
50
   case GL_MAP1_COLOR_4:
51
      return 4;
52
   case GL_MAP1_NORMAL:
53
      return 3;
54
   case GL_MAP1_TEXTURE_COORD_1:
55
      return 1;
56
   case GL_MAP1_TEXTURE_COORD_2:
57
      return 2;
58
   case GL_MAP1_TEXTURE_COORD_3:
59
      return 3;
60
   case GL_MAP1_TEXTURE_COORD_4:
61
      return 4;
62
   default:
63
      abort();                  /* TODO: is this OK? */
64
   }
65
   return 0;                    /*never get here */
66
}
67
 
68
static GLenum
69
test_nurbs_curve(GLUnurbsObj * nobj, curve_attribs * attribs)
70
{
71
   GLenum err;
72
   GLint tmp_int;
73
 
74
   if (attribs->order < 0) {
75
      call_user_error(nobj, GLU_INVALID_VALUE);
76
      return GLU_ERROR;
77
   }
78
   glGetIntegerv(GL_MAX_EVAL_ORDER, &tmp_int);
79
   if (attribs->order > tmp_int || attribs->order < 2) {
80
      call_user_error(nobj, GLU_NURBS_ERROR1);
81
      return GLU_ERROR;
82
   }
83
   if (attribs->knot_count < attribs->order + 2) {
84
      call_user_error(nobj, GLU_NURBS_ERROR2);
85
      return GLU_ERROR;
86
   }
87
   if (attribs->stride < 0) {
88
      call_user_error(nobj, GLU_NURBS_ERROR34);
89
      return GLU_ERROR;
90
   }
91
   if (attribs->knot == NULL || attribs->ctrlarray == NULL) {
92
      call_user_error(nobj, GLU_NURBS_ERROR36);
93
      return GLU_ERROR;
94
   }
95
   if ((err = test_knot(attribs->knot_count, attribs->knot, attribs->order))
96
       != GLU_NO_ERROR) {
97
      call_user_error(nobj, err);
98
      return GLU_ERROR;
99
   }
100
   return GLU_NO_ERROR;
101
}
102
 
103
static GLenum
104
test_nurbs_curves(GLUnurbsObj * nobj)
105
{
106
   /* test the geometric data */
107
   if (test_nurbs_curve(nobj, &(nobj->curve.geom)) != GLU_NO_ERROR)
108
      return GLU_ERROR;
109
   /* now test the attributive data */
110
   /* color */
111
   if (nobj->curve.color.type != GLU_INVALID_ENUM)
112
      if (test_nurbs_curve(nobj, &(nobj->curve.color)) != GLU_NO_ERROR)
113
         return GLU_ERROR;
114
   /* normal */
115
   if (nobj->curve.normal.type != GLU_INVALID_ENUM)
116
      if (test_nurbs_curve(nobj, &(nobj->curve.normal)) != GLU_NO_ERROR)
117
         return GLU_ERROR;
118
   /* texture */
119
   if (nobj->curve.texture.type != GLU_INVALID_ENUM)
120
      if (test_nurbs_curve(nobj, &(nobj->curve.texture)) != GLU_NO_ERROR)
121
         return GLU_ERROR;
122
   return GLU_NO_ERROR;
123
}
124
 
125
/* prepare the knot information structures */
126
static GLenum
127
fill_knot_structures(GLUnurbsObj * nobj, knot_str_type * geom_knot,
128
                     knot_str_type * color_knot, knot_str_type * normal_knot,
129
                     knot_str_type * texture_knot)
130
{
131
   GLint order;
132
   GLfloat *knot;
133
   GLint nknots;
134
   GLint t_min, t_max;
135
 
136
   geom_knot->unified_knot = NULL;
137
   knot = geom_knot->knot = nobj->curve.geom.knot;
138
   nknots = geom_knot->nknots = nobj->curve.geom.knot_count;
139
   order = geom_knot->order = nobj->curve.geom.order;
140
   geom_knot->delta_nknots = 0;
141
   t_min = geom_knot->t_min = order - 1;
142
   t_max = geom_knot->t_max = nknots - order;
143
   if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
144
      call_user_error(nobj, GLU_NURBS_ERROR3);
145
      return GLU_ERROR;
146
   }
147
   if (fabs(knot[0] - knot[t_min]) < EPSILON) {
148
      /* knot open at beggining */
149
      geom_knot->open_at_begin = GL_TRUE;
150
   }
151
   else
152
      geom_knot->open_at_begin = GL_FALSE;
153
   if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
154
      /* knot open at end */
155
      geom_knot->open_at_end = GL_TRUE;
156
   }
157
   else
158
      geom_knot->open_at_end = GL_FALSE;
159
   if (nobj->curve.color.type != GLU_INVALID_ENUM) {
160
      color_knot->unified_knot = (GLfloat *) 1;
161
      knot = color_knot->knot = nobj->curve.color.knot;
162
      nknots = color_knot->nknots = nobj->curve.color.knot_count;
163
      order = color_knot->order = nobj->curve.color.order;
164
      color_knot->delta_nknots = 0;
165
      t_min = color_knot->t_min = order - 1;
166
      t_max = color_knot->t_max = nknots - order;
167
      if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
168
         call_user_error(nobj, GLU_NURBS_ERROR3);
169
         return GLU_ERROR;
170
      }
171
      if (fabs(knot[0] - knot[t_min]) < EPSILON) {
172
         /* knot open at beggining */
173
         color_knot->open_at_begin = GL_TRUE;
174
      }
175
      else
176
         color_knot->open_at_begin = GL_FALSE;
177
      if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
178
         /* knot open at end */
179
         color_knot->open_at_end = GL_TRUE;
180
      }
181
      else
182
         color_knot->open_at_end = GL_FALSE;
183
   }
184
   else
185
      color_knot->unified_knot = NULL;
186
   if (nobj->curve.normal.type != GLU_INVALID_ENUM) {
187
      normal_knot->unified_knot = (GLfloat *) 1;
188
      knot = normal_knot->knot = nobj->curve.normal.knot;
189
      nknots = normal_knot->nknots = nobj->curve.normal.knot_count;
190
      order = normal_knot->order = nobj->curve.normal.order;
191
      normal_knot->delta_nknots = 0;
192
      t_min = normal_knot->t_min = order - 1;
193
      t_max = normal_knot->t_max = nknots - order;
194
      if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
195
         call_user_error(nobj, GLU_NURBS_ERROR3);
196
         return GLU_ERROR;
197
      }
198
      if (fabs(knot[0] - knot[t_min]) < EPSILON) {
199
         /* knot open at beggining */
200
         normal_knot->open_at_begin = GL_TRUE;
201
      }
202
      else
203
         normal_knot->open_at_begin = GL_FALSE;
204
      if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
205
         /* knot open at end */
206
         normal_knot->open_at_end = GL_TRUE;
207
      }
208
      else
209
         normal_knot->open_at_end = GL_FALSE;
210
   }
211
   else
212
      normal_knot->unified_knot = NULL;
213
   if (nobj->curve.texture.type != GLU_INVALID_ENUM) {
214
      texture_knot->unified_knot = (GLfloat *) 1;
215
      knot = texture_knot->knot = nobj->curve.texture.knot;
216
      nknots = texture_knot->nknots = nobj->curve.texture.knot_count;
217
      order = texture_knot->order = nobj->curve.texture.order;
218
      texture_knot->delta_nknots = 0;
219
      t_min = texture_knot->t_min = order - 1;
220
      t_max = texture_knot->t_max = nknots - order;
221
      if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
222
         call_user_error(nobj, GLU_NURBS_ERROR3);
223
         return GLU_ERROR;
224
      }
225
      if (fabs(knot[0] - knot[t_min]) < EPSILON) {
226
         /* knot open at beggining */
227
         texture_knot->open_at_begin = GL_TRUE;
228
      }
229
      else
230
         texture_knot->open_at_begin = GL_FALSE;
231
      if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
232
         /* knot open at end */
233
         texture_knot->open_at_end = GL_TRUE;
234
      }
235
      else
236
         texture_knot->open_at_end = GL_FALSE;
237
   }
238
   else
239
      texture_knot->unified_knot = NULL;
240
   return GLU_NO_ERROR;
241
}
242
 
243
/* covert the NURBS curve into a series of adjacent Bezier curves */
244
static GLenum
245
convert_curve(knot_str_type * the_knot, curve_attribs * attrib,
246
              GLfloat ** new_ctrl, GLint * ncontrol)
247
{
248
   GLenum err;
249
 
250
   if ((err = explode_knot(the_knot)) != GLU_NO_ERROR) {
251
      if (the_knot->unified_knot) {
252
         free(the_knot->unified_knot);
253
         the_knot->unified_knot = NULL;
254
      }
255
      return err;
256
   }
257
   if (the_knot->unified_knot) {
258
      free(the_knot->unified_knot);
259
      the_knot->unified_knot = NULL;
260
   }
261
   if ((err = calc_alphas(the_knot)) != GLU_NO_ERROR) {
262
      free(the_knot->new_knot);
263
      return err;
264
   }
265
   free(the_knot->new_knot);
266
   if ((err = calc_new_ctrl_pts(attrib->ctrlarray, attrib->stride, the_knot,
267
                                attrib->dim, new_ctrl, ncontrol))
268
       != GLU_NO_ERROR) {
269
      free(the_knot->alpha);
270
      return err;
271
   }
272
   free(the_knot->alpha);
273
   return GLU_NO_ERROR;
274
}
275
 
276
/* covert curves - geometry and possible attribute ones into equivalent */
277
/* sequence of adjacent Bezier curves */
278
static GLenum
279
convert_curves(GLUnurbsObj * nobj, GLfloat ** new_geom_ctrl,
280
               GLint * ncontrol, GLfloat ** new_color_ctrl,
281
               GLfloat ** new_normal_ctrl, GLfloat ** new_texture_ctrl)
282
{
283
   knot_str_type geom_knot, color_knot, normal_knot, texture_knot;
284
   GLint junk;
285
   GLenum err;
286
 
287
   *new_color_ctrl = *new_normal_ctrl = *new_texture_ctrl = NULL;
288
 
289
   if (fill_knot_structures(nobj, &geom_knot, &color_knot, &normal_knot,
290
                            &texture_knot) != GLU_NO_ERROR)
291
      return GLU_ERROR;
292
 
293
   /* unify knots - all knots should have the same number of working */
294
   /* ranges */
295
   if (
296
       (err =
297
        select_knot_working_range(nobj, &geom_knot, &color_knot, &normal_knot,
298
                                  &texture_knot)) != GLU_NO_ERROR) {
299
      return err;
300
   }
301
   /* convert the geometry curve */
302
   nobj->curve.geom.dim = get_curve_dim(nobj->curve.geom.type);
303
   if ((err = convert_curve(&geom_knot, &(nobj->curve.geom), new_geom_ctrl,
304
                            ncontrol)) != GLU_NO_ERROR) {
305
      free_unified_knots(&geom_knot, &color_knot, &normal_knot,
306
                         &texture_knot);
307
      call_user_error(nobj, err);
308
      return err;
309
   }
310
   /* if additional attributive curves are given convert them as well */
311
   if (color_knot.unified_knot) {
312
      nobj->curve.color.dim = get_curve_dim(nobj->curve.color.type);
313
      if ((err = convert_curve(&color_knot, &(nobj->curve.color),
314
                               new_color_ctrl, &junk)) != GLU_NO_ERROR) {
315
         free_unified_knots(&geom_knot, &color_knot, &normal_knot,
316
                            &texture_knot);
317
         free(*new_geom_ctrl);
318
         call_user_error(nobj, err);
319
         return err;
320
      }
321
   }
322
   if (normal_knot.unified_knot) {
323
      nobj->curve.normal.dim = get_curve_dim(nobj->curve.normal.type);
324
      if ((err = convert_curve(&normal_knot, &(nobj->curve.normal),
325
                               new_normal_ctrl, &junk)) != GLU_NO_ERROR) {
326
         free_unified_knots(&geom_knot, &color_knot, &normal_knot,
327
                            &texture_knot);
328
         free(*new_geom_ctrl);
329
         if (*new_color_ctrl)
330
            free(*new_color_ctrl);
331
         call_user_error(nobj, err);
332
         return err;
333
      }
334
   }
335
   if (texture_knot.unified_knot) {
336
      nobj->curve.texture.dim = get_curve_dim(nobj->curve.texture.type);
337
      if ((err = convert_curve(&texture_knot, &(nobj->curve.texture),
338
                               new_texture_ctrl, &junk)) != GLU_NO_ERROR) {
339
         free_unified_knots(&geom_knot, &color_knot, &normal_knot,
340
                            &texture_knot);
341
         free(*new_geom_ctrl);
342
         if (*new_color_ctrl)
343
            free(*new_color_ctrl);
344
         if (*new_normal_ctrl)
345
            free(*new_normal_ctrl);
346
         call_user_error(nobj, err);
347
         return err;
348
      }
349
   }
350
   return GLU_NO_ERROR;
351
}
352
 
353
/* main NURBS curve procedure */
354
void
355
do_nurbs_curve(GLUnurbsObj * nobj)
356
{
357
   GLint geom_order, color_order = 0, normal_order = 0, texture_order = 0;
358
   GLenum geom_type;
359
   GLint n_ctrl;
360
   GLfloat *new_geom_ctrl, *new_color_ctrl, *new_normal_ctrl,
361
      *new_texture_ctrl;
362
   GLfloat *geom_ctrl = 0, *color_ctrl = 0, *normal_ctrl = 0, *texture_ctrl = 0;
363
   GLint *factors;
364
   GLint i, j;
365
   GLint geom_dim, color_dim = 0, normal_dim = 0, texture_dim = 0;
366
 
367
   /* test the user supplied data */
368
   if (test_nurbs_curves(nobj) != GLU_NO_ERROR)
369
      return;
370
 
371
   if (convert_curves(nobj, &new_geom_ctrl, &n_ctrl, &new_color_ctrl,
372
                      &new_normal_ctrl, &new_texture_ctrl) != GLU_NO_ERROR)
373
      return;
374
 
375
   geom_order = nobj->curve.geom.order;
376
   geom_type = nobj->curve.geom.type;
377
   geom_dim = nobj->curve.geom.dim;
378
 
379
   if (glu_do_sampling_crv(nobj, new_geom_ctrl, n_ctrl, geom_order, geom_dim,
380
                           &factors) != GLU_NO_ERROR) {
381
      free(new_geom_ctrl);
382
      if (new_color_ctrl)
383
         free(new_color_ctrl);
384
      if (new_normal_ctrl)
385
         free(new_normal_ctrl);
386
      if (new_texture_ctrl)
387
         free(new_texture_ctrl);
388
      return;
389
   }
390
   glEnable(geom_type);
391
   if (new_color_ctrl) {
392
      glEnable(nobj->curve.color.type);
393
      color_dim = nobj->curve.color.dim;
394
      color_ctrl = new_color_ctrl;
395
      color_order = nobj->curve.color.order;
396
   }
397
   if (new_normal_ctrl) {
398
      glEnable(nobj->curve.normal.type);
399
      normal_dim = nobj->curve.normal.dim;
400
      normal_ctrl = new_normal_ctrl;
401
      normal_order = nobj->curve.normal.order;
402
   }
403
   if (new_texture_ctrl) {
404
      glEnable(nobj->curve.texture.type);
405
      texture_dim = nobj->curve.texture.dim;
406
      texture_ctrl = new_texture_ctrl;
407
      texture_order = nobj->curve.texture.order;
408
   }
409
   for (i = 0, j = 0, geom_ctrl = new_geom_ctrl;
410
        i < n_ctrl; i += geom_order, j++, geom_ctrl += geom_order * geom_dim) {
411
      if (fine_culling_test_2D
412
          (nobj, geom_ctrl, geom_order, geom_dim, geom_dim)) {
413
         color_ctrl += color_order * color_dim;
414
         normal_ctrl += normal_order * normal_dim;
415
         texture_ctrl += texture_order * texture_dim;
416
         continue;
417
      }
418
      glMap1f(geom_type, 0.0, 1.0, geom_dim, geom_order, geom_ctrl);
419
      if (new_color_ctrl) {
420
         glMap1f(nobj->curve.color.type, 0.0, 1.0, color_dim,
421
                 color_order, color_ctrl);
422
         color_ctrl += color_order * color_dim;
423
      }
424
      if (new_normal_ctrl) {
425
         glMap1f(nobj->curve.normal.type, 0.0, 1.0, normal_dim,
426
                 normal_order, normal_ctrl);
427
         normal_ctrl += normal_order * normal_dim;
428
      }
429
      if (new_texture_ctrl) {
430
         glMap1f(nobj->curve.texture.type, 0.0, 1.0, texture_dim,
431
                 texture_order, texture_ctrl);
432
         texture_ctrl += texture_order * texture_dim;
433
      }
434
      glMapGrid1f(factors[j], 0.0, 1.0);
435
      glEvalMesh1(GL_LINE, 0, factors[j]);
436
   }
437
   free(new_geom_ctrl);
438
   free(factors);
439
   if (new_color_ctrl)
440
      free(new_color_ctrl);
441
   if (new_normal_ctrl)
442
      free(new_normal_ctrl);
443
   if (new_texture_ctrl)
444
      free(new_texture_ctrl);
445
}