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