Example #1
0
// 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;

}
Example #2
0
// 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;
}
Example #5
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;
}