bool basic_builder::BuildScene( string file_name, Camera &camera, Scene &scene ) const
    {
    int line_num = 0;
    char input_line[512];
    Plugin    *dat = NULL;  // A container for arbitrary data.
    Object    *obj = NULL;  // The current object, which was the last object created.
    Shader    *shd = NULL;  // The current shader. 
    Aggregate *agg = NULL;  // Current aggregate object, to which all objects are now added.
    Envmap    *env = NULL;  // Current environment map.
    Material  *mat = NULL;  // Current material pointer.
    Material   material;    // Current material.

    scene.object    = NULL;
    scene.envmap    = NULL;
    scene.rasterize = NULL;

    // Attempt to open the input file.

    file_name += ".sdf";
    std::ifstream fin;
    fin.open( file_name.c_str() );
    if( fin.fail() )
        {
        cerr << "Error: Could not open file " << file_name << endl;
        return false;  // Report failure.
        }
    cout << "Reading " << file_name << "... ";
    cout.flush();

    // Set some defaults.

    material.diffuse      = White;
    material.emission     = Black;
    material.specular     = White;
    material.ambient      = Black;
    material.reflectivity = Black;
    material.translucency = Black;
    material.ref_index    = 0.0;
    material.Phong_exp    = 0.0;

    camera.x_res = default_image_width;
    camera.y_res = default_image_height;
    camera.x_win = Interval( -1.0, 1.0 );
    camera.y_win = Interval( -1.0, 1.0 );

    // Process lines until the end of file is reached.
    // Print a warning for all lines that are unrecognizable.

    while( fin.getline( input_line, 512 ) ) 
        {
        line_num++;
        if( Skip( input_line ) ) continue;

        // Ask each registered object if it recognizes the line.  If it does, it will
        // create a new instance of the object and return it as the function value.

        Plugin *plg = Instance_of_Plugin( input_line );

        if( plg != NULL )
            {
            switch( plg->PluginType() )
                {
                case data_plugin:
                    if( obj == NULL ) cerr << "Error: data ignored.  Line " << line_num << endl;
                    else obj->AddData( obj );
                    break;

                case shader_plugin:
                    shd = (Shader*)plg;
                    break;					
 
                case aggregate_plugin:
                    obj = (Object*)plg;
                    obj->shader   = shd;
                    obj->envmap   = env;
                    obj->material = Copy( mat, material );
                    obj->parent   = agg;
                    if( Emitter( material ) )
                        {
                        cerr << "Error: An aggregate object cannot be an emitter.  Line "
                             << line_num << ": "
                             << input_line << endl;
                        return false;
                        }
                    if( agg != NULL ) // If there is alrealy an agg obj, this one is a child.
                        {
                        // agg->AddChild( obj );
                        // Do not add aggregates as children until they are complete.
                        agg->material = Copy( mat, material );
                        }
                    else if( scene.object == NULL ) scene.object = obj;
	            agg = (Aggregate *)obj;
                    break;

                case primitive_plugin:
                    obj = (Object*)plg;
                    obj->shader   = shd;
                    obj->envmap   = env;
                    obj->material = Copy( mat, material );
                    obj->parent   = agg;
                    if( Emitter( material ) ) scene.lights.push_back( obj );
                    if( agg != NULL )
                        {
                        agg->AddChild( obj );
                        agg->material = Copy( mat, material );
                        }
                    else if( scene.object == NULL ) scene.object = obj;
                    break;

                case envmap_plugin:
                    env = (Envmap*)plg;
                    // If an environment map is set before any object is created, use it as
                    // the background.
                    if( obj == NULL ) scene.envmap = env;
                    break;

                case rasterizer_plugin:
                    if( scene.rasterize != NULL )
                        {
                         cerr << "Error: More than one rasterizer specified.  Line "
                             << line_num << ": "
                             << input_line << endl;
                        return false;
                        }
                    scene.rasterize = (Rasterizer *)plg;
                    break;
                } 
            continue;
            }

        // Now look for all the other stuff...  materials, camera, lights, etc.

        ParamReader get( input_line );
 
        if( get["eye"]          && get[camera.eye]            ) continue;
        if( get["lookat"]       && get[camera.lookat]         ) continue;            
        if( get["up"]           && get[camera.up]             ) continue;            
        if( get["vpdist"]       && get[camera.vpdist]         ) continue;                   
        if( get["x_res"]        && get[camera.x_res]          ) continue;
        if( get["y_res"]        && get[camera.y_res]          ) continue;
        if( get["x_win"]        && get[camera.x_win]          ) continue;
        if( get["y_win"]        && get[camera.y_win]          ) continue;
        if( get["ambient"]      && get[material.ambient]      ) continue;            
        if( get["diffuse"]      && get[material.diffuse]      ) continue;
        if( get["specular"]     && get[material.specular]     ) continue;
        if( get["emission"]     && get[material.emission]     ) continue;
        if( get["reflectivity"] && get[material.reflectivity] ) continue;
        if( get["translucency"] && get[material.translucency] ) continue;
        if( get["Phong_exp"]    && get[material.Phong_exp]    ) continue;
        if( get["ref_index"]    && get[material.ref_index]    ) continue;

        // If no object is defined at this point, it's an error.

        if( obj == NULL )
            {
            cerr << "Error reading scene file; No object defined at line "
                 << line_num << ": "
                 << input_line << endl;
            return false;
            }

        // Look for an end statement that closes the current aggregate.  This allows us to nest aggregates.

        if( get["end"] )
            { 
            if( agg == NULL )
                {
                cerr << "Error: end statement found outside an aggregate object at line "
                     << line_num << ": "
                     << input_line << endl;
                return false;
                }
            
            // Go back to adding objects to the parent object (if there is one).

            agg->Close(); // Signal the aggregate that it is now complete.
            Object *closed_agg = agg;
            agg = agg->parent;
            if( agg != NULL )
                {
                material = *(agg->material);
                mat = agg->material;
                shd = agg->shader;
                env = agg->envmap;
                agg->AddChild( closed_agg ); // Add the agg that just ended.
                }
            continue;
            }
        
        // If nothing matched, it's an error.  Print a warning and continue processing.

        cerr << "Warning: Unrecognized or ill-formed command at line "
             << line_num << ": "
             << input_line << endl;
        }

    if( agg != NULL )
        {
        cerr << "Error: Top-most aggregate object has no 'end' statement." << endl;
        return false;
        }

    cout << "done." << endl;
    return true;
    }