Blender V2.61 - r43446

EffectExporter.cpp

Go to the documentation of this file.
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 }