Merge branch 'blender2.7'
[blender.git] / source / blender / collada / Materials.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 #include "Materials.h"
18
19 MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) :
20         mContext(C),
21         material(ma),
22         effect(nullptr),
23         key_image_map(&key_image_map)
24 {
25         ntree = prepare_material_nodetree();
26         setShaderType();
27 }
28
29 MaterialNode::MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map) :
30         mContext(C),
31         material(ma),
32         effect(ef),
33         uid_image_map(&uid_image_map)
34 {
35         ntree = prepare_material_nodetree();
36         setShaderType();
37
38         std::map<std::string, bNode *> nmap;
39 #if 0
40         nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
41         nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
42         nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
43         nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
44         nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
45         nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
46         nmap["out"]->flag &= ~NODE_SELECT;
47
48         add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
49         add_link(ntree, nmap["main"], 0, nmap["add"], 1);
50         add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
51         add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
52
53         add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
54         // experimental, probably not used.
55         make_group(C, ntree, nmap);
56 #else
57         shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
58         output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
59         add_link(shader_node, 0, output_node, 0);
60 #endif
61 }
62
63 void MaterialNode::setShaderType()
64 {
65 #if 0
66         COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
67         // Currently we only support PBR based shaders
68         // TODO: simulate the effects with PBR
69
70         // blinn
71         if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
72                 ma->spec_shader = MA_SPEC_BLINN;
73                 ma->spec = ef->getShininess().getFloatValue();
74         }
75         // phong
76         else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
77                 ma->spec_shader = MA_SPEC_PHONG;
78                 ma->har = ef->getShininess().getFloatValue();
79         }
80         // lambert
81         else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
82                 ma->diff_shader = MA_DIFF_LAMBERT;
83         }
84         // default - lambert
85         else {
86                 ma->diff_shader = MA_DIFF_LAMBERT;
87                 fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
88         }
89 #endif
90 }
91
92 bNodeTree *MaterialNode::prepare_material_nodetree()
93 {
94         if (material->nodetree == NULL) {
95                 material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
96                 material->use_nodes = true;
97         }
98         return material->nodetree;
99 }
100
101 bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
102 {
103         bNode *node = nodeAddStaticNode(mContext, ntree, node_type);
104         if (node) {
105                 if (label.length() > 0) {
106                         strcpy(node->label, label.c_str());
107                 }
108                 node->locx = locx;
109                 node->locy = locy;
110                 node->flag |= NODE_SELECT;
111         }
112         node_map[label] = node;
113         return node;
114 }
115
116 void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index)
117 {
118         bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
119         bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
120
121         nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
122 }
123
124 void MaterialNode::set_reflectivity(float val)
125 {
126         material->metallic = val;
127         bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_METALLIC);
128         *(float *)socket->default_value = val;
129 }
130
131 void MaterialNode::set_ior(float val)
132 {
133         bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_IOR);
134         *(float *)socket->default_value = val;
135 }
136
137 void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label)
138 {
139         int locy = -300 * (node_map.size()-2);
140         if (cot.isColor()) {
141                 COLLADAFW::Color col = cot.getColor();
142                 bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_DIFFUSE);
143                 float *fcol = (float *)socket->default_value;
144
145                 fcol[0] = material->r = col.getRed();
146                 fcol[1] = material->g = col.getGreen();
147                 fcol[2] = material->b = col.getBlue();
148                 fcol[3] = material->a = col.getAlpha();
149         }
150         else if (cot.isTexture()) {
151                 bNode *texture_node = add_texture_node(cot, -300, locy, label);
152                 if (texture_node != NULL) {
153                         add_link(texture_node, 0, shader_node, 0);
154                 }
155         }
156 }
157
158 Image *MaterialNode::get_diffuse_image()
159 {
160         bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
161         if (shader == nullptr) {
162                 return nullptr;
163         }
164
165         bNodeSocket *in_socket = (bNodeSocket *)BLI_findlink(&shader->inputs, BC_PBR_DIFFUSE);
166         if (in_socket == nullptr) {
167                 return nullptr;
168         }
169
170         bNodeLink *link = in_socket->link;
171         if (link == nullptr) {
172                 return nullptr;
173         }
174
175         bNode *texture = link->fromnode;
176         if (texture == nullptr) {
177                 return nullptr;
178         }
179
180         if (texture->type != SH_NODE_TEX_IMAGE) {
181                 return nullptr;
182         }
183
184         Image *image = (Image *)texture->id;
185         return image;
186
187 }
188
189 static bNodeSocket *set_color(bNode *node, COLLADAFW::Color col)
190 {
191                 bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
192                 float *fcol = (float *)socket->default_value;
193                 fcol[0] = col.getRed();
194                 fcol[1] = col.getGreen();
195                 fcol[2] = col.getBlue();
196
197                 return socket;
198 }
199
200 void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label)
201 {
202         int locy = -300 * (node_map.size() - 2);
203         if (cot.isColor()) {
204                 COLLADAFW::Color col = cot.getColor();
205                 bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
206                 set_color(node, col);
207                 // TODO: Connect node
208         }
209         // texture
210         else if (cot.isTexture()) {
211                 add_texture_node(cot, -300, locy, label);
212                 // TODO: Connect node
213         }
214 }
215 void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label)
216 {
217         int locy = -300 * (node_map.size() - 2);
218         if (cot.isColor()) {
219                 COLLADAFW::Color col = cot.getColor();
220                 bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
221                 set_color(node, col);
222                 // TODO: Connect node
223         }
224         // texture
225         else if (cot.isTexture()) {
226                 add_texture_node(cot, -300, locy, label);
227                 // TODO: Connect node
228         }
229 }
230
231 void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot, std::string label)
232 {
233         int locy = -300 * (node_map.size() - 2);
234         if (cot.isColor()) {
235                 COLLADAFW::Color col = cot.getColor();
236                 bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
237                 set_color(node, col);
238                 // TODO: Connect node
239         }
240         // texture
241         else if (cot.isTexture()) {
242                 add_texture_node(cot, -300, locy, label);
243                 // TODO: Connect node
244         }
245 }
246
247 void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label)
248 {
249         if (effect == nullptr) {
250                 return;
251         }
252
253         int locy = -300 * (node_map.size() - 2);
254         if (cot.isColor()) {
255                 COLLADAFW::Color col = effect->getTransparent().getColor();
256                 float alpha = effect->getTransparency().getFloatValue();
257
258                 if (col.isValid()) {
259                         alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
260                 }
261                 if (col.isValid() || alpha < 1.0) {
262                         // not sure what to do here
263                 }
264
265                 bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
266                 set_color(node, col);
267                 // TODO: Connect node
268         }
269         // texture
270         else if (cot.isTexture()) {
271                 add_texture_node(cot, -300, locy, label);
272                 // TODO: Connect node
273         }
274 }
275
276 void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot, std::string label)
277 {
278         int locy = -300 * (node_map.size() - 2);
279         if (cot.isColor()) {
280                 COLLADAFW::Color col = cot.getColor();
281                 material->specr = col.getRed();
282                 material->specg = col.getGreen();
283                 material->specb = col.getBlue();
284
285                 bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
286                 set_color(node, col);
287                 // TODO: Connect node
288         }
289         // texture
290         else if (cot.isTexture()) {
291                 add_texture_node(cot, -300, locy, label);
292                 // TODO: Connect node
293         }
294 }
295
296 bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label)
297 {
298         if (effect == nullptr) {
299                 return nullptr;
300         }
301
302         UidImageMap &image_map = *uid_image_map;
303
304         COLLADAFW::Texture ctex = cot.getTexture();
305
306         COLLADAFW::SamplerPointerArray& samp_array = effect->getSamplerPointerArray();
307         COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
308
309         const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage();
310
311         if (image_map.find(ima_uid) == image_map.end()) {
312                 fprintf(stderr, "Couldn't find an image by UID.\n");
313                 return NULL;
314         }
315
316         Image *ima = image_map[ima_uid];
317         bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
318         texture_node->id = &ima->id;
319         return texture_node;
320
321 }