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 "bindentitycontainers.h"
33#include "dict2dict.h"
34#include "unalignedtransform.h"
35
36// appleseed.renderer headers.
37#include "renderer/api/object.h"
38#include "renderer/api/scene.h"
39
40// appleseed.foundation headers.
41#include "foundation/utility/api/specializedapiarrays.h"
42#include "foundation/utility/searchpaths.h"
43
44namespace bpy = boost::python;
45using namespace foundation;
46using namespace renderer;
47using namespace std;
48
49// Work around a regression in Visual Studio 2015 Update 3.
50#if defined(_MSC_VER) && _MSC_VER == 1900
51namespace boost
52{
53 template <> Object const volatile* get_pointer<Object const volatile>(Object const volatile* p) { return p; }
54 template <> ObjectInstance const volatile* get_pointer<ObjectInstance const volatile>(ObjectInstance const volatile* p) { return p; }
55}
56#endif
57
58namespace
59{
60 void bpy_list_to_string_array(const bpy::list& l, StringArray& strings)
61 {
62 strings.clear();
63
64 for (bpy::ssize_t i = 0, e = bpy::len(l); i < e; ++i)
65 {
66 bpy::extract<const char*> ex(l[i]);
67 if (!ex.check())
68 {
69 PyErr_SetString(PyExc_TypeError, "Incompatible type. Only strings.");
70 bpy::throw_error_already_set();
71 }
72
73 strings.push_back(ex());
74 }
75 }
76
77 bpy::list obj_material_slots(const Object* obj)
78 {
79 bpy::list result;
80
81 for (size_t i = 0, e = obj->get_material_slot_count(); i < e; ++i)
82 result.append(obj->get_material_slot(i));
83
84 return result;
85 }
86
87 auto_release_ptr<ObjectInstance> create_obj_instance_with_back_mat(
88 const string& name,
89 const bpy::dict& params,
90 const string& object_name,
91 const UnalignedTransformd& transform,
92 const bpy::dict& front_material_mappings,
93 const bpy::dict& back_material_mappings)
94 {
95 return
96 ObjectInstanceFactory::create(
97 name.c_str(),
98 bpy_dict_to_param_array(params),
99 object_name.c_str(),
100 transform.as_foundation_transform(),
101 bpy_dict_to_dictionary(front_material_mappings).strings(),
102 bpy_dict_to_dictionary(back_material_mappings).strings());
103 }
104
105 auto_release_ptr<ObjectInstance> create_obj_instance(
106 const string& name,
107 const bpy::dict& params,
108 const string& object_name,
109 const UnalignedTransformd& transform,
110 const bpy::dict& front_material_mappings)
111 {
112 return
113 create_obj_instance_with_back_mat(
114 name,
115 params,
116 object_name,
117 transform,
118 front_material_mappings,
119 bpy::dict());
120 }
121
122 UnalignedTransformd obj_inst_get_transform(const ObjectInstance* obj)
123 {
124 return UnalignedTransformd(obj->get_transform());
125 }
126
127 string obj_inst_get_obj_name(const ObjectInstance* obj)
128 {
129 return obj->get_object_name();
130 }
131
132 bpy::dict material_mappings_to_dict(const StringDictionary& mappings)
133 {
134 bpy::dict result;
135
136 for (const_each<StringDictionary> it = mappings; it; ++it)
137 result[it->key()] = it->value();
138
139 return result;
140 }
141
142 bpy::dict obj_inst_get_front_material_mappings(const ObjectInstance* obj)
143 {
144 return material_mappings_to_dict(obj->get_front_material_mappings());
145 }
146
147 bpy::dict obj_inst_get_back_material_mappings(const ObjectInstance* obj)
148 {
149 return material_mappings_to_dict(obj->get_back_material_mappings());
150 }
151}
152
153void bind_object()
154{
155 bpy::class_<Object, auto_release_ptr<Object>, bpy::bases<Entity>, boost::noncopyable>("Object", bpy::no_init)
156 .def("get_model", &Object::get_model)
157 .def("compute_local_bbox", &Object::compute_local_bbox)
158 .def("material_slots", &obj_material_slots)
159 .def("get_material_slot_count", &Object::get_material_slot_count)
160 .def("get_material_slot", &Object::get_material_slot)
161 ;
162
163 bind_typed_entity_vector<Object>("ObjectContainer");
164
165 bpy::class_<ObjectInstance, auto_release_ptr<ObjectInstance>, bpy::bases<Entity>, boost::noncopyable>("ObjectInstance", bpy::no_init)
166 .def("__init__", bpy::make_constructor(create_obj_instance))
167 .def("__init__", bpy::make_constructor(create_obj_instance_with_back_mat))
168 .def("get_object_name", &obj_inst_get_obj_name)
169 .def("find_object", &ObjectInstance::find_object, bpy::return_value_policy<bpy::reference_existing_object>())
170 .def("get_transform", &obj_inst_get_transform)
171 .def("bbox", &ObjectInstance::compute_parent_bbox)
172 .def("get_front_material_mappings", &obj_inst_get_front_material_mappings)
173 .def("get_back_material_mappings", &obj_inst_get_back_material_mappings)
174 ;
175
176 bind_typed_entity_vector<ObjectInstance>("ObjectInstanceContainer");
177}
178