|
Blender
V2.59
|
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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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 }*/