Logo Search packages:      
Sourcecode: k3d version File versions

frozen_mesh.cpp

Go to the documentation of this file.
// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
            \author Timothy M. Shead (tshead@k-3d.com)
*/

#include <k3dsdk/classes.h>
#include <k3dsdk/imaterial.h>
#include <k3dsdk/measurement.h>
#include <k3dsdk/mesh_filter.h>
#include <k3dsdk/module.h>
#include <k3dsdk/object.h>
#include <k3dsdk/persistence.h>
#include <k3dsdk/plugins.h>
#include <k3dsdk/renderman.h>
#include <k3dsdk/selection.h>
#include <k3dsdk/string_cast.h>
#include <k3dsdk/string_modifiers.h>
#include <k3dsdk/transform.h>
#include <k3dsdk/xml_utility.h>

#include <iterator>

namespace libk3dmesh
{

/////////////////////////////////////////////////////////////////////////////
// frozen_mesh_implementation

class frozen_mesh_implementation :
      public k3d::mesh_filter<k3d::persistent<k3d::object> >
{
      typedef k3d::mesh_filter<k3d::persistent<k3d::object> > base;

public:
      frozen_mesh_implementation(k3d::idocument& Document) :
            base(Document)
      {
            m_input_mesh.changed_signal().connect(SigC::slot(*this, &frozen_mesh_implementation::on_reset_geometry));
            m_output_mesh.need_data_signal().connect(SigC::slot(*this, &frozen_mesh_implementation::on_create_geometry));
      }

      void on_reset_geometry()
      {
//          m_output_mesh.reset();
      }

      k3d::mesh* on_create_geometry()
      {
            // If we don't have any input data, we're done ...
            k3d::mesh* const input = m_input_mesh.property_value();
            if(!input)
                  return 0;

            // Create mutable output geometry ...
            k3d::mesh* const output = new k3d::mesh();

            // Make a copy of the input geometry ...
            k3d::deep_copy(*input, *output);
            
            return output;
      }

      template<typename data_t>
      bool load_parameter(const std::string& XMLType, const std::string& Name, const std::string& Type, const std::string& Value, k3d::parameters_t& Parameters)
      {
            if(XMLType != Type)
                  return false;

            Parameters[Name] = k3d::from_string<data_t>(Value, data_t());     
            return true;
      }

      void load_parameters(const sdpxml::Element& Element, const k3d::ri::storage_class_t StorageClass, k3d::parameters_t& Parameters)
      {
            for(sdpxml::ElementCollection::const_iterator xml_parameters = Element.Children().begin(); xml_parameters != Element.Children().end(); ++xml_parameters)
                  {
                        if(xml_parameters->Name() != "parameters")
                              continue;
                              
                        for(sdpxml::ElementCollection::const_iterator xml_parameter = xml_parameters->Children().begin(); xml_parameter != xml_parameters->Children().end(); ++xml_parameter)
                              {
                                    if(xml_parameter->Name() != "parameter")
                                          continue;
                                          
                                    const std::string name = sdpxml::GetAttribute(*xml_parameter, "name", std::string());
                                    const std::string type = sdpxml::GetAttribute(*xml_parameter, "type", std::string());
                                    const std::string value = sdpxml::GetAttribute(*xml_parameter, "value", std::string());
                                    
                                    if(name.empty())
                                          {
                                                std::cerr << error << k3d_file_reference() << " unnamed parameter will not be loaded" << std::endl;
                                                continue;
                                          }
                                          
                                    if(type.empty())
                                          {
                                                std::cerr << error << k3d_file_reference() << " parameter [" << name << "] with unknown type will not be loaded" << std::endl;
                                                continue;
                                          }
                                          
                                    if(load_parameter<k3d::ri::integer>("integer", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::real>("real", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::string>("string", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::point>("point", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::vector>("vector", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::normal>("normal", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::color>("color", name, type, value, Parameters)) continue; 
                                    if(load_parameter<k3d::ri::hpoint>("hpoint", name, type, value, Parameters)) continue; 
                        //          if(load_parameter<k3d::ri::matrix>("matrix", name, type, value, Parameters)) continue;
                        
                                    std::cerr << error << k3d_file_reference() << " parameter [" << name << "] with unsupported type [" << type << "] will not be loaded" << std::endl;
                              }
                  }
      }

      void load_legacy_data(sdpxml::Document& Document, sdpxml::Element& Element, k3d::mesh& Mesh)
      {
            // Load points ...
            std::map<unsigned long, k3d::point*> point_map;
            sdpxml::Element* const xml_points = sdpxml::FindElement(Element, sdpxml::SameName("points"));
            if(xml_points)
                  {
                        for(sdpxml::ElementCollection::const_iterator xml_point = xml_points->Children().begin(); xml_point != xml_points->Children().end(); ++xml_point)
                              {
                                    if(xml_point->Name() != "point")
                                          continue;
                                    
                                    const unsigned long id = sdpxml::GetAttribute(*xml_point, "id", 0UL);
                                    return_if_fail(id);

                                    Mesh.points.push_back(new k3d::point(sdpxml::GetAttribute(*xml_point, "position", k3d::vector3(0, 0, 0))));
                                    point_map[id] = Mesh.points.back();
                              }
                  }
                  
            // Load polygons into a single, non-solid polyhedron ...
            sdpxml::Element* const xml_paths = sdpxml::FindElement(Element, sdpxml::SameName("paths"));
            if(xml_paths)
                  {
                        k3d::polyhedron* const polyhedron = new k3d::polyhedron();
                        Mesh.polyhedra.push_back(polyhedron);

                        const std::string xml_rendermode = sdpxml::GetAttribute(k3d::xml::safe_element(k3d::xml::safe_element(Element, "variables"), sdpxml::Element("variable", "", sdpxml::Attribute("name", "rendermode"))), "value", std::string("normal"));
                        polyhedron->type = ("subdivision" == xml_rendermode) ? k3d::polyhedron::CATMULL_CLARK_SUBDIVISION_MESH : k3d::polyhedron::POLYGONS;
                                                                        
                        for(sdpxml::ElementCollection::iterator xml_path = xml_paths->Children().begin(); xml_path != xml_paths->Children().end(); ++xml_path)
                              {
                                    if(xml_path->Name() != "path")
                                          continue;

                                    polyhedron->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_path, "material", 0UL));
                                                                                    
                                    sdpxml::Element* const xml_pathpoints = sdpxml::FindElement(*xml_path, sdpxml::SameName("pathpoints"));
                                    if(xml_pathpoints)
                                          {                       
                                                k3d::polyhedron::edges_t new_edges;
                                                for(sdpxml::ElementCollection::iterator xml_pathpoint = xml_pathpoints->Children().begin(); xml_pathpoint != xml_pathpoints->Children().end(); ++xml_pathpoint)
                                                      {
                                                            if(xml_pathpoint->Name() != "pathpoint")
                                                                  continue;
                                                                  
                                                            const unsigned long point_id = sdpxml::GetAttribute(*xml_pathpoint, "pointid", 0UL);
                                                            return_if_fail(point_map.count(point_id));
                                    
                                                            new_edges.push_back(new k3d::split_edge(point_map[point_id]));
                                                      }
                                                k3d::loop_edges(new_edges.begin(), new_edges.end());
                        
                                                polyhedron->edges.insert(polyhedron->edges.end(), new_edges.begin(), new_edges.end());
                                                polyhedron->faces.push_back(new k3d::face(new_edges.front()));
                                          }
                              }
                  }
      }

      void load(sdpxml::Document& Document, sdpxml::Element& Element)
      {
            base::load(Document, Element);

            // Create a new mesh ...
            k3d::mesh* const mesh = new k3d::mesh();
            m_output_mesh.reset(mesh);
                                    
            // Load legacy data from the original Mesh object
            load_legacy_data(Document, Element, *mesh);
            
            // Load the stored mesh data ...
            sdpxml::Element* const xml_mesh = sdpxml::FindElement(Element, sdpxml::SameName("mesh"));
            if(!xml_mesh)
                  return;
            
            // Load points ...
            sdpxml::Element* const xml_points = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("points"));
            if(xml_points)
                  {
                        for(sdpxml::ElementCollection::const_iterator xml_point = xml_points->Children().begin(); xml_point != xml_points->Children().end(); ++xml_point)
                              {
                                    if(xml_point->Name() != "point")
                                          continue;
                                          
                                    mesh->points.push_back(new k3d::point(sdpxml::GetAttribute(*xml_point, "position", k3d::vector3(0, 0, 0))));
                                    load_parameters(*xml_point, k3d::ri::VERTEX, mesh->points.back()->vertex_data);
                              }
                  }
                  
            // Load point groups ...
            sdpxml::Element* const xml_point_groups = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("pointgroups"));
            if(xml_point_groups)
                  {
                        for(sdpxml::ElementCollection::iterator xml_group = xml_point_groups->Children().begin(); xml_group != xml_point_groups->Children().end(); ++xml_group)
                              {
                                    if(xml_group->Name() != "group")
                                          continue;
                                    
                                    k3d::point_group* const group = new k3d::point_group();
                                    group->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_group, "material", 0UL));
                                    mesh->point_groups.push_back(group);
                                          
                                    sdpxml::Element* const xml_points = sdpxml::FindElement(*xml_group, sdpxml::SameName("points"));
                                    if(xml_points)
                                          {
                                                std::istringstream points_buffer(xml_points->Text());
                                                for(std::istream_iterator<unsigned long> point(points_buffer); point != std::istream_iterator<unsigned long>(); ++point)
                                                      {
                                                            const unsigned long point_index = *point - 1;
                                                            return_if_fail(point_index < mesh->points.size());
                                                            group->points.push_back(mesh->points[point_index]);
                                                      }
                                          }
                              }
                  }
      
            // Load polyhedra ...
            sdpxml::Element* const xml_polyhedra = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("polyhedra"));
            if(xml_polyhedra)
                  {
                        for(sdpxml::ElementCollection::iterator xml_polyhedron = xml_polyhedra->Children().begin(); xml_polyhedron != xml_polyhedra->Children().end(); ++xml_polyhedron)
                              {
                                    if(xml_polyhedron->Name() != "polyhedron")
                                          continue;

                                    k3d::polyhedron* const polyhedron = new k3d::polyhedron();
                                    
                                    polyhedron->type = k3d::polyhedron::POLYGONS;
                                    if(!sdpxml::ParseAttribute(*xml_polyhedron, "type", polyhedron->type))
                                          {
                                                std::cerr << warning << "Defaulting polyhedron type to POLYGONS" << std::endl;
                                          }

                                    polyhedron->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_polyhedron, "material", 0UL));
                                    mesh->polyhedra.push_back(polyhedron);

                                    // Load edges ...
                                    sdpxml::Element* const xml_edges = sdpxml::FindElement(*xml_polyhedron, sdpxml::SameName("edges"));
                                    if(xml_edges)
                                          {
                                                const unsigned long edge_count = std::count_if(xml_edges->Children().begin(), xml_edges->Children().end(), sdpxml::SameName("edge"));
                                                k3d::polyhedron::edges_t edges(edge_count);
                                                for(k3d::polyhedron::edges_t::iterator edge = edges.begin(); edge != edges.end(); ++edge)
                                                      *edge = new k3d::split_edge(0, 0, 0);
                                                

                                                k3d::polyhedron::edges_t::iterator edge = edges.begin();
                                                for(sdpxml::ElementCollection::iterator xml_edge = xml_edges->Children().begin(); xml_edge != xml_edges->Children().end(); ++xml_edge)
                                                      {
                                                            if(xml_edge->Name() != "edge")
                                                                  continue;

                                                            unsigned long vertex_index = 0;
                                                            return_if_fail(sdpxml::ParseAttribute(*xml_edge, "vertex", vertex_index));
                                                            return_if_fail(vertex_index <= mesh->points.size());

                                                            unsigned long face_clockwise_index = 0;
                                                            return_if_fail(sdpxml::ParseAttribute(*xml_edge, "faceclockwise", face_clockwise_index));
                                                            return_if_fail(face_clockwise_index <= edges.size());

                                                            unsigned long companion_index = 0;
                                                            return_if_fail(sdpxml::ParseAttribute(*xml_edge, "companion", companion_index));
                                                            return_if_fail(companion_index <= edges.size());

                                                            if(vertex_index)
                                                                  (*edge)->vertex = mesh->points[vertex_index-1];

                                                            if(face_clockwise_index)
                                                                  (*edge)->face_clockwise = edges[face_clockwise_index-1];

                                                            if(companion_index)
                                                                  (*edge)->companion = edges[companion_index-1];

                                                            ++edge;
                                                      }

                                                polyhedron->edges.swap(edges);
                                          }

                                    // Load faces ...
                                    sdpxml::Element* const xml_faces = sdpxml::FindElement(*xml_polyhedron, sdpxml::SameName("faces"));
                                    if(xml_faces)
                                          {
                                                for(sdpxml::ElementCollection::iterator xml_face = xml_faces->Children().begin(); xml_face != xml_faces->Children().end(); ++xml_face)
                                                      {
                                                            if(xml_face->Name() != "face")
                                                                  continue;

                                                            unsigned long first_edge_index = 0;
                                                            return_if_fail(sdpxml::ParseAttribute(*xml_face, "firstedge", first_edge_index));
                                                            return_if_fail(first_edge_index <= polyhedron->edges.size());

                                                            k3d::face* const face = new k3d::face(first_edge_index ? polyhedron->edges[first_edge_index-1] : 0);
                                                            polyhedron->faces.push_back(face);
                                                            
                                                            sdpxml::Element* const xml_holes = sdpxml::FindElement(*xml_face, sdpxml::SameName("holes"));
                                                            if(xml_holes)
                                                                  {
                                                                        for(sdpxml::ElementCollection::iterator xml_hole = xml_holes->Children().begin(); xml_hole != xml_holes->Children().end(); ++xml_hole)
                                                                              {
                                                                                    if(xml_hole->Name() != "hole")
                                                                                          continue;

                                                                                    unsigned long first_edge_index = 0;
                                                                                    return_if_fail(sdpxml::ParseAttribute(*xml_hole, "firstedge", first_edge_index));
                                                                                    return_if_fail(first_edge_index <= polyhedron->edges.size());
                                                                                    
                                                                                    face->holes.push_back(first_edge_index ? polyhedron->edges[first_edge_index-1] : 0);
                                                                                                                                                                                                                                                                                                                                                                                                                                          
/*                                                                                        
                                                                                    k3d::face::hole* const hole = new k3d::face::hole();
                                                                                    face->holes.push_back(hole);
            
                                                                                    sdpxml::Element* const xml_vertices = sdpxml::FindElement(*xml_hole, sdpxml::SameName("vertices"));
                                                                                    if(xml_vertices)
                                                                                          {                                                                       
                                                                                                std::istringstream vertices_buffer(xml_vertices->Text());
                                                                                                for(std::istream_iterator<unsigned long> vertex(vertices_buffer); vertex != std::istream_iterator<unsigned long>(); ++vertex)
                                                                                                      {
                                                                                                            const unsigned long vertex_index = *vertex - 1;
                                                                                                            return_if_fail(vertex_index < mesh->points.size());
                                                                                                            hole->vertices.push_back(mesh->points[vertex_index]);
                                                                                                      }
                                                                                          }
*/
                                                                              }
                                                                  }
                                                      }
                                          }
                              }
                  }
                  
            // Load linear curve groups ...
            sdpxml::Element* const xml_linear_curve_groups = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("linearcurvegroups"));
            if(xml_linear_curve_groups)
                  {
                        for(sdpxml::ElementCollection::iterator xml_group = xml_linear_curve_groups->Children().begin(); xml_group != xml_linear_curve_groups->Children().end(); ++xml_group)
                              {
                                    if(xml_group->Name() != "group")
                                          continue;
                                          
                                    k3d::linear_curve_group* const group = new k3d::linear_curve_group();
                                    group->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_group, "material", 0UL));
                                    mesh->linear_curve_groups.push_back(group);
                                    
                                    sdpxml::Element* const xml_curves = sdpxml::FindElement(*xml_group, sdpxml::SameName("curves"));
                                    if(!xml_curves)
                                          continue;
                                          
                                    for(sdpxml::ElementCollection::iterator xml_curve = xml_curves->Children().begin(); xml_curve != xml_curves->Children().end(); ++xml_curve)
                                          {
                                                if(xml_curve->Name() != "curve")
                                                      continue;
                                                      
                                                k3d::linear_curve* const curve = new k3d::linear_curve();
                                                group->curves.push_back(curve);
                                                
                                                sdpxml::Element* const xml_control_points = sdpxml::FindElement(*xml_curve, sdpxml::SameName("controlpoints"));
                                                if(!xml_control_points)
                                                      continue;

                                                std::istringstream points_buffer(xml_control_points->Text());
                                                for(std::istream_iterator<unsigned long> control_point(points_buffer); control_point != std::istream_iterator<unsigned long>(); ++control_point)
                                                      {
                                                            const unsigned long control_point_index = *control_point - 1;
                                                            return_if_fail(control_point_index < mesh->points.size());
                                                            curve->control_points.push_back(mesh->points[control_point_index]);
                                                      }
                                          }
                              }
                  }

            // Load cubic curve groups ...
            sdpxml::Element* const xml_cubic_curve_groups = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("cubiccurvegroups"));
            if(xml_cubic_curve_groups)
                  {
                        for(sdpxml::ElementCollection::iterator xml_group = xml_cubic_curve_groups->Children().begin(); xml_group != xml_cubic_curve_groups->Children().end(); ++xml_group)
                              {
                                    if(xml_group->Name() != "group")
                                          continue;
                                          
                                    k3d::cubic_curve_group* const group = new k3d::cubic_curve_group();
                                    group->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_group, "material", 0UL));
                                    mesh->cubic_curve_groups.push_back(group);
                                    
                                    sdpxml::Element* const xml_curves = sdpxml::FindElement(*xml_group, sdpxml::SameName("curves"));
                                    if(!xml_curves)
                                          continue;
                                          
                                    for(sdpxml::ElementCollection::iterator xml_curve = xml_curves->Children().begin(); xml_curve != xml_curves->Children().end(); ++xml_curve)
                                          {
                                                if(xml_curve->Name() != "curve")
                                                      continue;
                                                      
                                                k3d::cubic_curve* const curve = new k3d::cubic_curve();
                                                group->curves.push_back(curve);
                                                
                                                sdpxml::Element* const xml_control_points = sdpxml::FindElement(*xml_curve, sdpxml::SameName("controlpoints"));
                                                if(!xml_control_points)
                                                      continue;

                                                std::istringstream points_buffer(xml_control_points->Text());
                                                for(std::istream_iterator<unsigned long> control_point(points_buffer); control_point != std::istream_iterator<unsigned long>(); ++control_point)
                                                      {
                                                            const unsigned long control_point_index = *control_point - 1;
                                                            return_if_fail(control_point_index < mesh->points.size());
                                                            curve->control_points.push_back(mesh->points[control_point_index]);
                                                      }
                                          }
                              }
                  }

            // Load NURBS curve groups ...
            sdpxml::Element* const xml_nucurve_groups = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("nucurvegroups"));
            if(xml_nucurve_groups)
                  {
                        for(sdpxml::ElementCollection::iterator xml_group = xml_nucurve_groups->Children().begin(); xml_group != xml_nucurve_groups->Children().end(); ++xml_group)
                              {
                                    if(xml_group->Name() != "group")
                                          continue;
                                          
                                    k3d::nucurve_group* const group = new k3d::nucurve_group();
                                    group->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_group, "material", 0UL));
                                    mesh->nucurve_groups.push_back(group);
                                    
                                    sdpxml::Element* const xml_curves = sdpxml::FindElement(*xml_group, sdpxml::SameName("curves"));
                                    if(!xml_curves)
                                          continue;
                                    
                                    for(sdpxml::ElementCollection::iterator xml_curve = xml_curves->Children().begin(); xml_curve != xml_curves->Children().end(); ++xml_curve)
                                          {
                                                if(xml_curve->Name() != "curve")
                                                      continue;

                                                sdpxml::Element* const xml_knot_vector = sdpxml::FindElement(*xml_curve, sdpxml::SameName("knotvector"));
                                                sdpxml::Element* const xml_control_points = sdpxml::FindElement(*xml_curve, sdpxml::SameName("controlpoints"));
                                                sdpxml::Element* const xml_weights = sdpxml::FindElement(*xml_curve, sdpxml::SameName("weights"));

                                                if(xml_knot_vector && xml_control_points && xml_weights)
                                                      {
                                                            k3d::nucurve* const curve = new k3d::nucurve();
                                                            curve->order = sdpxml::GetAttribute(*xml_curve, "order", 0);
                                                            group->curves.push_back(curve);

                                                            std::istringstream knots_buffer(xml_knot_vector->Text());
                                                            std::copy(std::istream_iterator<double>(knots_buffer), std::istream_iterator<double>(), std::back_inserter(curve->knots));

                                                            std::istringstream points_buffer(xml_control_points->Text());
                                                            std::istringstream weights_buffer(xml_weights->Text());

                                                            std::istream_iterator<unsigned long> control_point(points_buffer);
                                                            std::istream_iterator<double> weight(weights_buffer);
                                                            for(; control_point != std::istream_iterator<unsigned long>() && weight != std::istream_iterator<double>(); ++control_point, ++weight)
                                                                  {
                                                                        const unsigned long control_point_index = *control_point - 1;
                                                                        return_if_fail(control_point_index < mesh->points.size());
                                                                        curve->control_points.push_back(k3d::nucurve::control_point(mesh->points[control_point_index], *weight));
                                                                  }
                                                      }
                                          }
                              }
                  }
      

            // Load bilinear patches ...
            sdpxml::Element* const xml_bilinear_patches = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("bilinearpatches"));
            if(xml_bilinear_patches)
                  {
                        for(sdpxml::ElementCollection::iterator xml_patch = xml_bilinear_patches->Children().begin(); xml_patch != xml_bilinear_patches->Children().end(); ++xml_patch)
                              {
                                    if(xml_patch->Name() != "patch")
                                          continue;
                                          
                                    k3d::bilinear_patch* const patch = new k3d::bilinear_patch();
                                    patch->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_patch, "material", 0UL));
                                    mesh->bilinear_patches.push_back(patch);
                                    
                                    sdpxml::Element* const xml_control_points = sdpxml::FindElement(*xml_patch, sdpxml::SameName("controlpoints"));
                                    if(!xml_control_points)
                                          continue;

                                    unsigned long storage_index = 0;
                                    std::istringstream points_buffer(xml_control_points->Text());
                                    for(std::istream_iterator<unsigned long> control_point(points_buffer); control_point != std::istream_iterator<unsigned long>(); ++control_point)
                                          {
                                                return_if_fail(storage_index < 4);
                                                
                                                const unsigned long control_point_index = *control_point - 1;
                                                return_if_fail(control_point_index < mesh->points.size());
                                                patch->control_points[storage_index++] = mesh->points[control_point_index];
                                          }
                              }
                  }
            
            // Load bicubic patches ...
            sdpxml::Element* const xml_bicubic_patches = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("bicubicpatches"));
            if(xml_bicubic_patches)
                  {
                        for(sdpxml::ElementCollection::iterator xml_patch = xml_bicubic_patches->Children().begin(); xml_patch != xml_bicubic_patches->Children().end(); ++xml_patch)
                              {
                                    if(xml_patch->Name() != "patch")
                                          continue;
                                          
                                    k3d::bicubic_patch* const patch = new k3d::bicubic_patch();
                                    patch->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_patch, "material", 0UL));
                                    mesh->bicubic_patches.push_back(patch);
                                    
                                    sdpxml::Element* const xml_control_points = sdpxml::FindElement(*xml_patch, sdpxml::SameName("controlpoints"));
                                    if(!xml_control_points)
                                          continue;

                                    unsigned long storage_index = 0;
                                    std::istringstream points_buffer(xml_control_points->Text());
                                    for(std::istream_iterator<unsigned long> control_point(points_buffer); control_point != std::istream_iterator<unsigned long>(); ++control_point)
                                          {
                                                return_if_fail(storage_index < 16);
                                                
                                                const unsigned long control_point_index = *control_point - 1;
                                                return_if_fail(control_point_index < mesh->points.size());
                                                patch->control_points[storage_index++] = mesh->points[control_point_index];
                                          }
                              }
                  }

            // Load NURBS patches ...
            sdpxml::Element* const xml_nupatches = sdpxml::FindElement(*xml_mesh, sdpxml::SameName("nupatches"));
            if(xml_nupatches)
                  {
                        for(sdpxml::ElementCollection::iterator xml_patch = xml_nupatches->Children().begin(); xml_patch != xml_nupatches->Children().end(); ++xml_patch)
                              {
                                    if(xml_patch->Name() != "patch")
                                          continue;

                                    sdpxml::Element* const xml_u_knot_vector = sdpxml::FindElement(*xml_patch, sdpxml::SameName("uknotvector"));
                                    sdpxml::Element* const xml_v_knot_vector = sdpxml::FindElement(*xml_patch, sdpxml::SameName("vknotvector"));
                                    sdpxml::Element* const xml_control_points = sdpxml::FindElement(*xml_patch, sdpxml::SameName("controlpoints"));
                                    sdpxml::Element* const xml_weights = sdpxml::FindElement(*xml_patch, sdpxml::SameName("weights"));

                                    if(xml_u_knot_vector && xml_v_knot_vector && xml_control_points && xml_weights)
                                          {
                                                k3d::nupatch* const patch = new k3d::nupatch();
                                                patch->u_order = sdpxml::GetAttribute(*xml_patch, "uorder", 0);
                                                patch->v_order = sdpxml::GetAttribute(*xml_patch, "vorder", 0);
                                                patch->material = reinterpret_cast<k3d::imaterial*>(sdpxml::GetAttribute(*xml_patch, "material", 0UL));
                                                mesh->nupatches.push_back(patch);

                                                std::istringstream u_knots_buffer(xml_u_knot_vector->Text());
                                                std::copy(std::istream_iterator<double>(u_knots_buffer), std::istream_iterator<double>(), std::back_inserter(patch->u_knots));

                                                std::istringstream v_knots_buffer(xml_v_knot_vector->Text());
                                                std::copy(std::istream_iterator<double>(v_knots_buffer), std::istream_iterator<double>(), std::back_inserter(patch->v_knots));

                                                std::istringstream points_buffer(xml_control_points->Text());
                                                std::istringstream weights_buffer(xml_weights->Text());

                                                std::istream_iterator<unsigned long> control_point(points_buffer);
                                                std::istream_iterator<double> weight(weights_buffer);
                                                for(; control_point != std::istream_iterator<unsigned long>() && weight != std::istream_iterator<double>(); ++control_point, ++weight)
                                                      {
                                                            const unsigned long control_point_index = *control_point - 1;
                                                            return_if_fail(control_point_index < mesh->points.size());
                                                            patch->control_points.push_back(k3d::nupatch::control_point(mesh->points[control_point_index], *weight));
                                                      }
                                          }
                              }
                  }
      }

      /// Once the entire document has been loaded, we use this bit of voodoo to convert material object IDs back into interface pointers
00604       class relink
      {
      public:
            relink(k3d::idocument& Document) : m_objects(Document.objects())
            {
            }
            
            template<typename T>
            void operator()(T* Object)
            {
                  Object->material = dynamic_cast<k3d::imaterial*>(k3d::find_object(m_objects, reinterpret_cast<k3d::iobject::id_type>(Object->material)));
            }
            
      private:
            k3d::iobject_collection& m_objects;
      };

      void load_complete()
      {
            base::load_complete();
            
            // If we aren't storing any data, we're done ...
            if(m_output_mesh.empty())
                  return;
            k3d::mesh& mesh = *m_output_mesh.value();
                  
            // Relink references to materials ...
            std::for_each(mesh.point_groups.begin(), mesh.point_groups.end(), relink(document()));
            std::for_each(mesh.polyhedra.begin(), mesh.polyhedra.end(), relink(document()));
            std::for_each(mesh.linear_curve_groups.begin(), mesh.linear_curve_groups.end(), relink(document()));
            std::for_each(mesh.cubic_curve_groups.begin(), mesh.cubic_curve_groups.end(), relink(document()));
            std::for_each(mesh.nucurve_groups.begin(), mesh.nucurve_groups.end(), relink(document()));
            std::for_each(mesh.bilinear_patches.begin(), mesh.bilinear_patches.end(), relink(document()));
            std::for_each(mesh.bicubic_patches.begin(), mesh.bicubic_patches.end(), relink(document()));
            std::for_each(mesh.nupatches.begin(), mesh.nupatches.end(), relink(document()));
      }

      template<typename data_t, typename iterator_t>
      bool save_parameter(sdpxml::Element& XMLParameters, iterator_t Parameter, const std::string& Type)
      {
            if(typeid(data_t) != Parameter->second.type())
                  return false;

            
            XMLParameters.Append(sdpxml::Element("parameter", "", sdpxml::Attribute("name", Parameter->first), sdpxml::Attribute("type", Type), sdpxml::Attribute("value", k3d::string_cast(boost::any_cast<data_t>(Parameter->second)))));

            return true;
      }

      void save_parameters(sdpxml::Element& Element, const k3d::parameters_t& Parameters, const k3d::ri::storage_class_t Type)
      {
            if(Parameters.empty())
                  return;

            sdpxml::Element& xml_parameters = Element.Append(sdpxml::Element("parameters", "", sdpxml::Attribute("type", k3d::string_cast(Type))));

            for(k3d::parameters_t::const_iterator parameter = Parameters.begin(); parameter != Parameters.end(); ++parameter)
                  {
                        if(save_parameter<k3d::ri::integer>(xml_parameters, parameter, "integer")) continue; 
                        if(save_parameter<k3d::ri::real>(xml_parameters, parameter, "real")) continue; 
                        if(save_parameter<k3d::ri::string>(xml_parameters, parameter, "string")) continue; 
                        if(save_parameter<k3d::ri::point>(xml_parameters, parameter, "point")) continue; 
                        if(save_parameter<k3d::ri::vector>(xml_parameters, parameter, "vector")) continue; 
                        if(save_parameter<k3d::ri::normal>(xml_parameters, parameter, "normal")) continue; 
                        if(save_parameter<k3d::ri::color>(xml_parameters, parameter, "color")) continue; 
                        if(save_parameter<k3d::ri::hpoint>(xml_parameters, parameter, "hpoint")) continue; 
            //          if(save_parameter<k3d::ri::matrix>(xml_parameters, parameter, "matrix")) continue;

                        std::cerr << error << "Unknown parameter type - parameter [" << parameter->first << "] will not be serialized" << std::endl;
                  }
      }

      void save(sdpxml::Element& Element, k3d::idependencies& Dependencies)
      {
            base::save(Element, Dependencies);

            // If we aren't storing any data, we're done ...
            if(m_output_mesh.empty())
                  return;
                  
            // Save our stored mesh data ...
            const k3d::mesh& mesh = *m_output_mesh.value();
            sdpxml::Element& xml_mesh = Element.Append(sdpxml::Element("mesh"));

            // Create a one-based index of points
            std::map<k3d::point*, unsigned long> point_map;
            point_map[0] = 0;
            for(k3d::mesh::points_t::const_iterator point = mesh.points.begin(); point != mesh.points.end(); ++point)
                  point_map.insert(std::make_pair(*point, point_map.size()));

            // Save points ...
            if(mesh.points.size())
                  {
                        sdpxml::Element& xml_points = xml_mesh.Append(sdpxml::Element("points"));
                        for(k3d::mesh::points_t::const_iterator point = mesh.points.begin(); point != mesh.points.end(); ++point)
                              {
                                    sdpxml::Element& xml_point = xml_points.Append(sdpxml::Element("point", "", sdpxml::Attribute("position", k3d::string_cast((**point).position))));
                                    save_parameters(xml_point, (*point)->vertex_data, k3d::ri::VERTEX);
                              }
                  }

            // Save point groups ...
            if(mesh.point_groups.size())
                  {
                        sdpxml::Element& xml_point_groups = xml_mesh.Append(sdpxml::Element("pointgroups"));
                        for(k3d::mesh::point_groups_t::const_iterator point_group = mesh.point_groups.begin(); point_group != mesh.point_groups.end(); ++point_group)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*point_group)->material);
                                    sdpxml::Element& xml_point_group = xml_point_groups.Append(sdpxml::Element("group", "", sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    std::ostringstream points_buffer;
                                    for(k3d::point_group::points_t::const_iterator point = (*point_group)->points.begin(); point != (*point_group)->points.end(); ++point)
                                          points_buffer << point_map[*point] << " ";
                                    xml_point_group.Append(sdpxml::Element("points", points_buffer.str()));

                                    save_parameters(xml_point_group, (*point_group)->constant_data, k3d::ri::CONSTANT);
                              }
                  }

            // Save polyhedra ...
            if(mesh.polyhedra.size())
                  {
                        // For each polyhedron ...
                        sdpxml::Element& xml_polyhedra = xml_mesh.Append(sdpxml::Element("polyhedra"));
                        for(k3d::mesh::polyhedra_t::const_iterator polyhedron = mesh.polyhedra.begin(); polyhedron != mesh.polyhedra.end(); ++polyhedron)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*polyhedron)->material);
                                    sdpxml::Element& xml_polyhedron = xml_polyhedra.Append(sdpxml::Element("polyhedron", "", sdpxml::Attribute("type", k3d::string_cast((*polyhedron)->type)), sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    // Create a one-based index of edges ...
                                    std::map<k3d::split_edge*, unsigned long> edge_map;
                                    edge_map[0] = 0;        
                                    for(k3d::polyhedron::edges_t::const_iterator edge = (*polyhedron)->edges.begin(); edge != (*polyhedron)->edges.end(); ++edge)
                                          edge_map.insert(std::make_pair(*edge, edge_map.size()));

                                    // Save edges ...
                                    if((*polyhedron)->edges.size())
                                          {
                                                sdpxml::Element& xml_edges = xml_polyhedron.Append(sdpxml::Element("edges"));
                                                for(k3d::polyhedron::edges_t::const_iterator edge = (*polyhedron)->edges.begin(); edge != (*polyhedron)->edges.end(); ++edge)
                                                      {
                                                            sdpxml::Element& xml_edge = xml_edges.Append(
                                                                  sdpxml::Element("edge", "",
                                                                        sdpxml::Attribute("vertex", k3d::string_cast(point_map[(*edge)->vertex])),
                                                                        sdpxml::Attribute("faceclockwise", k3d::string_cast(edge_map[(*edge)->face_clockwise])),
                                                                        sdpxml::Attribute("companion", k3d::string_cast(edge_map[(*edge)->companion]))));

                                                            save_parameters(xml_edge, (*edge)->facevarying_data, k3d::ri::FACEVARYING);
                                                      }
                                          }

                                    // Save faces ...
                                    if((*polyhedron)->faces.size())
                                          {
                                                sdpxml::Element& xml_faces = xml_polyhedron.Append(sdpxml::Element("faces"));
                                                for(k3d::polyhedron::faces_t::const_iterator face = (*polyhedron)->faces.begin(); face != (*polyhedron)->faces.end(); ++face)
                                                      {
                                                            sdpxml::Element& xml_face = xml_faces.Append(sdpxml::Element("face", "", sdpxml::Attribute("firstedge", k3d::string_cast(edge_map[(*face)->first_edge]))));
                                                            if((*face)->holes.size())
                                                                  {
                                                                        sdpxml::Element& xml_holes = xml_face.Append(sdpxml::Element("holes"));
                                                                        for(k3d::face::holes_t::const_iterator hole = (*face)->holes.begin(); hole != (*face)->holes.end(); ++hole)
                                                                              {
                                                                                    sdpxml::Element& xml_hole = xml_holes.Append(sdpxml::Element("hole", "", sdpxml::Attribute("firstedge", k3d::string_cast(edge_map[(*hole)]))));
/*
                                                                                    std::ostringstream points_buffer;
                                                                                    for(k3d::face::hole::vertices_t::const_iterator vertex = (*hole)->vertices.begin(); vertex != (*hole)->vertices.end(); ++vertex)
                                                                                          points_buffer << point_map[*vertex] << " ";
                                                                                    xml_hole.Append(sdpxml::Element("vertices", points_buffer.str()));
*/
                                                                              }
                                                                  }

                                                            save_parameters(xml_face, (*face)->uniform_data, k3d::ri::UNIFORM);
                                                      }
                                          }
                              }
                  }

            // Save linear curve groups ...
            if(mesh.linear_curve_groups.size())
                  {
                        sdpxml::Element& xml_linear_curve_groups = xml_mesh.Append(sdpxml::Element("linearcurvegroups"));
                        for(k3d::mesh::linear_curve_groups_t::const_iterator group = mesh.linear_curve_groups.begin(); group != mesh.linear_curve_groups.end(); ++group)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*group)->material);
                                    sdpxml::Element& xml_linear_curve_group = xml_linear_curve_groups.Append(sdpxml::Element("group", "", sdpxml::Attribute("wrap", k3d::string_cast((*group)->wrap)), sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    sdpxml::Element& xml_curves = xml_linear_curve_group.Append(sdpxml::Element("curves"));
                                    for(k3d::linear_curve_group::curves_t::const_iterator curve = (*group)->curves.begin(); curve != (*group)->curves.end(); ++curve)
                                          {
                                                sdpxml::Element& xml_curve = xml_curves.Append(sdpxml::Element("curve", ""));
                                                
                                                std::ostringstream points_buffer;
                                                for(k3d::linear_curve::control_points_t::const_iterator control_point = (*curve)->control_points.begin(); control_point != (*curve)->control_points.end(); ++control_point)
                                                      points_buffer << point_map[*control_point] << " ";
                                                xml_curve.Append(sdpxml::Element("controlpoints", points_buffer.str()));
                                          }
                              }
                  }

            // Save cubic curve groups ...
            if(mesh.cubic_curve_groups.size())
                  {
                        sdpxml::Element& xml_cubic_curve_groups = xml_mesh.Append(sdpxml::Element("cubiccurvegroups"));
                        for(k3d::mesh::cubic_curve_groups_t::const_iterator group = mesh.cubic_curve_groups.begin(); group != mesh.cubic_curve_groups.end(); ++group)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*group)->material);
                                    sdpxml::Element& xml_cubic_curve_group = xml_cubic_curve_groups.Append(sdpxml::Element("group", "", sdpxml::Attribute("wrap", k3d::string_cast((*group)->wrap)), sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    sdpxml::Element& xml_curves = xml_cubic_curve_group.Append(sdpxml::Element("curves"));
                                    for(k3d::cubic_curve_group::curves_t::const_iterator curve = (*group)->curves.begin(); curve != (*group)->curves.end(); ++curve)
                                          {
                                                sdpxml::Element& xml_curve = xml_curves.Append(sdpxml::Element("curve", ""));
                                                
                                                std::ostringstream points_buffer;
                                                for(k3d::cubic_curve::control_points_t::const_iterator control_point = (*curve)->control_points.begin(); control_point != (*curve)->control_points.end(); ++control_point)
                                                      points_buffer << point_map[*control_point] << " ";
                                                xml_curve.Append(sdpxml::Element("controlpoints", points_buffer.str()));
                                          }
                              }
                  }

            // Save NURBS curve groups ...
            if(mesh.nucurve_groups.size())
                  {
                        sdpxml::Element& xml_nucurve_groups = xml_mesh.Append(sdpxml::Element("nucurvegroups"));
                        for(k3d::mesh::nucurve_groups_t::const_iterator group = mesh.nucurve_groups.begin(); group != mesh.nucurve_groups.end(); ++group)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*group)->material);
                                    sdpxml::Element& xml_nucurve_group = xml_nucurve_groups.Append(sdpxml::Element("group", "", sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    sdpxml::Element& xml_curves = xml_nucurve_group.Append(sdpxml::Element("curves"));
                                    for(k3d::nucurve_group::curves_t::const_iterator curve = (*group)->curves.begin(); curve != (*group)->curves.end(); ++curve)
                                          {
                                                sdpxml::Element& xml_curve = xml_curves.Append(sdpxml::Element("curve", "", sdpxml::Attribute("order", k3d::string_cast((*curve)->order))));

                                                std::ostringstream knots_buffer;
                                                std::copy((*curve)->knots.begin(), (*curve)->knots.end(), std::ostream_iterator<double>(knots_buffer, " "));
                                                xml_curve.Append(sdpxml::Element("knotvector", knots_buffer.str()));
                                                
                                                std::ostringstream points_buffer;
                                                std::ostringstream weights_buffer;
                                                for(k3d::nucurve::control_points_t::const_iterator control_point = (*curve)->control_points.begin(); control_point != (*curve)->control_points.end(); ++control_point)
                                                      {
                                                            points_buffer << point_map[control_point->position] << " ";
                                                            weights_buffer << control_point->weight << " ";
                                                      }
                                                      
                                                xml_curve.Append(sdpxml::Element("controlpoints", points_buffer.str()));
                                                xml_curve.Append(sdpxml::Element("weights", weights_buffer.str()));
                                          }
                              }
                  }

            // Save bilinear patches ...
            if(mesh.bilinear_patches.size())
                  {
                        sdpxml::Element& xml_patches = xml_mesh.Append(sdpxml::Element("bilinearpatches"));
                        for(k3d::mesh::bilinear_patches_t::const_iterator patch = mesh.bilinear_patches.begin(); patch != mesh.bilinear_patches.end(); ++patch)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*patch)->material);
                                    sdpxml::Element& xml_patch = xml_patches.Append(sdpxml::Element("patch", "", sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    std::ostringstream points_buffer;
                                    for(k3d::bilinear_patch::control_points_t::const_iterator control_point = (*patch)->control_points.begin(); control_point != (*patch)->control_points.end(); ++control_point)
                                          points_buffer << point_map[*control_point] << " ";
                                    xml_patch.Append(sdpxml::Element("controlpoints", points_buffer.str()));
                              }
                  }

            // Save bicubic patches ...
            if(mesh.bicubic_patches.size())
                  {
                        sdpxml::Element& xml_patches = xml_mesh.Append(sdpxml::Element("bicubicpatches"));
                        for(k3d::mesh::bicubic_patches_t::const_iterator patch = mesh.bicubic_patches.begin(); patch != mesh.bicubic_patches.end(); ++patch)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*patch)->material);
                                    sdpxml::Element& xml_patch = xml_patches.Append(sdpxml::Element("patch", "", sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0))));

                                    std::ostringstream points_buffer;
                                    for(k3d::bicubic_patch::control_points_t::const_iterator control_point = (*patch)->control_points.begin(); control_point != (*patch)->control_points.end(); ++control_point)
                                          points_buffer << point_map[*control_point] << " ";
                                    xml_patch.Append(sdpxml::Element("controlpoints", points_buffer.str()));
                              }
                  }

            // Save NURBS patches ...
            if(mesh.nupatches.size())
                  {
                        sdpxml::Element& xml_patches = xml_mesh.Append(sdpxml::Element("nupatches"));
                        for(k3d::mesh::nupatches_t::const_iterator patch = mesh.nupatches.begin(); patch != mesh.nupatches.end(); ++patch)
                              {
                                    k3d::iobject* const material_object = dynamic_cast<k3d::iobject*>((*patch)->material);
                                    sdpxml::Element& xml_patch = xml_patches.Append(sdpxml::Element("patch", "", sdpxml::Attribute("uorder", k3d::string_cast((*patch)->u_order)), sdpxml::Attribute("vorder", k3d::string_cast((*patch)->v_order)), sdpxml::Attribute("material", k3d::string_cast(material_object ? material_object->id() : 0 ))));

                                    std::ostringstream u_knots_buffer;
                                    std::copy((*patch)->u_knots.begin(), (*patch)->u_knots.end(), std::ostream_iterator<double>(u_knots_buffer, " "));
                                    xml_patch.Append(sdpxml::Element("uknotvector", u_knots_buffer.str()));
                                    
                                    std::ostringstream v_knots_buffer;
                                    std::copy((*patch)->v_knots.begin(), (*patch)->v_knots.end(), std::ostream_iterator<double>(v_knots_buffer, " "));
                                    xml_patch.Append(sdpxml::Element("vknotvector", v_knots_buffer.str()));
                                    
                                    std::ostringstream points_buffer;
                                    std::ostringstream weights_buffer;
                                    for(k3d::nupatch::control_points_t::const_iterator control_point = (*patch)->control_points.begin(); control_point != (*patch)->control_points.end(); ++control_point)
                                          {
                                                points_buffer << point_map[control_point->position] << " ";
                                                weights_buffer << control_point->weight << " ";
                                          }
                                          
                                    xml_patch.Append(sdpxml::Element("controlpoints", points_buffer.str()));
                                    xml_patch.Append(sdpxml::Element("weights", weights_buffer.str()));
                              }
                  }
      }

      k3d::iplugin_factory& factory()
      {
            return get_factory();
      }

      static k3d::iplugin_factory& get_factory()
      {
            static k3d::plugin_factory<
                  k3d::document_plugin<frozen_mesh_implementation>,
                  k3d::interface_list<k3d::imesh_source,
                  k3d::interface_list<k3d::imesh_sink > > > factory(
                  k3d::classes::FrozenMesh(),
                  "FrozenMesh",
                  "Freezes its input for manual editing",
                  "Objects",
                  k3d::iplugin_factory::STABLE);

            return factory;
      }
};

/////////////////////////////////////////////////////////////////////////////
// frozen_mesh_factory

k3d::iplugin_factory& frozen_mesh_factory()
{
      return frozen_mesh_implementation::get_factory();
}

} // namespace libk3dmesh


Generated by  Doxygen 1.6.0   Back to index