source: OGRE/trunk/ogrenew/Tools/MeshUpgrader/src/main.cpp @ 657

Revision 657, 15.9 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://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
35using namespace std;
36
37void 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
55using 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
60LogManager* logMgr;
61Math* mth;
62MaterialManager* matMgr;
63SkeletonManager* skelMgr;
64MeshSerializer* meshSerializer;
65SkeletonSerializer* skeletonSerializer;
66DefaultHardwareBufferManager *bufferManager;
67ResourceGroupManager* rgm;
68MeshManager* meshMgr;
69
70String 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}
95void 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
119bool 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}
144void 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.
158void 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.
313void 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
335int 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
Note: See TracBrowser for help on using the repository browser.