00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef __VCGLIB_EXPORT_3DS
00026 #define __VCGLIB_EXPORT_3DS
00027
00028 #include <map>
00029 #include <wrap/callback.h>
00030 #include <wrap/io_trimesh/io_mask.h>
00031
00032 #include "io_material.h"
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include <lib3ds/file.h>
00054 #include <lib3ds/io.h>
00055 #include <lib3ds/mesh.h>
00056 #include <lib3ds/types.h>
00057 #include <lib3ds/material.h>
00058
00059 #include <vector>
00060 #include <iostream>
00061 #include <fstream>
00062
00063 #include <QString>
00064 #include <QMessageBox>
00065
00066 #define MAX_POLYGONS 65535
00067
00068 namespace vcg {
00069 namespace tri {
00070 namespace io {
00071
00072 template <class SaveMeshType>
00073 class Exporter3DS
00074 {
00075 public:
00076 typedef typename SaveMeshType::FaceIterator FaceIterator;
00077 typedef typename SaveMeshType::VertexIterator VertexIterator;
00078 typedef typename SaveMeshType::VertexType VertexType;
00079
00080
00081
00082 typedef std::pair<int,vcg::TexCoord2<float> > Key;
00083
00084
00085
00086
00087 enum SaveError
00088 {
00089 E_NOERROR,
00090 E_CANTOPENFILE,
00091 E_CANTCLOSEFILE,
00092 E_UNESPECTEDEOF,
00093 E_ABORTED,
00094 E_NOTDEFINITION,
00095 E_NOTVEXTEXVALID,
00096 E_NOTFACESVALID,
00097 E_NOTEXCOORDVALID,
00098 E_NOTNUMBERVERTVALID
00099 };
00100
00101
00102
00103
00104 static const char* ErrorMsg(int error)
00105 {
00106 static const char* obj_error_msg[] =
00107 {
00108 "No errors",
00109 "Can't open file",
00110 "can't close file",
00111 "Premature End of file",
00112 "File saving aborted",
00113 "Function not defined",
00114 "Vertices not valid",
00115 "Faces not valid",
00116 "Texture Coord not valid",
00117 "You cannot save more than 65535 vertices for the 3DS format"
00118 };
00119
00120 if(error>9 || error<0) return "Unknown error";
00121 else return obj_error_msg[error];
00122 };
00123
00124
00125
00126
00127 static int GetExportMaskCapability()
00128 {
00129 int capability = 0;
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 capability |= Mask::IOM_FACECOLOR;
00140 capability |= Mask::IOM_FACENORMAL;
00141
00142
00143 capability |= Mask::IOM_WEDGTEXCOORD;
00144 capability |= Mask::IOM_WEDGNORMAL;
00145
00146 return capability;
00147 }
00148
00149
00150
00151
00152 static int SaveBinary(SaveMeshType &m, const char * filename, const int &mask, CallBackPos *cb=0)
00153 {
00154 if(m.vn > MAX_POLYGONS)
00155 return E_NOTNUMBERVERTVALID;
00156
00157 if(m.vn == 0)
00158 return E_NOTVEXTEXVALID;
00159 if(m.fn == 0)
00160 return E_NOTFACESVALID;
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 std::map<Key,int> ListOfDuplexVert;
00219 std::vector<VertexType> VectorOfVertexType;
00220 std::vector<int> VertRemap;
00221 int count = 1;
00222 int nface = 0;
00223 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) )
00224 {
00225 FaceIterator fi;
00226 for(fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() )
00227 {
00228 for(unsigned int k=0;k<3;k++)
00229 {
00230 int i = GetIndexVertex(m, (*fi).V(k));
00231 vcg::TexCoord2<float> t = (*fi).WT(k);
00232 if(!m.vert[i].IsD())
00233 {
00234 if(AddDuplexVertexCoord(ListOfDuplexVert,Key(i,t)))
00235 {
00236 VectorOfVertexType.push_back((*(*fi).V(k)));
00237 ListOfDuplexVert[Key(i,t)] = VectorOfVertexType.size()-1;
00238 count++;
00239 }
00240 }
00241 }
00242
00243 if (cb !=NULL)
00244 (*cb)(100.0 * (float)++nface/(float)m.face.size(), "calc duplex vertex ...");
00245 else
00246 return E_ABORTED;
00247 }
00248 }
00249
00250 int number_vertex_to_duplicate = 0;
00251
00252 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ))
00253 number_vertex_to_duplicate = (count-1) - m.vn;
00254
00255 Lib3dsFile *file = lib3ds_file_new();
00256 Lib3dsMesh *mesh = lib3ds_mesh_new("mesh");
00257
00258 QString qnamematerial = "Material - %1";
00259 std::vector<Material> materials;
00260
00261 int current = 0;
00262 int max = m.vn+m.fn+number_vertex_to_duplicate;
00263
00264 lib3ds_mesh_new_point_list(mesh, m.vn + number_vertex_to_duplicate);
00265
00266 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ))
00267 lib3ds_mesh_new_texel_list(mesh,m.vn + number_vertex_to_duplicate);
00268
00269 int v_index = 0;
00270 VertexIterator vi;
00271
00272 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ))
00273 {
00274 for(unsigned int i=0; i< VectorOfVertexType.size();i++)
00275 {
00276 Lib3dsPoint point;
00277 point.pos[0] = VectorOfVertexType[i].P()[0];
00278 point.pos[1] = VectorOfVertexType[i].P()[1];
00279 point.pos[2] = VectorOfVertexType[i].P()[2];
00280
00281 mesh->pointL[i] = point;
00282
00283 if (cb !=NULL)
00284 (*cb)(100.0 * (float)++current/(float)max, "writing vertices ");
00285 else
00286 return E_ABORTED;
00287 }
00288 }
00289 else
00290 {
00291 VertRemap.resize(m.vert.size(),-1);
00292 for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if( !(*vi).IsD() )
00293 {
00294 Lib3dsPoint point;
00295 point.pos[0] = (*vi).P()[0];
00296 point.pos[1] = (*vi).P()[1];
00297 point.pos[2] = (*vi).P()[2];
00298
00299 mesh->pointL[v_index] = point;
00300 VertRemap[vi-m.vert.begin()]=v_index;
00301 if (cb !=NULL)
00302 (*cb)(100.0 * (float)++current/(float)max, "writing vertices ");
00303 else
00304 return E_ABORTED;
00305 v_index++;
00306 }
00307 }
00308
00309 lib3ds_mesh_new_face_list (mesh, m.face.size());
00310 int f_index = 0;
00311
00312 FaceIterator fi;
00313 for(fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() )
00314 {
00315 vcg::TexCoord2<float> t0(0,0),t1(0,0),t2(0,0);
00316 int i0 = GetIndexVertex(m, (*fi).V(0));
00317 int i1 = GetIndexVertex(m, (*fi).V(1));
00318 int i2 = GetIndexVertex(m, (*fi).V(2));
00319 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) )
00320 {
00321 t0 = (*fi).WT(0);
00322 t1 = (*fi).WT(1);
00323 t2 = (*fi).WT(2);
00324 }
00325
00326 Lib3dsFace face;
00327 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ))
00328 {
00329 face.points[0] = GetIndexDuplexVertex(ListOfDuplexVert,Key(i0,t0));
00330 face.points[1] = GetIndexDuplexVertex(ListOfDuplexVert,Key(i1,t1));
00331 face.points[2] = GetIndexDuplexVertex(ListOfDuplexVert,Key(i2,t2));
00332 }
00333 else
00334 {
00335 face.points[0] = VertRemap[i0];
00336 face.points[1] = VertRemap[i1];
00337 face.points[2] = VertRemap[i2];
00338 }
00339
00340
00341 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) )
00342 {
00343 mesh->texelL[face.points[0]][0] = t0.u();
00344 mesh->texelL[face.points[0]][1] = t0.v();
00345 mesh->texelL[face.points[1]][0] = t1.u();
00346 mesh->texelL[face.points[1]][1] = t1.v();
00347 mesh->texelL[face.points[2]][0] = t2.u();
00348 mesh->texelL[face.points[2]][1] = t2.v();
00349 }
00350
00351 if(mask & vcg::tri::io::Mask::IOM_FACEFLAGS)
00352 face.flags = 0;
00353
00354 face.smoothing = 10;
00355
00356 if((mask & vcg::tri::io::Mask::IOM_FACENORMAL) | (mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) )
00357 {
00358 face.normal[0] = (*fi).N()[0];
00359 face.normal[1] = (*fi).N()[1];
00360 face.normal[2] = (*fi).N()[2];
00361 }
00362
00363 if((mask & vcg::tri::io::Mask::IOM_FACECOLOR) | (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD))
00364 {
00365 int material_index = vcg::tri::io::Materials<SaveMeshType>::CreateNewMaterial(m, materials, 0, fi);
00366 if(material_index == (int)materials.size())
00367 {
00368 Lib3dsMaterial *material = lib3ds_material_new();
00369
00370 std::string name = qnamematerial.arg(material_index-1).toStdString();
00371 strcpy(material->name,name.c_str());
00372
00373 if(mask & vcg::tri::io::Mask::IOM_FACECOLOR)
00374 {
00375
00376 material->ambient[0] = materials[materials.size()-1].Ka[0];
00377 material->ambient[1] = materials[materials.size()-1].Ka[1];
00378 material->ambient[2] = materials[materials.size()-1].Ka[2];
00379 material->ambient[3] = materials[materials.size()-1].Tr;
00380
00381
00382 material->diffuse[0] = materials[materials.size()-1].Kd[0];
00383 material->diffuse[1] = materials[materials.size()-1].Kd[1];
00384 material->diffuse[2] = materials[materials.size()-1].Kd[2];
00385 material->diffuse[3] = materials[materials.size()-1].Tr;
00386
00387
00388 material->specular[0] = materials[materials.size()-1].Ks[0];
00389 material->specular[1] = materials[materials.size()-1].Ks[1];
00390 material->specular[2] = materials[materials.size()-1].Ks[2];
00391 material->specular[3] = materials[materials.size()-1].Tr;
00392
00393
00394 material->shininess = materials[materials.size()-1].Ns;
00395 }
00396
00397
00398 if(HasPerWedgeTexCoord(m) && (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) )
00399 strcpy(material->texture1_map.name,materials[materials.size()-1].map_Kd.c_str());
00400
00401 lib3ds_file_insert_material(file,material);
00402 strcpy(face.material,name.c_str());
00403 }
00404 else
00405 {
00406 std::string name = qnamematerial.arg(material_index).toStdString();
00407 strcpy(face.material,name.c_str());
00408 }
00409 }
00410
00411 mesh->faceL[f_index]=face;
00412
00413 if (cb !=NULL)
00414 (*cb)(100.0 * (float)++current/(float)max, "writing faces ");
00415 else
00416 return E_ABORTED;
00417 f_index++;
00418
00419 }
00420
00421 lib3ds_file_insert_mesh(file, mesh);
00422
00423 Lib3dsNode *node = lib3ds_node_new_object();
00424 strcpy(node->name,mesh->name);
00425 node->parent_id = LIB3DS_NO_PARENT;
00426 lib3ds_file_insert_node(file,node);
00427
00428 bool result = lib3ds_file_save(file, filename);
00429 if(result)
00430 return E_NOERROR;
00431 else
00432 return E_ABORTED;
00433 }
00434
00435
00436
00437
00438 static int Save(SaveMeshType &m, const char * filename, const int &mask, CallBackPos *cb=0)
00439 {
00440 return SaveBinary(m,filename,mask,cb);
00441 }
00442
00443
00444
00445
00446 inline static int GetIndexVertex(SaveMeshType &m, VertexType *p)
00447 {
00448 return p-&*(m.vert.begin());
00449 }
00450
00451
00452
00453
00454 inline static bool AddDuplexVertexCoord(std::map<Key,int> &m,Key key)
00455 {
00456 int index = m[key];
00457 if(index==0)
00458 return true;
00459 return false;
00460 }
00461
00462
00463
00464
00465 inline static int GetIndexDuplexVertex(std::map<Key,int> &m,Key key)
00466 {
00467 return m[key];
00468 }
00469
00470 };
00471
00472 }
00473 }
00474 }
00475
00476 #endif