Logo Search packages:      
Sourcecode: k3d version File versions

renderman.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
            \brief Implements the k3d::ri::render class, which provides a default implementation of k3d::ri::irender
            \author Tim Shead (tshead@k-3d.com)
            \author Romain Behar (romainbehar@yahoo.com)
*/

#include "algebra.h"
#include "imaterial.h"
#include "mesh.h"
#include "renderman.h"
#include "vectors.h"

#include <boost/array.hpp>

#include <iostream>
#include <numeric>
#include <set>

namespace boost
{

std::ostream& operator<<(std::ostream& Stream, const array<double, 16>& RHS)
{
      std::copy(RHS.begin(), RHS.end(), std::ostream_iterator<double>(Stream, " "));
      return Stream;
}

} // namespace boost

namespace
{

long& indentation_storage(std::ios& Stream)
{
      static const int index = std::ios::xalloc();
      return Stream.iword(index);
}

std::ostream& reset_indentation(std::ostream& Stream)
{
      indentation_storage(Stream) = 0;
      return Stream;
}

std::ostream& push_indent(std::ostream& Stream)
{
      indentation_storage(Stream)++;
      return Stream;
}

std::ostream& pop_indent(std::ostream& Stream)
{
      long& indent = indentation_storage(Stream);
      indent -= (indent > 0);
      return Stream;
}

std::ostream& indentation(std::ostream& Stream)
{
      const long& indent = indentation_storage(Stream);
      for(long i = 0; i < indent; i++)
            Stream << "   ";

      return Stream;
}

long& inline_types_storage(std::ios& Stream)
{
      static const int index = std::ios_base::xalloc();
      return Stream.iword(index);
}

bool inline_types(std::ostream& Stream)
{
      return inline_types_storage(Stream);
}

bool set_inline_types(std::ostream& Stream, const bool Enabled)
{
      bool old_state = inline_types_storage(Stream);

      inline_types_storage(Stream) = Enabled;

      return old_state;
}

/// Formats a string with real-quotes for inclusion in a RIB file; designed to be used as an inline formatting object
class format_string
{
public:
      explicit format_string(const k3d::ri::string& Token) :
            token(Token)
      {
      }

      friend std::ostream& operator<<(std::ostream& Stream, const format_string& RHS)
      {
            Stream << "\"" << RHS.token << "\"";
            return Stream;
      }

private:
      const k3d::ri::string& token;
};

/// Encapsulates a RenderMan RIB parameter type
struct predefined_type
{
      explicit predefined_type(const k3d::ri::parameter& Parameter) :
            storage_class(Parameter.storage_class),
            name(Parameter.name),
            type(Parameter.value.type()),
            array_dimension(Parameter.array_dimension)
      {
      }

      explicit predefined_type(const k3d::ri::storage_class_t StorageClass, const k3d::ri::string& Name, const std::type_info& Type, const k3d::ri::unsigned_integer ArrayDimension) :
            storage_class(StorageClass),
            name(Name),
            type(Type),
            array_dimension(ArrayDimension)
      {
      }

      friend bool operator<(const predefined_type& LHS, const predefined_type& RHS)
      {
            if(LHS.storage_class != RHS.storage_class)
                  return LHS.storage_class < RHS.storage_class;

            if(LHS.array_dimension != RHS.array_dimension)
                  return LHS.array_dimension < RHS.array_dimension;

            if(LHS.type != RHS.type)
                  return LHS.type.before(RHS.type);

            return LHS.name < RHS.name;
      }

      k3d::ri::storage_class_t storage_class;
      const k3d::ri::string name;
      const std::type_info& type;
      const k3d::ri::unsigned_integer array_dimension;
};

/// A collection of RenderMan RIB parameter types
00165 typedef std::set<predefined_type> predefined_types_t;

/// Returns the set of standard predefined RIB parameter types
00168 predefined_types_t& predefined_types()
{
      static predefined_types_t types;
      if(types.empty())
            {
                  types.insert(predefined_type(k3d::ri::VERTEX, "P", typeid(k3d::ri::point), 1));
                  types.insert(predefined_type(k3d::ri::VERTEX, "P", typeid(k3d::ri::points), 1));
                  types.insert(predefined_type(k3d::ri::VERTEX, "Pz", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::VERTEX, "Pz", typeid(k3d::ri::reals), 1));
                  types.insert(predefined_type(k3d::ri::VERTEX, "Pw", typeid(k3d::ri::hpoint), 1));
                  types.insert(predefined_type(k3d::ri::VERTEX, "Pw", typeid(k3d::ri::hpoints), 1));

                  types.insert(predefined_type(k3d::ri::VARYING, "N", typeid(k3d::ri::normal), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "N", typeid(k3d::ri::normals), 1));

                  types.insert(predefined_type(k3d::ri::VARYING, "Cs", typeid(k3d::ri::color), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "Cs", typeid(k3d::ri::colors), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "Os", typeid(k3d::ri::color), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "Os", typeid(k3d::ri::colors), 1));

                  types.insert(predefined_type(k3d::ri::VARYING, "s", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "s", typeid(k3d::ri::reals), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "t", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "t", typeid(k3d::ri::reals), 1));

                  types.insert(predefined_type(k3d::ri::VARYING, "blur", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "blur", typeid(k3d::ri::reals), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "sblur", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "sblur", typeid(k3d::ri::reals), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "tblur", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::VARYING, "tblur", typeid(k3d::ri::reals), 1));

                  types.insert(predefined_type(k3d::ri::UNIFORM, "width", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "width", typeid(k3d::ri::reals), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "swidth", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "swidth", typeid(k3d::ri::reals), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "twidth", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "twidth", typeid(k3d::ri::reals), 1));

                  types.insert(predefined_type(k3d::ri::UNIFORM, "filter", typeid(k3d::ri::string), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "filter", typeid(k3d::ri::strings), 1));

                  types.insert(predefined_type(k3d::ri::UNIFORM, "fill", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "fill", typeid(k3d::ri::reals), 1));

                  types.insert(predefined_type(k3d::ri::UNIFORM, "fov", typeid(k3d::ri::real), 1));
                  types.insert(predefined_type(k3d::ri::UNIFORM, "fov", typeid(k3d::ri::reals), 1));

                  types.insert(predefined_type(k3d::ri::UNIFORM, "shader", typeid(k3d::ri::string), 1));
            }

      return types;
}

/// Formats a parameter name for inclusion in a RIB file
class format_parameter_name
{
public:
      explicit format_parameter_name(const k3d::ri::parameter& Parameter) :
            parameter(Parameter)
      {
      }

      friend std::ostream& operator<<(std::ostream& Stream, const format_parameter_name& RHS)
      {
            Stream << "\"";

            // Only generate type information if inlining is enabled ...
            if(inline_types(Stream))
                  {
                        // Only generate type information if this type isn't already predefined ...
                        if(!predefined_types().count(predefined_type(RHS.parameter)))
                              {
                                    Stream << RHS.parameter.storage_class << " ";

                                    const std::type_info& type = RHS.parameter.value.type();

                                    if(RHS.parameter.value.empty())
                                          {
                                                Stream << "unknown ";
                                                std::cerr << __PRETTY_FUNCTION__ << ": cannot deduce type for empty parameter" << std::endl;
                                          }
                                    else if(typeid(k3d::ri::integer) == type || typeid(k3d::ri::integers) == type)
                                          {
                                                Stream << "integer";
                                          }
                                    else if(typeid(k3d::ri::real) == type || typeid(k3d::ri::reals) == type)
                                          {
                                                Stream << "float";
                                          }
                                    else if(typeid(k3d::ri::string) == type || typeid(k3d::ri::strings) == type)
                                          {
                                                Stream << "string";
                                          }
                                    else if(typeid(k3d::ri::point) == type || typeid(k3d::ri::points) == type)
                                          {
                                                Stream << "point";
                                          }
                                    else if(typeid(k3d::ri::vector) == type || typeid(k3d::ri::vectors) == type)
                                          {
                                                Stream << "vector";
                                          }
                                    else if(typeid(k3d::ri::normal) == type || typeid(k3d::ri::normals) == type)
                                          {
                                                Stream << "normal";
                                          }
                                    else if(typeid(k3d::ri::color) == type || typeid(k3d::ri::colors) == type)
                                          {
                                                Stream << "color";
                                          }
                                    else if(typeid(k3d::ri::hpoint) == type || typeid(k3d::ri::hpoints) == type)
                                          {
                                                Stream << "hpoint";
                                          }
                                    else if(typeid(k3d::ri::matrix) == type || typeid(k3d::ri::matrices) == type)
                                          {
                                                Stream << "matrix";
                                          }
                                    else
                                          {
                                                Stream << "unknown";
                                                std::cerr << __PRETTY_FUNCTION__ << ": cannot deduce parameter type for [" << RHS.parameter.name << "]" << std::endl;
                                          }

                                    if(RHS.parameter.array_dimension > 1)
                                          Stream << "[" << RHS.parameter.array_dimension << "]";

                                    Stream << " ";
                              }
                  }

            Stream << RHS.parameter.name;

            Stream << "\"";

            return Stream;
      }

private:
      const k3d::ri::parameter& parameter;
};

/// Formats an array of values within square brackets for inclusion in a RIB file; designed to be used as an inline formatting object
template<typename iterator_t, typename value_t>
class format_array_t
{
public:
      format_array_t(const iterator_t Begin, const iterator_t End) :
            begin(Begin),
            end(End)
      {
      }

      friend std::ostream& operator << (std::ostream& Stream, const format_array_t& RHS)
      {
            Stream << "[ ";
            std::copy(RHS.begin, RHS.end, std::ostream_iterator<value_t>(Stream, " "));
            Stream << "]";

            return Stream;
      }

private:
      const iterator_t begin;
      const iterator_t end;
};

/// Partial specialization of format_array_t for use with string values
template<typename iterator_t>
class format_array_t<iterator_t, k3d::ri::string>
{
public:
      format_array_t(const iterator_t Begin, const iterator_t End) :
            begin(Begin),
            end(End)
      {
      }

      friend std::ostream& operator << (std::ostream& Stream, const format_array_t& RHS)
      {
            Stream << "[ ";
            for(iterator_t element = RHS.begin; element != RHS.end; ++element)
                  Stream << format_string(*element) << " ";
            Stream << "]";

            return Stream;
      }

private:
      const iterator_t begin;
      const iterator_t end;
};

/// Convenience factory function for creating format_array_t objects
template<typename iterator_t>
00363 format_array_t<iterator_t, typename std::iterator_traits<iterator_t>::value_type> format_array(const iterator_t Begin, const iterator_t End)
{
      return format_array_t<iterator_t, typename std::iterator_traits<iterator_t>::value_type>(Begin, End);
}

} // namespace

namespace k3d
{

namespace ri
{

std::ostream& operator<<(std::ostream& Stream, const storage_class_t RHS)
{
      switch(RHS)
            {
                  case k3d::ri::CONSTANT:
                        Stream << "constant";
                        break;
                  case k3d::ri::UNIFORM:
                        Stream << "uniform";
                        break;
                  case k3d::ri::VARYING:
                        Stream << "varying";
                        break;
                  case k3d::ri::VERTEX:
                        Stream << "vertex";
                        break;
                  case k3d::ri::FACEVARYING:
                        Stream << "facevarying";
                        break;
                  default:
                        assert_not_reached();
            }

      return Stream;
}

std::ostream& operator<<(std::ostream& Stream, const parameter& RHS)
{
      Stream << format_parameter_name(RHS) << " ";

      if(RHS.value.empty())
            {
                  Stream << "[ ]";
            }
      else if(typeid(integer) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<integer>(RHS.value) << " ]";
            }
      else if(typeid(real) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<real>(RHS.value) << " ]";
            }
      else if(typeid(string) == RHS.value.type())
            {
                  Stream << "[ " << format_string(boost::any_cast<string>(RHS.value)) << " ]";
            }
      else if(typeid(point) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<point>(RHS.value) << " ]";
            }
      else if(typeid(vector) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<vector>(RHS.value) << " ]";
            }
      else if(typeid(normal) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<normal>(RHS.value) << " ]";
            }
      else if(typeid(color) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<color>(RHS.value) << " ]";
            }
      else if(typeid(hpoint) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<hpoint>(RHS.value) << " ]";
            }
      else if(typeid(matrix) == RHS.value.type())
            {
                  Stream << "[ " << boost::any_cast<matrix>(RHS.value) << " ]";
            }
      else if(typeid(integers) == RHS.value.type())
            {
                  const integers* const p = boost::any_cast<integers>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(reals) == RHS.value.type())
            {
                  const reals* const p = boost::any_cast<reals>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(strings) == RHS.value.type())
            {
                  const strings* const p = boost::any_cast<strings>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(points) == RHS.value.type())
            {
                  const points* const p = boost::any_cast<points>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(vectors) == RHS.value.type())
            {
                  const vectors* const p = boost::any_cast<vectors>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(normals) == RHS.value.type())
            {
                  const normals* const p = boost::any_cast<normals>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(colors) == RHS.value.type())
            {
                  const colors* const p = boost::any_cast<colors>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(hpoints) == RHS.value.type())
            {
                  const hpoints* const p = boost::any_cast<hpoints>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else if(typeid(matrices) == RHS.value.type())
            {
                  const matrices* const p = boost::any_cast<matrices>(&RHS.value);
                  Stream << format_array(p->begin(), p->end());
            }
      else
            {
                  Stream << "[ ]";
                  std::cerr << __PRETTY_FUNCTION__ << ": unknown parameter type for [" << RHS.name << "] will not be serialized" << std::endl;
            }

      return Stream;
}

std::ostream& operator<<(std::ostream& Stream, const parameter_list& RHS)
{
      std::copy(RHS.begin(), RHS.end(), std::ostream_iterator<parameter>(Stream, " "));
      return Stream;
}

/////////////////////////////////////////////////////////////////////////////
// motion_begin

00509 void motion_begin(const render_state& State)
{
      if(motion_blur(State))
            State.engine.RiMotionBeginV(State.sample_times);
}

/////////////////////////////////////////////////////////////////////////////
// motion_end

00518 void motion_end(const render_state& State)
{
      if(motion_blur(State))
            State.engine.RiMotionEnd();
}

/////////////////////////////////////////////////////////////////////////////
// motion_blur

00527 bool motion_blur(const render_state& State)
{
      return State.sample_times.size() > 1;
}

/////////////////////////////////////////////////////////////////////////////
// first_sample

00535 bool first_sample(const render_state& State)
{
      return 0 == State.sample_index;
}

/////////////////////////////////////////////////////////////////////////////
// last_sample

00543 bool last_sample(const render_state& State)
{
      return State.sample_index == State.sample_times.size() - 1;
}

/////////////////////////////////////////////////////////////////////////////
// convert

00551 const matrix convert(const k3d::matrix4& Matrix)
{
      matrix result;

      k3d::matrix4 temp(Matrix.Transpose());
      real* const m = temp;
      std::copy(m, m+16, result.begin());

      return result;
}

/////////////////////////////////////////////////////////////////////////////
// setup_material

void setup_material(iunknown* const Material, const render_state& State)
{
      k3d::ri::imaterial* const material = dynamic_cast<k3d::ri::imaterial*>(Material);
      if(material)
            {
                  material->setup_renderman_material(State);
            }
      else
            {
                  // We only generate RIB on the final sample ...
                  if(!last_sample(State))
                        return;

                  State.engine.RiSurfaceV("null");
            }
}

namespace detail
{

class same_type
{
public:
      same_type(const std::type_info& Type) :
            m_type(Type)
      {
      }

      bool operator()(const boost::any& Value)
      {
            return Value.type() == m_type;
      }

private:
      const std::type_info& m_type;
};

typedef std::vector<boost::any> values_t;

typedef std::map<std::string, values_t> grouped_parameters_t;

template<typename data_t, typename container_t>
const container_t build_array(const values_t& Values)
{
      container_t result;

      for(values_t::const_iterator value = Values.begin(); value != Values.end(); ++value)
            result.push_back(boost::any_cast<data_t>(*value));

      return result;
}

k3d::ri::parameter_list build_parameters(const grouped_parameters_t& Parameters, const k3d::ri::storage_class_t StorageClass)
{
      k3d::ri::parameter_list results;

      // For each group of values ...
      for(grouped_parameters_t::const_iterator group = Parameters.begin(); group != Parameters.end(); ++group)
            {
                  // Get some information about the group ...
                  const std::string& name = group->first;
                  const values_t& values = group->second;
                  const std::type_info& type = values.front().type();

                  // Check to see that all values have the same type; if not, skip the group ...
                  if(values.size() != static_cast<size_t>(std::count_if(values.begin(), values.end(), same_type(type))))
                        {
                              std::cerr << __PRETTY_FUNCTION__ << ": parameter [" << name << "] contains multiple types and will be ignored" << std::endl;
                              continue;
                        }

                  // OK, everything looks good so let's turn the group into a set of parameters ...
                  if(typeid(k3d::ri::integer) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::integer, k3d::ri::integers>(values)));
                        }
                  else if(typeid(k3d::ri::real) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::real, k3d::ri::reals>(values)));
                        }
                  else if(typeid(k3d::ri::string) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::string, k3d::ri::strings>(values)));
                        }
                  else if(typeid(k3d::ri::point) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::point, k3d::ri::points>(values)));
                        }
                  else if(typeid(k3d::ri::vector) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::vector, k3d::ri::vectors>(values)));
                        }
                  else if(typeid(k3d::ri::normal) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::normal, k3d::ri::normals>(values)));
                        }
                  else if(typeid(k3d::ri::color) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::color, k3d::ri::colors>(values)));
                        }
                  else if(typeid(k3d::ri::hpoint) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::hpoint, k3d::ri::hpoints>(values)));
                        }
                  else if(typeid(k3d::ri::matrix) == type)
                        {
                              results.push_back(k3d::ri::parameter(name, StorageClass, build_array<k3d::ri::matrix, k3d::ri::matrices>(values)));
                        }
                  else
                        {
                              std::cerr << __PRETTY_FUNCTION__ << ": cannot deduce parameter type for [" << name << "]" << std::endl;
                        }
            }

      return results;
}

void build_tags(const k3d::parameters_t::const_iterator Begin, const k3d::parameters_t::const_iterator& End, k3d::ri::strings& Tags, k3d::ri::unsigned_integers& TagCounts, k3d::ri::integers& TagIntegers, k3d::ri::reals& TagReals)
{

      for(k3d::parameters_t::const_iterator tag = Begin; tag != End; ++tag)
            {
                  if(tag->first == "interpolateboundary" && (tag->second.type() == typeid(bool)))
                        {
                              if(boost::any_cast<bool>(tag->second))
                                    {
                                          Tags.push_back("interpolateboundary");
                                          TagCounts.push_back(0);
                                          TagCounts.push_back(0);
                                          continue;
                                    }
                        }

                  std::cerr << warning << "Unknown or incorrectly typed tag [" << tag->first << "] will be ignored" << std::endl;
            }
}

void build_tags(const k3d::polyhedron::faces_t::const_iterator Begin, const k3d::polyhedron::faces_t::const_iterator& End, std::map<k3d::face*, k3d::ri::unsigned_integer>& FaceMap, k3d::ri::strings& Tags, k3d::ri::unsigned_integers& TagCounts, k3d::ri::integers& TagIntegers, k3d::ri::reals& TagReals)
{
      for(k3d::polyhedron::faces_t::const_iterator face = Begin; face != End; ++face)
            {
                  for(k3d::parameters_t::const_iterator tag = (*face)->tags.begin(); tag != (*face)->tags.end(); ++tag)
                        {
                              if(tag->first == "hole" && (tag->second.type() == typeid(bool)))
                                    {
                                          if(boost::any_cast<bool>(tag->second))
                                                {
                                                      Tags.push_back("hole");
                                                      TagCounts.push_back(1);
                                                      TagCounts.push_back(0);
                                                      TagIntegers.push_back(FaceMap[*face]);
                                                      continue;
                                                }
                                    }

                              std::cerr << warning << "Unknown or incorrectly typed face tag [" << tag->first << "] will be ignored" << std::endl;
                        }
            }
}

void build_tags(const k3d::polyhedron::edges_t::const_iterator Begin, const k3d::polyhedron::edges_t::const_iterator& End, std::map<k3d::point*, k3d::ri::unsigned_integer>& PointMap, k3d::ri::strings& Tags, k3d::ri::unsigned_integers& TagCounts, k3d::ri::integers& TagIntegers, k3d::ri::reals& TagReals)
{
      // First, get the set of all "joined" edges (i.e. eliminate companions)
      typedef std::set<k3d::split_edge*> joined_edges_t;
      joined_edges_t joined_edges;
      for(k3d::polyhedron::edges_t::const_iterator e = Begin; e != End; ++e)
            joined_edges.insert(std::max((*e), (*e)->companion));
      joined_edges.erase(0);

      for(joined_edges_t::const_iterator e = joined_edges.begin(); e != joined_edges.end(); ++e)
            {
                  k3d::split_edge& edge = **e;

                  for(k3d::parameters_t::const_iterator tag = edge.tags.begin(); tag != edge.tags.end(); ++tag)
                        {
                              if(tag->first == "crease" && (tag->second.type() == typeid(k3d::ri::real)) && edge.vertex && edge.face_clockwise && edge.face_clockwise->vertex)
                                    {
                                          Tags.push_back("crease");
                                          TagCounts.push_back(2);
                                          TagCounts.push_back(1);
                                          TagIntegers.push_back(PointMap[edge.vertex]);
                                          TagIntegers.push_back(PointMap[edge.face_clockwise->vertex]);
                                          TagReals.push_back(boost::any_cast<k3d::ri::real>(tag->second));
                                          continue;
                                    }

                              std::cerr << warning << "Unknown or incorrectly typed edge tag [" << tag->first << "] will be ignored" << std::endl;
                        }
            }
}

void build_tags(const std::vector<k3d::point*>::const_iterator Begin, const std::vector<k3d::point*>::const_iterator End, std::map<k3d::point*, k3d::ri::unsigned_integer>& PointMap, k3d::ri::strings& Tags, k3d::ri::unsigned_integers& TagCounts, k3d::ri::integers& TagIntegers, k3d::ri::reals& TagReals)
{
      for(std::vector<k3d::point*>::const_iterator point = Begin; point != End; ++point)
            {
                  for(k3d::parameters_t::const_iterator tag = (*point)->tags.begin(); tag != (*point)->tags.end(); ++tag)
                        {
                              if(tag->first == "corner" && (tag->second.type() == typeid(k3d::ri::real)))
                                    {
                                          Tags.push_back("corner");
                                          TagCounts.push_back(1);
                                          TagCounts.push_back(1);
                                          TagIntegers.push_back(PointMap[*point]);
                                          TagReals.push_back(boost::any_cast<k3d::ri::real>(tag->second));
                                          continue;
                                    }

                              std::cerr << warning << "Unknown or incorrectly-typed point tag [" << tag->first << "] will be ignored" << std::endl;
                        }
            }
}

k3d::ri::parameter_list build_parameters(const k3d::parameters_t::const_iterator& Begin, const k3d::parameters_t::const_iterator& End, const k3d::ri::storage_class_t StorageClass)
{
      grouped_parameters_t grouped_parameters;

      for(k3d::parameters_t::const_iterator parameter = Begin; parameter != End; ++parameter)
            grouped_parameters[parameter->first].push_back(parameter->second);

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(const boost::array<k3d::parameters_t, 4>::const_iterator& Begin, const boost::array<k3d::parameters_t, 4>::const_iterator& End, const k3d::ri::storage_class_t StorageClass)
{
      grouped_parameters_t grouped_parameters;

      for(boost::array<k3d::parameters_t, 4>::const_iterator parameters = Begin; parameters != End; ++parameters)
            {
                  for(k3d::parameters_t::const_iterator parameter = parameters->begin(); parameter != parameters->end(); ++parameter)
                        grouped_parameters[parameter->first].push_back(parameter->second);
            }

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(k3d::point** Begin, k3d::point** End, const k3d::ri::storage_class_t StorageClass)
{
      // Sanity check ...
      assert(k3d::ri::VERTEX == StorageClass);

      grouped_parameters_t grouped_parameters;

      for(k3d::point** point = Begin; point != End; ++point)
            {
                  for(k3d::parameters_t::const_iterator parameter = (*point)->vertex_data.begin(); parameter != (*point)->vertex_data.end(); ++parameter)
                        grouped_parameters[parameter->first].push_back(parameter->second);
            }

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(const std::vector<k3d::point*>::const_iterator Begin, const std::vector<k3d::point*>::const_iterator End, const k3d::ri::storage_class_t StorageClass)
{
      // Sanity check ...
      assert(k3d::ri::VERTEX == StorageClass);

      grouped_parameters_t grouped_parameters;

      for(std::vector<k3d::point*>::const_iterator point = Begin; point != End; ++point)
            {
                  for(k3d::parameters_t::const_iterator parameter = (*point)->vertex_data.begin(); parameter != (*point)->vertex_data.end(); ++parameter)
                        grouped_parameters[parameter->first].push_back(parameter->second);
            }

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(const std::vector<k3d::split_edge*>::const_iterator Begin, const std::vector<k3d::split_edge*>::const_iterator End, const k3d::ri::storage_class_t StorageClass)
{
      // Sanity check ...
      assert(k3d::ri::FACEVARYING == StorageClass);

      grouped_parameters_t grouped_parameters;

      for(std::vector<k3d::split_edge*>::const_iterator edge = Begin; edge != End; ++edge)
            {
                  for(k3d::parameters_t::const_iterator parameter = (*edge)->facevarying_data.begin(); parameter != (*edge)->facevarying_data.end(); ++parameter)
                        grouped_parameters[parameter->first].push_back(parameter->second);
            }

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(const k3d::polyhedron::faces_t::const_iterator Begin, const k3d::polyhedron::faces_t::const_iterator End, const k3d::ri::storage_class_t StorageClass)
{
      // Sanity check ...
      assert(k3d::ri::UNIFORM == StorageClass);

      grouped_parameters_t grouped_parameters;

      for(k3d::polyhedron::faces_t::const_iterator face = Begin; face != End; ++face)
            {
                  for(k3d::parameters_t::const_iterator parameter = (*face)->uniform_data.begin(); parameter != (*face)->uniform_data.end(); ++parameter)
                        grouped_parameters[parameter->first].push_back(parameter->second);
            }

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(const k3d::linear_curve_group::curves_t::const_iterator Begin, const k3d::linear_curve_group::curves_t::const_iterator End, const k3d::ri::storage_class_t StorageClass)
{
      grouped_parameters_t grouped_parameters;

      if(k3d::ri::UNIFORM == StorageClass)
            {
                  for(k3d::linear_curve_group::curves_t::const_iterator curve = Begin; curve != End; ++curve)
                        {
                              for(k3d::parameters_t::const_iterator parameter = (*curve)->uniform_data.begin(); parameter != (*curve)->uniform_data.end(); ++parameter)
                                    grouped_parameters[parameter->first].push_back(parameter->second);
                        }
            }
      else if(k3d::ri::VARYING == StorageClass)
            {
                  for(k3d::linear_curve_group::curves_t::const_iterator curve = Begin; curve != End; ++curve)
                        {
                              for(k3d::linear_curve::varying_t::const_iterator varying_data = (*curve)->varying_data.begin(); varying_data != (*curve)->varying_data.end(); ++varying_data)
                                    {
                                          for(k3d::parameters_t::const_iterator parameter = varying_data->begin(); parameter != varying_data->end(); ++parameter)
                                                grouped_parameters[parameter->first].push_back(parameter->second);
                                    }
                        }
            }

      return build_parameters(grouped_parameters, StorageClass);
}

k3d::ri::parameter_list build_parameters(const k3d::cubic_curve_group::curves_t::const_iterator Begin, const k3d::cubic_curve_group::curves_t::const_iterator End, const k3d::ri::storage_class_t StorageClass)
{
      grouped_parameters_t grouped_parameters;

      if(k3d::ri::UNIFORM == StorageClass)
            {
                  for(k3d::cubic_curve_group::curves_t::const_iterator curve = Begin; curve != End; ++curve)
                        {
                              for(k3d::parameters_t::const_iterator parameter = (*curve)->uniform_data.begin(); parameter != (*curve)->uniform_data.end(); ++parameter)
                                    grouped_parameters[parameter->first].push_back(parameter->second);
                        }
            }
      else if(k3d::ri::VARYING == StorageClass)
            {
                  for(k3d::cubic_curve_group::curves_t::const_iterator curve = Begin; curve != End; ++curve)
                        {
                              for(k3d::cubic_curve::varying_t::const_iterator varying_data = (*curve)->varying_data.begin(); varying_data != (*curve)->varying_data.end(); ++varying_data)
                                    {
                                          for(k3d::parameters_t::const_iterator parameter = varying_data->begin(); parameter != varying_data->end(); ++parameter)
                                                grouped_parameters[parameter->first].push_back(parameter->second);
                                    }
                        }
            }

      return build_parameters(grouped_parameters, StorageClass);
}

// RiBlobby

void push_matrix(const k3d::matrix4& Matrix, reals& Floats)
{
      const matrix m = convert(Matrix);
      for(matrix::const_iterator v = m.begin(); v != m.end(); v++)
            Floats.push_back(*v);
}

void push_vector3(const k3d::vector3& Vector, reals& Floats)
{
      Floats.push_back(Vector[0]);
      Floats.push_back(Vector[1]);
      Floats.push_back(Vector[2]);
}

/// Blobby virtual machine - builds the RiBlobby arrays
00935 class blobby_vm :
      private k3d::blobby::visitor
{
public:
      blobby_vm(k3d::blobby& Blobby, unsigned_integer& NLeaf, unsigned_integers& Codes, reals& Floats, strings& Strings, grouped_parameters_t& Parameters) :
            nleaf(NLeaf),
            codes(Codes),
            floats(Floats),
            names(Strings),
            grouped_parameters(Parameters)
      {
            m_opcode_id = 0;
            Blobby.accept(*this);
      }

      virtual ~blobby_vm() {}

private:
      void visit_constant(k3d::blobby::constant& Constant)
      {
            codes.push_back(1000);
            codes.push_back(floats.size());
            floats.push_back(Constant.value);

            m_opcodes.push(m_opcode_id++);
            nleaf++;
      }

      void visit_ellipsoid(k3d::blobby::ellipsoid& Ellipsoid)
      {
            codes.push_back(1001);
            codes.push_back(floats.size());

            // Output matrix ...
            push_matrix(k3d::translation3D(Ellipsoid.origin->position) * Ellipsoid.transformation, floats);

            // Save parameters ...
            for(parameters_t::const_iterator parameter = Ellipsoid.vertex_data.begin(); parameter != Ellipsoid.vertex_data.end(); parameter++)
                  grouped_parameters[parameter->first].push_back(parameter->second);

            m_opcodes.push(m_opcode_id++);
            nleaf++;
      }

      void visit_segment(k3d::blobby::segment& Segment)
      {
            codes.push_back(1002);
            codes.push_back(floats.size());

            // Output parameters ...
            push_vector3(Segment.start->position, floats);
            push_vector3(Segment.end->position, floats);
            floats.push_back(Segment.radius);
            push_matrix(Segment.transformation, floats);

            // Save extra parameters ...
            for(parameters_t::const_iterator parameter = Segment.vertex_data.begin(); parameter != Segment.vertex_data.end(); parameter++)
                  grouped_parameters[parameter->first].push_back(parameter->second);

            m_opcodes.push(m_opcode_id++);
            nleaf++;
      }

      void visit_subtract(k3d::blobby::subtract& Subtract)
      {
            // Note - order matters, here !
            Subtract.subtrahend->accept(*this);
            Subtract.minuend->accept(*this);

            codes.push_back(4);
            unsigned_integer opcode2 = m_opcodes.top();
            m_opcodes.pop();
            unsigned_integer opcode1 = m_opcodes.top();
            m_opcodes.pop();

            codes.push_back(opcode1);
            codes.push_back(opcode2);

            m_opcodes.push(m_opcode_id++);
      }

      void visit_divide(k3d::blobby::divide& Divide)
      {
            // Note - order matters, here !
            Divide.dividend->accept(*this);
            Divide.divisor->accept(*this);

            codes.push_back(5);
            unsigned_integer opcode2 = m_opcodes.top();
            m_opcodes.pop();
            unsigned_integer opcode1 = m_opcodes.top();
            m_opcodes.pop();

            codes.push_back(opcode1);
            codes.push_back(opcode2);

            m_opcodes.push(m_opcode_id++);
      }

      void visit_add(k3d::blobby::add& Add)
      {
            Add.operands_accept(*this);

            codes.push_back(0);
            codes.push_back(Add.operands.size());

            for(unsigned long n = 0; n < Add.operands.size(); ++n)
                  {
                        codes.push_back(m_opcodes.top());
                        m_opcodes.pop();
                  }

            m_opcodes.push(m_opcode_id++);
      }

      void visit_multiply(k3d::blobby::multiply& Multiply)
      {
            Multiply.operands_accept(*this);

            codes.push_back(1);
            codes.push_back(Multiply.operands.size());

            for(unsigned long n = 0; n < Multiply.operands.size(); n++)
                  {
                        codes.push_back(m_opcodes.top());
                        m_opcodes.pop();
                  }

            m_opcodes.push(m_opcode_id++);
      }

      void visit_max(k3d::blobby::max& Max)
      {
            Max.operands_accept(*this);

            codes.push_back(2);
            codes.push_back(Max.operands.size());

            for(unsigned long n = 0; n < Max.operands.size(); n++)
                  {
                        codes.push_back(m_opcodes.top());
                        m_opcodes.pop();
                  }

            m_opcodes.push(m_opcode_id++);
      }

      void visit_min(k3d::blobby::min& Min)
      {
            Min.operands_accept(*this);

            codes.push_back(3);
            codes.push_back(Min.operands.size());

            for(unsigned long n = 0; n < Min.operands.size(); n++)
                  {
                        codes.push_back(m_opcodes.top());
                        m_opcodes.pop();
                  }

            m_opcodes.push(m_opcode_id++);
      }

      std::stack<unsigned long> m_opcodes;
      unsigned long m_opcode_id;

      unsigned_integer& nleaf;
      unsigned_integers& codes;
      reals& floats;
      strings& names;
      grouped_parameters_t& grouped_parameters;
};

} // namespace detail

/////////////////////////////////////////////////////////////////////////////
// render

void render(const k3d::mesh& Mesh, const render_state& State)
{
      // For each point cloud in the mesh ...
      for(k3d::mesh::point_groups_t::const_iterator point_group = Mesh.point_groups.begin(); point_group != Mesh.point_groups.end(); ++point_group)
            {
                  // Set the point cloud material ...
                  k3d::ri::setup_material((*point_group)->material, State);

                  // Setup point cloud parameters ...
                  k3d::ri::parameter_list parameters;

                  // Setup constant parameters ...
                  parameters += detail::build_parameters((*point_group)->constant_data.begin(), (*point_group)->constant_data.end(), k3d::ri::CONSTANT);

                  // Setup vertex parameters ...
                  parameters += detail::build_parameters((*point_group)->points.begin(), (*point_group)->points.end(), k3d::ri::VERTEX);

                  // Setup points ...
                  k3d::ri::points points;
                  for(k3d::point_group::points_t::const_iterator point = (*point_group)->points.begin(); point != (*point_group)->points.end(); ++point)
                        points.push_back((*point)->position);
                  parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, points));

                  State.engine.RiPointsV(points.size(), parameters);
            }

      // For each polyhedron in the mesh ...
      for(k3d::mesh::polyhedra_t::const_iterator polyhedron = Mesh.polyhedra.begin(); polyhedron != Mesh.polyhedra.end(); ++polyhedron)
            {
                  // Set the polyhedron material ...
                  k3d::ri::setup_material((*polyhedron)->material, State);

                  /// Render as regular-ole' polygons
                  if(k3d::polyhedron::POLYGONS == (*polyhedron)->type)
                        {
                              // Setup geometry ...
                              k3d::ri::unsigned_integers loop_counts;
                              k3d::ri::unsigned_integers vertex_counts;
                              k3d::ri::unsigned_integers vertex_ids;
                              k3d::ri::points ripoints;

                              std::vector<k3d::point*> points;
                              std::vector<k3d::split_edge*> edges;
                              std::map<k3d::point*, k3d::ri::unsigned_integer> point_map;

                              // For each polygon face ...
                              for(k3d::polyhedron::faces_t::const_iterator face = (*polyhedron)->faces.begin(); face != (*polyhedron)->faces.end(); ++face)
                                    {
                                          // List vertices for the face ...
                                          k3d::ri::unsigned_integer vertex_count = 0;
                                          for(k3d::split_edge* edge = (*face)->first_edge; edge; edge = edge->face_clockwise)
                                                {
                                                      ++vertex_count;

                                                      edges.push_back(edge);

                                                      if(!point_map.count(edge->vertex))
                                                            {
                                                                  point_map.insert(std::make_pair(edge->vertex, points.size()));
                                                                  points.push_back(edge->vertex);
                                                                  ripoints.push_back(edge->vertex->position);
                                                            }

                                                      vertex_ids.push_back(point_map[edge->vertex]);

                                                      if((*face)->first_edge == edge->face_clockwise)
                                                            break;
                                                }
                                          vertex_counts.push_back(vertex_count);

                                          // For each hole in the face ...
                                          for(k3d::face::holes_t::const_iterator hole = (*face)->holes.begin(); hole != (*face)->holes.end(); ++hole)
                                                {
                                                      // List vertices for the hole ...
                                                      k3d::ri::unsigned_integer vertex_count = 0;
                                                      for(k3d::split_edge* edge = *hole; edge; edge = edge->face_clockwise)
                                                            {
                                                                  ++vertex_count;

                                                                  edges.push_back(edge);

                                                                  if(!point_map.count(edge->vertex))
                                                                        {
                                                                              point_map.insert(std::make_pair(edge->vertex, points.size()));
                                                                              points.push_back(edge->vertex);
                                                                              ripoints.push_back(edge->vertex->position);
                                                                        }

                                                                  vertex_ids.push_back(point_map[edge->vertex]);

                                                                  if(*hole == edge->face_clockwise)
                                                                        break;
                                                            }
                                                      vertex_counts.push_back(vertex_count);
                                                }

                                          // Total number of loops in the face (including holes) ...
                                          loop_counts.push_back(1 + (*face)->holes.size());
                                    }

                              if(loop_counts.size())
                                    {
                                          // Setup the polyhedron parameters ...
                                          k3d::ri::parameter_list parameters;

                                          // Setup constant data ...
                                          parameters += detail::build_parameters((*polyhedron)->constant_data.begin(), (*polyhedron)->constant_data.end(), k3d::ri::CONSTANT);

                                          // Setup uniform data ...
                                          parameters += detail::build_parameters((*polyhedron)->faces.begin(), (*polyhedron)->faces.end(), k3d::ri::UNIFORM);

                                          // Setup vertex data ...
                                          parameters += detail::build_parameters(points.begin(), points.end(), k3d::ri::VERTEX);

                                          // Setup points ...
                                          parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, ripoints));

                                          // Setup facevarying data ...
                                          parameters += detail::build_parameters(edges.begin(), edges.end(), k3d::ri::FACEVARYING);

                                          State.engine.RiPointsGeneralPolygonsV(loop_counts, vertex_counts, vertex_ids, parameters);
                                    }
                        }
                  // Render as a subdivision mesh ...
                  else if(k3d::polyhedron::CATMULL_CLARK_SUBDIVISION_MESH == (*polyhedron)->type)
                        {
                              k3d::ri::unsigned_integers vertex_counts;
                              k3d::ri::unsigned_integers vertex_ids;
                              k3d::ri::points ripoints;

                              std::vector<k3d::point*> points;
                              std::vector<k3d::split_edge*> edges;
                              std::map<k3d::point*, k3d::ri::unsigned_integer> point_map;
                              std::map<k3d::face*, k3d::ri::unsigned_integer> face_map;

                              // For each polygon face ...
                              for(k3d::polyhedron::faces_t::const_iterator face = (*polyhedron)->faces.begin(); face != (*polyhedron)->faces.end(); ++face)
                                    {
                                          face_map.insert(std::make_pair(*face, face_map.size()));

                                          // List vertices for the face ...
                                          k3d::ri::unsigned_integer vertex_count = 0;
                                          for(k3d::split_edge* edge = (*face)->first_edge; edge; edge = edge->face_clockwise)
                                                {
                                                      ++vertex_count;

                                                      edges.push_back(edge);

                                                      if(!point_map.count(edge->vertex))
                                                            {
                                                                  point_map.insert(std::make_pair(edge->vertex, points.size()));
                                                                  points.push_back(edge->vertex);
                                                                  ripoints.push_back(edge->vertex->position);
                                                            }

                                                      vertex_ids.push_back(point_map[edge->vertex]);

                                                      if((*face)->first_edge == edge->face_clockwise)
                                                            break;
                                                }
                                          vertex_counts.push_back(vertex_count);
                                    }

                              // Setup parameters ...
                              k3d::ri::parameter_list parameters;

                              // Setup constant data ...
                              parameters += detail::build_parameters((*polyhedron)->constant_data.begin(), (*polyhedron)->constant_data.end(), k3d::ri::CONSTANT);

                              // Setup uniform data ...
                              parameters += detail::build_parameters((*polyhedron)->faces.begin(), (*polyhedron)->faces.end(), k3d::ri::UNIFORM);

                              // Setup vertex data ...
                              parameters += detail::build_parameters(points.begin(), points.end(), k3d::ri::VERTEX);

                              // Setup points ...
                              parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, ripoints));

                              // Setup facevarying data ...
                              parameters += detail::build_parameters(edges.begin(), edges.end(), k3d::ri::FACEVARYING);

                              // Setup tags ...
                              k3d::ri::strings tags;
                              k3d::ri::unsigned_integers tag_counts;
                              k3d::ri::integers tag_integers;
                              k3d::ri::reals tag_reals;
                              detail::build_tags((*polyhedron)->tags.begin(), (*polyhedron)->tags.end(), tags, tag_counts, tag_integers, tag_reals);
                              detail::build_tags((*polyhedron)->faces.begin(), (*polyhedron)->faces.end(), face_map, tags, tag_counts, tag_integers, tag_reals);
                              detail::build_tags((*polyhedron)->edges.begin(), (*polyhedron)->edges.end(), point_map, tags, tag_counts, tag_integers, tag_reals);
                              detail::build_tags(points.begin(), points.end(), point_map, tags, tag_counts, tag_integers, tag_reals);


                              State.engine.RiSubdivisionMeshV("catmull-clark", vertex_counts, vertex_ids, tags, tag_counts, tag_integers, tag_reals, parameters);
                        }
            }

      // For each linear curve group in the mesh ...
      for(k3d::mesh::linear_curve_groups_t::const_iterator group = Mesh.linear_curve_groups.begin(); group != Mesh.linear_curve_groups.end(); ++group)
            {
                  // Set the group material ...
                  k3d::ri::setup_material((*group)->material, State);

                  // Keep track of curve control points ...
                  std::vector<k3d::point*> points;
                  k3d::ri::points ripoints;
                  k3d::ri::unsigned_integers point_counts;

                  // For each linear curve in the group ...
                  for(k3d::linear_curve_group::curves_t::const_iterator curve = (*group)->curves.begin(); curve != (*group)->curves.end(); ++curve)
                        {
                              for(k3d::linear_curve::control_points_t::const_iterator control_point = (*curve)->control_points.begin(); control_point != (*curve)->control_points.end(); ++control_point)
                                    {
                                          points.push_back(*control_point);
                                          ripoints.push_back((*control_point)->position);
                                    }

                              point_counts.push_back((*curve)->control_points.size());
                        }

                  // Setup group parameters ...
                  k3d::ri::parameter_list parameters;

                  // Setup constant parameters ...
                  parameters += detail::build_parameters((*group)->constant_data.begin(), (*group)->constant_data.end(), k3d::ri::CONSTANT);

                  // Setup uniform parameters ...
                  parameters += detail::build_parameters((*group)->curves.begin(), (*group)->curves.end(), k3d::ri::UNIFORM);

                  // Setup varying parameters ...
                  parameters += detail::build_parameters((*group)->curves.begin(), (*group)->curves.end(), k3d::ri::VARYING);

                  // Setup vertex parameters ...
                  parameters += detail::build_parameters(points.begin(), points.end(), k3d::ri::VERTEX);

                  // Setup points ...
                  parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, ripoints));

                  State.engine.RiCurvesV("linear", point_counts, (*group)->wrap ? "periodic" : "nonperiodic", parameters);
            }

      // For each cubic curve group in the mesh ...
      for(k3d::mesh::cubic_curve_groups_t::const_iterator group = Mesh.cubic_curve_groups.begin(); group != Mesh.cubic_curve_groups.end(); ++group)
            {
                  // Set the group material ...
                  k3d::ri::setup_material((*group)->material, State);

                  // Keep track of curve control points ...
                  std::vector<k3d::point*> points;
                  k3d::ri::points ripoints;
                  k3d::ri::unsigned_integers point_counts;

                  // For each cubic curve in the group ...
                  for(k3d::cubic_curve_group::curves_t::const_iterator curve = (*group)->curves.begin(); curve != (*group)->curves.end(); ++curve)
                        {
                              for(k3d::cubic_curve::control_points_t::const_iterator control_point = (*curve)->control_points.begin(); control_point != (*curve)->control_points.end(); ++control_point)
                                    {
                                          points.push_back(*control_point);
                                          ripoints.push_back((*control_point)->position);
                                    }

                              point_counts.push_back((*curve)->control_points.size());
                        }

                  // Setup group parameters ...
                  k3d::ri::parameter_list parameters;

                  // Setup constant parameters ...
                  parameters += detail::build_parameters((*group)->constant_data.begin(), (*group)->constant_data.end(), k3d::ri::CONSTANT);

                  // Setup uniform parameters ...
                  parameters += detail::build_parameters((*group)->curves.begin(), (*group)->curves.end(), k3d::ri::UNIFORM);

                  // Setup varying parameters ...
                  parameters += detail::build_parameters((*group)->curves.begin(), (*group)->curves.end(), k3d::ri::VARYING);

                  // Setup vertex parameters ...
                  parameters += detail::build_parameters(points.begin(), points.end(), k3d::ri::VERTEX);

                  // Setup points ...
                  parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, ripoints));

                  // At the moment, we force all cubic curves to be Bezier ...
                  State.engine.RiBasis("bezier", 3, "bezier", 3);
                  State.engine.RiCurvesV("cubic", point_counts, (*group)->wrap ? "periodic" : "nonperiodic", parameters);
            }

      // For each bilinear patch in the mesh ...
      for(k3d::mesh::bilinear_patches_t::const_iterator patch = Mesh.bilinear_patches.begin(); patch != Mesh.bilinear_patches.end(); ++patch)
            {
                  // Set the polyhedron material ...
                  k3d::ri::setup_material((*patch)->material, State);

                  // Setup patch parameters ...
                  k3d::ri::parameter_list parameters;

                  // Setup uniform parameters ...
                  parameters += detail::build_parameters((*patch)->uniform_data.begin(), (*patch)->uniform_data.end(), k3d::ri::UNIFORM);

                  // Setup varying parameters ...
                  parameters += detail::build_parameters((*patch)->varying_data.begin(), (*patch)->varying_data.end(), k3d::ri::VARYING);

                  // Setup vertex parameters ...
                  parameters += detail::build_parameters((*patch)->control_points.begin(), (*patch)->control_points.end(), k3d::ri::VERTEX);

                  // Setup points ...
                  k3d::ri::points points;
                  for(unsigned int i = 0; i != 4; ++i)
                        points.push_back((*patch)->control_points[i]->position);
                  parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, points));

                  State.engine.RiPatchV("bilinear", parameters);
            }

      // For each bicubic patch in the mesh ...
      for(k3d::mesh::bicubic_patches_t::const_iterator patch = Mesh.bicubic_patches.begin(); patch != Mesh.bicubic_patches.end(); ++patch)
            {
                  // Set the polyhedron material ...
                  k3d::ri::setup_material((*patch)->material, State);

                  // Setup patch parameters ...
                  k3d::ri::parameter_list parameters;

                  // Setup uniform parameters ...
                  parameters += detail::build_parameters((*patch)->uniform_data.begin(), (*patch)->uniform_data.end(), k3d::ri::UNIFORM);

                  // Setup varying parameters ...
                  parameters += detail::build_parameters((*patch)->varying_data.begin(), (*patch)->varying_data.end(), k3d::ri::VARYING);

                  // Setup vertex parameters ...
                  parameters += detail::build_parameters((*patch)->control_points.begin(), (*patch)->control_points.end(), k3d::ri::VERTEX);

                  // Setup points ...
                  k3d::ri::points points;
                  for(unsigned int i = 0; i != 16; ++i)
                        points.push_back((*patch)->control_points[i]->position);
                  parameters.push_back(k3d::ri::parameter(k3d::ri::RI_P(), k3d::ri::VERTEX, points));

                  // At the moment, we force all bicubic patches to be Bezier ...
                  State.engine.RiBasis("bezier", 3, "bezier", 3);
                  State.engine.RiPatchV("bicubic", parameters);
            }

      // For each NURBS patch in the mesh ...
      for(k3d::mesh::nupatches_t::const_iterator nupatch = Mesh.nupatches.begin(); nupatch != Mesh.nupatches.end(); ++nupatch)
            {
                  const k3d::nupatch& patch = **nupatch;

                  // Set the patch material ...
                  k3d::ri::setup_material(patch.material, State);

                  // Setup patch parameters ...
                  k3d::ri::parameter_list parameters;

                  const k3d::ri::unsigned_integer u_count = patch.u_knots.size() - patch.u_order;
                  const k3d::ri::unsigned_integer v_count = patch.v_knots.size() - patch.v_order;
                  const k3d::ri::unsigned_integer u_order = patch.u_order;
                  const k3d::ri::unsigned_integer v_order = patch.v_order;

                  // Setup points ...
                  k3d::ri::hpoints points;
                  for(k3d::nupatch::control_points_t::const_iterator control_point = patch.control_points.begin(); control_point != patch.control_points.end(); ++control_point)
                        points.push_back(k3d::vector4(control_point->position->position * control_point->weight, control_point->weight));
                  parameters.push_back(k3d::ri::parameter(k3d::ri::RI_PW(), k3d::ri::VERTEX, points));

                  State.engine.RiNuPatchV(
                        u_count,
                        u_order,
                        patch.u_knots,
                        patch.u_knots[u_order-1],
                        patch.u_knots[u_count],
                        v_count,
                        v_order,
                        patch.v_knots,
                        patch.v_knots[v_order-1],
                        patch.v_knots[v_count],
                        parameters
                        );
            }

      // For each blobby in the mesh ...
      for(k3d::mesh::blobbies_t::const_iterator blobby = Mesh.blobbies.begin(); blobby != Mesh.blobbies.end(); ++blobby)
            {
                  // Setup blobby parameters ...
                  unsigned_integer nleaf = 0;
                  unsigned_integers codes;
                  reals floats;
                  strings names;
                  detail::grouped_parameters_t grouped_parameters;

                  detail::blobby_vm(**blobby, nleaf, codes, floats, names, grouped_parameters);

                  parameter_list parameters;
                  parameters += detail::build_parameters(grouped_parameters, k3d::ri::VERTEX);
                  parameters += detail::build_parameters(grouped_parameters, k3d::ri::VARYING);

                  State.engine.RiBlobbyV(nleaf, codes, floats, names, parameters);
            }
}

/////////////////////////////////////////////////////////////////////////////
// render_engine::implementation

class render_engine::implementation
{
public:
      implementation(std::ostream& Stream) :
            m_stream(Stream),
            m_light_handle(0),
            m_object_handle(0),
            m_frame_block(false),
            m_world_block(false),
            m_object_block(false),
            m_motion_block(false)
      {
      }

      /// Stores the RIB output stream
      std::ostream& m_stream;
      /// Stores the current light handle
      light_handle m_light_handle;
      /// Stores the current object handle
      object_handle m_object_handle;
      /// Set to true within a frame block
      bool m_frame_block;
      /// Set to true within a world block
      bool m_world_block;
      /// Set to true within an object block
      bool m_object_block;
      /// Set to true within a motion block
      bool m_motion_block;
      /// Stores the set of shaders in-use
      shaders_t m_shaders;
};

/////////////////////////////////////////////////////////////////////////////
// render_engine

render_engine::render_engine(std::ostream& Stream) :
      m_implementation(new implementation(Stream))
{
      // Enable inline type declarations by default ...
      ::set_inline_types(m_implementation->m_stream, true);

      // Start out without any indentation ...
      ::reset_indentation(m_implementation->m_stream);

      // Start writing the RIB file header ...
      RiStructure("RenderMan RIB-Structure 1.0");
      m_implementation->m_stream << "version 3.03" << "\n";
}

render_engine::~render_engine()
{
      delete m_implementation;
}

01569 const render_engine::shaders_t render_engine::shaders()
{
      return m_implementation->m_shaders;
}

bool render_engine::set_inline_types(const bool Inline)
{
      return ::set_inline_types(m_implementation->m_stream, Inline);
}

void render_engine::RiDeclare(const string& Name, const string& Type)
{
      // Sanity checks ...
      return_if_fail(Name.size());
      return_if_fail(Type.size());

      m_implementation->m_stream << ::indentation << "Declare " << format_string(Name) << " " << format_string(Type) << "\n";
}

void render_engine::RiFrameBegin(const unsigned_integer FrameNumber)
{
      // Sanity checks ...
      if(m_implementation->m_frame_block)
            {
                  std::cerr << error << "Cannot nest calls to RiFrameBegin()" << std::endl;
                  return;
            }

      m_implementation->m_frame_block = true;
      m_implementation->m_stream << ::indentation << ::indentation << "FrameBegin " << FrameNumber << "\n";
      ::push_indent(m_implementation->m_stream);
}

void render_engine::RiFrameEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "FrameEnd" << "\n";
      m_implementation->m_frame_block = false;
}

void render_engine::RiWorldBegin()
{
      // Sanity checks ...
      if(m_implementation->m_world_block)
            {
                  std::cerr << error << "Cannot nest calls to RiWorldBegin()" << std::endl;
                  return;
            }

      m_implementation->m_world_block = true;
      m_implementation->m_stream << ::indentation << "WorldBegin" << "\n";
      ::push_indent(m_implementation->m_stream);
}

void render_engine::RiWorldEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "WorldEnd" << "\n";
      m_implementation->m_world_block = false;
}

void render_engine::RiFormat(const unsigned_integer XResolution, const unsigned_integer YResolution, const real AspectRatio)
{
      m_implementation->m_stream << ::indentation << "Format " << XResolution << " " << YResolution << " " << AspectRatio << "\n";
}

void render_engine::RiFrameAspectRatio(real AspectRatio)
{
      m_implementation->m_stream << ::indentation << "FrameAspectRatio " << AspectRatio << "\n";
}

void render_engine::RiScreenWindow(real Left, real Right, real Bottom, real Top)
{
      m_implementation->m_stream << ::indentation << "ScreenWindow " << Left << " " << Right << " " << Bottom << " " << Top << "\n";
}

void render_engine::RiCropWindow(real XMin, real XMax, real YMin, real YMax)
{
      m_implementation->m_stream << ::indentation << "CropWindow " << XMin << " " << XMax << " " << YMin << " " << YMax << "\n";
}

void render_engine::RiProjectionV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Projection " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiClipping(real NearPlane, real FarPlane)
{
      m_implementation->m_stream << ::indentation << "Clipping " << NearPlane << " " << FarPlane << "\n";
}

void render_engine::RiDepthOfField(real FStop, real FocalLength, real FocalDistance)
{
      m_implementation->m_stream << ::indentation << "DepthOfField " << FStop << " " << FocalLength << " " << FocalDistance << "\n";
}

void render_engine::RiShutter(real OpenTime, real CloseTime)
{
      m_implementation->m_stream << ::indentation << "Shutter " << OpenTime << " " << CloseTime << "\n";
}

void render_engine::RiPixelFilter(const string& FilterName, real XWidth, real YWidth)
{
      m_implementation->m_stream << ::indentation << "PixelFilter " << format_string(FilterName) << " " << XWidth << " " << YWidth << "\n";
}

void render_engine::RiPixelVariance(real Variation)
{
      m_implementation->m_stream << ::indentation << "PixelVariance " << Variation << "\n";
}
void render_engine::RiPixelSamples(real XSamples, real YSamples)
{
      m_implementation->m_stream << ::indentation << "PixelSamples " << XSamples << " " << YSamples << "\n";
}

void render_engine::RiExposure(real Gain, real Gamma)
{
      m_implementation->m_stream << ::indentation << "Exposure " << Gain << " " << Gamma << "\n";
}

void render_engine::RiImagerV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Imager " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiQuantize(const string& Type, integer One, integer QMin, integer QMax, real Amplitude)
{
      m_implementation->m_stream << ::indentation << "Quantize " << format_string(Type) << " " << One << " " << QMin << " " << QMax << " " << Amplitude << "\n";
}

void render_engine::RiDisplayV(const string& Name, const string& Type, const string& Mode, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Display " << format_string(Name) << " " << format_string(Type) << " " << format_string(Mode) << " " << Parameters << "\n";
}

void render_engine::RiHiderV(const string& Type, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Hider " << format_string(Type) << " " << Parameters << "\n";
}

void render_engine::RiColorSamples(const unsigned_integer ParameterCount, const reals& nRGB, const reals& RGBn)
{
      return_if_fail(ParameterCount == nRGB.size());
      return_if_fail(ParameterCount == RGBn.size());

      m_implementation->m_stream << ::indentation << "ColorSamples " << format_array(nRGB.begin(), nRGB.end()) << " " << format_array(RGBn.begin(), RGBn.end()) << "\n";
}

void render_engine::RiRelativeDetail(real RelativeDetail)
{
      m_implementation->m_stream << ::indentation << "RelativeDetail " << RelativeDetail << "\n";
}

void render_engine::RiOptionV(const string& Name, const parameter_list& Parameters)
{
      const bool old_state = ::set_inline_types(m_implementation->m_stream, false);

      m_implementation->m_stream << ::indentation << "Option " << format_string(Name) << " " << Parameters << "\n";

      ::set_inline_types(m_implementation->m_stream, old_state);
}

void render_engine::RiAttributeBegin()
{
      m_implementation->m_stream << ::indentation << "AttributeBegin" << "\n";
      ::push_indent(m_implementation->m_stream);
}

void render_engine::RiAttributeEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "AttributeEnd" << "\n";
}

void render_engine::RiColor(const color& Color)
{
      m_implementation->m_stream << ::indentation << "Color " << Color << "\n";
}

void render_engine::RiOpacity(const color& Opacity)
{
      m_implementation->m_stream << ::indentation << "Opacity " << Opacity << "\n";
}

void render_engine::RiTextureCoordinates(real S1, real T1, real S2, real T2, real S3, real T3, real S4, real T4)
{
      m_implementation->m_stream << ::indentation << "TextureCoordinates " << S1 << " " << T1 << " " << S2 << " " << T2 << " " << S3 << " " << T3 << " " << S4 << " " << T4 << "\n";
}

const light_handle render_engine::RiLightSourceV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "LightSource " << format_string(Name) << " " << ++m_implementation->m_light_handle << " " << Parameters << "\n";
      return m_implementation->m_light_handle;
}

const light_handle render_engine::RiAreaLightSourceV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "AreaLightSource " << format_string(Name) << " " << ++m_implementation->m_light_handle << " " << Parameters << "\n";
      return m_implementation->m_light_handle;
}

void render_engine::RiIlluminate(const light_handle LightHandle, bool OnOff)
{
      m_implementation->m_stream << ::indentation << "Illuminate " << LightHandle << " " << OnOff << "\n";
}

void render_engine::RiSurfaceV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Surface " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiAtmosphereV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Atmosphere " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiInteriorV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Interior " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiExteriorV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Exterior " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiShadingRate(real Size)
{
      m_implementation->m_stream << ::indentation << "ShadingRate " << Size << "\n";
}

void render_engine::RiShadingInterpolation(const string& Type)
{
      m_implementation->m_stream << ::indentation << "ShadingInterpolation " << format_string(Type) << "\n";
}

void render_engine::RiMatte(bool OnOff)
{
      m_implementation->m_stream << ::indentation << "Matte " << OnOff << "\n";
}

void render_engine::RiBound(const boost::array<real, 6>& Bound)
{
      m_implementation->m_stream << ::indentation << "Bound " << format_array(Bound.begin(), Bound.end()) << "\n";
}

void render_engine::RiDetail(const boost::array<real, 6>& Bound)
{
      m_implementation->m_stream << ::indentation << "Detail " << format_array(Bound.begin(), Bound.end()) << "\n";
}

void render_engine::RiDetailRange(const real MinVis, const real LowTran, const real UpTran, const real MaxVis)
{
      m_implementation->m_stream << ::indentation << "DetailRange " << MinVis << " " << LowTran << " " << UpTran << " " << MaxVis << "\n";
}

void render_engine::RiGeometricApproximation(const string& Type, real Value)
{
      m_implementation->m_stream << ::indentation << "GeometricApproximation " << format_string(Type) << " " << Value << "\n";
}

void render_engine::RiGeometricRepresentation(const string& Type)
{
      m_implementation->m_stream << ::indentation << "GeometricRepresentation " << format_string(Type) << "\n";
}

void render_engine::RiOrientation(const string& Orientation)
{
      m_implementation->m_stream << ::indentation << "Orientation " << format_string(Orientation) << "\n";
}

void render_engine::RiReverseOrientation()
{
      m_implementation->m_stream << ::indentation << "ReverseOrientation" << "\n";
}

void render_engine::RiSides(const unsigned_integer Sides)
{
      m_implementation->m_stream << ::indentation << "Sides " << Sides << "\n";
}

void render_engine::RiIdentity()
{
      m_implementation->m_stream << ::indentation << "Identity" << "\n";
}

void render_engine::RiTransform(const matrix& Transform)
{
      m_implementation->m_stream << ::indentation << "Transform " << format_array(Transform.begin(), Transform.end()) << "\n";
}

void render_engine::RiConcatTransform(const matrix& Transform)
{
      m_implementation->m_stream << ::indentation << "ConcatTransform " << format_array(Transform.begin(), Transform.end()) << "\n";
}

void render_engine::RiPerspective(real FieldOfView)
{
      m_implementation->m_stream << ::indentation << "Perspective " << FieldOfView << "\n";
}

void render_engine::RiTranslate(real DX, real DY, real DZ)
{
      m_implementation->m_stream << ::indentation << "Translate " << DX << " " << DY << " " << DZ << "\n";
}

void render_engine::RiRotate(real Angle, real DX, real DY, real DZ)
{
      m_implementation->m_stream << ::indentation << "Rotate " << Angle << " " << DX << " " << DY << " " << DZ << "\n";
}

void render_engine::RiScale(real DX, real DY, real DZ)
{
      m_implementation->m_stream << ::indentation << "Scale " << DX << " " << DY << " " << DZ << "\n";
}

void render_engine::RiSkew(real Angle, real DX1, real DY1, real DZ1, real DX2, real DY2, real DZ2)
{
      m_implementation->m_stream << ::indentation << "Skew " << Angle << " " << DX1 << " " << DY1 << " " << DZ1 << " " << DX2 << " " << DY2 << " " << DZ2 << "\n";
}

void render_engine::RiDeformationV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Deformation " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiDisplacementV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_shaders.insert(Name);
      m_implementation->m_stream << ::indentation << "Displacement " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiCoordinateSystem(const string& Space)
{
      m_implementation->m_stream << ::indentation << "CoordinateSystem " << format_string(Space) << "\n";
}

void render_engine::RiCoordSysTransform(const string& Space)
{
      m_implementation->m_stream << ::indentation << "CoordSysTransform " << format_string(Space) << "\n";
}

void render_engine::RiTransformBegin()
{
      m_implementation->m_stream << ::indentation << "TransformBegin" << "\n";
      ::push_indent(m_implementation->m_stream);
}

void render_engine::RiTransformEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "TransformEnd" << "\n";
}

void render_engine::RiAttributeV(const string& Name, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Attribute " << format_string(Name) << " " << Parameters << "\n";
}

void render_engine::RiPointsV(const unsigned_integer VertexCount, const parameter_list& Parameters)
{
      // Sanity checks ...
      return_if_fail(VertexCount);

      m_implementation->m_stream << ::indentation << "Points " << Parameters << "\n";
}

void render_engine::RiPolygonV(const unsigned_integer VertexCount, const parameter_list& Parameters)
{
      // Sanity checks ...
      return_if_fail(VertexCount);

      m_implementation->m_stream << ::indentation << "Polygon " << Parameters << "\n";
}

void render_engine::RiGeneralPolygonV(const unsigned_integers& VertexCounts, const parameter_list& Parameters)
{
      // Do some simple sanity checks ...
      return_if_fail(VertexCounts.size());

      m_implementation->m_stream << ::indentation << "GeneralPolygon " << format_array(VertexCounts.begin(), VertexCounts.end()) << " " << Parameters << "\n";
}

void render_engine::RiPointsPolygonsV(const unsigned_integers& VertexCounts, const unsigned_integers& VertexIDs, const parameter_list& Parameters)
{
      // Sanity checks ...
      return_if_fail(VertexCounts.size());
      return_if_fail(VertexIDs.size() == std::accumulate(VertexCounts.begin(), VertexCounts.end(), 0UL));

      m_implementation->m_stream << ::indentation << "PointsPolygons " << format_array(VertexCounts.begin(), VertexCounts.end()) << " " << format_array(VertexIDs.begin(), VertexIDs.end()) << " " << Parameters << "\n";
}

void render_engine::RiPointsGeneralPolygonsV(const unsigned_integers& LoopCounts, const unsigned_integers& VertexCounts, const unsigned_integers& VertexIDs, const parameter_list& Parameters)
{
      // Sanity checks ...
      return_if_fail(LoopCounts.size());
      return_if_fail(VertexCounts.size() == std::accumulate(LoopCounts.begin(), LoopCounts.end(), 0UL));
      return_if_fail(VertexIDs.size() == std::accumulate(VertexCounts.begin(), VertexCounts.end(), 0UL));

      m_implementation->m_stream << ::indentation << "PointsGeneralPolygons " << format_array(LoopCounts.begin(), LoopCounts.end()) << " " << format_array(VertexCounts.begin(), VertexCounts.end()) << " " << format_array(VertexIDs.begin(), VertexIDs.end()) << " " << Parameters << "\n";
}

void render_engine::RiBasis(const matrix& UBasis, const unsigned_integer UStep, const matrix& VBasis, const unsigned_integer VStep)
{
      m_implementation->m_stream << ::indentation << "Basis " << format_array(UBasis.begin(), UBasis.end()) << " " << UStep << " " << format_array(VBasis.begin(), VBasis.end()) << " " << VStep << "\n";
}

void render_engine::RiBasis(const string& UBasis, const unsigned_integer UStep, const string& VBasis, const unsigned_integer VStep)
{
      m_implementation->m_stream << ::indentation << "Basis " << format_string(UBasis) << " " << UStep << " " << format_string(VBasis) << " " << VStep << "\n";
}

void render_engine::RiPatchV(const string& Type, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Patch " << format_string(Type) << " " << Parameters << "\n";
}

void render_engine::RiPatchMeshV(const string& Type, const unsigned_integer UCount, const string& UWrap, const unsigned_integer VCount, const string& VWrap, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "PatchMesh " << format_string(Type) << " " << UCount << " " << format_string(UWrap) << " " << VCount << " " << format_string(VWrap) << " " << Parameters << "\n";
}

void render_engine::RiNuPatchV(const unsigned_integer UCount, const unsigned_integer UOrder, const reals& UKnot, const real UMin, const real UMax, const unsigned_integer VCount, const unsigned_integer VOrder, const reals& VKnot, const real VMin, const real VMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "NuPatch " << UCount << " " << UOrder << " " << format_array(UKnot.begin(), UKnot.end()) << " " << UMin << " " << UMax << " " << VCount << " " << VOrder << " " << format_array(VKnot.begin(), VKnot.end()) << " " << VMin << " " << VMax << " " << Parameters << "\n";
}

void render_engine::RiTrimCurve(const unsigned_integer LoopCount, const unsigned_integers& CurveCounts, const unsigned_integers& Orders, const reals& Knots, const reals& Minimums, const reals& Maximums, const unsigned_integers& KnotCounts, const reals& U, const reals& V, const reals& W)
{
      m_implementation->m_stream << ::indentation << "TrimCurve " << LoopCount << " " << format_array(CurveCounts.begin(), CurveCounts.end()) << " " << format_array(Orders.begin(), Orders.end()) << " " << format_array(Knots.begin(), Knots.end()) << " " << format_array(Minimums.begin(), Minimums.end()) << " " << format_array(Maximums.begin(), Maximums.end()) << " " << format_array(KnotCounts.begin(), KnotCounts.end()) << " " << format_array(U.begin(), U.end()) << " " << format_array(V.begin(), V.end()) << " " << format_array(W.begin(), W.end()) << "\n";
}

void render_engine::RiSphereV(real Radius, real ZMin, real ZMax, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Sphere " << Radius << " " << ZMin << " " << ZMax << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiConeV(real Height, real Radius, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Cone " << Height << " " << Radius << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiCylinderV(real Radius, real ZMin, real ZMax, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Cylinder " << Radius << " " << ZMin << " " << ZMax << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiHyperboloidV(const point& Point1, const point& Point2, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Hyperboloid " << Point1 << " " << Point2 << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiParaboloidV(real RMax, real ZMin, real ZMax, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Paraboloid " << RMax << " " << ZMin << " " << ZMax << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiDiskV(real Height, real Radius, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Disk " << Height << " " << Radius << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiTorusV(real MajorRadius, real MinorRadius, real PhiMin, real PhiMax, real ThetaMax, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Torus " << MajorRadius << " " << MinorRadius << " " << PhiMin << " " << PhiMax << " " << ThetaMax << " " << Parameters << "\n";
}

void render_engine::RiCurvesV(const string& Type, const unsigned_integers& VertexCounts, const string& Wrap, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Curves " << format_string(Type) << " " << format_array(VertexCounts.begin(), VertexCounts.end()) << " " << format_string(Wrap) << " " << Parameters << "\n";
}

void render_engine::RiGeometryV(const string& Type, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Geometry " << format_string(Type) << " " << Parameters << "\n";
}

void render_engine::RiSolidBegin(const string& Type)
{
      m_implementation->m_stream << ::indentation << "SolidBegin " << format_string(Type) << "\n";
      ::push_indent(m_implementation->m_stream);
}

void render_engine::RiSolidEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "SolidEnd" << "\n";
}

const object_handle render_engine::RiObjectBegin()
{
      // Sanity checks ...
      if(m_implementation->m_object_block)
            {
                  std::cerr << error << "Cannot nest calls to RiObjectBegin()" << std::endl;
                  return 0;
            }

      m_implementation->m_object_block = true;
      m_implementation->m_stream << ::indentation << "ObjectBegin " << ++m_implementation->m_object_handle << "\n";
      ::push_indent(m_implementation->m_stream);
      return m_implementation->m_object_handle;
}

void render_engine::RiObjectEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "ObjectEnd" << "\n";
      m_implementation->m_object_block = false;
}

void render_engine::RiObjectInstance(const object_handle Handle)
{
      m_implementation->m_stream << ::indentation << "ObjectInstance " << Handle << "\n";
}

void render_engine::RiMotionBeginV(const sample_times_t& Times)
{
      // Sanity checks ...
      if(m_implementation->m_motion_block)
            {
                  std::cerr << error << "Cannot nest calls to RiMotionBegin()" << std::endl;
                  return;
            }

      m_implementation->m_motion_block = true;
      m_implementation->m_stream << ::indentation << "MotionBegin " << format_array(Times.begin(), Times.end()) << "\n";
      ::push_indent(m_implementation->m_stream);
}

void render_engine::RiMotionEnd()
{
      ::pop_indent(m_implementation->m_stream);
      m_implementation->m_stream << ::indentation << "MotionEnd" << "\n";
      m_implementation->m_motion_block = false;
}

void render_engine::RiErrorHandler(const string& Style)
{
      m_implementation->m_stream << ::indentation << "ErrorHandler " << format_string(Style) << "\n";
}

void render_engine::RiComment(const string& Comment)
{
      m_implementation->m_stream << ::indentation << "#" << Comment << "\n";
}

void render_engine::RiNewline()
{
      m_implementation->m_stream << "\n";
}

void render_engine::RiReadArchive(const string& Archive)
{
      m_implementation->m_stream << ::indentation << "ReadArchive " << Archive << "\n";
}

void render_engine::RiStructure(const string& Structure)
{
      m_implementation->m_stream << "##" << Structure << "\n";
}

void render_engine::RiSubdivisionMeshV(const string& Scheme, const unsigned_integers& VertexCounts, const unsigned_integers& VertexIDs, const strings& Tags, const unsigned_integers& ArgCounts, const integers& IntegerArgs, const reals& FloatArgs, const parameter_list& Parameters)
{
      // Sanity checks ...
      return_if_fail(VertexIDs.size() == std::accumulate(VertexCounts.begin(), VertexCounts.end(), 0UL));

      m_implementation->m_stream << ::indentation << "SubdivisionMesh " << format_string(Scheme) << " " << format_array(VertexCounts.begin(), VertexCounts.end()) << " " << format_array(VertexIDs.begin(), VertexIDs.end()) << " " << format_array(Tags.begin(), Tags.end()) << " " << format_array(ArgCounts.begin(), ArgCounts.end()) << " " << format_array(IntegerArgs.begin(), IntegerArgs.end()) << " " << format_array(FloatArgs.begin(), FloatArgs.end()) << " " << Parameters << "\n";
}

void render_engine::RiMakeCubeFaceEnvironmentV(const string& px, const string& nx, const string& py, const string& ny, const string& pz, const string& nz, const string& texturename, const real fov, const string& swrap, const string& twrap, const string& filterfunc, const real swidth, const real twidth, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "MakeCubeFaceEnvironment " << format_string(px) << " " << format_string(nx) << " " << format_string(py) << " " << format_string(ny) << " " << format_string(pz) << " " << format_string(nz) << " " << format_string(texturename) << " ";
      m_implementation->m_stream << fov << " " << format_string(swrap) << " " << format_string(twrap) << " " << format_string(filterfunc) << " " << swidth << " " << twidth << " " << Parameters;
}

void render_engine::RiMakeLatLongEnvironmentV(const string& picturename, const string& texturename, const string& filterfunc, const real swidth, const real twidth, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "MakeLatLongEnvironment " << format_string(picturename) << " " << format_string(texturename) << " " << format_string(filterfunc) << " " << swidth << " " << twidth << " " << Parameters;
}

void render_engine::RiMakeShadowV(const string& picturename, const string& texturename, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "MakeShadow " << format_string(picturename) << " " << format_string(texturename) << " " << Parameters;
}

void render_engine::RiMakeTextureV(const string& picturename, const string& texturename, const string& swrap, const string& twrap, const string& filterfunc, const real swidth, const real twidth, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "MakeTexture " << format_string(picturename) << " " << format_string(texturename) << " " << format_string(swrap) << " " << format_string(twrap) << " " << format_string(filterfunc) << " " << swidth << " " << twidth << " " << Parameters;
}

void render_engine::RiBlobbyV(const unsigned_integer NLeaf, const unsigned_integers& Codes, const reals& Floats, const strings& Strings, const parameter_list& Parameters)
{
      m_implementation->m_stream << ::indentation << "Blobby " << NLeaf << " " << format_array(Codes.begin(), Codes.end()) << " " << format_array(Floats.begin(), Floats.end()) << " " << format_array(Strings.begin(), Strings.end()) << " " << Parameters << "\n";
}

02173 parameter_list& operator+=(parameter_list& LHS, const parameter_list& RHS)
{
      LHS.insert(LHS.end(), RHS.begin(), RHS.end());
      return LHS;
}

02179 parameter_list operator+(const parameter_list& LHS, const parameter_list& RHS)
{
      parameter_list results(LHS);
      results += RHS;

      return results;
}

} // namespace ri

} // namespace k3d



Generated by  Doxygen 1.6.0   Back to index