doxygen: add newline after \file
[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
22 #include <map>
23 #include <set>
24
25 #include "COLLADASWEffectProfile.h"
26 #include "COLLADAFWColorOrTexture.h"
27
28 #include "EffectExporter.h"
29 #include "DocumentExporter.h"
30 #include "MaterialExporter.h"
31
32 #include "collada_internal.h"
33 #include "collada_utils.h"
34
35 extern "C" {
36         #include "DNA_mesh_types.h"
37         #include "DNA_world_types.h"
38
39         #include "BKE_collection.h"
40         #include "BKE_customdata.h"
41         #include "BKE_mesh.h"
42         #include "BKE_material.h"
43 }
44
45 static std::string getActiveUVLayerName(Object *ob)
46 {
47         Mesh *me = (Mesh *)ob->data;
48
49         int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
50         if (num_layers)
51                 return std::string(bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV));
52
53         return "";
54 }
55
56 EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) :
57         COLLADASW::LibraryEffects(sw),
58         export_settings(export_settings),
59         key_image_map(key_image_map)
60 {}
61
62
63 bool EffectsExporter::hasEffects(Scene *sce)
64 {
65         FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
66         {
67                 int a;
68                 for (a = 0; a < ob->totcol; a++) {
69                         Material *ma = give_current_material(ob, a + 1);
70
71                         // no material, but check all of the slots
72                         if (!ma) continue;
73
74                         return true;
75                 }
76         }
77         FOREACH_SCENE_OBJECT_END;
78         return false;
79 }
80
81 void EffectsExporter::exportEffects(bContext *C, Scene *sce)
82 {
83         if (hasEffects(sce)) {
84                 this->mContext = C;
85                 this->scene = sce;
86                 openLibrary();
87                 MaterialFunctor mf;
88                 mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set);
89
90                 closeLibrary();
91         }
92 }
93
94 void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
95 {
96         ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); //XXX check if BLINN and PHONG can be supported as well
97 }
98
99 void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
100 {
101         if (ma->alpha == 1.0f) {
102                 return; // have no transparency
103         }
104
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, ma->alpha);
107         ep.setTransparent(cot);
108         ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
109 }
110 void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
111 {
112         // get diffuse color
113         COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
114         ep.setDiffuse(cot, false, "diffuse");
115 }
116
117 void EffectsExporter::set_specular_color(COLLADASW::EffectProfile &ep, Material *ma)
118 {
119         bool use_fallback = ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT;
120         COLLADASW::ColorOrTexture cot = bc_get_specular_color(ma, use_fallback);
121         ep.setSpecular(cot, 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, KeyImageMap &material_image_map, std::string &active_uv)
151 {
152         KeyImageMap::iterator iter;
153
154         for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
155
156                 Image *image = iter->second;
157                 std::string uid(id_name(image));
158                 std::string key = translate_id(uid);
159
160                 COLLADASW::Sampler *sampler = new COLLADASW::Sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
161                         key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
162                         key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
163
164                 sampler->setImageId(key);
165
166                 ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
167         }
168 }
169
170 void EffectsExporter::operator()(Material *ma, Object *ob)
171 {
172         KeyImageMap material_image_map;
173
174         openEffect(get_effect_id(ma));
175
176         COLLADASW::EffectProfile ep(mSW);
177         ep.setProfileType(COLLADASW::EffectProfile::COMMON);
178         ep.openProfile();
179         set_shader_type(ep, ma);
180
181         COLLADASW::ColorOrTexture cot;
182
183         set_transparency(ep, ma);
184         set_diffuse_color(ep, ma);
185         set_specular_color(ep, ma);
186         set_emission(ep, ma);
187
188         get_images(ma, material_image_map);
189         std::string active_uv(getActiveUVLayerName(ob));
190         create_image_samplers(ep, material_image_map, active_uv);
191
192 #if 0
193         unsigned int a, b;
194         for (a = 0, b = 0; a < tex_indices.size(); a++) {
195                 MTex *t = ma->mtex[tex_indices[a]];
196                 Image *ima = t->tex->ima;
197
198                 // Image not set for texture
199                 if (!ima) continue;
200
201                 std::string key(id_name(ima));
202                 key = translate_id(key);
203
204                 // create only one <sampler>/<surface> pair for each unique image
205                 if (im_samp_map.find(key) == im_samp_map.end()) {
206                         //<newparam> <sampler> <source>
207                         COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
208                                 key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
209                                 key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
210                         sampler.setImageId(key);
211                         // copy values to arrays since they will live longer
212                         samplers[a] = sampler;
213
214                         // store pointers so they can be used later when we create <texture>s
215                         samp_surf[b] = &samplers[a];
216                         //samp_surf[b][1] = &surfaces[a];
217
218                         im_samp_map[key] = b;
219                         b++;
220                 }
221         }
222
223         for (a = 0; a < tex_indices.size(); a++) {
224                 MTex *t = ma->mtex[tex_indices[a]];
225                 Image *ima = t->tex->ima;
226
227                 if (!ima) {
228                         continue;
229                 }
230
231                 std::string key(id_name(ima));
232                 key = translate_id(key);
233                 int i = im_samp_map[key];
234                 std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
235                 COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i]; // possibly uninitialised memory ...
236                 writeTextures(ep, key, sampler, t, ima, uvname);
237         }
238 #endif
239
240         // performs the actual writing
241         ep.addProfileElements();
242         bool twoSided = false;
243         if (ob->type == OB_MESH && ob->data) {
244                 Mesh *me = (Mesh *)ob->data;
245                 if (me->flag & ME_TWOSIDED)
246                         twoSided = true;
247         }
248         if (twoSided)
249                 ep.addExtraTechniqueParameter("GOOGLEEARTH", "double_sided", 1);
250         ep.addExtraTechniques(mSW);
251
252         ep.closeProfile();
253         if (twoSided)
254                 mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>");
255         closeEffect();
256 }
257
258 COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
259                                                          std::string& uv_layer_name,
260                                                          COLLADASW::Sampler *sampler
261                                                          /*COLLADASW::Surface *surface*/)
262 {
263
264         COLLADASW::Texture texture(translate_id(id_name(ima)));
265         texture.setTexcoord(uv_layer_name);
266         //texture.setSurface(*surface);
267         texture.setSampler(*sampler);
268
269         COLLADASW::ColorOrTexture cot(texture);
270         return cot;
271 }
272
273 COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a)
274 {
275         COLLADASW::Color color(r, g, b, a);
276         COLLADASW::ColorOrTexture cot(color);
277         return cot;
278 }