// This function creates a cylinder similarly to the teapot // and the torus above. This time the cylinder is trimmed with // a circle defined by 9 square-based control points to show // an example of defining a circle without using infinite control // points (see [Piegl and Tiller], pp. 299, Ex7.2 (Figure 7.16)) as // well as to show how to define a rational trimming curve. NodePtr makeTrimmedCylinder() { SimpleMaterialPtr cylmat = SimpleMaterial::create(); beginEditCP(cylmat); { cylmat->setDiffuse( Color3f(0.0, 0.8, 0.7)); cylmat->setAmbient( Color3f(0.2, 0.2, 0.2)); cylmat->setEmission( Color3f(0.02, 0.02, 0.02) ); cylmat->setSpecular( Color3f(0.78, 0.78, 0.78) ); cylmat->setShininess( 128 ); cylmat->addChunk(g_fb_chunk); } endEditCP(cylmat); float knots4[4] = {0, 0, 1, 1}; float knots_circle[8] = {0, 0, 0, 0.5, 0.5, 1, 1, 1}; float knots_outertrim[7] = {0, 0, 1, 2, 3, 4, 4}; float knots_trimcircle[12] = {0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1, 1, 1 }; float cylcps[10][4] = { { 1.00, 0, -.50, 1}, { 1.00, 0, .50, 1}, { 0, 1.00, 0, 0}, { 0, 1.00, 0, 0}, {-1.00, 0, -.50, 1}, {-1.00, 0, .50, 1}, { 0, -1.00, 0, 0}, { 0, -1.00, 0, 0}, { 1.00, 0, -.50, 1}, { 1.00, 0, .50, 1}, }; float outertrim_cps[5][2] = { {0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, }; float trimcircle_cps[9][3] = { {0.541667, 0.5, 1}, {0.383016, 0.235702, 0.707107}, {0.5, 0.333333, 1}, {0.324091, 0.235702, 0.707107}, {0.458333, 0.5, 1}, {0.324091, 0.471405, 0.707107}, {0.5, 0.666667, 1}, {0.383016, 0.471405, 0.707107}, {0.541667, 0.5, 1}, }; NodePtr cylnode = makeSurface(10, cylcps, 2, 1, 8, knots_circle, 4, knots4, 0.001, cylmat); SurfacePtr s = SurfacePtr::dcast(cylnode->getCore()); // add outer trimming around the domain addTrimCurve(s, 5, outertrim_cps, 1, 7, knots_outertrim, true); // add inside circle trimming addTrimCurve(s, 9, trimcircle_cps, 2, 12, knots_trimcircle, true); return cylnode; }
// This function creates a torus from a single NURBS surface // using only 25 control points (of which 12 are unique). // Similarly to the teapot, this uses the half-circle // constructed from 3 control points (of which the middle point // is infinite) which is then mirrored to form a full circle. // (See the NURBS book [Piegl and Tiller], pp. 296, Ex7.1 (Figure 7.15) // for details on the half-circle.) NodePtr makeTorus() { SimpleMaterialPtr torusmat = SimpleMaterial::create(); beginEditCP(torusmat); { torusmat->setDiffuse( Color3f(1.0, 0.0, 0.2)); torusmat->setAmbient( Color3f(0.2, 0.2, 0.2)); torusmat->setEmission( Color3f(0.02, 0.02, 0.02) ); torusmat->setSpecular( Color3f(0.78, 0.78, 0.78) ); torusmat->setShininess( 128 ); torusmat->addChunk(g_fb_chunk); } endEditCP(torusmat); float knots_circle[8] = {0, 0, 0, 0.5, 0.5, 1, 1, 1}; float toruscps[25][4] = { { 1.00, 0, .75, 1}, // { .25, 0, 0, 0}, // { 1.00, 0, 1.25, 1}, // { -.25, 0, 0, 0}, // { 1.00, 0, .75, 1}, { 0, 1.00, 0, 0}, // { 0, .25, 0, 0}, // { 0, 1.00, 0, 0}, { 0, -.25, 0, 0}, // { 0, 1.00, 0, 0}, {-1.00, 0, .75, 1}, // { -.25, 0, 0, 0}, // {-1.00, 0, 1.25, 1}, // { .25, 0, 0, 0}, // {-1.00, 0, .75, 1}, { 0, -1.00, 0, 0}, // { 0, -.25, 0, 0}, { 0, -1.00, 0, 0}, { 0, .25, 0, 0}, { 0, -1.00, 0, 0}, { 1.00, 0, .75, 1}, { .25, 0, 0, 0}, { 1.00, 0, 1.25, 1}, { -.25, 0, 0, 0}, { 1.00, 0, .75, 1}, }; NodePtr torus = makeSurface(25, toruscps, 2, 2, 8, knots_circle, 8, knots_circle, 0.005, torusmat); return torus; }
int main (int argc, char **argv) { osgInit(argc, argv); FieldContainerPtr pProto = Geometry::getClassType().getPrototype(); GeometryPtr pGeoProto = GeometryPtr::dcast(pProto); if(pGeoProto != NullFC) { pGeoProto->setDlistCache(false); } // init GLUT glutInit(&argc, argv); glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutCreateWindow("OpenSG"); glutKeyboardFunc(key); // glutReshapeFunc(resize); glutDisplayFunc(display); // glutMouseFunc(mouse); // glutMotionFunc(motion); glutIdleFunc(display); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 60, 1, 0.1, 10 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluLookAt( 3, 3, 3, 0, 0, 0, 0, 0, 1 ); glDepthFunc( GL_LEQUAL ); glEnable( GL_DEPTH_TEST ); glEnable( GL_LIGHTING ); glLineWidth( 3 ); #if 0 // for testing only: register Node type functions IntersectAction::registerEnterDefault(Group::getStaticType(), osgFunctionFunctor2(groupEnter)); IntersectAction::registerEnterDefault(Geometry::getStaticType(), osgFunctionFunctor2(geometryEnter)); IntersectAction::registerEnterDefault(Transform::getStaticType(), osgFunctionFunctor2(transformEnter)); IntersectAction::registerLeaveDefault(Transform::getStaticType(), osgFunctionFunctor2(transformLeave)); #endif // create test scene SimpleMaterialPtr white = SimpleMaterial::create(); SimpleMaterialPtr red = SimpleMaterial::create(); white->setEmission( Color3f( 1,1,1 ) ); red->setEmission( Color3f( 1,0,0 ) ); // g1->(g2->g3->p1,t1->p2) GeometryPtr g; NodePtr p1 = makePlane( 2,2,2,2 ); g = GeometryPtr::dcast(p1->getCore()); g->setMaterial( white ); p1->updateVolume(); NodePtr p2 = makePlane( 2,2,2,2 ); g = GeometryPtr::dcast(p2->getCore()); g->setMaterial( white ); p2->updateVolume(); NodePtr g4 = Node::create(); TransformPtr t1 = Transform::create(); beginEditCP(t1); t1->editMatrix().setRotate( Quaternion( Vec3f(1,0,0), 30 ) ); endEditCP(t1); beginEditCP(g4); g4->setCore( t1 ); g4->addChild( p2 ); g4->updateVolume(); endEditCP(g4); NodePtr g3 = Node::create(); GroupPtr g3c = Group::create(); beginEditCP(g3); g3->setCore( g3c ); g3->addChild( p1 ); g3->updateVolume(); endEditCP(g3); NodePtr g2 = Node::create(); GroupPtr g2c = Group::create(); beginEditCP(g2); g2->setCore( g2c ); g2->addChild( g3 ); g2->updateVolume(); endEditCP(g2); iroot = Node::create(); GroupPtr g1c = Group::create(); beginEditCP(iroot); iroot->setCore( g1c ); iroot->addChild( g2 ); iroot->addChild( g4 ); iroot->updateVolume(); endEditCP(iroot); // make the root and test objects points = GeoPositions3f::create(); beginEditCP(points); points->addValue( Pnt3f(0,0,0) ); points->addValue( Pnt3f(0,0,0) ); points->addValue( Pnt3f(0,0,0) ); points->addValue( Pnt3f(0,0,0) ); points->addValue( Pnt3f(0,0,0) ); endEditCP(points); GeoIndicesUI32Ptr index = GeoIndicesUI32::create(); beginEditCP(index); index->addValue( 0 ); index->addValue( 1 ); index->addValue( 2 ); index->addValue( 3 ); index->addValue( 4 ); endEditCP(index); GeoPLengthsPtr lens = GeoPLengthsUI32::create(); beginEditCP(lens); lens->addValue( 2 ); lens->addValue( 3 ); endEditCP(lens); GeoPTypesPtr type = GeoPTypesUI8::create(); beginEditCP(type); type->addValue( GL_LINES ); type->addValue( GL_TRIANGLES ); endEditCP(type); GeometryPtr testgeocore = Geometry::create(); beginEditCP(testgeocore); testgeocore->setPositions( points ); testgeocore->setIndices( index ); testgeocore->setLengths( lens ); testgeocore->setTypes( type ); testgeocore->setMaterial( red ); endEditCP( testgeocore ); NodePtr testgeo = Node::create(); beginEditCP(testgeo); testgeo->setCore( testgeocore ); endEditCP( testgeo ); root = Node::create(); GroupPtr rootc = Group::create(); beginEditCP(root); root->setCore( rootc ); root->addChild( iroot ); root->addChild( testgeo ); endEditCP( root ); dact = DrawAction::create(); dact->setFrustumCulling(false); glutMainLoop(); return 0; }
int main (int argc, char **argv) { // GLUT init osgInit(argc, argv); osgLog().setLogLevel ( OSG::LOG_DEBUG ); FieldContainerPtr pProto = Geometry::getClassType().getPrototype(); GeometryPtr pGeoProto = GeometryPtr::dcast(pProto); if(pGeoProto != NullFC) { pGeoProto->setDlistCache(true); } glutInit(&argc, argv); glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); UInt32 id = glutCreateWindow("OpenSG"); glutKeyboardFunc(key); glutReshapeFunc(resize); glutDisplayFunc(display); // glutMouseFunc(mouse); // glutMotionFunc(motion); glutIdleFunc(display); // create a material (need that to test textures) ChunkMaterialPtr mat; beginEditCP(mat); mat = ChunkMaterial::create(); MaterialChunkPtr mc = MaterialChunk::create(); beginEditCP(mc); mc->setDiffuse( Color4f( 1,.8,.8,1 ) ); mc->setAmbient( Color4f( 0.1,0.1,0.1,1 ) ); mc->setSpecular( Color4f( 1,1,1,1 ) ); mc->setShininess( 20 ); mc->setBackMaterial(true); mc->setBackColorMaterial(GL_DIFFUSE); mc->setBackDiffuse( Color4f( 1,0,0,1 ) ); mc->setBackAmbient( Color4f( 0.1,0.1,0.1,1 ) ); mc->setBackSpecular( Color4f( 0,1,0,1 ) ); mc->setBackShininess( 10 ); mc->setLit(true); endEditCP(mc); mat->addChunk(mc); // Texture chunk UChar8 imgdata[] = { 255,0,0,128, 0,255,0,128, 0,0,255,255, 255,255,255,255 }; ImagePtr pImage = Image::create(); pImage->set( Image::OSG_RGBA_PF, 2, 2, 1, 1, 1, 0, imgdata ); if ( argc > 1 ) pImage->read( argv[1] ); TextureChunkPtr xchunk; xchunk = TextureChunk::create(); xchunk->setImage( pImage ); xchunk->setMinFilter( GL_NEAREST ); xchunk->setMagFilter( GL_NEAREST ); xchunk->setWrapS( GL_REPEAT ); xchunk->setWrapT( GL_REPEAT ); xchunk->setEnvMode( GL_MODULATE ); mat->addChunk( xchunk ); endEditCP(mat); objects[0] = makePolygon(ccwSquare, sizeof(ccwSquare)/sizeof(double[3])); objects[1] = makePolygon(ccwSquare, sizeof(ccwSquare)/sizeof(double[3])); objects[2] = makePolygon(star, sizeof(star)/sizeof(double[3])); objects[3] = makePolygon(star, sizeof(star)/sizeof(double[3])); objects[4] = makePolygon(cwSquare, sizeof(cwSquare)/sizeof(double[3])); objects[5] = makePolygon(cwSquare, sizeof(cwSquare)/sizeof(double[3])); objects[6] = makePolygon(doubleEight, sizeof(doubleEight)/sizeof(double[3])); objects[7] = makePolygon(doubleEight, sizeof(doubleEight)/sizeof(double[3])); //tesselate every second object for(int i = 1; i < nobjects; i+=2) { GeometryPtr::dcast(objects[i]->getCore())->setMaterial( mat ); std::cerr << "Polygon Node: " << std::hex << objects[i] << std::endl; // try to create convex primitives OSG::GeometryPtr pGeo = GeometryPtr::dcast(objects[i]->getCore()); std::cerr << "Tesselating polygon : " << i << std::endl; createConvexPrimitives(pGeo); } // normal material SimpleMaterialPtr nmat; nmat = SimpleMaterial::create(); beginEditCP(nmat); nmat->setEmission( Color3f( 0,1,0 ) ); endEditCP(nmat); for ( UInt16 i = 0; i < nobjects; i++ ) { normalobjects[i] = calcVertexNormalsGeo( GeometryPtr::dcast(objects[i]->getCore()), .5); GeometryPtr::dcast(normalobjects[i]->getCore())->setMaterial(nmat); } // // The action win = GLUTWindow::create(); win->setId(id); win->init(); glEnable( GL_LIGHT0 ); float p[4]={0,0,1,0}; glLightfv(GL_LIGHT0, GL_POSITION, p); float c[4]={1,1,1,1}; glLightfv(GL_LIGHT0, GL_DIFFUSE, c); glLightfv(GL_LIGHT0, GL_SPECULAR, c); glPointSize( 3 ); glEnable( GL_DEPTH_TEST ); glEnable( GL_LIGHTING ); glClearColor( .3, .3, .8, 1 ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 60, 1, 0.1, 10 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluLookAt( 3, 3, 3, 0, 0, 0, 0, 0, 1 ); dact = DrawAction::create(); dact->setWindow(get_pointer(win)); dact->setFrustumCulling( false ); glutMainLoop(); return 0; }
// This function creates the classic Utah teapot from 4 NURBS // surfaces: one surface each for the lid, body, handle and spout. // The "classic" representation is using 18 rational Bezier patches, // but in order to show the construction of more complex surfaces // these have been combined into as few NURBS surfaces as possible. NodePtr makeTeapot() { SimpleMaterialPtr teapotmat = SimpleMaterial::create(); beginEditCP(teapotmat); { teapotmat->setDiffuse( Color3f(0.8, 0.8, 0.8)); teapotmat->setAmbient( Color3f(0.2, 0.2, 0.2)); teapotmat->setEmission( Color3f(0.02, 0.02, 0.02) ); teapotmat->setSpecular( Color3f(0.78, 0.78, 0.78) ); teapotmat->setShininess( 128 ); teapotmat->addChunk(g_fb_chunk); } endEditCP(teapotmat); NodePtr teapotroot = makeCoredNode<Group>(); float knots11[11] = {0, 0, 0, 0, 0.5, 0.5, 0.5, 1, 1, 1, 1}; float knots14[14] = {0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3}; float knots_circle[8] = {0, 0, 0, 0.5, 0.5, 1, 1, 1}; float lidcps[35][4] = { { 0.0000, 4.0000, 0.0000, 1.0000}, { 0.0000, 4.0000, 0.8000, 1.0000}, { 0.0000, 3.6000, 0.0000, 1.0000}, { 0.0000, 3.4000, 0.2000, 1.0000}, { 0.0000, 3.2000, 0.4000, 1.0000}, { 0.0000, 3.2000, 1.3000, 1.0000}, { 0.0000, 3.0000, 1.3000, 1.0000}, {-0.0000, 0.0000, 0.0000, 0.0000}, {-0.8000, 0.0000, 0.0000, 0.0000}, {-0.0000, 0.0000, 0.0000, 0.0000}, {-0.2000, 0.0000, 0.0000, 0.0000}, {-0.4000, 0.0000, 0.0000, 0.0000}, {-1.3000, 0.0000, 0.0000, 0.0000}, {-1.3000, 0.0000, 0.0000, 0.0000}, { 0.0000, 4.0000,-0.0000, 1.0000}, { 0.0000, 4.0000,-0.8000, 1.0000}, { 0.0000, 3.6000,-0.0000, 1.0000}, { 0.0000, 3.4000,-0.2000, 1.0000}, { 0.0000, 3.2000,-0.4000, 1.0000}, { 0.0000, 3.2000,-1.3000, 1.0000}, { 0.0000, 3.0000,-1.3000, 1.0000}, { 0.0000, 0.0000, 0.0000, 0.0000}, { 0.8000, 0.0000, 0.0000, 0.0000}, { 0.0000, 0.0000, 0.0000, 0.0000}, { 0.2000, 0.0000, 0.0000, 0.0000}, { 0.4000, 0.0000, 0.0000, 0.0000}, { 1.3000, 0.0000, 0.0000, 0.0000}, { 1.3000, 0.0000, 0.0000, 0.0000}, { 0.0000, 4.0000, 0.0000, 1.0000}, { 0.0000, 4.0000, 0.8000, 1.0000}, { 0.0000, 3.6000, 0.0000, 1.0000}, { 0.0000, 3.4000, 0.2000, 1.0000}, { 0.0000, 3.2000, 0.4000, 1.0000}, { 0.0000, 3.2000, 1.3000, 1.0000}, { 0.0000, 3.0000, 1.3000, 1.0000}, }; NodePtr lid = makeSurface(35, lidcps, 2, 3, 8, knots_circle, 11, knots11, 0.005, teapotmat); float bodycps[50][4] = { { 0.0000, 3.0000, 1.4000, 1.0000}, { 0.0000, 3.1750, 1.3375, 1.0000}, { 0.0000, 3.1750, 1.4375, 1.0000}, { 0.0000, 3.0000, 1.5000, 1.0000}, { 0.0000, 2.3000, 1.7500, 1.0000}, { 0.0000, 1.6000, 2.0000, 1.0000}, { 0.0000, 1.0000, 2.0000, 1.0000}, { 0.0000, 0.4000, 2.0000, 1.0000}, { 0.0000, 0.2000, 1.5000, 1.0000}, { 0.0000, 0.0000, 1.5000, 1.0000}, {-1.4000, 0.0000, 0.0000, 0.0000}, {-1.3375, 0.0000, 0.0000, 0.0000}, {-1.4375, 0.0000, 0.0000, 0.0000}, {-1.5000, 0.0000, 0.0000, 0.0000}, {-1.7500, 0.0000, 0.0000, 0.0000}, {-2.0000, 0.0000, 0.0000, 0.0000}, {-2.0000, 0.0000, 0.0000, 0.0000}, {-2.0000, 0.0000, 0.0000, 0.0000}, {-1.5000, 0.0000, 0.0000, 0.0000}, {-1.5000, 0.0000, 0.0000, 0.0000}, { 0.0000, 3.0000,-1.4000, 1.0000}, { 0.0000, 3.1750,-1.3375, 1.0000}, { 0.0000, 3.1750,-1.4375, 1.0000}, { 0.0000, 3.0000,-1.5000, 1.0000}, { 0.0000, 2.3000,-1.7500, 1.0000}, { 0.0000, 1.6000,-2.0000, 1.0000}, { 0.0000, 1.0000,-2.0000, 1.0000}, { 0.0000, 0.4000,-2.0500, 1.0000}, { 0.0000, 0.2000,-1.5000, 1.0000}, { 0.0000, 0.0000,-1.5000, 1.0000}, { 1.4000, 0.0000, 0.0000, 0.0000}, { 1.3375, 0.0000, 0.0000, 0.0000}, { 1.4375, 0.0000, 0.0000, 0.0000}, { 1.5000, 0.0000, 0.0000, 0.0000}, { 1.7500, 0.0000, 0.0000, 0.0000}, { 2.0000, 0.0000, 0.0000, 0.0000}, { 2.0000, 0.0000, 0.0000, 0.0000}, { 2.0000, 0.0000, 0.0000, 0.0000}, { 1.5000, 0.0000, 0.0000, 0.0000}, { 1.5000, 0.0000, 0.0000, 0.0000}, { 0.0000, 3.0000, 1.4000, 1.0000}, { 0.0000, 3.1750, 1.3375, 1.0000}, { 0.0000, 3.1750, 1.4375, 1.0000}, { 0.0000, 3.0000, 1.5000, 1.0000}, { 0.0000, 2.3000, 1.7500, 1.0000}, { 0.0000, 1.6000, 2.0000, 1.0000}, { 0.0000, 1.0000, 2.0000, 1.0000}, { 0.0000, 0.4000, 2.0000, 1.0000}, { 0.0000, 0.2000, 1.5000, 1.0000}, { 0.0000, 0.0000, 1.5000, 1.0000}, }; NodePtr body = makeSurface(50, bodycps, 2, 3, 8, knots_circle, 14, knots14, 0.005, teapotmat); float handlecps[35][4] = { { 1.5000, 2.8000, 0.0000, 1.0000}, { 2.5000, 2.8000, 0.0000, 1.0000}, { 3.0000, 2.8000, 0.0000, 1.0000}, { 3.0000, 2.2000, 0.0000, 1.0000}, { 3.0000, 1.6000, 0.0000, 1.0000}, { 2.6500, 1.0500, 0.0000, 1.0000}, { 1.9000, 0.6000, 0.0000, 1.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 0.0000, 0.0000, 0.3000, 0.0000}, { 1.6000, 2.5000, 0.0000, 1.0000}, { 2.3000, 2.5000, 0.0000, 1.0000}, { 2.7000, 2.5000, 0.0000, 1.0000}, { 2.7000, 2.2000, 0.0000, 1.0000}, { 2.7000, 1.9000, 0.0000, 1.0000}, { 2.5000, 1.5000, 0.0000, 1.0000}, { 2.0000, 1.0000, 0.0000, 1.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 0.0000, 0.0000,-0.3000, 0.0000}, { 1.5000, 2.8000, 0.0000, 1.0000}, { 2.5000, 2.8000, 0.0000, 1.0000}, { 3.0000, 2.8000, 0.0000, 1.0000}, { 3.0000, 2.2000, 0.0000, 1.0000}, { 3.0000, 1.6000, 0.0000, 1.0000}, { 2.6500, 1.0500, 0.0000, 1.0000}, { 1.9000, 0.6000, 0.0000, 1.0000}, }; NodePtr handle = makeSurface(35, handlecps, 2, 3, 8, knots_circle, 11, knots11, 0.005, teapotmat); float spoutcps[35][4] = { {-1.7000, 0.6000, 0.0000, 1.0000}, {-3.1000, 0.9000, 0.0000, 1.0000}, {-2.4000, 2.6000, 0.0000, 1.0000}, {-3.3000, 3.0000, 0.0000, 1.0000}, {-3.5250, 3.1250, 0.0000, 1.0000}, {-3.4500, 3.1500, 0.0000, 1.0000}, {-3.2000, 3.0000, 0.0000, 1.0000}, { 0.0000, 0.0000, 0.6600, 0.0000}, { 0.0000, 0.0000, 0.6600, 0.0000}, { 0.0000, 0.0000, 0.2500, 0.0000}, { 0.0000, 0.0000, 0.2500, 0.0000}, { 0.0000, 0.0000, 0.2500, 0.0000}, { 0.0000, 0.0000, 0.1500, 0.0000}, { 0.0000, 0.0000, 0.1500, 0.0000}, {-1.7000, 1.7000, 0.0000, 1.0000}, {-2.6000, 1.7000, 0.0000, 1.0000}, {-2.3000, 2.6000, 0.0000, 1.0000}, {-2.7000, 3.0000, 0.0000, 1.0000}, {-2.8000, 3.1000, 0.0000, 1.0000}, {-2.9000, 3.1000, 0.0000, 1.0000}, {-2.8000, 3.0000, 0.0000, 1.0000}, { 0.0000, 0.0000,-0.6600, 0.0000}, { 0.0000, 0.0000,-0.6600, 0.0000}, { 0.0000, 0.0000,-0.2500, 0.0000}, { 0.0000, 0.0000,-0.2500, 0.0000}, { 0.0000, 0.0000,-0.2500, 0.0000}, { 0.0000, 0.0000,-0.1500, 0.0000}, { 0.0000, 0.0000,-0.1500, 0.0000}, {-1.7000, 0.6000, 0.0000, 1.0000}, {-3.1000, 0.9000, 0.0000, 1.0000}, {-2.4000, 2.6000, 0.0000, 1.0000}, {-3.3000, 3.0000, 0.0000, 1.0000}, {-3.5250, 3.1250, 0.0000, 1.0000}, {-3.4500, 3.1500, 0.0000, 1.0000}, {-3.2000, 3.0000, 0.0000, 1.0000}, }; NodePtr spout = makeSurface(35, spoutcps, 2, 3, 8, knots_circle, 11, knots11, 0.005, teapotmat); beginEditCP(teapotroot); teapotroot->addChild(lid); teapotroot->addChild(body); teapotroot->addChild(handle); teapotroot->addChild(spout); endEditCP(teapotroot); return teapotroot; }