1
2 //
3 // This source file is part of appleseed.
4 // Visit https://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-2018 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 "bindentitycontainers.h"
32 #include "dict2dict.h"
33 #include "metadata.h"
34 #include "unalignedtransform.h"
35
36 // appleseed.renderer headers.
37 #include "renderer/api/scene.h"
38 #include "renderer/api/texture.h"
39
40 // appleseed.foundation headers.
41 #include "foundation/platform/python.h"
42 #include "foundation/utility/searchpaths.h"
43
44 namespace bpy = boost::python;
45 using namespace foundation;
46 using namespace renderer;
47 using namespace std;
48
49 // Work around a regression in Visual Studio 2015 Update 3.
50 #if defined(_MSC_VER) && _MSC_VER == 1900
51 namespace boost
52 {
get_pointer(Texture const volatile * p)53 template <> Texture const volatile* get_pointer<Texture const volatile>(Texture const volatile* p) { return p; }
get_pointer(ITextureFactory const volatile * p)54 template <> ITextureFactory const volatile* get_pointer<ITextureFactory const volatile>(ITextureFactory const volatile* p) { return p; }
get_pointer(TextureFactoryRegistrar const volatile * p)55 template <> TextureFactoryRegistrar const volatile* get_pointer<TextureFactoryRegistrar const volatile>(TextureFactoryRegistrar const volatile* p) { return p; }
get_pointer(TextureInstance const volatile * p)56 template <> TextureInstance const volatile* get_pointer<TextureInstance const volatile>(TextureInstance const volatile* p) { return p; }
57 }
58 #endif
59
60 namespace
61 {
string_list_to_search_paths(const bpy::list & search_paths,SearchPaths & paths)62 void string_list_to_search_paths(
63 const bpy::list& search_paths,
64 SearchPaths& paths)
65 {
66 for (bpy::ssize_t i = 0, e = bpy::len(search_paths); i < e; ++i)
67 {
68 bpy::extract<const char*> extractor(search_paths[i]);
69 if (extractor.check())
70 paths.push_back_explicit_path(extractor());
71 else
72 {
73 PyErr_SetString(PyExc_TypeError, "Incompatible type. Only strings accepted.");
74 bpy::throw_error_already_set();
75 }
76 }
77 }
78
create_texture(const string & model,const string & name,const bpy::dict & params,const bpy::list & search_paths)79 auto_release_ptr<Texture> create_texture(
80 const string& model,
81 const string& name,
82 const bpy::dict& params,
83 const bpy::list& search_paths)
84 {
85 TextureFactoryRegistrar factories;
86 const ITextureFactory* factory = factories.lookup(model.c_str());
87
88 if (factory)
89 {
90 SearchPaths paths;
91 string_list_to_search_paths(search_paths, paths);
92
93 return factory->create(name.c_str(), bpy_dict_to_param_array(params), paths);
94 }
95 else
96 {
97 PyErr_SetString(PyExc_RuntimeError, "Texture model not found");
98 bpy::throw_error_already_set();
99 }
100
101 return auto_release_ptr<Texture>();
102 }
103
factory_create_texture(const ITextureFactory * factory,const char * name,const bpy::dict & params,const bpy::list & search_paths)104 auto_release_ptr<Texture> factory_create_texture(
105 const ITextureFactory* factory,
106 const char* name,
107 const bpy::dict& params,
108 const bpy::list& search_paths)
109 {
110 SearchPaths paths;
111 string_list_to_search_paths(search_paths, paths);
112
113 return factory->create(name, bpy_dict_to_param_array(params), paths);
114 }
115
create_texture_instance(const string & name,const bpy::dict & params,const string & texture_name,const UnalignedTransformf & transform)116 auto_release_ptr<TextureInstance> create_texture_instance(
117 const string& name,
118 const bpy::dict& params,
119 const string& texture_name,
120 const UnalignedTransformf& transform)
121 {
122 return
123 TextureInstanceFactory::create(
124 name.c_str(),
125 bpy_dict_to_param_array(params),
126 texture_name.c_str(),
127 transform.as_foundation_transform());
128 }
129
texture_inst_get_transform(const TextureInstance * tx)130 UnalignedTransformf texture_inst_get_transform(const TextureInstance* tx)
131 {
132 return UnalignedTransformf(tx->get_transform());
133 }
134
texture_inst_get_texture_name(const TextureInstance * tx)135 string texture_inst_get_texture_name(const TextureInstance* tx)
136 {
137 return tx->get_texture_name();
138 }
139 }
140
bind_texture()141 void bind_texture()
142 {
143 bpy::enum_<TextureAddressingMode>("TextureAddressingMode")
144 .value("Clamp", TextureAddressingClamp)
145 .value("Wrap", TextureAddressingWrap);
146
147 bpy::enum_<TextureFilteringMode>("TextureFilteringMode")
148 .value("Nearest", TextureFilteringNearest)
149 .value("Bilinear", TextureFilteringBilinear)
150 .value("Bicubic", TextureFilteringBicubic)
151 .value("Feline", TextureFilteringFeline)
152 .value("EWA", TextureFilteringEWA);
153
154 bpy::enum_<TextureAlphaMode>("TextureAlphaMode")
155 .value("AlphaChannel", TextureAlphaModeAlphaChannel)
156 .value("Luminance", TextureAlphaModeLuminance)
157 .value("Detect", TextureAlphaModeDetect);
158
159 bpy::class_<Texture, auto_release_ptr<Texture>, bpy::bases<Entity>, boost::noncopyable>("Texture", bpy::no_init)
160 .def("get_model_metadata", &detail::get_entity_model_metadata<TextureFactoryRegistrar>).staticmethod("get_model_metadata")
161 .def("get_input_metadata", &detail::get_entity_input_metadata<TextureFactoryRegistrar>).staticmethod("get_input_metadata")
162 .def("__init__", bpy::make_constructor(create_texture))
163 .def("get_model", &Texture::get_model)
164 .def("get_color_space", &Texture::get_color_space);
165
166 bind_typed_entity_vector<Texture>("TextureContainer");
167
168 bpy::class_<TextureInstance, auto_release_ptr<TextureInstance>, bpy::bases<Entity>, boost::noncopyable>("TextureInstance", bpy::no_init)
169 .def("__init__", bpy::make_constructor(create_texture_instance))
170 .def("get_addressing_mode", &TextureInstance::get_addressing_mode)
171 .def("get_alpha_mode", &TextureInstance::get_alpha_mode)
172 .def("get_filtering_mode", &TextureInstance::get_filtering_mode)
173 .def("get_transform", &texture_inst_get_transform)
174 .def("get_texture_name", &texture_inst_get_texture_name)
175 .def("find_texture", &TextureInstance::find_texture, bpy::return_value_policy<bpy::reference_existing_object>());
176
177 bind_typed_entity_vector<TextureInstance>("TextureInstanceContainer");
178
179 bpy::class_<ITextureFactory, boost::noncopyable>("ITextureFactory", bpy::no_init)
180 .def("create", &factory_create_texture);
181
182 bpy::class_<TextureFactoryRegistrar, boost::noncopyable>("TextureFactoryRegistrar", bpy::no_init)
183 .def("lookup", &TextureFactoryRegistrar::lookup, bpy::return_value_policy<bpy::reference_existing_object>());
184 }
185