1
2//
3// This source file is part of appleseed.
4// Visit http://appleseedhq.net/ for additional information and resources.
5//
6// This software is released under the MIT license.
7//
8// Copyright (c) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited
9// Copyright (c) 2014-2017 Esteban Tovagliari, The appleseedhq Organization
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28//
29
30// appleseed.python headers.
31#include "pyseed.h" // has to be first, to avoid redefinition warnings
32#include "dict2dict.h"
33
34// appleseed.renderer headers.
35#include "renderer/api/frame.h"
36#include "renderer/kernel/aov/imagestack.h"
37
38// appleseed.foundation headers.
39#include "foundation/image/image.h"
40#include "foundation/image/tile.h"
41
42namespace bpy = boost::python;
43using namespace foundation;
44using namespace renderer;
45using namespace std;
46
47// Work around a regression in Visual Studio 2015 Update 3.
48#if defined(_MSC_VER) && _MSC_VER == 1900
49namespace boost
50{
51 template <> Image const volatile* get_pointer<Image const volatile>(Image const volatile* p) { return p; }
52 template <> Frame const volatile* get_pointer<Frame const volatile>(Frame const volatile* p) { return p; }
53}
54#endif
55
56namespace
57{
58 auto_release_ptr<Frame> create_frame(
59 const string& name,
60 const bpy::dict& params)
61 {
62 return FrameFactory::create(name.c_str(), bpy_dict_to_param_array(params));
63 }
64
65 void transform_tile_to_output_color_space(const Frame* frame, Tile* tile)
66 {
67 frame->transform_to_output_color_space(*tile);
68 }
69
70 void transform_image_to_output_color_space(const Frame* frame, Image* image)
71 {
72 frame->transform_to_output_color_space(*image);
73 }
74
75 bpy::object archive_frame(const Frame* frame, const char* directory)
76 {
77 char* output = 0;
78
79 if (frame->archive(directory, &output))
80 {
81 const bpy::str path(output);
82 foundation::free_string(output);
83 return path;
84 }
85
86 // Return None.
87 return bpy::object();
88 }
89
90 void copy_item_from_list(
91 const bpy::list& l,
92 const size_t index,
93 size_t& dst)
94 {
95 bpy::extract<size_t> ex(l[index]);
96 if (!ex.check())
97 {
98 PyErr_SetString(PyExc_TypeError, "Incompatible type.");
99 bpy::throw_error_already_set();
100 }
101
102 dst = ex();
103 }
104
105 void set_crop_window(Frame* frame, const bpy::list& window)
106 {
107 if (bpy::len(window) != 4)
108 {
109 PyErr_SetString(PyExc_RuntimeError, "Invalid list length given to appleseed.Frame.set_crop_window");
110 bpy::throw_error_already_set();
111 }
112
113 AABB2u crop;
114 copy_item_from_list(window, 0, crop.min[0]);
115 copy_item_from_list(window, 1, crop.min[1]);
116 copy_item_from_list(window, 2, crop.max[0]);
117 copy_item_from_list(window, 3, crop.max[1]);
118 frame->set_crop_window(crop);
119 }
120
121 bpy::list get_crop_window(const Frame* frame)
122 {
123 AABB2u window = frame->get_crop_window();
124 bpy::list result;
125 result.append(window.min[0]);
126 result.append(window.min[1]);
127 result.append(window.max[0]);
128 result.append(window.max[1]);
129 return result;
130 }
131}
132
133void bind_frame()
134{
135 bpy::class_<Frame, auto_release_ptr<Frame>, bpy::bases<Entity>, boost::noncopyable>("Frame", bpy::no_init)
136 .def("__init__", bpy::make_constructor(create_frame))
137
138 .def("reset_crop_window", &Frame::reset_crop_window)
139 .def("has_crop_window", &Frame::has_crop_window)
140 .def("set_crop_window", set_crop_window)
141 .def("get_crop_window", get_crop_window)
142
143 .def("image", &Frame::image, bpy::return_value_policy<bpy::reference_existing_object>())
144 .def("aov_images", &Frame::aov_images, bpy::return_value_policy<bpy::reference_existing_object>())
145
146 .def("transform_tile_to_output_color_space", transform_tile_to_output_color_space)
147 .def("transform_image_to_output_color_space", transform_image_to_output_color_space)
148
149 .def("clear_main_image", &Frame::clear_main_image)
150 .def("write_main_image", &Frame::write_main_image)
151 .def("write_aov_images", &Frame::write_aov_images)
152 .def("archive", archive_frame)
153 ;
154}
155