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:
10 ** http://oss.sgi.com/projects/FreeB
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.
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.
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.
40 #include "glimports.h"
43 #include "subdivider.h"
45 #include "bezierarc.h"
47 #include "renderhints.h"
51 #include "patchlist.h"
53 #include "nurbsconsts.h"
54 #include "trimvertpool.h"
55 #include "simplemath.h"
57 #include "polyUtil.h" //for function area()
59 //#define PARTITION_TEST
61 #include "partitionY.h"
62 #include "monoTriangulation.h"
63 #include "dataTransform.h"
64 #include "monoChain.h"
69 #define OPTIMIZE_UNTRIMED_CASE
73 Subdivider::makePatchBoundary( const REAL
*from
, const REAL
*to
)
83 Arc_ptr jarc
= new(arcpool
) Arc( arc_bottom
, 0 );
84 arctessellator
.bezier( jarc
, smin
, smax
, tmin
, tmin
);
86 pjarc
= jarc
->append( pjarc
);
88 jarc
= new(arcpool
) Arc( arc_right
, 0 );
89 arctessellator
.bezier( jarc
, smax
, smax
, tmin
, tmax
);
91 pjarc
= jarc
->append( pjarc
);
93 jarc
= new(arcpool
) Arc( arc_top
, 0 );
94 arctessellator
.bezier( jarc
, smax
, smin
, tmax
, tmax
);
96 pjarc
= jarc
->append( pjarc
);
98 jarc
= new(arcpool
) Arc( arc_left
, 0 );
99 arctessellator
.bezier( jarc
, smin
, smin
, tmax
, tmin
);
101 jarc
->append( pjarc
);
103 assert( jarc
->check() != 0 );
107 /*---------------------------------------------------------------------------
108 * Subdivider - construct a subdivider
109 *---------------------------------------------------------------------------
112 Subdivider::Subdivider( Renderhints
& r
, Backend
& b
)
114 arctessellator( trimvertexpool
, pwlarcpool
),
115 arcpool( sizeof( Arc
), 1, "arcpool" ),
116 bezierarcpool( sizeof( BezierArc
), 1, "Bezarcpool" ),
117 pwlarcpool( sizeof( PwlArc
), 1, "Pwlarcpool" ),
124 Subdivider::setJumpbuffer( JumpBuffer
*j
)
129 /*---------------------------------------------------------------------------
130 * clear - reset all state after possible error condition
131 *---------------------------------------------------------------------------
135 Subdivider::clear( void )
137 trimvertexpool
.clear();
140 bezierarcpool
.clear();
143 /*---------------------------------------------------------------------------
144 * ~Subdivider - destroy a subdivider
145 *---------------------------------------------------------------------------
148 Subdivider::~Subdivider( void )
152 /*---------------------------------------------------------------------------
153 * addArc - add a bezier arc to a trim loop and to a bin
154 *---------------------------------------------------------------------------
157 Subdivider::addArc( REAL
*cpts
, Quilt
*quilt
, long _nuid
)
159 BezierArc
*bezierArc
= new(bezierarcpool
) BezierArc
;
160 Arc
*jarc
= new(arcpool
) Arc( arc_none
, _nuid
);
162 jarc
->bezierArc
= bezierArc
;
163 bezierArc
->order
= quilt
->qspec
->order
;
164 bezierArc
->stride
= quilt
->qspec
->stride
;
165 bezierArc
->mapdesc
= quilt
->mapdesc
;
166 bezierArc
->cpts
= cpts
;
167 initialbin
.addarc( jarc
);
168 pjarc
= jarc
->append( pjarc
);
171 /*---------------------------------------------------------------------------
172 * addArc - add a pwl arc to a trim loop and to a bin
173 *---------------------------------------------------------------------------
177 Subdivider::addArc( int npts
, TrimVertex
*pts
, long _nuid
)
179 Arc
*jarc
= new(arcpool
) Arc( arc_none
, _nuid
);
180 jarc
->pwlArc
= new(pwlarcpool
) PwlArc( npts
, pts
);
181 initialbin
.addarc( jarc
);
182 pjarc
= jarc
->append( pjarc
);
186 Subdivider::beginQuilts( void )
192 Subdivider::addQuilt( Quilt
*quilt
)
198 /*---------------------------------------------------------------------------
199 * drawSurfaces - main entry point for surface tessellation
200 *---------------------------------------------------------------------------
204 Subdivider::drawSurfaces( long nuid
)
210 //initialbin could be nonempty due to some errors
211 freejarcs(initialbin
);
215 for( Quilt
*q
= qlist
; q
; q
= q
->next
) {
216 if( q
->isCulled( ) == CULL_TRIVIAL_REJECT
) {
217 freejarcs( initialbin
);
224 qlist
->getRange( from
, to
, spbrkpts
, tpbrkpts
);
225 #ifdef OPTIMIZE_UNTRIMED_CASE
226 //perform optimization only when the samplng method is
227 //DOMAIN_DISTANCE and the display methdo is either
228 //fill or outline_polygon.
229 int optimize
= (is_domain_distance_sampling
&& (renderhints
.display_method
!= N_OUTLINE_PATCH
));
232 if( ! initialbin
.isnonempty() ) {
233 #ifdef OPTIMIZE_UNTRIMED_CASE
237 makeBorderTrim( from
, to
);
240 makeBorderTrim( from
, to
);
244 qlist
->findRates( spbrkpts
, tpbrkpts
, rate
);
246 if( decompose( initialbin
, min(rate
[0], rate
[1]) ) )
247 mylongjmp( jumpbuffer
, 31 );
250 backend
.bgnsurf( renderhints
.wiretris
, renderhints
.wirequads
, nuid
);
252 #ifdef PARTITION_TEST
253 if( initialbin
.isnonempty() && spbrkpts
.end
-2 == spbrkpts
.start
&&
254 tpbrkpts
.end
-2 == tpbrkpts
.start
)
256 for(int i
=spbrkpts
.start
; i
<spbrkpts
.end
-1; i
++){
257 for(int j
=tpbrkpts
.start
; j
<tpbrkpts
.end
-1; j
++){
259 pta
[0] = spbrkpts
.pts
[i
];
260 ptb
[0] = spbrkpts
.pts
[i
+1];
261 pta
[1] = tpbrkpts
.pts
[j
];
262 ptb
[1] = tpbrkpts
.pts
[j
+1];
263 qlist
->downloadAll(pta
, ptb
, backend
);
269 poly
= bin_to_DLineLoops(initialbin
);
271 poly
=poly
->deleteDegenerateLinesAllPolygons();
273 sampledLine
* retSampledLines
;
274 //printf("before MC_partition\n");
275 poly
= MC_partitionY(poly
, &retSampledLines
);
276 //printf("after MC_partition\n");
282 primStream
pStream(5000,5000);
285 for(temp
=poly
; temp
!= NULL
; temp
=temp
->getNextPolygon())
287 monoTriangulation(temp
, &pStream
);
289 slicer
.evalStream(&pStream
);
292 //need to clean up space
295 freejarcs( initialbin
);
300 printf("num_polygons=%i\n", poly->numPolygons());
301 printf("num_edges=%i\n", poly->numEdgesAllPolygons());
302 poly->writeAllPolygons("zloutputFile");
305 primStream pStream(20,20);
306 for(directedLine* tempD = poly; tempD != NULL; tempD = tempD->getNextPolygon())
307 monoTriangulation(tempD, &pStream);
312 #endif //PARTITION_TEST
315 #ifdef OPTIMIZE_UNTRIMED_CASE
316 if( (!initialbin
.isnonempty()) && optimize
)
321 for(i
=spbrkpts
.start
; i
<spbrkpts
.end
-1; i
++){
322 for(j
=tpbrkpts
.start
; j
<tpbrkpts
.end
-1; j
++){
324 pta
[0] = spbrkpts
.pts
[i
];
325 ptb
[0] = spbrkpts
.pts
[i
+1];
326 pta
[1] = tpbrkpts
.pts
[j
];
327 ptb
[1] = tpbrkpts
.pts
[j
+1];
328 qlist
->downloadAll(pta
, ptb
, backend
);
330 num_u_steps
= (int) (domain_distance_u_rate
* (ptb
[0]-pta
[0]));
331 num_v_steps
= (int) (domain_distance_v_rate
* (ptb
[1]-pta
[1]));
333 if(num_u_steps
<= 0) num_u_steps
= 1;
334 if(num_v_steps
<= 0) num_v_steps
= 1;
336 backend
.surfgrid(pta
[0], ptb
[0], num_u_steps
,
337 ptb
[1], pta
[1], num_v_steps
);
338 backend
.surfmesh(0,0,num_u_steps
,num_v_steps
);
343 /* the following is left for reference purpose, don't delete
346 Patchlist patchlist(qlist, pta, ptb);
347 patchlist.getstepsize();
349 tempSource=makePatchBoundary(pta, ptb);
351 tessellation(*tempSource, patchlist);
361 subdivideInS( initialbin
);
364 subdivideInS( initialbin
);
372 Subdivider::subdivideInS( Bin
& source
)
374 if( renderhints
.display_method
== N_OUTLINE_PARAM
) {
380 splitInS( source
, spbrkpts
.start
, spbrkpts
.end
);
385 /*---------------------------------------------------------------------------
386 * splitInS - split a patch and a bin by an isoparametric line
387 *---------------------------------------------------------------------------
391 Subdivider::splitInS( Bin
& source
, int start
, int end
)
393 if( source
.isnonempty() ) {
395 int i
= start
+ (end
- start
) / 2;
397 split( source
, left
, right
, 0, spbrkpts
.pts
[i
] );
398 splitInS( left
, start
, i
);
399 splitInS( right
, i
+1, end
);
401 if( start
== spbrkpts
.start
|| start
== spbrkpts
.end
) {
403 } else if( renderhints
.display_method
== N_OUTLINE_PARAM_S
) {
410 splitInT( source
, tpbrkpts
.start
, tpbrkpts
.end
);
416 /*---------------------------------------------------------------------------
417 * splitInT - split a patch and a bin by an isoparametric line
418 *---------------------------------------------------------------------------
422 Subdivider::splitInT( Bin
& source
, int start
, int end
)
424 if( source
.isnonempty() ) {
426 int i
= start
+ (end
- start
) / 2;
428 split( source
, left
, right
, 1, tpbrkpts
.pts
[i
] );
429 splitInT( left
, start
, i
);
430 splitInT( right
, i
+1, end
);
432 if( start
== tpbrkpts
.start
|| start
== tpbrkpts
.end
) {
434 } else if( renderhints
.display_method
== N_OUTLINE_PARAM_ST
) {
443 pta
[0] = spbrkpts
.pts
[s_index
-1];
444 pta
[1] = tpbrkpts
.pts
[t_index
-1];
446 ptb
[0] = spbrkpts
.pts
[s_index
];
447 ptb
[1] = tpbrkpts
.pts
[t_index
];
448 qlist
->downloadAll( pta
, ptb
, backend
);
450 Patchlist
patchlist( qlist
, pta
, ptb
);
452 printf("-------samplingSplit-----\n");
453 source.show("samplingSplit source");
455 samplingSplit( source
, patchlist
, renderhints
.maxsubdivisions
, 0 );
463 /*--------------------------------------------------------------------------
464 * samplingSplit - recursively subdivide patch, cull check each subpatch
465 *--------------------------------------------------------------------------
469 Subdivider::samplingSplit(
471 Patchlist
& patchlist
,
475 if( ! source
.isnonempty() ) return;
477 if( patchlist
.cullCheck() == CULL_TRIVIAL_REJECT
) {
482 patchlist
.getstepsize();
484 if( renderhints
.display_method
== N_OUTLINE_PATCH
) {
485 tessellation( source
, patchlist
);
493 tessellation( source
, patchlist
);
495 if( patchlist
.needsSamplingSubdivision() && (subdivisions
> 0) ) {
496 if( ! patchlist
.needsSubdivision( 0 ) )
498 else if( ! patchlist
.needsSubdivision( 1 ) )
504 REAL mid
= ( patchlist
.pspec
[param
].range
[0] +
505 patchlist
.pspec
[param
].range
[1] ) * 0.5;
506 split( source
, left
, right
, param
, mid
);
507 Patchlist
subpatchlist( patchlist
, param
, mid
);
508 samplingSplit( left
, subpatchlist
, subdivisions
-1, param
);
509 samplingSplit( right
, patchlist
, subdivisions
-1, param
);
513 nonSamplingSplit( source
, patchlist
, subdivisions
, param
);
520 Subdivider::nonSamplingSplit(
522 Patchlist
& patchlist
,
526 if( patchlist
.needsNonSamplingSubdivision() && (subdivisions
> 0) ) {
530 REAL mid
= ( patchlist
.pspec
[param
].range
[0] +
531 patchlist
.pspec
[param
].range
[1] ) * 0.5;
532 split( source
, left
, right
, param
, mid
);
533 Patchlist
subpatchlist( patchlist
, param
, mid
);
534 if( left
.isnonempty() )
535 if( subpatchlist
.cullCheck() == CULL_TRIVIAL_REJECT
)
538 nonSamplingSplit( left
, subpatchlist
, subdivisions
-1, param
);
539 if( right
.isnonempty() )
540 if( patchlist
.cullCheck() == CULL_TRIVIAL_REJECT
)
543 nonSamplingSplit( right
, patchlist
, subdivisions
-1, param
);
548 backend
.patch( patchlist
.pspec
[0].range
[0], patchlist
.pspec
[0].range
[1],
549 patchlist
.pspec
[1].range
[0], patchlist
.pspec
[1].range
[1] );
551 if( renderhints
.display_method
== N_OUTLINE_SUBDIV
) {
557 findIrregularS( source
);
558 monosplitInS( source
, smbrkpts
.start
, smbrkpts
.end
);
563 /*--------------------------------------------------------------------------
564 * tessellation - set tessellation of interior and boundary of patch
565 *--------------------------------------------------------------------------
569 Subdivider::tessellation( Bin
& bin
, Patchlist
&patchlist
)
571 // tessellate unsampled trim curves
572 tessellate( bin
, patchlist
.pspec
[1].sidestep
[1], patchlist
.pspec
[0].sidestep
[1],
573 patchlist
.pspec
[1].sidestep
[0], patchlist
.pspec
[0].sidestep
[0] );
575 // set interior sampling rates
576 slicer
.setstriptessellation( patchlist
.pspec
[0].stepsize
, patchlist
.pspec
[1].stepsize
);
578 //added by zl: set the order which will be used in slicer.c++
579 slicer
.set_ulinear( (patchlist
.get_uorder() == 2));
580 slicer
.set_vlinear( (patchlist
.get_vorder() == 2));
582 // set boundary sampling rates
583 stepsizes
[0] = patchlist
.pspec
[1].stepsize
;
584 stepsizes
[1] = patchlist
.pspec
[0].stepsize
;
585 stepsizes
[2] = patchlist
.pspec
[1].stepsize
;
586 stepsizes
[3] = patchlist
.pspec
[0].stepsize
;
589 /*---------------------------------------------------------------------------
590 * monosplitInS - split a patch and a bin by an isoparametric line
591 *---------------------------------------------------------------------------
595 Subdivider::monosplitInS( Bin
& source
, int start
, int end
)
597 if( source
.isnonempty() ) {
599 int i
= start
+ (end
- start
) / 2;
601 split( source
, left
, right
, 0, smbrkpts
.pts
[i
] );
602 monosplitInS( left
, start
, i
);
603 monosplitInS( right
, i
+1, end
);
605 if( renderhints
.display_method
== N_OUTLINE_SUBDIV_S
) {
611 findIrregularT( source
);
612 monosplitInT( source
, tmbrkpts
.start
, tmbrkpts
.end
);
618 /*---------------------------------------------------------------------------
619 * monosplitInT - split a patch and a bin by an isoparametric line
620 *---------------------------------------------------------------------------
624 Subdivider::monosplitInT( Bin
& source
, int start
, int end
)
626 if( source
.isnonempty() ) {
628 int i
= start
+ (end
- start
) / 2;
630 split( source
, left
, right
, 1, tmbrkpts
.pts
[i
] );
631 monosplitInT( left
, start
, i
);
632 monosplitInT( right
, i
+1, end
);
634 if( renderhints
.display_method
== N_OUTLINE_SUBDIV_ST
) {
639 printf("*******render\n");
640 source.show("source\n");
650 /*----------------------------------------------------------------------------
651 * findIrregularS - determine points of non-monotonicity is s direction
652 *----------------------------------------------------------------------------
656 Subdivider::findIrregularS( Bin
& bin
)
658 assert( bin
.firstarc()->check() != 0 );
660 smbrkpts
.grow( bin
.numarcs() );
662 for( Arc_ptr jarc
=bin
.firstarc(); jarc
; jarc
=bin
.nextarc() ) {
663 REAL
*a
= jarc
->prev
->tail();
664 REAL
*b
= jarc
->tail();
665 REAL
*c
= jarc
->head();
667 if( b
[1] == a
[1] && b
[1] == c
[1] ) continue;
670 if((b
[1]<=a
[1] && b
[1] <= c
[1]) ||
671 (b
[1]>=a
[1] && b
[1] >= c
[1]))
673 //each arc (jarc, jarc->prev, jarc->next) is a
674 //monotone arc consisting of multiple line segements.
675 //it may happen that jarc->prev and jarc->next are the same,
676 //that is, jarc->prev and jarc form a closed loop.
677 //In such case, a and c will be the same.
678 if(a
[0]==c
[0] && a
[1] == c
[1])
680 if(jarc
->pwlArc
->npts
>2)
682 c
= jarc
->pwlArc
->pts
[jarc
->pwlArc
->npts
-2].param
;
686 assert(jarc
->prev
->pwlArc
->npts
>2);
687 a
= jarc
->prev
->pwlArc
->pts
[jarc
->prev
->pwlArc
->npts
-2].param
;
699 if( b[1] <= a[1] && b[1] <= c[1] ) {
700 if( ! ccwTurn_tr( jarc->prev, jarc ) )
701 smbrkpts.add( b[0] );
702 } else if( b[1] >= a[1] && b[1] >= c[1] ) {
703 if( ! ccwTurn_tl( jarc->prev, jarc ) )
704 smbrkpts.add( b[0] );
713 /*----------------------------------------------------------------------------
714 * findIrregularT - determine points of non-monotonicity in t direction
715 * where one arc is parallel to the s axis.
716 *----------------------------------------------------------------------------
720 Subdivider::findIrregularT( Bin
& bin
)
722 assert( bin
.firstarc()->check() != 0 );
724 tmbrkpts
.grow( bin
.numarcs() );
726 for( Arc_ptr jarc
=bin
.firstarc(); jarc
; jarc
=bin
.nextarc() ) {
727 REAL
*a
= jarc
->prev
->tail();
728 REAL
*b
= jarc
->tail();
729 REAL
*c
= jarc
->head();
731 if( b
[0] == a
[0] && b
[0] == c
[0] ) continue;
733 if( b
[0] <= a
[0] && b
[0] <= c
[0] ) {
734 if( a
[1] != b
[1] && b
[1] != c
[1] ) continue;
735 if( ! ccwTurn_sr( jarc
->prev
, jarc
) )
736 tmbrkpts
.add( b
[1] );
737 } else if ( b
[0] >= a
[0] && b
[0] >= c
[0] ) {
738 if( a
[1] != b
[1] && b
[1] != c
[1] ) continue;
739 if( ! ccwTurn_sl( jarc
->prev
, jarc
) )
740 tmbrkpts
.add( b
[1] );
746 /*-----------------------------------------------------------------------------
747 * makeBorderTrim - if no user input trimming data then create
748 * a trimming curve around the boundaries of the Quilt. The curve consists of
749 * four Jordan arcs, one for each side of the Quilt, connected, of course,
751 *-----------------------------------------------------------------------------
755 Subdivider::makeBorderTrim( const REAL
*from
, const REAL
*to
)
764 Arc_ptr jarc
= new(arcpool
) Arc( arc_bottom
, 0 );
765 arctessellator
.bezier( jarc
, smin
, smax
, tmin
, tmin
);
766 initialbin
.addarc( jarc
);
767 pjarc
= jarc
->append( pjarc
);
769 jarc
= new(arcpool
) Arc( arc_right
, 0 );
770 arctessellator
.bezier( jarc
, smax
, smax
, tmin
, tmax
);
771 initialbin
.addarc( jarc
);
772 pjarc
= jarc
->append( pjarc
);
774 jarc
= new(arcpool
) Arc( arc_top
, 0 );
775 arctessellator
.bezier( jarc
, smax
, smin
, tmax
, tmax
);
776 initialbin
.addarc( jarc
);
777 pjarc
= jarc
->append( pjarc
);
779 jarc
= new(arcpool
) Arc( arc_left
, 0 );
780 arctessellator
.bezier( jarc
, smin
, smin
, tmax
, tmin
);
781 initialbin
.addarc( jarc
);
782 jarc
->append( pjarc
);
784 assert( jarc
->check() != 0 );
787 /*----------------------------------------------------------------------------
788 * render - renders all monotone regions in a bin and frees the bin
789 *----------------------------------------------------------------------------
793 Subdivider::render( Bin
& bin
)
798 slicer
.setisolines( ( renderhints
.display_method
== N_ISOLINE_S
) ? 1 : 0 );
800 slicer
.setisolines( 0 );
803 for( Arc_ptr jarc
=bin
.firstarc(); jarc
; jarc
=bin
.nextarc() ) {
804 if( jarc
->ismarked() ) {
805 assert( jarc
->check( ) != 0 );
806 Arc_ptr jarchead
= jarc
;
810 } while (jarc
!= jarchead
);
811 slicer
.slice( jarc
);
816 /*---------------------------------------------------------------------------
817 * outline - render the trimmed patch by outlining the boundary
818 *---------------------------------------------------------------------------
822 Subdivider::outline( Bin
& bin
)
825 for( Arc_ptr jarc
=bin
.firstarc(); jarc
; jarc
=bin
.nextarc() ) {
826 if( jarc
->ismarked() ) {
827 assert( jarc
->check( ) != 0 );
828 Arc_ptr jarchead
= jarc
;
830 slicer
.outline( jarc
);
833 } while (jarc
!= jarchead
);
838 /*---------------------------------------------------------------------------
839 * freejarcs - free all arcs in a bin
840 *---------------------------------------------------------------------------
844 Subdivider::freejarcs( Bin
& bin
)
846 bin
.adopt(); /* XXX - should not be necessary */
849 while( (jarc
= bin
.removearc()) != NULL
) {
850 if( jarc
->pwlArc
) jarc
->pwlArc
->deleteMe( pwlarcpool
); jarc
->pwlArc
= 0;
851 if( jarc
->bezierArc
) jarc
->bezierArc
->deleteMe( bezierarcpool
); jarc
->bezierArc
= 0;
852 jarc
->deleteMe( arcpool
);
856 /*----------------------------------------------------------------------------
857 * tessellate - tessellate all Bezier arcs in a bin
858 * 1) only accepts linear Bezier arcs as input
859 * 2) the Bezier arcs are stored in the pwlArc structure
860 * 3) only vertical or horizontal lines work
862 * 1) represent Bezier arcs in BezierArc structure
863 * (this requires a multitude of changes to the code)
864 * 2) accept high degree Bezier arcs (hard)
865 * 3) map the curve onto the surface to determine tessellation
866 * 4) work for curves of arbitrary geometry
867 *----------------------------------------------------------------------------
872 Subdivider::tessellate( Bin
& bin
, REAL rrate
, REAL trate
, REAL lrate
, REAL brate
)
874 for( Arc_ptr jarc
=bin
.firstarc(); jarc
; jarc
=bin
.nextarc() ) {
875 if( jarc
->isbezier( ) ) {
876 assert( jarc
->pwlArc
->npts
== 2 );
877 TrimVertex
*pts
= jarc
->pwlArc
->pts
;
878 REAL s1
= pts
[0].param
[0];
879 REAL t1
= pts
[0].param
[1];
880 REAL s2
= pts
[1].param
[0];
881 REAL t2
= pts
[1].param
[1];
883 jarc
->pwlArc
->deleteMe( pwlarcpool
); jarc
->pwlArc
= 0;
885 switch( jarc
->getside() ) {
888 arctessellator
.pwl_left( jarc
, s1
, t1
, t2
, lrate
);
892 arctessellator
.pwl_right( jarc
, s1
, t1
, t2
, rrate
);
896 arctessellator
.pwl_top( jarc
, t1
, s1
, s2
, trate
);
900 arctessellator
.pwl_bottom( jarc
, t1
, s1
, s2
, brate
);
906 assert( ! jarc
->isbezier() );
907 assert( jarc
->check() != 0 );