[SOLVED] Mesh Load Problem Subsequent to Eihort Migration

Problems building or running the engine, queries about how to use features etc.
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

[SOLVED] Mesh Load Problem Subsequent to Eihort Migration

Post by daves »

We have been using Dagon for some time. For a variety of reasons we took the plunge this week to migrate to Eihort. The application compiled and linked without too many issues (mostly down in the CEGUI interface). Upon execution Ogre died with an assertion while trying to load one of our meshes. These are meshes that we have been using for sometime without issue.

I tried to run the mesh upgrader and it also terminated with the same assertion. The assertion image is attached:

Image

These meshes were created through use of 3dMax and the ofusion CE plugin.

Shooting to regenerate the meshes is unlikely to do any good since that will very likely give us the same data. Also my understanding is that ofusion does not yet support eihort. :(

Can someone please suggest an approach to get past this hurdle.

Thanks in advance.
Last edited by daves on Wed Apr 25, 2007 4:32 pm, edited 3 times in total.
User avatar
tuan kuranes
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 2653
Joined: Wed Sep 24, 2003 8:07 am
Location: Haute Garonne, France
x 4

Post by tuan kuranes »

daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

Omg this forum is great. Thanks for the immediate response. I dont think my page finished refreshing after I hit submit.. and already you posted what looks like the solution.
:)
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

I've downloaded what I think is the cvs head for the meshupgrader. It has the -b option, which I believe is the one that has been added to fix the bounding box issues for static meshes.

However when I try to run the upgrader with this option it asserts in the same location.

This is the code that I'm using (main.cpp in ogremeshupgrader). Can someone tell me if this is the right version to be using.

Code: Select all

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/


#include "Ogre.h"
#include "OgreMeshSerializer.h"
#include "OgreSkeletonSerializer.h"
#include "OgreDefaultHardwareBufferManager.h"
#include "OgreHardwareVertexBuffer.h"

#include <iostream>
#include <sys/stat.h>

using namespace std;
using namespace Ogre;

void help(void)
{
    // Print help message
    cout << endl << "OgreMeshUpgrader: Upgrades .mesh files to the latest version." << endl;
    cout << "Provided for OGRE by Steve Streeting 2004" << endl << endl;
    cout << "Usage: OgreMeshUpgrader [-e] sourcefile [destfile] " << endl;
	cout << "-i             = Interactive mode, prompt for options" << endl;
	cout << "-l lodlevels   = number of LOD levels" << endl;
	cout << "-d loddist     = distance increment to reduce LOD" << endl;
	cout << "-p lodpercent  = Percentage triangle reduction amount per LOD" << endl;
	cout << "-f lodnumtris  = Fixed vertex reduction per LOD" << endl;
    cout << "-e         = DON'T generate edge lists (for stencil shadows)" << endl;
    cout << "-t         = Generate tangents (for normal mapping)" << endl;
	cout << "-td [uvw|tangent]" << endl;
	cout << "           = Tangent vertex semantic destination (default tangent)" << endl;
	cout << "-r         = DON'T reorganise buffers to recommended format" << endl;
	cout << "-d3d       = Convert to D3D colour formats" << endl;
	cout << "-gl        = Convert to GL colour formats" << endl;
	cout << "-srcd3d    = Interpret ambiguous colours as D3D style" << endl;
	cout << "-srcgl     = Interpret ambiguous colours as GL style" << endl;
	cout << "-E endian  = Set endian mode 'big' 'little' or 'native' (default)" << endl;
	cout << "-b         = Recalculate bounding box (static meshes only)" << endl;
    cout << "sourcefile = name of file to convert" << endl;
    cout << "destfile   = optional name of file to write to. If you don't" << endl;
    cout << "             specify this OGRE overwrites the existing file." << endl;

    cout << endl;
}

struct UpgradeOptions
{
	bool interactive;
	bool suppressEdgeLists;
	bool generateTangents;
	VertexElementSemantic tangentSemantic;
	bool dontReorganise;
	bool destColourFormatSet;
	VertexElementType destColourFormat;
	bool srcColourFormatSet;
	VertexElementType srcColourFormat;
	unsigned short numLods;
	Real lodDist;
	Real lodPercent;
	size_t lodFixed;
	bool usePercent;
	Serializer::Endian endian;
	bool recalcBounds;

};


// Crappy globals
// NB some of these are not directly used, but are required to
//   instantiate the singletons used in the dlls
LogManager* logMgr;
Math* mth;
MaterialManager* matMgr;
SkeletonManager* skelMgr;
MeshSerializer* meshSerializer;
SkeletonSerializer* skeletonSerializer;
DefaultHardwareBufferManager *bufferManager;
ResourceGroupManager* rgm;
MeshManager* meshMgr;
UpgradeOptions opts;

void parseOpts(UnaryOptionList& unOpts, BinaryOptionList& binOpts)
{
	opts.interactive = false;
	opts.suppressEdgeLists = false;
	opts.generateTangents = false;
	opts.tangentSemantic = VES_TANGENT;
	opts.dontReorganise = false;
	opts.endian = Serializer::ENDIAN_NATIVE;
	opts.destColourFormatSet = false;
	opts.srcColourFormatSet = false;

	opts.lodDist = 500;
	opts.lodFixed = 0;
	opts.lodPercent = 20;
	opts.numLods = 0;
	opts.usePercent = true;
	opts.recalcBounds = false;


	UnaryOptionList::iterator ui = unOpts.find("-e");
	opts.suppressEdgeLists = ui->second;
	ui = unOpts.find("-t");
	opts.generateTangents = ui->second;
	ui = unOpts.find("-i");
	opts.interactive = ui->second;
	ui = unOpts.find("-r");
	opts.dontReorganise = ui->second;
	ui = unOpts.find("-d3d");
	if (ui->second)
	{
		opts.destColourFormatSet = true;
		opts.destColourFormat = VET_COLOUR_ARGB;
	}
	ui = unOpts.find("-gl");
	if (ui->second)
	{
		opts.destColourFormatSet = true;
		opts.destColourFormat = VET_COLOUR_ABGR;
	}
	ui = unOpts.find("-srcd3d");
	if (ui->second)
	{
		opts.srcColourFormatSet = true;
		opts.srcColourFormat = VET_COLOUR_ARGB;
	}
	ui = unOpts.find("-srcgl");
	if (ui->second)
	{
		opts.srcColourFormatSet = true;
		opts.srcColourFormat = VET_COLOUR_ABGR;
	}
	ui = unOpts.find("-b");
	if (ui->second)
	{
		opts.recalcBounds = true;
	}


	BinaryOptionList::iterator bi = binOpts.find("-l");
	if (!bi->second.empty())
	{
		opts.numLods = StringConverter::parseInt(bi->second);
	}

	bi = binOpts.find("-d");
	if (!bi->second.empty())
	{
		opts.lodDist = StringConverter::parseReal(bi->second);
	}

	bi = binOpts.find("-p");
	if (!bi->second.empty())
	{
		opts.lodPercent = StringConverter::parseReal(bi->second);
		opts.usePercent = true;
	}


	bi = binOpts.find("-f");
	if (!bi->second.empty())
	{
		opts.lodFixed = StringConverter::parseInt(bi->second);
		opts.usePercent = false;
	}

	bi = binOpts.find("-E");
	if (!bi->second.empty())
	{
	    if (bi->second == "big")
            opts.endian = Serializer::ENDIAN_BIG;
	    else if (bi->second == "little")
            opts.endian = Serializer::ENDIAN_LITTLE;
	    else 
            opts.endian = Serializer::ENDIAN_NATIVE;
    }
	bi = binOpts.find("-td");
	if (!bi->second.empty())
	{
		if (bi->second == "uvw")
			opts.tangentSemantic = VES_TEXTURE_COORDINATES;
		else // if (bi->second == "tangent"), or anything else
			opts.tangentSemantic = VES_TANGENT;
	}
}

String describeSemantic(VertexElementSemantic sem)
{
	switch (sem)
	{
	case VES_POSITION:
		return "Positions";
	case VES_NORMAL:
		return "Normals";
	case VES_BLEND_WEIGHTS:
		return "Blend Weights";
	case VES_BLEND_INDICES:
		return "Blend Indices";
	case VES_DIFFUSE:
		return "Diffuse";
	case VES_SPECULAR:
		return "Specular";
	case VES_TEXTURE_COORDINATES:
		return "Texture coordinates";
	case VES_BINORMAL:
		return "Binormals";
	case VES_TANGENT:
		return "Tangents";
	};
    return "";
}
void displayVertexBuffers(VertexDeclaration::VertexElementList& elemList)
{
	// Iterate per buffer
	unsigned short currentBuffer = 999;
	unsigned short elemNum = 0;
	VertexDeclaration::VertexElementList::iterator i, iend;
	iend = elemList.end();
	for (i = elemList.begin(); i != iend; ++i)
	{
		if (i->getSource() != currentBuffer)
		{
			currentBuffer = i->getSource();
			cout << "> Buffer " << currentBuffer << ":" << endl;
		}
		cout << "   - Element " << elemNum++ << ": " << describeSemantic(i->getSemantic());
		if (i->getSemantic() == VES_TEXTURE_COORDINATES)
		{
			cout << " (index " << i->getIndex() << ")"; 
		}
		cout << endl;

	}
}
// Sort routine for VertexElement
bool vertexElementLess(const VertexElement& e1, const VertexElement& e2)
{
	// Sort by source first
	if (e1.getSource() < e2.getSource())
	{
		return true;
	}
	else if (e1.getSource() == e2.getSource())
	{
		// Use ordering of semantics to sort
		if (e1.getSemantic() < e2.getSemantic())
		{
			return true;
		}
		else if (e1.getSemantic() == e2.getSemantic())
		{
			// Use index to sort
			if (e1.getIndex() < e2.getIndex())
			{
				return true;
			}
		}
	}
	return false;
}
void copyElems(VertexDeclaration* decl, VertexDeclaration::VertexElementList* elemList)
{
	
	elemList->clear();
	const VertexDeclaration::VertexElementList& origElems = decl->getElements();
    VertexDeclaration::VertexElementList::const_iterator i, iend;
	iend = origElems.end();
	for (i = origElems.begin(); i != iend; ++i)
	{
		elemList->push_back(*i);
	}
	elemList->sort(VertexDeclaration::vertexElementLess);
}
// Utility function to allow the user to modify the layout of vertex buffers.
void reorganiseVertexBuffers(const String& desc, Mesh& mesh, VertexData* vertexData)
{
	cout << endl << desc << ":- " << endl;
	// Copy elements into a list
	VertexDeclaration::VertexElementList elemList;
	copyElems(vertexData->vertexDeclaration, &elemList);

	bool finish = false;
	bool anyChanges = false;
	while (!finish)
	{
		displayVertexBuffers(elemList);
		cout << endl;

		cout << "Options: (a)utomatic" << endl;
        cout << "         (m)ove element" << endl;
		cout << "         (d)elete element" << endl;
		cout << "         (r)eset" << endl;
		cout << "         (f)inish" << endl;
		String response = "";
		while (response.empty())
		{
			cin >> response;
			StringUtil::toLowerCase(response);

			if (response == "m")
			{
				String moveResp;
				cout << "Which element do you want to move (type number): ";
				cin >> moveResp;
				if (!moveResp.empty())
				{
					int eindex = StringConverter::parseInt(moveResp);
					VertexDeclaration::VertexElementList::iterator movei = elemList.begin();
					std::advance(movei, eindex);
					cout << endl << "Move element " << eindex << "(" + describeSemantic(movei->getSemantic()) << ") to which buffer: ";
					cin >> moveResp;
					if (!moveResp.empty())
					{
						int bindex = StringConverter::parseInt(moveResp);
						// Move (note offset will be wrong)
						*movei = VertexElement(bindex, 0, movei->getType(),
							movei->getSemantic(), movei->getIndex());
						elemList.sort(vertexElementLess);
                        anyChanges = true;
								
					}
				}
			}
            else if (response == "a")
            {
                // Automatic
                VertexDeclaration* newDcl = 
                    vertexData->vertexDeclaration->getAutoOrganisedDeclaration(
                        mesh.hasSkeleton(), mesh.hasVertexAnimation());
                copyElems(newDcl, &elemList);
                HardwareBufferManager::getSingleton().destroyVertexDeclaration(newDcl);
                anyChanges = true;

            }
			else if (response == "d")
			{
				String moveResp;
				cout << "Which element do you want to delete (type number): ";
				cin >> moveResp;
				if (!moveResp.empty())
				{
					int eindex = StringConverter::parseInt(moveResp);
					VertexDeclaration::VertexElementList::iterator movei = elemList.begin();
					std::advance(movei, eindex);
                    cout << std::endl << "Delete element " << eindex << "(" + describeSemantic(movei->getSemantic()) << ")?: ";
					cin >> moveResp;
					StringUtil::toLowerCase(moveResp);
					if (moveResp == "y")
					{
						elemList.erase(movei);
                        anyChanges = true;
					}
				}
			}
			else if (response == "r")
			{
				// reset
				copyElems(vertexData->vertexDeclaration, &elemList);
				anyChanges = false;
			}
			else if (response == "f")
			{
				// finish
				finish = true;
			}
			else
			{
				response == "";
			}
			
		}
	}

	if (anyChanges)
	{
		String response;
		while (response.empty())
		{
			displayVertexBuffers(elemList);
			cout << "Really reorganise the vertex buffers this way?";
			cin >> response;
			StringUtil::toLowerCase(response);
			if (response == "y")
			{
				VertexDeclaration* newDecl = HardwareBufferManager::getSingleton().createVertexDeclaration();
				VertexDeclaration::VertexElementList::iterator i, iend;
				iend = elemList.end();
				unsigned short currentBuffer = 999;
				size_t offset;
				for (i = elemList.begin(); i != iend; ++i)
				{
					// Calc offsets since reorg changes them
					if (i->getSource() != currentBuffer)
					{
						offset = 0;
						currentBuffer = i->getSource();
					}
					newDecl->addElement(
						currentBuffer,
						offset,
						i->getType(),
						i->getSemantic(),
						i->getIndex());

					offset += VertexElement::getTypeSize(i->getType());
					
				}
                // Usages don't matter here since we're onlly exporting
                BufferUsageList bufferUsages;
                for (size_t u = 0; u <= newDecl->getMaxSource(); ++u)
                    bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY);
				vertexData->reorganiseBuffers(newDecl, bufferUsages);
			}
			else if (response == "n")
			{
				// do nothing
			}
			else
			{
				response = "";
			}
        }
		
	}
		

	
}
// Utility function to allow the user to modify the layout of vertex buffers.
void reorganiseVertexBuffers(Mesh& mesh)
{
	if (mesh.sharedVertexData)
	{
		if (opts.interactive)
			reorganiseVertexBuffers("Shared Geometry", mesh, mesh.sharedVertexData);
		else
		{
			// Automatic
			VertexDeclaration* newDcl = 
				mesh.sharedVertexData->vertexDeclaration->getAutoOrganisedDeclaration(
				mesh.hasSkeleton(), mesh.hasVertexAnimation());
			if (*newDcl != *(mesh.sharedVertexData->vertexDeclaration))
			{
				// Usages don't matter here since we're onlly exporting
				BufferUsageList bufferUsages;
				for (size_t u = 0; u <= newDcl->getMaxSource(); ++u)
					bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY);
				mesh.sharedVertexData->reorganiseBuffers(newDcl, bufferUsages);
			}

		}
	}

    Mesh::SubMeshIterator smIt = mesh.getSubMeshIterator();
	unsigned short idx = 0;
	while (smIt.hasMoreElements())
	{
		SubMesh* sm = smIt.getNext();
		if (!sm->useSharedVertices)
		{
			if (opts.interactive)
			{
				StringUtil::StrStreamType str;
				str << "SubMesh " << idx++; 
				reorganiseVertexBuffers(str.str(), mesh, sm->vertexData);
			}
			else
			{
				// Automatic
				VertexDeclaration* newDcl = 
					sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(
					mesh.hasSkeleton(), mesh.hasVertexAnimation());
				if (*newDcl != *(sm->vertexData->vertexDeclaration))
				{
					// Usages don't matter here since we're onlly exporting
					BufferUsageList bufferUsages;
					for (size_t u = 0; u <= newDcl->getMaxSource(); ++u)
						bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY);
					sm->vertexData->reorganiseBuffers(newDcl, bufferUsages);
				}
				
			}
		}
	}
}


void vertexBufferReorg(Mesh& mesh)
{
	String response;

	if (opts.interactive)
	{

		// Check to see whether we would like to reorganise vertex buffers
		std::cout << "\nWould you like to reorganise the vertex buffers for this mesh?";
		while (response.empty())
		{
			cin >> response;
			StringUtil::toLowerCase(response);
			if (response == "y")
			{
				reorganiseVertexBuffers(mesh);
			}
			else if (response == "n")
			{
				// Do nothing
			}
			else
			{
				response = "";
			}
		}
	}
	else if (!opts.dontReorganise)
	{
		reorganiseVertexBuffers(mesh);
	}

}

void buildLod(Mesh* mesh)
{	
	String response;

	// Prompt for LOD generation?
	bool genLod = false;
	bool askLodDtls = false;
	if (!opts.interactive) // derive from params if in batch mode
	{
		askLodDtls = false;
		if (opts.numLods == 0)
		{
			genLod = false;
		}
		else
		{
			genLod = true;
		}
	}
	else if(opts.numLods == 0) // otherwise only ask if not specified on command line
	{
		if (mesh->getNumLodLevels() > 1)
		{
			std::cout << "\nXML already contains level-of detail information.\n"
				"Do you want to: (u)se it, (r)eplace it, or (d)rop it?";
			while (response == "")
			{
				cin >> response;
				StringUtil::toLowerCase(response);
				if (response == "u")
				{
					// Do nothing
				}
				else if (response == "d")
				{
					mesh->removeLodLevels();
				}
				else if (response == "r")
				{
					genLod = true;
					askLodDtls = true;

				}
				else
				{
					response = "";
				}
			}// while response == ""
		}
		else // no existing LOD
		{
			std::cout << "\nWould you like to generate LOD information? (y/n)";
			while (response == "")
			{
				cin >> response;
				StringUtil::toLowerCase(response);
				if (response == "n")
				{
					// Do nothing
				}
				else if (response == "y")
				{
					genLod = true;
					askLodDtls = true;
				}
			}
		}
	}

	if (genLod)
	{
		unsigned short numLod;
		ProgressiveMesh::VertexReductionQuota quota;
		Real reduction;
		Mesh::LodDistanceList distanceList;

		if (askLodDtls)
		{
			cout << "\nHow many extra LOD levels would you like to generate?";
			cin >> numLod;

			cout << "\nWhat unit of reduction would you like to use:" <<
				"\n(f)ixed or (p)roportional?";
			cin >> response;
			StringUtil::toLowerCase(response);
			if (response == "f")
			{
				quota = ProgressiveMesh::VRQ_CONSTANT;
				cout << "\nHow many vertices should be removed at each LOD?";
			}
			else
			{
				quota = ProgressiveMesh::VRQ_PROPORTIONAL;
				cout << "\nWhat percentage of remaining vertices should be removed "
					"\at each LOD (e.g. 50)?";
			}
			cin >> reduction;
			if (quota == ProgressiveMesh::VRQ_PROPORTIONAL)
			{
				// Percentage -> parametric
				reduction = reduction * 0.01f;
			}

			cout << "\nEnter the distance for each LOD to come into effect.";

			Real distance;
			for (unsigned short iLod = 0; iLod < numLod; ++iLod)
			{
				cout << "\nLOD Level " << (iLod+1) << ":";
				cin >> distance;
				distanceList.push_back(distance);
			}
		}
		else
		{
			numLod = opts.numLods;
			quota = opts.usePercent? 
				ProgressiveMesh::VRQ_PROPORTIONAL : ProgressiveMesh::VRQ_CONSTANT;
			if (opts.usePercent)
			{
				reduction = opts.lodPercent * 0.01f;
			}
			else
			{
				reduction = opts.lodFixed;
			}
			Real currDist = 0;
			for (unsigned short iLod = 0; iLod < numLod; ++iLod)
			{
				currDist += opts.lodDist;
				distanceList.push_back(currDist);
			}

		}

		mesh->generateLodLevels(distanceList, quota, reduction);
	}

}

void checkColour(VertexData* vdata, bool &hasColour, bool &hasAmbiguousColour,
	VertexElementType& originalType)
{
	const VertexDeclaration::VertexElementList& elemList = vdata->vertexDeclaration->getElements();
	for (VertexDeclaration::VertexElementList::const_iterator i = elemList.begin();
		i != elemList.end(); ++i)
	{
		const VertexElement& elem = *i;
		switch (elem.getType())
		{
		case VET_COLOUR:
			hasAmbiguousColour = true;
		case VET_COLOUR_ABGR:
		case VET_COLOUR_ARGB:
			hasColour = true;
			originalType = elem.getType();
		default:
			// do nothing
			;
		};
	}

}

void resolveColourAmbiguities(Mesh* mesh)
{
	// Check what we're dealing with 
	bool hasColour = false;
	bool hasAmbiguousColour = false;
	VertexElementType originalType;
	if (mesh->sharedVertexData)
	{
		checkColour(mesh->sharedVertexData, hasColour, hasAmbiguousColour, originalType);
	}
	for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		SubMesh* sm = mesh->getSubMesh(i);
		if (sm->useSharedVertices == false)
		{
			checkColour(sm->vertexData, hasColour, hasAmbiguousColour, originalType);
		}
	}

	String response;
	if (hasAmbiguousColour)
	{
		if (opts.srcColourFormatSet)
		{
			originalType = opts.srcColourFormat;
		}
		else
		{
			// unknown input colour, have to ask
			std::cout << "\nYour mesh has vertex colours but I don't know whether they were generated\n"
				<< "using GL or D3D ordering. Please indicate which was used when the mesh was\n"
				<< "created (type 'gl' or 'd3d').\n";
			while (response.empty())
			{
				cin >> response;
				StringUtil::toLowerCase(response);
				if (response == "d3d")
				{
					originalType = VET_COLOUR_ARGB;
				}
				else if (response == "gl")
				{
					originalType = VET_COLOUR_ABGR;
				}
				else
				{
					response = "";
				}
			}
		}
	}

	// Ask what format we want to save in
	VertexElementType desiredType;
	if (hasColour)
	{
		if (opts.destColourFormatSet)
		{
			desiredType = opts.destColourFormat;
		}
		else
		{
			if (opts.interactive)
			{

				response = "";
				std::cout << "\nYour mesh has vertex colours, which can be stored in one of two layouts,\n"
					<< "each of which will be slightly faster to load in a different render system.\n"
					<< "Do you want to prefer Direct3D (d3d) or OpenGL (gl)?\n";
				while (response.empty())
				{
					cin >> response;
					StringUtil::toLowerCase(response);
					if (response == "d3d")
					{
						desiredType = VET_COLOUR_ARGB;
					}
					else if (response == "gl")
					{
						desiredType = VET_COLOUR_ABGR;
					}
					else
					{
						response = "";
					}
				}
			}
			else
			{
				// 'do no harm'
				return;
			}
		}

	}

	if (mesh->sharedVertexData && hasColour)
	{
		mesh->sharedVertexData->convertPackedColour(originalType, desiredType);
	}
	for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		SubMesh* sm = mesh->getSubMesh(i);
		if (sm->useSharedVertices == false && hasColour)
		{
			sm->vertexData->convertPackedColour(originalType, desiredType);
		}
	}


}

void recalcBounds(const VertexData* vdata, AxisAlignedBox& aabb, Real& radius)
{
	const VertexElement* posElem = 
		vdata->vertexDeclaration->findElementBySemantic(VES_POSITION);
	
	const HardwareVertexBufferSharedPtr buf = vdata->vertexBufferBinding->getBuffer(
		posElem->getSource());
	void* pBase = buf->lock(HardwareBuffer::HBL_READ_ONLY);

	for (size_t v = 0; v < vdata->vertexCount; ++v)
	{
		float* pFloat;
		posElem->baseVertexPointerToElement(pBase, &pFloat);
		
		Vector3 pos(pFloat[0], pFloat[1], pFloat[2]);
		aabb.merge(pos);
		radius = std::max(radius, pos.length());

		pBase = static_cast<void*>(static_cast<char*>(pBase) + buf->getVertexSize());

	}

	buf->unlock();

}

void recalcBounds(Mesh* mesh)
{
	AxisAlignedBox aabb;
	Real radius = 0.0f;

	if (mesh->sharedVertexData)
		recalcBounds(mesh->sharedVertexData, aabb, radius);
	for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		SubMesh* sm = mesh->getSubMesh(i);
		if (!sm->useSharedVertices)
			recalcBounds(sm->vertexData, aabb, radius);
	}

	mesh->_setBounds(aabb, false);
	mesh->_setBoundingSphereRadius(radius);
}

int main(int numargs, char** args)
{
    if (numargs < 2)
    {
        help();
        return -1;
    }

    logMgr = new LogManager();
	logMgr->createLog("OgreMeshUpgrade.log", true);
    rgm = new ResourceGroupManager();
    mth = new Math();
    matMgr = new MaterialManager();
    matMgr->initialise();
    skelMgr = new SkeletonManager();
    meshSerializer = new MeshSerializer();
    skeletonSerializer = new SkeletonSerializer();
    bufferManager = new DefaultHardwareBufferManager(); // needed because we don't have a rendersystem
    meshMgr = new MeshManager();
	// don't pad during upgrade
	meshMgr->setBoundsPaddingFactor(0.0f);

    
    UnaryOptionList unOptList;
    BinaryOptionList binOptList;

	unOptList["-i"] = false;
    unOptList["-e"] = false;
    unOptList["-t"] = false;
	unOptList["-r"] = false;
	unOptList["-gl"] = false;
	unOptList["-d3d"] = false;
	unOptList["-srcgl"] = false;
	unOptList["-srcd3d"] = false;
	unOptList["-b"] = false;
	binOptList["-l"] = "";
	binOptList["-d"] = "";
	binOptList["-p"] = "";
	binOptList["-f"] = "";
	binOptList["-E"] = "";
	binOptList["-td"] = "";

    int startIdx = findCommandLineOpts(numargs, args, unOptList, binOptList);
	parseOpts(unOptList, binOptList);

    String source(args[startIdx]);

    logMgr->createLog("OgreMeshUpgrader.log");


    // Load the mesh
    struct stat tagStat;

    FILE* pFile = fopen( source.c_str(), "rb" );
    if (!pFile)
    {
        OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND, 
            "File " + source + " not found.", "OgreMeshUpgrade");
    }
    stat( source.c_str(), &tagStat );
    MemoryDataStream* memstream = new MemoryDataStream(source, tagStat.st_size, true);
    fread( (void*)memstream->getPtr(), tagStat.st_size, 1, pFile );
    fclose( pFile );

	Mesh mesh(meshMgr, "conversion", 0, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

    DataStreamPtr stream(memstream);
    meshSerializer->importMesh(stream, &mesh);

    // Write out the converted mesh
    String dest;
    if (numargs == startIdx + 2)
    {
        dest = args[startIdx + 1];
    }
    else
    {
        dest = source;
    }

	String response;

	vertexBufferReorg(mesh);

	// Deal with VET_COLOUR ambiguities
	resolveColourAmbiguities(&mesh);
	
	buildLod(&mesh);

    // Make sure we generate edge lists, provided they are not deliberately disabled
    if (!opts.suppressEdgeLists)
    {
        cout << "\nGenerating edge lists.." << std::endl;
        mesh.buildEdgeList();
    }
	else
	{
		mesh.freeEdgeList();
	}

    // Generate tangents?
    if (opts.generateTangents)
    {
        unsigned short srcTex, destTex;
        bool existing = mesh.suggestTangentVectorBuildParams(opts.tangentSemantic, srcTex, destTex);
        if (existing)
        {
			if (opts.interactive)
			{
				std::cout << "\nThis mesh appears to already have a set of tangents, " <<
					"which would suggest tangent vectors have already been calculated. Do you really " <<
					"want to generate new tangent vectors (may duplicate)? (y/n)";
				while (response == "")
				{
					cin >> response;
					StringUtil::toLowerCase(response);
					if (response == "y")
					{
						// Do nothing
					}
					else if (response == "n")
					{
						opts.generateTangents = false;
					}
					else
					{
						response = "";
					}
				}
			}
			else
			{
				// safe
				opts.generateTangents = false;
			}

        }
        if (opts.generateTangents)
        {
            cout << "Generating tangent vectors...." << std::endl;
            mesh.buildTangentVectors(opts.tangentSemantic, srcTex, destTex);
        }
    }


	if (opts.recalcBounds)
		recalcBounds(&mesh);

    meshSerializer->exportMesh(&mesh, dest, opts.endian);
    



    delete meshMgr;
    delete skeletonSerializer;
    delete meshSerializer;
    delete skelMgr;
    delete matMgr;
    delete mth;
    delete rgm;
    delete logMgr;

    return 0;

}




daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

Stepping through the upgrader, I see that the assertion is occuring on mesh serialization..

the recalcBounds option is only applied subsequent to serialization.

The -b option does not look like it does the job.

Any thoughts?
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

Just found this reference:
http://www.ogre3d.org/phpBB2/viewtopic. ... +mesh+load

Will see if latest ofusion has the fix... will then use that to regenerate meshes. will mark this solved once i try that.

Thanks.

--

Ok When I run 3ds max, with ofusion plugged in, I cant even tell which version of Ofusion Pro we have (we are using the Pro version that we purchased last summer). Rather than just blindly updating to the latest with a hope that it will fix the problem (when indeed it might not if the latest version is the same as the version that we have), I'd like to get some idea that the version that we are moving to has the fix.

Does anyone know for sure that this AABB box export problem has been fixed in Ofusion? Also does someone know how to tell what version of ofusion you are using?


Thanks again.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 67

Post by sinbad »

If you run the meshupgrader in release mode you won't get the assertion. The assertion is just there to catch the problem but of course the meshupgrader would then go on to fix it for you.

Yes, the AABB problem has been fixed in oFusion, I've heard from several people who have exported with the new version happily.
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

Thank you. Sure enough the release version did not assert.

I am also trying to reexport my meshes with an updated ofusion. I will post one last time once that is successful.

I think this will get us past the current hump.
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

We are now able to get past scene load.

Thanks again.