Blender V2.61 - r43446

GeometryExporter.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 <sstream>
00030 
00031 #include "COLLADASWPrimitves.h"
00032 #include "COLLADASWSource.h"
00033 #include "COLLADASWVertices.h"
00034 #include "COLLADABUUtils.h"
00035 
00036 #include "GeometryExporter.h"
00037 
00038 #include "DNA_meshdata_types.h"
00039 #include "BKE_customdata.h"
00040 #include "BKE_material.h"
00041 
00042 #include "collada_internal.h"
00043 
00044 // TODO: optimize UV sets by making indexed list with duplicates removed
00045 GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings) {}
00046 
00047 
00048 void GeometryExporter::exportGeom(Scene *sce)
00049 {
00050     openLibrary();
00051 
00052     mScene = sce;
00053     GeometryFunctor gf;
00054     gf.forEachMeshObjectInScene<GeometryExporter>(sce, *this, this->export_settings->selected);
00055 
00056     closeLibrary();
00057 }
00058 
00059 void GeometryExporter::operator()(Object *ob)
00060 {
00061     // XXX don't use DerivedMesh, Mesh instead?
00062 
00063 #if 0       
00064     DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
00065 #endif
00066     Mesh *me = (Mesh*)ob->data;
00067     std::string geom_id = get_geometry_id(ob);
00068     std::vector<Normal> nor;
00069     std::vector<Face> norind;
00070 
00071     // Skip if linked geometry was already exported from another reference
00072     if (exportedGeometry.find(geom_id) != exportedGeometry.end())
00073         return;
00074     exportedGeometry.insert(geom_id);
00075 
00076     bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
00077 
00078     create_normals(nor, norind, me);
00079 
00080     // openMesh(geoId, geoName, meshId)
00081     openMesh(geom_id);
00082     
00083     // writes <source> for vertex coords
00084     createVertsSource(geom_id, me);
00085     
00086     // writes <source> for normal coords
00087     createNormalsSource(geom_id, me, nor);
00088 
00089     bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
00090     
00091     // writes <source> for uv coords if mesh has uv coords
00092     if (has_uvs)
00093         createTexcoordsSource(geom_id, me);
00094 
00095     if (has_color)
00096         createVertexColorSource(geom_id, me);
00097 
00098     // <vertices>
00099     COLLADASW::Vertices verts(mSW);
00100     verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
00101     COLLADASW::InputList &input_list = verts.getInputList();
00102     COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
00103     input_list.push_back(input);
00104     verts.add();
00105 
00106     // XXX slow     
00107     if (ob->totcol) {
00108         for(int a = 0; a < ob->totcol; a++) {
00109             createPolylist(a, has_uvs, has_color, ob, geom_id, norind);
00110         }
00111     }
00112     else {
00113         createPolylist(0, has_uvs, has_color, ob, geom_id, norind);
00114     }
00115     
00116     closeMesh();
00117     
00118     if (me->flag & ME_TWOSIDED) {
00119         mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
00120     }
00121     
00122     closeGeometry();
00123     
00124 #if 0
00125     dm->release(dm);
00126 #endif
00127 }
00128 
00129 // powerful because it handles both cases when there is material and when there's not
00130 void GeometryExporter::createPolylist(short material_index,
00131                     bool has_uvs,
00132                     bool has_color,
00133                     Object *ob,
00134                     std::string& geom_id,
00135                     std::vector<Face>& norind)
00136 {
00137     Mesh *me = (Mesh*)ob->data;
00138     MFace *mfaces = me->mface;
00139     int totfaces = me->totface;
00140 
00141     // <vcount>
00142     int i;
00143     int faces_in_polylist = 0;
00144     std::vector<unsigned long> vcount_list;
00145 
00146     // count faces with this material
00147     for (i = 0; i < totfaces; i++) {
00148         MFace *f = &mfaces[i];
00149         
00150         if (f->mat_nr == material_index) {
00151             faces_in_polylist++;
00152             if (f->v4 == 0) {
00153                 vcount_list.push_back(3);
00154             }
00155             else {
00156                 vcount_list.push_back(4);
00157             }
00158         }
00159     }
00160 
00161     // no faces using this material
00162     if (faces_in_polylist == 0) {
00163         fprintf(stderr, "%s: no faces use material %d\n", id_name(ob).c_str(), material_index);
00164         return;
00165     }
00166         
00167     Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
00168     COLLADASW::Polylist polylist(mSW);
00169         
00170     // sets count attribute in <polylist>
00171     polylist.setCount(faces_in_polylist);
00172         
00173     // sets material name
00174     if (ma) {
00175         std::ostringstream ostr;
00176         ostr << translate_id(id_name(ma)) << material_index+1;
00177         polylist.setMaterial(ostr.str());
00178     }
00179             
00180     COLLADASW::InputList &til = polylist.getInputList();
00181         
00182     // creates <input> in <polylist> for vertices 
00183     COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
00184         
00185     // creates <input> in <polylist> for normals
00186     COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
00187         
00188     til.push_back(input1);
00189     til.push_back(input2);
00190         
00191     // if mesh has uv coords writes <input> for TEXCOORD
00192     int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
00193 
00194     for (i = 0; i < num_layers; i++) {
00195         // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
00196         COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
00197                                 makeUrl(makeTexcoordSourceId(geom_id, i)),
00198                                 2, // offset always 2, this is only until we have optimized UV sets
00199                                 i  // set number equals UV map index
00200                                 );
00201         til.push_back(input3);
00202     }
00203 
00204     if (has_color) {
00205         COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
00206         til.push_back(input4);
00207     }
00208         
00209     // sets <vcount>
00210     polylist.setVCountList(vcount_list);
00211         
00212     // performs the actual writing
00213     polylist.prepareToAppendValues();
00214         
00215     // <p>
00216     int texindex = 0;
00217     for (i = 0; i < totfaces; i++) {
00218         MFace *f = &mfaces[i];
00219 
00220         if (f->mat_nr == material_index) {
00221 
00222             unsigned int *v = &f->v1;
00223             unsigned int *n = &norind[i].v1;
00224             for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
00225                 polylist.appendValues(v[j]);
00226                 polylist.appendValues(n[j]);
00227 
00228                 if (has_uvs)
00229                     polylist.appendValues(texindex + j);
00230 
00231                 if (has_color)
00232                     polylist.appendValues(texindex + j);
00233             }
00234         }
00235 
00236         texindex += 3;
00237         if (f->v4 != 0)
00238             texindex++;
00239     }
00240         
00241     polylist.finish();
00242 }
00243 
00244 // creates <source> for positions
00245 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
00246 {
00247 #if 0
00248     int totverts = dm->getNumVerts(dm);
00249     MVert *verts = dm->getVertArray(dm);
00250 #endif
00251     int totverts = me->totvert;
00252     MVert *verts = me->mvert;
00253     
00254     COLLADASW::FloatSourceF source(mSW);
00255     source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
00256     source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
00257                       ARRAY_ID_SUFFIX);
00258     source.setAccessorCount(totverts);
00259     source.setAccessorStride(3);
00260     COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00261     param.push_back("X");
00262     param.push_back("Y");
00263     param.push_back("Z");
00264     /*main function, it creates <source id = "">, <float_array id = ""
00265       count = ""> */
00266     source.prepareToAppendValues();
00267     //appends data to <float_array>
00268     int i = 0;
00269     for (i = 0; i < totverts; i++) {
00270         source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);            
00271     }
00272     
00273     source.finish();
00274 
00275 }
00276 
00277 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
00278 {
00279     if (!CustomData_has_layer(&me->fdata, CD_MCOL))
00280         return;
00281 
00282     MFace *f;
00283     int totcolor = 0, i, j;
00284 
00285     for (i = 0, f = me->mface; i < me->totface; i++, f++)
00286         totcolor += f->v4 ? 4 : 3;
00287 
00288     COLLADASW::FloatSourceF source(mSW);
00289     source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR));
00290     source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + ARRAY_ID_SUFFIX);
00291     source.setAccessorCount(totcolor);
00292     source.setAccessorStride(3);
00293 
00294     COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00295     param.push_back("R");
00296     param.push_back("G");
00297     param.push_back("B");
00298 
00299     source.prepareToAppendValues();
00300 
00301     int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
00302 
00303     MCol *mcol = (MCol*)me->fdata.layers[index].data;
00304     MCol *c = mcol;
00305 
00306     for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++)
00307         for (j = 0; j < (f->v4 ? 4 : 3); j++)
00308             source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f);
00309     
00310     source.finish();
00311 }
00312 
00313 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
00314 {
00315     char suffix[20];
00316     sprintf(suffix, "-%d", layer_index);
00317     return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
00318 }
00319 
00320 //creates <source> for texcoords
00321 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
00322 {
00323 #if 0
00324     int totfaces = dm->getNumFaces(dm);
00325     MFace *mfaces = dm->getFaceArray(dm);
00326 #endif
00327     int totfaces = me->totface;
00328     MFace *mfaces = me->mface;
00329 
00330     int totuv = 0;
00331     int i;
00332 
00333     // count totuv
00334     for (i = 0; i < totfaces; i++) {
00335         MFace *f = &mfaces[i];
00336         if (f->v4 == 0) {
00337             totuv+=3;
00338         }
00339         else {
00340             totuv+=4;
00341         }
00342     }
00343 
00344     int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
00345 
00346     // write <source> for each layer
00347     // each <source> will get id like meshName + "map-channel-1"
00348     for (int a = 0; a < num_layers; a++) {
00349         MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
00350         // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
00351         
00352         COLLADASW::FloatSourceF source(mSW);
00353         std::string layer_id = makeTexcoordSourceId(geom_id, a);
00354         source.setId(layer_id);
00355         source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
00356         
00357         source.setAccessorCount(totuv);
00358         source.setAccessorStride(2);
00359         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00360         param.push_back("S");
00361         param.push_back("T");
00362         
00363         source.prepareToAppendValues();
00364         
00365         for (i = 0; i < totfaces; i++) {
00366             MFace *f = &mfaces[i];
00367             
00368             for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
00369                 source.appendValues(tface[i].uv[j][0],
00370                                     tface[i].uv[j][1]);
00371             }
00372         }
00373         
00374         source.finish();
00375     }
00376 }
00377 
00378 
00379 //creates <source> for normals
00380 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
00381 {
00382 #if 0
00383     int totverts = dm->getNumVerts(dm);
00384     MVert *verts = dm->getVertArray(dm);
00385 #endif
00386 
00387     COLLADASW::FloatSourceF source(mSW);
00388     source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
00389     source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
00390                       ARRAY_ID_SUFFIX);
00391     source.setAccessorCount((unsigned long)nor.size());
00392     source.setAccessorStride(3);
00393     COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00394     param.push_back("X");
00395     param.push_back("Y");
00396     param.push_back("Z");
00397     
00398     source.prepareToAppendValues();
00399 
00400     std::vector<Normal>::iterator it;
00401     for (it = nor.begin(); it != nor.end(); it++) {
00402         Normal& n = *it;
00403         source.appendValues(n.x, n.y, n.z);
00404     }
00405 
00406     source.finish();
00407 }
00408 
00409 void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
00410 {
00411     int i, j, v;
00412     MVert *vert = me->mvert;
00413     std::map<unsigned int, unsigned int> nshar;
00414 
00415     for (i = 0; i < me->totface; i++) {
00416         MFace *fa = &me->mface[i];
00417         Face f;
00418         unsigned int *nn = &f.v1;
00419         unsigned int *vv = &fa->v1;
00420 
00421         memset(&f, 0, sizeof(f));
00422         v = fa->v4 == 0 ? 3 : 4;
00423 
00424         if (!(fa->flag & ME_SMOOTH)) {
00425             Normal n;
00426             if (v == 4)
00427                 normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
00428             else
00429                 normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
00430             nor.push_back(n);
00431         }
00432 
00433         for (j = 0; j < v; j++) {
00434             if (fa->flag & ME_SMOOTH) {
00435                 if (nshar.find(*vv) != nshar.end())
00436                     *nn = nshar[*vv];
00437                 else {
00438                     Normal n = {
00439                         vert[*vv].no[0]/32767.0,
00440                         vert[*vv].no[1]/32767.0,
00441                         vert[*vv].no[2]/32767.0
00442                     };
00443                     nor.push_back(n);
00444                     *nn = (unsigned int)nor.size() - 1;
00445                     nshar[*vv] = *nn;
00446                 }
00447                 vv++;
00448             }
00449             else {
00450                 *nn = (unsigned int)nor.size() - 1;
00451             }
00452             nn++;
00453         }
00454 
00455         ind.push_back(f);
00456     }
00457 }
00458 
00459 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) {
00460     return geom_id + getSuffixBySemantic(type) + other_suffix;
00461 }
00462 
00463 
00464 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) {
00465     
00466     std::string id(getIdBySemantics(geom_id, type, other_suffix));
00467     return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
00468     
00469 }
00470 
00471 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
00472 {
00473     return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
00474 }
00475 
00476 
00477 /* int GeometryExporter::getTriCount(MFace *faces, int totface) {
00478     int i;
00479     int tris = 0;
00480     for (i = 0; i < totface; i++) {
00481         // if quad
00482         if (faces[i].v4 != 0)
00483             tris += 2;
00484         else
00485             tris++;
00486     }
00487 
00488     return tris;
00489     }*/