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