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