|
Blender
V2.59
|
00001 /* 00002 * $Id: EffectExporter.cpp 38079 2011-07-04 08:59:28Z jesterking $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, 00021 * Nathan Letwory 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <map> 00032 00033 #include "COLLADASWEffectProfile.h" 00034 00035 #include "EffectExporter.h" 00036 #include "MaterialExporter.h" 00037 00038 #include "DNA_mesh_types.h" 00039 #include "DNA_texture_types.h" 00040 00041 #include "BKE_customdata.h" 00042 00043 #include "collada_internal.h" 00044 #include "collada_utils.h" 00045 00046 // OB_MESH is assumed 00047 static std::string getActiveUVLayerName(Object *ob) 00048 { 00049 Mesh *me = (Mesh*)ob->data; 00050 00051 int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); 00052 if (num_layers) 00053 return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE)); 00054 00055 return ""; 00056 } 00057 00058 EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){} 00059 00060 bool EffectsExporter::hasEffects(Scene *sce) 00061 { 00062 Base *base = (Base *)sce->base.first; 00063 00064 while(base) { 00065 Object *ob= base->object; 00066 int a; 00067 for(a = 0; a < ob->totcol; a++) 00068 { 00069 Material *ma = give_current_material(ob, a+1); 00070 00071 // no material, but check all of the slots 00072 if (!ma) continue; 00073 00074 return true; 00075 } 00076 base= base->next; 00077 } 00078 return false; 00079 } 00080 00081 void EffectsExporter::exportEffects(Scene *sce, bool export_selected) 00082 { 00083 if(hasEffects(sce)) { 00084 openLibrary(); 00085 MaterialFunctor mf; 00086 mf.forEachMaterialInScene<EffectsExporter>(sce, *this, export_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); 00098 // specular 00099 cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); 00100 ep.setSpecular(cot); 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); 00115 // specular 00116 cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); 00117 ep.setSpecular(cot); 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); 00154 } 00155 else { 00156 ep.setIndexOfRefraction(1.0f); 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); 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); 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); 00176 00177 // ambient 00178 cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f); 00179 ep.setAmbient(cot); 00180 00181 // reflective, reflectivity 00182 if (ma->mode & MA_RAYMIRROR) { 00183 cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f); 00184 ep.setReflective(cot); 00185 ep.setReflectivity(ma->ray_mirror); 00186 } 00187 // else { 00188 // cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); 00189 // ep.setReflective(cot); 00190 // ep.setReflectivity(ma->spec); 00191 // } 00192 00193 // specular 00194 if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) { 00195 cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f); 00196 ep.setSpecular(cot); 00197 } 00198 00199 // XXX make this more readable if possible 00200 00201 // create <sampler> and <surface> for each image 00202 COLLADASW::Sampler samplers[MAX_MTEX]; 00203 //COLLADASW::Surface surfaces[MAX_MTEX]; 00204 //void *samp_surf[MAX_MTEX][2]; 00205 void *samp_surf[MAX_MTEX][1]; 00206 00207 // image to index to samp_surf map 00208 // samp_surf[index] stores 2 pointers, sampler and surface 00209 std::map<std::string, int> im_samp_map; 00210 00211 unsigned int a, b; 00212 for (a = 0, b = 0; a < tex_indices.size(); a++) { 00213 MTex *t = ma->mtex[tex_indices[a]]; 00214 Image *ima = t->tex->ima; 00215 00216 // Image not set for texture 00217 if(!ima) continue; 00218 00219 std::string key(id_name(ima)); 00220 key = translate_id(key); 00221 00222 // create only one <sampler>/<surface> pair for each unique image 00223 if (im_samp_map.find(key) == im_samp_map.end()) { 00224 // //<newparam> <surface> <init_from> 00225 // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D, 00226 // key + COLLADASW::Surface::SURFACE_SID_SUFFIX); 00227 // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM); 00228 // sio.setImageReference(key); 00229 // surface.setInitOption(sio); 00230 00231 // COLLADASW::NewParamSurface surface(mSW); 00232 // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D); 00233 00234 //<newparam> <sampler> <source> 00235 COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, 00236 key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, 00237 key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); 00238 sampler.setImageId(key); 00239 // copy values to arrays since they will live longer 00240 samplers[a] = sampler; 00241 //surfaces[a] = surface; 00242 00243 // store pointers so they can be used later when we create <texture>s 00244 samp_surf[b][0] = &samplers[a]; 00245 //samp_surf[b][1] = &surfaces[a]; 00246 00247 im_samp_map[key] = b; 00248 b++; 00249 } 00250 } 00251 00252 // used as fallback when MTex->uvname is "" (this is pretty common) 00253 // it is indeed the correct value to use in that case 00254 std::string active_uv(getActiveUVLayerName(ob)); 00255 00256 // write textures 00257 // XXX very slow 00258 for (a = 0; a < tex_indices.size(); a++) { 00259 MTex *t = ma->mtex[tex_indices[a]]; 00260 Image *ima = t->tex->ima; 00261 00262 // Image not set for texture 00263 if(!ima) continue; 00264 00265 // we assume map input is always TEXCO_UV 00266 00267 std::string key(id_name(ima)); 00268 key = translate_id(key); 00269 int i = im_samp_map[key]; 00270 COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0]; 00271 //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1]; 00272 00273 std::string uvname = strlen(t->uvname) ? t->uvname : active_uv; 00274 00275 // color 00276 if (t->mapto & (MAP_COL | MAP_COLSPEC)) { 00277 ep.setDiffuse(createTexture(ima, uvname, sampler)); 00278 } 00279 // ambient 00280 if (t->mapto & MAP_AMB) { 00281 ep.setAmbient(createTexture(ima, uvname, sampler)); 00282 } 00283 // specular 00284 if (t->mapto & MAP_SPEC) { 00285 ep.setSpecular(createTexture(ima, uvname, sampler)); 00286 } 00287 // emission 00288 if (t->mapto & MAP_EMIT) { 00289 ep.setEmission(createTexture(ima, uvname, sampler)); 00290 } 00291 // reflective 00292 if (t->mapto & MAP_REF) { 00293 ep.setReflective(createTexture(ima, uvname, sampler)); 00294 } 00295 // alpha 00296 if (t->mapto & MAP_ALPHA) { 00297 ep.setTransparent(createTexture(ima, uvname, sampler)); 00298 } 00299 // extension: 00300 // Normal map --> Must be stored with <extra> tag as different technique, 00301 // since COLLADA doesn't support normal maps, even in current COLLADA 1.5. 00302 if (t->mapto & MAP_NORM) { 00303 COLLADASW::Texture texture(key); 00304 texture.setTexcoord(uvname); 00305 texture.setSampler(*sampler); 00306 // technique FCOLLADA, with the <bump> tag, is most likely the best understood, 00307 // most widespread de-facto standard. 00308 texture.setProfileName("FCOLLADA"); 00309 texture.setChildElementName("bump"); 00310 ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture)); 00311 } 00312 } 00313 // performs the actual writing 00314 ep.addProfileElements(); 00315 bool twoSided = false; 00316 if (ob->type == OB_MESH && ob->data) { 00317 Mesh *me = (Mesh*)ob->data; 00318 if (me->flag & ME_TWOSIDED) 00319 twoSided = true; 00320 } 00321 if (twoSided) 00322 ep.addExtraTechniqueParameter("GOOGLEEARTH", "double_sided", 1); 00323 ep.addExtraTechniques(mSW); 00324 00325 ep.closeProfile(); 00326 if (twoSided) 00327 mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>"); 00328 closeEffect(); 00329 } 00330 00331 COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima, 00332 std::string& uv_layer_name, 00333 COLLADASW::Sampler *sampler 00334 /*COLLADASW::Surface *surface*/) 00335 { 00336 00337 COLLADASW::Texture texture(translate_id(id_name(ima))); 00338 texture.setTexcoord(uv_layer_name); 00339 //texture.setSurface(*surface); 00340 texture.setSampler(*sampler); 00341 00342 COLLADASW::ColorOrTexture cot(texture); 00343 return cot; 00344 } 00345 00346 COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a) 00347 { 00348 COLLADASW::Color color(r,g,b,a); 00349 COLLADASW::ColorOrTexture cot(color); 00350 return cot; 00351 } 00352 00353 //returns the array of mtex indices which have image 00354 //need this for exporting textures 00355 void EffectsExporter::createTextureIndices(Material *ma, std::vector<int> &indices) 00356 { 00357 indices.clear(); 00358 00359 for (int a = 0; a < MAX_MTEX; a++) { 00360 if (ma->mtex[a] && 00361 ma->mtex[a]->tex && 00362 ma->mtex[a]->tex->type == TEX_IMAGE && 00363 ma->mtex[a]->texco == TEXCO_UV){ 00364 indices.push_back(a); 00365 } 00366 } 00367 }