Then it required passing in -Wl,-rpath=/usr/local/lib to g++ because I didn't want to set LD_LIBRARY_PATH or figure out how to do it in my IDE.
After all the headache, I got my very simple mesh viewer to work.
It requires IrrAssimp source code to be in a folder IrrAssimp in the same directory as main.cpp
Other than that, it's a single file:
Code: Select all
/*
* main.cpp
*
* Created on: July 20, 2023
* Author: Nicolaus Anderson
*/
#include <irrlicht.h>
#include "IrrAssimp/IrrAssimp.h"
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
class MeshAnimator
: public irr::scene::ISceneNodeAnimator
{
public:
MeshAnimator();
~MeshAnimator();
//void setMesh( irr::scene::ISkinnedMesh* );
void play();
void pause();
void stop();
bool isPlaying() const;
virtual void animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs);
ISceneNodeAnimator* createClone(irr::scene::ISceneNode* node, irr::scene::ISceneManager* newManager);
private:
bool nowPlaying;
bool reset;
//irr::scene::ISkinnedMesh* animMesh;
};
MeshAnimator::MeshAnimator()
: nowPlaying(false)
, reset(false)
//, animMesh(0)
{}
MeshAnimator::~MeshAnimator()
{
/*if ( animMesh )
{
animMesh->drop();
animMesh = 0;
}*/
}
/*
void MeshAnimator::setMesh( irr::scene::ISkinnedMesh* mesh )
{
if ( animMesh )
{
animMesh->drop();
}
animMesh = mesh;
if ( animMesh )
{
animMesh->grab();
}
}*/
void MeshAnimator::play()
{
nowPlaying = true;
}
void MeshAnimator::pause()
{
nowPlaying = false;
}
void MeshAnimator::stop()
{
nowPlaying = false;
reset = true;
}
bool MeshAnimator::isPlaying() const
{
return nowPlaying;
}
void MeshAnimator::animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs)
{
// This method is totally useless because it comes after OnAnimate() of IAnimatedMeshSceneNode
return;
/*
setEnabled(nowPlaying, timeMs);
if ( reset )
{
StartTime = timeMs;
PauseTimeStart = timeMs;
reset = false;
}
if ( !nowPlaying || node->getType() != irr::scene::ESNT_ANIMATED_MESH )
return;
irr::scene::IAnimatedMeshSceneNode* animMeshNode = (irr::scene::IAnimatedMeshSceneNode*)node;
irr::scene::ISkinnedMesh* animMesh = (irr::scene::ISkinnedMesh*) animMeshNode->getMesh();
irr::u32 animTime = timeMs - (StartTime + PauseTimeSum);
//irr::u32 frameCount = animMesh->getFrameCount();
//irr::u32 frame = ((irr::u32)(animMesh->getAnimationSpeed() * animTime / 1000)) % frameCount;
// getAnimationSpeed is in frames per millisecond, not per second
//irr::u32 frame = ((irr::u32)(animMesh->getAnimationSpeed() * animTime)) % frameCount;
//irr::u32 frame = ((irr::u32)(animMeshNode->getAnimationSpeed() * animTime)) % (animMeshNode->getEndFrame() - 1);
irr::f32 frame = fmodf( animMeshNode->getAnimationSpeed() * animTime, animMeshNode->getEndFrame() - animMeshNode->getStartFrame() );
animMeshNode->setCurrentFrame(frame);
//bool blend = true;
//animMesh->animateMesh(frame, blend);
*/
}
irr::scene::ISceneNodeAnimator*
MeshAnimator::createClone(irr::scene::ISceneNode* node, irr::scene::ISceneManager* newManager)
{
return 0; // Do not copy this animator
}
class App
: irr::IEventReceiver
{
public:
App();
~App();
int run();
void makeGUI();
virtual bool OnEvent(const irr::SEvent& event);
bool OnGUIEvent(const irr::SEvent& event);
bool OnKeyEvent(const irr::SEvent& event);
void playMeshAnimation();
void stopMeshAnimation();
void resetCamera();
private:
enum {
EID_Camera = 0,
EID_Light,
EID_Mesh
};
enum {
EGUIID_Close = 0,
EGUIID_OpenFile,
EGUIID_OpenFileDialog,
EGUIID_MeshAnimInfoText,
EGUIID_PlayMeshAnim,
EGUIID_StopMeshAnim,
};
irr::IrrlichtDevice* irrDevice;
IrrAssimp* irrAssimp;
bool useAssimp;
//irr::scene::IAnimatedMesh* animMesh;
irr::scene::ISkinnedMesh* animMesh;
irr::scene::IAnimatedMeshSceneNode* animMeshNode;
MeshAnimator meshAnimator;
irr::scene::ICameraSceneNode* camNode;
irr::gui::IGUIButton* openFileButton;
irr::gui::IGUIFileOpenDialog* openFileDialog;
irr::gui::IGUIStaticText* meshInfoText;
irr::gui::IGUIButton* playPauseMeshAnimationButton;
irr::gui::IGUIButton* stopMeshAnimationButton;
};
App::App()
: irrDevice(0)
, irrAssimp(0)
, useAssimp(false)
, animMesh(0)
, animMeshNode(0)
, meshAnimator()
, camNode(0)
, openFileButton(0)
, openFileDialog(0)
, meshInfoText(0)
, playPauseMeshAnimationButton(0)
, stopMeshAnimationButton(0)
{
}
App::~App()
{
if ( irrAssimp )
{
delete irrAssimp;
}
if ( irrDevice )
{
irrDevice->drop();
irrDevice = 0;
}
}
int App::run()
{
irrDevice = irr::createDevice(
irr::video::EDT_OPENGL, irr::core::dimension2du(900,700), 32, false, false, false, this);
if ( !irrDevice )
return 1;
irrAssimp = new IrrAssimp(irrDevice->getSceneManager());
//IrrAssimpImport irrAssimpImport = new IrrAssimpImport();
//irrDevice->getSceneManager()->addExternalMeshLoader(irrAssimpImport);
//irrAssimpImport->drop();
//irrDevice->getSceneManager()->addCameraSceneNodeMaya(0, -200, 100, 10, (int)EID_Camera, 10, true, 0, 0);
camNode =
irrDevice->getSceneManager()->addCameraSceneNode(
0, irr::core::vector3df(5,0,0), irr::core::vector3df(0), EID_Camera, true);
irrDevice->getSceneManager()->addLightSceneNode(
0, irr::core::vector3df(10,20,10), irr::video::SColor(0xffffff), 100, EID_Light);
irrDevice->getVideoDriver()->setAmbientLight(irr::video::SColor(255,50,50,50));
makeGUI();
while(irrDevice->run())
{
irrDevice->getVideoDriver()->beginScene(true, true, irr::video::SColor(255,0,0,255));
irrDevice->getSceneManager()->drawAll();
irrDevice->getGUIEnvironment()->drawAll();
irrDevice->getVideoDriver()->endScene();
}
return 0;
}
void App::makeGUI()
{
irr::gui::IGUIEnvironment* guienv = irrDevice->getGUIEnvironment();
irr::core::vector2di startXY{0,0};
irr::core::dimension2du buttonSize{100,40};
openFileButton = guienv->addButton(
irr::core::recti(startXY, buttonSize),
0, EGUIID_OpenFile, L"Open", L"Open a mesh file");
startXY.X += (irr::s32)buttonSize.Width;
playPauseMeshAnimationButton = guienv->addButton(
irr::core::recti(startXY, buttonSize),
0, EGUIID_PlayMeshAnim, L"Play/Pause", L"Play or Pause mesh animation");
startXY.X += (irr::s32)buttonSize.Width;
stopMeshAnimationButton = guienv->addButton(
irr::core::recti(startXY, buttonSize),
0, EGUIID_StopMeshAnim, L"Stop", L"Stop mesh animation");
startXY.X += (irr::s32)buttonSize.Width;
meshInfoText = guienv->addStaticText(L"",
irr::core::recti(startXY, irr::core::dimension2du(200,40)),
true, true, 0, EGUIID_MeshAnimInfoText, true);
}
bool App::OnEvent(const irr::SEvent& event)
{
switch( event.EventType )
{
case irr::EET_GUI_EVENT:
return OnGUIEvent(event);
case irr::EET_KEY_INPUT_EVENT:
return OnKeyEvent(event);
default:
break;
}
return false;
}
bool App::OnGUIEvent(const irr::SEvent& event)
{
irr::io::path filePath;
switch(event.GUIEvent.EventType)
{
case irr::gui::EGET_BUTTON_CLICKED:
switch( event.GUIEvent.Caller->getID() )
{
case EGUIID_Close:
irrDevice->closeDevice();
return true;
case EGUIID_OpenFile:
if ( !openFileDialog )
{
openFileDialog =
irrDevice->getGUIEnvironment()->addFileOpenDialog(
L"Open File", true, 0, EGUIID_OpenFileDialog
);
}
return true;
case EGUIID_PlayMeshAnim:
playMeshAnimation();
return true;
case EGUIID_StopMeshAnim:
stopMeshAnimation();
return true;
default: break;
}
break;
case irr::gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED:
openFileDialog = 0;
break;
case irr::gui::EGET_FILE_SELECTED:
// Path to file
filePath = openFileDialog->getFileNameP();
if ( animMesh )
{
irrDevice->getSceneManager()->getMeshCache()->removeMesh(animMesh);
animMesh = 0;
}
if ( useAssimp )
{
animMesh = (irr::scene::ISkinnedMesh*)irrAssimp->getMesh(filePath);
} else {
animMesh = (irr::scene::ISkinnedMesh*)irrDevice->getSceneManager()->getMesh(filePath);
}
if ( !animMesh )
{
meshInfoText->setText(L"Mesh could not be loaded");
} else {
if ( animMeshNode )
{
animMeshNode->remove();
}
animMeshNode =
irrDevice->getSceneManager()->addAnimatedMeshSceneNode(
animMesh, 0, EID_Mesh,
irr::core::vector3df(0) - animMesh->getBoundingBox().getCenter(),
irr::core::vector3df(0,0,0),
irr::core::vector3df(1),
false);
animMeshNode->addAnimator(&meshAnimator);
meshInfoText->setText(L"Loaded mesh");
resetCamera();
}
openFileDialog = 0;
break;
default: break;
}
return false;
}
bool App::OnKeyEvent(const irr::SEvent& event)
{
irr::core::matrix4 rotationMatrix;
rotationMatrix.buildRotateFromTo(irr::core::vector3df(1,0,0), irr::core::vector3df(0.5,0,0.5));
irr::core::vector3df camPos;
if ( event.KeyInput.PressedDown )
switch(event.KeyInput.Key)
{
case irr::KEY_RIGHT:
camPos = camNode->getPosition();
rotationMatrix.rotateVect(camPos);
camNode->setPosition(camPos);
return true;
case irr::KEY_LEFT:
camPos = camNode->getPosition();
rotationMatrix.inverseRotateVect(camPos);
camNode->setPosition(camPos);
return true;
case irr::KEY_UP:
camPos = camNode->getPosition();
if ( event.KeyInput.Shift == true )
{
camPos /= 2;
camNode->setPosition(camPos);
} else {
camPos.Y += camPos.getLength()/10;
camNode->setPosition(camPos);
}
return true;
case irr::KEY_DOWN:
camPos = camNode->getPosition();
if ( event.KeyInput.Shift == true )
{
camPos *= 2;
camNode->setPosition(camPos);
} else {
camPos.Y -= camPos.getLength()/10;
camNode->setPosition(camPos);
}
return true;
case irr::KEY_ADD:
animMeshNode->setScale( animMeshNode->getScale() * 2 );
return true;
case irr::KEY_MINUS:
animMeshNode->setScale( animMeshNode->getScale() / 2 );
return true;
case irr::KEY_KEY_0:
useAssimp = !useAssimp;
meshInfoText->setText( useAssimp? L"Using Assimp" : L"Using default loader");
return true;
default: break;
}
return false;
}
void App::playMeshAnimation()
{
meshAnimator.play();
animMeshNode->setLoopMode(true); // Only this works apparently
animMeshNode->setCurrentFrame(0);
}
void App::stopMeshAnimation()
{
meshAnimator.stop();
animMeshNode->setLoopMode(false);
}
void App::resetCamera()
{
camNode->setPosition( irr::core::vector3df(5,0,0) );
}
int main(int argc, char* argv[])
{
App app{};
return app.run();
}
Movement of camera:
+ means scale mesh up
- means scale mesh down
up arrow means move up
up arrow + shift means zoom in
down arrow means move down
down arrow + shift means zoom out
right arrow means rotate 45 degrees around mesh
left arrow means rotate -45 degrees around mesh
I figured the code might be useful to someone who wants to see the results of loading with IrrAssimp.
For me, I found the only thing IrrAssimp loaded correctly was .x files. Even for .obj it failed to load the associated .mtl files.
It did load .blend files, preserving Blender axis orientation, though it didn't load any colors.
In fact, other than .x and b3d, it didn't load any colors or textures.