Code Snippet
using namespace Magnum;
using namespace Magnum::Math::Literals;
class CameraObject;
class ModelViewerApp;
class CameraObject: public Interconnect::Receiver, public Object3D {
public:
CameraObject(ModelViewerApp& app);
void mousePressEvent(Platform::Application::MouseEvent& event) {}
void mouseReleaseEvent(Platform::Application::MouseEvent& event) {}
void mouseMoveEvent(Platform::Application::MouseMoveEvent& event) {
...
event.setAccepted(true);
}
private:
Vector2i _prevPos{-1, -1};
};
class ModelViewerApp: public Platform::Application, public Interconnect::Emitter{
private:
Scene3D _scene;
Object3D _sceneRoot;
CameraObject _cameraObject;
Shaders::Phong _coloredShader{{}, 2};
std::shared_ptr<SceneGraph::Camera3D> _camera;
SceneGraph::DrawableGroup3D _drawables;
Containers::Array<Containers::Optional<GL::Mesh>> _meshes;
public:
explicit ModelViewerApp(const Arguments& arguments);
struct SignalKey{enum Event{
mousePressEvent,
mouseReleaseEvent,
mouseMoveEvent
};};
template <SignalKey::Event _SignalKey, class ...Args>
Signal triggered(typename Interconnect::Implementation::Identity<Args>::Type... args) {
return emit(&ModelViewerApp::triggered<_SignalKey, Args...>, args ...);
}
private:
void drawEvent() override;
void mousePressEvent(MouseEvent& event) override;
void mouseReleaseEvent(MouseEvent& event) override;
void mouseMoveEvent(MouseMoveEvent& event) override;
};
CameraObject::CameraObject(ModelViewerApp& app) {
using App = ModelViewerApp;
Interconnect::connect(app, &App::triggered<App::SignalKey::mousePressEvent, App::MouseEvent&>,
*this, &CameraObject::mousePressEvent);
Interconnect::connect(app, &App::triggered<App::SignalKey::mouseReleaseEvent, App::MouseEvent&>,
*this, &CameraObject::mouseReleaseEvent);
Interconnect::connect(app, &App::triggered<App::SignalKey::mouseMoveEvent, App::MouseMoveEvent&>,
*this, &CameraObject::mouseMoveEvent);
}
ModelViewerApp::ModelViewerApp(const Arguments& arguments):
Platform::Application{arguments, Configuration{}.setTitle("Magnum Primitives Example")},
_cameraObject(*this)
{
Utility::Arguments args;
args.addArgument("file").setHelp("file", "file to load")
.parse(arguments.argc, arguments.argv);
GL::Renderer::enable(GL::Renderer::Feature::DepthTest);
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);
const Trade::MeshData3D cube = Primitives::cubeSolid();
...
_sceneRoot.setParent(&_scene);
_cameraObject
.setParent(&_scene)
.translate(Vector3(0.0f, 10.f, 60.0f));
_camera.reset( new SceneGraph::Camera3D{_cameraObject});
(*_camera)
.setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)
.setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.01f, 1000.0f))
.setViewport(GL::defaultFramebuffer.viewport().size());
...
new ColoredDrawable{_sceneRoot, _coloredShader, *_meshes[0], 0x377777_rgbf, _drawables};
}
void ModelViewerApp::drawEvent() {
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);
_camera->draw(_drawables);
swapBuffers();
}
void ModelViewerApp::mousePressEvent(MouseEvent& event) {
triggered<SignalKey::mousePressEvent, MouseEvent&>(event);
}
void ModelViewerApp::mouseReleaseEvent(MouseEvent& event) {
triggered<SignalKey::mouseReleaseEvent, MouseEvent&>(event);
}
void ModelViewerApp::mouseMoveEvent(MouseMoveEvent& event) {
triggered<SignalKey::mouseMoveEvent, MouseMoveEvent&>(event);
if(event.isAccepted()) redraw();
}
MAGNUM_APPLICATION_MAIN(ModelViewerApp)
For The Complete Version Code
#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/DualQuaternionTransformation.h>
#include <Magnum/Platform/GlfwApplication.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Interconnect/Emitter.h>
#include <Corrade/Interconnect/Receiver.h>
#include <Corrade/Utility/Arguments.h>
using namespace Magnum;
typedef SceneGraph::Object<SceneGraph::DualQuaternionTransformation> Object3D;
typedef SceneGraph::Scene<SceneGraph::DualQuaternionTransformation> Scene3D;
class ColoredDrawable: public SceneGraph::Drawable3D {
public:
explicit ColoredDrawable(Object3D& object, Shaders::Phong& shader, GL::Mesh& mesh, const Color4& color, SceneGraph::DrawableGroup3D& group):
SceneGraph::Drawable3D{object, &group}, _shader(shader), _mesh(mesh), _color{color} {}
private:
void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) override {
_shader
.setSpecularColor({0, 0, 0})
.setDiffuseColor(_color)
.setAmbientColor({0.2, 0.2, 0.2})
.setLightPositions({camera.cameraMatrix().transformPoint({0.0f, 0.0f, -50.0f}),
camera.cameraMatrix().transformPoint({0.0f, 0.0f, 50.0f})})
.setTransformationMatrix(transformationMatrix)
.setNormalMatrix(transformationMatrix.rotationScaling())
.setProjectionMatrix(camera.projectionMatrix());
_mesh.draw(_shader);
}
Shaders::Phong& _shader;
GL::Mesh& _mesh;
Color4 _color;
};
class TexturedDrawable: public SceneGraph::Drawable3D {
public:
explicit TexturedDrawable(Object3D& object, Shaders::Phong& shader, GL::Mesh& mesh, GL::Texture2D& texture, SceneGraph::DrawableGroup3D& group):
SceneGraph::Drawable3D{object, &group}, _shader(shader), _mesh(mesh), _texture(texture) {}
private:
void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) override {
_shader
.setLightPosition(camera.cameraMatrix().transformPoint({-3.0f, 10.0f, 10.0f}))
.setTransformationMatrix(transformationMatrix)
.setNormalMatrix(transformationMatrix.rotationScaling())
.setProjectionMatrix(camera.projectionMatrix())
.bindDiffuseTexture(_texture);
_mesh.draw(_shader);
}
Shaders::Phong& _shader;
GL::Mesh& _mesh;
GL::Texture2D& _texture;
};
using namespace Magnum;
using namespace Magnum::Math::Literals;
class CameraObject;
class ModelViewerApp;
class CameraObject: public Interconnect::Receiver, public Object3D {
public:
CameraObject(ModelViewerApp& app);
void mousePressEvent(Platform::Application::MouseEvent& event) {}
void mouseReleaseEvent(Platform::Application::MouseEvent& event) {}
void mouseMoveEvent(Platform::Application::MouseMoveEvent& event) {
if(_prevPos[0] < 0 )
_prevPos = event.position();
else {
this->rotateZ(Rad((event.position()[0]-_prevPos[0])/360.0*3.1415926));
// this->rotateX(Rad((event.position()[1]-_prevPos[1])/360.0*3.1415926));
_prevPos = event.position();
}
event.setAccepted(true);
}
private:
Vector2i _prevPos{-1, -1};
};
class ModelViewerApp: public Platform::Application, public Interconnect::Emitter{
private:
Scene3D _scene;
Object3D _sceneRoot;
CameraObject _cameraObject;
Shaders::Phong _coloredShader{{}, 2};
std::shared_ptr<SceneGraph::Camera3D> _camera;
SceneGraph::DrawableGroup3D _drawables;
Containers::Array<Containers::Optional<GL::Mesh>> _meshes;
public:
explicit ModelViewerApp(const Arguments& arguments);
struct SignalKey{enum Event{
mousePressEvent,
mouseReleaseEvent,
mouseMoveEvent
};};
template <SignalKey::Event _SignalKey, class ...Args>
Signal triggered(typename Interconnect::Implementation::Identity<Args>::Type... args) {
return emit(&ModelViewerApp::triggered<_SignalKey, Args...>, args ...);
}
private:
void drawEvent() override;
void mousePressEvent(MouseEvent& event) override;
void mouseReleaseEvent(MouseEvent& event) override;
void mouseMoveEvent(MouseMoveEvent& event) override;
};
CameraObject::CameraObject(ModelViewerApp& app) {
using App = ModelViewerApp;
Interconnect::connect(app, &App::triggered<App::SignalKey::mousePressEvent, App::MouseEvent&>,
*this, &CameraObject::mousePressEvent);
Interconnect::connect(app, &App::triggered<App::SignalKey::mouseReleaseEvent, App::MouseEvent&>,
*this, &CameraObject::mouseReleaseEvent);
Interconnect::connect(app, &App::triggered<App::SignalKey::mouseMoveEvent, App::MouseMoveEvent&>,
*this, &CameraObject::mouseMoveEvent);
}
ModelViewerApp::ModelViewerApp(const Arguments& arguments):
Platform::Application{arguments, Configuration{}.setTitle("Magnum Primitives Example")},
_cameraObject(*this)
{
Utility::Arguments args;
args.addArgument("file").setHelp("file", "file to load")
.parse(arguments.argc, arguments.argv);
GL::Renderer::enable(GL::Renderer::Feature::DepthTest);
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);
const Trade::MeshData3D cube = Primitives::cubeSolid();
/* Load a scene importer plugin */
PluginManager::Manager<Trade::AbstractImporter> manager;
Containers::Pointer<Trade::AbstractImporter> importer = manager.loadAndInstantiate("ObjImporter");
if(!importer) std::exit(1);
if(!importer->openFile(args.value("file")))
std::exit(1);
_sceneRoot.setParent(&_scene);
_cameraObject
.setParent(&_scene)
.translate(Vector3(0.0f, 10.f, 60.0f));
_camera.reset( new SceneGraph::Camera3D{_cameraObject});
(*_camera)
.setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)
.setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.01f, 1000.0f))
.setViewport(GL::defaultFramebuffer.viewport().size());
_meshes = Containers::Array<Containers::Optional<GL::Mesh>>{importer->mesh3DCount()};
for(UnsignedInt i = 0; i != importer->mesh3DCount(); ++i) {
Containers::Optional<Trade::MeshData3D> meshData = importer->mesh3D(i);
if(!meshData || meshData->primitive() != MeshPrimitive::Triangles) {
Warning{} << "Cannot load the mesh, skipping";
continue;
}
/* Compile the mesh */
_meshes[i] = MeshTools::compile(*meshData, MeshTools::CompileFlag::GenerateSmoothNormals);
}
new ColoredDrawable{_sceneRoot, _coloredShader, *_meshes[0], 0x377777_rgbf, _drawables};
}
void ModelViewerApp::drawEvent() {
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);
_camera->draw(_drawables);
swapBuffers();
}
void ModelViewerApp::mousePressEvent(MouseEvent& event) {
triggered<SignalKey::mousePressEvent, MouseEvent&>(event);
}
void ModelViewerApp::mouseReleaseEvent(MouseEvent& event) {
triggered<SignalKey::mouseReleaseEvent, MouseEvent&>(event);
}
void ModelViewerApp::mouseMoveEvent(MouseMoveEvent& event) {
triggered<SignalKey::mouseMoveEvent, MouseMoveEvent&>(event);
if(event.isAccepted()) redraw();
}
MAGNUM_APPLICATION_MAIN(ModelViewerApp)