| 1 | /* | 
|---|
| 2 | ----------------------------------------------------------------------------- | 
|---|
| 3 | This source file is part of OGRE | 
|---|
| 4 |     (Object-oriented Graphics Rendering Engine) | 
|---|
| 5 | For the latest info, see http://www.ogre3d.org/ | 
|---|
| 6 |  | 
|---|
| 7 | Copyright (c) 2000-2006 Torus Knot Software Ltd | 
|---|
| 8 | Also see acknowledgements in Readme.html | 
|---|
| 9 |  | 
|---|
| 10 | This program is free software; you can redistribute it and/or modify it under | 
|---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software | 
|---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later | 
|---|
| 13 | version. | 
|---|
| 14 |  | 
|---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. | 
|---|
| 18 |  | 
|---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with | 
|---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
|---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to | 
|---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. | 
|---|
| 23 |  | 
|---|
| 24 | You may alternatively use this source under the terms of a specific version of | 
|---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from | 
|---|
| 26 | Torus Knot Software Ltd. | 
|---|
| 27 | ----------------------------------------------------------------------------- | 
|---|
| 28 | */ | 
|---|
| 29 |  | 
|---|
| 30 |  | 
|---|
| 31 | #include "Ogre.h" | 
|---|
| 32 | #include "OgreXMLMeshSerializer.h" | 
|---|
| 33 | #include "OgreMeshSerializer.h" | 
|---|
| 34 | #include "OgreXMLSkeletonSerializer.h" | 
|---|
| 35 | #include "OgreSkeletonSerializer.h" | 
|---|
| 36 | #include "OgreXMLPrerequisites.h" | 
|---|
| 37 | #include "OgreDefaultHardwareBufferManager.h" | 
|---|
| 38 | #include <iostream> | 
|---|
| 39 | #include <sys/stat.h> | 
|---|
| 40 |  | 
|---|
| 41 | using namespace std; | 
|---|
| 42 | using namespace Ogre; | 
|---|
| 43 |  | 
|---|
| 44 | struct XmlOptions | 
|---|
| 45 | { | 
|---|
| 46 |     String source; | 
|---|
| 47 |     String dest; | 
|---|
| 48 |     String sourceExt; | 
|---|
| 49 |     String destExt; | 
|---|
| 50 |     String logFile; | 
|---|
| 51 |     bool interactiveMode; | 
|---|
| 52 |     unsigned short numLods; | 
|---|
| 53 |     Real lodDist; | 
|---|
| 54 |     Real lodPercent; | 
|---|
| 55 |     size_t lodFixed; | 
|---|
| 56 |     size_t nuextremityPoints; | 
|---|
| 57 |     bool usePercent; | 
|---|
| 58 |     bool generateEdgeLists; | 
|---|
| 59 |     bool generateTangents; | 
|---|
| 60 |         VertexElementSemantic tangentSemantic; | 
|---|
| 61 |     bool reorganiseBuffers; | 
|---|
| 62 |         bool optimiseAnimations; | 
|---|
| 63 |         bool quietMode; | 
|---|
| 64 |         bool d3d; | 
|---|
| 65 |         bool gl; | 
|---|
| 66 |         Serializer::Endian endian; | 
|---|
| 67 | }; | 
|---|
| 68 |  | 
|---|
| 69 | void help(void) | 
|---|
| 70 | { | 
|---|
| 71 |     // Print help message | 
|---|
| 72 |     cout << endl << "OgreXMLConvert: Converts data between XML and OGRE binary formats." << endl; | 
|---|
| 73 |     cout << "Provided for OGRE by Steve Streeting" << endl << endl; | 
|---|
| 74 |     cout << "Usage: OgreXMLConverter [options] sourcefile [destfile] " << endl; | 
|---|
| 75 |         cout << endl << "Available options:" << endl; | 
|---|
| 76 |     cout << "-i             = interactive mode - prompt for options" << endl; | 
|---|
| 77 |     cout << "(The next 4 options are only applicable when converting XML to Mesh)" << endl; | 
|---|
| 78 |     cout << "-l lodlevels   = number of LOD levels" << endl; | 
|---|
| 79 |     cout << "-d loddist     = distance increment to reduce LOD" << endl; | 
|---|
| 80 |     cout << "-p lodpercent  = Percentage triangle reduction amount per LOD" << endl; | 
|---|
| 81 |     cout << "-f lodnumtris  = Fixed vertex reduction per LOD" << endl; | 
|---|
| 82 |     cout << "-e             = DON'T generate edge lists (for stencil shadows)" << endl; | 
|---|
| 83 |     cout << "-r             = DON'T reorganise vertex buffers to OGRE recommended format." << endl; | 
|---|
| 84 |     cout << "-t             = Generate tangents (for normal mapping)" << endl; | 
|---|
| 85 |         cout << "-td [uvw|tangent]" << endl; | 
|---|
| 86 |         cout << "           = Tangent vertex semantic destination (default tangent)" << endl; | 
|---|
| 87 |     cout << "-o             = DON'T optimise out redundant tracks & keyframes" << endl; | 
|---|
| 88 |         cout << "-d3d           = Prefer D3D packed colour formats (default on Windows)" << endl; | 
|---|
| 89 |         cout << "-gl            = Prefer GL packed colour formats (default on non-Windows)" << endl; | 
|---|
| 90 |         cout << "-E endian      = Set endian mode 'big' 'little' or 'native' (default)" << endl; | 
|---|
| 91 |         cout << "-x num         = Generate no more than num eXtremes for every submesh (default 0)" << endl; | 
|---|
| 92 |         cout << "-q             = Quiet mode, less output" << endl; | 
|---|
| 93 |     cout << "-log filename  = name of the log file (default: 'OgreXMLConverter.log')" << endl; | 
|---|
| 94 |     cout << "sourcefile     = name of file to convert" << endl; | 
|---|
| 95 |     cout << "destfile       = optional name of file to write to. If you don't" << endl; | 
|---|
| 96 |     cout << "                 specify this OGRE works it out through the extension " << endl; | 
|---|
| 97 |     cout << "                 and the XML contents if the source is XML. For example" << endl; | 
|---|
| 98 |     cout << "                 test.mesh becomes test.xml, test.xml becomes test.mesh " << endl; | 
|---|
| 99 |     cout << "                 if the XML document root is <mesh> etc."  << endl; | 
|---|
| 100 |  | 
|---|
| 101 |     cout << endl; | 
|---|
| 102 | } | 
|---|
| 103 |  | 
|---|
| 104 |  | 
|---|
| 105 | XmlOptions parseArgs(int numArgs, char **args) | 
|---|
| 106 | { | 
|---|
| 107 |     XmlOptions opts; | 
|---|
| 108 |  | 
|---|
| 109 |     opts.interactiveMode = false; | 
|---|
| 110 |     opts.lodDist = 500; | 
|---|
| 111 |     opts.lodFixed = 0; | 
|---|
| 112 |     opts.lodPercent = 20; | 
|---|
| 113 |     opts.numLods = 0; | 
|---|
| 114 |     opts.nuextremityPoints = 0; | 
|---|
| 115 |     opts.usePercent = true; | 
|---|
| 116 |     opts.generateEdgeLists = true; | 
|---|
| 117 |     opts.generateTangents = false; | 
|---|
| 118 |         opts.tangentSemantic = VES_TANGENT; | 
|---|
| 119 |     opts.reorganiseBuffers = true; | 
|---|
| 120 |         opts.optimiseAnimations = true; | 
|---|
| 121 |     opts.quietMode = false; | 
|---|
| 122 |         opts.endian = Serializer::ENDIAN_NATIVE; | 
|---|
| 123 |  | 
|---|
| 124 |     // ignore program name | 
|---|
| 125 |     char* source = 0; | 
|---|
| 126 |     char* dest = 0; | 
|---|
| 127 |  | 
|---|
| 128 |     // Set up options | 
|---|
| 129 |     UnaryOptionList unOpt; | 
|---|
| 130 |     BinaryOptionList binOpt; | 
|---|
| 131 |  | 
|---|
| 132 |     unOpt["-i"] = false; | 
|---|
| 133 |     unOpt["-e"] = false; | 
|---|
| 134 |     unOpt["-r"] = false; | 
|---|
| 135 |     unOpt["-t"] = false; | 
|---|
| 136 |     unOpt["-o"] = false; | 
|---|
| 137 |         unOpt["-q"] = false; | 
|---|
| 138 |         unOpt["-d3d"] = false; | 
|---|
| 139 |         unOpt["-gl"] = false; | 
|---|
| 140 |     binOpt["-l"] = ""; | 
|---|
| 141 |     binOpt["-d"] = ""; | 
|---|
| 142 |     binOpt["-p"] = ""; | 
|---|
| 143 |     binOpt["-f"] = ""; | 
|---|
| 144 |     binOpt["-E"] = ""; | 
|---|
| 145 |     binOpt["-x"] = ""; | 
|---|
| 146 |     binOpt["-log"] = "OgreXMLConverter.log"; | 
|---|
| 147 |         binOpt["-td"] = ""; | 
|---|
| 148 |  | 
|---|
| 149 |     int startIndex = findCommandLineOpts(numArgs, args, unOpt, binOpt); | 
|---|
| 150 |     UnaryOptionList::iterator ui; | 
|---|
| 151 |     BinaryOptionList::iterator bi; | 
|---|
| 152 |  | 
|---|
| 153 |         ui = unOpt.find("-q"); | 
|---|
| 154 |         if (ui->second) | 
|---|
| 155 |         { | 
|---|
| 156 |                 opts.quietMode = true; | 
|---|
| 157 |         } | 
|---|
| 158 |  | 
|---|
| 159 |         ui = unOpt.find("-i"); | 
|---|
| 160 |     if (ui->second) | 
|---|
| 161 |     { | 
|---|
| 162 |         opts.interactiveMode = true; | 
|---|
| 163 |     } | 
|---|
| 164 |     else | 
|---|
| 165 |     { | 
|---|
| 166 |         ui = unOpt.find("-e"); | 
|---|
| 167 |         if (ui->second) | 
|---|
| 168 |         { | 
|---|
| 169 |             opts.generateEdgeLists = false; | 
|---|
| 170 |         } | 
|---|
| 171 |      | 
|---|
| 172 |         ui = unOpt.find("-r"); | 
|---|
| 173 |         if (ui->second) | 
|---|
| 174 |         { | 
|---|
| 175 |             opts.reorganiseBuffers = false; | 
|---|
| 176 |         } | 
|---|
| 177 |  | 
|---|
| 178 |         ui = unOpt.find("-t"); | 
|---|
| 179 |         if (ui->second) | 
|---|
| 180 |         { | 
|---|
| 181 |             opts.generateTangents = true; | 
|---|
| 182 |         } | 
|---|
| 183 |                 bi = binOpt.find("-td"); | 
|---|
| 184 |                 if (!bi->second.empty()) | 
|---|
| 185 |                 { | 
|---|
| 186 |                         if (bi->second == "uvw") | 
|---|
| 187 |                                 opts.tangentSemantic = VES_TEXTURE_COORDINATES; | 
|---|
| 188 |                         else | 
|---|
| 189 |                                 opts.tangentSemantic = VES_TANGENT; | 
|---|
| 190 |                 } | 
|---|
| 191 |  | 
|---|
| 192 |         ui = unOpt.find("-o"); | 
|---|
| 193 |         if (ui->second) | 
|---|
| 194 |         { | 
|---|
| 195 |             opts.optimiseAnimations = false; | 
|---|
| 196 |         } | 
|---|
| 197 |  | 
|---|
| 198 |                 bi = binOpt.find("-l"); | 
|---|
| 199 |         if (!bi->second.empty()) | 
|---|
| 200 |         { | 
|---|
| 201 |             opts.numLods = StringConverter::parseInt(bi->second); | 
|---|
| 202 |         } | 
|---|
| 203 |  | 
|---|
| 204 |         bi = binOpt.find("-d"); | 
|---|
| 205 |         if (!bi->second.empty()) | 
|---|
| 206 |         { | 
|---|
| 207 |             opts.lodDist = StringConverter::parseReal(bi->second); | 
|---|
| 208 |         } | 
|---|
| 209 |  | 
|---|
| 210 |         bi = binOpt.find("-p"); | 
|---|
| 211 |         if (!bi->second.empty()) | 
|---|
| 212 |         { | 
|---|
| 213 |             opts.lodPercent = StringConverter::parseReal(bi->second); | 
|---|
| 214 |             opts.usePercent = true; | 
|---|
| 215 |         } | 
|---|
| 216 |  | 
|---|
| 217 |  | 
|---|
| 218 |         bi = binOpt.find("-f"); | 
|---|
| 219 |         if (!bi->second.empty()) | 
|---|
| 220 |         { | 
|---|
| 221 |             opts.lodFixed = StringConverter::parseInt(bi->second); | 
|---|
| 222 |             opts.usePercent = false; | 
|---|
| 223 |         } | 
|---|
| 224 |  | 
|---|
| 225 |         bi = binOpt.find("-x"); | 
|---|
| 226 |         if (!bi->second.empty()) | 
|---|
| 227 |         { | 
|---|
| 228 |             opts.nuextremityPoints = StringConverter::parseInt(bi->second); | 
|---|
| 229 |         } | 
|---|
| 230 |  | 
|---|
| 231 |         bi = binOpt.find("-log"); | 
|---|
| 232 |         if (!bi->second.empty()) | 
|---|
| 233 |         { | 
|---|
| 234 |             opts.logFile = bi->second; | 
|---|
| 235 |         } | 
|---|
| 236 |  | 
|---|
| 237 |         bi = binOpt.find("-E"); | 
|---|
| 238 |         if (!bi->second.empty()) | 
|---|
| 239 |         { | 
|---|
| 240 |             if (bi->second == "big") | 
|---|
| 241 |                 opts.endian = Serializer::ENDIAN_BIG; | 
|---|
| 242 |             else if (bi->second == "little") | 
|---|
| 243 |                 opts.endian = Serializer::ENDIAN_LITTLE; | 
|---|
| 244 |             else  | 
|---|
| 245 |                 opts.endian = Serializer::ENDIAN_NATIVE; | 
|---|
| 246 |         } | 
|---|
| 247 |  | 
|---|
| 248 |                 ui = unOpt.find("-d3d"); | 
|---|
| 249 |                 if (ui->second) | 
|---|
| 250 |                 { | 
|---|
| 251 |                         opts.d3d = true; | 
|---|
| 252 |                 } | 
|---|
| 253 |  | 
|---|
| 254 |                 ui = unOpt.find("-gl"); | 
|---|
| 255 |                 if (ui->second) | 
|---|
| 256 |                 { | 
|---|
| 257 |                         opts.gl = true; | 
|---|
| 258 |                         opts.d3d = false; | 
|---|
| 259 |                 } | 
|---|
| 260 |  | 
|---|
| 261 |         } | 
|---|
| 262 |     // Source / dest | 
|---|
| 263 |     if (numArgs > startIndex) | 
|---|
| 264 |         source = args[startIndex]; | 
|---|
| 265 |     if (numArgs > startIndex+1) | 
|---|
| 266 |         dest = args[startIndex+1]; | 
|---|
| 267 |  | 
|---|
| 268 |     if (!source) | 
|---|
| 269 |     { | 
|---|
| 270 |         cout << "Missing source file - abort. " << endl; | 
|---|
| 271 |         help(); | 
|---|
| 272 |         exit(1); | 
|---|
| 273 |     } | 
|---|
| 274 |     // Work out what kind of conversion this is | 
|---|
| 275 |     opts.source = source; | 
|---|
| 276 |         std::vector<String> srcparts = StringUtil::split(opts.source, "."); | 
|---|
| 277 |     String& ext = srcparts.back(); | 
|---|
| 278 |         StringUtil::toLowerCase(ext); | 
|---|
| 279 |     opts.sourceExt = ext; | 
|---|
| 280 |  | 
|---|
| 281 |     if (!dest) | 
|---|
| 282 |     { | 
|---|
| 283 |         if (opts.sourceExt == "xml") | 
|---|
| 284 |         { | 
|---|
| 285 |             // dest is source minus .xml | 
|---|
| 286 |             opts.dest = opts.source.substr(0, opts.source.size() - 4); | 
|---|
| 287 |         } | 
|---|
| 288 |         else | 
|---|
| 289 |         { | 
|---|
| 290 |             // dest is source + .xml | 
|---|
| 291 |             opts.dest = opts.source; | 
|---|
| 292 |             opts.dest.append(".xml"); | 
|---|
| 293 |         } | 
|---|
| 294 |  | 
|---|
| 295 |     } | 
|---|
| 296 |     else | 
|---|
| 297 |     { | 
|---|
| 298 |         opts.dest = dest; | 
|---|
| 299 |     } | 
|---|
| 300 |         std::vector<String> dstparts = StringUtil::split(opts.dest, "."); | 
|---|
| 301 |     ext = dstparts.back(); | 
|---|
| 302 |         StringUtil::toLowerCase(ext); | 
|---|
| 303 |     opts.destExt = ext; | 
|---|
| 304 |  | 
|---|
| 305 |     if (!opts.quietMode)  | 
|---|
| 306 |         { | 
|---|
| 307 |         cout << endl; | 
|---|
| 308 |         cout << "-- OPTIONS --" << endl; | 
|---|
| 309 |         cout << "source file      = " << opts.source << endl; | 
|---|
| 310 |         cout << "destination file = " << opts.dest << endl; | 
|---|
| 311 |             cout << "log file         = " << opts.logFile << endl; | 
|---|
| 312 |         cout << "interactive mode = " << StringConverter::toString(opts.interactiveMode) << endl; | 
|---|
| 313 |         if (opts.numLods == 0) | 
|---|
| 314 |         { | 
|---|
| 315 |             cout << "lod levels       = none (or use existing)" << endl; | 
|---|
| 316 |         } | 
|---|
| 317 |         else | 
|---|
| 318 |         { | 
|---|
| 319 |             cout << "lod levels       = " << opts.numLods << endl; | 
|---|
| 320 |             cout << "lod distance     = " << opts.lodDist << endl; | 
|---|
| 321 |             if (opts.usePercent) | 
|---|
| 322 |             { | 
|---|
| 323 |                 cout << "lod reduction    = " << opts.lodPercent << "%" << endl; | 
|---|
| 324 |             } | 
|---|
| 325 |             else | 
|---|
| 326 |             { | 
|---|
| 327 |                 cout << "lod reduction    = " << opts.lodFixed << " verts" << endl; | 
|---|
| 328 |             } | 
|---|
| 329 |         } | 
|---|
| 330 |         if (opts.nuextremityPoints) | 
|---|
| 331 |             cout << "Generate extremes per submesh = " << opts.nuextremityPoints << endl; | 
|---|
| 332 |         cout << "Generate edge lists  = " << opts.generateEdgeLists << endl; | 
|---|
| 333 |         cout << "Generate tangents = " << opts.generateTangents << endl; | 
|---|
| 334 |         cout << "Reorganise vertex buffers = " << opts.reorganiseBuffers << endl; | 
|---|
| 335 |         cout << "Optimise animations = " << opts.optimiseAnimations << endl; | 
|---|
| 336 |          | 
|---|
| 337 |         cout << "-- END OPTIONS --" << endl; | 
|---|
| 338 |         cout << endl; | 
|---|
| 339 |     } | 
|---|
| 340 |  | 
|---|
| 341 |  | 
|---|
| 342 |     return opts; | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | // Crappy globals | 
|---|
| 346 | // NB some of these are not directly used, but are required to | 
|---|
| 347 | //   instantiate the singletons used in the dlls | 
|---|
| 348 | LogManager* logMgr = 0; | 
|---|
| 349 | Math* mth = 0; | 
|---|
| 350 | MaterialManager* matMgr = 0; | 
|---|
| 351 | SkeletonManager* skelMgr = 0; | 
|---|
| 352 | MeshSerializer* meshSerializer = 0; | 
|---|
| 353 | XMLMeshSerializer* xmlMeshSerializer = 0; | 
|---|
| 354 | SkeletonSerializer* skeletonSerializer = 0; | 
|---|
| 355 | XMLSkeletonSerializer* xmlSkeletonSerializer = 0; | 
|---|
| 356 | DefaultHardwareBufferManager *bufferManager = 0; | 
|---|
| 357 | MeshManager* meshMgr = 0; | 
|---|
| 358 | ResourceGroupManager* rgm = 0; | 
|---|
| 359 |  | 
|---|
| 360 |  | 
|---|
| 361 | void meshToXML(XmlOptions opts) | 
|---|
| 362 | { | 
|---|
| 363 |     std::ifstream ifs; | 
|---|
| 364 |     ifs.open(opts.source.c_str(), std::ios_base::in | std::ios_base::binary); | 
|---|
| 365 |     // pass false for freeOnClose to FileStreamDataStream since ifs is created on stack | 
|---|
| 366 |     DataStreamPtr stream(new FileStreamDataStream(opts.source, &ifs, false)); | 
|---|
| 367 |  | 
|---|
| 368 |     MeshPtr mesh = MeshManager::getSingleton().create("conversion",  | 
|---|
| 369 |         ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); | 
|---|
| 370 |      | 
|---|
| 371 |  | 
|---|
| 372 |     meshSerializer->importMesh(stream, mesh.getPointer()); | 
|---|
| 373 |     | 
|---|
| 374 |     xmlMeshSerializer->exportMesh(mesh.getPointer(), opts.dest); | 
|---|
| 375 |  | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | void XMLToBinary(XmlOptions opts) | 
|---|
| 379 | { | 
|---|
| 380 |     // Read root element and decide from there what type | 
|---|
| 381 |     String response; | 
|---|
| 382 |     TiXmlDocument* doc = new TiXmlDocument(opts.source); | 
|---|
| 383 |     // Some double-parsing here but never mind | 
|---|
| 384 |     if (!doc->LoadFile()) | 
|---|
| 385 |     { | 
|---|
| 386 |         cout << "Unable to open file " << opts.source << " - fatal error." << endl; | 
|---|
| 387 |         delete doc; | 
|---|
| 388 |         exit (1); | 
|---|
| 389 |     } | 
|---|
| 390 |     TiXmlElement* root = doc->RootElement(); | 
|---|
| 391 |     if (!stricmp(root->Value(), "mesh")) | 
|---|
| 392 |     { | 
|---|
| 393 |         delete doc; | 
|---|
| 394 |         MeshPtr newMesh = MeshManager::getSingleton().createManual("conversion",  | 
|---|
| 395 |             ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); | 
|---|
| 396 |                 VertexElementType colourElementType; | 
|---|
| 397 |                 if (opts.d3d) | 
|---|
| 398 |                         colourElementType = VET_COLOUR_ARGB; | 
|---|
| 399 |                 else | 
|---|
| 400 |                         colourElementType = VET_COLOUR_ABGR; | 
|---|
| 401 |  | 
|---|
| 402 |         xmlMeshSerializer->importMesh(opts.source, colourElementType, newMesh.getPointer()); | 
|---|
| 403 |  | 
|---|
| 404 |         // Re-jig the buffers? | 
|---|
| 405 |         if (opts.reorganiseBuffers) | 
|---|
| 406 |         { | 
|---|
| 407 |             logMgr->logMessage("Reorganising vertex buffers to automatic layout.."); | 
|---|
| 408 |             // Shared geometry | 
|---|
| 409 |             if (newMesh->sharedVertexData) | 
|---|
| 410 |             { | 
|---|
| 411 |                 // Automatic | 
|---|
| 412 |                 VertexDeclaration* newDcl =  | 
|---|
| 413 |                     newMesh->sharedVertexData->vertexDeclaration->getAutoOrganisedDeclaration( | 
|---|
| 414 |                         newMesh->hasSkeleton(), newMesh->hasVertexAnimation()); | 
|---|
| 415 |                 if (*newDcl != *(newMesh->sharedVertexData->vertexDeclaration)) | 
|---|
| 416 |                 { | 
|---|
| 417 |                     // Usages don't matter here since we're onlly exporting | 
|---|
| 418 |                     BufferUsageList bufferUsages; | 
|---|
| 419 |                     for (size_t u = 0; u <= newDcl->getMaxSource(); ++u) | 
|---|
| 420 |                         bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY); | 
|---|
| 421 |                     newMesh->sharedVertexData->reorganiseBuffers(newDcl, bufferUsages); | 
|---|
| 422 |                 } | 
|---|
| 423 |             } | 
|---|
| 424 |             // Dedicated geometry | 
|---|
| 425 |             Mesh::SubMeshIterator smIt = newMesh->getSubMeshIterator(); | 
|---|
| 426 |             while (smIt.hasMoreElements()) | 
|---|
| 427 |             { | 
|---|
| 428 |                 SubMesh* sm = smIt.getNext(); | 
|---|
| 429 |                 if (!sm->useSharedVertices) | 
|---|
| 430 |                 { | 
|---|
| 431 |                     // Automatic | 
|---|
| 432 |                     VertexDeclaration* newDcl =  | 
|---|
| 433 |                         sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration( | 
|---|
| 434 |                             newMesh->hasSkeleton(), newMesh->hasVertexAnimation()); | 
|---|
| 435 |                     if (*newDcl != *(sm->vertexData->vertexDeclaration)) | 
|---|
| 436 |                     { | 
|---|
| 437 |                         // Usages don't matter here since we're onlly exporting | 
|---|
| 438 |                         BufferUsageList bufferUsages; | 
|---|
| 439 |                         for (size_t u = 0; u <= newDcl->getMaxSource(); ++u) | 
|---|
| 440 |                             bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY); | 
|---|
| 441 |                         sm->vertexData->reorganiseBuffers(newDcl, bufferUsages); | 
|---|
| 442 |                     } | 
|---|
| 443 |                 } | 
|---|
| 444 |             } | 
|---|
| 445 |  | 
|---|
| 446 |         } | 
|---|
| 447 |  | 
|---|
| 448 |         // Prompt for LOD generation? | 
|---|
| 449 |         bool genLod = false; | 
|---|
| 450 |         bool askLodDtls = false; | 
|---|
| 451 |         if (!opts.interactiveMode) // derive from params if in batch mode | 
|---|
| 452 |         { | 
|---|
| 453 |             askLodDtls = false; | 
|---|
| 454 |             if (opts.numLods == 0) | 
|---|
| 455 |             { | 
|---|
| 456 |                 genLod = false; | 
|---|
| 457 |             } | 
|---|
| 458 |             else | 
|---|
| 459 |             { | 
|---|
| 460 |                 genLod = true; | 
|---|
| 461 |             } | 
|---|
| 462 |         } | 
|---|
| 463 |         else if(opts.numLods == 0) // otherwise only ask if not specified on command line | 
|---|
| 464 |         { | 
|---|
| 465 |             if (newMesh->getNumLodLevels() > 1) | 
|---|
| 466 |             { | 
|---|
| 467 |                 std::cout << "\nXML already contains level-of detail information.\n" | 
|---|
| 468 |                     "Do you want to: (u)se it, (r)eplace it, or (d)rop it?"; | 
|---|
| 469 |                 while (response == "") | 
|---|
| 470 |                 { | 
|---|
| 471 |                     cin >> response; | 
|---|
| 472 |                                         StringUtil::toLowerCase(response); | 
|---|
| 473 |                     if (response == "u") | 
|---|
| 474 |                     { | 
|---|
| 475 |                         // Do nothing | 
|---|
| 476 |                     } | 
|---|
| 477 |                     else if (response == "d") | 
|---|
| 478 |                     { | 
|---|
| 479 |                         newMesh->removeLodLevels(); | 
|---|
| 480 |                     } | 
|---|
| 481 |                     else if (response == "r") | 
|---|
| 482 |                     { | 
|---|
| 483 |                         genLod = true; | 
|---|
| 484 |                         askLodDtls = true; | 
|---|
| 485 |  | 
|---|
| 486 |                     } | 
|---|
| 487 |                     else | 
|---|
| 488 |                     { | 
|---|
| 489 |                         response = ""; | 
|---|
| 490 |                     } | 
|---|
| 491 |                 }// while response == "" | 
|---|
| 492 |             } | 
|---|
| 493 |             else // no existing LOD | 
|---|
| 494 |             { | 
|---|
| 495 |                 std::cout << "\nWould you like to generate LOD information? (y/n)"; | 
|---|
| 496 |                 while (response == "") | 
|---|
| 497 |                 { | 
|---|
| 498 |                     cin >> response; | 
|---|
| 499 |                                         StringUtil::toLowerCase(response); | 
|---|
| 500 |                     if (response == "n") | 
|---|
| 501 |                     { | 
|---|
| 502 |                         // Do nothing | 
|---|
| 503 |                     } | 
|---|
| 504 |                     else if (response == "y") | 
|---|
| 505 |                     { | 
|---|
| 506 |                         genLod = true; | 
|---|
| 507 |                         askLodDtls = true; | 
|---|
| 508 |                     } | 
|---|
| 509 |                 } | 
|---|
| 510 |             } | 
|---|
| 511 |         } | 
|---|
| 512 |  | 
|---|
| 513 |         if (genLod) | 
|---|
| 514 |         { | 
|---|
| 515 |             unsigned short numLod; | 
|---|
| 516 |             ProgressiveMesh::VertexReductionQuota quota; | 
|---|
| 517 |             Real reduction; | 
|---|
| 518 |             Mesh::LodDistanceList distanceList; | 
|---|
| 519 |  | 
|---|
| 520 |             if (askLodDtls) | 
|---|
| 521 |             { | 
|---|
| 522 |                 cout << "\nHow many extra LOD levels would you like to generate?"; | 
|---|
| 523 |                 cin >> numLod; | 
|---|
| 524 |  | 
|---|
| 525 |                 cout << "\nWhat unit of reduction would you like to use:" << | 
|---|
| 526 |                     "\n(f)ixed or (p)roportional?"; | 
|---|
| 527 |                 cin >> response; | 
|---|
| 528 |                                 StringUtil::toLowerCase(response); | 
|---|
| 529 |                 if (response == "f") | 
|---|
| 530 |                 { | 
|---|
| 531 |                     quota = ProgressiveMesh::VRQ_CONSTANT; | 
|---|
| 532 |                     cout << "\nHow many vertices should be removed at each LOD?"; | 
|---|
| 533 |                 } | 
|---|
| 534 |                 else | 
|---|
| 535 |                 { | 
|---|
| 536 |                     quota = ProgressiveMesh::VRQ_PROPORTIONAL; | 
|---|
| 537 |                     cout << "\nWhat percentage of remaining vertices should be removed " | 
|---|
| 538 |                         "\at each LOD (e.g. 50)?"; | 
|---|
| 539 |                 } | 
|---|
| 540 |                 cin >> reduction; | 
|---|
| 541 |                 if (quota == ProgressiveMesh::VRQ_PROPORTIONAL) | 
|---|
| 542 |                 { | 
|---|
| 543 |                     // Percentage -> parametric | 
|---|
| 544 |                     reduction = reduction * 0.01f; | 
|---|
| 545 |                 } | 
|---|
| 546 |  | 
|---|
| 547 |                 cout << "\nEnter the distance for each LOD to come into effect."; | 
|---|
| 548 |  | 
|---|
| 549 |                 Real distance; | 
|---|
| 550 |                 for (unsigned short iLod = 0; iLod < numLod; ++iLod) | 
|---|
| 551 |                 { | 
|---|
| 552 |                     cout << "\nLOD Level " << (iLod+1) << ":"; | 
|---|
| 553 |                     cin >> distance; | 
|---|
| 554 |                     distanceList.push_back(distance); | 
|---|
| 555 |                 } | 
|---|
| 556 |             } | 
|---|
| 557 |             else | 
|---|
| 558 |             { | 
|---|
| 559 |                 numLod = opts.numLods; | 
|---|
| 560 |                 quota = opts.usePercent?  | 
|---|
| 561 |                     ProgressiveMesh::VRQ_PROPORTIONAL : ProgressiveMesh::VRQ_CONSTANT; | 
|---|
| 562 |                 if (opts.usePercent) | 
|---|
| 563 |                 { | 
|---|
| 564 |                     reduction = opts.lodPercent * 0.01f; | 
|---|
| 565 |                 } | 
|---|
| 566 |                 else | 
|---|
| 567 |                 { | 
|---|
| 568 |                     reduction = opts.lodFixed; | 
|---|
| 569 |                 } | 
|---|
| 570 |                 Real currDist = 0; | 
|---|
| 571 |                 for (unsigned short iLod = 0; iLod < numLod; ++iLod) | 
|---|
| 572 |                 { | 
|---|
| 573 |                     currDist += opts.lodDist; | 
|---|
| 574 |                     distanceList.push_back(currDist); | 
|---|
| 575 |                 } | 
|---|
| 576 |  | 
|---|
| 577 |             } | 
|---|
| 578 |  | 
|---|
| 579 |             newMesh->generateLodLevels(distanceList, quota, reduction); | 
|---|
| 580 |         } | 
|---|
| 581 |  | 
|---|
| 582 |         if (opts.interactiveMode) | 
|---|
| 583 |         { | 
|---|
| 584 |             std::cout << "\nWould you like to include edge lists to enable stencil shadows with this mesh? (y/n)"; | 
|---|
| 585 |             while (response == "") | 
|---|
| 586 |             { | 
|---|
| 587 |                 cin >> response; | 
|---|
| 588 |                 StringUtil::toLowerCase(response); | 
|---|
| 589 |                 if (response == "y") | 
|---|
| 590 |                 { | 
|---|
| 591 |                     // Do nothing | 
|---|
| 592 |                 } | 
|---|
| 593 |                 else if (response == "n") | 
|---|
| 594 |                 { | 
|---|
| 595 |                     opts.generateEdgeLists = false; | 
|---|
| 596 |                 } | 
|---|
| 597 |                 else | 
|---|
| 598 |                 { | 
|---|
| 599 |                     response = ""; | 
|---|
| 600 |                 } | 
|---|
| 601 |             } | 
|---|
| 602 |  | 
|---|
| 603 |  | 
|---|
| 604 |             std::cout << "\nWould you like to generate tangents to enable normal mapping with this mesh? (y/n)"; | 
|---|
| 605 |             while (response == "") | 
|---|
| 606 |             { | 
|---|
| 607 |                 cin >> response; | 
|---|
| 608 |                 StringUtil::toLowerCase(response); | 
|---|
| 609 |                 if (response == "y") | 
|---|
| 610 |                 { | 
|---|
| 611 |                     opts.generateTangents = true; | 
|---|
| 612 |                 } | 
|---|
| 613 |                 else if (response == "n") | 
|---|
| 614 |                 { | 
|---|
| 615 |                     // Do nothing | 
|---|
| 616 |                 } | 
|---|
| 617 |                 else | 
|---|
| 618 |                 { | 
|---|
| 619 |                     response = ""; | 
|---|
| 620 |                 } | 
|---|
| 621 |             } | 
|---|
| 622 |         } | 
|---|
| 623 |  | 
|---|
| 624 |         if (opts.generateEdgeLists) | 
|---|
| 625 |         { | 
|---|
| 626 |             if (!opts.quietMode)  | 
|---|
| 627 |                         { | 
|---|
| 628 |                 std::cout << "Generating edge lists...." << std::endl; | 
|---|
| 629 |             } | 
|---|
| 630 |             newMesh->buildEdgeList(); | 
|---|
| 631 |         } | 
|---|
| 632 |  | 
|---|
| 633 |         if (opts.generateTangents) | 
|---|
| 634 |         { | 
|---|
| 635 |             unsigned short srcTex, destTex; | 
|---|
| 636 |             bool existing = newMesh->suggestTangentVectorBuildParams(opts.tangentSemantic, srcTex, destTex); | 
|---|
| 637 |             if (existing) | 
|---|
| 638 |             { | 
|---|
| 639 |                 std::cout << "\nThis mesh appears to already have a set of 3D texture coordinates, " << | 
|---|
| 640 |                     "which would suggest tangent vectors have already been calculated. Do you really " << | 
|---|
| 641 |                     "want to generate new tangent vectors (may duplicate)? (y/n)"; | 
|---|
| 642 |                 while (response == "") | 
|---|
| 643 |                 { | 
|---|
| 644 |                     cin >> response; | 
|---|
| 645 |                     StringUtil::toLowerCase(response); | 
|---|
| 646 |                     if (response == "y") | 
|---|
| 647 |                     { | 
|---|
| 648 |                         // Do nothing | 
|---|
| 649 |                     } | 
|---|
| 650 |                     else if (response == "n") | 
|---|
| 651 |                     { | 
|---|
| 652 |                         opts.generateTangents = false; | 
|---|
| 653 |                     } | 
|---|
| 654 |                     else | 
|---|
| 655 |                     { | 
|---|
| 656 |                         response = ""; | 
|---|
| 657 |                     } | 
|---|
| 658 |                 } | 
|---|
| 659 |  | 
|---|
| 660 |             } | 
|---|
| 661 |             if (opts.generateTangents) | 
|---|
| 662 |             { | 
|---|
| 663 |                 if (!opts.quietMode)  | 
|---|
| 664 |                                 { | 
|---|
| 665 |                     std::cout << "Generating tangent vectors...." << std::endl; | 
|---|
| 666 |                 } | 
|---|
| 667 |                 newMesh->buildTangentVectors(opts.tangentSemantic, srcTex, destTex); | 
|---|
| 668 |             } | 
|---|
| 669 |         } | 
|---|
| 670 |  | 
|---|
| 671 |         if (opts.nuextremityPoints) | 
|---|
| 672 |         { | 
|---|
| 673 |             Mesh::SubMeshIterator smIt = newMesh->getSubMeshIterator(); | 
|---|
| 674 |             while (smIt.hasMoreElements()) | 
|---|
| 675 |             { | 
|---|
| 676 |                 SubMesh* sm = smIt.getNext(); | 
|---|
| 677 |                 sm->generateExtremes (opts.nuextremityPoints); | 
|---|
| 678 |             } | 
|---|
| 679 |         } | 
|---|
| 680 |  | 
|---|
| 681 |         meshSerializer->exportMesh(newMesh.getPointer(), opts.dest, opts.endian); | 
|---|
| 682 |     } | 
|---|
| 683 |     else if (!stricmp(root->Value(), "skeleton")) | 
|---|
| 684 |     { | 
|---|
| 685 |         delete doc; | 
|---|
| 686 |         SkeletonPtr newSkel = SkeletonManager::getSingleton().create("conversion",  | 
|---|
| 687 |             ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); | 
|---|
| 688 |         xmlSkeletonSerializer->importSkeleton(opts.source, newSkel.getPointer()); | 
|---|
| 689 |                 if (opts.optimiseAnimations) | 
|---|
| 690 |                 { | 
|---|
| 691 |                         newSkel->optimiseAllAnimations(); | 
|---|
| 692 |                 } | 
|---|
| 693 |         skeletonSerializer->exportSkeleton(newSkel.getPointer(), opts.dest, opts.endian); | 
|---|
| 694 |     } | 
|---|
| 695 |     else | 
|---|
| 696 |     { | 
|---|
| 697 |         delete doc; | 
|---|
| 698 |     } | 
|---|
| 699 |  | 
|---|
| 700 | } | 
|---|
| 701 |  | 
|---|
| 702 | void skeletonToXML(XmlOptions opts) | 
|---|
| 703 | { | 
|---|
| 704 |  | 
|---|
| 705 |     std::ifstream ifs; | 
|---|
| 706 |     ifs.open(opts.source.c_str(), std::ios_base::in | std::ios_base::binary); | 
|---|
| 707 |         if (!ifs) | 
|---|
| 708 |         { | 
|---|
| 709 |                 cout << "Unable to load file " << opts.source << endl; | 
|---|
| 710 |                 exit(1); | 
|---|
| 711 |         } | 
|---|
| 712 |  | 
|---|
| 713 |     SkeletonPtr skel = SkeletonManager::getSingleton().create("conversion",  | 
|---|
| 714 |         ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); | 
|---|
| 715 |  | 
|---|
| 716 |     // pass false for freeOnClose to FileStreamDataStream since ifs is created localy on stack | 
|---|
| 717 |     DataStreamPtr stream(new FileStreamDataStream(opts.source, &ifs, false)); | 
|---|
| 718 |     skeletonSerializer->importSkeleton(stream, skel.getPointer()); | 
|---|
| 719 |     | 
|---|
| 720 |     xmlSkeletonSerializer->exportSkeleton(skel.getPointer(), opts.dest); | 
|---|
| 721 |  | 
|---|
| 722 | } | 
|---|
| 723 |  | 
|---|
| 724 | int main(int numargs, char** args) | 
|---|
| 725 | { | 
|---|
| 726 |     if (numargs < 2) | 
|---|
| 727 |     { | 
|---|
| 728 |         help(); | 
|---|
| 729 |         return -1; | 
|---|
| 730 |     } | 
|---|
| 731 |  | 
|---|
| 732 |         // Assume success | 
|---|
| 733 |         int retCode = 0; | 
|---|
| 734 |  | 
|---|
| 735 |         try  | 
|---|
| 736 |         { | 
|---|
| 737 |                 XmlOptions opts = parseArgs(numargs, args); | 
|---|
| 738 |  | 
|---|
| 739 |                 logMgr = new LogManager(); | 
|---|
| 740 |                 logMgr->createLog(opts.logFile, false, !opts.quietMode);  | 
|---|
| 741 |                 rgm = new ResourceGroupManager(); | 
|---|
| 742 |                 mth = new Math(); | 
|---|
| 743 |                 meshMgr = new MeshManager(); | 
|---|
| 744 |                 matMgr = new MaterialManager(); | 
|---|
| 745 |                 matMgr->initialise(); | 
|---|
| 746 |                 skelMgr = new SkeletonManager(); | 
|---|
| 747 |                 meshSerializer = new MeshSerializer(); | 
|---|
| 748 |                 xmlMeshSerializer = new XMLMeshSerializer(); | 
|---|
| 749 |                 skeletonSerializer = new SkeletonSerializer(); | 
|---|
| 750 |                 xmlSkeletonSerializer = new XMLSkeletonSerializer(); | 
|---|
| 751 |                 bufferManager = new DefaultHardwareBufferManager(); // needed because we don't have a rendersystem | 
|---|
| 752 |  | 
|---|
| 753 |  | 
|---|
| 754 |  | 
|---|
| 755 |                 if (opts.sourceExt == "mesh") | 
|---|
| 756 |                 { | 
|---|
| 757 |                         meshToXML(opts); | 
|---|
| 758 |                 } | 
|---|
| 759 |                 else if (opts.sourceExt == "skeleton") | 
|---|
| 760 |                 { | 
|---|
| 761 |                         skeletonToXML(opts); | 
|---|
| 762 |                 } | 
|---|
| 763 |                 else if (opts.sourceExt == "xml") | 
|---|
| 764 |                 { | 
|---|
| 765 |                         XMLToBinary(opts); | 
|---|
| 766 |                 } | 
|---|
| 767 |                 else | 
|---|
| 768 |                 { | 
|---|
| 769 |                         cout << "Unknown input type.\n"; | 
|---|
| 770 |                         retCode = 1; | 
|---|
| 771 |                 } | 
|---|
| 772 |  | 
|---|
| 773 |         } | 
|---|
| 774 |         catch(Exception& e) | 
|---|
| 775 |         { | 
|---|
| 776 |                 cout << "Exception caught: " << e.getDescription(); | 
|---|
| 777 |                 retCode = 1; | 
|---|
| 778 |         } | 
|---|
| 779 |  | 
|---|
| 780 |     delete xmlSkeletonSerializer; | 
|---|
| 781 |     delete skeletonSerializer; | 
|---|
| 782 |     delete xmlMeshSerializer; | 
|---|
| 783 |     delete meshSerializer; | 
|---|
| 784 |     delete skelMgr; | 
|---|
| 785 |     delete matMgr; | 
|---|
| 786 |     delete meshMgr; | 
|---|
| 787 |         delete bufferManager; | 
|---|
| 788 |     delete mth; | 
|---|
| 789 |     delete rgm; | 
|---|
| 790 |     delete logMgr; | 
|---|
| 791 |  | 
|---|
| 792 |     return retCode; | 
|---|
| 793 |  | 
|---|
| 794 | } | 
|---|
| 795 |  | 
|---|