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