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