Collada exporter update
[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   return "";
53 }
54
55 EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw,
56                                  BCExportSettings &export_settings,
57                                  KeyImageMap &key_image_map)
58     : COLLADASW::LibraryEffects(sw), export_settings(export_settings), key_image_map(key_image_map)
59 {
60 }
61
62 bool EffectsExporter::hasEffects(Scene *sce)
63 {
64   FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
65     int a;
66     for (a = 0; a < ob->totcol; a++) {
67       Material *ma = give_current_material(ob, a + 1);
68
69       // no material, but check all of the slots
70       if (!ma)
71         continue;
72
73       return true;
74     }
75   }
76   FOREACH_SCENE_OBJECT_END;
77   return false;
78 }
79
80 void EffectsExporter::exportEffects(bContext *C, Scene *sce)
81 {
82   if (hasEffects(sce)) {
83     this->mContext = C;
84     this->scene = sce;
85     openLibrary();
86     MaterialFunctor mf;
87     mf.forEachMaterialInExportSet<EffectsExporter>(
88         sce, *this, this->export_settings.get_export_set());
89
90     closeLibrary();
91   }
92 }
93
94 void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
95 {
96   /* XXX check if BLINN and PHONG can be supported as well */
97   ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
98 }
99
100 void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
101 {
102   COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
103   float transparency = cot.getColor().getAlpha();
104   if (transparency < 1) {
105     // Tod: because we are in A_ONE mode transparency is calculated like this:
106     COLLADASW::ColorOrTexture cot = getcol(1.0f, 1.0f, 1.0f, transparency);
107     ep.setTransparent(cot);
108     ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
109   }
110 }
111 void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
112 {
113   // get diffuse color
114   COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
115   ep.setDiffuse(cot, false, "diffuse");
116 }
117
118 void EffectsExporter::set_reflectivity(COLLADASW::EffectProfile &ep, Material *ma)
119 {
120   double reflectivity = bc_get_reflectivity(ma);
121   ep.setReflectivity(reflectivity, false, "specular");
122 }
123
124 void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
125 {
126   // not yet supported (needs changes in principled shader
127 }
128
129 void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
130 {
131   if (!ma->use_nodes) {
132     return;
133   }
134
135   MaterialNode material = MaterialNode(mContext, ma, key_image_map);
136   Image *image = material.get_diffuse_image();
137   if (image == nullptr) {
138     return;
139   }
140
141   std::string uid(id_name(image));
142   std::string key = translate_id(uid);
143
144   if (material_image_map.find(key) == material_image_map.end()) {
145     material_image_map[key] = image;
146     key_image_map[key] = image;
147   }
148 }
149
150 void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep,
151                                             KeyImageMap &material_image_map,
152                                             std::string &active_uv)
153 {
154   KeyImageMap::iterator iter;
155
156   for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
157
158     Image *image = iter->second;
159     std::string uid(id_name(image));
160     std::string key = translate_id(uid);
161
162     COLLADASW::Sampler *sampler = new COLLADASW::Sampler(
163         COLLADASW::Sampler::SAMPLER_TYPE_2D,
164         key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
165         key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
166
167     sampler->setImageId(key);
168
169     ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
170   }
171 }
172
173 void EffectsExporter::operator()(Material *ma, Object *ob)
174 {
175   KeyImageMap material_image_map;
176
177   openEffect(get_effect_id(ma));
178
179   COLLADASW::EffectProfile ep(mSW);
180   ep.setProfileType(COLLADASW::EffectProfile::COMMON);
181   ep.openProfile();
182   set_shader_type(ep, ma);
183
184   COLLADASW::ColorOrTexture cot;
185
186   set_transparency(ep, ma);
187   set_diffuse_color(ep, ma);
188   set_reflectivity(ep, ma);
189   set_emission(ep, ma);
190
191   get_images(ma, material_image_map);
192   std::string active_uv(getActiveUVLayerName(ob));
193   create_image_samplers(ep, material_image_map, active_uv);
194
195 #if 0
196   unsigned int a, b;
197   for (a = 0, b = 0; a < tex_indices.size(); a++) {
198     MTex *t = ma->mtex[tex_indices[a]];
199     Image *ima = t->tex->ima;
200
201     // Image not set for texture
202     if (!ima)
203       continue;
204
205     std::string key(id_name(ima));
206     key = translate_id(key);
207
208     // create only one <sampler>/<surface> pair for each unique image
209     if (im_samp_map.find(key) == im_samp_map.end()) {
210       //<newparam> <sampler> <source>
211       COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
212                                  key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
213                                  key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
214       sampler.setImageId(key);
215       // copy values to arrays since they will live longer
216       samplers[a] = sampler;
217
218       // store pointers so they can be used later when we create <texture>s
219       samp_surf[b] = &samplers[a];
220       //samp_surf[b][1] = &surfaces[a];
221
222       im_samp_map[key] = b;
223       b++;
224     }
225   }
226
227   for (a = 0; a < tex_indices.size(); a++) {
228     MTex *t = ma->mtex[tex_indices[a]];
229     Image *ima = t->tex->ima;
230
231     if (!ima) {
232       continue;
233     }
234
235     std::string key(id_name(ima));
236     key = translate_id(key);
237     int i = im_samp_map[key];
238     std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
239     COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)
240         samp_surf[i];  // possibly uninitialised memory ...
241     writeTextures(ep, key, sampler, t, ima, uvname);
242   }
243 #endif
244
245   // performs the actual writing
246   ep.addProfileElements();
247   ep.addExtraTechniques(mSW);
248
249   ep.closeProfile();
250   closeEffect();
251 }
252
253 COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
254                                                          std::string &uv_layer_name,
255                                                          COLLADASW::Sampler *sampler
256                                                          /*COLLADASW::Surface *surface*/)
257 {
258
259   COLLADASW::Texture texture(translate_id(id_name(ima)));
260   texture.setTexcoord(uv_layer_name);
261   // texture.setSurface(*surface);
262   texture.setSampler(*sampler);
263
264   COLLADASW::ColorOrTexture cot(texture);
265   return cot;
266 }
267
268 COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a)
269 {
270   COLLADASW::Color color(r, g, b, a);
271   COLLADASW::ColorOrTexture cot(color);
272   return cot;
273 }