a784776d34209c7e0f3ec2c6572328142d522105
[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   ep.setTransparency(alpha, false, "alpha");
106 }
107
108 void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
109 {
110   // get diffuse color
111   COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
112   ep.setDiffuse(cot, false, "diffuse");
113 }
114
115 void EffectsExporter::set_ambient(COLLADASW::EffectProfile &ep, Material *ma)
116 {
117   // get diffuse color
118   COLLADASW::ColorOrTexture cot = bc_get_ambient(ma);
119   ep.setAmbient(cot, false, "ambient");
120 }
121 void EffectsExporter::set_specular(COLLADASW::EffectProfile &ep, Material *ma)
122 {
123   // get diffuse color
124   COLLADASW::ColorOrTexture cot = bc_get_specular(ma);
125   ep.setSpecular(cot, false, "specular");
126 }
127 void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma)
128 {
129   // get diffuse color
130   COLLADASW::ColorOrTexture cot = bc_get_reflective(ma);
131   ep.setReflective(cot, false, "reflective");
132 }
133
134 void EffectsExporter::set_reflectivity(COLLADASW::EffectProfile &ep, Material *ma)
135 {
136   double reflectivity = bc_get_reflectivity(ma);
137   ep.setReflectivity(reflectivity, false, "specular");
138 }
139
140 void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
141 {
142   COLLADASW::ColorOrTexture cot = bc_get_emission(ma);
143   ep.setEmission(cot, false, "emission");
144 }
145
146 void EffectsExporter::set_ior(COLLADASW::EffectProfile &ep, Material *ma)
147 {
148   double alpha = bc_get_ior(ma);
149   ep.setIndexOfRefraction(alpha, false, "ior");
150 }
151
152 void EffectsExporter::set_shininess(COLLADASW::EffectProfile &ep, Material *ma)
153 {
154   double shininess = bc_get_shininess(ma);
155   ep.setShininess(shininess, false, "shininess");
156 }
157
158 void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
159 {
160   if (!ma->use_nodes) {
161     return;
162   }
163
164   MaterialNode material = MaterialNode(mContext, ma, key_image_map);
165   Image *image = material.get_diffuse_image();
166   if (image == nullptr) {
167     return;
168   }
169
170   std::string uid(id_name(image));
171   std::string key = translate_id(uid);
172
173   if (material_image_map.find(key) == material_image_map.end()) {
174     material_image_map[key] = image;
175     key_image_map[key] = image;
176   }
177 }
178
179 void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep,
180                                             KeyImageMap &material_image_map,
181                                             std::string &active_uv)
182 {
183   KeyImageMap::iterator iter;
184
185   for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
186
187     Image *image = iter->second;
188     std::string uid(id_name(image));
189     std::string key = translate_id(uid);
190
191     COLLADASW::Sampler *sampler = new COLLADASW::Sampler(
192         COLLADASW::Sampler::SAMPLER_TYPE_2D,
193         key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
194         key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
195
196     sampler->setImageId(key);
197
198     ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
199   }
200 }
201
202 void EffectsExporter::operator()(Material *ma, Object *ob)
203 {
204   KeyImageMap material_image_map;
205
206   openEffect(get_effect_id(ma));
207
208   COLLADASW::EffectProfile ep(mSW);
209   ep.setProfileType(COLLADASW::EffectProfile::COMMON);
210   ep.openProfile();
211   set_shader_type(ep, ma);  // creates a Lambert Shader for now
212
213   COLLADASW::ColorOrTexture cot;
214
215   set_diffuse_color(ep, ma);
216   set_emission(ep, ma);
217   set_ior(ep, ma);
218   set_reflectivity(ep, ma);
219   set_transparency(ep, ma);
220
221   /* TODO: */
222   // set_shininess(ep, ma); shininess not supported for lambert
223   // set_ambient(ep, ma);
224   // set_specular(ep, ma);
225
226   get_images(ma, material_image_map);
227   std::string active_uv(getActiveUVLayerName(ob));
228   create_image_samplers(ep, material_image_map, active_uv);
229
230 #if 0
231   unsigned int a, b;
232   for (a = 0, b = 0; a < tex_indices.size(); a++) {
233     MTex *t = ma->mtex[tex_indices[a]];
234     Image *ima = t->tex->ima;
235
236     // Image not set for texture
237     if (!ima) {
238       continue;
239     }
240
241     std::string key(id_name(ima));
242     key = translate_id(key);
243
244     // create only one <sampler>/<surface> pair for each unique image
245     if (im_samp_map.find(key) == im_samp_map.end()) {
246       //<newparam> <sampler> <source>
247       COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
248                                  key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
249                                  key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
250       sampler.setImageId(key);
251       // copy values to arrays since they will live longer
252       samplers[a] = sampler;
253
254       // store pointers so they can be used later when we create <texture>s
255       samp_surf[b] = &samplers[a];
256       //samp_surf[b][1] = &surfaces[a];
257
258       im_samp_map[key] = b;
259       b++;
260     }
261   }
262
263   for (a = 0; a < tex_indices.size(); a++) {
264     MTex *t = ma->mtex[tex_indices[a]];
265     Image *ima = t->tex->ima;
266
267     if (!ima) {
268       continue;
269     }
270
271     std::string key(id_name(ima));
272     key = translate_id(key);
273     int i = im_samp_map[key];
274     std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
275     COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)
276         samp_surf[i];  // possibly uninitialized memory ...
277     writeTextures(ep, key, sampler, t, ima, uvname);
278   }
279 #endif
280
281   // performs the actual writing
282   ep.addProfileElements();
283   ep.addExtraTechniques(mSW);
284
285   ep.closeProfile();
286   closeEffect();
287 }
288
289 COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
290                                                          std::string &uv_layer_name,
291                                                          COLLADASW::Sampler *sampler
292                                                          /*COLLADASW::Surface *surface*/)
293 {
294
295   COLLADASW::Texture texture(translate_id(id_name(ima)));
296   texture.setTexcoord(uv_layer_name);
297   // texture.setSurface(*surface);
298   texture.setSampler(*sampler);
299
300   COLLADASW::ColorOrTexture cot(texture);
301   return cot;
302 }
303
304 COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a)
305 {
306   COLLADASW::Color color(r, g, b, a);
307   COLLADASW::ColorOrTexture cot(color);
308   return cot;
309 }