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