From da34d69340ddc1eaadd600eb1b260464a6f63d4e Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Mon, 4 May 2020 05:29:02 -0700 Subject: [PATCH 1/7] Add Scenegraph Primitives Example An example showing using primitives and the SceneGraph, as mentioned in: https://github.com/mosra/magnum/issues/102 Implements DrawableObject subclass of Drawable3D, demonstrates parenting objects to the scene and to other objects, and shows local object transformations and camera transformations using left and right click respectively --- CMakeLists.txt | 1 + src/CMakeLists.txt | 4 + src/primitives-scenegraph/CMakeLists.txt | 64 ++++++ .../PrimitivesSceneGraphExample.cpp | 207 ++++++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 src/primitives-scenegraph/CMakeLists.txt create mode 100644 src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 54c83a328..3daaa28b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ cmake_dependent_option(WITH_MOTIONBLUR_EXAMPLE "Build Motion Blur example" OFF " option(WITH_OVR_EXAMPLE "Build OVR example" OFF) option(WITH_PICKING_EXAMPLE "Build Picking example" OFF) option(WITH_PRIMITIVES_EXAMPLE "Build Primitives example" OFF) +option(WITH_PRIMITIVES_SCENEGRAPH_EXAMPLE "Build Primitives SceneGraph example" OFF) option(WITH_SHADOWS_EXAMPLE "Build Shadow Mapping example" OFF) option(WITH_TEXT_EXAMPLE "Build Text example (requires some TTF font plugin)" OFF) cmake_dependent_option(WITH_TEXTUREDTRIANGLE_EXAMPLE "Build TexturedTriangle example (requires some TGA importer plugin)" OFF "NOT MAGNUM_TARGET_GLES" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0982e199f..ef123092b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -107,6 +107,10 @@ if(WITH_PRIMITIVES_EXAMPLE) add_subdirectory(primitives) endif() +if(WITH_PRIMITIVES_SCENEGRAPH_EXAMPLE) + add_subdirectory(primitives-scenegraph) +endif() + if(WITH_SHADOWS_EXAMPLE) add_subdirectory(shadows) endif() diff --git a/src/primitives-scenegraph/CMakeLists.txt b/src/primitives-scenegraph/CMakeLists.txt new file mode 100644 index 000000000..621f82b18 --- /dev/null +++ b/src/primitives-scenegraph/CMakeLists.txt @@ -0,0 +1,64 @@ +# +# This file is part of Magnum. +# +# Original authors — credit is appreciated but not required: +# +# 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 — +# Vladimír Vondruš +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or distribute +# this software, either in source code form or as a compiled binary, for any +# purpose, commercial or non-commercial, and by any means. +# +# In jurisdictions that recognize copyright laws, the author or authors of +# this software dedicate any and all copyright interest in the software to +# the public domain. We make this dedication for the benefit of the public +# at large and to the detriment of our heirs and successors. We intend this +# dedication to be an overt act of relinquishment in perpetuity of all +# present and future rights to this software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +cmake_minimum_required(VERSION 3.4) + +project(MagnumPrimitivesSceneGraphExample CXX) + +# Add module path in case this is project root +if(PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../modules/" ${CMAKE_MODULE_PATH}) +endif() + +find_package(Corrade REQUIRED Main) +find_package(Magnum REQUIRED + GL + MeshTools + Primitives + Shaders + SceneGraph + Sdl2Application) + +set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON) + +add_executable(magnum-primitives-scenegraph WIN32 PrimitivesSceneGraphExample.cpp) +target_link_libraries(magnum-primitives-scenegraph PRIVATE + Corrade::Main + Magnum::Application + Magnum::GL + Magnum::Magnum + Magnum::MeshTools + Magnum::Primitives + Magnum::SceneGraph + Magnum::Shaders) + +install(TARGETS magnum-primitives-scenegraph DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}) + +# Make the executable a default target to build & run in Visual Studio +set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT magnum-primitives-scenegraph) diff --git a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp new file mode 100644 index 000000000..3ca318a71 --- /dev/null +++ b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp @@ -0,0 +1,207 @@ +/* + This file is part of Magnum. + + Original authors — credit is appreciated but not required: + + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 — + Vladimír Vondruš + + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or distribute + this software, either in source code form or as a compiled binary, for any + purpose, commercial or non-commercial, and by any means. + + In jurisdictions that recognize copyright laws, the author or authors of + this software dedicate any and all copyright interest in the software to + the public domain. We make this dedication for the benefit of the public + at large and to the detriment of our heirs and successors. We intend this + dedication to be an overt act of relinquishment in perpetuity of all + present and future rights to this software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Magnum { namespace Examples { + +using namespace Magnum::Math::Literals; + +typedef SceneGraph::Object Object3D; +typedef SceneGraph::Scene Scene3D; + +class DrawableObject : public Object3D, SceneGraph::Drawable3D { + public: + explicit DrawableObject(Shaders::Phong& shader, const Color3& color, GL::Mesh& mesh, Object3D& parent, SceneGraph::DrawableGroup3D& drawables) : Object3D{ &parent }, SceneGraph::Drawable3D{ *this, &drawables }, _shader(shader), _color{ color }, _mesh(mesh) {} + + void setColor(Color3 color) { _color = color; } + Color3 getColor() { return _color; } + + private: + virtual void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) { + _shader.setTransformationMatrix(transformationMatrix) + .setNormalMatrix(transformationMatrix.normalMatrix()) + .setProjectionMatrix(camera.projectionMatrix()) + .setAmbientColor(_color*0.3f) + .setDiffuseColor(_color) + /* relative to the camera */ + .setLightPosition({ 13.0f, 2.0f, 5.0f }) + .draw(_mesh); + } + + GL::Mesh& _mesh; + Shaders::Phong& _shader; + Color3 _color; +}; + + +class PrimitivesSceneGraphExample: public Platform::Application { + public: + explicit PrimitivesSceneGraphExample(const Arguments& arguments); + + private: + void drawEvent() override; + void mousePressEvent(MouseEvent& event) override; + void mouseReleaseEvent(MouseEvent& event) override; + void mouseMoveEvent(MouseMoveEvent& event) override; + + Scene3D _scene; + Object3D* _cameraObject; + SceneGraph::Camera3D* _camera; + SceneGraph::DrawableGroup3D _drawables; + + Shaders::Phong _shader; + GL::Mesh _cube, _plane, _sphere, _sphereWireframe; + + enum { ObjectCount = 4 }; + DrawableObject* _objects[ObjectCount]; + + Matrix4 _transformation, _projection; + Vector2i _previousMousePosition, _mousePressPosition; +}; + + + +PrimitivesSceneGraphExample::PrimitivesSceneGraphExample(const Arguments& arguments): + Platform::Application{arguments, Configuration{} + .setTitle("Magnum Primitives SceneGraph Example")} +{ + /* Global renderer configuration */ + GL::Renderer::enable(GL::Renderer::Feature::DepthTest); + GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); + + /* Set up meshes */ + _cube = MeshTools::compile(Primitives::cubeSolid()); + _sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32)); + _sphereWireframe = MeshTools::compile(Primitives::uvSphereWireframe(16, 32)); + _plane = MeshTools::compile(Primitives::planeSolid()); + + _projection = + Matrix4::perspectiveProjection( + 35.0_degf, Vector2{windowSize()}.aspectRatio(), 0.01f, 100.0f)* + Matrix4::translation(Vector3::zAxis(-10.0f)); + + /* Set up objects*/ + (*(_objects[0] = new DrawableObject{_shader, 0x3bd267_rgbf, _cube, _scene, _drawables })) + .rotateZ(45.0_degf) + .rotateX(-45.0_degf) + .translate({ 0.5f, 0.0f, -2.0f }); + + (*(_objects[1] = new DrawableObject{_shader, 0x2f83cc_rgbf, _sphere, _scene, _drawables })) + .scale(Vector3(0.75f)) + .translate({ -1.2f, -0.3f, -0.2f }); + + /* This uvSphereWireframe object has its parent set to the uvSphereSolid object, rather than + the _scene*/ + (*(_objects[2] = new DrawableObject{ _shader, 0x2f83cc_rgbf, _sphereWireframe, (*_objects[1]), _drawables })) + .scale(Vector3(1.01f)); + + (*(_objects[3] = new DrawableObject{_shader, 0xcd3431_rgbf, _plane, _scene, _drawables })) + .rotate(30.0_degf, Vector3(1.0f).normalized()) + .rotateX(-30.0_degf) + .scale(Vector3(2.0f)) + .translate({ 0.0f, -0.30f, -3.3f }); + + /* Configure camera */ + _cameraObject = new Object3D{ &_scene }; + _cameraObject->translate(Vector3::zAxis(8.0f)); + _camera = new SceneGraph::Camera3D{ *_cameraObject }; + _camera->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend) + .setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 4.0f / 3.0f, 0.001f, 100.0f)) + .setViewport(GL::defaultFramebuffer.viewport().size()); +} + +void PrimitivesSceneGraphExample::drawEvent() { + GL::defaultFramebuffer.clear( + GL::FramebufferClear::Color|GL::FramebufferClear::Depth); + + _camera->draw(_drawables); + swapBuffers(); +} + +void PrimitivesSceneGraphExample::mousePressEvent(MouseEvent& event) { + if(event.button() != MouseEvent::Button::Left) return; + + _previousMousePosition = _mousePressPosition = event.position(); + event.setAccepted(); +} + +void PrimitivesSceneGraphExample::mouseReleaseEvent(MouseEvent& event) { + if (event.button() != MouseEvent::Button::Left || _mousePressPosition != event.position()) return; + //Change the color of each object + for (auto* o : _objects) o->setColor(Color3::fromHsv({ o->getColor().hue() + 50.0_degf, 1.0f, 1.0f })); + + event.setAccepted(); + redraw(); +} + +void PrimitivesSceneGraphExample::mouseMoveEvent(MouseMoveEvent& event) { + /* We have to take window size, not framebuffer size, since the position is + in window coordinates and the two can be different on HiDPI systems */ + const Vector2 delta = 3.0f* + Vector2{ event.position() - _previousMousePosition } / + Vector2{ windowSize() }; + + // + if ((event.buttons() & MouseMoveEvent::Button::Right)) { + (*_cameraObject) + .rotate(Rad{ -delta.y() }, _cameraObject->transformation().right().normalized()) + .rotateY(Rad{ -delta.x() }); + } + + if ((event.buttons() & MouseMoveEvent::Button::Left)) { + for (auto* o : _objects) { + (*o).transformLocal(Matrix4::rotationX(Rad{ delta.y() }) * Matrix4::rotationY(Rad{ delta.x() })); + } + } + + _previousMousePosition = event.position(); + event.setAccepted(); + redraw(); +} + +}} + +MAGNUM_APPLICATION_MAIN(Magnum::Examples::PrimitivesSceneGraphExample) From 41b618732a8b65cd75f70b4bf602b370bbe93a67 Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Mon, 4 May 2020 05:30:53 -0700 Subject: [PATCH 2/7] fix tabs/spaces formatting --- src/primitives-scenegraph/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/primitives-scenegraph/CMakeLists.txt b/src/primitives-scenegraph/CMakeLists.txt index 621f82b18..37627d755 100644 --- a/src/primitives-scenegraph/CMakeLists.txt +++ b/src/primitives-scenegraph/CMakeLists.txt @@ -42,7 +42,7 @@ find_package(Magnum REQUIRED MeshTools Primitives Shaders - SceneGraph + SceneGraph Sdl2Application) set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON) @@ -55,7 +55,7 @@ target_link_libraries(magnum-primitives-scenegraph PRIVATE Magnum::Magnum Magnum::MeshTools Magnum::Primitives - Magnum::SceneGraph + Magnum::SceneGraph Magnum::Shaders) install(TARGETS magnum-primitives-scenegraph DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}) From 82ec5713efae7fb95eb36acda0b179d74cdf72e7 Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Mon, 4 May 2020 05:35:42 -0700 Subject: [PATCH 3/7] Add comments to button click events --- src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp index 3ca318a71..ae8cee717 100644 --- a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp +++ b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp @@ -170,6 +170,7 @@ void PrimitivesSceneGraphExample::mousePressEvent(MouseEvent& event) { void PrimitivesSceneGraphExample::mouseReleaseEvent(MouseEvent& event) { if (event.button() != MouseEvent::Button::Left || _mousePressPosition != event.position()) return; + //Change the color of each object for (auto* o : _objects) o->setColor(Color3::fromHsv({ o->getColor().hue() + 50.0_degf, 1.0f, 1.0f })); @@ -184,13 +185,14 @@ void PrimitivesSceneGraphExample::mouseMoveEvent(MouseMoveEvent& event) { Vector2{ event.position() - _previousMousePosition } / Vector2{ windowSize() }; - // + /* Dragging with right mouse button will rotate the camera */ if ((event.buttons() & MouseMoveEvent::Button::Right)) { (*_cameraObject) .rotate(Rad{ -delta.y() }, _cameraObject->transformation().right().normalized()) .rotateY(Rad{ -delta.x() }); } + /* Dragging with left mouse button will rotate the objects locally */ if ((event.buttons() & MouseMoveEvent::Button::Left)) { for (auto* o : _objects) { (*o).transformLocal(Matrix4::rotationX(Rad{ delta.y() }) * Matrix4::rotationY(Rad{ delta.x() })); From 54fadfe94d2f4158a685476a9bf045db49b064f2 Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Sat, 9 May 2020 03:23:02 -0700 Subject: [PATCH 4/7] Change getColor() to color() --- src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp index ae8cee717..8df7d228c 100644 --- a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp +++ b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp @@ -57,7 +57,7 @@ class DrawableObject : public Object3D, SceneGraph::Drawable3D { explicit DrawableObject(Shaders::Phong& shader, const Color3& color, GL::Mesh& mesh, Object3D& parent, SceneGraph::DrawableGroup3D& drawables) : Object3D{ &parent }, SceneGraph::Drawable3D{ *this, &drawables }, _shader(shader), _color{ color }, _mesh(mesh) {} void setColor(Color3 color) { _color = color; } - Color3 getColor() { return _color; } + Color3 color() const { return _color; } private: virtual void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) { @@ -172,7 +172,7 @@ void PrimitivesSceneGraphExample::mouseReleaseEvent(MouseEvent& event) { if (event.button() != MouseEvent::Button::Left || _mousePressPosition != event.position()) return; //Change the color of each object - for (auto* o : _objects) o->setColor(Color3::fromHsv({ o->getColor().hue() + 50.0_degf, 1.0f, 1.0f })); + for (auto* o : _objects) o->setColor(Color3::fromHsv({ o->color().hue() + 50.0_degf, 1.0f, 1.0f })); event.setAccepted(); redraw(); From 3aad33707a43d8889979ef13c26b1829137af619 Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Sat, 9 May 2020 03:23:52 -0700 Subject: [PATCH 5/7] Update author information --- src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp index 8df7d228c..250c05f75 100644 --- a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp +++ b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp @@ -3,8 +3,9 @@ Original authors — credit is appreciated but not required: - 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 — + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 — Vladimír Vondruš + Brandon Pomeroy This is free and unencumbered software released into the public domain. From 5c9c92e8aad85a73cba56b135c384c0cb61b3f18 Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Sat, 9 May 2020 04:02:42 -0700 Subject: [PATCH 6/7] Update author formatting --- src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp index 250c05f75..b0edef52c 100644 --- a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp +++ b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp @@ -3,8 +3,9 @@ Original authors — credit is appreciated but not required: - 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 — + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 — Vladimír Vondruš + 2020 — Brandon Pomeroy This is free and unencumbered software released into the public domain. From 7e83fd727a7c6109fbe0c4c023e4a0415ae0a2aa Mon Sep 17 00:00:00 2001 From: Brandon Pomeroy Date: Sat, 9 May 2020 04:04:39 -0700 Subject: [PATCH 7/7] Update formatting with .editorconfig --- .../PrimitivesSceneGraphExample.cpp | 344 +++++++++--------- 1 file changed, 173 insertions(+), 171 deletions(-) diff --git a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp index b0edef52c..6f8f74572 100644 --- a/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp +++ b/src/primitives-scenegraph/PrimitivesSceneGraphExample.cpp @@ -1,32 +1,32 @@ /* - This file is part of Magnum. + This file is part of Magnum. - Original authors — credit is appreciated but not required: + Original authors — credit is appreciated but not required: - 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 — - Vladimír Vondruš + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 — + Vladimír Vondruš 2020 — Brandon Pomeroy - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or distribute - this software, either in source code form or as a compiled binary, for any - purpose, commercial or non-commercial, and by any means. - - In jurisdictions that recognize copyright laws, the author or authors of - this software dedicate any and all copyright interest in the software to - the public domain. We make this dedication for the benefit of the public - at large and to the detriment of our heirs and successors. We intend this - dedication to be an overt act of relinquishment in perpetuity of all - present and future rights to this software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or distribute + this software, either in source code form or as a compiled binary, for any + purpose, commercial or non-commercial, and by any means. + + In jurisdictions that recognize copyright laws, the author or authors of + this software dedicate any and all copyright interest in the software to + the public domain. We make this dedication for the benefit of the public + at large and to the detriment of our heirs and successors. We intend this + dedication to be an overt act of relinquishment in perpetuity of all + present and future rights to this software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include @@ -47,165 +47,167 @@ #include #include -namespace Magnum { namespace Examples { - -using namespace Magnum::Math::Literals; - -typedef SceneGraph::Object Object3D; -typedef SceneGraph::Scene Scene3D; - -class DrawableObject : public Object3D, SceneGraph::Drawable3D { - public: - explicit DrawableObject(Shaders::Phong& shader, const Color3& color, GL::Mesh& mesh, Object3D& parent, SceneGraph::DrawableGroup3D& drawables) : Object3D{ &parent }, SceneGraph::Drawable3D{ *this, &drawables }, _shader(shader), _color{ color }, _mesh(mesh) {} - - void setColor(Color3 color) { _color = color; } - Color3 color() const { return _color; } - - private: - virtual void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) { - _shader.setTransformationMatrix(transformationMatrix) - .setNormalMatrix(transformationMatrix.normalMatrix()) - .setProjectionMatrix(camera.projectionMatrix()) - .setAmbientColor(_color*0.3f) - .setDiffuseColor(_color) - /* relative to the camera */ - .setLightPosition({ 13.0f, 2.0f, 5.0f }) - .draw(_mesh); +namespace Magnum { + namespace Examples { + + using namespace Magnum::Math::Literals; + + typedef SceneGraph::Object Object3D; + typedef SceneGraph::Scene Scene3D; + + class DrawableObject : public Object3D, SceneGraph::Drawable3D { + public: + explicit DrawableObject(Shaders::Phong& shader, const Color3& color, GL::Mesh& mesh, Object3D& parent, SceneGraph::DrawableGroup3D& drawables) : Object3D{ &parent }, SceneGraph::Drawable3D{ *this, &drawables }, _shader(shader), _color{ color }, _mesh(mesh) {} + + void setColor(Color3 color) { _color = color; } + Color3 color() const { return _color; } + + private: + virtual void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) { + _shader.setTransformationMatrix(transformationMatrix) + .setNormalMatrix(transformationMatrix.normalMatrix()) + .setProjectionMatrix(camera.projectionMatrix()) + .setAmbientColor(_color*0.3f) + .setDiffuseColor(_color) + /* relative to the camera */ + .setLightPosition({ 13.0f, 2.0f, 5.0f }) + .draw(_mesh); + } + + GL::Mesh& _mesh; + Shaders::Phong& _shader; + Color3 _color; + }; + + + class PrimitivesSceneGraphExample : public Platform::Application { + public: + explicit PrimitivesSceneGraphExample(const Arguments& arguments); + + private: + void drawEvent() override; + void mousePressEvent(MouseEvent& event) override; + void mouseReleaseEvent(MouseEvent& event) override; + void mouseMoveEvent(MouseMoveEvent& event) override; + + Scene3D _scene; + Object3D* _cameraObject; + SceneGraph::Camera3D* _camera; + SceneGraph::DrawableGroup3D _drawables; + + Shaders::Phong _shader; + GL::Mesh _cube, _plane, _sphere, _sphereWireframe; + + enum { ObjectCount = 4 }; + DrawableObject* _objects[ObjectCount]; + + Matrix4 _transformation, _projection; + Vector2i _previousMousePosition, _mousePressPosition; + }; + + + + PrimitivesSceneGraphExample::PrimitivesSceneGraphExample(const Arguments& arguments) : + Platform::Application{ arguments, Configuration{} + .setTitle("Magnum Primitives SceneGraph Example") } + { + /* Global renderer configuration */ + GL::Renderer::enable(GL::Renderer::Feature::DepthTest); + GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); + + /* Set up meshes */ + _cube = MeshTools::compile(Primitives::cubeSolid()); + _sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32)); + _sphereWireframe = MeshTools::compile(Primitives::uvSphereWireframe(16, 32)); + _plane = MeshTools::compile(Primitives::planeSolid()); + + _projection = + Matrix4::perspectiveProjection( + 35.0_degf, Vector2{ windowSize() }.aspectRatio(), 0.01f, 100.0f)* + Matrix4::translation(Vector3::zAxis(-10.0f)); + + /* Set up objects*/ + (*(_objects[0] = new DrawableObject{ _shader, 0x3bd267_rgbf, _cube, _scene, _drawables })) + .rotateZ(45.0_degf) + .rotateX(-45.0_degf) + .translate({ 0.5f, 0.0f, -2.0f }); + + (*(_objects[1] = new DrawableObject{ _shader, 0x2f83cc_rgbf, _sphere, _scene, _drawables })) + .scale(Vector3(0.75f)) + .translate({ -1.2f, -0.3f, -0.2f }); + + /* This uvSphereWireframe object has its parent set to the uvSphereSolid object, rather than + the _scene*/ + (*(_objects[2] = new DrawableObject{ _shader, 0x2f83cc_rgbf, _sphereWireframe, (*_objects[1]), _drawables })) + .scale(Vector3(1.01f)); + + (*(_objects[3] = new DrawableObject{ _shader, 0xcd3431_rgbf, _plane, _scene, _drawables })) + .rotate(30.0_degf, Vector3(1.0f).normalized()) + .rotateX(-30.0_degf) + .scale(Vector3(2.0f)) + .translate({ 0.0f, -0.30f, -3.3f }); + + /* Configure camera */ + _cameraObject = new Object3D{ &_scene }; + _cameraObject->translate(Vector3::zAxis(8.0f)); + _camera = new SceneGraph::Camera3D{ *_cameraObject }; + _camera->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend) + .setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 4.0f / 3.0f, 0.001f, 100.0f)) + .setViewport(GL::defaultFramebuffer.viewport().size()); } - - GL::Mesh& _mesh; - Shaders::Phong& _shader; - Color3 _color; -}; - - -class PrimitivesSceneGraphExample: public Platform::Application { - public: - explicit PrimitivesSceneGraphExample(const Arguments& arguments); - - private: - void drawEvent() override; - void mousePressEvent(MouseEvent& event) override; - void mouseReleaseEvent(MouseEvent& event) override; - void mouseMoveEvent(MouseMoveEvent& event) override; - - Scene3D _scene; - Object3D* _cameraObject; - SceneGraph::Camera3D* _camera; - SceneGraph::DrawableGroup3D _drawables; - - Shaders::Phong _shader; - GL::Mesh _cube, _plane, _sphere, _sphereWireframe; - - enum { ObjectCount = 4 }; - DrawableObject* _objects[ObjectCount]; - - Matrix4 _transformation, _projection; - Vector2i _previousMousePosition, _mousePressPosition; -}; - - - -PrimitivesSceneGraphExample::PrimitivesSceneGraphExample(const Arguments& arguments): - Platform::Application{arguments, Configuration{} - .setTitle("Magnum Primitives SceneGraph Example")} -{ - /* Global renderer configuration */ - GL::Renderer::enable(GL::Renderer::Feature::DepthTest); - GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); - - /* Set up meshes */ - _cube = MeshTools::compile(Primitives::cubeSolid()); - _sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32)); - _sphereWireframe = MeshTools::compile(Primitives::uvSphereWireframe(16, 32)); - _plane = MeshTools::compile(Primitives::planeSolid()); - - _projection = - Matrix4::perspectiveProjection( - 35.0_degf, Vector2{windowSize()}.aspectRatio(), 0.01f, 100.0f)* - Matrix4::translation(Vector3::zAxis(-10.0f)); - - /* Set up objects*/ - (*(_objects[0] = new DrawableObject{_shader, 0x3bd267_rgbf, _cube, _scene, _drawables })) - .rotateZ(45.0_degf) - .rotateX(-45.0_degf) - .translate({ 0.5f, 0.0f, -2.0f }); - - (*(_objects[1] = new DrawableObject{_shader, 0x2f83cc_rgbf, _sphere, _scene, _drawables })) - .scale(Vector3(0.75f)) - .translate({ -1.2f, -0.3f, -0.2f }); - - /* This uvSphereWireframe object has its parent set to the uvSphereSolid object, rather than - the _scene*/ - (*(_objects[2] = new DrawableObject{ _shader, 0x2f83cc_rgbf, _sphereWireframe, (*_objects[1]), _drawables })) - .scale(Vector3(1.01f)); - - (*(_objects[3] = new DrawableObject{_shader, 0xcd3431_rgbf, _plane, _scene, _drawables })) - .rotate(30.0_degf, Vector3(1.0f).normalized()) - .rotateX(-30.0_degf) - .scale(Vector3(2.0f)) - .translate({ 0.0f, -0.30f, -3.3f }); - - /* Configure camera */ - _cameraObject = new Object3D{ &_scene }; - _cameraObject->translate(Vector3::zAxis(8.0f)); - _camera = new SceneGraph::Camera3D{ *_cameraObject }; - _camera->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend) - .setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 4.0f / 3.0f, 0.001f, 100.0f)) - .setViewport(GL::defaultFramebuffer.viewport().size()); -} -void PrimitivesSceneGraphExample::drawEvent() { - GL::defaultFramebuffer.clear( - GL::FramebufferClear::Color|GL::FramebufferClear::Depth); + void PrimitivesSceneGraphExample::drawEvent() { + GL::defaultFramebuffer.clear( + GL::FramebufferClear::Color | GL::FramebufferClear::Depth); - _camera->draw(_drawables); - swapBuffers(); -} + _camera->draw(_drawables); + swapBuffers(); + } -void PrimitivesSceneGraphExample::mousePressEvent(MouseEvent& event) { - if(event.button() != MouseEvent::Button::Left) return; + void PrimitivesSceneGraphExample::mousePressEvent(MouseEvent& event) { + if (event.button() != MouseEvent::Button::Left) return; - _previousMousePosition = _mousePressPosition = event.position(); - event.setAccepted(); -} + _previousMousePosition = _mousePressPosition = event.position(); + event.setAccepted(); + } -void PrimitivesSceneGraphExample::mouseReleaseEvent(MouseEvent& event) { - if (event.button() != MouseEvent::Button::Left || _mousePressPosition != event.position()) return; + void PrimitivesSceneGraphExample::mouseReleaseEvent(MouseEvent& event) { + if (event.button() != MouseEvent::Button::Left || _mousePressPosition != event.position()) return; - //Change the color of each object - for (auto* o : _objects) o->setColor(Color3::fromHsv({ o->color().hue() + 50.0_degf, 1.0f, 1.0f })); + //Change the color of each object + for (auto* o : _objects) o->setColor(Color3::fromHsv({ o->color().hue() + 50.0_degf, 1.0f, 1.0f })); - event.setAccepted(); - redraw(); -} + event.setAccepted(); + redraw(); + } -void PrimitivesSceneGraphExample::mouseMoveEvent(MouseMoveEvent& event) { - /* We have to take window size, not framebuffer size, since the position is - in window coordinates and the two can be different on HiDPI systems */ - const Vector2 delta = 3.0f* - Vector2{ event.position() - _previousMousePosition } / - Vector2{ windowSize() }; - - /* Dragging with right mouse button will rotate the camera */ - if ((event.buttons() & MouseMoveEvent::Button::Right)) { - (*_cameraObject) - .rotate(Rad{ -delta.y() }, _cameraObject->transformation().right().normalized()) - .rotateY(Rad{ -delta.x() }); - } - - /* Dragging with left mouse button will rotate the objects locally */ - if ((event.buttons() & MouseMoveEvent::Button::Left)) { - for (auto* o : _objects) { - (*o).transformLocal(Matrix4::rotationX(Rad{ delta.y() }) * Matrix4::rotationY(Rad{ delta.x() })); + void PrimitivesSceneGraphExample::mouseMoveEvent(MouseMoveEvent& event) { + /* We have to take window size, not framebuffer size, since the position is + in window coordinates and the two can be different on HiDPI systems */ + const Vector2 delta = 3.0f* + Vector2{ event.position() - _previousMousePosition } / + Vector2{ windowSize() }; + + /* Dragging with right mouse button will rotate the camera */ + if ((event.buttons() & MouseMoveEvent::Button::Right)) { + (*_cameraObject) + .rotate(Rad{ -delta.y() }, _cameraObject->transformation().right().normalized()) + .rotateY(Rad{ -delta.x() }); + } + + /* Dragging with left mouse button will rotate the objects locally */ + if ((event.buttons() & MouseMoveEvent::Button::Left)) { + for (auto* o : _objects) { + (*o).transformLocal(Matrix4::rotationX(Rad{ delta.y() }) * Matrix4::rotationY(Rad{ delta.x() })); + } + } + + _previousMousePosition = event.position(); + event.setAccepted(); + redraw(); } + } - - _previousMousePosition = event.position(); - event.setAccepted(); - redraw(); } -}} - MAGNUM_APPLICATION_MAIN(Magnum::Examples::PrimitivesSceneGraphExample)