Logo Search packages:      
Sourcecode: k3d version File versions

render_engine.cpp

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

/** \file
            \author Tim Shead <tshead@k-3d.com>
*/

#include <k3dsdk/classes.h>
#include <k3dsdk/frames.h>
#include <k3dsdk/ianimation_render_engine.h>
#include <k3dsdk/ioptions.h>
#include <k3dsdk/iprojection.h>
#include <k3dsdk/irender_farm.h>
#include <k3dsdk/istill_render_engine.h>
#include <k3dsdk/iviewport_host.h>
#include <k3dsdk/measurement.h>
#include <k3dsdk/module.h>
#include <k3dsdk/object.h>
#include <k3dsdk/persistence.h>
#include <k3dsdk/property.h>
#include <k3dsdk/property_group_collection.h>
#include <k3dsdk/renderman.h>
#include <k3dsdk/shaders.h>
#include <k3dsdk/string_modifiers.h>
#include <k3dsdk/time_source.h>
#include <k3dsdk/transformable.h>
#include <k3dsdk/viewport.h>

#include <boost/filesystem/fstream.hpp>

#include <iomanip>

#ifdef      WIN32
#ifdef      near
#undef      near
#endif      //near
#ifdef      far
#undef      far
#endif      //far
#endif      //WIN32

namespace libk3drenderman
{

namespace detail
{

class pre_render
{
public:
      explicit pre_render(const k3d::ri::render_state& State) :
            m_state(State)
      {
      }

      void operator()(k3d::iobject* const Object)
      {
            k3d::ri::irenderable* const renderable = dynamic_cast<k3d::ri::irenderable*>(Object);
            if(renderable)
                  renderable->renderman_pre_render(m_state);
      }

private:
      const k3d::ri::render_state& m_state;
};

class setup_light
{
public:
      explicit setup_light(const k3d::ri::render_state& State) :
            m_state(State)
      {
      }

      void operator()(k3d::iobject* const Object)
      {
            k3d::ri::ilight* const light = dynamic_cast<k3d::ri::ilight*>(Object);
            if(light)
                  light->setup_renderman_light(m_state);
      }

private:
      const k3d::ri::render_state& m_state;
};

class setup_texture
{
public:
      explicit setup_texture(k3d::irender_frame& Frame, k3d::ri::irender_engine& Engine) :
            m_frame(Frame),
            m_engine(Engine)
      {
      }

      void operator()(k3d::iobject* const Object)
      {
            k3d::ri::itexture* const texture = dynamic_cast<k3d::ri::itexture*>(Object);
            if(texture)
                  texture->setup_renderman_texture(m_frame, m_engine);
      }

private:
      k3d::irender_frame& m_frame;
      k3d::ri::irender_engine& m_engine;
};

class render
{
public:
      explicit render(const k3d::ri::render_state& State) :
            m_state(State)
      {
      }

      void operator()(k3d::iobject* const Object)
      {
            k3d::ri::irenderable* const renderable = dynamic_cast<k3d::ri::irenderable*>(Object);
            if(renderable)
                  renderable->renderman_render(m_state);
      }

private:
      const k3d::ri::render_state& m_state;
};

const unsigned long default_pixel_width = 320;
const unsigned long default_pixel_height = 240;
const double default_pixel_aspect_ratio = 1.0;
const double default_screen_aspect_ratio = default_pixel_aspect_ratio * static_cast<double>(default_pixel_width) / static_cast<double>(default_pixel_height);

std::string default_renderman_render_engine()
{
      std::string type;
      std::string engine;
      std::string name;
      
      k3d::application().options().default_render_engine(type, engine, name);
      if(type == "ri")
            return engine;
            
      return "aqsis";
}

} // namespace detail

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

class render_engine :
      public k3d::viewport::drawable<k3d::transformable<k3d::persistent<k3d::object> > >,
      public k3d::ianimation_render_engine,
      public k3d::istill_render_engine,
      public k3d::iviewport_host,
      public k3d::property_group_collection
{
      typedef k3d::viewport::drawable<k3d::transformable<k3d::persistent<k3d::object> > > base;

public:
      render_engine(k3d::idocument& Document) :
            base(Document),
            m_render_engine(k3d::init_name("render_engine") + k3d::init_description("Render Engine [string]") + k3d::init_value(detail::default_renderman_render_engine()) + k3d::init_document(Document) + k3d::init_values(render_engine_values())),
            m_pixel_width(k3d::init_name("pixel_width") + k3d::init_description("Output pixel width [positive integer]") + k3d::init_value(detail::default_pixel_width) + k3d::init_document(Document) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_pixel_height(k3d::init_name("pixel_height") + k3d::init_description("Output pixel height [positive integer]") + k3d::init_value(detail::default_pixel_height) + k3d::init_document(document()) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_pixel_aspect_ratio(k3d::init_name("pixel_aspect_ratio") + k3d::init_description("Output pixel aspect ratio [positive real]") + k3d::init_value(detail::default_pixel_aspect_ratio) + k3d::init_document(document()) + k3d::init_constraint(k3d::constraint::minimum(std::numeric_limits<double>::epsilon())) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_default_atmosphere_shader(k3d::init_name("default_atmosphere_shader") + k3d::init_description("Default atmosphere shader [object]") + k3d::init_object_value(0) + k3d::init_document(Document)),
            m_default_interior_shader(k3d::init_name("default_interior_shader") + k3d::init_description("Default interior shader [object]") + k3d::init_object_value(0) + k3d::init_document(Document)),
            m_default_exterior_shader(k3d::init_name("default_exterior_shader") + k3d::init_description("Default exterior shader [object]") + k3d::init_object_value(0) + k3d::init_document(Document)),
            m_imager_shader(k3d::init_name("imager_shader") + k3d::init_description("Imager shader [object]") + k3d::init_object_value(0) + k3d::init_document(Document)),
            m_orthographic(k3d::init_name("orthographic") + k3d::init_description("Orthographic [boolean]") + k3d::init_value(false) + k3d::init_document(Document)),
            m_left(k3d::init_name("left") + k3d::init_description("Left [number]") + k3d::init_value(-0.5 * detail::default_screen_aspect_ratio) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_right(k3d::init_name("right") + k3d::init_description("Right [number]") + k3d::init_value(0.5 * detail::default_screen_aspect_ratio) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_top(k3d::init_name("top") + k3d::init_description("Top [number]") + k3d::init_value(0.5) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_bottom(k3d::init_name("bottom") + k3d::init_description("Bottom [number]") + k3d::init_value(-0.5) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_near(k3d::init_name("near") + k3d::init_description("Near plane distance [number]") + k3d::init_value(1.0) + k3d::init_constraint(k3d::constraint::minimum(0.0)) + k3d::init_document(Document) + k3d::init_precision(1) + k3d::init_step_increment(0.1) + k3d::init_units(typeid(k3d::measurement::distance))),
            m_far(k3d::init_name("far") + k3d::init_description("Far plane distance [number]") + k3d::init_value(1000.0) + k3d::init_constraint(k3d::constraint::minimum(0.0)) + k3d::init_document(Document) + k3d::init_precision(1) + k3d::init_step_increment(0.1) + k3d::init_units(typeid(k3d::measurement::distance))),
            m_bucket_width(k3d::init_name("bucket_width") + k3d::init_description("Bucket Width [positive integer]") + k3d::init_value(16) + k3d::init_document(Document) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_bucket_height(k3d::init_name("bucket_height") + k3d::init_description("Bucket Height [positive integer]") + k3d::init_value(16) + k3d::init_document(Document) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_grid_size(k3d::init_name("grid_size") + k3d::init_description("Grid Size [positive integer]") + k3d::init_value(256) + k3d::init_document(Document) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_eye_splits(k3d::init_name("eye_splits") + k3d::init_description("Eye Splits [positive integer]") + k3d::init_value(10) + k3d::init_document(Document) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_texture_memory(k3d::init_name("texture_memory") + k3d::init_description("Texture Memory [positive integer]") + k3d::init_value(1024) + k3d::init_document(Document) + k3d::init_constraint(k3d::constraint::minimum(1UL)) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_render_alpha(k3d::init_name("render_alpha") + k3d::init_description("Render Alpha [boolean]") + k3d::init_value(true) + k3d::init_document(Document)),
            m_pixel_xsamples(k3d::init_name("pixel_xsamples") + k3d::init_description("Pixel X Samples [positive real]") + k3d::init_value(1.0) + k3d::init_document(document()) + k3d::init_constraint(k3d::constraint::minimum(std::numeric_limits<double>::epsilon())) + k3d::init_precision(2) + k3d::init_step_increment(1.0) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_pixel_ysamples(k3d::init_name("pixel_ysamples") + k3d::init_description("Pixel Y Samples [positive real]") + k3d::init_value(1.0) + k3d::init_document(document()) + k3d::init_constraint(k3d::constraint::minimum(std::numeric_limits<double>::epsilon())) + k3d::init_precision(2) + k3d::init_step_increment(1.0) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_pixel_filter(k3d::init_name("pixel_filter") + k3d::init_description("Pixel Filter [string]") + k3d::init_value(k3d::ri::RI_GAUSSIAN()) + k3d::init_document(document()) + k3d::init_values(pixel_filter_values())),
            m_pixel_filter_width(k3d::init_name("pixel_filter_width") + k3d::init_description("Pixel Filter Width [positive real]") + k3d::init_value(2.0) + k3d::init_document(document()) + k3d::init_constraint(k3d::constraint::minimum(std::numeric_limits<double>::epsilon())) + k3d::init_precision(2) + k3d::init_step_increment(1.0) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_pixel_filter_height(k3d::init_name("pixel_filter_height") + k3d::init_description("Pixel Filter Height [positive real]") + k3d::init_value(2.0) + k3d::init_document(document()) + k3d::init_constraint(k3d::constraint::minimum(std::numeric_limits<double>::epsilon())) + k3d::init_precision(2) + k3d::init_step_increment(1.0) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_exposure(k3d::init_name("exposure") + k3d::init_description("Exposure [real]") + k3d::init_value(1.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_gamma(k3d::init_name("gamma") + k3d::init_description("Gamma [real]") + k3d::init_value(1.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_dof(k3d::init_name("dof") + k3d::init_description("Depth of Field [boolean]") + k3d::init_value(false) + k3d::init_document(Document)),
            m_fstop(k3d::init_name("fstop") + k3d::init_description("f-stop [real]") + k3d::init_value(0.3) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_focal_length(k3d::init_name("focal_length") + k3d::init_description("Focal Length [distance]") + k3d::init_value(1.6) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::distance))),
            m_focus_plane(k3d::init_name("focus_plane") + k3d::init_description("Focus Plane [distance]") + k3d::init_value(30.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::distance))),
            m_shading_rate(k3d::init_name("shading_rate") + k3d::init_description("Shading Rate [real]") + k3d::init_value(1.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.1) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_shading_interpolation(k3d::init_name("shading_interpolation") + k3d::init_description("Shading Interpolation [string]") + k3d::init_value(k3d::ri::RI_CONSTANT()) + k3d::init_document(Document) + k3d::init_values(shading_interpolation_values())),
            m_two_sided(k3d::init_name("two_sided") + k3d::init_description("Two Sided [boolean]") + k3d::init_value(true) + k3d::init_document(Document)),
            m_crop_window_left(k3d::init_name("crop_window_left") + k3d::init_description("Crop Window Left [real]") + k3d::init_value(0.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_crop_window_right(k3d::init_name("crop_window_right") + k3d::init_description("Crop Window Right [real]") + k3d::init_value(1.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_crop_window_top(k3d::init_name("crop_window_top") + k3d::init_description("Crop Window Top [real]") + k3d::init_value(0.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_crop_window_bottom(k3d::init_name("crop_window_bottom") + k3d::init_description("Crop Window Bottom [real]") + k3d::init_value(1.0) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(0.01) + k3d::init_units(typeid(k3d::measurement::scalar))),
            m_motion_blur(k3d::init_name("motion_blur") + k3d::init_description("Motion Blur [boolean]") + k3d::init_value(false) + k3d::init_document(Document)),
            m_render_motion_blur(k3d::init_name("render_motion_blur") + k3d::init_description("Render Motion Blur [boolean]") + k3d::init_value(false) + k3d::init_document(Document)),
            m_perspective_projection(m_left, m_right, m_top, m_bottom, m_near, m_far),
            m_orthographic_projection(m_left, m_right, m_top, m_bottom, m_near, m_far)
      {
            enable_serialization(k3d::persistence::proxy(m_render_engine));
            enable_serialization(k3d::persistence::proxy(m_pixel_width));
            enable_serialization(k3d::persistence::proxy(m_pixel_height));
            enable_serialization(k3d::persistence::proxy(m_pixel_aspect_ratio));
            enable_serialization(k3d::persistence::object_proxy(m_default_atmosphere_shader));
            enable_serialization(k3d::persistence::object_proxy(m_default_interior_shader));
            enable_serialization(k3d::persistence::object_proxy(m_default_exterior_shader));
            enable_serialization(k3d::persistence::object_proxy(m_imager_shader));
            enable_serialization(k3d::persistence::proxy(m_orthographic));
            enable_serialization(k3d::persistence::proxy(m_left));
            enable_serialization(k3d::persistence::proxy(m_right));
            enable_serialization(k3d::persistence::proxy(m_top));
            enable_serialization(k3d::persistence::proxy(m_bottom));
            enable_serialization(k3d::persistence::proxy(m_near));
            enable_serialization(k3d::persistence::proxy(m_far));
            enable_serialization(k3d::persistence::proxy(m_bucket_width));
            enable_serialization(k3d::persistence::proxy(m_bucket_height));
            enable_serialization(k3d::persistence::proxy(m_grid_size));
            enable_serialization(k3d::persistence::proxy(m_eye_splits));
            enable_serialization(k3d::persistence::proxy(m_texture_memory));
            enable_serialization(k3d::persistence::proxy(m_render_alpha));
            enable_serialization(k3d::persistence::proxy(m_pixel_xsamples));
            enable_serialization(k3d::persistence::proxy(m_pixel_ysamples));
            enable_serialization(k3d::persistence::proxy(m_pixel_filter));
            enable_serialization(k3d::persistence::proxy(m_pixel_filter_width));
            enable_serialization(k3d::persistence::proxy(m_pixel_filter_height));
            enable_serialization(k3d::persistence::proxy(m_exposure));
            enable_serialization(k3d::persistence::proxy(m_gamma));
            enable_serialization(k3d::persistence::proxy(m_dof));
            enable_serialization(k3d::persistence::proxy(m_fstop));
            enable_serialization(k3d::persistence::proxy(m_focal_length));
            enable_serialization(k3d::persistence::proxy(m_focus_plane));
            enable_serialization(k3d::persistence::proxy(m_shading_rate));
            enable_serialization(k3d::persistence::proxy(m_shading_interpolation));
            enable_serialization(k3d::persistence::proxy(m_two_sided));
            enable_serialization(k3d::persistence::proxy(m_crop_window_left));
            enable_serialization(k3d::persistence::proxy(m_crop_window_right));
            enable_serialization(k3d::persistence::proxy(m_crop_window_top));
            enable_serialization(k3d::persistence::proxy(m_crop_window_bottom));
            enable_serialization(k3d::persistence::proxy(m_motion_blur));
            enable_serialization(k3d::persistence::proxy(m_render_motion_blur));

            register_property(m_render_engine);
            register_property(m_pixel_width);
            register_property(m_pixel_height);
            register_property(m_pixel_aspect_ratio);
            register_property(m_default_atmosphere_shader);
            register_property(m_default_interior_shader);
            register_property(m_default_exterior_shader);
            register_property(m_imager_shader);
            register_property(m_orthographic);
            register_property(m_left);
            register_property(m_right);
            register_property(m_top);
            register_property(m_bottom);
            register_property(m_near);
            register_property(m_far);
            register_property(m_bucket_width);
            register_property(m_bucket_height);
            register_property(m_grid_size);
            register_property(m_eye_splits);
            register_property(m_texture_memory);
            register_property(m_render_alpha);
            register_property(m_pixel_xsamples);
            register_property(m_pixel_ysamples);
            register_property(m_pixel_filter);
            register_property(m_pixel_filter_width);
            register_property(m_pixel_filter_height);
            register_property(m_exposure);
            register_property(m_gamma);
            register_property(m_dof);
            register_property(m_fstop);
            register_property(m_focal_length);
            register_property(m_focus_plane);
            register_property(m_shading_rate);
            register_property(m_shading_interpolation);
            register_property(m_two_sided);
            register_property(m_crop_window_left);
            register_property(m_crop_window_right);
            register_property(m_crop_window_top);
            register_property(m_crop_window_bottom);
            register_property(m_motion_blur);
            register_property(m_render_motion_blur);

            k3d::iproperty_group_collection::group output_group("Output");
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_render_engine));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_width));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_height));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_aspect_ratio));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_default_atmosphere_shader));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_default_interior_shader));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_default_exterior_shader));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_imager_shader));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_render_alpha));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_crop_window_left));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_crop_window_right));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_crop_window_top));
            output_group.properties.push_back(&static_cast<k3d::iproperty&>(m_crop_window_bottom));
            
            k3d::iproperty_group_collection::group sampling_group("Sampling");
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_bucket_width));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_bucket_height));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_grid_size));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_eye_splits));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_xsamples));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_ysamples));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_filter));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_filter_width));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_pixel_filter_height));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_shading_rate));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_shading_interpolation));
            sampling_group.properties.push_back(&static_cast<k3d::iproperty&>(m_render_motion_blur));

            k3d::iproperty_group_collection::group lens_group("Lens");
            lens_group.properties.push_back(&static_cast<k3d::iproperty&>(m_exposure));
            lens_group.properties.push_back(&static_cast<k3d::iproperty&>(m_gamma));
            lens_group.properties.push_back(&static_cast<k3d::iproperty&>(m_dof));
            lens_group.properties.push_back(&static_cast<k3d::iproperty&>(m_fstop));
            lens_group.properties.push_back(&static_cast<k3d::iproperty&>(m_focal_length));
            lens_group.properties.push_back(&static_cast<k3d::iproperty&>(m_focus_plane));
            
            k3d::iproperty_group_collection::group projection_group("Projection");
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_orthographic));
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_left));
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_right));
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_top));
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_bottom));
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_near));
            projection_group.properties.push_back(&static_cast<k3d::iproperty&>(m_far));

            register_property_group(output_group);
            register_property_group(sampling_group);
            register_property_group(lens_group);
            register_property_group(projection_group);

            m_orthographic.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_left.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_right.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_top.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_bottom.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_near.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_far.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
                        
            m_input_matrix.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_position.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_orientation.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            m_scale.changed_signal().connect(SigC::slot(*this, &render_engine::async_redraw_all));
            
            m_pixel_width.changed_signal().connect(SigC::slot(*this, &render_engine::on_pixel_width_changed));
            m_pixel_height.changed_signal().connect(SigC::slot(*this, &render_engine::on_pixel_height_changed));
      }

      void constrain_screen_aspect_ratio(double& Ratio)
      {
            // Constrain the aspect ratio to match our output image
            Ratio = static_cast<double>(m_pixel_width.property_value()) / static_cast<double>(m_pixel_height.property_value());
      }

      k3d::iprojection* projection()
      {
            if(m_orthographic.property_value())
                  return &m_orthographic_projection;
                  
            return &m_perspective_projection;
      }

      aspect_ratio_changed_signal_t& aspect_ratio_changed_signal()
      {
            return m_aspect_ratio_changed_signal;
      }
      
      void on_pixel_width_changed()
      {
            const unsigned long pixel_width = m_pixel_width.property_value();
            const unsigned long pixel_height = m_pixel_height.property_value();
            
            return_if_fail(pixel_height);
            const double ratio = static_cast<double>(pixel_width) / static_cast<double>(pixel_height);
            
            m_left.set_value(-0.5 * ratio * std::abs(m_top.value() - m_bottom.value()));
            m_right.set_value(0.5 * ratio * std::abs(m_top.value() - m_bottom.value()));
            
            m_aspect_ratio_changed_signal.emit();
      }

      void on_pixel_height_changed()
      {
            const unsigned long pixel_width = m_pixel_width.property_value();
            const unsigned long pixel_height = m_pixel_height.property_value();
            
            return_if_fail(pixel_width);
            const double ratio = static_cast<double>(pixel_height) / static_cast<double>(pixel_width);
            
            m_top.set_value(0.5 * ratio * std::abs(m_right.value() - m_left.value()));
            m_bottom.set_value(-0.5 * ratio * std::abs(m_right.value() - m_left.value()));
            
            m_aspect_ratio_changed_signal.emit();
      }
                  
      void on_viewport_draw(const k3d::viewport::render_state& State)
      {
            glDisable(GL_LIGHTING);
            glDisable(GL_TEXTURE_1D);
            glDisable(GL_TEXTURE_2D);

            glColor3d(0, 0, 0);
            glLineWidth(1.0f);
            glDisable(GL_LINE_STIPPLE);

            draw();
      }

      void on_viewport_select(const k3d::viewport::render_state& State)
      {
            draw();
      }

      void draw()
      {
            // Our dimensions
            const double bodylength = 0.5 * 0.5;
            const double bodywidth = 0.25 * 0.5;
            const double bodyheight = 0.25 * 0.5;
            const double lenslength = 0.25 * 0.5;
            const double lenswidth = 0.15 * 0.5;
            const double lensheight = 0.1 * 0.5;
            const double lensoffset = 0.05;
            const double filmradius = 0.2;
            const double filmwidth = 0.125 * 0.5;

            // Draw the camera body ...
            glBegin(GL_LINE_LOOP);
            glVertex3d(-bodywidth, bodyheight, bodylength);
            glVertex3d(bodywidth, bodyheight, bodylength);
            glVertex3d(bodywidth, bodyheight, -bodylength);
            glVertex3d(-bodywidth, bodyheight, -bodylength);
            glEnd();

            glBegin(GL_LINE_LOOP);
            glVertex3d(-bodywidth, -bodyheight, bodylength);
            glVertex3d(bodywidth, -bodyheight, bodylength);
            glVertex3d(bodywidth, -bodyheight, -bodylength);
            glVertex3d(-bodywidth, -bodyheight, -bodylength);
            glEnd();

            glBegin(GL_LINES);
            glVertex3d(-bodywidth, bodyheight, bodylength);
            glVertex3d(-bodywidth, -bodyheight, bodylength);
            glVertex3d(bodywidth, bodyheight, bodylength);
            glVertex3d(bodywidth, -bodyheight, bodylength);
            glVertex3d(bodywidth, bodyheight, -bodylength);
            glVertex3d(bodywidth, -bodyheight, -bodylength);
            glVertex3d(-bodywidth, bodyheight, -bodylength);
            glVertex3d(-bodywidth, -bodyheight, -bodylength);
            glEnd();

            // Draw the camera lens ...
            glBegin(GL_LINE_LOOP);
            glVertex3d(-lenswidth, lensheight, bodylength);
            glVertex3d(lenswidth, lensheight, bodylength);
            glVertex3d(lenswidth, -lensheight, bodylength);
            glVertex3d(-lenswidth, -lensheight, bodylength);
            glEnd();

            glBegin(GL_LINE_LOOP);
            glVertex3d(-lenswidth - lensoffset, lensheight + lensoffset, bodylength + lenslength);
            glVertex3d(lenswidth + lensoffset, lensheight + lensoffset, bodylength + lenslength);
            glVertex3d(lenswidth + lensoffset, -lensheight - lensoffset, bodylength + lenslength);
            glVertex3d(-lenswidth - lensoffset, -lensheight - lensoffset, bodylength + lenslength);
            glEnd();

            glBegin(GL_LINES);
            glVertex3d(-lenswidth, lensheight, bodylength);
            glVertex3d(-lenswidth - lensoffset, lensheight + lensoffset, bodylength + lenslength);
            glVertex3d(lenswidth, lensheight, bodylength);
            glVertex3d(lenswidth + lensoffset, lensheight + lensoffset, bodylength + lenslength);
            glVertex3d(lenswidth, -lensheight, bodylength);
            glVertex3d(lenswidth + lensoffset, -lensheight - lensoffset, bodylength + lenslength);
            glVertex3d(-lenswidth, -lensheight, bodylength);
            glVertex3d(-lenswidth - lensoffset, -lensheight - lensoffset, bodylength + lenslength);
            glEnd();

            // Draw the film can ...
            glBegin(GL_LINE_LOOP);
            glVertex3d(-filmwidth, bodyheight, -bodylength);
            glVertex3d(-filmwidth, bodyheight, -bodylength + filmradius);
            glVertex3d(-filmwidth, bodyheight + 0.8 * filmradius, -bodylength + 0.8 * filmradius);
            glVertex3d(-filmwidth, bodyheight + filmradius, -bodylength);
            glVertex3d(-filmwidth, bodyheight + 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(-filmwidth, bodyheight, -bodylength - filmradius);
            glVertex3d(-filmwidth, bodyheight - 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(-filmwidth, bodyheight - filmradius, -bodylength);
            glEnd();

            glBegin(GL_LINE_LOOP);
            glVertex3d(filmwidth, bodyheight, -bodylength);
            glVertex3d(filmwidth, bodyheight, -bodylength + filmradius);
            glVertex3d(filmwidth, bodyheight + 0.8 * filmradius, -bodylength + 0.8 * filmradius);
            glVertex3d(filmwidth, bodyheight + filmradius, -bodylength);
            glVertex3d(filmwidth, bodyheight + 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(filmwidth, bodyheight, -bodylength - filmradius);
            glVertex3d(filmwidth, bodyheight - 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(filmwidth, bodyheight - filmradius, -bodylength);
            glEnd();

            glBegin(GL_LINES);
            glVertex3d(-filmwidth, bodyheight, -bodylength + filmradius);
            glVertex3d(filmwidth, bodyheight, -bodylength + filmradius);
            glVertex3d(-filmwidth, bodyheight + 0.8 * filmradius, -bodylength + 0.8 * filmradius);
            glVertex3d(filmwidth, bodyheight + 0.8 * filmradius, -bodylength + 0.8 * filmradius);
            glVertex3d(-filmwidth, bodyheight + filmradius, -bodylength);
            glVertex3d(filmwidth, bodyheight + filmradius, -bodylength);
            glVertex3d(-filmwidth, bodyheight + 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(filmwidth, bodyheight + 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(-filmwidth, bodyheight, -bodylength - filmradius);
            glVertex3d(filmwidth, bodyheight, -bodylength - filmradius);
            glVertex3d(-filmwidth, bodyheight - 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(filmwidth, bodyheight - 0.8 * filmradius, -bodylength - 0.8 * filmradius);
            glVertex3d(-filmwidth, bodyheight - filmradius, -bodylength);
            glVertex3d(filmwidth, bodyheight - filmradius, -bodylength);
            glEnd();
      }

      bool render_preview()
      {
            // Keep track of compiled shaders ...
            k3d::ri::render_engine::shaders_t shaders;

            // Start a new render job ...
            k3d::irender_job& job = k3d::application().render_farm().create_job("k3d-preview");

            // Add a single render frame to the job ...
            k3d::irender_frame& frame = job.create_frame("frame");

            // Create an output image path ...
            const boost::filesystem::path outputimagepath = frame.add_output_file("outputimage");
            return_val_if_fail(!outputimagepath.empty(), false);

            // Render it (visible rendering) ...
            return_val_if_fail(render(frame, outputimagepath, true, shaders), false);

            // Start the job running ...
            k3d::application().render_farm().start_job(job);

            return true;
      }

      bool render_frame(const boost::filesystem::path& OutputImage, const bool ViewImage)
      {
            // Sanity checks ...
            return_val_if_fail(!OutputImage.empty(), false);

            // Keep track of compiled shaders ...
            k3d::ri::render_engine::shaders_t shaders;

            // Start a new render job ...
            k3d::irender_job& job = k3d::application().render_farm().create_job("k3d-render-frame");

            // Add a single render frame to the job ...
            k3d::irender_frame& frame = job.create_frame("frame");

            // Create an output image path ...
            const boost::filesystem::path outputimagepath = frame.add_output_file("outputimage");
            return_val_if_fail(!outputimagepath.empty(), false);

            // Copy the output image to its requested destination ...
            frame.add_copy_operation(outputimagepath, OutputImage);

            // View the output image when it's done ...
            if(ViewImage)
                  frame.add_view_operation(OutputImage);

            // Render it (hidden rendering) ...
            return_val_if_fail(render(frame, outputimagepath, false, shaders), false);

            // Start the job running ...
            k3d::application().render_farm().start_job(job);

            return true;
      }

      bool render_animation(const boost::filesystem::path& OutputImages, const bool ViewCompletedImages)
      {
            // Sanity checks ...
            return_val_if_fail(!OutputImages.empty(), false);

            // Ensure that the document has animation capabilities, first ...
            k3d::iproperty* const start_time_property = k3d::get_start_time(document());
            k3d::iproperty* const end_time_property = k3d::get_end_time(document());
            k3d::iproperty* const frame_rate_property = k3d::get_frame_rate(document());
            k3d::iwritable_property* const time_property = dynamic_cast<k3d::iwritable_property*>(k3d::get_time(document()));
            return_val_if_fail(start_time_property && end_time_property && frame_rate_property && time_property, false);

            // Test the output images filepath to make sure it can hold all the frames we're going to generate ...
            const double start_time = boost::any_cast<double>(k3d::get_property_value(document().dag(), *start_time_property));
            const double end_time = boost::any_cast<double>(k3d::get_property_value(document().dag(), *end_time_property));
            const double frame_rate = boost::any_cast<double>(k3d::get_property_value(document().dag(), *frame_rate_property));
            
            const long start_frame = static_cast<long>(k3d::round(frame_rate * start_time));
            const long end_frame = static_cast<long>(k3d::round(frame_rate * end_time));
            
            k3d::frames frames(OutputImages, start_frame, end_frame);
            return_val_if_fail(frames.max_frame() >= end_frame, false);

            // Keep track of compiled shaders ...
            k3d::ri::render_engine::shaders_t shaders;

            // Start a new render job ...
            k3d::irender_job& job = k3d::application().render_farm().create_job("k3d-render-animation");

            // For each frame to be rendered ...
            for(long view_frame = start_frame; view_frame < end_frame; ++view_frame)
                  {
                        // Set the frame time ...
                        time_property->set_value(view_frame / frame_rate);

                        // Redraw everything ...
                        k3d::viewport::redraw_all(document(), k3d::iviewport::SYNCHRONOUS);

                        // Add a render frame to the job ...
                        std::stringstream buffer;
                        buffer << "frame-" << std::setw(frames.frame_digits()) << std::setfill('0') << view_frame;
                        k3d::irender_frame& frame = job.create_frame(buffer.str());

                        // Create an output image path ...
                        const boost::filesystem::path outputimagepath = frame.add_output_file("outputimage");
                        return_val_if_fail(!outputimagepath.empty(), false);

                        // Copy the output image to its requested destination ...
                        boost::filesystem::path destination;
                        frames.frame(view_frame, destination);
                        frame.add_copy_operation(outputimagepath, destination);

                        // View the output image when it's done ...
                        if(ViewCompletedImages)
                              frame.add_view_operation(destination);

                        // Render it (hidden rendering) ...
                        return_val_if_fail(render(frame, outputimagepath, false, shaders), false);
                  }

            // Start the job running ...
            k3d::application().render_farm().start_job(job);

            return true;
      }

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

      static k3d::iplugin_factory& get_factory()
      {
            static k3d::plugin_factory<
                  k3d::document_plugin<render_engine>,
                         k3d::interface_list<k3d::iviewport_host,
                         k3d::interface_list<k3d::itransform_source,
                         k3d::interface_list<k3d::itransform_sink,
                         k3d::interface_list<k3d::ianimation_render_engine,
                         k3d::interface_list<k3d::istill_render_engine > > > > > > factory(
                              k3d::classes::RenderManEngine(),
                              "RenderManEngine",
                              "RenderMan Render Engine",
                              "Objects",
                              k3d::iplugin_factory::STABLE);

            return factory;
      }

private:
      bool render(k3d::irender_frame& Frame, const boost::filesystem::path& OutputImagePath, const bool VisibleRender, k3d::ri::render_engine::shaders_t& Shaders)
      {
            // Sanity checks ...
            return_val_if_fail(!OutputImagePath.empty(), false);

            // Setup global time for this frame ...
            k3d::iproperty* const frame_rate_property = k3d::get_frame_rate(document());
            k3d::iproperty* const time_property = k3d::get_time(document());
            k3d::iwritable_property* const writable_time_property = dynamic_cast<k3d::iwritable_property*>(time_property);
            return_val_if_fail(frame_rate_property && time_property && writable_time_property, false);
            
            const double frame_delta = 1.0 / boost::any_cast<double>(k3d::get_property_value(document().dag(), *frame_rate_property));
            const double frame_time = boost::any_cast<double>(k3d::get_property_value(document().dag(), *time_property));

            // Start our RIB file ...
            const std::string ribfilename("world.rib");
            const boost::filesystem::path ribfilepath = Frame.add_input_file(ribfilename);
            return_val_if_fail(!ribfilepath.empty(), false);

            // Open the RIB file stream ...
            boost::filesystem::ofstream ribfile(ribfilepath);
            return_val_if_fail(ribfile.good(), false);

            // Setup the frame for RI rendering with the user's preferred engine ...
            Frame.add_render_operation("ri", m_render_engine.property_value(), boost::filesystem::path(ribfilename, boost::filesystem::native), VisibleRender);

            // Create the Ri render engine object ...
            k3d::ri::render_engine engine(ribfile);

            // Administrivia ...
            engine.RiNewline();
            engine.RiComment("Created with K-3D Version " + k3d::to_string(VERSION) + ", http://www.k-3d.org");

            // Set path options ...
            engine.RiNewline();
            engine.RiComment("Setup file search paths");

            k3d::ri::parameter_list searchpath_options;
            searchpath_options.push_back(k3d::ri::parameter("shader", k3d::ri::UNIFORM, k3d::application().shader_cache_path().native_file_string() + ":&"));
            engine.RiOptionV("searchpath", searchpath_options);

            // Perform frame-start operations for textures
            std::for_each(document().objects().collection().begin(), document().objects().collection().end(), detail::setup_texture(Frame, engine));

            // Start the (final output) frame ...
            engine.RiNewline();
            engine.RiFrameBegin(1);

            // Set limits options
            engine.RiNewline();
            engine.RiComment("Setup options");

            k3d::ri::integers bucketsize;
            bucketsize.push_back(m_bucket_width.property_value());
            bucketsize.push_back(m_bucket_height.property_value());

            k3d::ri::parameter_list limits;
            limits.push_back(k3d::ri::parameter("gridsize", k3d::ri::UNIFORM, static_cast<k3d::ri::integer>(m_grid_size.property_value())));
            limits.push_back(k3d::ri::parameter("bucketsize", k3d::ri::UNIFORM, bucketsize, bucketsize.size()));
            limits.push_back(k3d::ri::parameter("eyesplits", k3d::ri::UNIFORM, static_cast<k3d::ri::integer>(m_eye_splits.property_value())));
            limits.push_back(k3d::ri::parameter("texturememory", k3d::ri::UNIFORM, static_cast<k3d::ri::integer>(m_texture_memory.property_value())));
            engine.RiOptionV("limits", limits);

            // Set the display type ...
            engine.RiNewline();
            engine.RiComment("Setup Display");

            boost::filesystem::path outputimage(OutputImagePath);

            if(VisibleRender)
                  engine.RiDisplayV(outputimage.leaf(), k3d::ri::RI_FRAMEBUFFER(), k3d::ri::RI_RGB());
            else
                  {
                        if(m_render_alpha.property_value())
                              engine.RiDisplayV(outputimage.leaf(), k3d::ri::RI_FILE(), k3d::ri::RI_RGBA());
                        else
                              engine.RiDisplayV(outputimage.leaf(), k3d::ri::RI_FILE(), k3d::ri::RI_RGB());
                  }

            engine.RiFormat(static_cast<int>(m_pixel_width.property_value()), static_cast<int>(m_pixel_height.property_value()), m_pixel_aspect_ratio.property_value());

            // Set pixel sampling rates ...
            engine.RiPixelSamples(m_pixel_xsamples.property_value(), m_pixel_ysamples.property_value());
            engine.RiPixelFilter(m_pixel_filter.property_value(), m_pixel_filter_width.property_value(), m_pixel_filter_height.property_value());

            // Set gain & gamma ...
            engine.RiExposure(m_exposure.property_value(), m_gamma.property_value());

            // Set depth-of-field options ...
            if(m_dof.property_value())
                  engine.RiDepthOfField(
                        m_fstop.property_value(),
                        m_focal_length.property_value(),
                        m_focus_plane.property_value());

            // Set global shading rate ...
            engine.RiShadingRate(m_shading_rate.property_value());

            // Set global shading interpolation ...
            engine.RiShadingInterpolation(m_shading_interpolation.property_value());

            // We use LH orientation, the way Our Lord Who Art In Heaven wants us to ...
            engine.RiOrientation(k3d::ri::RI_LH());

            // Double-sided surfaces ...
            engine.RiSides(m_two_sided.property_value() ? 2 : 1);

            // Crop window ...
            engine.RiCropWindow(m_crop_window_left.property_value(), m_crop_window_right.property_value(), m_crop_window_top.property_value(), m_crop_window_bottom.property_value());

            // Setup our motion-blur sampling loop ...
            k3d::ri::sample_times_t samples(1, 0.0);
            if(m_render_motion_blur.property_value())
                  samples.push_back(1.0);

            const bool motion_blur_camera = m_motion_blur.property_value();
            std::vector<k3d::vector3> motion_blur_camera_position_samples;
            std::vector<k3d::angle_axis> motion_blur_camera_orientation_samples;

            for(boost::uint32_t sample_index = 0; sample_index < samples.size(); ++sample_index)
                  {
                        // Calculate the current time and animate the document ...
                        const double sample_delta = (samples.size() > 1) ? frame_delta / static_cast<double>(samples.size() - 1) : frame_delta;
                        const double sample_time = frame_time + (sample_index * sample_delta);

                        writable_time_property->set_value(sample_time);

                        const k3d::matrix4 transform_matrix(matrix());
                        const k3d::angle_axis orientation(k3d::euler_angles(transform_matrix, k3d::euler_angles::ZXYstatic));
                        const k3d::vector3 position(k3d::extractTranslation(transform_matrix));

                        motion_blur_camera_position_samples.push_back(position);
                        motion_blur_camera_orientation_samples.push_back(orientation);

                        // Setup render state ...
                        k3d::ri::render_state state(Frame, engine, *projection(), k3d::ri::FINAL_FRAME, samples, sample_index, transform_matrix);

                        if(k3d::ri::last_sample(state))
                              {
                                    engine.RiNewline();
                                    engine.RiComment("Setup viewing transformation");
                                    
                                    if(m_orthographic.property_value())
                                          {
                                                engine.RiProjectionV("orthographic");
                                                engine.RiScreenWindow(m_left.property_value(), m_right.property_value(), m_bottom.property_value(), m_top.property_value());
                                                engine.RiClipping(m_near.property_value(), m_far.property_value());
                                          }
                                    else
                                          {
                                                engine.RiProjectionV("perspective");
                                                engine.RiScreenWindow(m_left.property_value(), m_right.property_value(), m_bottom.property_value(), m_top.property_value());
                                                engine.RiClipping(m_near.property_value(), m_far.property_value());
                                          }

                                    if(k3d::ri::motion_blur(state) && motion_blur_camera)
                                          {
                                                engine.RiMotionBeginV(state.sample_times);
                                                for(unsigned int i = 0; i < motion_blur_camera_orientation_samples.size(); ++i)
                                                      {
                                                            k3d::quaternion q(motion_blur_camera_orientation_samples[i]);
                                                            k3d::euler_angles a(q, k3d::euler_angles::ZXYstatic);
                                                            engine.RiRotate(-k3d::degrees(a[0]), 0.0f, 0.0f, 1.0f);
                                                      }
                                                engine.RiMotionEnd();
                                                
                                                engine.RiMotionBeginV(state.sample_times);
                                                for(unsigned int i = 0; i < motion_blur_camera_orientation_samples.size(); ++i)
                                                      {
                                                            k3d::quaternion q(motion_blur_camera_orientation_samples[i]);
                                                            k3d::euler_angles a(q, k3d::euler_angles::ZXYstatic);
                                                            engine.RiRotate(-k3d::degrees(a[1]), 1.0f, 0.0f, 0.0f);
                                                      }
                                                engine.RiMotionEnd();

                                                engine.RiMotionBeginV(state.sample_times);
                                                for(unsigned int i = 0; i < motion_blur_camera_orientation_samples.size(); ++i)
                                                      {
                                                            k3d::quaternion q(motion_blur_camera_orientation_samples[i]);
                                                            k3d::euler_angles a(q, k3d::euler_angles::ZXYstatic);
                                                            engine.RiRotate(-k3d::degrees(a[2]), 0.0f, 1.0f, 0.0f);
                                                      }
                                                engine.RiMotionEnd();
                                                
                                                engine.RiMotionBeginV(state.sample_times);
                                                for(unsigned int i = 0; i < motion_blur_camera_position_samples.size(); ++i)
                                                      engine.RiTranslate(-motion_blur_camera_position_samples[i][0], -motion_blur_camera_position_samples[i][1], -motion_blur_camera_position_samples[i][2]);
                                                engine.RiMotionEnd();
                                          }
                                    else
                                          {
                                                k3d::quaternion q(motion_blur_camera_orientation_samples[0]);
                                                k3d::euler_angles a(q, k3d::euler_angles::ZXYstatic);
                                                engine.RiRotate(-k3d::degrees(a[0]), 0.0f, 0.0f, 1.0f);

                                                q = k3d::quaternion(motion_blur_camera_orientation_samples[0]);
                                                a = k3d::euler_angles(q, k3d::euler_angles::ZXYstatic);
                                                engine.RiRotate(-k3d::degrees(a[1]), 1.0f, 0.0f, 0.0f);
                                                
                                                q = k3d::quaternion(motion_blur_camera_orientation_samples[0]);
                                                a = k3d::euler_angles(q, k3d::euler_angles::ZXYstatic);
                                                engine.RiRotate(-k3d::degrees(a[2]), 0.0f, 1.0f, 0.0f);
                                                
                                                engine.RiTranslate(-motion_blur_camera_position_samples[0][0], -motion_blur_camera_position_samples[0][1], -motion_blur_camera_position_samples[0][2]);
                                          }

                                    // Default shaders ...
                                    if(m_default_atmosphere_shader.interface())
                                          m_default_atmosphere_shader.interface()->setup_renderman_atmosphere_shader(state);
                                    if(m_default_interior_shader.interface())
                                          m_default_interior_shader.interface()->setup_renderman_interior_shader(state);
                                    if(m_default_exterior_shader.interface())
                                          m_default_exterior_shader.interface()->setup_renderman_exterior_shader(state);
                                    if(m_imager_shader.interface())
                                          m_imager_shader.interface()->setup_renderman_imager_shader(state);
                                          
                                    // Begin the world ...
                                    engine.RiNewline();
                                    engine.RiWorldBegin();
                              }

                        // Pre-render objects ...
                        std::for_each(document().objects().collection().begin(), document().objects().collection().end(), detail::pre_render(state));

                        // Setup lights ...
                        std::for_each(document().objects().collection().begin(), document().objects().collection().end(), detail::setup_light(state));

                        // Render objects ...
                        std::for_each(document().objects().collection().begin(), document().objects().collection().end(), detail::render(state));

                        if(k3d::ri::last_sample(state))
                              {
                                    // Finish the world ...
                                    engine.RiWorldEnd();
                              }
                  }

            // Finish the frame ...
            engine.RiFrameEnd();

            // Reset the time back to the beginning of the frame ...
            writable_time_property->set_value(frame_time);

            // Synchronize shaders ...
            const k3d::ri::render_engine::shaders_t shaders = engine.shaders();
            for(k3d::ri::render_engine::shaders_t::const_iterator shader_name = shaders.begin(); shader_name != shaders.end(); ++shader_name)
                  {
                        // If this shader has already been synchronized, we're done ...
                        if(Shaders.count(*shader_name))
                              continue;

                        // Find a matching shader ...
                        for(sdpsl::shaders_t::const_iterator shader = k3d::application().shaders().begin(); shader != k3d::application().shaders().end(); ++shader)
                              {
                                    // No match ...
                                    if(shader->name != *shader_name)
                                          continue;

                                    // Compile that bad-boy!
                                    if(!k3d::compile_shader(
                                          boost::filesystem::path(shader->file_path, boost::filesystem::native),
                                          "ri",
                                          m_render_engine.property_value()))
                                          std::cerr << "Error compiling shader [" << shader->name << "]" << std::endl;

                                    break;
                              }

                        // Keep track of this shader ...
                        Shaders.insert(*shader_name);
                  }

            return true;
      }

      k3d_list_property(std::string, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_render_engine;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_width;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_height;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_aspect_ratio;
      k3d_object_property(k3d::ri::ivolume_shader, k3d::immutable_name, k3d::with_undo, k3d::local_storage) m_default_atmosphere_shader;
      k3d_object_property(k3d::ri::ivolume_shader, k3d::immutable_name, k3d::with_undo, k3d::local_storage) m_default_interior_shader;
      k3d_object_property(k3d::ri::ivolume_shader, k3d::immutable_name, k3d::with_undo, k3d::local_storage) m_default_exterior_shader;
      k3d_object_property(k3d::ri::iimager_shader, k3d::immutable_name, k3d::with_undo, k3d::local_storage) m_imager_shader;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_orthographic;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_left;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_right;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_top;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_bottom;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_near;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_far;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_bucket_width;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_bucket_height;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_grid_size;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_eye_splits;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_texture_memory;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_render_alpha;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_xsamples;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_ysamples;
      k3d_list_property(std::string, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_pixel_filter;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_filter_width;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_pixel_filter_height;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_exposure;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_gamma;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_dof;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_fstop;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_focal_length;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_focus_plane;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_shading_rate;
      k3d_list_property(std::string, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_shading_interpolation;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_two_sided;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_crop_window_left;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_crop_window_right;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_crop_window_top;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_crop_window_bottom;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_motion_blur;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_render_motion_blur;

      aspect_ratio_changed_signal_t m_aspect_ratio_changed_signal;

      class perspective_projection :
            public k3d::iperspective
      {
      public:
            perspective_projection(k3d::iproperty& Left, k3d::iproperty& Right, k3d::iproperty& Top, k3d::iproperty& Bottom, k3d::iproperty& Near, k3d::iproperty& Far) :
                  m_left(Left),
                  m_right(Right),
                  m_top(Top),
                  m_bottom(Bottom),
                  m_near(Near),
                  m_far(Far)
            {
            }
      
            k3d::iproperty& left()
            {
                  return m_left;
            }
            
            k3d::iproperty& right()
            {
                  return m_right;
            }
            
            k3d::iproperty& top()
            {
                  return m_top;
            }
            
            k3d::iproperty& bottom()
            {
                  return m_bottom;
            }
            
            k3d::iproperty& near()
            {
                  return m_near;
            }
            
            k3d::iproperty& far()
            {
                  return m_far;
            }
            
      private:
            k3d::iproperty& m_left;
            k3d::iproperty& m_right;
            k3d::iproperty& m_top;
            k3d::iproperty& m_bottom;
            k3d::iproperty& m_near;
            k3d::iproperty& m_far;
      };
      
      class orthographic_projection :
            public k3d::iorthographic
      {
      public:
            orthographic_projection(k3d::iproperty& Left, k3d::iproperty& Right, k3d::iproperty& Top, k3d::iproperty& Bottom, k3d::iproperty& Near, k3d::iproperty& Far) :
                  m_left(Left),
                  m_right(Right),
                  m_top(Top),
                  m_bottom(Bottom),
                  m_near(Near),
                  m_far(Far)
            {
            }
      
            k3d::iproperty& left()
            {
                  return m_left;
            }
            
            k3d::iproperty& right()
            {
                  return m_right;
            }
            
            k3d::iproperty& top()
            {
                  return m_top;
            }
            
            k3d::iproperty& bottom()
            {
                  return m_bottom;
            }
            
            k3d::iproperty& near()
            {
                  return m_near;
            }
            
            k3d::iproperty& far()
            {
                  return m_far;
            }
            
      private:
            k3d::iproperty& m_left;
            k3d::iproperty& m_right;
            k3d::iproperty& m_top;
            k3d::iproperty& m_bottom;
            k3d::iproperty& m_near;
            k3d::iproperty& m_far;
      };
      
      perspective_projection m_perspective_projection;
      orthographic_projection m_orthographic_projection;

      const k3d::ilist_property<std::string>::values_t& render_engine_values()
      {
            static k3d::ilist_property<std::string>::values_t values;
            if(values.empty())
                  {
                        const k3d::ioptions::render_engines_t engines = k3d::application().options().render_engines();
                        for(k3d::ioptions::render_engines_t::const_iterator engine = engines.begin(); engine != engines.end(); ++engine)
                              {
                                    if(engine->type == "ri")
                                          values.push_back(engine->engine);
                              }
                  }
            return values;
      }

      const k3d::ilist_property<std::string>::values_t& pixel_filter_values()
      {
            static k3d::ilist_property<std::string>::values_t values;
            if(values.empty())
                  {
                        values.push_back(k3d::ri::RI_GAUSSIAN());
                        values.push_back(k3d::ri::RI_BOX());
                        values.push_back(k3d::ri::RI_TRIANGLE());
                        values.push_back(k3d::ri::RI_CATMULL_ROM());
                        values.push_back(k3d::ri::RI_SINC());
                  }
            return values;
      }

      const k3d::ilist_property<std::string>::values_t& shading_interpolation_values()
      {
            static k3d::ilist_property<std::string>::values_t values;
            if(values.empty())
                  {
                        values.push_back(k3d::ri::RI_CONSTANT());
                        values.push_back(k3d::ri::RI_SMOOTH());
                  }
            return values;
      }
};

k3d::iplugin_factory& render_engine_factory()
{
      return render_engine::get_factory();
}

} // namespace libk3drenderman



Generated by  Doxygen 1.6.0   Back to index