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
35// appleseed.renderer headers.
36#include "renderer/api/shadergroup.h"
37
38// appleseed.foundation headers.
39#include "foundation/utility/api/specializedapiarrays.h"
40#include "foundation/utility/autoreleaseptr.h"
41#include "foundation/utility/searchpaths.h"
42
43// Standard headers.
44#include <cstddef>
45#include <string>
46
47namespace bpy = boost::python;
48using namespace foundation;
49using namespace renderer;
50using namespace std;
51
52// Work around a regression in Visual Studio 2015 Update 3.
53#if defined(_MSC_VER) && _MSC_VER == 1900
54namespace boost
55{
56 template <> ShaderGroup const volatile* get_pointer<ShaderGroup const volatile>(ShaderGroup const volatile* p) { return p; }
57}
58#endif
59
60namespace
61{
62 auto_release_ptr<ShaderGroup> create_shader_group(const string& name)
63 {
64 return ShaderGroupFactory::create(name.c_str());
65 }
66
67 void add_shader(
68 ShaderGroup* sg,
69 const string& type,
70 const string& name,
71 const string& layer,
72 bpy::dict params)
73 {
74 sg->add_shader(type.c_str(), name.c_str(), layer.c_str(), bpy_dict_to_param_array(params));
75 }
76
77 // A wrapper class that contains a ShaderQuery and a SearchPaths.
78 class ShaderQueryWrapper
79 : public boost::noncopyable
80 {
81 public:
82 ShaderQueryWrapper()
83 {
84 m_shader_query = ShaderQueryFactory::create();
85 }
86
87 explicit ShaderQueryWrapper(const char* search_path)
88 {
89 m_shader_query = ShaderQueryFactory::create(search_path);
90 }
91
92 explicit ShaderQueryWrapper(bpy::list search_paths)
93 {
94 for (bpy::ssize_t i = 0, e = bpy::len(search_paths); i < e; ++i)
95 {
96 const bpy::extract<const char*> extractor(search_paths[i]);
97 if (extractor.check())
98 m_search_paths.push_back(extractor());
99 else
100 {
101 PyErr_SetString(PyExc_TypeError, "Incompatible type. Only strings accepted.");
102 bpy::throw_error_already_set();
103 }
104 }
105
106 m_shader_query = ShaderQueryFactory::create(m_search_paths);
107 }
108
109 bool open(const char* shader_name)
110 {
111 return m_shader_query->open(shader_name);
112 }
113
114 string get_shader_name() const
115 {
116 return m_shader_query->get_shader_name();
117 }
118
119 string get_shader_type() const
120 {
121 return m_shader_query->get_shader_type();
122 }
123
124 size_t get_param_count() const
125 {
126 return m_shader_query->get_param_count();
127 }
128
129 bpy::dict get_param_info(const size_t param_index) const
130 {
131 return dictionary_to_bpy_dict(
132 m_shader_query->get_param_info(param_index));
133 }
134
135 bpy::dict get_metadata() const
136 {
137 return dictionary_to_bpy_dict(
138 m_shader_query->get_metadata());
139 }
140
141 private:
142 SearchPaths m_search_paths;
143 auto_release_ptr<ShaderQuery> m_shader_query;
144 };
145}
146
147void bind_shader_group()
148{
149 bpy::class_<ShaderGroup, auto_release_ptr<ShaderGroup>, bpy::bases<Entity>, boost::noncopyable>("ShaderGroup", bpy::no_init)
150 .def("__init__", bpy::make_constructor(create_shader_group))
151 .def("add_shader", add_shader)
152 .def("add_connection", &ShaderGroup::add_connection)
153 .def("clear", &ShaderGroup::clear)
154 ;
155
156 bpy::class_<ShaderQueryWrapper, boost::noncopyable>("ShaderQuery")
157 .def(bpy::init<const char*>())
158 .def(bpy::init<bpy::list>())
159 .def("open", &ShaderQueryWrapper::open)
160 .def("get_shader_name", &ShaderQueryWrapper::get_shader_name)
161 .def("get_shader_type", &ShaderQueryWrapper::get_shader_type)
162 .def("get_num_params", &ShaderQueryWrapper::get_param_count)
163 .def("get_param_info", &ShaderQueryWrapper::get_param_info)
164 .def("get_metadata", &ShaderQueryWrapper::get_metadata)
165 ;
166
167 bind_typed_entity_vector<ShaderGroup>("ShaderGroupContainer");
168}
169