[657] | 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-2005 The OGRE Team
|
---|
| 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 | */
|
---|
| 25 |
|
---|
| 26 |
|
---|
| 27 | #include "Ogre.h"
|
---|
| 28 | #include "OgreMeshSerializer.h"
|
---|
| 29 | #include "OgreSkeletonSerializer.h"
|
---|
| 30 | #include "OgreDefaultHardwareBufferManager.h"
|
---|
| 31 |
|
---|
| 32 | #include <iostream>
|
---|
| 33 | #include <sys/stat.h>
|
---|
| 34 |
|
---|
| 35 | using namespace std;
|
---|
| 36 |
|
---|
| 37 | void help(void)
|
---|
| 38 | {
|
---|
| 39 | // Print help message
|
---|
| 40 | cout << endl << "OgreMeshUpgrader: Upgrades .mesh files to the latest version." << endl;
|
---|
| 41 | cout << "Provided for OGRE by Steve Streeting 2004" << endl << endl;
|
---|
| 42 | cout << "Usage: OgreMeshUpgrader [-e] sourcefile [destfile] " << endl;
|
---|
| 43 | cout << "-e = DON'T generate edge lists (for stencil shadows)" << endl;
|
---|
| 44 | cout << "-t = Generate tangents (for normal mapping)" << endl;
|
---|
| 45 | cout << "sourcefile = name of file to convert" << endl;
|
---|
| 46 | cout << "destfile = optional name of file to write to. If you don't" << endl;
|
---|
| 47 | cout << " specify this OGRE overwrites the existing file." << endl;
|
---|
| 48 |
|
---|
| 49 | cout << endl;
|
---|
| 50 | }
|
---|
| 51 |
|
---|
| 52 |
|
---|
| 53 |
|
---|
| 54 |
|
---|
| 55 | using namespace Ogre;
|
---|
| 56 |
|
---|
| 57 | // Crappy globals
|
---|
| 58 | // NB some of these are not directly used, but are required to
|
---|
| 59 | // instantiate the singletons used in the dlls
|
---|
| 60 | LogManager* logMgr;
|
---|
| 61 | Math* mth;
|
---|
| 62 | MaterialManager* matMgr;
|
---|
| 63 | SkeletonManager* skelMgr;
|
---|
| 64 | MeshSerializer* meshSerializer;
|
---|
| 65 | SkeletonSerializer* skeletonSerializer;
|
---|
| 66 | DefaultHardwareBufferManager *bufferManager;
|
---|
| 67 | ResourceGroupManager* rgm;
|
---|
| 68 | MeshManager* meshMgr;
|
---|
| 69 |
|
---|
| 70 | String describeSemantic(VertexElementSemantic sem)
|
---|
| 71 | {
|
---|
| 72 | switch (sem)
|
---|
| 73 | {
|
---|
| 74 | case VES_POSITION:
|
---|
| 75 | return "Positions";
|
---|
| 76 | case VES_NORMAL:
|
---|
| 77 | return "Normals";
|
---|
| 78 | case VES_BLEND_WEIGHTS:
|
---|
| 79 | return "Blend Weights";
|
---|
| 80 | case VES_BLEND_INDICES:
|
---|
| 81 | return "Blend Indices";
|
---|
| 82 | case VES_DIFFUSE:
|
---|
| 83 | return "Diffuse";
|
---|
| 84 | case VES_SPECULAR:
|
---|
| 85 | return "Specular";
|
---|
| 86 | case VES_TEXTURE_COORDINATES:
|
---|
| 87 | return "Texture coordinates";
|
---|
| 88 | case VES_BINORMAL:
|
---|
| 89 | return "Binormals";
|
---|
| 90 | case VES_TANGENT:
|
---|
| 91 | return "Tangents";
|
---|
| 92 | };
|
---|
| 93 | return "";
|
---|
| 94 | }
|
---|
| 95 | void displayVertexBuffers(VertexDeclaration::VertexElementList& elemList)
|
---|
| 96 | {
|
---|
| 97 | // Iterate per buffer
|
---|
| 98 | unsigned short currentBuffer = 999;
|
---|
| 99 | unsigned short elemNum = 0;
|
---|
| 100 | VertexDeclaration::VertexElementList::iterator i, iend;
|
---|
| 101 | iend = elemList.end();
|
---|
| 102 | for (i = elemList.begin(); i != iend; ++i)
|
---|
| 103 | {
|
---|
| 104 | if (i->getSource() != currentBuffer)
|
---|
| 105 | {
|
---|
| 106 | currentBuffer = i->getSource();
|
---|
| 107 | cout << "> Buffer " << currentBuffer << ":" << endl;
|
---|
| 108 | }
|
---|
| 109 | cout << " - Element " << elemNum++ << ": " << describeSemantic(i->getSemantic());
|
---|
| 110 | if (i->getSemantic() == VES_TEXTURE_COORDINATES)
|
---|
| 111 | {
|
---|
| 112 | cout << " (index " << i->getIndex() << ")";
|
---|
| 113 | }
|
---|
| 114 | cout << endl;
|
---|
| 115 |
|
---|
| 116 | }
|
---|
| 117 | }
|
---|
| 118 | // Sort routine for VertexElement
|
---|
| 119 | bool vertexElementLess(const VertexElement& e1, const VertexElement& e2)
|
---|
| 120 | {
|
---|
| 121 | // Sort by source first
|
---|
| 122 | if (e1.getSource() < e2.getSource())
|
---|
| 123 | {
|
---|
| 124 | return true;
|
---|
| 125 | }
|
---|
| 126 | else if (e1.getSource() == e2.getSource())
|
---|
| 127 | {
|
---|
| 128 | // Use ordering of semantics to sort
|
---|
| 129 | if (e1.getSemantic() < e2.getSemantic())
|
---|
| 130 | {
|
---|
| 131 | return true;
|
---|
| 132 | }
|
---|
| 133 | else if (e1.getSemantic() == e2.getSemantic())
|
---|
| 134 | {
|
---|
| 135 | // Use index to sort
|
---|
| 136 | if (e1.getIndex() < e2.getIndex())
|
---|
| 137 | {
|
---|
| 138 | return true;
|
---|
| 139 | }
|
---|
| 140 | }
|
---|
| 141 | }
|
---|
| 142 | return false;
|
---|
| 143 | }
|
---|
| 144 | void copyElems(VertexDeclaration* decl, VertexDeclaration::VertexElementList* elemList)
|
---|
| 145 | {
|
---|
| 146 |
|
---|
| 147 | elemList->clear();
|
---|
| 148 | const VertexDeclaration::VertexElementList& origElems = decl->getElements();
|
---|
| 149 | VertexDeclaration::VertexElementList::const_iterator i, iend;
|
---|
| 150 | iend = origElems.end();
|
---|
| 151 | for (i = origElems.begin(); i != iend; ++i)
|
---|
| 152 | {
|
---|
| 153 | elemList->push_back(*i);
|
---|
| 154 | }
|
---|
| 155 | elemList->sort(VertexDeclaration::vertexElementLess);
|
---|
| 156 | }
|
---|
| 157 | // Utility function to allow the user to modify the layout of vertex buffers.
|
---|
| 158 | void reorganiseVertexBuffers(const String& desc, Mesh& mesh, VertexData* vertexData)
|
---|
| 159 | {
|
---|
| 160 | cout << endl << desc << ":- " << endl;
|
---|
| 161 | // Copy elements into a list
|
---|
| 162 | VertexDeclaration::VertexElementList elemList;
|
---|
| 163 | copyElems(vertexData->vertexDeclaration, &elemList);
|
---|
| 164 |
|
---|
| 165 | bool finish = false;
|
---|
| 166 | bool anyChanges = false;
|
---|
| 167 | while (!finish)
|
---|
| 168 | {
|
---|
| 169 | displayVertexBuffers(elemList);
|
---|
| 170 | cout << endl;
|
---|
| 171 |
|
---|
| 172 | cout << "Options: (a)utomatic" << endl;
|
---|
| 173 | cout << " (m)ove element" << endl;
|
---|
| 174 | cout << " (d)elete element" << endl;
|
---|
| 175 | cout << " (r)eset" << endl;
|
---|
| 176 | cout << " (f)inish" << endl;
|
---|
| 177 | String response = "";
|
---|
| 178 | while (response.empty())
|
---|
| 179 | {
|
---|
| 180 | cin >> response;
|
---|
| 181 | StringUtil::toLowerCase(response);
|
---|
| 182 |
|
---|
| 183 | if (response == "m")
|
---|
| 184 | {
|
---|
| 185 | String moveResp;
|
---|
| 186 | cout << "Which element do you want to move (type number): ";
|
---|
| 187 | cin >> moveResp;
|
---|
| 188 | if (!moveResp.empty())
|
---|
| 189 | {
|
---|
| 190 | int eindex = StringConverter::parseInt(moveResp);
|
---|
| 191 | VertexDeclaration::VertexElementList::iterator movei = elemList.begin();
|
---|
| 192 | std::advance(movei, eindex);
|
---|
| 193 | cout << endl << "Move element " << eindex << "(" + describeSemantic(movei->getSemantic()) << ") to which buffer: ";
|
---|
| 194 | cin >> moveResp;
|
---|
| 195 | if (!moveResp.empty())
|
---|
| 196 | {
|
---|
| 197 | int bindex = StringConverter::parseInt(moveResp);
|
---|
| 198 | // Move (note offset will be wrong)
|
---|
| 199 | *movei = VertexElement(bindex, 0, movei->getType(),
|
---|
| 200 | movei->getSemantic(), movei->getIndex());
|
---|
| 201 | elemList.sort(vertexElementLess);
|
---|
| 202 | anyChanges = true;
|
---|
| 203 |
|
---|
| 204 | }
|
---|
| 205 | }
|
---|
| 206 | }
|
---|
| 207 | else if (response == "a")
|
---|
| 208 | {
|
---|
| 209 | // Automatic
|
---|
| 210 | VertexDeclaration* newDcl =
|
---|
| 211 | vertexData->vertexDeclaration->getAutoOrganisedDeclaration(
|
---|
| 212 | mesh.hasSkeleton());
|
---|
| 213 | copyElems(newDcl, &elemList);
|
---|
| 214 | HardwareBufferManager::getSingleton().destroyVertexDeclaration(newDcl);
|
---|
| 215 | anyChanges = true;
|
---|
| 216 |
|
---|
| 217 | }
|
---|
| 218 | else if (response == "d")
|
---|
| 219 | {
|
---|
| 220 | String moveResp;
|
---|
| 221 | cout << "Which element do you want to delete (type number): ";
|
---|
| 222 | cin >> moveResp;
|
---|
| 223 | if (!moveResp.empty())
|
---|
| 224 | {
|
---|
| 225 | int eindex = StringConverter::parseInt(moveResp);
|
---|
| 226 | VertexDeclaration::VertexElementList::iterator movei = elemList.begin();
|
---|
| 227 | std::advance(movei, eindex);
|
---|
| 228 | cout << std::endl << "Delete element " << eindex << "(" + describeSemantic(movei->getSemantic()) << ")?: ";
|
---|
| 229 | cin >> moveResp;
|
---|
| 230 | StringUtil::toLowerCase(moveResp);
|
---|
| 231 | if (moveResp == "y")
|
---|
| 232 | {
|
---|
| 233 | elemList.erase(movei);
|
---|
| 234 | anyChanges = true;
|
---|
| 235 | }
|
---|
| 236 | }
|
---|
| 237 | }
|
---|
| 238 | else if (response == "r")
|
---|
| 239 | {
|
---|
| 240 | // reset
|
---|
| 241 | copyElems(vertexData->vertexDeclaration, &elemList);
|
---|
| 242 | anyChanges = false;
|
---|
| 243 | }
|
---|
| 244 | else if (response == "f")
|
---|
| 245 | {
|
---|
| 246 | // finish
|
---|
| 247 | finish = true;
|
---|
| 248 | }
|
---|
| 249 | else
|
---|
| 250 | {
|
---|
| 251 | response == "";
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | }
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | if (anyChanges)
|
---|
| 258 | {
|
---|
| 259 | String response;
|
---|
| 260 | while (response.empty())
|
---|
| 261 | {
|
---|
| 262 | displayVertexBuffers(elemList);
|
---|
| 263 | cout << "Really reorganise the vertex buffers this way?";
|
---|
| 264 | cin >> response;
|
---|
| 265 | StringUtil::toLowerCase(response);
|
---|
| 266 | if (response == "y")
|
---|
| 267 | {
|
---|
| 268 | VertexDeclaration* newDecl = HardwareBufferManager::getSingleton().createVertexDeclaration();
|
---|
| 269 | VertexDeclaration::VertexElementList::iterator i, iend;
|
---|
| 270 | iend = elemList.end();
|
---|
| 271 | unsigned short currentBuffer = 999;
|
---|
| 272 | size_t offset;
|
---|
| 273 | for (i = elemList.begin(); i != iend; ++i)
|
---|
| 274 | {
|
---|
| 275 | // Calc offsets since reorg changes them
|
---|
| 276 | if (i->getSource() != currentBuffer)
|
---|
| 277 | {
|
---|
| 278 | offset = 0;
|
---|
| 279 | currentBuffer = i->getSource();
|
---|
| 280 | }
|
---|
| 281 | newDecl->addElement(
|
---|
| 282 | currentBuffer,
|
---|
| 283 | offset,
|
---|
| 284 | i->getType(),
|
---|
| 285 | i->getSemantic(),
|
---|
| 286 | i->getIndex());
|
---|
| 287 |
|
---|
| 288 | offset += VertexElement::getTypeSize(i->getType());
|
---|
| 289 |
|
---|
| 290 | }
|
---|
| 291 | // Usages don't matter here since we're onlly exporting
|
---|
| 292 | BufferUsageList bufferUsages;
|
---|
| 293 | for (size_t u = 0; u <= newDecl->getMaxSource(); ++u)
|
---|
| 294 | bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
---|
| 295 | vertexData->reorganiseBuffers(newDecl, bufferUsages);
|
---|
| 296 | }
|
---|
| 297 | else if (response == "n")
|
---|
| 298 | {
|
---|
| 299 | // do nothing
|
---|
| 300 | }
|
---|
| 301 | else
|
---|
| 302 | {
|
---|
| 303 | response = "";
|
---|
| 304 | }
|
---|
| 305 | }
|
---|
| 306 |
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 |
|
---|
| 310 |
|
---|
| 311 | }
|
---|
| 312 | // Utility function to allow the user to modify the layout of vertex buffers.
|
---|
| 313 | void reorganiseVertexBuffers(Mesh& mesh)
|
---|
| 314 | {
|
---|
| 315 | if (mesh.sharedVertexData)
|
---|
| 316 | {
|
---|
| 317 | reorganiseVertexBuffers("Shared Geometry", mesh, mesh.sharedVertexData);
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 | Mesh::SubMeshIterator smIt = mesh.getSubMeshIterator();
|
---|
| 321 | unsigned short idx = 0;
|
---|
| 322 | while (smIt.hasMoreElements())
|
---|
| 323 | {
|
---|
| 324 | SubMesh* sm = smIt.getNext();
|
---|
| 325 | if (!sm->useSharedVertices)
|
---|
| 326 | {
|
---|
| 327 | StringUtil::StrStreamType str;
|
---|
| 328 | str << "SubMesh " << idx++;
|
---|
| 329 | reorganiseVertexBuffers(str.str(), mesh, sm->vertexData);
|
---|
| 330 | }
|
---|
| 331 | }
|
---|
| 332 | }
|
---|
| 333 |
|
---|
| 334 |
|
---|
| 335 | int main(int numargs, char** args)
|
---|
| 336 | {
|
---|
| 337 | if (numargs < 2)
|
---|
| 338 | {
|
---|
| 339 | help();
|
---|
| 340 | return -1;
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | logMgr = new LogManager();
|
---|
| 344 | logMgr->createLog("OgreMeshUpgrade.log", true);
|
---|
| 345 | rgm = new ResourceGroupManager();
|
---|
| 346 | mth = new Math();
|
---|
| 347 | matMgr = new MaterialManager();
|
---|
| 348 | matMgr->initialise();
|
---|
| 349 | skelMgr = new SkeletonManager();
|
---|
| 350 | meshSerializer = new MeshSerializer();
|
---|
| 351 | skeletonSerializer = new SkeletonSerializer();
|
---|
| 352 | bufferManager = new DefaultHardwareBufferManager(); // needed because we don't have a rendersystem
|
---|
| 353 | meshMgr = new MeshManager();
|
---|
| 354 | // don't pad during upgrade
|
---|
| 355 | meshMgr->setBoundsPaddingFactor(0.0f);
|
---|
| 356 |
|
---|
| 357 |
|
---|
| 358 | UnaryOptionList unOptList;
|
---|
| 359 | BinaryOptionList binOptList;
|
---|
| 360 |
|
---|
| 361 | unOptList["-e"] = false;
|
---|
| 362 | unOptList["-t"] = false;
|
---|
| 363 | int startIdx = findCommandLineOpts(numargs, args, unOptList, binOptList);
|
---|
| 364 |
|
---|
| 365 | String source(args[startIdx]);
|
---|
| 366 |
|
---|
| 367 | logMgr->createLog("OgreMeshUpgrader.log");
|
---|
| 368 |
|
---|
| 369 |
|
---|
| 370 | // Load the mesh
|
---|
| 371 | struct stat tagStat;
|
---|
| 372 |
|
---|
| 373 | FILE* pFile = fopen( source.c_str(), "rb" );
|
---|
| 374 | if (!pFile)
|
---|
| 375 | {
|
---|
| 376 | OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
|
---|
| 377 | "File " + source + " not found.", "OgreMeshUpgrade");
|
---|
| 378 | }
|
---|
| 379 | stat( source.c_str(), &tagStat );
|
---|
| 380 | MemoryDataStream* memstream = new MemoryDataStream(source, tagStat.st_size, true);
|
---|
| 381 | fread( (void*)memstream->getPtr(), tagStat.st_size, 1, pFile );
|
---|
| 382 | fclose( pFile );
|
---|
| 383 |
|
---|
| 384 | Mesh mesh(meshMgr, "conversion", 0, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
---|
| 385 |
|
---|
| 386 | DataStreamPtr stream(memstream);
|
---|
| 387 | meshSerializer->importMesh(stream, &mesh);
|
---|
| 388 |
|
---|
| 389 | // Write out the converted mesh
|
---|
| 390 | String dest;
|
---|
| 391 | if (numargs == startIdx + 2)
|
---|
| 392 | {
|
---|
| 393 | dest = args[startIdx + 1];
|
---|
| 394 | }
|
---|
| 395 | else
|
---|
| 396 | {
|
---|
| 397 | dest = source;
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | String response;
|
---|
| 401 |
|
---|
| 402 | // Check to see whether we would like to reorganise vertex buffers
|
---|
| 403 | std::cout << "\nWould you like to reorganise the vertex buffers for this mesh?";
|
---|
| 404 | while (response.empty())
|
---|
| 405 | {
|
---|
| 406 | cin >> response;
|
---|
| 407 | StringUtil::toLowerCase(response);
|
---|
| 408 | if (response == "y")
|
---|
| 409 | {
|
---|
| 410 | reorganiseVertexBuffers(mesh);
|
---|
| 411 | }
|
---|
| 412 | else if (response == "n")
|
---|
| 413 | {
|
---|
| 414 | // Do nothing
|
---|
| 415 | }
|
---|
| 416 | else
|
---|
| 417 | {
|
---|
| 418 | response = "";
|
---|
| 419 | }
|
---|
| 420 | }
|
---|
| 421 |
|
---|
| 422 | // Prompt for LOD generation
|
---|
| 423 | bool genLod = false;
|
---|
| 424 | response = "";
|
---|
| 425 | if (mesh.getNumLodLevels() > 1)
|
---|
| 426 | {
|
---|
| 427 | std::cout << "\nMesh already contains level-of detail information.\n"
|
---|
| 428 | "Do you want to: (u)se it, (r)eplace it, or (d)rop it?";
|
---|
| 429 | while (response.empty())
|
---|
| 430 | {
|
---|
| 431 | cin >> response;
|
---|
| 432 | StringUtil::toLowerCase(response);
|
---|
| 433 | if (response == "u")
|
---|
| 434 | {
|
---|
| 435 | // Do nothing
|
---|
| 436 | }
|
---|
| 437 | else if (response == "d")
|
---|
| 438 | {
|
---|
| 439 | mesh.removeLodLevels();
|
---|
| 440 | }
|
---|
| 441 | else if (response == "r")
|
---|
| 442 | {
|
---|
| 443 | genLod = true;
|
---|
| 444 | }
|
---|
| 445 | else
|
---|
| 446 | {
|
---|
| 447 | response = "";
|
---|
| 448 | }
|
---|
| 449 | }// while response == ""
|
---|
| 450 | }
|
---|
| 451 | else // no existing LOD
|
---|
| 452 | {
|
---|
| 453 | std::cout << "\nWould you like to generate LOD information? (y/n)";
|
---|
| 454 | while (response == "")
|
---|
| 455 | {
|
---|
| 456 | cin >> response;
|
---|
| 457 | StringUtil::toLowerCase(response);
|
---|
| 458 | if (response == "n")
|
---|
| 459 | {
|
---|
| 460 | // Do nothing
|
---|
| 461 | }
|
---|
| 462 | else if (response == "y")
|
---|
| 463 | {
|
---|
| 464 | genLod = true;
|
---|
| 465 | }
|
---|
| 466 | }
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | if (genLod)
|
---|
| 470 | {
|
---|
| 471 | unsigned short numLod;
|
---|
| 472 | ProgressiveMesh::VertexReductionQuota quota;
|
---|
| 473 | Real reduction;
|
---|
| 474 |
|
---|
| 475 | cout << "\nHow many extra LOD levels would you like to generate?";
|
---|
| 476 | cin >> numLod;
|
---|
| 477 |
|
---|
| 478 | cout << "\nWhat unit of reduction would you like to use:"
|
---|
| 479 | "\n(f)ixed or (p)roportional?";
|
---|
| 480 | cin >> response;
|
---|
| 481 | StringUtil::toLowerCase(response);
|
---|
| 482 | if (response == "f")
|
---|
| 483 | {
|
---|
| 484 | quota = ProgressiveMesh::VRQ_CONSTANT;
|
---|
| 485 | cout << "\nHow many vertices should be removed at each LOD?";
|
---|
| 486 | }
|
---|
| 487 | else
|
---|
| 488 | {
|
---|
| 489 | quota = ProgressiveMesh::VRQ_PROPORTIONAL;
|
---|
| 490 | cout << "\nWhat proportion of remaining vertices should be removed " <<
|
---|
| 491 | "at each LOD (e.g. 0.5)?";
|
---|
| 492 | }
|
---|
| 493 | cin >> reduction;
|
---|
| 494 |
|
---|
| 495 | cout << "\nEnter the distance for each LOD to come into effect.";
|
---|
| 496 |
|
---|
| 497 | Real distance;
|
---|
| 498 | Mesh::LodDistanceList distanceList;
|
---|
| 499 | for (unsigned short iLod = 0; iLod < numLod; ++iLod)
|
---|
| 500 | {
|
---|
| 501 | cout << "\nLOD Level " << (iLod+1) << ":";
|
---|
| 502 | cin >> distance;
|
---|
| 503 | distanceList.push_back(distance);
|
---|
| 504 | }
|
---|
| 505 |
|
---|
| 506 | mesh.generateLodLevels(distanceList, quota, reduction);
|
---|
| 507 | }
|
---|
| 508 |
|
---|
| 509 | // Make sure we generate edge lists, provided they are not deliberately disabled
|
---|
| 510 | UnaryOptionList::iterator ui = unOptList.find("-e");
|
---|
| 511 |
|
---|
| 512 | if (!ui->second)
|
---|
| 513 | {
|
---|
| 514 | cout << "\nGenerating edge lists.." << std::endl;
|
---|
| 515 | mesh.buildEdgeList();
|
---|
| 516 | }
|
---|
| 517 |
|
---|
| 518 | // Generate tangents?
|
---|
| 519 | ui = unOptList.find("-t");
|
---|
| 520 | bool generateTangents = ui->second;
|
---|
| 521 | if (generateTangents)
|
---|
| 522 | {
|
---|
| 523 | unsigned short srcTex, destTex;
|
---|
| 524 | bool existing = mesh.suggestTangentVectorBuildParams(srcTex, destTex);
|
---|
| 525 | if (existing)
|
---|
| 526 | {
|
---|
| 527 | std::cout << "\nThis mesh appears to already have a set of 3D texture coordinates, " <<
|
---|
| 528 | "which would suggest tangent vectors have already been calculated. Do you really " <<
|
---|
| 529 | "want to generate new tangent vectors (may duplicate)? (y/n)";
|
---|
| 530 | while (response == "")
|
---|
| 531 | {
|
---|
| 532 | cin >> response;
|
---|
| 533 | StringUtil::toLowerCase(response);
|
---|
| 534 | if (response == "y")
|
---|
| 535 | {
|
---|
| 536 | // Do nothing
|
---|
| 537 | }
|
---|
| 538 | else if (response == "n")
|
---|
| 539 | {
|
---|
| 540 | generateTangents = false;
|
---|
| 541 | }
|
---|
| 542 | else
|
---|
| 543 | {
|
---|
| 544 | response = "";
|
---|
| 545 | }
|
---|
| 546 | }
|
---|
| 547 |
|
---|
| 548 | }
|
---|
| 549 | if (generateTangents)
|
---|
| 550 | {
|
---|
| 551 | cout << "Generating tangent vectors...." << std::endl;
|
---|
| 552 | mesh.buildTangentVectors(srcTex, destTex);
|
---|
| 553 | }
|
---|
| 554 | }
|
---|
| 555 |
|
---|
| 556 |
|
---|
| 557 |
|
---|
| 558 | meshSerializer->exportMesh(&mesh, dest);
|
---|
| 559 |
|
---|
| 560 |
|
---|
| 561 |
|
---|
| 562 |
|
---|
| 563 | delete meshMgr;
|
---|
| 564 | delete skeletonSerializer;
|
---|
| 565 | delete meshSerializer;
|
---|
| 566 | delete skelMgr;
|
---|
| 567 | delete matMgr;
|
---|
| 568 | delete mth;
|
---|
| 569 | delete rgm;
|
---|
| 570 | delete logMgr;
|
---|
| 571 |
|
---|
| 572 | return 0;
|
---|
| 573 |
|
---|
| 574 | }
|
---|
| 575 |
|
---|