Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, 00019 * Nathan Letwory 00020 * 00021 * ***** END GPL LICENSE BLOCK ***** 00022 */ 00023 00029 #include <map> 00030 00031 #include "COLLADASWEffectProfile.h" 00032 00033 #include "EffectExporter.h" 00034 #include "MaterialExporter.h" 00035 00036 #include "DNA_mesh_types.h" 00037 #include "DNA_texture_types.h" 00038 #include "DNA_world_types.h" 00039 00040 #include "BKE_customdata.h" 00041 00042 #include "collada_internal.h" 00043 #include "collada_utils.h" 00044 00045 // OB_MESH is assumed 00046 static std::string getActiveUVLayerName(Object *ob) 00047 { 00048 Mesh *me = (Mesh*)ob->data; 00049 00050 int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); 00051 if (num_layers) 00052 return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE)); 00053 00054 return ""; 00055 } 00056 00057 EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) {} 00058 00059 bool EffectsExporter::hasEffects(Scene *sce) 00060 { 00061 Base *base = (Base *)sce->base.first; 00062 00063 while(base) { 00064 Object *ob= base->object; 00065 int a; 00066 for(a = 0; a < ob->totcol; a++) 00067 { 00068 Material *ma = give_current_material(ob, a+1); 00069 00070 // no material, but check all of the slots 00071 if (!ma) continue; 00072 00073 return true; 00074 } 00075 base= base->next; 00076 } 00077 return false; 00078 } 00079 00080 void EffectsExporter::exportEffects(Scene *sce) 00081 { 00082 if(hasEffects(sce)) { 00083 this->scene = sce; 00084 openLibrary(); 00085 MaterialFunctor mf; 00086 mf.forEachMaterialInScene<EffectsExporter>(sce, *this, this->export_settings->selected); 00087 00088 closeLibrary(); 00089 } 00090 } 00091 00092 void EffectsExporter::writeBlinn(COLLADASW::EffectProfile &ep, Material *ma) 00093 { 00094 COLLADASW::ColorOrTexture cot; 00095 ep.setShaderType(COLLADASW::EffectProfile::BLINN); 00096 // shininess 00097 ep.setShininess(ma->har, false , "shininess"); 00098 // specular 00099 cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); 00100 ep.setSpecular(cot, false , "specular" ); 00101 } 00102 00103 void EffectsExporter::writeLambert(COLLADASW::EffectProfile &ep, Material *ma) 00104 { 00105 COLLADASW::ColorOrTexture cot; 00106 ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); 00107 } 00108 00109 void EffectsExporter::writePhong(COLLADASW::EffectProfile &ep, Material *ma) 00110 { 00111 COLLADASW::ColorOrTexture cot; 00112 ep.setShaderType(COLLADASW::EffectProfile::PHONG); 00113 // shininess 00114 ep.setShininess(ma->har , false , "shininess" ); 00115 // specular 00116 cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); 00117 ep.setSpecular(cot, false , "specular" ); 00118 } 00119 00120 void EffectsExporter::operator()(Material *ma, Object *ob) 00121 { 00122 // create a list of indices to textures of type TEX_IMAGE 00123 std::vector<int> tex_indices; 00124 createTextureIndices(ma, tex_indices); 00125 00126 openEffect(translate_id(id_name(ma)) + "-effect"); 00127 00128 COLLADASW::EffectProfile ep(mSW); 00129 ep.setProfileType(COLLADASW::EffectProfile::COMMON); 00130 ep.openProfile(); 00131 // set shader type - one of three blinn, phong or lambert 00132 if(ma->spec>0.0f) { 00133 if (ma->spec_shader == MA_SPEC_BLINN) { 00134 writeBlinn(ep, ma); 00135 } 00136 else { 00137 // \todo figure out handling of all spec+diff shader combos blender has, for now write phong 00138 // for now set phong in case spec shader is not blinn 00139 writePhong(ep, ma); 00140 } 00141 } else { 00142 if(ma->diff_shader == MA_DIFF_LAMBERT) { 00143 writeLambert(ep, ma); 00144 } 00145 else { 00146 // \todo figure out handling of all spec+diff shader combos blender has, for now write phong 00147 writePhong(ep, ma); 00148 } 00149 } 00150 00151 // index of refraction 00152 if (ma->mode & MA_RAYTRANSP) { 00153 ep.setIndexOfRefraction(ma->ang, false , "index_of_refraction"); 00154 } 00155 else { 00156 ep.setIndexOfRefraction(1.0f, false , "index_of_refraction"); 00157 } 00158 00159 COLLADASW::ColorOrTexture cot; 00160 00161 // transparency 00162 if (ma->mode & MA_TRANSP) { 00163 // Tod: because we are in A_ONE mode transparency is calculated like this: 00164 ep.setTransparency(ma->alpha, false , "transparency"); 00165 // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f); 00166 // ep.setTransparent(cot); 00167 } 00168 00169 // emission 00170 cot=getcol(ma->emit, ma->emit, ma->emit, 1.0f); 00171 ep.setEmission(cot, false , "emission"); 00172 00173 // diffuse multiplied by diffuse intensity 00174 cot = getcol(ma->r * ma->ref, ma->g * ma->ref, ma->b * ma->ref, 1.0f); 00175 ep.setDiffuse(cot, false , "diffuse"); 00176 00177 // ambient 00178 /* ma->ambX is calculated only on render, so lets do it here manually and not rely on ma->ambX. */ 00179 if(this->scene->world) 00180 cot = getcol(this->scene->world->ambr*ma->amb, this->scene->world->ambg*ma->amb, this->scene->world->ambb*ma->amb, 1.0f); 00181 else 00182 cot = getcol(ma->amb, ma->amb, ma->amb, 1.0f); 00183 00184 ep.setAmbient(cot, false , "ambient"); 00185 00186 // reflective, reflectivity 00187 if (ma->mode & MA_RAYMIRROR) { 00188 cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f); 00189 ep.setReflective(cot); 00190 ep.setReflectivity(ma->ray_mirror); 00191 } 00192 // else { 00193 // cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); 00194 // ep.setReflective(cot); 00195 // ep.setReflectivity(ma->spec); 00196 // } 00197 00198 // specular 00199 if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) { 00200 cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f); 00201 ep.setSpecular(cot, false , "specular"); 00202 } 00203 00204 // XXX make this more readable if possible 00205 00206 // create <sampler> and <surface> for each image 00207 COLLADASW::Sampler samplers[MAX_MTEX]; 00208 //COLLADASW::Surface surfaces[MAX_MTEX]; 00209 //void *samp_surf[MAX_MTEX][2]; 00210 void *samp_surf[MAX_MTEX][1]; 00211 00212 // image to index to samp_surf map 00213 // samp_surf[index] stores 2 pointers, sampler and surface 00214 std::map<std::string, int> im_samp_map; 00215 00216 unsigned int a, b; 00217 for (a = 0, b = 0; a < tex_indices.size(); a++) { 00218 MTex *t = ma->mtex[tex_indices[a]]; 00219 Image *ima = t->tex->ima; 00220 00221 // Image not set for texture 00222 if(!ima) continue; 00223 00224 std::string key(id_name(ima)); 00225 key = translate_id(key); 00226 00227 // create only one <sampler>/<surface> pair for each unique image 00228 if (im_samp_map.find(key) == im_samp_map.end()) { 00229 // //<newparam> <surface> <init_from> 00230 // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D, 00231 // key + COLLADASW::Surface::SURFACE_SID_SUFFIX); 00232 // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM); 00233 // sio.setImageReference(key); 00234 // surface.setInitOption(sio); 00235 00236 // COLLADASW::NewParamSurface surface(mSW); 00237 // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D); 00238 00239 //<newparam> <sampler> <source> 00240 COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, 00241 key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, 00242 key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); 00243 sampler.setImageId(key); 00244 // copy values to arrays since they will live longer 00245 samplers[a] = sampler; 00246 //surfaces[a] = surface; 00247 00248 // store pointers so they can be used later when we create <texture>s 00249 samp_surf[b][0] = &samplers[a]; 00250 //samp_surf[b][1] = &surfaces[a]; 00251 00252 im_samp_map[key] = b; 00253 b++; 00254 } 00255 } 00256 00257 // used as fallback when MTex->uvname is "" (this is pretty common) 00258 // it is indeed the correct value to use in that case 00259 std::string active_uv(getActiveUVLayerName(ob)); 00260 00261 // write textures 00262 // XXX very slow 00263 for (a = 0; a < tex_indices.size(); a++) { 00264 MTex *t = ma->mtex[tex_indices[a]]; 00265 Image *ima = t->tex->ima; 00266 00267 // Image not set for texture 00268 if(!ima) continue; 00269 00270 // we assume map input is always TEXCO_UV 00271 00272 std::string key(id_name(ima)); 00273 key = translate_id(key); 00274 int i = im_samp_map[key]; 00275 COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0]; 00276 //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1]; 00277 00278 std::string uvname = strlen(t->uvname) ? t->uvname : active_uv; 00279 00280 // color 00281 if (t->mapto & (MAP_COL | MAP_COLSPEC)) { 00282 ep.setDiffuse(createTexture(ima, uvname, sampler), false , "diffuse"); 00283 } 00284 // ambient 00285 if (t->mapto & MAP_AMB) { 00286 ep.setAmbient(createTexture(ima, uvname, sampler), false , "ambient"); 00287 } 00288 // specular 00289 if (t->mapto & MAP_SPEC) { 00290 ep.setSpecular(createTexture(ima, uvname, sampler), false , "specular"); 00291 } 00292 // emission 00293 if (t->mapto & MAP_EMIT) { 00294 ep.setEmission(createTexture(ima, uvname, sampler), false , "emission"); 00295 } 00296 // reflective 00297 if (t->mapto & MAP_REF) { 00298 ep.setReflective(createTexture(ima, uvname, sampler)); 00299 } 00300 // alpha 00301 if (t->mapto & MAP_ALPHA) { 00302 ep.setTransparent(createTexture(ima, uvname, sampler)); 00303 } 00304 // extension: 00305 // Normal map --> Must be stored with <extra> tag as different technique, 00306 // since COLLADA doesn't support normal maps, even in current COLLADA 1.5. 00307 if (t->mapto & MAP_NORM) { 00308 COLLADASW::Texture texture(key); 00309 texture.setTexcoord(uvname); 00310 texture.setSampler(*sampler); 00311 // technique FCOLLADA, with the <bump> tag, is most likely the best understood, 00312 // most widespread de-facto standard. 00313 texture.setProfileName("FCOLLADA"); 00314 texture.setChildElementName("bump"); 00315 ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture)); 00316 } 00317 } 00318 // performs the actual writing 00319 ep.addProfileElements(); 00320 bool twoSided = false; 00321 if (ob->type == OB_MESH && ob->data) { 00322 Mesh *me = (Mesh*)ob->data; 00323 if (me->flag & ME_TWOSIDED) 00324 twoSided = true; 00325 } 00326 if (twoSided) 00327 ep.addExtraTechniqueParameter("GOOGLEEARTH", "double_sided", 1); 00328 ep.addExtraTechniques(mSW); 00329 00330 ep.closeProfile(); 00331 if (twoSided) 00332 mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>"); 00333 closeEffect(); 00334 } 00335 00336 COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima, 00337 std::string& uv_layer_name, 00338 COLLADASW::Sampler *sampler 00339 /*COLLADASW::Surface *surface*/) 00340 { 00341 00342 COLLADASW::Texture texture(translate_id(id_name(ima))); 00343 texture.setTexcoord(uv_layer_name); 00344 //texture.setSurface(*surface); 00345 texture.setSampler(*sampler); 00346 00347 COLLADASW::ColorOrTexture cot(texture); 00348 return cot; 00349 } 00350 00351 COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a) 00352 { 00353 COLLADASW::Color color(r,g,b,a); 00354 COLLADASW::ColorOrTexture cot(color); 00355 return cot; 00356 } 00357 00358 //returns the array of mtex indices which have image 00359 //need this for exporting textures 00360 void EffectsExporter::createTextureIndices(Material *ma, std::vector<int> &indices) 00361 { 00362 indices.clear(); 00363 00364 for (int a = 0; a < MAX_MTEX; a++) { 00365 if (ma->mtex[a] && 00366 ma->mtex[a]->tex && 00367 ma->mtex[a]->tex->type == TEX_IMAGE && 00368 ma->mtex[a]->texco == TEXCO_UV){ 00369 indices.push_back(a); 00370 } 00371 } 00372 }