scene::IAnimatedMesh* IrrlichtManager::LoadMesh(const Config& config, const c8* filename, bool animated)
{
if ( !filename || !strlen(filename) )
return NULL;
u32 beginTime = GetIrrlichtTimer()->getRealTime();
io::path extension;
core::getFileNameExtension(extension, filename);
extension.make_lower();
// some models might want special handling
// bool isLmo = (extension == ".lmo");
bool isX = (extension == ".x");
// load a mesh into the engine
bool wasCached = IsMeshInCache(filename);
scene::IAnimatedMesh* m = mSceneManager->getMesh(filename);
if (!m)
{
return NULL;
}
//fprintf(stderr, "loaded mesh %s\n", filename);
if ( !wasCached )
{
LOG.DebugLn("Time meshloading: ", core::stringc(GetIrrlichtTimer()->getRealTime() - beginTime).c_str());
// Let's fix some stuff which couldn't easily be set in the modeling tool (or would have gotten lost on export)
SetMaterialTypeByTextureName(m, video::EMT_TRANSPARENT_ALPHA_CHANNEL, "alpha");
SetMaterialTypeByTextureName(m, video::EMT_SOLID, "race_light01");
SetMaterialTypeByTextureName(m, video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF, "mask");
if ( isX && animated )
{
SetSpecularMaterial(m, 0, 0, 0);
}
setMaterialFlags(config, m);
// must be after SetMaterialTypeByTextureName as it replaces those materials again
SetES2ShaderMaterials(m);
if ( !animated )
{
// Reduce number of vertices by welding those which are identical.
// TODO: There might be a way to preprocess that, but probably difficult without changing the file-format.
// Because I have the suspicion those are create by the obj loader and are not cause by duplicates in the obj file itself (it also has some - but I don't think that many)
// So maybe another solution would be fixing that in the obj loader (or maybe it's fixed there already just not in the lmo loader? Not tried.)
u32 weldTime = GetIrrlichtTimer()->getRealTime();
//scene::IMesh * weldedMesh = mSceneManager->getMeshManipulator()->createMeshWelded(m->getMesh(0)); // too slow
scene::IMesh * weldedMesh = ExtIrr::CreateMeshWelded(m->getMesh(0));
LOG.DebugLn("Time createMeshWelded: ", core::stringc(GetIrrlichtTimer()->getRealTime() - weldTime).c_str());
weldTime = GetIrrlichtTimer()->getRealTime();
scene::IAnimatedMesh* m2 = mSceneManager->getMeshManipulator()->createAnimatedMesh(weldedMesh, m->getMeshType ());
weldedMesh->drop();
weldedMesh = NULL;
LOG.DebugLn("Time createAnimatedMesh: ", core::stringc(GetIrrlichtTimer()->getRealTime() - weldTime).c_str());
if ( m2 )
{
LOG.DebugLn("Old num vertices: ", core::stringc(getMeshVertexCount(m)).c_str());
LOG.DebugLn("New num vertices: ", core::stringc(getMeshVertexCount(m2)).c_str());
scene::IMeshCache * meshCache = mSceneManager->getMeshCache ();
meshCache->removeMesh(m);
meshCache->addMesh(filename, m2);
m = m2;
m2->drop();
m2 = NULL;
}
// In our case only the .X files are animated. So all others can be static
m->getMesh(0)->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX_AND_INDEX);
}
else
{
// Don't actually notice any speed difference when setting this.
m->getMesh(0)->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX);
}
}
return m;
}
scene::ISceneNode* IrrlichtManager::LoadModel(const Config& config, const c8* fileModel, scene::ITriangleSelector** createSelector)
{
u32 beginTime = GetIrrlichtTimer()->getRealTime();
scene::IAnimatedMesh* m = LoadMesh(config, fileModel, false);
if (!m)
{
return NULL;
}
// set default material properties
scene::ISceneNode* meshResult = NULL;
// Octree might still make sense if EHM_STATIC doesn't work on a platform.
// But needs profiling and a way to figure out _if_ EHM_STATIC does not work (unfortunately some Android devices seem to lie about it).
// meshResult = mSceneManager->addOctreeSceneNode(m, /*parent*/NULL, /*id*/-1, /*minimalPolysPerNode*/ 128);
meshResult = mSceneManager->addMeshSceneNode(m);
if ( createSelector )
{
*createSelector = meshResult->getTriangleSelector();
if ( *createSelector )
{
(*createSelector)->grab();
}
else
{
LOG.LogLn(LP_WARN, "mesh had no triangle selector: ", fileModel);
// We got no loopings, so we can be sure we never collide against triangles with normals pointing downwards.
// So we can kick them out and only collide against the rest.
scene::IMesh * reducedMesh = ExtIrr::CreateSubMeshForNormal(m->getMesh(0), irr::core::vector3df(0, 1, 0), -0.5f);
// create some fitting triangle-selector. Best choice depends a lot on level layout.
//*createSelector = mSceneManager->createOctreeTriangleSelector(reducedMesh, meshResult, 32 );
float cellSize = config.GetHoverRadius() * 2.f + 1.f; // We know we use radius*2 in physics - so this way never more than 4 cells are checked
*createSelector = new GridTriangleSelector(reducedMesh, meshResult, cellSize);
reducedMesh->drop();
LOG.DebugLn("Time created selector: ", core::stringc(GetIrrlichtTimer()->getRealTime() - beginTime).c_str());
}
}
meshResult->setName(fileModel); // Having the name makes debugging a lot easier
meshResult->setAutomaticCulling(scene::EAC_BOX); // EAC_OFF EAC_BOX EAC_FRUSTUM_BOX EAC_FRUSTUM_SPHERE
meshResult->setDebugDataVisible(false);
// LOG.DebugLn("Time LoadModel sum: ", core::stringc(GetIrrlichtTimer()->getRealTime() - beginTime).c_str());
return meshResult;
}
scene::IAnimatedMeshSceneNode* IrrlichtManager::LoadAnimatedModel(const Config& config, const c8* fileModel)
{
// load a model-mesh into the engine
scene::IAnimatedMesh* m = LoadMesh(config, fileModel, true);
if (!m)
{
return NULL;
}
//printf("loaded model %s\n", filename_);
// set default material properties
scene::IAnimatedMeshSceneNode* meshResult = NULL;
meshResult = mSceneManager->addAnimatedMeshSceneNode(m);
meshResult->setDebugDataVisible(false);
meshResult->setAutomaticCulling(scene::EAC_OFF); // EAC_OFF EAC_BOX EAC_FRUSTUM_BOX EAC_FRUSTUM_SPHERE
return meshResult;
}