Skip to content

File base_application.hpp

File List > gui > magnum > base_application.hpp

Go to the documentation of this file

#ifndef ROBOT_DART_GUI_MAGNUM_BASE_APPLICATION_HPP
#define ROBOT_DART_GUI_MAGNUM_BASE_APPLICATION_HPP

#include <mutex>
#include <unistd.h>
#include <unordered_map>

#include <robot_dart/gui/helper.hpp>
#include <robot_dart/gui/magnum/drawables.hpp>
#include <robot_dart/gui/magnum/gs/camera.hpp>
#include <robot_dart/gui/magnum/gs/cube_map.hpp>
#include <robot_dart/gui/magnum/gs/cube_map_color.hpp>
#include <robot_dart/gui/magnum/gs/phong_multi_light.hpp>
#include <robot_dart/gui/magnum/gs/shadow_map.hpp>
#include <robot_dart/gui/magnum/gs/shadow_map_color.hpp>
#include <robot_dart/gui/magnum/types.hpp>

#include <robot_dart/utils_headers_external_gui.hpp>

#include <Magnum/GL/CubeMapTextureArray.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/TextureArray.h>
#include <Magnum/Platform/GLContext.h>
#ifndef MAGNUM_MAC_OSX
#include <Magnum/Platform/WindowlessEglApplication.h>
#else
#include <Magnum/Platform/WindowlessCglApplication.h>
#endif
#include <Magnum/Shaders/DistanceFieldVector.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Shaders/VertexColor.h>

#include <Magnum/Text/AbstractFont.h>
#include <Magnum/Text/DistanceFieldGlyphCache.h>
#include <Magnum/Text/Renderer.h>

#define get_gl_context_with_sleep(name, ms_sleep)                             \
    /* Create/Get GLContext */                                                \
    Corrade::Utility::Debug name##_magnum_silence_output{nullptr};            \
    Magnum::Platform::WindowlessGLContext* name = nullptr;                    \
    while (name == nullptr) {                                                 \
        name = robot_dart::gui::magnum::GlobalData::instance()->gl_context(); \
        /* Sleep for some ms */                                               \
        usleep(ms_sleep * 1000);                                              \
    }                                                                         \
    while (!name->makeCurrent()) {                                            \
        /* Sleep for some ms */                                               \
        usleep(ms_sleep * 1000);                                              \
    }                                                                         \
                                                                              \
    Magnum::Platform::GLContext name##_magnum_context;

#define get_gl_context(name) get_gl_context_with_sleep(name, 0)

#define release_gl_context(name) robot_dart::gui::magnum::GlobalData::instance()->free_gl_context(name);

namespace robot_dart {
    namespace gui {
        namespace magnum {
            struct GlobalData {
            public:
                static GlobalData* instance()
                {
                    static GlobalData gdata;
                    return &gdata;
                }

                GlobalData(const GlobalData&) = delete;
                void operator=(const GlobalData&) = delete;

                Magnum::Platform::WindowlessGLContext* gl_context();
                void free_gl_context(Magnum::Platform::WindowlessGLContext* context);

                /* You should call this before starting to draw or after finished */
                void set_max_contexts(size_t N);

            private:
                GlobalData() = default;
                ~GlobalData() = default;

                void _create_contexts();

                std::vector<Magnum::Platform::WindowlessGLContext> _gl_contexts;
                std::vector<bool> _used;
                std::mutex _context_mutex;
                size_t _max_contexts = 4;
            };

            struct GraphicsConfiguration {
                // General
                size_t width = 640;
                size_t height = 480;
                std::string title = "DART";

                // Shadows
#ifndef MAGNUM_MAC_OSX
                bool shadowed = true;
                bool transparent_shadows = true;
#else
                // Disabling shadows by default on OSX
                bool shadowed = false;
                bool transparent_shadows = false;
#endif
                size_t shadow_map_size = 1024;

                // Lights
                size_t max_lights = 3;
                double specular_strength = 0.25; // strength of the specular component

                // These options are only for the main camera
                bool draw_main_camera = true;
                bool draw_debug = true;
                bool draw_text = true;

                // Background (default = black)
                Eigen::Vector4d bg_color{0.0, 0.0, 0.0, 1.0};
            };

            struct DebugDrawData {
                Magnum::Shaders::VertexColorGL3D* axes_shader;
                Magnum::GL::Mesh* axes_mesh;
                Magnum::Shaders::FlatGL2D* background_shader;
                Magnum::GL::Mesh* background_mesh;

                Magnum::Shaders::DistanceFieldVectorGL2D* text_shader;
                Magnum::GL::Buffer* text_vertices;
                Magnum::GL::Buffer* text_indices;
                Magnum::Text::AbstractFont* font;
                Magnum::Text::DistanceFieldGlyphCache* cache;
            };

            class BaseApplication {
            public:
                BaseApplication(const GraphicsConfiguration& configuration = GraphicsConfiguration());
                virtual ~BaseApplication() {}

                void init(RobotDARTSimu* simu, const GraphicsConfiguration& configuration);

                void clear_lights();
                void add_light(const gs::Light& light);
                gs::Light& light(size_t i);
                std::vector<gs::Light>& lights();
                size_t num_lights() const;

                Magnum::SceneGraph::DrawableGroup3D& drawables() { return _drawables; }
                Scene3D& scene() { return _scene; }
                gs::Camera& camera() { return *_camera; }
                const gs::Camera& camera() const { return *_camera; }

                bool done() const;

                void look_at(const Eigen::Vector3d& camera_pos,
                    const Eigen::Vector3d& look_at,
                    const Eigen::Vector3d& up);

                virtual void render() {}

                void update_lights(const gs::Camera& camera);
                void update_graphics();
                void render_shadows();

                bool attach_camera(gs::Camera& camera, dart::dynamics::BodyNode* body);

                // video (FPS is mandatory here, see the Graphics class for automatic computation)
                void record_video(const std::string& video_fname, int fps) { _camera->record_video(video_fname, fps); }

                bool shadowed() const { return _shadowed; }
                bool transparent_shadows() const { return _transparent_shadows; }
                void enable_shadows(bool enable = true, bool drawTransparentShadows = false);

                Corrade::Containers::Optional<Magnum::Image2D>& image() { return _camera->image(); }

                // This is for visualization purposes
                GrayscaleImage depth_image();

                // Image filled with depth buffer values
                GrayscaleImage raw_depth_image();

                // "Image" filled with depth buffer values (this returns an array of doubles)
                DepthImage depth_array();

                // Access to debug data
                DebugDrawData debug_draw_data()
                {
                    DebugDrawData data;
                    data.axes_shader = _3D_axis_shader.get();
                    data.background_shader = _background_shader.get();
                    data.axes_mesh = _3D_axis_mesh.get();
                    data.background_mesh = _background_mesh.get();
                    data.text_shader = _text_shader.get();
                    data.text_vertices = _text_vertices.get();
                    data.text_indices = _text_indices.get();
                    data.font = _font.get();
                    data.cache = _glyph_cache.get();

                    return data;
                }

            protected:
                /* Magnum */
                Scene3D _scene;
                Magnum::SceneGraph::DrawableGroup3D _drawables, _shadowed_drawables, _shadowed_color_drawables, _cubemap_drawables, _cubemap_color_drawables;
                std::unique_ptr<gs::PhongMultiLight> _color_shader, _texture_shader;

                std::unique_ptr<gs::Camera> _camera;

                bool _done = false;

                /* GUI Config */
                GraphicsConfiguration _configuration;

                /* DART */
                RobotDARTSimu* _simu;
                std::unique_ptr<Magnum::DartIntegration::World> _dart_world;
                std::unordered_map<Magnum::DartIntegration::Object*, ObjectStruct*> _drawable_objects;
                std::vector<gs::Light> _lights;

                /* Shadows */
                bool _shadowed = true, _transparent_shadows = false;
                int _transparentSize = 0;
                std::unique_ptr<gs::ShadowMap> _shadow_shader, _shadow_texture_shader;
                std::unique_ptr<gs::ShadowMapColor> _shadow_color_shader, _shadow_texture_color_shader;
                std::unique_ptr<gs::CubeMap> _cubemap_shader, _cubemap_texture_shader;
                std::unique_ptr<gs::CubeMapColor> _cubemap_color_shader, _cubemap_texture_color_shader;
                std::vector<ShadowData> _shadow_data;
                std::unique_ptr<Magnum::GL::Texture2DArray> _shadow_texture, _shadow_color_texture;
                std::unique_ptr<Magnum::GL::CubeMapTextureArray> _shadow_cube_map, _shadow_color_cube_map;
                int _max_lights = 5;
                int _shadow_map_size = 512;
                std::unique_ptr<Camera3D> _shadow_camera;
                Object3D* _shadow_camera_object;

                /* Debug visualization */
                std::unique_ptr<Magnum::GL::Mesh> _3D_axis_mesh;
                std::unique_ptr<Magnum::Shaders::VertexColorGL3D> _3D_axis_shader;
                std::unique_ptr<Magnum::GL::Mesh> _background_mesh;
                std::unique_ptr<Magnum::Shaders::FlatGL2D> _background_shader;

                /* Text visualization */
                std::unique_ptr<Magnum::Shaders::DistanceFieldVectorGL2D> _text_shader;
                Corrade::PluginManager::Manager<Magnum::Text::AbstractFont> _font_manager;
                Corrade::Containers::Pointer<Magnum::Text::DistanceFieldGlyphCache> _glyph_cache;
                Corrade::Containers::Pointer<Magnum::Text::AbstractFont> _font;
                Corrade::Containers::Pointer<Magnum::GL::Buffer> _text_vertices;
                Corrade::Containers::Pointer<Magnum::GL::Buffer> _text_indices;

                /* Importer */
                Corrade::PluginManager::Manager<Magnum::Trade::AbstractImporter> _importer_manager;

                void _gl_clean_up();
                void _prepare_shadows();
            };

            template <typename T>
            inline BaseApplication* make_application(RobotDARTSimu* simu, const GraphicsConfiguration& configuration = GraphicsConfiguration())
            {
                int argc = 0;
                char** argv = NULL;

                return new T(argc, argv, simu, configuration);
                // configuration.width, configuration.height, configuration.shadowed, configuration.transparent_shadows, configuration.max_lights, configuration.shadow_map_size);
            }
        } // namespace magnum
    } // namespace gui
} // namespace robot_dart

#endif