reshuffling of dlls
[reactos.git] / reactos / dll / win32 / glu32 / libnurbs / internals / tobezier.cc
1 /*
2 ** License Applicability. Except to the extent portions of this file are
3 ** made subject to an alternative license as permitted in the SGI Free
4 ** Software License B, Version 1.1 (the "License"), the contents of this
5 ** file are subject only to the provisions of the License. You may not use
6 ** this file except in compliance with the License. You may obtain a copy
7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
9 **
10 ** http://oss.sgi.com/projects/FreeB
11 **
12 ** Note that, as provided in the License, the Software is distributed on an
13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
17 **
18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21 ** Copyright in any portions created by third parties is as indicated
22 ** elsewhere herein. All Rights Reserved.
23 **
24 ** Additional Notice Provisions: The application programming interfaces
25 ** established by SGI in conjunction with the Original Code are The
26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31 ** published by SGI, but has not been independently verified as being
32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
33 */
34
35 /*
36 * tobezier.c++
37 *
38 * $Date$ $Revision: 1.1 $
39 * $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/glu32/libnurbs/internals/tobezier.cc,v 1.1 2004/02/02 16:39:13 navaraf Exp $
40 */
41
42 #include "glimports.h"
43 #include "myassert.h"
44 #include "mystdio.h"
45 #include "mystring.h"
46 #include "quilt.h"
47 #include "knotvector.h"
48
49 /* local type definitions */
50 struct Breakpt { /* breakpoints */
51 Knot value; /* value */
52 int multi; /* multiplicity */
53 int def; /* deficit */
54 };
55
56 struct Knotspec { /* knotvector format */
57 long order; /* order of spline */
58 Knot_ptr inkbegin; /* input knot sequence */
59 Knot_ptr inkend; /* location after last knot */
60 Knot_ptr outkbegin; /* in-process knot subsequence */
61 Knot_ptr outkend; /* location after last knot */
62 Knot_ptr kleft; /* */
63 Knot_ptr kright; /* */
64 Knot_ptr kfirst; /* */
65 Knot_ptr klast; /* */
66 Knot_ptr sbegin; /* conversion factor values */
67 Breakpt * bbegin; /* in-process breakpoints */
68 Breakpt * bend; /* last breakpoint */
69 int ncoords; /* coordinates per control point */
70 int prestride; /* stride between input points */
71 int poststride; /* stride between output points */
72 int preoffset; /* scaled point offset */
73 int postoffset; /* scaled point offset */
74 int prewidth; /* width of dimension */
75 int postwidth; /* width of dimension */
76 int istransformed; /* was dimension transformed */
77 Knotspec * next; /* next knotspec */
78 Knotspec * kspectotrans; /* knotspec in transformation direction */
79
80 Knotspec( void );
81 ~Knotspec( void );
82 void factors( void );
83 void insert( REAL * );
84 void preselect();
85 void select( void );
86 void copy( INREAL *, REAL * );
87 void breakpoints( void );
88 void knots( void );
89 void transform( REAL * );
90 void showpts( REAL * );
91
92 void pt_io_copy( REAL *, INREAL * );
93 void pt_oo_copy( REAL *, REAL * );
94 void pt_oo_sum( REAL*, REAL*, REAL*, Knot, Knot );
95 };
96
97 struct Splinespec { /* a non-uniform tensor element */
98 Splinespec( int );
99 ~Splinespec(void);
100 Knotspec *kspec; /* format of each param. dir. */
101 int dim; /* domain dimension */
102 REAL * outcpts; /* Bezier control points */
103
104 void kspecinit( Knotvector & );
105 void kspecinit( Knotvector &, Knotvector & );
106 void select( void );
107 void layout( long );
108 void setupquilt( Quilt_ptr );
109 void copy( INREAL * );
110 void transform( void );
111 };
112
113 /*-----------------------------------------------------------------------------
114 * Quilt::toBezier - convert from NURBS to rational Bezier
115 *-----------------------------------------------------------------------------
116 */
117
118 void
119 Quilt::toBezier(
120 Knotvector& knotvector, /* a knot vector */
121 INREAL *ctlpts, /* input contol points */
122 long ncoords ) /* number of coordinates per control point */
123 {
124 Splinespec spline( 1 );
125 spline.kspecinit( knotvector );
126 spline.select();
127 spline.layout( ncoords );
128 spline.setupquilt( this );
129 spline.copy( ctlpts );
130 spline.transform();
131 }
132
133 void
134 Quilt::toBezier(
135 Knotvector& sknotvector, /* a knot vector */
136 Knotvector& tknotvector, /* a knot vector */
137 INREAL *ctlpts, /* input contol points */
138 long ncoords ) /* number of coordinates per control point */
139 {
140 Splinespec spline( 2 );
141 spline.kspecinit( sknotvector, tknotvector );
142 spline.select();
143 spline.layout( ncoords );
144 spline.setupquilt( this );
145 spline.copy( ctlpts );
146 spline.transform();
147 }
148 Splinespec::Splinespec( int dimen )
149 {
150 dim = dimen;
151 }
152
153 Splinespec::~Splinespec( void )
154 {
155 /* Note: do NOT delete 'outcpts' here since its address (not contents)
156 * is copied in 'cpts' in this file in function Splinespec::setupquilt().
157 * This block of memory will eventually be deleted in file quilt.c++ in
158 * function Quilt::deleteMe() through 'cpts' so do NOT delete it here!
159 */
160 Knotspec *ktrav= kspec; //start at beginning of list
161 while (ktrav != 0) { //any items to delete?
162 Knotspec *deleteThis= ktrav; //remember to delete this
163 ktrav= ktrav->next; //go to next item if any
164 delete deleteThis; //delete it
165 }
166 } /* ~Splinespec() */
167
168 /*-----------------------------------------------------------------------------
169 * Splinespec::kspecinit - initialize Splinespec structure
170 *
171 * Client: Quilt::toBezier
172 *-----------------------------------------------------------------------------
173 */
174
175 void
176 Splinespec::kspecinit( Knotvector& knotvector )
177 {
178 kspec = new Knotspec;
179 kspec->inkbegin = knotvector.knotlist;
180 kspec->inkend = knotvector.knotlist + knotvector.knotcount;
181 kspec->prestride = (int) knotvector.stride;
182 kspec->order = knotvector.order;
183 kspec->next = NULL;
184 }
185
186 void
187 Splinespec::kspecinit( Knotvector& sknotvector, Knotvector& tknotvector )
188 {
189 kspec = new Knotspec;
190 Knotspec *tkspec = new Knotspec;
191
192 kspec->inkbegin = sknotvector.knotlist;
193 kspec->inkend = sknotvector.knotlist + sknotvector.knotcount;
194 kspec->prestride = (int) sknotvector.stride;
195 kspec->order = sknotvector.order;
196 kspec->next = tkspec;
197
198 tkspec->inkbegin = tknotvector.knotlist;
199 tkspec->inkend = tknotvector.knotlist + tknotvector.knotcount;
200 tkspec->prestride = (int) tknotvector.stride;
201 tkspec->order = tknotvector.order;
202 tkspec->next = NULL;
203 }
204
205
206 /*-----------------------------------------------------------------------------
207 * Splinespec::select - select the subsegments to copy
208 *
209 * Client: gl_quilt_to_bezier
210 *-----------------------------------------------------------------------------
211 */
212
213 void
214 Splinespec::select( )
215 {
216 for( Knotspec *knotspec = kspec; knotspec; knotspec = knotspec->next ) {
217 knotspec->preselect();
218 knotspec->select();
219 }
220 }
221
222 /*-----------------------------------------------------------------------------
223 * Splinespec::layout -
224 *
225 * Client: gl_quilt_to_bezier
226 *-----------------------------------------------------------------------------
227 */
228
229 void
230 Splinespec::layout( long ncoords )
231 {
232
233 long stride = ncoords;
234 for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next ) {
235 knotspec->poststride = (int) stride;
236 stride *= ((knotspec->bend-knotspec->bbegin)*knotspec->order + knotspec->postoffset);
237 knotspec->preoffset *= knotspec->prestride;
238 knotspec->prewidth *= knotspec->poststride;
239 knotspec->postwidth *= knotspec->poststride;
240 knotspec->postoffset *= knotspec->poststride;
241 knotspec->ncoords = (int) ncoords;
242 }
243 outcpts = new REAL[stride];
244 assert( outcpts != 0 );
245 }
246
247 /*-----------------------------------------------------------------------------
248 * Splinespec::copy - copy the control points of current subobject
249 *
250 * Client: gl_quilt_to_bezier
251 *-----------------------------------------------------------------------------
252 */
253
254 void
255 Splinespec::copy( INREAL *incpts )
256 {
257 kspec->copy( incpts, outcpts );
258 }
259
260 /*-----------------------------------------------------------------------------
261 * Splinespec::setupquilt - assign all quilt variables from knotspec
262 *
263 * Client: gl_quilt_to_bezier
264 *-----------------------------------------------------------------------------
265 */
266
267 void
268 Splinespec::setupquilt( Quilt_ptr quilt )
269 {
270 Quiltspec_ptr qspec = quilt->qspec;
271 quilt->eqspec = qspec + dim;
272 for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next, qspec++ ) {
273 qspec->stride = knotspec->poststride;
274 qspec->width = knotspec->bend - knotspec->bbegin;
275 qspec->order = (int) knotspec->order;
276 qspec->offset = knotspec->postoffset;
277 qspec->index = 0;
278 qspec->bdry[0] = (knotspec->kleft == knotspec->kfirst) ? 1 : 0;
279 qspec->bdry[1] = (knotspec->kright == knotspec->klast) ? 1 : 0;
280 qspec->breakpoints = new Knot[qspec->width+1];
281 Knot_ptr k = qspec->breakpoints;
282 for( Breakpt *bk = knotspec->bbegin; bk <= knotspec->bend; bk++ )
283 *(k++) = bk->value;
284 }
285 quilt->cpts = outcpts;
286 quilt->next = 0;
287 }
288
289 /*-----------------------------------------------------------------------------
290 * Splinespec::transform - convert a spline to Bezier format
291 *
292 * Client: gl_quilt_to_bezier
293 *-----------------------------------------------------------------------------
294 */
295
296 void
297 Splinespec::transform( void )
298 {
299 Knotspec *knotspec;
300 for( knotspec = kspec; knotspec; knotspec=knotspec->next )
301 knotspec->istransformed = 0;
302
303 for( knotspec = kspec; knotspec; knotspec=knotspec->next ) {
304 for( Knotspec *kspec2 = kspec; kspec2; kspec2=kspec2->next )
305 kspec2->kspectotrans = knotspec;
306 kspec->transform( outcpts );
307 knotspec->istransformed = 1;
308 }
309 }
310
311
312 /*-----------------------------------------------------------------------------
313 * Knotspec::Knotspec - constuct a knot spec
314 *-----------------------------------------------------------------------------
315 */
316
317 Knotspec::Knotspec( void )
318 {
319 bbegin = 0;
320 sbegin = 0;
321 outkbegin = 0;
322 }
323
324 /*-----------------------------------------------------------------------------
325 * Knotspec::copy - copy the control points along minor direction
326 *
327 * Client: Splinespec::copy
328 *-----------------------------------------------------------------------------
329 */
330
331 void
332 Knotspec::copy( INREAL *inpt, REAL *outpt )
333 {
334 inpt = (INREAL *) (((char *) inpt) + preoffset);
335
336 if( next ) {
337 for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
338 next->copy( inpt, outpt );
339 inpt = (INREAL *) (((char *) inpt) + prestride);
340 }
341 } else {
342 for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
343 pt_io_copy( outpt, inpt );
344 inpt = (INREAL *) (((char *) inpt) + prestride);
345 }
346 }
347 }
348
349 /*-----------------------------------------------------------------------------
350 * Knotspec::showpts - print out points before transformation
351 *
352 * Client: Knotspec::select
353 *-----------------------------------------------------------------------------
354 */
355 void
356 Knotspec::showpts( REAL *outpt )
357 {
358 if( next ) {
359 for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
360 next->showpts( outpt );
361 } else {
362 for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
363 dprintf( "show %g %g %g\n", outpt[0], outpt[1], outpt[2] );
364 }
365 }
366
367 /*-----------------------------------------------------------------------------
368 * Knotspec::factors - precompute scale factors
369 * - overwrites knot vector, actual new knot vector is NOT produced
370 *
371 * Client: Knotspec::select
372 *-----------------------------------------------------------------------------
373 */
374
375 void
376 Knotspec::factors( void )
377 {
378 Knot *mid = (outkend - 1) - order + bend->multi;
379 Knot_ptr fptr = sbegin;
380
381 for( Breakpt *bpt = bend; bpt >= bbegin; bpt-- ) {
382 mid -= bpt->multi; // last knot less than knot to insert
383 int def = bpt->def - 1; // number of knots to insert
384 if( def <= 0 ) continue;
385 Knot kv = bpt->value; // knot to insert
386
387 Knot *kf = (mid-def) + (order-1);
388 for( Knot *kl = kf + def; kl != kf; kl-- ) {
389 Knot *kh, *kt;
390 for( kt=kl, kh=mid; kt != kf; kh--, kt-- )
391 *(fptr++) = (kv - *kh) / (*kt - *kh);
392 *kl = kv;
393 }
394 }
395 }
396
397 /*-----------------------------------------------------------------------------
398 * Knotspec::insert - convert subobject in direction of kspec into Bezier
399 *
400 * Client: Knotspec::transform
401 *-----------------------------------------------------------------------------
402 */
403
404 void
405 Knotspec::insert( REAL *p )
406 {
407 Knot_ptr fptr = sbegin;
408 REAL *srcpt = p + prewidth - poststride;
409 REAL *dstpt = p + postwidth + postoffset - poststride;
410 Breakpt *bpt = bend;
411
412 for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride ) {
413 REAL *p1 = srcpt;
414 for( REAL *p2 = srcpt-poststride; p2 != pend; p1 = p2, p2 -= poststride ) {
415 pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
416 fptr++;
417 }
418 }
419
420 for( --bpt; bpt >= bbegin; bpt-- ) {
421
422 for( int multi = bpt->multi; multi > 0; multi-- ) {
423 pt_oo_copy( dstpt, srcpt );
424 dstpt -= poststride;
425 srcpt -= poststride;
426 }
427
428 for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride, dstpt-=poststride ) {
429 pt_oo_copy( dstpt, srcpt );
430 REAL *p1 = srcpt;
431
432 for( REAL *p2 = srcpt-poststride; p2 != pend; p1=p2, p2 -= poststride ) {
433 pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
434 fptr++;
435 }
436 }
437 }
438 }
439
440 /*-----------------------------------------------------------------------------
441 * Knotspec::preselect - initialize kspec for processing
442 *
443 * Client: Splinespec::select
444 *-----------------------------------------------------------------------------
445 */
446
447 void
448 Knotspec::preselect( void )
449 {
450 Knot kval;
451
452 /* position klast after last knot of "last" breakpoint */
453 for( klast = inkend - order, kval = *klast; klast != inkend; klast++ )
454 if( ! identical( *klast, kval ) ) break;
455
456 /* position kfirst after last knot of "first" breakpoint */
457 for( kfirst = inkbegin+order-1, kval= *kfirst; kfirst != inkend; kfirst++ )
458 if( ! identical( *kfirst, kval ) ) break;
459
460 /* compute multiplicity of first breakpoint */
461 Knot_ptr k;
462 for( k = kfirst - 1; k >= inkbegin; k-- )
463 if( ! identical( kval, *k ) ) break;
464 k++;
465
466 /* allocate space for breakpoints -
467 use worst case estimate on number of breakpoints */
468
469 bbegin = new Breakpt[(klast - kfirst)+1];
470 /* record multiplicity and value of first breakpoint */
471 bbegin->multi = kfirst - k;
472 bbegin->value = kval;
473 bend = bbegin;
474
475 kleft = kright = kfirst;
476 }
477
478
479 /*-----------------------------------------------------------------------------
480 * Knotspec::select - Knotspec::select segments and precompute scale factors
481 *
482 * Client: Splinespec::select
483 *-----------------------------------------------------------------------------
484 */
485
486 void
487 Knotspec::select( void )
488 {
489 breakpoints();
490 knots();
491 factors();
492
493 preoffset = kleft - (inkbegin + order);
494 postwidth = (int)((bend - bbegin) * order);
495 prewidth = (int)((outkend - outkbegin) - order);
496 postoffset = (bbegin->def > 1) ? (bbegin->def-1) : 0;
497 }
498
499 /*-----------------------------------------------------------------------------
500 * Knotspec::breakpoints - compute breakpoints for knotspec
501 *
502 * Client: Knotspec::select
503 *-----------------------------------------------------------------------------
504 */
505
506 void
507 Knotspec::breakpoints( void )
508 {
509 Breakpt *ubpt = bbegin;
510 Breakpt *ubend = bend;
511 long nfactors = 0;
512
513 ubpt->value = ubend->value;
514 ubpt->multi = ubend->multi;
515
516 kleft = kright;
517
518 for( ; kright != klast; kright++ ) {
519 if ( identical(*kright,ubpt->value) ) {
520 (ubpt->multi)++;
521 } else {
522 ubpt->def = (int) (order - ubpt->multi);
523 nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
524 (++ubpt)->value = *kright;
525 ubpt->multi = 1;
526 }
527 }
528 ubpt->def = (int) (order - ubpt->multi);
529 nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
530
531 bend = ubpt;
532
533 if( nfactors ) {
534 sbegin = new Knot[nfactors];
535 } else {
536 sbegin = NULL;
537 }
538 }
539
540
541 /*-----------------------------------------------------------------------------
542 * Knotspec::knots - copy relevant subsequence of knots into temporary area
543 *
544 * Client: Knotspec::select
545 *-----------------------------------------------------------------------------
546 */
547
548 void
549 Knotspec::knots( void )
550 {
551 Knot_ptr inkpt = kleft - order;
552 Knot_ptr inkend = kright + bend->def;
553
554 /* allocate space for knots and factors */
555 outkbegin = new Knot[inkend-inkpt];
556 Knot_ptr outkpt;
557 for( outkpt = outkbegin; inkpt != inkend; inkpt++, outkpt++ )
558 *outkpt = *inkpt;
559
560 outkend = outkpt;
561 }
562
563
564 /*-----------------------------------------------------------------------------
565 * Knotspec::transform - convert a spline along a given direction
566 *
567 * Client: Splienspec::transform
568 *-----------------------------------------------------------------------------
569 */
570
571 void
572 Knotspec::transform( REAL *p )
573 {
574 if( next ) {
575 if( this == kspectotrans ) {
576 next->transform( p );
577 } else {
578 if( istransformed ) {
579 p += postoffset;
580 for( REAL *pend = p + postwidth; p != pend; p += poststride )
581 next->transform( p );
582 } else {
583 REAL *pend = p + prewidth;
584 for( ; p != pend; p += poststride )
585 next->transform( p );
586 }
587 }
588 } else {
589 if( this == kspectotrans ) {
590 insert( p );
591 } else {
592 if( istransformed ) {
593 p += postoffset;
594 for( REAL *pend = p + postwidth; p != pend; p += poststride )
595 kspectotrans->insert( p );
596 } else {
597 REAL *pend = p + prewidth;
598 for( ; p != pend; p += poststride )
599 kspectotrans->insert( p );
600 }
601 }
602 }
603 }
604
605 /*-----------------------------------------------------------------------------
606 * Knotspec::~Knotspec - free space alocated for knotspec
607 *-----------------------------------------------------------------------------
608 */
609
610 Knotspec::~Knotspec( void )
611 {
612 if( bbegin ) delete[] bbegin;
613 if( sbegin ) delete[] sbegin;
614 if( outkbegin ) delete[] outkbegin;
615 }
616
617
618 /*-----------------------------------------------------------------------------
619 * pt_io_copy - make internal copy of input cntrl pt. of x coords
620 *-----------------------------------------------------------------------------
621 */
622
623 void
624 Knotspec::pt_io_copy( REAL *topt, INREAL *frompt )
625 {
626 switch( ncoords ) {
627 case 4:
628 topt[3] = (REAL) frompt[3];
629 case 3:
630 topt[2] = (REAL) frompt[2];
631 case 2:
632 topt[1] = (REAL) frompt[1];
633 case 1:
634 topt[0] = (REAL) frompt[0];
635 break;
636 default: {
637 for( int i = 0; i < ncoords; i++ )
638 *topt++ = (REAL) *frompt++;
639 }
640 }
641 }
642
643 /*-----------------------------------------------------------------------------
644 * pt_oo_copy - make internal copy of internal cntrl pt. of x coords
645 *-----------------------------------------------------------------------------
646 */
647
648 void
649 Knotspec::pt_oo_copy( REAL *topt, REAL *frompt )
650 {
651 switch( ncoords ) {
652 case 4:
653 topt[3] = frompt[3];
654 case 3:
655 topt[2] = frompt[2];
656 case 2:
657 topt[1] = frompt[1];
658 case 1:
659 topt[0] = frompt[0];
660 break;
661 default:
662 memcpy( topt, frompt, ncoords * sizeof( REAL ) );
663 }
664 }
665
666 /*-----------------------------------------------------------------------------
667 * pt_oo_sum - compute affine combination of internal cntrl pts
668 *-----------------------------------------------------------------------------
669 */
670
671 void
672 Knotspec::pt_oo_sum( REAL *x, REAL *y, REAL *z, Knot a, Knot b )
673 {
674 switch( ncoords ) {
675 case 4:
676 x[3] = a * y[3] + b * z[3];
677 case 3:
678 x[2] = a * y[2] + b * z[2];
679 case 2:
680 x[1] = a * y[1] + b * z[1];
681 case 1:
682 x[0] = a * y[0] + b * z[0];
683 break;
684 default: {
685 for( int i = 0; i < ncoords; i++ )
686 *x++ = a * *y++ + b * *z++;
687 }
688 }
689 }