Incompatible usage of the Collada transparency value
[blender.git] / source / blender / collada / EffectExporter.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 /** \file
18  * \ingroup collada
19  */
20
21 #include <map>
22 #include <set>
23
24 #include "COLLADASWEffectProfile.h"
25 #include "COLLADAFWColorOrTexture.h"
26
27 #include "EffectExporter.h"
28 #include "DocumentExporter.h"
29 #include "MaterialExporter.h"
30
31 #include "collada_internal.h"
32 #include "collada_utils.h"
33
34 extern "C" {
35 #include "DNA_mesh_types.h"
36 #include "DNA_world_types.h"
37
38 #include "BKE_collection.h"
39 #include "BKE_customdata.h"
40 #include "BKE_mesh.h"
41 #include "BKE_material.h"
42 }
43
44 static std::string getActiveUVLayerName(Object *ob)
45 {
46   Mesh *me = (Mesh *)ob->data;
47
48   int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
49   if (num_layers) {
50     return std::string(bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV));
51   }
52
53   return "";
54 }
55
56 EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw,
57                                  BCExportSettings &export_settings,
58                                  KeyImageMap &key_image_map)
59     : COLLADASW::LibraryEffects(sw), export_settings(export_settings), key_image_map(key_image_map)
60 {
61 }
62
63 bool EffectsExporter::hasEffects(Scene *sce)
64 {
65   FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
66     int a;
67     for (a = 0; a < ob->totcol; a++) {
68       Material *ma = give_current_material(ob, a + 1);
69
70       // no material, but check all of the slots
71       if (!ma) {
72         continue;
73       }
74
75       return true;
76     }
77   }
78   FOREACH_SCENE_OBJECT_END;
79   return false;
80 }
81
82 void EffectsExporter::exportEffects(bContext *C, Scene *sce)
83 {
84   if (hasEffects(sce)) {
85     this->mContext = C;
86     this->scene = sce;
87     openLibrary();
88     MaterialFunctor mf;
89     mf.forEachMaterialInExportSet<EffectsExporter>(
90         sce, *this, this->export_settings.get_export_set());
91
92     closeLibrary();
93   }
94 }
95
96 void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
97 {
98   /* XXX check if BLINN and PHONG can be supported as well */
99   ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
100 }
101
102 void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
103 {
104   double alpha = bc_get_alpha(ma);
105   if (alpha < 1) {
106     // workaround use <transparent> to avoid wrong handling of <transparency> by other tools
107     COLLADASW::ColorOrTexture cot = bc_get_cot(0, 0, 0, alpha);
108     ep.setTransparent(cot, false, "alpha");
109     ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
110   }
111 }
112
113 void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
114 {
115   // get diffuse color
116   COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
117   ep.setDiffuse(cot, false, "diffuse");
118 }
119
120 void EffectsExporter::set_ambient(COLLADASW::EffectProfile &ep, Material *ma)
121 {
122   // get diffuse color
123   COLLADASW::ColorOrTexture cot = bc_get_ambient(ma);
124   ep.setAmbient(cot, false, "ambient");
125 }
126 void EffectsExporter::set_specular(COLLADASW::EffectProfile &ep, Material *ma)
127 {
128   // get diffuse color
129   COLLADASW::ColorOrTexture cot = bc_get_specular(ma);
130   ep.setSpecular(cot, false, "specular");
131 }
132 void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma)
133 {
134   // get diffuse color
135   COLLADASW::ColorOrTexture cot = bc_get_reflective(ma);
136   ep.setReflective(cot, false, "reflective");
137 }
138
139 void EffectsExporter::set_reflectivity(COLLADASW::EffectProfile &ep, Material *ma)
140 {
141   double reflectivity = bc_get_reflectivity(ma);
142   if (reflectivity > 0.0) {
143     ep.setReflectivity(reflectivity, false, "specular");
144   }
145 }
146
147 void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
148 {
149   COLLADASW::ColorOrTexture cot = bc_get_emission(ma);
150   ep.setEmission(cot, false, "emission");
151 }
152
153 void EffectsExporter::set_ior(COLLADASW::EffectProfile &ep, Material *ma)
154 {
155   double alpha = bc_get_ior(ma);
156   ep.setIndexOfRefraction(alpha, false, "ior");
157 }
158
159 void EffectsExporter::set_shininess(COLLADASW::EffectProfile &ep, Material *ma)
160 {
161   double shininess = bc_get_shininess(ma);
162   ep.setShininess(shininess, false, "shininess");
163 }
164
165 void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
166 {
167   if (!ma->use_nodes) {
168     return;
169   }
170
171   MaterialNode material = MaterialNode(mContext, ma, key_image_map);
172   Image *image = material.get_diffuse_image();
173   if (image == nullptr) {
174     return;
175   }
176
177   std::string uid(id_name(image));
178   std::string key = translate_id(uid);
179
180   if (material_image_map.find(key) == material_image_map.end()) {
181     material_image_map[key] = image;
182     key_image_map[key] = image;
183   }
184 }
185
186 void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep,
187                                             KeyImageMap &material_image_map,
188                                             std::string &active_uv)
189 {
190   KeyImageMap::iterator iter;
191
192   for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
193
194     Image *image = iter->second;
195     std::string uid(id_name(image));
196     std::string key = translate_id(uid);
197
198     COLLADASW::Sampler *sampler = new COLLADASW::Sampler(
199         COLLADASW::Sampler::SAMPLER_TYPE_2D,
200         key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
201         key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
202
203     sampler->setImageId(key);
204
205     ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
206   }
207 }
208
209 void EffectsExporter::operator()(Material *ma, Object *ob)
210 {
211   KeyImageMap material_image_map;
212
213   openEffect(get_effect_id(ma));
214
215   COLLADASW::EffectProfile ep(mSW);
216   ep.setProfileType(COLLADASW::EffectProfile::COMMON);
217   ep.openProfile();
218   set_shader_type(ep, ma);  // creates a Lambert Shader for now
219
220   COLLADASW::ColorOrTexture cot;
221
222   set_diffuse_color(ep, ma);
223   set_emission(ep, ma);
224   set_ior(ep, ma);
225   set_reflectivity(ep, ma);
226   set_transparency(ep, ma);
227
228   /* TODO: */
229   // set_shininess(ep, ma); shininess not supported for lambert
230   // set_ambient(ep, ma);
231   // set_specular(ep, ma);
232
233   get_images(ma, material_image_map);
234   std::string active_uv(getActiveUVLayerName(ob));
235   create_image_samplers(ep, material_image_map, active_uv);
236
237 #if 0
238   unsigned int a, b;
239   for (a = 0, b = 0; a < tex_indices.size(); a++) {
240     MTex *t = ma->mtex[tex_indices[a]];
241     Image *ima = t->tex->ima;
242
243     // Image not set for texture
244     if (!ima) {
245       continue;
246     }
247
248     std::string key(id_name(ima));
249     key = translate_id(key);
250
251     // create only one <sampler>/<surface> pair for each unique image
252     if (im_samp_map.find(key) == im_samp_map.end()) {
253       //<newparam> <sampler> <source>
254       COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
255                                  key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
256                                  key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
257       sampler.setImageId(key);
258       // copy values to arrays since they will live longer
259       samplers[a] = sampler;
260
261       // store pointers so they can be used later when we create <texture>s
262       samp_surf[b] = &samplers[a];
263       //samp_surf[b][1] = &surfaces[a];
264
265       im_samp_map[key] = b;
266       b++;
267     }
268   }
269
270   for (a = 0; a < tex_indices.size(); a++) {
271     MTex *t = ma->mtex[tex_indices[a]];
272     Image *ima = t->tex->ima;
273
274     if (!ima) {
275       continue;
276     }
277
278     std::string key(id_name(ima));
279     key = translate_id(key);
280     int i = im_samp_map[key];
281     std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
282     COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)
283         samp_surf[i];  // possibly uninitialized memory ...
284     writeTextures(ep, key, sampler, t, ima, uvname);
285   }
286 #endif
287
288   // performs the actual writing
289   ep.addProfileElements();
290   ep.addExtraTechniques(mSW);
291
292   ep.closeProfile();
293   closeEffect();
294 }
295
296 COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
297                                                          std::string &uv_layer_name,
298                                                          COLLADASW::Sampler *sampler
299                                                          /*COLLADASW::Surface *surface*/)
300 {
301
302   COLLADASW::Texture texture(translate_id(id_name(ima)));
303   texture.setTexcoord(uv_layer_name);
304   // texture.setSurface(*surface);
305   texture.setSampler(*sampler);
306
307   COLLADASW::ColorOrTexture cot(texture);
308   return cot;
309 }
310
311 COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a)
312 {
313   COLLADASW::Color color(r, g, b, a);
314   COLLADASW::ColorOrTexture cot(color);
315   return cot;
316 }