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 * nurbsinterfac.c++
37 *
38 */
39
40#include "glimports.h"
41#include "mystdio.h"
42#include "nurbsconsts.h"
43#include "nurbstess.h"
44#include "bufpool.h"
45#include "quilt.h"
46#include "displaylist.h"
47#include "knotvector.h"
48#include "mapdesc.h"
49
50#define THREAD( work, arg, cleanup ) \
51	if( dl ) {\
52	    arg->save = 1;\
53	    dl->append( (PFVS)&NurbsTessellator::work, (void *) arg, (PFVS)&NurbsTessellator::cleanup );\
54 	} else {\
55	    arg->save = 0;\
56	    work( arg );\
57	}
58
59#define THREAD2( work ) \
60	if( dl ) {\
61	    dl->append( (PFVS)&NurbsTessellator::work, 0, 0 );\
62 	} else {\
63	    work( );\
64	}
65
66NurbsTessellator::NurbsTessellator( BasicCurveEvaluator &c, BasicSurfaceEvaluator& e)
67	: maplist( backend ),
68	  backend( c, e ),
69          subdivider( renderhints, backend ),
70	  o_pwlcurvePool( sizeof( O_pwlcurve ), 32, "o_pwlcurvePool" ),
71	  o_nurbscurvePool( sizeof( O_nurbscurve ), 32, "o_nurbscurvePool"),
72	  o_curvePool( sizeof( O_curve ), 32,  "o_curvePool" ),
73	  o_trimPool( sizeof( O_trim ), 32,  "o_trimPool" ),
74	  o_surfacePool( sizeof( O_surface ), 1, "o_surfacePool" ),
75	  o_nurbssurfacePool( sizeof( O_nurbssurface ), 4, "o_nurbssurfacePool" ),
76	  propertyPool( sizeof( Property ), 32, "propertyPool" ),
77          quiltPool( sizeof( Quilt  ), 32, "quiltPool" )
78{
79    dl		= 0;
80    inSurface	= 0;
81    inCurve	= 0;
82    inTrim	= 0;
83    playBack	= 0;
84    jumpbuffer  = newJumpbuffer();
85    subdivider.setJumpbuffer( jumpbuffer );
86}
87
88NurbsTessellator::~NurbsTessellator( void )
89{
90    if( inTrim ) {
91	do_nurbserror( 12 );
92	endtrim();
93    }
94
95    if( inSurface ) {
96        *nextNurbssurface = 0;
97        do_freeall();
98    }
99
100    if (jumpbuffer) {
101        deleteJumpbuffer(jumpbuffer);
102	jumpbuffer= 0;
103    }
104}
105
106/*-----------------------------------------------------------------------------
107 * bgnsurface - allocate and initialize an o_surface structure
108 *
109 * Client: GL user
110 *-----------------------------------------------------------------------------
111 */
112void
113NurbsTessellator::bgnsurface( long nuid )
114{
115    O_surface *o_surface = new(o_surfacePool) O_surface;
116    o_surface->nuid = nuid;
117    THREAD( do_bgnsurface, o_surface, do_freebgnsurface );
118}
119
120/*-----------------------------------------------------------------------------
121 * bgncurve - allocate an initialize an o_curve structure
122 *
123 * Client: GL user
124 *-----------------------------------------------------------------------------
125 */
126void
127NurbsTessellator::bgncurve( long nuid )
128{
129    O_curve *o_curve = new(o_curvePool) O_curve;
130    o_curve->nuid = nuid;
131    THREAD( do_bgncurve, o_curve, do_freebgncurve );
132}
133/*-----------------------------------------------------------------------------
134 * endcurve -
135 *
136 * Client:
137 *-----------------------------------------------------------------------------
138 */
139
140void
141NurbsTessellator::endcurve( void )
142{
143    THREAD2( do_endcurve );
144}
145
146/*-----------------------------------------------------------------------------
147 * endsurface - user level end of surface call
148 *
149 * Client: GL user
150 *-----------------------------------------------------------------------------
151 */
152void
153NurbsTessellator::endsurface( void )
154{
155    THREAD2( do_endsurface );
156}
157
158
159/*-----------------------------------------------------------------------------
160 * bgntrim - allocate and initialize a new trim loop structure (o_trim )
161 *
162 * Client: GL user
163 *-----------------------------------------------------------------------------
164 */
165void
166NurbsTessellator::bgntrim( void )
167{
168    O_trim *o_trim = new(o_trimPool) O_trim;
169    THREAD( do_bgntrim, o_trim, do_freebgntrim );
170}
171
172/*-----------------------------------------------------------------------------
173 * endtrim -
174 *
175 * Client: GL user
176 *-----------------------------------------------------------------------------
177 */
178void
179NurbsTessellator::endtrim( void )
180{
181    THREAD2( do_endtrim );
182}
183
184
185/*-----------------------------------------------------------------------------
186 * pwlcurve -
187 *
188 *      count        - number of points on curve
189 *      array        - array of points on curve
190 *      byte_stride  - distance between points in bytes
191 *      type         - valid data flag
192 *
193 * Client: Gl user
194 *-----------------------------------------------------------------------------
195 */
196void
197NurbsTessellator::pwlcurve( long count, INREAL array[], long byte_stride, long type )
198{
199    Mapdesc *mapdesc = maplist.locate( type );
200
201    if( mapdesc == 0 ) {
202	do_nurbserror( 35 );
203	isDataValid = 0;
204	return;
205    }
206
207    if ( (type != N_P2D) && (type != N_P2DR) ) {
208	do_nurbserror( 22 );
209	isDataValid = 0;
210	return;
211    }
212    if( count < 0 ) {
213	do_nurbserror( 33 );
214	isDataValid = 0;
215	return;
216    }
217    if( byte_stride < 0 ) {
218	do_nurbserror( 34 );
219	isDataValid = 0;
220	return;
221    }
222
223#ifdef NOTDEF
224    if( mapdesc->isRational() ) {
225	INREAL *p = array;
226	INREAL x = p[0]; INREAL y = p[1]; INREAL w = p[2];
227	p = (INREAL *) (((char *) p) + byte_stride);
228	for( long i = 1; i != count; i++ ) {
229	    if( p[0] == x && p[1] == y && p[2] == w ) break;
230	    x = p[0]; y = p[1]; w = p[2];
231	    p = (INREAL *) (((char *) p) + byte_stride);
232	}
233	if( i != count ) {
234	    do_nurbserror( 37 );
235	    _glu_dprintf( "point %d (%f,%f)\n", i, x, y );
236	    isDataValid = 0;
237	    return;
238	}
239    } else {
240	INREAL *p = array;
241	INREAL x = p[0]; INREAL y = p[1];
242	p = (INREAL *) (((char *) p) + byte_stride);
243	for( long i = 1; i != count; i++ ) {
244	    if( p[0] == x && p[1] == y ) break;
245	    x = p[0]; y = p[1];
246	    p = (INREAL *) (((char *) p) + byte_stride);
247	}
248	if( i != count ) {
249	    do_nurbserror( 37 );
250	    _glu_dprintf( "point %d (%f,%f)\n", i, x, y );
251	    isDataValid = 0;
252	    return;
253	}
254    }
255#endif
256
257    O_pwlcurve	*o_pwlcurve = new(o_pwlcurvePool) O_pwlcurve( type, count, array, byte_stride, extTrimVertexPool.get((int)count) );
258    THREAD( do_pwlcurve, o_pwlcurve, do_freepwlcurve );
259}
260
261
262/*-----------------------------------------------------------------------------
263 * nurbscurve -
264 *
265 * Client: GL user
266 *-----------------------------------------------------------------------------
267 */
268void
269NurbsTessellator::nurbscurve(
270    long nknots, 		/* number of p knots */
271    INREAL knot[], 		/* nondecreasing knot values in p */
272    long byte_stride,		/* distance in bytes between control points */
273    INREAL ctlarray[], 		/* pointer to first control point */
274    long order,			/* order of spline */
275    long type )			/* description of range space */
276{
277
278    Mapdesc *mapdesc = maplist.locate( type );
279
280    if( mapdesc == 0 ) {
281	do_nurbserror( 35 );
282	isDataValid = 0;
283	return;
284    }
285
286    if( ctlarray == 0 ) {
287	do_nurbserror( 36 );
288	isDataValid = 0;
289	return;
290    }
291
292    if( byte_stride < 0 ) {
293	do_nurbserror( 34 );
294	isDataValid = 0;
295	return;
296    }
297
298    Knotvector knots;
299
300    knots.init( nknots, byte_stride, order, knot );
301    if( do_check_knots( &knots, "curve" ) ) return;
302
303    O_nurbscurve *o_nurbscurve = new(o_nurbscurvePool) O_nurbscurve(type);
304    o_nurbscurve->bezier_curves = new(quiltPool) Quilt(mapdesc);
305    o_nurbscurve->bezier_curves->toBezier( knots,ctlarray, mapdesc->getNcoords() );
306
307    THREAD( do_nurbscurve, o_nurbscurve, do_freenurbscurve );
308}
309
310
311/*-----------------------------------------------------------------------------
312 * nurbssurface -
313 *
314 * Client: User routine
315 *-----------------------------------------------------------------------------
316 */
317void
318NurbsTessellator::nurbssurface(
319    long sknot_count,		/* number of s knots */
320    INREAL sknot[],		/* nondecreasing knot values in s */
321    long tknot_count, 		/* number of t knots */
322    INREAL tknot[],		/* nondecreasing knot values in t */
323    long s_byte_stride,		/* s step size in memory bytes */
324    long t_byte_stride,		/* t step size in memory bytes */
325    INREAL ctlarray[],		/* pointer to first control point */
326    long sorder,		/* order of the spline in s parameter */
327    long torder,		/* order of the spline in t parameter */
328    long type)			/* description of range space */
329{
330    Mapdesc *mapdesc = maplist.locate( type );
331
332    if( mapdesc == 0 ) {
333	do_nurbserror( 35 );
334	isDataValid = 0;
335	return;
336    }
337
338    if( s_byte_stride < 0 ) {
339	do_nurbserror( 34 );
340	isDataValid = 0;
341	return;
342    }
343
344    if( t_byte_stride < 0 ) {
345	do_nurbserror( 34 );
346	isDataValid = 0;
347	return;
348    }
349
350    Knotvector sknotvector, tknotvector;
351
352    sknotvector.init( sknot_count, s_byte_stride, sorder, sknot );
353    if( do_check_knots( &sknotvector, "surface" ) ) return;
354
355    tknotvector.init( tknot_count, t_byte_stride, torder, tknot );
356    if( do_check_knots( &tknotvector, "surface" ) ) return;
357
358    O_nurbssurface *o_nurbssurface = new(o_nurbssurfacePool) O_nurbssurface(type);
359    o_nurbssurface->bezier_patches = new(quiltPool) Quilt(mapdesc);
360
361    o_nurbssurface->bezier_patches->toBezier( sknotvector, tknotvector,
362	ctlarray, mapdesc->getNcoords() );
363    THREAD( do_nurbssurface, o_nurbssurface, do_freenurbssurface );
364}
365
366
367/*-----------------------------------------------------------------------------
368 * setnurbsproperty -
369 *
370 *-----------------------------------------------------------------------------
371 */
372void
373NurbsTessellator::setnurbsproperty( long tag, INREAL value )
374{
375    if( ! renderhints.isProperty( tag ) ) {
376	do_nurbserror( 26 );
377    } else {
378	Property *prop = new(propertyPool) Property( tag, value );
379	THREAD( do_setnurbsproperty, prop, do_freenurbsproperty );
380    }
381}
382
383/*-----------------------------------------------------------------------------
384 * setnurbsproperty -
385 *
386 *-----------------------------------------------------------------------------
387 */
388void
389NurbsTessellator::setnurbsproperty( long type, long tag, INREAL value )
390{
391    Mapdesc *mapdesc = maplist.locate( type );
392
393    if( mapdesc == 0 ) {
394	do_nurbserror( 35 );
395	return;
396    }
397
398    if( ! mapdesc->isProperty( tag ) ) {
399	do_nurbserror( 26 );
400	return;
401    }
402
403    Property *prop = new(propertyPool) Property( type, tag, value );
404    THREAD( do_setnurbsproperty2, prop, do_freenurbsproperty );
405}
406
407
408/*-----------------------------------------------------------------------------
409 * getnurbsproperty -
410 *
411 *-----------------------------------------------------------------------------
412 */
413
414void
415NurbsTessellator::getnurbsproperty( long tag, INREAL *value )
416{
417    if( renderhints.isProperty( tag ) ) {
418	*value = renderhints.getProperty( tag );
419    } else {
420	do_nurbserror( 26 );
421    }
422}
423
424/*-----------------------------------------------------------------------------
425 * getnurbsproperty -
426 *
427 *-----------------------------------------------------------------------------
428 */
429
430void
431NurbsTessellator::getnurbsproperty( long type, long tag, INREAL *value )
432{
433    Mapdesc *mapdesc = maplist.locate( type );
434
435    if( mapdesc == 0 )
436	do_nurbserror( 35 );
437
438    if( mapdesc->isProperty( tag  ) ) {
439	*value = mapdesc->getProperty( tag );
440    } else {
441	do_nurbserror( 26 );
442    }
443}
444
445/*--------------------------------------------------------------------------
446 * setnurbsproperty - accept a user supplied matrix as culling or sampling mat
447 *--------------------------------------------------------------------------
448 */
449
450void
451NurbsTessellator::setnurbsproperty( long type, long purpose, INREAL *mat )
452{
453    // XXX - cannot be put in display list
454    Mapdesc *mapdesc = maplist.locate( type );
455
456    if( mapdesc == 0 ) {
457	do_nurbserror( 35 );
458	isDataValid = 0;
459    } else if( purpose == N_BBOXSIZE ) {
460	mapdesc->setBboxsize( mat );
461    } else {
462#ifndef NDEBUG
463        _glu_dprintf( "ERRORRORRORR!!!\n");
464#endif
465    }
466}
467
468/*--------------------------------------------------------------------------
469 * setnurbsproperty - accept a user supplied matrix as culling or sampling mat
470 *--------------------------------------------------------------------------
471 */
472
473void
474NurbsTessellator::setnurbsproperty( long type, long purpose, INREAL *mat,
475    long rstride, long cstride )
476{
477    // XXX - cannot be put in display list
478    Mapdesc *mapdesc = maplist.locate( type );
479
480    if( mapdesc == 0 ) {
481	do_nurbserror( 35 );
482	isDataValid = 0;
483    } else if( purpose == N_CULLINGMATRIX ) {
484	mapdesc->setCmat( mat, rstride, cstride );
485    } else if( purpose == N_SAMPLINGMATRIX ) {
486	mapdesc->setSmat( mat, rstride, cstride );
487    } else if( purpose == N_BBOXMATRIX ) {
488	mapdesc->setBmat( mat, rstride, cstride );
489    } else {
490#ifndef NDEBUG
491        _glu_dprintf( "ERRORRORRORR!!!\n");
492#endif
493    }
494}
495
496void
497NurbsTessellator::redefineMaps( void )
498{
499    maplist.initialize();
500}
501
502void
503NurbsTessellator::defineMap( long type, long rational, long ncoords )
504{
505    maplist.define( type, (int) rational, (int) ncoords );
506}
507
508void
509NurbsTessellator::discardRecording( void *_dl )
510{
511    delete (DisplayList *) _dl;
512}
513
514void *
515NurbsTessellator::beginRecording( void )
516{
517    dl = new DisplayList( this );
518    return (void *) dl;
519}
520
521void
522NurbsTessellator::endRecording( void )
523{
524    dl->endList();
525    dl = 0;
526}
527
528void
529NurbsTessellator::playRecording( void *_dl )
530{
531    playBack = 1;
532    bgnrender();
533    ((DisplayList *)_dl)->play();
534    endrender();
535    playBack = 0;
536}
537
538