From ff4acf84be9be83230062ad749c6bcf99296d5d9 Mon Sep 17 00:00:00 2001 From: PodmogilnyjIvan Date: Fri, 3 Dec 2021 03:34:31 -0800 Subject: [PATCH] raw --- .gitignore | 55 + CMakeLists.txt | 210 + Changelog.md | 37 + Dependencies.md | 48 + LICENSE | 674 ++ README.md | 214 + Thirdparty/DBoW2/CMakeLists.txt | 40 + Thirdparty/DBoW2/DBoW2/BowVector.cpp | 130 + Thirdparty/DBoW2/DBoW2/BowVector.h | 119 + Thirdparty/DBoW2/DBoW2/FClass.h | 71 + Thirdparty/DBoW2/DBoW2/FORB.cpp | 193 + Thirdparty/DBoW2/DBoW2/FORB.h | 79 + Thirdparty/DBoW2/DBoW2/FeatureVector.cpp | 85 + Thirdparty/DBoW2/DBoW2/FeatureVector.h | 66 + Thirdparty/DBoW2/DBoW2/ScoringObject.cpp | 315 + Thirdparty/DBoW2/DBoW2/ScoringObject.h | 96 + Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h | 1665 ++++ Thirdparty/DBoW2/DUtils/Random.cpp | 129 + Thirdparty/DBoW2/DUtils/Random.h | 184 + Thirdparty/DBoW2/DUtils/Timestamp.cpp | 246 + Thirdparty/DBoW2/DUtils/Timestamp.h | 204 + Thirdparty/DBoW2/README.txt | 7 + Thirdparty/Pangolin/.clang-format | 2 + Thirdparty/Pangolin/.gitignore | 3 + Thirdparty/Pangolin/.gitmodules | 3 + Thirdparty/Pangolin/.travis.yml | 30 + Thirdparty/Pangolin/CMakeLists.txt | 109 + Thirdparty/Pangolin/LICENCE | 22 + Thirdparty/Pangolin/README.md | 176 + Thirdparty/Pangolin/appveyor.yml | 25 + Thirdparty/Pangolin/cmake_uninstall.cmake.in | 25 + Thirdparty/Pangolin/external/CMakeLists.txt | 153 + .../include/experimental/optional.hpp | 1067 +++ Thirdparty/Pangolin/include/mpark/variant.hpp | 2468 ++++++ .../include/pangolin/compat/glutbitmap.h | 92 + .../include/pangolin/compat/optional.h | 20 + .../include/pangolin/compat/type_traits.h | 49 + .../include/pangolin/compat/variant.h | 25 + .../pangolin/console/ConsoleInterpreter.h | 80 + .../include/pangolin/console/ConsoleView.h | 109 + .../include/pangolin/display/attach.h | 86 + .../pangolin/display/device/OsxWindow.h | 68 + .../display/device/PangolinNSApplication.h | 59 + .../display/device/PangolinNSGLView.h | 45 + .../pangolin/display/device/WinWindow.h | 89 + .../pangolin/display/device/X11GlContext.h | 0 .../pangolin/display/device/X11Window.h | 109 + .../pangolin/display/device/display_android.h | 333 + .../include/pangolin/display/display.h | 219 + .../pangolin/display/display_internal.h | 138 + .../include/pangolin/display/image_view.h | 74 + .../pangolin/display/opengl_render_state.h | 446 + .../include/pangolin/display/user_app.h | 43 + .../Pangolin/include/pangolin/display/view.h | 235 + .../include/pangolin/display/viewport.h | 65 + .../pangolin/display/widgets/widgets.h | 141 + .../include/pangolin/display/window.h | 90 + .../pangolin/factory/factory_registry.h | 114 + .../include/pangolin/geometry/geometry.h | 95 + .../include/pangolin/geometry/geometry_obj.h | 34 + .../include/pangolin/geometry/geometry_ply.h | 165 + .../include/pangolin/geometry/glgeometry.h | 87 + Thirdparty/Pangolin/include/pangolin/gl/cg.h | 283 + .../Pangolin/include/pangolin/gl/colour.h | 178 + .../include/pangolin/gl/compat/gl2engine.h | 320 + .../include/pangolin/gl/compat/gl_es_compat.h | 60 + Thirdparty/Pangolin/include/pangolin/gl/gl.h | 273 + .../Pangolin/include/pangolin/gl/gl.hpp | 866 ++ .../Pangolin/include/pangolin/gl/glchar.h | 78 + .../Pangolin/include/pangolin/gl/glcuda.h | 258 + .../Pangolin/include/pangolin/gl/gldraw.h | 518 ++ .../Pangolin/include/pangolin/gl/glfont.h | 78 + .../include/pangolin/gl/glformattraits.h | 214 + .../Pangolin/include/pangolin/gl/glinclude.h | 46 + .../Pangolin/include/pangolin/gl/glpangoglu.h | 79 + .../include/pangolin/gl/glpixformat.h | 95 + .../Pangolin/include/pangolin/gl/glplatform.h | 83 + .../Pangolin/include/pangolin/gl/glsl.h | 738 ++ .../Pangolin/include/pangolin/gl/glstate.h | 220 + .../Pangolin/include/pangolin/gl/gltext.h | 98 + .../include/pangolin/gl/gltexturecache.h | 116 + .../Pangolin/include/pangolin/gl/glvbo.h | 225 + .../include/pangolin/handler/handler.h | 116 + .../include/pangolin/handler/handler_enums.h | 94 + .../pangolin/handler/handler_glbuffer.h | 48 + .../include/pangolin/handler/handler_image.h | 162 + .../Pangolin/include/pangolin/image/copy.h | 45 + .../Pangolin/include/pangolin/image/image.h | 428 + .../include/pangolin/image/image_convert.h | 31 + .../include/pangolin/image/image_io.h | 65 + .../include/pangolin/image/image_utils.h | 185 + .../include/pangolin/image/managed_image.h | 175 + .../Pangolin/include/pangolin/image/memcpy.h | 110 + .../include/pangolin/image/pixel_format.h | 66 + .../include/pangolin/image/typed_image.h | 91 + .../pangolin/ios/PangolinAppDelegate.h | 36 + .../include/pangolin/ios/PangolinUIView.h | 22 + .../Pangolin/include/pangolin/log/packet.h | 70 + .../include/pangolin/log/packetstream.h | 111 + .../pangolin/log/packetstream_reader.h | 120 + .../pangolin/log/packetstream_source.h | 63 + .../include/pangolin/log/packetstream_tags.h | 46 + .../pangolin/log/packetstream_writer.h | 173 + .../include/pangolin/log/playback_session.h | 48 + .../Pangolin/include/pangolin/log/sync_time.h | 230 + .../Pangolin/include/pangolin/pangolin.h | 64 + .../Pangolin/include/pangolin/platform.h | 81 + .../Pangolin/include/pangolin/plot/datalog.h | 243 + .../Pangolin/include/pangolin/plot/plotter.h | 282 + .../Pangolin/include/pangolin/plot/range.h | 372 + .../include/pangolin/python/pyinterpreter.h | 70 + .../include/pangolin/python/pypangoio.h | 178 + .../include/pangolin/python/pypangolin_init.h | 40 + .../include/pangolin/python/pyuniqueobj.h | 111 + .../Pangolin/include/pangolin/python/pyvar.h | 271 + .../Pangolin/include/pangolin/scene/axis.h | 117 + .../include/pangolin/scene/interactive.h | 69 + .../pangolin/scene/interactive_index.h | 115 + .../include/pangolin/scene/renderable.h | 117 + .../include/pangolin/scene/scenehandler.h | 182 + .../Pangolin/include/pangolin/scene/tree.h | 49 + .../include/pangolin/tools/video_viewer.h | 106 + .../include/pangolin/utils/argagg.hpp | 1548 ++++ .../Pangolin/include/pangolin/utils/assert.h | 60 + .../include/pangolin/utils/compontent_cast.h | 42 + .../include/pangolin/utils/file_extension.h | 74 + .../include/pangolin/utils/file_utils.h | 151 + .../pangolin/utils/fix_size_buffer_queue.h | 153 + .../include/pangolin/utils/format_string.h | 87 + .../Pangolin/include/pangolin/utils/log.h | 44 + .../include/pangolin/utils/memstreambuf.h | 55 + .../Pangolin/include/pangolin/utils/params.h | 80 + .../Pangolin/include/pangolin/utils/parse.h | 108 + .../include/pangolin/utils/picojson.h | 1416 +++ .../pangolin/utils/posix/condition_variable.h | 27 + .../include/pangolin/utils/posix/semaphore.h | 26 + .../utils/posix/shared_memory_buffer.h | 25 + .../include/pangolin/utils/registration.h | 64 + .../include/pangolin/utils/signal_slot.h | 56 + .../include/pangolin/utils/sigstate.h | 75 + .../include/pangolin/utils/simple_math.h | 446 + .../include/pangolin/utils/threadedfilebuf.h | 97 + .../Pangolin/include/pangolin/utils/timer.h | 116 + .../include/pangolin/utils/transform.h | 102 + .../include/pangolin/utils/type_convert.h | 210 + .../Pangolin/include/pangolin/utils/uri.h | 49 + .../include/pangolin/utils/variadic_all.h | 44 + .../include/pangolin/utils/xml/license.txt | 52 + .../include/pangolin/utils/xml/rapidxml.hpp | 2635 ++++++ .../pangolin/utils/xml/rapidxml_iterators.hpp | 174 + .../pangolin/utils/xml/rapidxml_print.hpp | 421 + .../pangolin/utils/xml/rapidxml_utils.hpp | 122 + .../pangolin/var/input_record_repeat.h | 86 + .../Pangolin/include/pangolin/var/var.h | 340 + .../Pangolin/include/pangolin/var/varextra.h | 92 + .../Pangolin/include/pangolin/var/varstate.h | 130 + .../Pangolin/include/pangolin/var/varvalue.h | 114 + .../include/pangolin/var/varvaluegeneric.h | 87 + .../Pangolin/include/pangolin/var/varvaluet.h | 46 + .../include/pangolin/var/varwrapper.h | 91 + .../include/pangolin/video/drivers/debayer.h | 116 + .../pangolin/video/drivers/deinterlace.h | 62 + .../pangolin/video/drivers/depthsense.h | 171 + .../include/pangolin/video/drivers/ffmpeg.h | 207 + .../include/pangolin/video/drivers/firewire.h | 254 + .../include/pangolin/video/drivers/images.h | 121 + .../pangolin/video/drivers/images_out.h | 60 + .../include/pangolin/video/drivers/join.h | 78 + .../include/pangolin/video/drivers/merge.h | 70 + .../include/pangolin/video/drivers/mirror.h | 96 + .../include/pangolin/video/drivers/openni.h | 72 + .../include/pangolin/video/drivers/openni2.h | 147 + .../pangolin/video/drivers/openni_common.h | 153 + .../include/pangolin/video/drivers/pack.h | 84 + .../include/pangolin/video/drivers/pango.h | 104 + .../video/drivers/pango_video_output.h | 70 + .../include/pangolin/video/drivers/pleora.h | 196 + .../include/pangolin/video/drivers/pvn.h | 77 + .../pangolin/video/drivers/realsense.h | 87 + .../pangolin/video/drivers/realsense2.h | 87 + .../pangolin/video/drivers/shared_memory.h | 37 + .../include/pangolin/video/drivers/shift.h | 73 + .../include/pangolin/video/drivers/split.h | 65 + .../include/pangolin/video/drivers/teli.h | 118 + .../include/pangolin/video/drivers/test.h | 66 + .../include/pangolin/video/drivers/thread.h | 112 + .../include/pangolin/video/drivers/truncate.h | 71 + .../include/pangolin/video/drivers/unpack.h | 84 + .../include/pangolin/video/drivers/uvc.h | 115 + .../video/drivers/uvc_mediafoundation.h | 82 + .../include/pangolin/video/drivers/v4l.h | 128 + .../pangolin/video/iostream_operators.h | 132 + .../pangolin/video/stream_encoder_factory.h | 22 + .../include/pangolin/video/stream_info.h | 100 + .../Pangolin/include/pangolin/video/video.h | 261 + .../include/pangolin/video/video_exception.h | 29 + .../include/pangolin/video/video_input.h | 140 + .../include/pangolin/video/video_interface.h | 183 + .../include/pangolin/video/video_output.h | 93 + .../pangolin/video/video_output_interface.h | 52 + .../pangolin/video/video_record_repeat.h | 31 + .../include/tinyobj/tiny_obj_loader.h | 2547 ++++++ Thirdparty/Pangolin/package.xml | 16 + .../Pangolin/pyexamples/SimpleDisplay.py | 66 + Thirdparty/Pangolin/pyexamples/SimplePlot.py | 36 + Thirdparty/Pangolin/pyexamples/SimpleVideo.py | 58 + Thirdparty/Pangolin/src/CMakeLists.txt | 776 ++ Thirdparty/Pangolin/src/Doxyfile.in | 2281 +++++ .../Pangolin/src/PangolinConfig.cmake.in | 14 + .../src/PangolinConfigVersion.cmake.in | 17 + .../src/_embed_/fonts/AnonymousPro.ttf | Bin 0 -> 158080 bytes .../src/_embed_/fonts/AnonymousPro.txt | 94 + Thirdparty/Pangolin/src/config.h.in | 72 + .../Pangolin/src/console/ConsoleView.cpp | 327 + .../display/device/PangolinNSApplication.mm | 95 + .../src/display/device/PangolinNSGLView.mm | 325 + .../src/display/device/display_android.cpp | 1026 +++ .../src/display/device/display_headless.cpp | 166 + .../src/display/device/display_osx.mm | 249 + .../src/display/device/display_wayland.cpp | 1048 +++ .../src/display/device/display_win.cpp | 599 ++ .../src/display/device/display_x11.cpp | 530 ++ Thirdparty/Pangolin/src/display/display.cpp | 660 ++ .../Pangolin/src/display/image_view.cpp | 223 + .../src/display/opengl_render_state.cpp | 707 ++ Thirdparty/Pangolin/src/display/view.cpp | 583 ++ Thirdparty/Pangolin/src/display/viewport.cpp | 113 + .../Pangolin/src/display/widgets/widgets.cpp | 680 ++ .../Pangolin/src/display/window_factory.cpp | 42 + Thirdparty/Pangolin/src/geometry/geometry.cpp | 73 + .../Pangolin/src/geometry/geometry_obj.cpp | 254 + .../Pangolin/src/geometry/geometry_ply.cpp | 483 + .../Pangolin/src/geometry/glgeometry.cpp | 142 + Thirdparty/Pangolin/src/geometry/tinyobj.cpp | 29 + .../Pangolin/src/gl/compat/gl2engine.cpp | 39 + Thirdparty/Pangolin/src/gl/glchar.cpp | 70 + Thirdparty/Pangolin/src/gl/gldraw.cpp | 51 + Thirdparty/Pangolin/src/gl/glfont.cpp | 214 + Thirdparty/Pangolin/src/gl/glpangoglu.cpp | 274 + Thirdparty/Pangolin/src/gl/gltext.cpp | 202 + Thirdparty/Pangolin/src/gl/gltexturecache.cpp | 38 + Thirdparty/Pangolin/src/gl/stb_truetype.h | 4882 ++++++++++ Thirdparty/Pangolin/src/handler/handler.cpp | 401 + .../Pangolin/src/handler/handler_glbuffer.cpp | 45 + .../Pangolin/src/handler/handler_image.cpp | 462 + Thirdparty/Pangolin/src/image/image_io.cpp | 177 + .../Pangolin/src/image/image_io_exr.cpp | 188 + .../Pangolin/src/image/image_io_jpg.cpp | 263 + .../Pangolin/src/image/image_io_lz4.cpp | 86 + .../src/image/image_io_packed12bit.cpp | 85 + .../Pangolin/src/image/image_io_pango.cpp | 62 + .../Pangolin/src/image/image_io_png.cpp | 234 + .../Pangolin/src/image/image_io_ppm.cpp | 104 + .../Pangolin/src/image/image_io_raw.cpp | 25 + .../Pangolin/src/image/image_io_tga.cpp | 53 + .../Pangolin/src/image/image_io_zstd.cpp | 125 + .../Pangolin/src/image/pixel_format.cpp | 70 + .../Pangolin/src/ios/PangolinAppDelegate.mm | 49 + Thirdparty/Pangolin/src/ios/PangolinUIView.mm | 202 + Thirdparty/Pangolin/src/log/packet.cpp | 79 + Thirdparty/Pangolin/src/log/packetstream.cpp | 146 + .../Pangolin/src/log/packetstream_reader.cpp | 425 + .../Pangolin/src/log/packetstream_writer.cpp | 156 + .../Pangolin/src/log/playback_session.cpp | 26 + Thirdparty/Pangolin/src/plot/datalog.cpp | 287 + Thirdparty/Pangolin/src/plot/plotter.cpp | 1171 +++ .../Pangolin/src/python/pyinterpreter.cpp | 239 + .../Pangolin/src/python/pypangolin/attach.cpp | 48 + .../Pangolin/src/python/pypangolin/attach.hpp | 37 + .../Pangolin/src/python/pypangolin/colour.cpp | 48 + .../Pangolin/src/python/pypangolin/colour.hpp | 37 + .../src/python/pypangolin/datalog.cpp | 86 + .../src/python/pypangolin/datalog.hpp | 37 + .../src/python/pypangolin/display.cpp | 81 + .../src/python/pypangolin/display.hpp | 36 + .../Pangolin/src/python/pypangolin/gl.cpp | 102 + .../Pangolin/src/python/pypangolin/gl.hpp | 36 + .../src/python/pypangolin/gl_draw.cpp | 71 + .../src/python/pypangolin/gl_draw.hpp | 37 + .../Pangolin/src/python/pypangolin/glsl.cpp | 72 + .../Pangolin/src/python/pypangolin/glsl.hpp | 36 + .../src/python/pypangolin/handler.cpp | 58 + .../src/python/pypangolin/handler.hpp | 62 + .../Pangolin/src/python/pypangolin/image.cpp | 34 + .../Pangolin/src/python/pypangolin/image.hpp | 67 + .../src/python/pypangolin/image_view.cpp | 50 + .../src/python/pypangolin/image_view.hpp | 37 + .../python/pypangolin/opengl_render_state.cpp | 116 + .../python/pypangolin/opengl_render_state.hpp | 37 + .../Pangolin/src/python/pypangolin/params.cpp | 43 + .../Pangolin/src/python/pypangolin/params.hpp | 37 + .../src/python/pypangolin/pixel_format.cpp | 43 + .../src/python/pypangolin/pixel_format.hpp | 37 + .../src/python/pypangolin/plotter.cpp | 131 + .../src/python/pypangolin/plotter.hpp | 37 + .../src/python/pypangolin/pypangolin.h | 83 + .../Pangolin/src/python/pypangolin/var.cpp | 157 + .../Pangolin/src/python/pypangolin/var.hpp | 67 + .../Pangolin/src/python/pypangolin/video.cpp | 645 ++ .../Pangolin/src/python/pypangolin/video.hpp | 37 + .../Pangolin/src/python/pypangolin/view.cpp | 86 + .../Pangolin/src/python/pypangolin/view.hpp | 37 + .../src/python/pypangolin/viewport.cpp | 56 + .../src/python/pypangolin/viewport.hpp | 38 + .../Pangolin/src/python/pypangolin/widget.cpp | 36 + .../Pangolin/src/python/pypangolin/widget.hpp | 37 + .../Pangolin/src/python/pypangolin/window.cpp | 105 + .../Pangolin/src/python/pypangolin/window.hpp | 37 + .../Pangolin/src/python/pypangolin_init.cpp | 57 + .../Pangolin/src/python/pypangolin_module.cpp | 33 + .../Pangolin/src/tools/video_viewer.cpp | 446 + .../Pangolin/src/utils/file_extension.cpp | 223 + Thirdparty/Pangolin/src/utils/file_utils.cpp | 496 ++ .../src/utils/posix/condition_variable.cpp | 89 + .../Pangolin/src/utils/posix/semaphore.cpp | 83 + .../src/utils/posix/shared_memory_buffer.cpp | 134 + Thirdparty/Pangolin/src/utils/sigstate.cpp | 60 + .../Pangolin/src/utils/threadedfilebuf.cpp | 286 + Thirdparty/Pangolin/src/utils/timer.cpp | 0 Thirdparty/Pangolin/src/utils/uri.cpp | 104 + .../Pangolin/src/var/input_record_repeat.cpp | 183 + Thirdparty/Pangolin/src/var/vars.cpp | 259 + .../Pangolin/src/video/drivers/debayer.cpp | 362 + .../src/video/drivers/deinterlace.cpp | 107 + .../Pangolin/src/video/drivers/depthsense.cpp | 656 ++ .../Pangolin/src/video/drivers/ffmpeg.cpp | 953 ++ .../Pangolin/src/video/drivers/firewire.cpp | 969 ++ .../Pangolin/src/video/drivers/images.cpp | 298 + .../Pangolin/src/video/drivers/images_out.cpp | 126 + .../Pangolin/src/video/drivers/join.cpp | 429 + .../Pangolin/src/video/drivers/json.cpp | 86 + .../Pangolin/src/video/drivers/merge.cpp | 165 + .../Pangolin/src/video/drivers/mirror.cpp | 589 ++ .../Pangolin/src/video/drivers/openni.cpp | 299 + .../Pangolin/src/video/drivers/openni2.cpp | 690 ++ .../Pangolin/src/video/drivers/pack.cpp | 260 + .../Pangolin/src/video/drivers/pango.cpp | 243 + .../src/video/drivers/pango_video_output.cpp | 303 + .../Pangolin/src/video/drivers/pleora.cpp | 744 ++ Thirdparty/Pangolin/src/video/drivers/pvn.cpp | 136 + .../Pangolin/src/video/drivers/realsense.cpp | 100 + .../Pangolin/src/video/drivers/realsense2.cpp | 114 + .../src/video/drivers/shared_memory.cpp | 99 + .../Pangolin/src/video/drivers/shift.cpp | 159 + .../Pangolin/src/video/drivers/split.cpp | 158 + .../Pangolin/src/video/drivers/teli.cpp | 550 ++ .../Pangolin/src/video/drivers/test.cpp | 111 + .../Pangolin/src/video/drivers/thread.cpp | 269 + .../Pangolin/src/video/drivers/truncate.cpp | 110 + .../Pangolin/src/video/drivers/unpack.cpp | 268 + Thirdparty/Pangolin/src/video/drivers/uvc.cpp | 364 + .../src/video/drivers/uvc_mediafoundation.cpp | 660 ++ Thirdparty/Pangolin/src/video/drivers/v4l.cpp | 798 ++ .../src/video/stream_encoder_factory.cpp | 62 + Thirdparty/Pangolin/src/video/video.cpp | 80 + Thirdparty/Pangolin/src/video/video_input.cpp | 220 + .../src/video/video_interface_factory.cpp | 42 + .../Pangolin/src/video/video_output.cpp | 137 + .../video/video_output_interface_factory.cpp | 42 + Thirdparty/Pangolin/test/CMakeLists.txt | 1 + Thirdparty/Pangolin/test/log/CMakeLists.txt | 6 + Thirdparty/Pangolin/test/log/testlog.cpp | 282 + Thirdparty/Pangolin/tools/CMakeLists.txt | 17 + .../Pangolin/tools/ModelViewer/CMakeLists.txt | 6 + .../Pangolin/tools/ModelViewer/main.cpp | 270 + .../Pangolin/tools/ModelViewer/rendertree.h | 97 + .../Pangolin/tools/ModelViewer/shader.h | 134 + Thirdparty/Pangolin/tools/ModelViewer/util.h | 30 + .../Pangolin/tools/Plotter/CMakeLists.txt | 53 + .../tools/Plotter/application-x-pangoplot.xml | 9 + .../Pangolin/tools/Plotter/csv_data_loader.h | 87 + Thirdparty/Pangolin/tools/Plotter/main.cpp | 126 + .../tools/VideoConvert/CMakeLists.txt | 15 + .../Pangolin/tools/VideoConvert/main.cpp | 75 + .../Pangolin/tools/VideoJson/CMakeLists.txt | 18 + .../Pangolin/tools/VideoJson/main-print.cpp | 36 + .../tools/VideoJson/main-transform.cpp | 63 + .../Pangolin/tools/VideoViewer/CMakeLists.txt | 53 + .../tools/VideoViewer/application-x-pango.svg | 424 + .../tools/VideoViewer/application-x-pango.xml | 10 + .../Pangolin/tools/VideoViewer/main.cpp | 51 + Thirdparty/g2o/CMakeLists.txt | 178 + Thirdparty/g2o/README.txt | 3 + Thirdparty/g2o/config.h.in | 13 + Thirdparty/g2o/g2o/core/base_binary_edge.h | 119 + Thirdparty/g2o/g2o/core/base_binary_edge.hpp | 218 + Thirdparty/g2o/g2o/core/base_edge.h | 110 + Thirdparty/g2o/g2o/core/base_multi_edge.h | 113 + Thirdparty/g2o/g2o/core/base_multi_edge.hpp | 222 + Thirdparty/g2o/g2o/core/base_unary_edge.h | 100 + Thirdparty/g2o/g2o/core/base_unary_edge.hpp | 129 + Thirdparty/g2o/g2o/core/base_vertex.h | 120 + Thirdparty/g2o/g2o/core/base_vertex.hpp | 55 + Thirdparty/g2o/g2o/core/batch_stats.cpp | 90 + Thirdparty/g2o/g2o/core/batch_stats.h | 83 + Thirdparty/g2o/g2o/core/block_solver.h | 193 + Thirdparty/g2o/g2o/core/block_solver.hpp | 634 ++ Thirdparty/g2o/g2o/core/cache.cpp | 183 + Thirdparty/g2o/g2o/core/cache.h | 140 + Thirdparty/g2o/g2o/core/creators.h | 75 + Thirdparty/g2o/g2o/core/eigen_types.h | 73 + .../g2o/g2o/core/estimate_propagator.cpp | 267 + Thirdparty/g2o/g2o/core/estimate_propagator.h | 175 + Thirdparty/g2o/g2o/core/factory.cpp | 217 + Thirdparty/g2o/g2o/core/factory.h | 179 + Thirdparty/g2o/g2o/core/hyper_dijkstra.cpp | 261 + Thirdparty/g2o/g2o/core/hyper_dijkstra.h | 112 + Thirdparty/g2o/g2o/core/hyper_graph.cpp | 166 + Thirdparty/g2o/g2o/core/hyper_graph.h | 220 + .../g2o/g2o/core/hyper_graph_action.cpp | 268 + Thirdparty/g2o/g2o/core/hyper_graph_action.h | 222 + .../g2o/g2o/core/jacobian_workspace.cpp | 89 + Thirdparty/g2o/g2o/core/jacobian_workspace.h | 96 + Thirdparty/g2o/g2o/core/linear_solver.h | 109 + .../g2o/core/marginal_covariance_cholesky.cpp | 222 + .../g2o/core/marginal_covariance_cholesky.h | 103 + Thirdparty/g2o/g2o/core/matrix_operations.h | 74 + Thirdparty/g2o/g2o/core/matrix_structure.cpp | 125 + Thirdparty/g2o/g2o/core/matrix_structure.h | 69 + Thirdparty/g2o/g2o/core/openmp_mutex.h | 97 + Thirdparty/g2o/g2o/core/optimizable_graph.cpp | 910 ++ Thirdparty/g2o/g2o/core/optimizable_graph.h | 688 ++ .../g2o/g2o/core/optimization_algorithm.cpp | 62 + .../g2o/g2o/core/optimization_algorithm.h | 117 + .../core/optimization_algorithm_dogleg.cpp | 229 + .../g2o/core/optimization_algorithm_dogleg.h | 89 + .../core/optimization_algorithm_factory.cpp | 137 + .../g2o/core/optimization_algorithm_factory.h | 167 + .../optimization_algorithm_gauss_newton.cpp | 101 + .../optimization_algorithm_gauss_newton.h | 54 + .../core/optimization_algorithm_levenberg.cpp | 214 + .../core/optimization_algorithm_levenberg.h | 92 + .../core/optimization_algorithm_property.h | 57 + .../optimization_algorithm_with_hessian.cpp | 101 + .../optimization_algorithm_with_hessian.h | 72 + Thirdparty/g2o/g2o/core/parameter.cpp | 40 + Thirdparty/g2o/g2o/core/parameter.h | 56 + .../g2o/g2o/core/parameter_container.cpp | 142 + Thirdparty/g2o/g2o/core/parameter_container.h | 74 + Thirdparty/g2o/g2o/core/robust_kernel.cpp | 46 + Thirdparty/g2o/g2o/core/robust_kernel.h | 81 + .../g2o/g2o/core/robust_kernel_factory.cpp | 111 + .../g2o/g2o/core/robust_kernel_factory.h | 151 + .../g2o/g2o/core/robust_kernel_impl.cpp | 173 + Thirdparty/g2o/g2o/core/robust_kernel_impl.h | 167 + Thirdparty/g2o/g2o/core/solver.cpp | 87 + Thirdparty/g2o/g2o/core/solver.h | 151 + Thirdparty/g2o/g2o/core/sparse_block_matrix.h | 231 + .../g2o/g2o/core/sparse_block_matrix.hpp | 657 ++ .../g2o/g2o/core/sparse_block_matrix_ccs.h | 282 + .../g2o/core/sparse_block_matrix_diagonal.h | 108 + .../g2o/g2o/core/sparse_block_matrix_test.cpp | 107 + Thirdparty/g2o/g2o/core/sparse_optimizer.cpp | 615 ++ Thirdparty/g2o/g2o/core/sparse_optimizer.h | 312 + .../g2o/g2o/solvers/linear_solver_dense.h | 125 + .../g2o/g2o/solvers/linear_solver_eigen.h | 237 + Thirdparty/g2o/g2o/stuff/color_macros.h | 65 + Thirdparty/g2o/g2o/stuff/macros.h | 134 + Thirdparty/g2o/g2o/stuff/misc.h | 206 + Thirdparty/g2o/g2o/stuff/os_specific.c | 64 + Thirdparty/g2o/g2o/stuff/os_specific.h | 56 + Thirdparty/g2o/g2o/stuff/property.cpp | 105 + Thirdparty/g2o/g2o/stuff/property.h | 158 + Thirdparty/g2o/g2o/stuff/string_tools.cpp | 200 + Thirdparty/g2o/g2o/stuff/string_tools.h | 176 + Thirdparty/g2o/g2o/stuff/timeutil.cpp | 124 + Thirdparty/g2o/g2o/stuff/timeutil.h | 132 + Thirdparty/g2o/g2o/types/se3_ops.h | 47 + Thirdparty/g2o/g2o/types/se3_ops.hpp | 85 + Thirdparty/g2o/g2o/types/se3mat.cpp | 39 + Thirdparty/g2o/g2o/types/se3mat.h | 47 + Thirdparty/g2o/g2o/types/se3quat.h | 306 + Thirdparty/g2o/g2o/types/sim3.h | 307 + Thirdparty/g2o/g2o/types/types_sba.cpp | 56 + Thirdparty/g2o/g2o/types/types_sba.h | 61 + .../g2o/g2o/types/types_seven_dof_expmap.cpp | 239 + .../g2o/g2o/types/types_seven_dof_expmap.h | 176 + .../g2o/g2o/types/types_six_dof_expmap.cpp | 407 + .../g2o/g2o/types/types_six_dof_expmap.h | 242 + Thirdparty/g2o/license-bsd.txt | 27 + build.sh | 31 + build_ros.sh | 7 + include/Atlas.h | 134 + include/CameraModels/GeometricCamera.h | 99 + include/CameraModels/KannalaBrandt8.h | 116 + include/CameraModels/Pinhole.h | 108 + include/Config.h | 6 + include/Converter.h | 63 + include/Frame.h | 327 + include/FrameDrawer.h | 88 + include/G2oTypes.h | 863 ++ include/ImuTypes.h | 285 + include/Initializer.h | 106 + include/KeyFrame.h | 389 + include/KeyFrameDatabase.h | 88 + include/LocalMapping.h | 201 + include/LoopClosing.h | 226 + include/MLPnPsolver.h | 254 + include/Map.h | 165 + include/MapDrawer.h | 73 + include/MapPoint.h | 187 + include/ORBVocabulary.h | 34 + include/ORBextractor.h | 114 + include/ORBmatcher.h | 115 + include/OptimizableTypes.h | 219 + include/Optimizer.h | 123 + include/PnPsolver.h | 195 + include/Sim3Solver.h | 134 + include/System.h | 243 + include/Tracking.h | 353 + include/TwoViewReconstruction.h | 99 + include/Viewer.h | 98 + include/getopt.c | 1258 +++ include/getopt.h | 188 + include/unistd.h | 59 + src/Atlas.cc | 305 + src/CameraModels/KannalaBrandt8.cpp | 536 ++ src/CameraModels/Pinhole.cpp | 214 + src/Converter.cc | 217 + src/Frame.cc | 1247 +++ src/FrameDrawer.cc | 404 + src/G2oTypes.cc | 874 ++ src/ImuTypes.cc | 521 ++ src/Initializer.cc | 922 ++ src/KeyFrame.cc | 1160 +++ src/KeyFrameDatabase.cc | 857 ++ src/LocalMapping.cc | 1521 ++++ src/LoopClosing.cc | 2118 +++++ src/MLPnPsolver.cpp | 1045 +++ src/Map.cc | 493 ++ src/MapDrawer.cc | 512 ++ src/MapPoint.cc | 599 ++ src/ORBextractor.cc | 1179 +++ src/ORBmatcher.cc | 2599 ++++++ src/OptimizableTypes.cpp | 332 + src/Optimizer.cc | 7824 +++++++++++++++++ src/PnPsolver.cc | 1019 +++ src/Sim3Solver.cc | 508 ++ src/System.cc | 790 ++ src/Tracking.cc | 4185 +++++++++ src/TwoViewReconstruction.cc | 935 ++ src/Viewer.cc | 374 + 542 files changed, 136810 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 Changelog.md create mode 100644 Dependencies.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Thirdparty/DBoW2/CMakeLists.txt create mode 100644 Thirdparty/DBoW2/DBoW2/BowVector.cpp create mode 100644 Thirdparty/DBoW2/DBoW2/BowVector.h create mode 100644 Thirdparty/DBoW2/DBoW2/FClass.h create mode 100644 Thirdparty/DBoW2/DBoW2/FORB.cpp create mode 100644 Thirdparty/DBoW2/DBoW2/FORB.h create mode 100644 Thirdparty/DBoW2/DBoW2/FeatureVector.cpp create mode 100644 Thirdparty/DBoW2/DBoW2/FeatureVector.h create mode 100644 Thirdparty/DBoW2/DBoW2/ScoringObject.cpp create mode 100644 Thirdparty/DBoW2/DBoW2/ScoringObject.h create mode 100644 Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h create mode 100644 Thirdparty/DBoW2/DUtils/Random.cpp create mode 100644 Thirdparty/DBoW2/DUtils/Random.h create mode 100644 Thirdparty/DBoW2/DUtils/Timestamp.cpp create mode 100644 Thirdparty/DBoW2/DUtils/Timestamp.h create mode 100644 Thirdparty/DBoW2/README.txt create mode 100644 Thirdparty/Pangolin/.clang-format create mode 100644 Thirdparty/Pangolin/.gitignore create mode 100644 Thirdparty/Pangolin/.gitmodules create mode 100644 Thirdparty/Pangolin/.travis.yml create mode 100644 Thirdparty/Pangolin/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/LICENCE create mode 100644 Thirdparty/Pangolin/README.md create mode 100644 Thirdparty/Pangolin/appveyor.yml create mode 100644 Thirdparty/Pangolin/cmake_uninstall.cmake.in create mode 100644 Thirdparty/Pangolin/external/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/include/experimental/optional.hpp create mode 100644 Thirdparty/Pangolin/include/mpark/variant.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/compat/glutbitmap.h create mode 100644 Thirdparty/Pangolin/include/pangolin/compat/optional.h create mode 100644 Thirdparty/Pangolin/include/pangolin/compat/type_traits.h create mode 100644 Thirdparty/Pangolin/include/pangolin/compat/variant.h create mode 100644 Thirdparty/Pangolin/include/pangolin/console/ConsoleInterpreter.h create mode 100644 Thirdparty/Pangolin/include/pangolin/console/ConsoleView.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/attach.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/OsxWindow.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSApplication.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSGLView.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/WinWindow.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/X11GlContext.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/X11Window.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/device/display_android.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/display.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/display_internal.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/image_view.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/opengl_render_state.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/user_app.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/view.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/viewport.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/widgets/widgets.h create mode 100644 Thirdparty/Pangolin/include/pangolin/display/window.h create mode 100644 Thirdparty/Pangolin/include/pangolin/factory/factory_registry.h create mode 100644 Thirdparty/Pangolin/include/pangolin/geometry/geometry.h create mode 100644 Thirdparty/Pangolin/include/pangolin/geometry/geometry_obj.h create mode 100644 Thirdparty/Pangolin/include/pangolin/geometry/geometry_ply.h create mode 100644 Thirdparty/Pangolin/include/pangolin/geometry/glgeometry.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/cg.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/colour.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/compat/gl2engine.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/compat/gl_es_compat.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/gl.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/gl.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glchar.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glcuda.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/gldraw.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glfont.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glformattraits.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glinclude.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glpangoglu.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glpixformat.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glplatform.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glsl.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glstate.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/gltext.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/gltexturecache.h create mode 100644 Thirdparty/Pangolin/include/pangolin/gl/glvbo.h create mode 100644 Thirdparty/Pangolin/include/pangolin/handler/handler.h create mode 100644 Thirdparty/Pangolin/include/pangolin/handler/handler_enums.h create mode 100644 Thirdparty/Pangolin/include/pangolin/handler/handler_glbuffer.h create mode 100644 Thirdparty/Pangolin/include/pangolin/handler/handler_image.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/copy.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/image.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/image_convert.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/image_io.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/image_utils.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/managed_image.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/memcpy.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/pixel_format.h create mode 100644 Thirdparty/Pangolin/include/pangolin/image/typed_image.h create mode 100644 Thirdparty/Pangolin/include/pangolin/ios/PangolinAppDelegate.h create mode 100644 Thirdparty/Pangolin/include/pangolin/ios/PangolinUIView.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/packet.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/packetstream.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/packetstream_reader.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/packetstream_source.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/packetstream_tags.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/packetstream_writer.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/playback_session.h create mode 100644 Thirdparty/Pangolin/include/pangolin/log/sync_time.h create mode 100644 Thirdparty/Pangolin/include/pangolin/pangolin.h create mode 100644 Thirdparty/Pangolin/include/pangolin/platform.h create mode 100644 Thirdparty/Pangolin/include/pangolin/plot/datalog.h create mode 100644 Thirdparty/Pangolin/include/pangolin/plot/plotter.h create mode 100644 Thirdparty/Pangolin/include/pangolin/plot/range.h create mode 100644 Thirdparty/Pangolin/include/pangolin/python/pyinterpreter.h create mode 100644 Thirdparty/Pangolin/include/pangolin/python/pypangoio.h create mode 100644 Thirdparty/Pangolin/include/pangolin/python/pypangolin_init.h create mode 100644 Thirdparty/Pangolin/include/pangolin/python/pyuniqueobj.h create mode 100644 Thirdparty/Pangolin/include/pangolin/python/pyvar.h create mode 100644 Thirdparty/Pangolin/include/pangolin/scene/axis.h create mode 100644 Thirdparty/Pangolin/include/pangolin/scene/interactive.h create mode 100644 Thirdparty/Pangolin/include/pangolin/scene/interactive_index.h create mode 100644 Thirdparty/Pangolin/include/pangolin/scene/renderable.h create mode 100644 Thirdparty/Pangolin/include/pangolin/scene/scenehandler.h create mode 100644 Thirdparty/Pangolin/include/pangolin/scene/tree.h create mode 100644 Thirdparty/Pangolin/include/pangolin/tools/video_viewer.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/argagg.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/assert.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/compontent_cast.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/file_extension.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/file_utils.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/fix_size_buffer_queue.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/format_string.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/log.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/memstreambuf.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/params.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/parse.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/picojson.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/posix/condition_variable.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/posix/semaphore.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/posix/shared_memory_buffer.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/registration.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/signal_slot.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/sigstate.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/simple_math.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/threadedfilebuf.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/timer.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/transform.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/type_convert.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/uri.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/variadic_all.h create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/xml/license.txt create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_iterators.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_print.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_utils.hpp create mode 100644 Thirdparty/Pangolin/include/pangolin/var/input_record_repeat.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/var.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/varextra.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/varstate.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/varvalue.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/varvaluegeneric.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/varvaluet.h create mode 100644 Thirdparty/Pangolin/include/pangolin/var/varwrapper.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/debayer.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/deinterlace.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/depthsense.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/ffmpeg.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/firewire.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/images.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/images_out.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/join.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/merge.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/mirror.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/openni.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/openni2.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/openni_common.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/pack.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/pango.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/pango_video_output.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/pleora.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/pvn.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/realsense.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/realsense2.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/shared_memory.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/shift.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/split.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/teli.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/test.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/thread.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/truncate.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/unpack.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/uvc.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/uvc_mediafoundation.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/drivers/v4l.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/iostream_operators.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/stream_encoder_factory.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/stream_info.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video_exception.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video_input.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video_interface.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video_output.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video_output_interface.h create mode 100644 Thirdparty/Pangolin/include/pangolin/video/video_record_repeat.h create mode 100644 Thirdparty/Pangolin/include/tinyobj/tiny_obj_loader.h create mode 100644 Thirdparty/Pangolin/package.xml create mode 100644 Thirdparty/Pangolin/pyexamples/SimpleDisplay.py create mode 100644 Thirdparty/Pangolin/pyexamples/SimplePlot.py create mode 100644 Thirdparty/Pangolin/pyexamples/SimpleVideo.py create mode 100644 Thirdparty/Pangolin/src/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/src/Doxyfile.in create mode 100644 Thirdparty/Pangolin/src/PangolinConfig.cmake.in create mode 100644 Thirdparty/Pangolin/src/PangolinConfigVersion.cmake.in create mode 100644 Thirdparty/Pangolin/src/_embed_/fonts/AnonymousPro.ttf create mode 100644 Thirdparty/Pangolin/src/_embed_/fonts/AnonymousPro.txt create mode 100644 Thirdparty/Pangolin/src/config.h.in create mode 100644 Thirdparty/Pangolin/src/console/ConsoleView.cpp create mode 100644 Thirdparty/Pangolin/src/display/device/PangolinNSApplication.mm create mode 100644 Thirdparty/Pangolin/src/display/device/PangolinNSGLView.mm create mode 100644 Thirdparty/Pangolin/src/display/device/display_android.cpp create mode 100644 Thirdparty/Pangolin/src/display/device/display_headless.cpp create mode 100644 Thirdparty/Pangolin/src/display/device/display_osx.mm create mode 100644 Thirdparty/Pangolin/src/display/device/display_wayland.cpp create mode 100644 Thirdparty/Pangolin/src/display/device/display_win.cpp create mode 100644 Thirdparty/Pangolin/src/display/device/display_x11.cpp create mode 100644 Thirdparty/Pangolin/src/display/display.cpp create mode 100644 Thirdparty/Pangolin/src/display/image_view.cpp create mode 100644 Thirdparty/Pangolin/src/display/opengl_render_state.cpp create mode 100644 Thirdparty/Pangolin/src/display/view.cpp create mode 100644 Thirdparty/Pangolin/src/display/viewport.cpp create mode 100644 Thirdparty/Pangolin/src/display/widgets/widgets.cpp create mode 100644 Thirdparty/Pangolin/src/display/window_factory.cpp create mode 100644 Thirdparty/Pangolin/src/geometry/geometry.cpp create mode 100644 Thirdparty/Pangolin/src/geometry/geometry_obj.cpp create mode 100644 Thirdparty/Pangolin/src/geometry/geometry_ply.cpp create mode 100644 Thirdparty/Pangolin/src/geometry/glgeometry.cpp create mode 100644 Thirdparty/Pangolin/src/geometry/tinyobj.cpp create mode 100644 Thirdparty/Pangolin/src/gl/compat/gl2engine.cpp create mode 100644 Thirdparty/Pangolin/src/gl/glchar.cpp create mode 100644 Thirdparty/Pangolin/src/gl/gldraw.cpp create mode 100644 Thirdparty/Pangolin/src/gl/glfont.cpp create mode 100644 Thirdparty/Pangolin/src/gl/glpangoglu.cpp create mode 100644 Thirdparty/Pangolin/src/gl/gltext.cpp create mode 100644 Thirdparty/Pangolin/src/gl/gltexturecache.cpp create mode 100644 Thirdparty/Pangolin/src/gl/stb_truetype.h create mode 100644 Thirdparty/Pangolin/src/handler/handler.cpp create mode 100644 Thirdparty/Pangolin/src/handler/handler_glbuffer.cpp create mode 100644 Thirdparty/Pangolin/src/handler/handler_image.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_exr.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_jpg.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_lz4.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_packed12bit.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_pango.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_png.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_ppm.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_raw.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_tga.cpp create mode 100644 Thirdparty/Pangolin/src/image/image_io_zstd.cpp create mode 100644 Thirdparty/Pangolin/src/image/pixel_format.cpp create mode 100644 Thirdparty/Pangolin/src/ios/PangolinAppDelegate.mm create mode 100644 Thirdparty/Pangolin/src/ios/PangolinUIView.mm create mode 100644 Thirdparty/Pangolin/src/log/packet.cpp create mode 100644 Thirdparty/Pangolin/src/log/packetstream.cpp create mode 100644 Thirdparty/Pangolin/src/log/packetstream_reader.cpp create mode 100644 Thirdparty/Pangolin/src/log/packetstream_writer.cpp create mode 100644 Thirdparty/Pangolin/src/log/playback_session.cpp create mode 100644 Thirdparty/Pangolin/src/plot/datalog.cpp create mode 100644 Thirdparty/Pangolin/src/plot/plotter.cpp create mode 100644 Thirdparty/Pangolin/src/python/pyinterpreter.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/attach.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/attach.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/colour.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/colour.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/datalog.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/datalog.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/display.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/display.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/gl.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/gl.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/gl_draw.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/gl_draw.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/glsl.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/glsl.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/handler.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/handler.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/image.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/image.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/image_view.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/image_view.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/opengl_render_state.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/opengl_render_state.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/params.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/params.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/pixel_format.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/pixel_format.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/plotter.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/plotter.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/pypangolin.h create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/var.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/var.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/video.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/video.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/view.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/view.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/viewport.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/viewport.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/widget.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/widget.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/window.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin/window.hpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin_init.cpp create mode 100644 Thirdparty/Pangolin/src/python/pypangolin_module.cpp create mode 100644 Thirdparty/Pangolin/src/tools/video_viewer.cpp create mode 100644 Thirdparty/Pangolin/src/utils/file_extension.cpp create mode 100644 Thirdparty/Pangolin/src/utils/file_utils.cpp create mode 100644 Thirdparty/Pangolin/src/utils/posix/condition_variable.cpp create mode 100644 Thirdparty/Pangolin/src/utils/posix/semaphore.cpp create mode 100644 Thirdparty/Pangolin/src/utils/posix/shared_memory_buffer.cpp create mode 100644 Thirdparty/Pangolin/src/utils/sigstate.cpp create mode 100644 Thirdparty/Pangolin/src/utils/threadedfilebuf.cpp create mode 100644 Thirdparty/Pangolin/src/utils/timer.cpp create mode 100644 Thirdparty/Pangolin/src/utils/uri.cpp create mode 100644 Thirdparty/Pangolin/src/var/input_record_repeat.cpp create mode 100644 Thirdparty/Pangolin/src/var/vars.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/debayer.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/deinterlace.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/depthsense.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/ffmpeg.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/firewire.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/images.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/images_out.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/join.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/json.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/merge.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/mirror.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/openni.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/openni2.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/pack.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/pango.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/pango_video_output.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/pleora.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/pvn.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/realsense.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/realsense2.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/shared_memory.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/shift.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/split.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/teli.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/test.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/thread.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/truncate.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/unpack.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/uvc.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/uvc_mediafoundation.cpp create mode 100644 Thirdparty/Pangolin/src/video/drivers/v4l.cpp create mode 100644 Thirdparty/Pangolin/src/video/stream_encoder_factory.cpp create mode 100644 Thirdparty/Pangolin/src/video/video.cpp create mode 100644 Thirdparty/Pangolin/src/video/video_input.cpp create mode 100644 Thirdparty/Pangolin/src/video/video_interface_factory.cpp create mode 100644 Thirdparty/Pangolin/src/video/video_output.cpp create mode 100644 Thirdparty/Pangolin/src/video/video_output_interface_factory.cpp create mode 100644 Thirdparty/Pangolin/test/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/test/log/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/test/log/testlog.cpp create mode 100644 Thirdparty/Pangolin/tools/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/tools/ModelViewer/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/tools/ModelViewer/main.cpp create mode 100644 Thirdparty/Pangolin/tools/ModelViewer/rendertree.h create mode 100644 Thirdparty/Pangolin/tools/ModelViewer/shader.h create mode 100644 Thirdparty/Pangolin/tools/ModelViewer/util.h create mode 100644 Thirdparty/Pangolin/tools/Plotter/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/tools/Plotter/application-x-pangoplot.xml create mode 100644 Thirdparty/Pangolin/tools/Plotter/csv_data_loader.h create mode 100644 Thirdparty/Pangolin/tools/Plotter/main.cpp create mode 100644 Thirdparty/Pangolin/tools/VideoConvert/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/tools/VideoConvert/main.cpp create mode 100644 Thirdparty/Pangolin/tools/VideoJson/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/tools/VideoJson/main-print.cpp create mode 100644 Thirdparty/Pangolin/tools/VideoJson/main-transform.cpp create mode 100644 Thirdparty/Pangolin/tools/VideoViewer/CMakeLists.txt create mode 100644 Thirdparty/Pangolin/tools/VideoViewer/application-x-pango.svg create mode 100644 Thirdparty/Pangolin/tools/VideoViewer/application-x-pango.xml create mode 100644 Thirdparty/Pangolin/tools/VideoViewer/main.cpp create mode 100644 Thirdparty/g2o/CMakeLists.txt create mode 100644 Thirdparty/g2o/README.txt create mode 100644 Thirdparty/g2o/config.h.in create mode 100644 Thirdparty/g2o/g2o/core/base_binary_edge.h create mode 100644 Thirdparty/g2o/g2o/core/base_binary_edge.hpp create mode 100644 Thirdparty/g2o/g2o/core/base_edge.h create mode 100644 Thirdparty/g2o/g2o/core/base_multi_edge.h create mode 100644 Thirdparty/g2o/g2o/core/base_multi_edge.hpp create mode 100644 Thirdparty/g2o/g2o/core/base_unary_edge.h create mode 100644 Thirdparty/g2o/g2o/core/base_unary_edge.hpp create mode 100644 Thirdparty/g2o/g2o/core/base_vertex.h create mode 100644 Thirdparty/g2o/g2o/core/base_vertex.hpp create mode 100644 Thirdparty/g2o/g2o/core/batch_stats.cpp create mode 100644 Thirdparty/g2o/g2o/core/batch_stats.h create mode 100644 Thirdparty/g2o/g2o/core/block_solver.h create mode 100644 Thirdparty/g2o/g2o/core/block_solver.hpp create mode 100644 Thirdparty/g2o/g2o/core/cache.cpp create mode 100644 Thirdparty/g2o/g2o/core/cache.h create mode 100644 Thirdparty/g2o/g2o/core/creators.h create mode 100644 Thirdparty/g2o/g2o/core/eigen_types.h create mode 100644 Thirdparty/g2o/g2o/core/estimate_propagator.cpp create mode 100644 Thirdparty/g2o/g2o/core/estimate_propagator.h create mode 100644 Thirdparty/g2o/g2o/core/factory.cpp create mode 100644 Thirdparty/g2o/g2o/core/factory.h create mode 100644 Thirdparty/g2o/g2o/core/hyper_dijkstra.cpp create mode 100644 Thirdparty/g2o/g2o/core/hyper_dijkstra.h create mode 100644 Thirdparty/g2o/g2o/core/hyper_graph.cpp create mode 100644 Thirdparty/g2o/g2o/core/hyper_graph.h create mode 100644 Thirdparty/g2o/g2o/core/hyper_graph_action.cpp create mode 100644 Thirdparty/g2o/g2o/core/hyper_graph_action.h create mode 100644 Thirdparty/g2o/g2o/core/jacobian_workspace.cpp create mode 100644 Thirdparty/g2o/g2o/core/jacobian_workspace.h create mode 100644 Thirdparty/g2o/g2o/core/linear_solver.h create mode 100644 Thirdparty/g2o/g2o/core/marginal_covariance_cholesky.cpp create mode 100644 Thirdparty/g2o/g2o/core/marginal_covariance_cholesky.h create mode 100644 Thirdparty/g2o/g2o/core/matrix_operations.h create mode 100644 Thirdparty/g2o/g2o/core/matrix_structure.cpp create mode 100644 Thirdparty/g2o/g2o/core/matrix_structure.h create mode 100644 Thirdparty/g2o/g2o/core/openmp_mutex.h create mode 100644 Thirdparty/g2o/g2o/core/optimizable_graph.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimizable_graph.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_dogleg.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_dogleg.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_factory.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_factory.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_gauss_newton.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_gauss_newton.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_levenberg.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_levenberg.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_property.h create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_with_hessian.cpp create mode 100644 Thirdparty/g2o/g2o/core/optimization_algorithm_with_hessian.h create mode 100644 Thirdparty/g2o/g2o/core/parameter.cpp create mode 100644 Thirdparty/g2o/g2o/core/parameter.h create mode 100644 Thirdparty/g2o/g2o/core/parameter_container.cpp create mode 100644 Thirdparty/g2o/g2o/core/parameter_container.h create mode 100644 Thirdparty/g2o/g2o/core/robust_kernel.cpp create mode 100644 Thirdparty/g2o/g2o/core/robust_kernel.h create mode 100644 Thirdparty/g2o/g2o/core/robust_kernel_factory.cpp create mode 100644 Thirdparty/g2o/g2o/core/robust_kernel_factory.h create mode 100644 Thirdparty/g2o/g2o/core/robust_kernel_impl.cpp create mode 100644 Thirdparty/g2o/g2o/core/robust_kernel_impl.h create mode 100644 Thirdparty/g2o/g2o/core/solver.cpp create mode 100644 Thirdparty/g2o/g2o/core/solver.h create mode 100644 Thirdparty/g2o/g2o/core/sparse_block_matrix.h create mode 100644 Thirdparty/g2o/g2o/core/sparse_block_matrix.hpp create mode 100644 Thirdparty/g2o/g2o/core/sparse_block_matrix_ccs.h create mode 100644 Thirdparty/g2o/g2o/core/sparse_block_matrix_diagonal.h create mode 100644 Thirdparty/g2o/g2o/core/sparse_block_matrix_test.cpp create mode 100644 Thirdparty/g2o/g2o/core/sparse_optimizer.cpp create mode 100644 Thirdparty/g2o/g2o/core/sparse_optimizer.h create mode 100644 Thirdparty/g2o/g2o/solvers/linear_solver_dense.h create mode 100644 Thirdparty/g2o/g2o/solvers/linear_solver_eigen.h create mode 100644 Thirdparty/g2o/g2o/stuff/color_macros.h create mode 100644 Thirdparty/g2o/g2o/stuff/macros.h create mode 100644 Thirdparty/g2o/g2o/stuff/misc.h create mode 100644 Thirdparty/g2o/g2o/stuff/os_specific.c create mode 100644 Thirdparty/g2o/g2o/stuff/os_specific.h create mode 100644 Thirdparty/g2o/g2o/stuff/property.cpp create mode 100644 Thirdparty/g2o/g2o/stuff/property.h create mode 100644 Thirdparty/g2o/g2o/stuff/string_tools.cpp create mode 100644 Thirdparty/g2o/g2o/stuff/string_tools.h create mode 100644 Thirdparty/g2o/g2o/stuff/timeutil.cpp create mode 100644 Thirdparty/g2o/g2o/stuff/timeutil.h create mode 100644 Thirdparty/g2o/g2o/types/se3_ops.h create mode 100644 Thirdparty/g2o/g2o/types/se3_ops.hpp create mode 100644 Thirdparty/g2o/g2o/types/se3mat.cpp create mode 100644 Thirdparty/g2o/g2o/types/se3mat.h create mode 100644 Thirdparty/g2o/g2o/types/se3quat.h create mode 100644 Thirdparty/g2o/g2o/types/sim3.h create mode 100644 Thirdparty/g2o/g2o/types/types_sba.cpp create mode 100644 Thirdparty/g2o/g2o/types/types_sba.h create mode 100644 Thirdparty/g2o/g2o/types/types_seven_dof_expmap.cpp create mode 100644 Thirdparty/g2o/g2o/types/types_seven_dof_expmap.h create mode 100644 Thirdparty/g2o/g2o/types/types_six_dof_expmap.cpp create mode 100644 Thirdparty/g2o/g2o/types/types_six_dof_expmap.h create mode 100644 Thirdparty/g2o/license-bsd.txt create mode 100644 build.sh create mode 100644 build_ros.sh create mode 100644 include/Atlas.h create mode 100644 include/CameraModels/GeometricCamera.h create mode 100644 include/CameraModels/KannalaBrandt8.h create mode 100644 include/CameraModels/Pinhole.h create mode 100644 include/Config.h create mode 100644 include/Converter.h create mode 100644 include/Frame.h create mode 100644 include/FrameDrawer.h create mode 100644 include/G2oTypes.h create mode 100644 include/ImuTypes.h create mode 100644 include/Initializer.h create mode 100644 include/KeyFrame.h create mode 100644 include/KeyFrameDatabase.h create mode 100644 include/LocalMapping.h create mode 100644 include/LoopClosing.h create mode 100644 include/MLPnPsolver.h create mode 100644 include/Map.h create mode 100644 include/MapDrawer.h create mode 100644 include/MapPoint.h create mode 100644 include/ORBVocabulary.h create mode 100644 include/ORBextractor.h create mode 100644 include/ORBmatcher.h create mode 100644 include/OptimizableTypes.h create mode 100644 include/Optimizer.h create mode 100644 include/PnPsolver.h create mode 100644 include/Sim3Solver.h create mode 100644 include/System.h create mode 100644 include/Tracking.h create mode 100644 include/TwoViewReconstruction.h create mode 100644 include/Viewer.h create mode 100644 include/getopt.c create mode 100644 include/getopt.h create mode 100644 include/unistd.h create mode 100644 src/Atlas.cc create mode 100644 src/CameraModels/KannalaBrandt8.cpp create mode 100644 src/CameraModels/Pinhole.cpp create mode 100644 src/Converter.cc create mode 100644 src/Frame.cc create mode 100644 src/FrameDrawer.cc create mode 100644 src/G2oTypes.cc create mode 100644 src/ImuTypes.cc create mode 100644 src/Initializer.cc create mode 100644 src/KeyFrame.cc create mode 100644 src/KeyFrameDatabase.cc create mode 100644 src/LocalMapping.cc create mode 100644 src/LoopClosing.cc create mode 100644 src/MLPnPsolver.cpp create mode 100644 src/Map.cc create mode 100644 src/MapDrawer.cc create mode 100644 src/MapPoint.cc create mode 100644 src/ORBextractor.cc create mode 100644 src/ORBmatcher.cc create mode 100644 src/OptimizableTypes.cpp create mode 100644 src/Optimizer.cc create mode 100644 src/PnPsolver.cc create mode 100644 src/Sim3Solver.cc create mode 100644 src/System.cc create mode 100644 src/Tracking.cc create mode 100644 src/TwoViewReconstruction.cc create mode 100644 src/Viewer.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e161f99 --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +CMakeLists.txt.user +CMakeLists_modified.txt + +Examples/ +evaluation/ + +Examples/RGB-D/rgbd_tum + +Examples/Monocular/mono_euroc +Examples/Monocular/mono_kitti +Examples/Monocular/mono_tum +Examples/Monocular/mono_tum_vi + +Examples/Stereo/stereo_euroc +Examples/Stereo/stereo_kitti +Examples/Stereo/stereo_tum_vi + +Examples/Monocular-Inertial/mono_inertial_euroc +Examples/Monocular-Inertial/mono_inertial_tum_vi + +Examples/Stereo-Inertial/stereo_inertial_euroc +Examples/Stereo-Inertial/stereo_inertial_tum_vi + +Examples/ROS/ORB_SLAM3/Mono +Examples/ROS/ORB_SLAM3/Mono_Inertial +Examples/ROS/ORB_SLAM3/MonoAR +Examples/ROS/ORB_SLAM3/RGBD +Examples/ROS/ORB_SLAM3/Stereo +Examples/ROS/ORB_SLAM3/Stereo_Inertial + +Examples/ROS/ORB_SLAM3/CMakeLists.txt.user +Examples/ROS/ORB_SLAM3/build/ + +KeyFrameTrajectory.txt +CameraTrajectory.txt +kf_*.txt +f_*.txt +Thirdparty/DBoW2/build/ +Thirdparty/DBoW2/lib/ +Thirdparty/g2o/build/ +Thirdparty/g2o/config.h +Thirdparty/g2o/lib/ + +Thirdparty/Pangolin/build/ +Thirdparty/Pangolin/vcpkg/ +Thirdparty/Pangolin/CMakeModules/ + +Vocabulary/ORBvoc.txt.tar.gz +build/ + +cmake_modules/ +cmake-build-debug/ + +*.pyc +*.osa diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..512e2aa --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,210 @@ +cmake_minimum_required(VERSION 2.8) +project(ORB_SLAM3) + +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Release) +ENDIF() + +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Release>") + +MESSAGE("Build type: " ${CMAKE_BUILD_TYPE}) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -march=native") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=native") + +# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-deprecated -O3 -march=native ") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-deprecated -O3 -march=native") + +# Check C++11 or C++0x support +if(MSVC) + message(MSVC_VERSION "Using MSVC, Skipping std=c++11 support...") +else() + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) + CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) + if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + add_definitions(-DCOMPILEDWITHC11) + message(STATUS "Using flag -std=c++11.") + elseif(COMPILER_SUPPORTS_CXX0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + add_definitions(-DCOMPILEDWITHC0X) + message(STATUS "Using flag -std=c++0x.") + else() + message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") + endif() +endif() + +LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules) + +set(OpenCV_DIR C:/OpenCV3/build) +set(Boost_INCLUDE_DIR C:/Users/ivan/Source/Repos/ORB-SLAM3forWindows/Thirdparty/boost_1_77_0/) +# set(Boost_LIB_DIR C:/Users/ivan/Source/Repos/ORB-SLAM3forWindows/Thirdparty/boost_1_77_0/stage/lib) + + +find_package(OpenCV 3.4.16) +if(NOT OpenCV_FOUND) + find_package(OpenCV 3.0 REQUIRED C:/OpenCV3/build/x64/vc15/lib) + if(NOT OpenCV_FOUND) + message(FATAL_ERROR "OpenCV > 3.0 not found.") + endif() +endif() + +MESSAGE("OPENCV VERSION:") +MESSAGE(${OpenCV_VERSION}) + +find_package(Eigen3 3.1.0 REQUIRED) +find_package(Pangolin REQUIRED) +find_package(Boost) +find_package(realsense2) + +include_directories( +${PROJECT_SOURCE_DIR} +${PROJECT_SOURCE_DIR}/include +${PROJECT_SOURCE_DIR}/include/CameraModels +${EIGEN3_INCLUDE_DIR} +${Pangolin_INCLUDE_DIRS} +${Boost_INCLUDE_DIR} +) + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) + +add_library(${PROJECT_NAME} SHARED +src/System.cc +src/Tracking.cc +src/LocalMapping.cc +src/LoopClosing.cc +src/ORBextractor.cc +src/ORBmatcher.cc +src/FrameDrawer.cc +src/Converter.cc +src/MapPoint.cc +src/KeyFrame.cc +src/Atlas.cc +src/Map.cc +src/MapDrawer.cc +src/Optimizer.cc +src/Frame.cc +src/KeyFrameDatabase.cc +src/Sim3Solver.cc +src/Initializer.cc +src/Viewer.cc +src/ImuTypes.cc +src/G2oTypes.cc +src/CameraModels/Pinhole.cpp +src/CameraModels/KannalaBrandt8.cpp +src/OptimizableTypes.cpp +src/MLPnPsolver.cpp +src/TwoViewReconstruction.cc +include/System.h +include/Tracking.h +include/LocalMapping.h +include/LoopClosing.h +include/ORBextractor.h +include/ORBmatcher.h +include/FrameDrawer.h +include/Converter.h +include/MapPoint.h +include/KeyFrame.h +include/Atlas.h +include/Map.h +include/MapDrawer.h +include/Optimizer.h +include/Frame.h +include/KeyFrameDatabase.h +include/Sim3Solver.h +include/Initializer.h +include/Viewer.h +include/ImuTypes.h +include/G2oTypes.h +include/CameraModels/GeometricCamera.h +include/CameraModels/Pinhole.h +include/CameraModels/KannalaBrandt8.h +include/OptimizableTypes.h +include/MLPnPsolver.h +include/TwoViewReconstruction.h +include/Config.h +) + +add_subdirectory(Thirdparty/g2o) + +target_link_libraries(${PROJECT_NAME} +${OpenCV_LIBS} +${EIGEN3_LIBS} +${Pangolin_LIBRARIES} +${Boost_LIBS} +${PROJECT_SOURCE_DIR}/Thirdparty/DBoW2/lib/libDBoW2.so +${PROJECT_SOURCE_DIR}/Thirdparty/g2o/lib/libg2o.so +-lboost_serialization +-lcrypto +) + + +### Build examples + +# RGB-D examples +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/RGB-D) + +add_executable(rgbd_tum +Examples/RGB-D/rgbd_tum.cc) +target_link_libraries(rgbd_tum ${PROJECT_NAME}) + + +# Stereo examples +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/Stereo) + +add_executable(stereo_kitti +Examples/Stereo/stereo_kitti.cc) +target_link_libraries(stereo_kitti ${PROJECT_NAME}) + +add_executable(stereo_euroc +Examples/Stereo/stereo_euroc.cc) +target_link_libraries(stereo_euroc ${PROJECT_NAME}) + +add_executable(stereo_tum_vi +Examples/Stereo/stereo_tum_vi.cc) +target_link_libraries(stereo_tum_vi ${PROJECT_NAME}) + +# Monocular examples +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/Monocular) + +add_executable(mono_tum +Examples/Monocular/mono_tum.cc) +target_link_libraries(mono_tum ${PROJECT_NAME}) + +add_executable(mono_kitti +Examples/Monocular/mono_kitti.cc) +target_link_libraries(mono_kitti ${PROJECT_NAME}) + +add_executable(mono_euroc +Examples/Monocular/mono_euroc.cc) +target_link_libraries(mono_euroc ${PROJECT_NAME}) + +add_executable(mono_tum_vi +Examples/Monocular/mono_tum_vi.cc) +target_link_libraries(mono_tum_vi ${PROJECT_NAME}) + +# Monocular-Inertial examples +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/Monocular-Inertial) + +add_executable(mono_inertial_euroc +Examples/Monocular-Inertial/mono_inertial_euroc.cc) +target_link_libraries(mono_inertial_euroc ${PROJECT_NAME}) + +add_executable(mono_inertial_tum_vi +Examples/Monocular-Inertial/mono_inertial_tum_vi.cc) +target_link_libraries(mono_inertial_tum_vi ${PROJECT_NAME}) + +# Stereo-Inertial examples +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/Stereo-Inertial) + +add_executable(stereo_inertial_euroc +Examples/Stereo-Inertial/stereo_inertial_euroc.cc) +target_link_libraries(stereo_inertial_euroc ${PROJECT_NAME}) + +add_executable(stereo_inertial_tum_vi +Examples/Stereo-Inertial/stereo_inertial_tum_vi.cc) +target_link_libraries(stereo_inertial_tum_vi ${PROJECT_NAME}) + diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..ecdffc4 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,37 @@ +# ORB-SLAM3 +Details of changes between the different versions. + +### V0.4: Beta version, 21 April 2021 + +- Changed OpenCV dynamic matrices to static matrices to speed up the code. + +- Capability to measure running time of the system threads. + +- Compatibility with OpenCV 4.0 (Requires at least OpenCV 3.0) + +- Fixed minor bugs. + + +### V0.3: Beta version, 4 Sep 2020 + +- RGB-D compatibility, the RGB-D examples have been adapted to the new version. + +- Kitti and TUM dataset compatibility, these examples have been adapted to the new version. + +- ROS compatibility, updated the old references in the code to work with this version. + +- Config file parser, the YAML file contains the session configuration, a wrong parametrization may break the execution without any information to solve it. This version parses the file to read all the fields and give a proper answer if one of the fields have been wrongly deffined or does not exist. + +- Fixed minor bugs. + + +### V0.2: Beta version, 7 Aug 2020 +Initial release. It has these capabilities: + +- Multiple-Maps capabilities, it is able to handle multiple maps in the same session and merge them when a common area is detected with a seamless fussion. + +- Inertial sensor, the IMU initialization takes 2 seconds to achieve a scale error less than 5\% and it is reffined in the next 10 seconds until it is around 1\%. Inertial measures are integrated at frame rate to estimate the scale, gravity and velocity in order to improve the visual features detection and make the system robust to temporal occlusions. + +- Fisheye sensor, the fisheye sensors are now fully supported in monocular and stereo. + + diff --git a/Dependencies.md b/Dependencies.md new file mode 100644 index 0000000..c194d26 --- /dev/null +++ b/Dependencies.md @@ -0,0 +1,48 @@ +##List of Known Dependencies +###ORB-SLAM3 version 0.3 + +In this document we list all the pieces of code included by ORB-SLAM3 and linked libraries which are not property of the authors of ORB-SLAM3. + + +#####Code in **src** and **include** folders + +* *ORBextractor.cc*. +This is a modified version of orb.cpp of OpenCV library. The original code is BSD licensed. + +* *PnPsolver.h, PnPsolver.cc*. +This is a modified version of the epnp.h and epnp.cc of Vincent Lepetit. +This code can be found in popular BSD licensed computer vision libraries as [OpenCV](https://github.com/Itseez/opencv/blob/master/modules/calib3d/src/epnp.cpp) and [OpenGV](https://github.com/laurentkneip/opengv/blob/master/src/absolute_pose/modules/Epnp.cpp). The original code is FreeBSD. + +* *MLPnPsolver.h, MLPnPsolver.cc*. +This is a modified version of the MLPnP of Steffen Urban from [here](https://github.com/urbste/opengv). +The original code is BSD licensed. + +* Function *ORBmatcher::DescriptorDistance* in *ORBmatcher.cc*. +The code is from: http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel. +The code is in the public domain. + +#####Code in Thirdparty folder + +* All code in **DBoW2** folder. +This is a modified version of [DBoW2](https://github.com/dorian3d/DBoW2) and [DLib](https://github.com/dorian3d/DLib) library. All files included are BSD licensed. + +* All code in **g2o** folder. +This is a modified version of [g2o](https://github.com/RainerKuemmerle/g2o). All files included are BSD licensed. + +#####Library dependencies + +* **Pangolin (visualization and user interface)**. +[MIT license](https://en.wikipedia.org/wiki/MIT_License). + +* **OpenCV**. +BSD license. + +* **Eigen3**. +For versions greater than 3.1.1 is MPL2, earlier versions are LGPLv3. + +* **ROS (Optional, only if you build Examples/ROS)**. +BSD license. In the manifest.xml the only declared package dependencies are roscpp, tf, sensor_msgs, image_transport, cv_bridge, which are all BSD licensed. + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6753219 --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +# ORB-SLAM3 + +### V0.4: Beta version, 21 April 2021 +**Authors:** Carlos Campos, Richard Elvira, Juan J. Gómez Rodríguez, [José M. M. Montiel](http://webdiis.unizar.es/~josemari/), [Juan D. Tardos](http://webdiis.unizar.es/~jdtardos/). + +The [Changelog](https://github.com/UZ-SLAMLab/ORB_SLAM3/blob/master/Changelog.md) describes the features of each version. + +ORB-SLAM3 is the first real-time SLAM library able to perform **Visual, Visual-Inertial and Multi-Map SLAM** with **monocular, stereo and RGB-D** cameras, using **pin-hole and fisheye** lens models. In all sensor configurations, ORB-SLAM3 is as robust as the best systems available in the literature, and significantly more accurate. + +We provide examples to run ORB-SLAM3 in the [EuRoC dataset](http://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets) using stereo or monocular, with or without IMU, and in the [TUM-VI dataset](https://vision.in.tum.de/data/datasets/visual-inertial-dataset) using fisheye stereo or monocular, with or without IMU. Videos of some example executions can be found at [ORB-SLAM3 channel](https://www.youtube.com/channel/UCXVt-kXG6T95Z4tVaYlU80Q). + +This software is based on [ORB-SLAM2](https://github.com/raulmur/ORB_SLAM2) developed by [Raul Mur-Artal](http://webdiis.unizar.es/~raulmur/), [Juan D. Tardos](http://webdiis.unizar.es/~jdtardos/), [J. M. M. Montiel](http://webdiis.unizar.es/~josemari/) and [Dorian Galvez-Lopez](http://doriangalvez.com/) ([DBoW2](https://github.com/dorian3d/DBoW2)). + + + +### Related Publications: + +[ORB-SLAM3] Carlos Campos, Richard Elvira, Juan J. Gómez Rodríguez, José M. M. Montiel and Juan D. Tardós, **ORB-SLAM3: An Accurate Open-Source Library for Visual, Visual-Inertial and Multi-Map SLAM**, *IEEE Transactions on Robotics, 2021* **[PDF](https://arxiv.org/abs/2007.11898)**. + +[IMU-Initialization] Carlos Campos, J. M. M. Montiel and Juan D. Tardós, **Inertial-Only Optimization for Visual-Inertial Initialization**, *ICRA 2020*. **[PDF](https://arxiv.org/pdf/2003.05766.pdf)** + +[ORBSLAM-Atlas] Richard Elvira, J. M. M. Montiel and Juan D. Tardós, **ORBSLAM-Atlas: a robust and accurate multi-map system**, *IROS 2019*. **[PDF](https://arxiv.org/pdf/1908.11585.pdf)**. + +[ORBSLAM-VI] Raúl Mur-Artal, and Juan D. Tardós, **Visual-inertial monocular SLAM with map reuse**, IEEE Robotics and Automation Letters, vol. 2 no. 2, pp. 796-803, 2017. **[PDF](https://arxiv.org/pdf/1610.05949.pdf)**. + +[Stereo and RGB-D] Raúl Mur-Artal and Juan D. Tardós. **ORB-SLAM2: an Open-Source SLAM System for Monocular, Stereo and RGB-D Cameras**. *IEEE Transactions on Robotics,* vol. 33, no. 5, pp. 1255-1262, 2017. **[PDF](https://arxiv.org/pdf/1610.06475.pdf)**. + +[Monocular] Raúl Mur-Artal, José M. M. Montiel and Juan D. Tardós. **ORB-SLAM: A Versatile and Accurate Monocular SLAM System**. *IEEE Transactions on Robotics,* vol. 31, no. 5, pp. 1147-1163, 2015. (**2015 IEEE Transactions on Robotics Best Paper Award**). **[PDF](https://arxiv.org/pdf/1502.00956.pdf)**. + +[DBoW2 Place Recognition] Dorian Gálvez-López and Juan D. Tardós. **Bags of Binary Words for Fast Place Recognition in Image Sequences**. *IEEE Transactions on Robotics,* vol. 28, no. 5, pp. 1188-1197, 2012. **[PDF](http://doriangalvez.com/php/dl.php?dlp=GalvezTRO12.pdf)** + +# 1. License + +ORB-SLAM3 is released under [GPLv3 license](https://github.com/UZ-SLAMLab/ORB_SLAM3/LICENSE). For a list of all code/library dependencies (and associated licenses), please see [Dependencies.md](https://github.com/UZ-SLAMLab/ORB_SLAM3/blob/master/Dependencies.md). + +For a closed-source version of ORB-SLAM3 for commercial purposes, please contact the authors: orbslam (at) unizar (dot) es. + +If you use ORB-SLAM3 in an academic work, please cite: + + @article{ORBSLAM3_2020, + title={{ORB-SLAM3}: An Accurate Open-Source Library for Visual, Visual-Inertial + and Multi-Map {SLAM}}, + author={Campos, Carlos AND Elvira, Richard AND G\´omez, Juan J. AND Montiel, + Jos\'e M. M. AND Tard\'os, Juan D.}, + journal={arXiv preprint arXiv:2007.11898}, + year={2020} + } + +# 2. Prerequisites +We have tested the library in **Ubuntu 16.04** and **18.04**, but it should be easy to compile in other platforms. A powerful computer (e.g. i7) will ensure real-time performance and provide more stable and accurate results. + +## C++11 or C++0x Compiler +We use the new thread and chrono functionalities of C++11. + +## Pangolin +We use [Pangolin](https://github.com/stevenlovegrove/Pangolin) for visualization and user interface. Dowload and install instructions can be found at: https://github.com/stevenlovegrove/Pangolin. + +## OpenCV +We use [OpenCV](http://opencv.org) to manipulate images and features. Dowload and install instructions can be found at: http://opencv.org. **Required at leat 3.0. Tested with OpenCV 3.2.0 and 4.4.0**. + +## Eigen3 +Required by g2o (see below). Download and install instructions can be found at: http://eigen.tuxfamily.org. **Required at least 3.1.0**. + +## DBoW2 and g2o (Included in Thirdparty folder) +We use modified versions of the [DBoW2](https://github.com/dorian3d/DBoW2) library to perform place recognition and [g2o](https://github.com/RainerKuemmerle/g2o) library to perform non-linear optimizations. Both modified libraries (which are BSD) are included in the *Thirdparty* folder. + +## Python +Required to calculate the alignment of the trajectory with the ground truth. **Required Numpy module**. + +* (win) http://www.python.org/downloads/windows +* (deb) `sudo apt install libpython2.7-dev` +* (mac) preinstalled with osx + +## ROS (optional) + +We provide some examples to process input of a monocular, monocular-inertial, stereo, stereo-inertial or RGB-D camera using ROS. Building these examples is optional. These have been tested with ROS Melodic under Ubuntu 18.04. + +# 3. Building ORB-SLAM3 library and examples + +Clone the repository: +``` +git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git ORB_SLAM3 +``` + +We provide a script `build.sh` to build the *Thirdparty* libraries and *ORB-SLAM3*. Please make sure you have installed all required dependencies (see section 2). Execute: +``` +cd ORB_SLAM3 +chmod +x build.sh +./build.sh +``` + +This will create **libORB_SLAM3.so** at *lib* folder and the executables in *Examples* folder. + +# 4. EuRoC Examples +[EuRoC dataset](http://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets) was recorded with two pinhole cameras and an inertial sensor. We provide an example script to launch EuRoC sequences in all the sensor configurations. + +1. Download a sequence (ASL format) from http://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets + +2. Open the script "euroc_examples.sh" in the root of the project. Change **pathDatasetEuroc** variable to point to the directory where the dataset has been uncompressed. + +3. Execute the following script to process all the sequences with all sensor configurations: +``` +./euroc_examples +``` + +## Evaluation +EuRoC provides ground truth for each sequence in the IMU body reference. As pure visual executions report trajectories centered in the left camera, we provide in the "evaluation" folder the transformation of the ground truth to the left camera reference. Visual-inertial trajectories use the ground truth from the dataset. + +Execute the following script to process sequences and compute the RMS ATE: +``` +./euroc_eval_examples +``` + +# 5. TUM-VI Examples +[TUM-VI dataset](https://vision.in.tum.de/data/datasets/visual-inertial-dataset) was recorded with two fisheye cameras and an inertial sensor. + +1. Download a sequence from https://vision.in.tum.de/data/datasets/visual-inertial-dataset and uncompress it. + +2. Open the script "tum_vi_examples.sh" in the root of the project. Change **pathDatasetTUM_VI** variable to point to the directory where the dataset has been uncompressed. + +3. Execute the following script to process all the sequences with all sensor configurations: +``` +./tum_vi_examples +``` + +## Evaluation +In TUM-VI ground truth is only available in the room where all sequences start and end. As a result the error measures the drift at the end of the sequence. + +Execute the following script to process sequences and compute the RMS ATE: +``` +./tum_vi_eval_examples +``` + +# 6. ROS Examples + +### Building the nodes for mono, mono-inertial, stereo, stereo-inertial and RGB-D +Tested with ROS Melodic and ubuntu 18.04. + +1. Add the path including *Examples/ROS/ORB_SLAM3* to the ROS_PACKAGE_PATH environment variable. Open .bashrc file: + ``` + gedit ~/.bashrc + ``` +and add at the end the following line. Replace PATH by the folder where you cloned ORB_SLAM3: + + ``` + export ROS_PACKAGE_PATH=${ROS_PACKAGE_PATH}:PATH/ORB_SLAM3/Examples/ROS + ``` + +2. Execute `build_ros.sh` script: + + ``` + chmod +x build_ros.sh + ./build_ros.sh + ``` + +### Running Monocular Node +For a monocular input from topic `/camera/image_raw` run node ORB_SLAM3/Mono. You will need to provide the vocabulary file and a settings file. See the monocular examples above. + + ``` + rosrun ORB_SLAM3 Mono PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE + ``` + +### Running Monocular-Inertial Node +For a monocular input from topic `/camera/image_raw` and an inertial input from topic `/imu`, run node ORB_SLAM3/Mono_Inertial. Setting the optional third argument to true will apply CLAHE equalization to images (Mainly for TUM-VI dataset). + + ``` + rosrun ORB_SLAM3 Mono PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE [EQUALIZATION] + ``` + +### Running Stereo Node +For a stereo input from topic `/camera/left/image_raw` and `/camera/right/image_raw` run node ORB_SLAM3/Stereo. You will need to provide the vocabulary file and a settings file. For Pinhole camera model, if you **provide rectification matrices** (see Examples/Stereo/EuRoC.yaml example), the node will recitify the images online, **otherwise images must be pre-rectified**. For FishEye camera model, rectification is not required since system works with original images: + + ``` + rosrun ORB_SLAM3 Stereo PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE ONLINE_RECTIFICATION + ``` + +### Running Stereo-Inertial Node +For a stereo input from topics `/camera/left/image_raw` and `/camera/right/image_raw`, and an inertial input from topic `/imu`, run node ORB_SLAM3/Stereo_Inertial. You will need to provide the vocabulary file and a settings file, including rectification matrices if required in a similar way to Stereo case: + + ``` + rosrun ORB_SLAM3 Stereo_Inertial PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE ONLINE_RECTIFICATION [EQUALIZATION] + ``` + +### Running RGB_D Node +For an RGB-D input from topics `/camera/rgb/image_raw` and `/camera/depth_registered/image_raw`, run node ORB_SLAM3/RGBD. You will need to provide the vocabulary file and a settings file. See the RGB-D example above. + + ``` + rosrun ORB_SLAM3 RGBD PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE + ``` + +**Running ROS example:** Download a rosbag (e.g. V1_02_medium.bag) from the EuRoC dataset (http://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets). Open 3 tabs on the terminal and run the following command at each tab for a Stereo-Inertial configuration: + ``` + roscore + ``` + + ``` + rosrun ORB_SLAM3 Stereo_Inertial Vocabulary/ORBvoc.txt Examples/Stereo-Inertial/EuRoC.yaml true + ``` + + ``` + rosbag play --pause V1_02_medium.bag /cam0/image_raw:=/camera/left/image_raw /cam1/image_raw:=/camera/right/image_raw /imu0:=/imu + ``` + +Once ORB-SLAM3 has loaded the vocabulary, press space in the rosbag tab. + +**Remark:** For rosbags from TUM-VI dataset, some play issue may appear due to chunk size. One possible solution is to rebag them with the default chunk size, for example: + ``` + rosrun rosbag fastrebag.py dataset-room1_512_16.bag dataset-room1_512_16_small_chunks.bag + ``` + +# 7. Running time analysis +A flag in `include\Config.h` activates time measurements. It is necessary to uncomment the line `#define REGISTER_TIMES` to obtain the time stats of one execution which is shown at the terminal and stored in a text file(`ExecTimeMean.txt`). + diff --git a/Thirdparty/DBoW2/CMakeLists.txt b/Thirdparty/DBoW2/CMakeLists.txt new file mode 100644 index 0000000..c561724 --- /dev/null +++ b/Thirdparty/DBoW2/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 2.8) +project(DBoW2) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native ") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native") + +set(HDRS_DBOW2 + DBoW2/BowVector.h + DBoW2/FORB.h + DBoW2/FClass.h + DBoW2/FeatureVector.h + DBoW2/ScoringObject.h + DBoW2/TemplatedVocabulary.h) +set(SRCS_DBOW2 + DBoW2/BowVector.cpp + DBoW2/FORB.cpp + DBoW2/FeatureVector.cpp + DBoW2/ScoringObject.cpp) + +set(HDRS_DUTILS + DUtils/Random.h + DUtils/Timestamp.h) +set(SRCS_DUTILS + DUtils/Random.cpp + DUtils/Timestamp.cpp) + +find_package(OpenCV 4.0 QUIET) +if(NOT OpenCV_FOUND) + find_package(OpenCV 3.0 QUIET) + if(NOT OpenCV_FOUND) + message(FATAL_ERROR "OpenCV > 3.0 not found.") + endif() +endif() + +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) + +include_directories(${OpenCV_INCLUDE_DIRS}) +add_library(DBoW2 SHARED ${SRCS_DBOW2} ${SRCS_DUTILS}) +target_link_libraries(DBoW2 ${OpenCV_LIBS}) + diff --git a/Thirdparty/DBoW2/DBoW2/BowVector.cpp b/Thirdparty/DBoW2/DBoW2/BowVector.cpp new file mode 100644 index 0000000..1337fa3 --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/BowVector.cpp @@ -0,0 +1,130 @@ +/** + * File: BowVector.cpp + * Date: March 2011 + * Author: Dorian Galvez-Lopez + * Description: bag of words vector + * License: see the LICENSE.txt file + * + */ + +#include +#include +#include +#include +#include + +#include "BowVector.h" + +namespace DBoW2 { + +// -------------------------------------------------------------------------- + +BowVector::BowVector(void) +{ +} + +// -------------------------------------------------------------------------- + +BowVector::~BowVector(void) +{ +} + +// -------------------------------------------------------------------------- + +void BowVector::addWeight(WordId id, WordValue v) +{ + BowVector::iterator vit = this->lower_bound(id); + + if(vit != this->end() && !(this->key_comp()(id, vit->first))) + { + vit->second += v; + } + else + { + this->insert(vit, BowVector::value_type(id, v)); + } +} + +// -------------------------------------------------------------------------- + +void BowVector::addIfNotExist(WordId id, WordValue v) +{ + BowVector::iterator vit = this->lower_bound(id); + + if(vit == this->end() || (this->key_comp()(id, vit->first))) + { + this->insert(vit, BowVector::value_type(id, v)); + } +} + +// -------------------------------------------------------------------------- + +void BowVector::normalize(LNorm norm_type) +{ + double norm = 0.0; + BowVector::iterator it; + + if(norm_type == DBoW2::L1) + { + for(it = begin(); it != end(); ++it) + norm += fabs(it->second); + } + else + { + for(it = begin(); it != end(); ++it) + norm += it->second * it->second; + norm = sqrt(norm); + } + + if(norm > 0.0) + { + for(it = begin(); it != end(); ++it) + it->second /= norm; + } +} + +// -------------------------------------------------------------------------- + +std::ostream& operator<< (std::ostream &out, const BowVector &v) +{ + BowVector::const_iterator vit; + std::vector::const_iterator iit; + unsigned int i = 0; + const unsigned int N = v.size(); + for(vit = v.begin(); vit != v.end(); ++vit, ++i) + { + out << "<" << vit->first << ", " << vit->second << ">"; + + if(i < N-1) out << ", "; + } + return out; +} + +// -------------------------------------------------------------------------- + +void BowVector::saveM(const std::string &filename, size_t W) const +{ + std::fstream f(filename.c_str(), std::ios::out); + + WordId last = 0; + BowVector::const_iterator bit; + for(bit = this->begin(); bit != this->end(); ++bit) + { + for(; last < bit->first; ++last) + { + f << "0 "; + } + f << bit->second << " "; + + last = bit->first + 1; + } + for(; last < (WordId)W; ++last) + f << "0 "; + + f.close(); +} + +// -------------------------------------------------------------------------- + +} // namespace DBoW2 + diff --git a/Thirdparty/DBoW2/DBoW2/BowVector.h b/Thirdparty/DBoW2/DBoW2/BowVector.h new file mode 100644 index 0000000..a7a12a9 --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/BowVector.h @@ -0,0 +1,119 @@ +/** + * File: BowVector.h + * Date: March 2011 + * Author: Dorian Galvez-Lopez + * Description: bag of words vector + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_T_BOW_VECTOR__ +#define __D_T_BOW_VECTOR__ + +#include +#include +#include + +#include +#include + +namespace DBoW2 { + +/// Id of words +typedef unsigned int WordId; + +/// Value of a word +typedef double WordValue; + +/// Id of nodes in the vocabulary treee +typedef unsigned int NodeId; + +/// L-norms for normalization +enum LNorm +{ + L1, + L2 +}; + +/// Weighting type +enum WeightingType +{ + TF_IDF, + TF, + IDF, + BINARY +}; + +/// Scoring type +enum ScoringType +{ + L1_NORM, + L2_NORM, + CHI_SQUARE, + KL, + BHATTACHARYYA, + DOT_PRODUCT, +}; + +/// Vector of words to represent images +class BowVector: + public std::map +{ + friend class boost::serialization::access; + template + void serialize(Archive& ar, const int version) + { + ar & boost::serialization::base_object >(*this); + } + +public: + + /** + * Constructor + */ + BowVector(void); + + /** + * Destructor + */ + ~BowVector(void); + + /** + * Adds a value to a word value existing in the vector, or creates a new + * word with the given value + * @param id word id to look for + * @param v value to create the word with, or to add to existing word + */ + void addWeight(WordId id, WordValue v); + + /** + * Adds a word with a value to the vector only if this does not exist yet + * @param id word id to look for + * @param v value to give to the word if this does not exist + */ + void addIfNotExist(WordId id, WordValue v); + + /** + * L1-Normalizes the values in the vector + * @param norm_type norm used + */ + void normalize(LNorm norm_type); + + /** + * Prints the content of the bow vector + * @param out stream + * @param v + */ + friend std::ostream& operator<<(std::ostream &out, const BowVector &v); + + /** + * Saves the bow vector as a vector in a matlab file + * @param filename + * @param W number of words in the vocabulary + */ + void saveM(const std::string &filename, size_t W) const; +}; + +} // namespace DBoW2 + +#endif diff --git a/Thirdparty/DBoW2/DBoW2/FClass.h b/Thirdparty/DBoW2/DBoW2/FClass.h new file mode 100644 index 0000000..13be53d --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/FClass.h @@ -0,0 +1,71 @@ +/** + * File: FClass.h + * Date: November 2011 + * Author: Dorian Galvez-Lopez + * Description: generic FClass to instantiate templated classes + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_T_FCLASS__ +#define __D_T_FCLASS__ + +#include +#include +#include + +namespace DBoW2 { + +/// Generic class to encapsulate functions to manage descriptors. +/** + * This class must be inherited. Derived classes can be used as the + * parameter F when creating Templated structures + * (TemplatedVocabulary, TemplatedDatabase, ...) + */ +class FClass +{ + class TDescriptor; + typedef const TDescriptor *pDescriptor; + + /** + * Calculates the mean value of a set of descriptors + * @param descriptors + * @param mean mean descriptor + */ + virtual void meanValue(const std::vector &descriptors, + TDescriptor &mean) = 0; + + /** + * Calculates the distance between two descriptors + * @param a + * @param b + * @return distance + */ + static double distance(const TDescriptor &a, const TDescriptor &b); + + /** + * Returns a string version of the descriptor + * @param a descriptor + * @return string version + */ + static std::string toString(const TDescriptor &a); + + /** + * Returns a descriptor from a string + * @param a descriptor + * @param s string version + */ + static void fromString(TDescriptor &a, const std::string &s); + + /** + * Returns a mat with the descriptors in float format + * @param descriptors + * @param mat (out) NxL 32F matrix + */ + static void toMat32F(const std::vector &descriptors, + cv::Mat &mat); +}; + +} // namespace DBoW2 + +#endif diff --git a/Thirdparty/DBoW2/DBoW2/FORB.cpp b/Thirdparty/DBoW2/DBoW2/FORB.cpp new file mode 100644 index 0000000..80bf473 --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/FORB.cpp @@ -0,0 +1,193 @@ +/** + * File: FORB.cpp + * Date: June 2012 + * Author: Dorian Galvez-Lopez + * Description: functions for ORB descriptors + * License: see the LICENSE.txt file + * + * Distance function has been modified + * + */ + + +#include +#include +#include +#include + +#include "FORB.h" + +using namespace std; + +namespace DBoW2 { + +// -------------------------------------------------------------------------- + +const int FORB::L=32; + +void FORB::meanValue(const std::vector &descriptors, + FORB::TDescriptor &mean) +{ + if(descriptors.empty()) + { + mean.release(); + return; + } + else if(descriptors.size() == 1) + { + mean = descriptors[0]->clone(); + } + else + { + vector sum(FORB::L * 8, 0); + + for(size_t i = 0; i < descriptors.size(); ++i) + { + const cv::Mat &d = *descriptors[i]; + const unsigned char *p = d.ptr(); + + for(int j = 0; j < d.cols; ++j, ++p) + { + if(*p & (1 << 7)) ++sum[ j*8 ]; + if(*p & (1 << 6)) ++sum[ j*8 + 1 ]; + if(*p & (1 << 5)) ++sum[ j*8 + 2 ]; + if(*p & (1 << 4)) ++sum[ j*8 + 3 ]; + if(*p & (1 << 3)) ++sum[ j*8 + 4 ]; + if(*p & (1 << 2)) ++sum[ j*8 + 5 ]; + if(*p & (1 << 1)) ++sum[ j*8 + 6 ]; + if(*p & (1)) ++sum[ j*8 + 7 ]; + } + } + + mean = cv::Mat::zeros(1, FORB::L, CV_8U); + unsigned char *p = mean.ptr(); + + const int N2 = (int)descriptors.size() / 2 + descriptors.size() % 2; + for(size_t i = 0; i < sum.size(); ++i) + { + if(sum[i] >= N2) + { + // set bit + *p |= 1 << (7 - (i % 8)); + } + + if(i % 8 == 7) ++p; + } + } +} + +// -------------------------------------------------------------------------- + +int FORB::distance(const FORB::TDescriptor &a, + const FORB::TDescriptor &b) +{ + // Bit set count operation from + // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + + const int *pa = a.ptr(); + const int *pb = b.ptr(); + + int dist=0; + + for(int i=0; i<8; i++, pa++, pb++) + { + unsigned int v = *pa ^ *pb; + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + dist += (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; + } + + return dist; +} + +// -------------------------------------------------------------------------- + +std::string FORB::toString(const FORB::TDescriptor &a) +{ + stringstream ss; + const unsigned char *p = a.ptr(); + + for(int i = 0; i < a.cols; ++i, ++p) + { + ss << (int)*p << " "; + } + + return ss.str(); +} + +// -------------------------------------------------------------------------- + +void FORB::fromString(FORB::TDescriptor &a, const std::string &s) +{ + a.create(1, FORB::L, CV_8U); + unsigned char *p = a.ptr(); + + stringstream ss(s); + for(int i = 0; i < FORB::L; ++i, ++p) + { + int n; + ss >> n; + + if(!ss.fail()) + *p = (unsigned char)n; + } + +} + +// -------------------------------------------------------------------------- + +void FORB::toMat32F(const std::vector &descriptors, + cv::Mat &mat) +{ + if(descriptors.empty()) + { + mat.release(); + return; + } + + const size_t N = descriptors.size(); + + mat.create(N, FORB::L*8, CV_32F); + float *p = mat.ptr(); + + for(size_t i = 0; i < N; ++i) + { + const int C = descriptors[i].cols; + const unsigned char *desc = descriptors[i].ptr(); + + for(int j = 0; j < C; ++j, p += 8) + { + p[0] = (desc[j] & (1 << 7) ? 1 : 0); + p[1] = (desc[j] & (1 << 6) ? 1 : 0); + p[2] = (desc[j] & (1 << 5) ? 1 : 0); + p[3] = (desc[j] & (1 << 4) ? 1 : 0); + p[4] = (desc[j] & (1 << 3) ? 1 : 0); + p[5] = (desc[j] & (1 << 2) ? 1 : 0); + p[6] = (desc[j] & (1 << 1) ? 1 : 0); + p[7] = desc[j] & (1); + } + } +} + +// -------------------------------------------------------------------------- + +void FORB::toMat8U(const std::vector &descriptors, + cv::Mat &mat) +{ + mat.create(descriptors.size(), 32, CV_8U); + + unsigned char *p = mat.ptr(); + + for(size_t i = 0; i < descriptors.size(); ++i, p += 32) + { + const unsigned char *d = descriptors[i].ptr(); + std::copy(d, d+32, p); + } + +} + +// -------------------------------------------------------------------------- + +} // namespace DBoW2 + + diff --git a/Thirdparty/DBoW2/DBoW2/FORB.h b/Thirdparty/DBoW2/DBoW2/FORB.h new file mode 100644 index 0000000..a39599f --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/FORB.h @@ -0,0 +1,79 @@ +/** + * File: FORB.h + * Date: June 2012 + * Author: Dorian Galvez-Lopez + * Description: functions for ORB descriptors + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_T_F_ORB__ +#define __D_T_F_ORB__ + +#include +#include +#include + +#include "FClass.h" + +namespace DBoW2 { + +/// Functions to manipulate ORB descriptors +class FORB: protected FClass +{ +public: + + /// Descriptor type + typedef cv::Mat TDescriptor; // CV_8U + /// Pointer to a single descriptor + typedef const TDescriptor *pDescriptor; + /// Descriptor length (in bytes) + static const int L; + + /** + * Calculates the mean value of a set of descriptors + * @param descriptors + * @param mean mean descriptor + */ + static void meanValue(const std::vector &descriptors, + TDescriptor &mean); + + /** + * Calculates the distance between two descriptors + * @param a + * @param b + * @return distance + */ + static int distance(const TDescriptor &a, const TDescriptor &b); + + /** + * Returns a string version of the descriptor + * @param a descriptor + * @return string version + */ + static std::string toString(const TDescriptor &a); + + /** + * Returns a descriptor from a string + * @param a descriptor + * @param s string version + */ + static void fromString(TDescriptor &a, const std::string &s); + + /** + * Returns a mat with the descriptors in float format + * @param descriptors + * @param mat (out) NxL 32F matrix + */ + static void toMat32F(const std::vector &descriptors, + cv::Mat &mat); + + static void toMat8U(const std::vector &descriptors, + cv::Mat &mat); + +}; + +} // namespace DBoW2 + +#endif + diff --git a/Thirdparty/DBoW2/DBoW2/FeatureVector.cpp b/Thirdparty/DBoW2/DBoW2/FeatureVector.cpp new file mode 100644 index 0000000..c055a15 --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/FeatureVector.cpp @@ -0,0 +1,85 @@ +/** + * File: FeatureVector.cpp + * Date: November 2011 + * Author: Dorian Galvez-Lopez + * Description: feature vector + * License: see the LICENSE.txt file + * + */ + +#include "FeatureVector.h" +#include +#include +#include + +namespace DBoW2 { + +// --------------------------------------------------------------------------- + +FeatureVector::FeatureVector(void) +{ +} + +// --------------------------------------------------------------------------- + +FeatureVector::~FeatureVector(void) +{ +} + +// --------------------------------------------------------------------------- + +void FeatureVector::addFeature(NodeId id, unsigned int i_feature) +{ + FeatureVector::iterator vit = this->lower_bound(id); + + if(vit != this->end() && vit->first == id) + { + vit->second.push_back(i_feature); + } + else + { + vit = this->insert(vit, FeatureVector::value_type(id, + std::vector() )); + vit->second.push_back(i_feature); + } +} + +// --------------------------------------------------------------------------- + +std::ostream& operator<<(std::ostream &out, + const FeatureVector &v) +{ + if(!v.empty()) + { + FeatureVector::const_iterator vit = v.begin(); + + const std::vector* f = &vit->second; + + out << "<" << vit->first << ": ["; + if(!f->empty()) out << (*f)[0]; + for(unsigned int i = 1; i < f->size(); ++i) + { + out << ", " << (*f)[i]; + } + out << "]>"; + + for(++vit; vit != v.end(); ++vit) + { + f = &vit->second; + + out << ", <" << vit->first << ": ["; + if(!f->empty()) out << (*f)[0]; + for(unsigned int i = 1; i < f->size(); ++i) + { + out << ", " << (*f)[i]; + } + out << "]>"; + } + } + + return out; +} + +// --------------------------------------------------------------------------- + +} // namespace DBoW2 diff --git a/Thirdparty/DBoW2/DBoW2/FeatureVector.h b/Thirdparty/DBoW2/DBoW2/FeatureVector.h new file mode 100644 index 0000000..426f36d --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/FeatureVector.h @@ -0,0 +1,66 @@ +/** + * File: FeatureVector.h + * Date: November 2011 + * Author: Dorian Galvez-Lopez + * Description: feature vector + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_T_FEATURE_VECTOR__ +#define __D_T_FEATURE_VECTOR__ + +#include "BowVector.h" +#include +#include +#include + +#include +#include + +namespace DBoW2 { + +/// Vector of nodes with indexes of local features +class FeatureVector: + public std::map > +{ + friend class boost::serialization::access; + template + void serialize(Archive& ar, const int version) + { + ar & boost::serialization::base_object > >(*this); + } + +public: + + /** + * Constructor + */ + FeatureVector(void); + + /** + * Destructor + */ + ~FeatureVector(void); + + /** + * Adds a feature to an existing node, or adds a new node with an initial + * feature + * @param id node id to add or to modify + * @param i_feature index of feature to add to the given node + */ + void addFeature(NodeId id, unsigned int i_feature); + + /** + * Sends a string versions of the feature vector through the stream + * @param out stream + * @param v feature vector + */ + friend std::ostream& operator<<(std::ostream &out, const FeatureVector &v); + +}; + +} // namespace DBoW2 + +#endif + diff --git a/Thirdparty/DBoW2/DBoW2/ScoringObject.cpp b/Thirdparty/DBoW2/DBoW2/ScoringObject.cpp new file mode 100644 index 0000000..063a96e --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/ScoringObject.cpp @@ -0,0 +1,315 @@ +/** + * File: ScoringObject.cpp + * Date: November 2011 + * Author: Dorian Galvez-Lopez + * Description: functions to compute bow scores + * License: see the LICENSE.txt file + * + */ + +#include +#include "TemplatedVocabulary.h" +#include "BowVector.h" + +using namespace DBoW2; + +// If you change the type of WordValue, make sure you change also the +// epsilon value (this is needed by the KL method) +const double GeneralScoring::LOG_EPS = log(DBL_EPSILON); // FLT_EPSILON + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +double L1Scoring::score(const BowVector &v1, const BowVector &v2) const +{ + BowVector::const_iterator v1_it, v2_it; + const BowVector::const_iterator v1_end = v1.end(); + const BowVector::const_iterator v2_end = v2.end(); + + v1_it = v1.begin(); + v2_it = v2.begin(); + + double score = 0; + + while(v1_it != v1_end && v2_it != v2_end) + { + const WordValue& vi = v1_it->second; + const WordValue& wi = v2_it->second; + + if(v1_it->first == v2_it->first) + { + score += fabs(vi - wi) - fabs(vi) - fabs(wi); + + // move v1 and v2 forward + ++v1_it; + ++v2_it; + } + else if(v1_it->first < v2_it->first) + { + // move v1 forward + v1_it = v1.lower_bound(v2_it->first); + // v1_it = (first element >= v2_it.id) + } + else + { + // move v2 forward + v2_it = v2.lower_bound(v1_it->first); + // v2_it = (first element >= v1_it.id) + } + } + + // ||v - w||_{L1} = 2 + Sum(|v_i - w_i| - |v_i| - |w_i|) + // for all i | v_i != 0 and w_i != 0 + // (Nister, 2006) + // scaled_||v - w||_{L1} = 1 - 0.5 * ||v - w||_{L1} + score = -score/2.0; + + return score; // [0..1] +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +double L2Scoring::score(const BowVector &v1, const BowVector &v2) const +{ + BowVector::const_iterator v1_it, v2_it; + const BowVector::const_iterator v1_end = v1.end(); + const BowVector::const_iterator v2_end = v2.end(); + + v1_it = v1.begin(); + v2_it = v2.begin(); + + double score = 0; + + while(v1_it != v1_end && v2_it != v2_end) + { + const WordValue& vi = v1_it->second; + const WordValue& wi = v2_it->second; + + if(v1_it->first == v2_it->first) + { + score += vi * wi; + + // move v1 and v2 forward + ++v1_it; + ++v2_it; + } + else if(v1_it->first < v2_it->first) + { + // move v1 forward + v1_it = v1.lower_bound(v2_it->first); + // v1_it = (first element >= v2_it.id) + } + else + { + // move v2 forward + v2_it = v2.lower_bound(v1_it->first); + // v2_it = (first element >= v1_it.id) + } + } + + // ||v - w||_{L2} = sqrt( 2 - 2 * Sum(v_i * w_i) ) + // for all i | v_i != 0 and w_i != 0 ) + // (Nister, 2006) + if(score >= 1) // rounding errors + score = 1.0; + else + score = 1.0 - sqrt(1.0 - score); // [0..1] + + return score; +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +double ChiSquareScoring::score(const BowVector &v1, const BowVector &v2) + const +{ + BowVector::const_iterator v1_it, v2_it; + const BowVector::const_iterator v1_end = v1.end(); + const BowVector::const_iterator v2_end = v2.end(); + + v1_it = v1.begin(); + v2_it = v2.begin(); + + double score = 0; + + // all the items are taken into account + + while(v1_it != v1_end && v2_it != v2_end) + { + const WordValue& vi = v1_it->second; + const WordValue& wi = v2_it->second; + + if(v1_it->first == v2_it->first) + { + // (v-w)^2/(v+w) - v - w = -4 vw/(v+w) + // we move the -4 out + if(vi + wi != 0.0) score += vi * wi / (vi + wi); + + // move v1 and v2 forward + ++v1_it; + ++v2_it; + } + else if(v1_it->first < v2_it->first) + { + // move v1 forward + v1_it = v1.lower_bound(v2_it->first); + } + else + { + // move v2 forward + v2_it = v2.lower_bound(v1_it->first); + } + } + + // this takes the -4 into account + score = 2. * score; // [0..1] + + return score; +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +double KLScoring::score(const BowVector &v1, const BowVector &v2) const +{ + BowVector::const_iterator v1_it, v2_it; + const BowVector::const_iterator v1_end = v1.end(); + const BowVector::const_iterator v2_end = v2.end(); + + v1_it = v1.begin(); + v2_it = v2.begin(); + + double score = 0; + + // all the items or v are taken into account + + while(v1_it != v1_end && v2_it != v2_end) + { + const WordValue& vi = v1_it->second; + const WordValue& wi = v2_it->second; + + if(v1_it->first == v2_it->first) + { + if(vi != 0 && wi != 0) score += vi * log(vi/wi); + + // move v1 and v2 forward + ++v1_it; + ++v2_it; + } + else if(v1_it->first < v2_it->first) + { + // move v1 forward + score += vi * (log(vi) - LOG_EPS); + ++v1_it; + } + else + { + // move v2_it forward, do not add any score + v2_it = v2.lower_bound(v1_it->first); + // v2_it = (first element >= v1_it.id) + } + } + + // sum rest of items of v + for(; v1_it != v1_end; ++v1_it) + if(v1_it->second != 0) + score += v1_it->second * (log(v1_it->second) - LOG_EPS); + + return score; // cannot be scaled +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +double BhattacharyyaScoring::score(const BowVector &v1, + const BowVector &v2) const +{ + BowVector::const_iterator v1_it, v2_it; + const BowVector::const_iterator v1_end = v1.end(); + const BowVector::const_iterator v2_end = v2.end(); + + v1_it = v1.begin(); + v2_it = v2.begin(); + + double score = 0; + + while(v1_it != v1_end && v2_it != v2_end) + { + const WordValue& vi = v1_it->second; + const WordValue& wi = v2_it->second; + + if(v1_it->first == v2_it->first) + { + score += sqrt(vi * wi); + + // move v1 and v2 forward + ++v1_it; + ++v2_it; + } + else if(v1_it->first < v2_it->first) + { + // move v1 forward + v1_it = v1.lower_bound(v2_it->first); + // v1_it = (first element >= v2_it.id) + } + else + { + // move v2 forward + v2_it = v2.lower_bound(v1_it->first); + // v2_it = (first element >= v1_it.id) + } + } + + return score; // already scaled +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +double DotProductScoring::score(const BowVector &v1, + const BowVector &v2) const +{ + BowVector::const_iterator v1_it, v2_it; + const BowVector::const_iterator v1_end = v1.end(); + const BowVector::const_iterator v2_end = v2.end(); + + v1_it = v1.begin(); + v2_it = v2.begin(); + + double score = 0; + + while(v1_it != v1_end && v2_it != v2_end) + { + const WordValue& vi = v1_it->second; + const WordValue& wi = v2_it->second; + + if(v1_it->first == v2_it->first) + { + score += vi * wi; + + // move v1 and v2 forward + ++v1_it; + ++v2_it; + } + else if(v1_it->first < v2_it->first) + { + // move v1 forward + v1_it = v1.lower_bound(v2_it->first); + // v1_it = (first element >= v2_it.id) + } + else + { + // move v2 forward + v2_it = v2.lower_bound(v1_it->first); + // v2_it = (first element >= v1_it.id) + } + } + + return score; // cannot scale +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + diff --git a/Thirdparty/DBoW2/DBoW2/ScoringObject.h b/Thirdparty/DBoW2/DBoW2/ScoringObject.h new file mode 100644 index 0000000..8d5b821 --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/ScoringObject.h @@ -0,0 +1,96 @@ +/** + * File: ScoringObject.h + * Date: November 2011 + * Author: Dorian Galvez-Lopez + * Description: functions to compute bow scores + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_T_SCORING_OBJECT__ +#define __D_T_SCORING_OBJECT__ + +#include "BowVector.h" + +namespace DBoW2 { + +/// Base class of scoring functions +class GeneralScoring +{ +public: + /** + * Computes the score between two vectors. Vectors must be sorted and + * normalized if necessary + * @param v (in/out) + * @param w (in/out) + * @return score + */ + virtual double score(const BowVector &v, const BowVector &w) const = 0; + + /** + * Returns whether a vector must be normalized before scoring according + * to the scoring scheme + * @param norm norm to use + * @return true iff must normalize + */ + virtual bool mustNormalize(LNorm &norm) const = 0; + + /// Log of epsilon + static const double LOG_EPS; + // If you change the type of WordValue, make sure you change also the + // epsilon value (this is needed by the KL method) + + virtual ~GeneralScoring() {} //!< Required for virtual base classes + +}; + +/** + * Macro for defining Scoring classes + * @param NAME name of class + * @param MUSTNORMALIZE if vectors must be normalized to compute the score + * @param NORM type of norm to use when MUSTNORMALIZE + */ +#define __SCORING_CLASS(NAME, MUSTNORMALIZE, NORM) \ + NAME: public GeneralScoring \ + { public: \ + /** \ + * Computes score between two vectors \ + * @param v \ + * @param w \ + * @return score between v and w \ + */ \ + virtual double score(const BowVector &v, const BowVector &w) const; \ + \ + /** \ + * Says if a vector must be normalized according to the scoring function \ + * @param norm (out) if true, norm to use + * @return true iff vectors must be normalized \ + */ \ + virtual inline bool mustNormalize(LNorm &norm) const \ + { norm = NORM; return MUSTNORMALIZE; } \ + } + +/// L1 Scoring object +class __SCORING_CLASS(L1Scoring, true, L1); + +/// L2 Scoring object +class __SCORING_CLASS(L2Scoring, true, L2); + +/// Chi square Scoring object +class __SCORING_CLASS(ChiSquareScoring, true, L1); + +/// KL divergence Scoring object +class __SCORING_CLASS(KLScoring, true, L1); + +/// Bhattacharyya Scoring object +class __SCORING_CLASS(BhattacharyyaScoring, true, L1); + +/// Dot product Scoring object +class __SCORING_CLASS(DotProductScoring, false, L1); + +#undef __SCORING_CLASS + +} // namespace DBoW2 + +#endif + diff --git a/Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h b/Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h new file mode 100644 index 0000000..0195934 --- /dev/null +++ b/Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h @@ -0,0 +1,1665 @@ +/** + * This is a modified version of TemplatedVocabulary.h from DBoW2 (see below). + * Added functions: Save and Load from text files without using cv::FileStorage. + * Date: August 2015 + * Raúl Mur-Artal + */ + +/** + * File: TemplatedVocabulary.h + * Date: February 2011 + * Author: Dorian Galvez-Lopez + * Description: templated vocabulary + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_T_TEMPLATED_VOCABULARY__ +#define __D_T_TEMPLATED_VOCABULARY__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "FeatureVector.h" +#include "BowVector.h" +#include "ScoringObject.h" + +#include "../DUtils/Random.h" + +using namespace std; + +namespace DBoW2 { + +/// @param TDescriptor class of descriptor +/// @param F class of descriptor functions +template +/// Generic Vocabulary +class TemplatedVocabulary +{ +public: + + /** + * Initiates an empty vocabulary + * @param k branching factor + * @param L depth levels + * @param weighting weighting type + * @param scoring scoring type + */ + TemplatedVocabulary(int k = 10, int L = 5, + WeightingType weighting = TF_IDF, ScoringType scoring = L1_NORM); + + /** + * Creates the vocabulary by loading a file + * @param filename + */ + TemplatedVocabulary(const std::string &filename); + + /** + * Creates the vocabulary by loading a file + * @param filename + */ + TemplatedVocabulary(const char *filename); + + /** + * Copy constructor + * @param voc + */ + TemplatedVocabulary(const TemplatedVocabulary &voc); + + /** + * Destructor + */ + virtual ~TemplatedVocabulary(); + + /** + * Assigns the given vocabulary to this by copying its data and removing + * all the data contained by this vocabulary before + * @param voc + * @return reference to this vocabulary + */ + TemplatedVocabulary& operator=( + const TemplatedVocabulary &voc); + + /** + * Creates a vocabulary from the training features with the already + * defined parameters + * @param training_features + */ + virtual void create + (const std::vector > &training_features); + + /** + * Creates a vocabulary from the training features, setting the branching + * factor and the depth levels of the tree + * @param training_features + * @param k branching factor + * @param L depth levels + */ + virtual void create + (const std::vector > &training_features, + int k, int L); + + /** + * Creates a vocabulary from the training features, setting the branching + * factor nad the depth levels of the tree, and the weighting and scoring + * schemes + */ + virtual void create + (const std::vector > &training_features, + int k, int L, WeightingType weighting, ScoringType scoring); + + /** + * Returns the number of words in the vocabulary + * @return number of words + */ + virtual inline unsigned int size() const; + + /** + * Returns whether the vocabulary is empty (i.e. it has not been trained) + * @return true iff the vocabulary is empty + */ + virtual inline bool empty() const; + + /** + * Transforms a set of descriptores into a bow vector + * @param features + * @param v (out) bow vector of weighted words + */ + virtual void transform(const std::vector& features, BowVector &v) + const; + + /** + * Transform a set of descriptors into a bow vector and a feature vector + * @param features + * @param v (out) bow vector + * @param fv (out) feature vector of nodes and feature indexes + * @param levelsup levels to go up the vocabulary tree to get the node index + */ + virtual void transform(const std::vector& features, + BowVector &v, FeatureVector &fv, int levelsup) const; + + /** + * Transforms a single feature into a word (without weight) + * @param feature + * @return word id + */ + virtual WordId transform(const TDescriptor& feature) const; + + /** + * Returns the score of two vectors + * @param a vector + * @param b vector + * @return score between vectors + * @note the vectors must be already sorted and normalized if necessary + */ + inline double score(const BowVector &a, const BowVector &b) const; + + /** + * Returns the id of the node that is "levelsup" levels from the word given + * @param wid word id + * @param levelsup 0..L + * @return node id. if levelsup is 0, returns the node id associated to the + * word id + */ + virtual NodeId getParentNode(WordId wid, int levelsup) const; + + /** + * Returns the ids of all the words that are under the given node id, + * by traversing any of the branches that goes down from the node + * @param nid starting node id + * @param words ids of words + */ + void getWordsFromNode(NodeId nid, std::vector &words) const; + + /** + * Returns the branching factor of the tree (k) + * @return k + */ + inline int getBranchingFactor() const { return m_k; } + + /** + * Returns the depth levels of the tree (L) + * @return L + */ + inline int getDepthLevels() const { return m_L; } + + /** + * Returns the real depth levels of the tree on average + * @return average of depth levels of leaves + */ + float getEffectiveLevels() const; + + /** + * Returns the descriptor of a word + * @param wid word id + * @return descriptor + */ + virtual inline TDescriptor getWord(WordId wid) const; + + /** + * Returns the weight of a word + * @param wid word id + * @return weight + */ + virtual inline WordValue getWordWeight(WordId wid) const; + + /** + * Returns the weighting method + * @return weighting method + */ + inline WeightingType getWeightingType() const { return m_weighting; } + + /** + * Returns the scoring method + * @return scoring method + */ + inline ScoringType getScoringType() const { return m_scoring; } + + /** + * Changes the weighting method + * @param type new weighting type + */ + inline void setWeightingType(WeightingType type); + + /** + * Changes the scoring method + * @param type new scoring type + */ + void setScoringType(ScoringType type); + + /** + * Loads the vocabulary from a text file + * @param filename + */ + bool loadFromTextFile(const std::string &filename); + + /** + * Saves the vocabulary into a text file + * @param filename + */ + void saveToTextFile(const std::string &filename) const; + + /** + * Saves the vocabulary into a file + * @param filename + */ + void save(const std::string &filename) const; + + /** + * Loads the vocabulary from a file + * @param filename + */ + void load(const std::string &filename); + + /** + * Saves the vocabulary to a file storage structure + * @param fn node in file storage + */ + virtual void save(cv::FileStorage &fs, + const std::string &name = "vocabulary") const; + + /** + * Loads the vocabulary from a file storage node + * @param fn first node + * @param subname name of the child node of fn where the tree is stored. + * If not given, the fn node is used instead + */ + virtual void load(const cv::FileStorage &fs, + const std::string &name = "vocabulary"); + + /** + * Stops those words whose weight is below minWeight. + * Words are stopped by setting their weight to 0. There are not returned + * later when transforming image features into vectors. + * Note that when using IDF or TF_IDF, the weight is the idf part, which + * is equivalent to -log(f), where f is the frequency of the word + * (f = Ni/N, Ni: number of training images where the word is present, + * N: number of training images). + * Note that the old weight is forgotten, and subsequent calls to this + * function with a lower minWeight have no effect. + * @return number of words stopped now + */ + virtual int stopWords(double minWeight); + +protected: + + /// Pointer to descriptor + typedef const TDescriptor *pDescriptor; + + /// Tree node + struct Node + { + /// Node id + NodeId id; + /// Weight if the node is a word + WordValue weight; + /// Children + vector children; + /// Parent node (undefined in case of root) + NodeId parent; + /// Node descriptor + TDescriptor descriptor; + + /// Word id if the node is a word + WordId word_id; + + /** + * Empty constructor + */ + Node(): id(0), weight(0), parent(0), word_id(0){} + + /** + * Constructor + * @param _id node id + */ + Node(NodeId _id): id(_id), weight(0), parent(0), word_id(0){} + + /** + * Returns whether the node is a leaf node + * @return true iff the node is a leaf + */ + inline bool isLeaf() const { return children.empty(); } + }; + +protected: + + /** + * Creates an instance of the scoring object accoring to m_scoring + */ + void createScoringObject(); + + /** + * Returns a set of pointers to descriptores + * @param training_features all the features + * @param features (out) pointers to the training features + */ + void getFeatures( + const vector > &training_features, + vector &features) const; + + /** + * Returns the word id associated to a feature + * @param feature + * @param id (out) word id + * @param weight (out) word weight + * @param nid (out) if given, id of the node "levelsup" levels up + * @param levelsup + */ + virtual void transform(const TDescriptor &feature, + WordId &id, WordValue &weight, NodeId* nid = NULL, int levelsup = 0) const; + + /** + * Returns the word id associated to a feature + * @param feature + * @param id (out) word id + */ + virtual void transform(const TDescriptor &feature, WordId &id) const; + + /** + * Creates a level in the tree, under the parent, by running kmeans with + * a descriptor set, and recursively creates the subsequent levels too + * @param parent_id id of parent node + * @param descriptors descriptors to run the kmeans on + * @param current_level current level in the tree + */ + void HKmeansStep(NodeId parent_id, const vector &descriptors, + int current_level); + + /** + * Creates k clusters from the given descriptors with some seeding algorithm. + * @note In this class, kmeans++ is used, but this function should be + * overriden by inherited classes. + */ + virtual void initiateClusters(const vector &descriptors, + vector &clusters) const; + + /** + * Creates k clusters from the given descriptor sets by running the + * initial step of kmeans++ + * @param descriptors + * @param clusters resulting clusters + */ + void initiateClustersKMpp(const vector &descriptors, + vector &clusters) const; + + /** + * Create the words of the vocabulary once the tree has been built + */ + void createWords(); + + /** + * Sets the weights of the nodes of tree according to the given features. + * Before calling this function, the nodes and the words must be already + * created (by calling HKmeansStep and createWords) + * @param features + */ + void setNodeWeights(const vector > &features); + +protected: + + /// Branching factor + int m_k; + + /// Depth levels + int m_L; + + /// Weighting method + WeightingType m_weighting; + + /// Scoring method + ScoringType m_scoring; + + /// Object for computing scores + GeneralScoring* m_scoring_object; + + /// Tree nodes + std::vector m_nodes; + + /// Words of the vocabulary (tree leaves) + /// this condition holds: m_words[wid]->word_id == wid + std::vector m_words; + +}; + +// -------------------------------------------------------------------------- + +template +TemplatedVocabulary::TemplatedVocabulary + (int k, int L, WeightingType weighting, ScoringType scoring) + : m_k(k), m_L(L), m_weighting(weighting), m_scoring(scoring), + m_scoring_object(NULL) +{ + createScoringObject(); +} + +// -------------------------------------------------------------------------- + +template +TemplatedVocabulary::TemplatedVocabulary + (const std::string &filename): m_scoring_object(NULL) +{ + load(filename); +} + +// -------------------------------------------------------------------------- + +template +TemplatedVocabulary::TemplatedVocabulary + (const char *filename): m_scoring_object(NULL) +{ + load(filename); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::createScoringObject() +{ + delete m_scoring_object; + m_scoring_object = NULL; + + switch(m_scoring) + { + case L1_NORM: + m_scoring_object = new L1Scoring; + break; + + case L2_NORM: + m_scoring_object = new L2Scoring; + break; + + case CHI_SQUARE: + m_scoring_object = new ChiSquareScoring; + break; + + case KL: + m_scoring_object = new KLScoring; + break; + + case BHATTACHARYYA: + m_scoring_object = new BhattacharyyaScoring; + break; + + case DOT_PRODUCT: + m_scoring_object = new DotProductScoring; + break; + + } +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::setScoringType(ScoringType type) +{ + m_scoring = type; + createScoringObject(); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::setWeightingType(WeightingType type) +{ + this->m_weighting = type; +} + +// -------------------------------------------------------------------------- + +template +TemplatedVocabulary::TemplatedVocabulary( + const TemplatedVocabulary &voc) + : m_scoring_object(NULL) +{ + *this = voc; +} + +// -------------------------------------------------------------------------- + +template +TemplatedVocabulary::~TemplatedVocabulary() +{ + delete m_scoring_object; +} + +// -------------------------------------------------------------------------- + +template +TemplatedVocabulary& +TemplatedVocabulary::operator= + (const TemplatedVocabulary &voc) +{ + this->m_k = voc.m_k; + this->m_L = voc.m_L; + this->m_scoring = voc.m_scoring; + this->m_weighting = voc.m_weighting; + + this->createScoringObject(); + + this->m_nodes.clear(); + this->m_words.clear(); + + this->m_nodes = voc.m_nodes; + this->createWords(); + + return *this; +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::create( + const std::vector > &training_features) +{ + m_nodes.clear(); + m_words.clear(); + + // expected_nodes = Sum_{i=0..L} ( k^i ) + int expected_nodes = + (int)((pow((double)m_k, (double)m_L + 1) - 1)/(m_k - 1)); + + m_nodes.reserve(expected_nodes); // avoid allocations when creating the tree + + + vector features; + getFeatures(training_features, features); + + + // create root + m_nodes.push_back(Node(0)); // root + + // create the tree + HKmeansStep(0, features, 1); + + // create the words + createWords(); + + // and set the weight of each node of the tree + setNodeWeights(training_features); + +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::create( + const std::vector > &training_features, + int k, int L) +{ + m_k = k; + m_L = L; + + create(training_features); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::create( + const std::vector > &training_features, + int k, int L, WeightingType weighting, ScoringType scoring) +{ + m_k = k; + m_L = L; + m_weighting = weighting; + m_scoring = scoring; + createScoringObject(); + + create(training_features); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::getFeatures( + const vector > &training_features, + vector &features) const +{ + features.resize(0); + + typename vector >::const_iterator vvit; + typename vector::const_iterator vit; + for(vvit = training_features.begin(); vvit != training_features.end(); ++vvit) + { + features.reserve(features.size() + vvit->size()); + for(vit = vvit->begin(); vit != vvit->end(); ++vit) + { + features.push_back(&(*vit)); + } + } +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::HKmeansStep(NodeId parent_id, + const vector &descriptors, int current_level) +{ + if(descriptors.empty()) return; + + // features associated to each cluster + vector clusters; + vector > groups; // groups[i] = [j1, j2, ...] + // j1, j2, ... indices of descriptors associated to cluster i + + clusters.reserve(m_k); + groups.reserve(m_k); + + //const int msizes[] = { m_k, descriptors.size() }; + //cv::SparseMat assoc(2, msizes, CV_8U); + //cv::SparseMat last_assoc(2, msizes, CV_8U); + //// assoc.row(cluster_idx).col(descriptor_idx) = 1 iif associated + + if((int)descriptors.size() <= m_k) + { + // trivial case: one cluster per feature + groups.resize(descriptors.size()); + + for(unsigned int i = 0; i < descriptors.size(); i++) + { + groups[i].push_back(i); + clusters.push_back(*descriptors[i]); + } + } + else + { + // select clusters and groups with kmeans + + bool first_time = true; + bool goon = true; + + // to check if clusters move after iterations + vector last_association, current_association; + + while(goon) + { + // 1. Calculate clusters + + if(first_time) + { + // random sample + initiateClusters(descriptors, clusters); + } + else + { + // calculate cluster centres + + for(unsigned int c = 0; c < clusters.size(); ++c) + { + vector cluster_descriptors; + cluster_descriptors.reserve(groups[c].size()); + + /* + for(unsigned int d = 0; d < descriptors.size(); ++d) + { + if( assoc.find(c, d) ) + { + cluster_descriptors.push_back(descriptors[d]); + } + } + */ + + vector::const_iterator vit; + for(vit = groups[c].begin(); vit != groups[c].end(); ++vit) + { + cluster_descriptors.push_back(descriptors[*vit]); + } + + + F::meanValue(cluster_descriptors, clusters[c]); + } + + } // if(!first_time) + + // 2. Associate features with clusters + + // calculate distances to cluster centers + groups.clear(); + groups.resize(clusters.size(), vector()); + current_association.resize(descriptors.size()); + + //assoc.clear(); + + typename vector::const_iterator fit; + //unsigned int d = 0; + for(fit = descriptors.begin(); fit != descriptors.end(); ++fit)//, ++d) + { + double best_dist = F::distance(*(*fit), clusters[0]); + unsigned int icluster = 0; + + for(unsigned int c = 1; c < clusters.size(); ++c) + { + double dist = F::distance(*(*fit), clusters[c]); + if(dist < best_dist) + { + best_dist = dist; + icluster = c; + } + } + + //assoc.ref(icluster, d) = 1; + + groups[icluster].push_back(fit - descriptors.begin()); + current_association[ fit - descriptors.begin() ] = icluster; + } + + // kmeans++ ensures all the clusters has any feature associated with them + + // 3. check convergence + if(first_time) + { + first_time = false; + } + else + { + //goon = !eqUChar(last_assoc, assoc); + + goon = false; + for(unsigned int i = 0; i < current_association.size(); i++) + { + if(current_association[i] != last_association[i]){ + goon = true; + break; + } + } + } + + if(goon) + { + // copy last feature-cluster association + last_association = current_association; + //last_assoc = assoc.clone(); + } + + } // while(goon) + + } // if must run kmeans + + // create nodes + for(unsigned int i = 0; i < clusters.size(); ++i) + { + NodeId id = m_nodes.size(); + m_nodes.push_back(Node(id)); + m_nodes.back().descriptor = clusters[i]; + m_nodes.back().parent = parent_id; + m_nodes[parent_id].children.push_back(id); + } + + // go on with the next level + if(current_level < m_L) + { + // iterate again with the resulting clusters + const vector &children_ids = m_nodes[parent_id].children; + for(unsigned int i = 0; i < clusters.size(); ++i) + { + NodeId id = children_ids[i]; + + vector child_features; + child_features.reserve(groups[i].size()); + + vector::const_iterator vit; + for(vit = groups[i].begin(); vit != groups[i].end(); ++vit) + { + child_features.push_back(descriptors[*vit]); + } + + if(child_features.size() > 1) + { + HKmeansStep(id, child_features, current_level + 1); + } + } + } +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::initiateClusters + (const vector &descriptors, vector &clusters) const +{ + initiateClustersKMpp(descriptors, clusters); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::initiateClustersKMpp( + const vector &pfeatures, vector &clusters) const +{ + // Implements kmeans++ seeding algorithm + // Algorithm: + // 1. Choose one center uniformly at random from among the data points. + // 2. For each data point x, compute D(x), the distance between x and the nearest + // center that has already been chosen. + // 3. Add one new data point as a center. Each point x is chosen with probability + // proportional to D(x)^2. + // 4. Repeat Steps 2 and 3 until k centers have been chosen. + // 5. Now that the initial centers have been chosen, proceed using standard k-means + // clustering. + + DUtils::Random::SeedRandOnce(); + + clusters.resize(0); + clusters.reserve(m_k); + vector min_dists(pfeatures.size(), std::numeric_limits::max()); + + // 1. + + int ifeature = DUtils::Random::RandomInt(0, pfeatures.size()-1); + + // create first cluster + clusters.push_back(*pfeatures[ifeature]); + + // compute the initial distances + typename vector::const_iterator fit; + vector::iterator dit; + dit = min_dists.begin(); + for(fit = pfeatures.begin(); fit != pfeatures.end(); ++fit, ++dit) + { + *dit = F::distance(*(*fit), clusters.back()); + } + + while((int)clusters.size() < m_k) + { + // 2. + dit = min_dists.begin(); + for(fit = pfeatures.begin(); fit != pfeatures.end(); ++fit, ++dit) + { + if(*dit > 0) + { + double dist = F::distance(*(*fit), clusters.back()); + if(dist < *dit) *dit = dist; + } + } + + // 3. + double dist_sum = std::accumulate(min_dists.begin(), min_dists.end(), 0.0); + + if(dist_sum > 0) + { + double cut_d; + do + { + cut_d = DUtils::Random::RandomValue(0, dist_sum); + } while(cut_d == 0.0); + + double d_up_now = 0; + for(dit = min_dists.begin(); dit != min_dists.end(); ++dit) + { + d_up_now += *dit; + if(d_up_now >= cut_d) break; + } + + if(dit == min_dists.end()) + ifeature = pfeatures.size()-1; + else + ifeature = dit - min_dists.begin(); + + clusters.push_back(*pfeatures[ifeature]); + + } // if dist_sum > 0 + else + break; + + } // while(used_clusters < m_k) + +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::createWords() +{ + m_words.resize(0); + + if(!m_nodes.empty()) + { + m_words.reserve( (int)pow((double)m_k, (double)m_L) ); + + typename vector::iterator nit; + + nit = m_nodes.begin(); // ignore root + for(++nit; nit != m_nodes.end(); ++nit) + { + if(nit->isLeaf()) + { + nit->word_id = m_words.size(); + m_words.push_back( &(*nit) ); + } + } + } +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::setNodeWeights + (const vector > &training_features) +{ + const unsigned int NWords = m_words.size(); + const unsigned int NDocs = training_features.size(); + + if(m_weighting == TF || m_weighting == BINARY) + { + // idf part must be 1 always + for(unsigned int i = 0; i < NWords; i++) + m_words[i]->weight = 1; + } + else if(m_weighting == IDF || m_weighting == TF_IDF) + { + // IDF and TF-IDF: we calculte the idf path now + + // Note: this actually calculates the idf part of the tf-idf score. + // The complete tf-idf score is calculated in ::transform + + vector Ni(NWords, 0); + vector counted(NWords, false); + + typename vector >::const_iterator mit; + typename vector::const_iterator fit; + + for(mit = training_features.begin(); mit != training_features.end(); ++mit) + { + fill(counted.begin(), counted.end(), false); + + for(fit = mit->begin(); fit < mit->end(); ++fit) + { + WordId word_id; + transform(*fit, word_id); + + if(!counted[word_id]) + { + Ni[word_id]++; + counted[word_id] = true; + } + } + } + + // set ln(N/Ni) + for(unsigned int i = 0; i < NWords; i++) + { + if(Ni[i] > 0) + { + m_words[i]->weight = log((double)NDocs / (double)Ni[i]); + }// else // This cannot occur if using kmeans++ + } + + } + +} + +// -------------------------------------------------------------------------- + +template +inline unsigned int TemplatedVocabulary::size() const +{ + return m_words.size(); +} + +// -------------------------------------------------------------------------- + +template +inline bool TemplatedVocabulary::empty() const +{ + return m_words.empty(); +} + +// -------------------------------------------------------------------------- + +template +float TemplatedVocabulary::getEffectiveLevels() const +{ + long sum = 0; + typename std::vector::const_iterator wit; + for(wit = m_words.begin(); wit != m_words.end(); ++wit) + { + const Node *p = *wit; + + for(; p->id != 0; sum++) p = &m_nodes[p->parent]; + } + + return (float)((double)sum / (double)m_words.size()); +} + +// -------------------------------------------------------------------------- + +template +TDescriptor TemplatedVocabulary::getWord(WordId wid) const +{ + return m_words[wid]->descriptor; +} + +// -------------------------------------------------------------------------- + +template +WordValue TemplatedVocabulary::getWordWeight(WordId wid) const +{ + return m_words[wid]->weight; +} + +// -------------------------------------------------------------------------- + +template +WordId TemplatedVocabulary::transform + (const TDescriptor& feature) const +{ + if(empty()) + { + return 0; + } + + WordId wid; + transform(feature, wid); + return wid; +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::transform( + const std::vector& features, BowVector &v) const +{ + v.clear(); + + if(empty()) + { + return; + } + + // normalize + LNorm norm; + bool must = m_scoring_object->mustNormalize(norm); + + typename vector::const_iterator fit; + + if(m_weighting == TF || m_weighting == TF_IDF) + { + for(fit = features.begin(); fit < features.end(); ++fit) + { + WordId id; + WordValue w; + // w is the idf value if TF_IDF, 1 if TF + + transform(*fit, id, w); + + // not stopped + if(w > 0) v.addWeight(id, w); + } + + if(!v.empty() && !must) + { + // unnecessary when normalizing + const double nd = v.size(); + for(BowVector::iterator vit = v.begin(); vit != v.end(); vit++) + vit->second /= nd; + } + + } + else // IDF || BINARY + { + for(fit = features.begin(); fit < features.end(); ++fit) + { + WordId id; + WordValue w; + // w is idf if IDF, or 1 if BINARY + + transform(*fit, id, w); + + // not stopped + if(w > 0) v.addIfNotExist(id, w); + + } // if add_features + } // if m_weighting == ... + + if(must) v.normalize(norm); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::transform( + const std::vector& features, + BowVector &v, FeatureVector &fv, int levelsup) const +{ + v.clear(); + fv.clear(); + + if(empty()) // safe for subclasses + { + return; + } + + // normalize + LNorm norm; + bool must = m_scoring_object->mustNormalize(norm); + + typename vector::const_iterator fit; + + if(m_weighting == TF || m_weighting == TF_IDF) + { + unsigned int i_feature = 0; + for(fit = features.begin(); fit < features.end(); ++fit, ++i_feature) + { + WordId id; + NodeId nid; + WordValue w; + // w is the idf value if TF_IDF, 1 if TF + + transform(*fit, id, w, &nid, levelsup); + + if(w > 0) // not stopped + { + v.addWeight(id, w); + fv.addFeature(nid, i_feature); + } + } + + if(!v.empty() && !must) + { + // unnecessary when normalizing + const double nd = v.size(); + for(BowVector::iterator vit = v.begin(); vit != v.end(); vit++) + vit->second /= nd; + } + + } + else // IDF || BINARY + { + unsigned int i_feature = 0; + for(fit = features.begin(); fit < features.end(); ++fit, ++i_feature) + { + WordId id; + NodeId nid; + WordValue w; + // w is idf if IDF, or 1 if BINARY + + transform(*fit, id, w, &nid, levelsup); + + if(w > 0) // not stopped + { + v.addIfNotExist(id, w); + fv.addFeature(nid, i_feature); + } + } + } // if m_weighting == ... + + if(must) v.normalize(norm); +} + +// -------------------------------------------------------------------------- + +template +inline double TemplatedVocabulary::score + (const BowVector &v1, const BowVector &v2) const +{ + return m_scoring_object->score(v1, v2); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::transform + (const TDescriptor &feature, WordId &id) const +{ + WordValue weight; + transform(feature, id, weight); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::transform(const TDescriptor &feature, + WordId &word_id, WordValue &weight, NodeId *nid, int levelsup) const +{ + // propagate the feature down the tree + vector nodes; + typename vector::const_iterator nit; + + // level at which the node must be stored in nid, if given + const int nid_level = m_L - levelsup; + if(nid_level <= 0 && nid != NULL) *nid = 0; // root + + NodeId final_id = 0; // root + int current_level = 0; + + do + { + ++current_level; + nodes = m_nodes[final_id].children; + final_id = nodes[0]; + + double best_d = F::distance(feature, m_nodes[final_id].descriptor); + + for(nit = nodes.begin() + 1; nit != nodes.end(); ++nit) + { + NodeId id = *nit; + double d = F::distance(feature, m_nodes[id].descriptor); + if(d < best_d) + { + best_d = d; + final_id = id; + } + } + + if(nid != NULL && current_level == nid_level) + *nid = final_id; + + } while( !m_nodes[final_id].isLeaf() ); + + // turn node id into word id + word_id = m_nodes[final_id].word_id; + weight = m_nodes[final_id].weight; +} + +// -------------------------------------------------------------------------- + +template +NodeId TemplatedVocabulary::getParentNode + (WordId wid, int levelsup) const +{ + NodeId ret = m_words[wid]->id; // node id + while(levelsup > 0 && ret != 0) // ret == 0 --> root + { + --levelsup; + ret = m_nodes[ret].parent; + } + return ret; +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::getWordsFromNode + (NodeId nid, std::vector &words) const +{ + words.clear(); + + if(m_nodes[nid].isLeaf()) + { + words.push_back(m_nodes[nid].word_id); + } + else + { + words.reserve(m_k); // ^1, ^2, ... + + vector parents; + parents.push_back(nid); + + while(!parents.empty()) + { + NodeId parentid = parents.back(); + parents.pop_back(); + + const vector &child_ids = m_nodes[parentid].children; + vector::const_iterator cit; + + for(cit = child_ids.begin(); cit != child_ids.end(); ++cit) + { + const Node &child_node = m_nodes[*cit]; + + if(child_node.isLeaf()) + words.push_back(child_node.word_id); + else + parents.push_back(*cit); + + } // for each child + } // while !parents.empty + } +} + +// -------------------------------------------------------------------------- + +template +int TemplatedVocabulary::stopWords(double minWeight) +{ + int c = 0; + typename vector::iterator wit; + for(wit = m_words.begin(); wit != m_words.end(); ++wit) + { + if((*wit)->weight < minWeight) + { + ++c; + (*wit)->weight = 0; + } + } + return c; +} + +// -------------------------------------------------------------------------- + +template +bool TemplatedVocabulary::loadFromTextFile(const std::string &filename) +{ + ifstream f; + f.open(filename.c_str()); + + if(f.eof()) + return false; + + m_words.clear(); + m_nodes.clear(); + + string s; + getline(f,s); + stringstream ss; + ss << s; + ss >> m_k; + ss >> m_L; + int n1, n2; + ss >> n1; + ss >> n2; + + if(m_k<0 || m_k>20 || m_L<1 || m_L>10 || n1<0 || n1>5 || n2<0 || n2>3) + { + std::cerr << "Vocabulary loading failure: This is not a correct text file!" << endl; + return false; + } + + m_scoring = (ScoringType)n1; + m_weighting = (WeightingType)n2; + createScoringObject(); + + // nodes + int expected_nodes = + (int)((pow((double)m_k, (double)m_L + 1) - 1)/(m_k - 1)); + m_nodes.reserve(expected_nodes); + + m_words.reserve(pow((double)m_k, (double)m_L + 1)); + + m_nodes.resize(1); + m_nodes[0].id = 0; + while(!f.eof()) + { + string snode; + getline(f,snode); + stringstream ssnode; + ssnode << snode; + + int nid = m_nodes.size(); + m_nodes.resize(m_nodes.size()+1); + m_nodes[nid].id = nid; + + int pid ; + ssnode >> pid; + m_nodes[nid].parent = pid; + m_nodes[pid].children.push_back(nid); + + int nIsLeaf; + ssnode >> nIsLeaf; + + stringstream ssd; + for(int iD=0;iD> sElement; + ssd << sElement << " "; + } + F::fromString(m_nodes[nid].descriptor, ssd.str()); + + ssnode >> m_nodes[nid].weight; + + if(nIsLeaf>0) + { + int wid = m_words.size(); + m_words.resize(wid+1); + + m_nodes[nid].word_id = wid; + m_words[wid] = &m_nodes[nid]; + } + else + { + m_nodes[nid].children.reserve(m_k); + } + } + + return true; + +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::saveToTextFile(const std::string &filename) const +{ + fstream f; + f.open(filename.c_str(),ios_base::out); + f << m_k << " " << m_L << " " << " " << m_scoring << " " << m_weighting << endl; + + for(size_t i=1; i +void TemplatedVocabulary::save(const std::string &filename) const +{ + cv::FileStorage fs(filename.c_str(), cv::FileStorage::WRITE); + if(!fs.isOpened()) throw string("Could not open file ") + filename; + + save(fs); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::load(const std::string &filename) +{ + cv::FileStorage fs(filename.c_str(), cv::FileStorage::READ); + if(!fs.isOpened()) throw string("Could not open file ") + filename; + + this->load(fs); +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::save(cv::FileStorage &f, + const std::string &name) const +{ + // Format YAML: + // vocabulary + // { + // k: + // L: + // scoringType: + // weightingType: + // nodes + // [ + // { + // nodeId: + // parentId: + // weight: + // descriptor: + // } + // ] + // words + // [ + // { + // wordId: + // nodeId: + // } + // ] + // } + // + // The root node (index 0) is not included in the node vector + // + + f << name << "{"; + + f << "k" << m_k; + f << "L" << m_L; + f << "scoringType" << m_scoring; + f << "weightingType" << m_weighting; + + // tree + f << "nodes" << "["; + vector parents, children; + vector::const_iterator pit; + + parents.push_back(0); // root + + while(!parents.empty()) + { + NodeId pid = parents.back(); + parents.pop_back(); + + const Node& parent = m_nodes[pid]; + children = parent.children; + + for(pit = children.begin(); pit != children.end(); pit++) + { + const Node& child = m_nodes[*pit]; + + // save node data + f << "{:"; + f << "nodeId" << (int)child.id; + f << "parentId" << (int)pid; + f << "weight" << (double)child.weight; + f << "descriptor" << F::toString(child.descriptor); + f << "}"; + + // add to parent list + if(!child.isLeaf()) + { + parents.push_back(*pit); + } + } + } + + f << "]"; // nodes + + // words + f << "words" << "["; + + typename vector::const_iterator wit; + for(wit = m_words.begin(); wit != m_words.end(); wit++) + { + WordId id = wit - m_words.begin(); + f << "{:"; + f << "wordId" << (int)id; + f << "nodeId" << (int)(*wit)->id; + f << "}"; + } + + f << "]"; // words + + f << "}"; + +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::load(const cv::FileStorage &fs, + const std::string &name) +{ + m_words.clear(); + m_nodes.clear(); + + cv::FileNode fvoc = fs[name]; + + m_k = (int)fvoc["k"]; + m_L = (int)fvoc["L"]; + m_scoring = (ScoringType)((int)fvoc["scoringType"]); + m_weighting = (WeightingType)((int)fvoc["weightingType"]); + + createScoringObject(); + + // nodes + cv::FileNode fn = fvoc["nodes"]; + + m_nodes.resize(fn.size() + 1); // +1 to include root + m_nodes[0].id = 0; + + for(unsigned int i = 0; i < fn.size(); ++i) + { + NodeId nid = (int)fn[i]["nodeId"]; + NodeId pid = (int)fn[i]["parentId"]; + WordValue weight = (WordValue)fn[i]["weight"]; + string d = (string)fn[i]["descriptor"]; + + m_nodes[nid].id = nid; + m_nodes[nid].parent = pid; + m_nodes[nid].weight = weight; + m_nodes[pid].children.push_back(nid); + + F::fromString(m_nodes[nid].descriptor, d); + } + + // words + fn = fvoc["words"]; + + m_words.resize(fn.size()); + + for(unsigned int i = 0; i < fn.size(); ++i) + { + NodeId wid = (int)fn[i]["wordId"]; + NodeId nid = (int)fn[i]["nodeId"]; + + m_nodes[nid].word_id = wid; + m_words[wid] = &m_nodes[nid]; + } +} + +// -------------------------------------------------------------------------- + +/** + * Writes printable information of the vocabulary + * @param os stream to write to + * @param voc + */ +template +std::ostream& operator<<(std::ostream &os, + const TemplatedVocabulary &voc) +{ + os << "Vocabulary: k = " << voc.getBranchingFactor() + << ", L = " << voc.getDepthLevels() + << ", Weighting = "; + + switch(voc.getWeightingType()) + { + case TF_IDF: os << "tf-idf"; break; + case TF: os << "tf"; break; + case IDF: os << "idf"; break; + case BINARY: os << "binary"; break; + } + + os << ", Scoring = "; + switch(voc.getScoringType()) + { + case L1_NORM: os << "L1-norm"; break; + case L2_NORM: os << "L2-norm"; break; + case CHI_SQUARE: os << "Chi square distance"; break; + case KL: os << "KL-divergence"; break; + case BHATTACHARYYA: os << "Bhattacharyya coefficient"; break; + case DOT_PRODUCT: os << "Dot product"; break; + } + + os << ", Number of words = " << voc.size(); + + return os; +} + +} // namespace DBoW2 + +#endif diff --git a/Thirdparty/DBoW2/DUtils/Random.cpp b/Thirdparty/DBoW2/DUtils/Random.cpp new file mode 100644 index 0000000..1d78273 --- /dev/null +++ b/Thirdparty/DBoW2/DUtils/Random.cpp @@ -0,0 +1,129 @@ +/* + * File: Random.cpp + * Project: DUtils library + * Author: Dorian Galvez-Lopez + * Date: April 2010 + * Description: manages pseudo-random numbers + * License: see the LICENSE.txt file + * + */ + +#include "Random.h" +#include "Timestamp.h" +#include +using namespace std; + +bool DUtils::Random::m_already_seeded = false; + +void DUtils::Random::SeedRand(){ + Timestamp time; + time.setToCurrentTime(); + srand((unsigned)time.getFloatTime()); +} + +void DUtils::Random::SeedRandOnce() +{ + if(!m_already_seeded) + { + DUtils::Random::SeedRand(); + m_already_seeded = true; + } +} + +void DUtils::Random::SeedRand(int seed) +{ + srand(seed); +} + +void DUtils::Random::SeedRandOnce(int seed) +{ + if(!m_already_seeded) + { + DUtils::Random::SeedRand(seed); + m_already_seeded = true; + } +} + +int DUtils::Random::RandomInt(int min, int max){ + int d = max - min + 1; + return int(((double)rand()/((double)RAND_MAX + 1.0)) * d) + min; +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +DUtils::Random::UnrepeatedRandomizer::UnrepeatedRandomizer(int min, int max) +{ + if(min <= max) + { + m_min = min; + m_max = max; + } + else + { + m_min = max; + m_max = min; + } + + createValues(); +} + +// --------------------------------------------------------------------------- + +DUtils::Random::UnrepeatedRandomizer::UnrepeatedRandomizer + (const DUtils::Random::UnrepeatedRandomizer& rnd) +{ + *this = rnd; +} + +// --------------------------------------------------------------------------- + +int DUtils::Random::UnrepeatedRandomizer::get() +{ + if(empty()) createValues(); + + DUtils::Random::SeedRandOnce(); + + int k = DUtils::Random::RandomInt(0, m_values.size()-1); + int ret = m_values[k]; + m_values[k] = m_values.back(); + m_values.pop_back(); + + return ret; +} + +// --------------------------------------------------------------------------- + +void DUtils::Random::UnrepeatedRandomizer::createValues() +{ + int n = m_max - m_min + 1; + + m_values.resize(n); + for(int i = 0; i < n; ++i) m_values[i] = m_min + i; +} + +// --------------------------------------------------------------------------- + +void DUtils::Random::UnrepeatedRandomizer::reset() +{ + if((int)m_values.size() != m_max - m_min + 1) createValues(); +} + +// --------------------------------------------------------------------------- + +DUtils::Random::UnrepeatedRandomizer& +DUtils::Random::UnrepeatedRandomizer::operator= + (const DUtils::Random::UnrepeatedRandomizer& rnd) +{ + if(this != &rnd) + { + this->m_min = rnd.m_min; + this->m_max = rnd.m_max; + this->m_values = rnd.m_values; + } + return *this; +} + +// --------------------------------------------------------------------------- + + diff --git a/Thirdparty/DBoW2/DUtils/Random.h b/Thirdparty/DBoW2/DUtils/Random.h new file mode 100644 index 0000000..5115dc4 --- /dev/null +++ b/Thirdparty/DBoW2/DUtils/Random.h @@ -0,0 +1,184 @@ +/* + * File: Random.h + * Project: DUtils library + * Author: Dorian Galvez-Lopez + * Date: April 2010, November 2011 + * Description: manages pseudo-random numbers + * License: see the LICENSE.txt file + * + */ + +#pragma once +#ifndef __D_RANDOM__ +#define __D_RANDOM__ + +#include +#include + +namespace DUtils { + +/// Functions to generate pseudo-random numbers +class Random +{ +public: + class UnrepeatedRandomizer; + +public: + /** + * Sets the random number seed to the current time + */ + static void SeedRand(); + + /** + * Sets the random number seed to the current time only the first + * time this function is called + */ + static void SeedRandOnce(); + + /** + * Sets the given random number seed + * @param seed + */ + static void SeedRand(int seed); + + /** + * Sets the given random number seed only the first time this function + * is called + * @param seed + */ + static void SeedRandOnce(int seed); + + /** + * Returns a random number in the range [0..1] + * @return random T number in [0..1] + */ + template + static T RandomValue(){ + return (T)rand()/(T)RAND_MAX; + } + + /** + * Returns a random number in the range [min..max] + * @param min + * @param max + * @return random T number in [min..max] + */ + template + static T RandomValue(T min, T max){ + return Random::RandomValue() * (max - min) + min; + } + + /** + * Returns a random int in the range [min..max] + * @param min + * @param max + * @return random int in [min..max] + */ + static int RandomInt(int min, int max); + + /** + * Returns a random number from a gaussian distribution + * @param mean + * @param sigma standard deviation + */ + template + static T RandomGaussianValue(T mean, T sigma) + { + // Box-Muller transformation + T x1, x2, w, y1; + + do { + x1 = (T)2. * RandomValue() - (T)1.; + x2 = (T)2. * RandomValue() - (T)1.; + w = x1 * x1 + x2 * x2; + } while ( w >= (T)1. || w == (T)0. ); + + w = sqrt( ((T)-2.0 * log( w ) ) / w ); + y1 = x1 * w; + + return( mean + y1 * sigma ); + } + +private: + + /// If SeedRandOnce() or SeedRandOnce(int) have already been called + static bool m_already_seeded; + +}; + +// --------------------------------------------------------------------------- + +/// Provides pseudo-random numbers with no repetitions +class Random::UnrepeatedRandomizer +{ +public: + + /** + * Creates a randomizer that returns numbers in the range [min, max] + * @param min + * @param max + */ + UnrepeatedRandomizer(int min, int max); + ~UnrepeatedRandomizer(){} + + /** + * Copies a randomizer + * @param rnd + */ + UnrepeatedRandomizer(const UnrepeatedRandomizer& rnd); + + /** + * Copies a randomizer + * @param rnd + */ + UnrepeatedRandomizer& operator=(const UnrepeatedRandomizer& rnd); + + /** + * Returns a random number not given before. If all the possible values + * were already given, the process starts again + * @return unrepeated random number + */ + int get(); + + /** + * Returns whether all the possible values between min and max were + * already given. If get() is called when empty() is true, the behaviour + * is the same than after creating the randomizer + * @return true iff all the values were returned + */ + inline bool empty() const { return m_values.empty(); } + + /** + * Returns the number of values still to be returned + * @return amount of values to return + */ + inline unsigned int left() const { return m_values.size(); } + + /** + * Resets the randomizer as it were just created + */ + void reset(); + +protected: + + /** + * Creates the vector with available values + */ + void createValues(); + +protected: + + /// Min of range of values + int m_min; + /// Max of range of values + int m_max; + + /// Available values + std::vector m_values; + +}; + +} + +#endif + diff --git a/Thirdparty/DBoW2/DUtils/Timestamp.cpp b/Thirdparty/DBoW2/DUtils/Timestamp.cpp new file mode 100644 index 0000000..497304a --- /dev/null +++ b/Thirdparty/DBoW2/DUtils/Timestamp.cpp @@ -0,0 +1,246 @@ +/* + * File: Timestamp.cpp + * Author: Dorian Galvez-Lopez + * Date: March 2009 + * Description: timestamping functions + * + * Note: in windows, this class has a 1ms resolution + * + * License: see the LICENSE.txt file + * + */ + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#ifndef WIN32 +#define WIN32 +#endif +#endif + +#ifdef WIN32 +#include +#define sprintf sprintf_s +#else +#include +#endif + +#include "Timestamp.h" + +using namespace std; + +using namespace DUtils; + +Timestamp::Timestamp(Timestamp::tOptions option) +{ + if(option & CURRENT_TIME) + setToCurrentTime(); + else if(option & ZERO) + setTime(0.); +} + +Timestamp::~Timestamp(void) +{ +} + +bool Timestamp::empty() const +{ + return m_secs == 0 && m_usecs == 0; +} + +void Timestamp::setToCurrentTime(){ + +#ifdef WIN32 + struct __timeb32 timebuffer; + _ftime32_s( &timebuffer ); // C4996 + // Note: _ftime is deprecated; consider using _ftime_s instead + m_secs = timebuffer.time; + m_usecs = timebuffer.millitm * 1000; +#else + struct timeval now; + gettimeofday(&now, NULL); + m_secs = now.tv_sec; + m_usecs = now.tv_usec; +#endif + +} + +void Timestamp::setTime(const string &stime){ + string::size_type p = stime.find('.'); + if(p == string::npos){ + m_secs = atol(stime.c_str()); + m_usecs = 0; + }else{ + m_secs = atol(stime.substr(0, p).c_str()); + + string s_usecs = stime.substr(p+1, 6); + m_usecs = atol(stime.substr(p+1).c_str()); + m_usecs *= (unsigned long)pow(10.0, double(6 - s_usecs.length())); + } +} + +void Timestamp::setTime(double s) +{ + m_secs = (unsigned long)s; + m_usecs = (s - (double)m_secs) * 1e6; +} + +double Timestamp::getFloatTime() const { + return double(m_secs) + double(m_usecs)/1000000.0; +} + +string Timestamp::getStringTime() const { + char buf[32]; + sprintf(buf, "%.6lf", this->getFloatTime()); + return string(buf); +} + +double Timestamp::operator- (const Timestamp &t) const { + return this->getFloatTime() - t.getFloatTime(); +} + +Timestamp& Timestamp::operator+= (double s) +{ + *this = *this + s; + return *this; +} + +Timestamp& Timestamp::operator-= (double s) +{ + *this = *this - s; + return *this; +} + +Timestamp Timestamp::operator+ (double s) const +{ + unsigned long secs = (long)floor(s); + unsigned long usecs = (long)((s - (double)secs) * 1e6); + + return this->plus(secs, usecs); +} + +Timestamp Timestamp::plus(unsigned long secs, unsigned long usecs) const +{ + Timestamp t; + + const unsigned long max = 1000000ul; + + if(m_usecs + usecs >= max) + t.setTime(m_secs + secs + 1, m_usecs + usecs - max); + else + t.setTime(m_secs + secs, m_usecs + usecs); + + return t; +} + +Timestamp Timestamp::operator- (double s) const +{ + unsigned long secs = (long)floor(s); + unsigned long usecs = (long)((s - (double)secs) * 1e6); + + return this->minus(secs, usecs); +} + +Timestamp Timestamp::minus(unsigned long secs, unsigned long usecs) const +{ + Timestamp t; + + const unsigned long max = 1000000ul; + + if(m_usecs < usecs) + t.setTime(m_secs - secs - 1, max - (usecs - m_usecs)); + else + t.setTime(m_secs - secs, m_usecs - usecs); + + return t; +} + +bool Timestamp::operator> (const Timestamp &t) const +{ + if(m_secs > t.m_secs) return true; + else if(m_secs == t.m_secs) return m_usecs > t.m_usecs; + else return false; +} + +bool Timestamp::operator>= (const Timestamp &t) const +{ + if(m_secs > t.m_secs) return true; + else if(m_secs == t.m_secs) return m_usecs >= t.m_usecs; + else return false; +} + +bool Timestamp::operator< (const Timestamp &t) const +{ + if(m_secs < t.m_secs) return true; + else if(m_secs == t.m_secs) return m_usecs < t.m_usecs; + else return false; +} + +bool Timestamp::operator<= (const Timestamp &t) const +{ + if(m_secs < t.m_secs) return true; + else if(m_secs == t.m_secs) return m_usecs <= t.m_usecs; + else return false; +} + +bool Timestamp::operator== (const Timestamp &t) const +{ + return(m_secs == t.m_secs && m_usecs == t.m_usecs); +} + + +string Timestamp::Format(bool machine_friendly) const +{ + struct tm tm_time; + + time_t t = (time_t)getFloatTime(); + +#ifdef WIN32 + localtime_s(&tm_time, &t); +#else + localtime_r(&t, &tm_time); +#endif + + char buffer[128]; + + if(machine_friendly) + { + strftime(buffer, 128, "%Y%m%d_%H%M%S", &tm_time); + } + else + { + strftime(buffer, 128, "%c", &tm_time); // Thu Aug 23 14:55:02 2001 + } + + return string(buffer); +} + +string Timestamp::Format(double s) { + int days = int(s / (24. * 3600.0)); + s -= days * (24. * 3600.0); + int hours = int(s / 3600.0); + s -= hours * 3600; + int minutes = int(s / 60.0); + s -= minutes * 60; + int seconds = int(s); + int ms = int((s - seconds)*1e6); + + stringstream ss; + ss.fill('0'); + bool b; + if((b = (days > 0))) ss << days << "d "; + if((b = (b || hours > 0))) ss << setw(2) << hours << ":"; + if((b = (b || minutes > 0))) ss << setw(2) << minutes << ":"; + if(b) ss << setw(2); + ss << seconds; + if(!b) ss << "." << setw(6) << ms; + + return ss.str(); +} + + diff --git a/Thirdparty/DBoW2/DUtils/Timestamp.h b/Thirdparty/DBoW2/DUtils/Timestamp.h new file mode 100644 index 0000000..b92f89f --- /dev/null +++ b/Thirdparty/DBoW2/DUtils/Timestamp.h @@ -0,0 +1,204 @@ +/* + * File: Timestamp.h + * Author: Dorian Galvez-Lopez + * Date: March 2009 + * Description: timestamping functions + * License: see the LICENSE.txt file + * + */ + +#ifndef __D_TIMESTAMP__ +#define __D_TIMESTAMP__ + +#include +using namespace std; + +namespace DUtils { + +/// Timestamp +class Timestamp +{ +public: + + /// Options to initiate a timestamp + enum tOptions + { + NONE = 0, + CURRENT_TIME = 0x1, + ZERO = 0x2 + }; + +public: + + /** + * Creates a timestamp + * @param option option to set the initial time stamp + */ + Timestamp(Timestamp::tOptions option = NONE); + + /** + * Destructor + */ + virtual ~Timestamp(void); + + /** + * Says if the timestamp is "empty": seconds and usecs are both 0, as + * when initiated with the ZERO flag + * @return true iif secs == usecs == 0 + */ + bool empty() const; + + /** + * Sets this instance to the current time + */ + void setToCurrentTime(); + + /** + * Sets the timestamp from seconds and microseconds + * @param secs: seconds + * @param usecs: microseconds + */ + inline void setTime(unsigned long secs, unsigned long usecs){ + m_secs = secs; + m_usecs = usecs; + } + + /** + * Returns the timestamp in seconds and microseconds + * @param secs seconds + * @param usecs microseconds + */ + inline void getTime(unsigned long &secs, unsigned long &usecs) const + { + secs = m_secs; + usecs = m_usecs; + } + + /** + * Sets the timestamp from a string with the time in seconds + * @param stime: string such as "1235603336.036609" + */ + void setTime(const string &stime); + + /** + * Sets the timestamp from a number of seconds from the epoch + * @param s seconds from the epoch + */ + void setTime(double s); + + /** + * Returns this timestamp as the number of seconds in (long) float format + */ + double getFloatTime() const; + + /** + * Returns this timestamp as the number of seconds in fixed length string format + */ + string getStringTime() const; + + /** + * Returns the difference in seconds between this timestamp (greater) and t (smaller) + * If the order is swapped, a negative number is returned + * @param t: timestamp to subtract from this timestamp + * @return difference in seconds + */ + double operator- (const Timestamp &t) const; + + /** + * Returns a copy of this timestamp + s seconds + us microseconds + * @param s seconds + * @param us microseconds + */ + Timestamp plus(unsigned long s, unsigned long us) const; + + /** + * Returns a copy of this timestamp - s seconds - us microseconds + * @param s seconds + * @param us microseconds + */ + Timestamp minus(unsigned long s, unsigned long us) const; + + /** + * Adds s seconds to this timestamp and returns a reference to itself + * @param s seconds + * @return reference to this timestamp + */ + Timestamp& operator+= (double s); + + /** + * Substracts s seconds to this timestamp and returns a reference to itself + * @param s seconds + * @return reference to this timestamp + */ + Timestamp& operator-= (double s); + + /** + * Returns a copy of this timestamp + s seconds + * @param s: seconds + */ + Timestamp operator+ (double s) const; + + /** + * Returns a copy of this timestamp - s seconds + * @param s: seconds + */ + Timestamp operator- (double s) const; + + /** + * Returns whether this timestamp is at the future of t + * @param t + */ + bool operator> (const Timestamp &t) const; + + /** + * Returns whether this timestamp is at the future of (or is the same as) t + * @param t + */ + bool operator>= (const Timestamp &t) const; + + /** + * Returns whether this timestamp and t represent the same instant + * @param t + */ + bool operator== (const Timestamp &t) const; + + /** + * Returns whether this timestamp is at the past of t + * @param t + */ + bool operator< (const Timestamp &t) const; + + /** + * Returns whether this timestamp is at the past of (or is the same as) t + * @param t + */ + bool operator<= (const Timestamp &t) const; + + /** + * Returns the timestamp in a human-readable string + * @param machine_friendly if true, the returned string is formatted + * to yyyymmdd_hhmmss, without weekday or spaces + * @note This has not been tested under Windows + * @note The timestamp is truncated to seconds + */ + string Format(bool machine_friendly = false) const; + + /** + * Returns a string version of the elapsed time in seconds, with the format + * xd hh:mm:ss, hh:mm:ss, mm:ss or s.us + * @param s: elapsed seconds (given by getFloatTime) to format + */ + static string Format(double s); + + +protected: + /// Seconds + unsigned long m_secs; // seconds + /// Microseconds + unsigned long m_usecs; // microseconds +}; + +} + +#endif + diff --git a/Thirdparty/DBoW2/README.txt b/Thirdparty/DBoW2/README.txt new file mode 100644 index 0000000..71827f0 --- /dev/null +++ b/Thirdparty/DBoW2/README.txt @@ -0,0 +1,7 @@ +You should have received this DBoW2 version along with ORB-SLAM2 (https://github.com/raulmur/ORB_SLAM2). +See the original DBoW2 library at: https://github.com/dorian3d/DBoW2 +All files included in this version are BSD, see LICENSE.txt + +We also use Random.h, Random.cpp, Timestamp.pp and Timestamp.h from DLib/DUtils. +See the original DLib library at: https://github.com/dorian3d/DLib +All files included in this version are BSD, see LICENSE.txt diff --git a/Thirdparty/Pangolin/.clang-format b/Thirdparty/Pangolin/.clang-format new file mode 100644 index 0000000..9d15924 --- /dev/null +++ b/Thirdparty/Pangolin/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: false diff --git a/Thirdparty/Pangolin/.gitignore b/Thirdparty/Pangolin/.gitignore new file mode 100644 index 0000000..ca02887 --- /dev/null +++ b/Thirdparty/Pangolin/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +CMakeLists.txt.user +build* diff --git a/Thirdparty/Pangolin/.gitmodules b/Thirdparty/Pangolin/.gitmodules new file mode 100644 index 0000000..7676f39 --- /dev/null +++ b/Thirdparty/Pangolin/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/pybind11"] + path = external/pybind11 + url = https://github.com/pybind/pybind11.git diff --git a/Thirdparty/Pangolin/.travis.yml b/Thirdparty/Pangolin/.travis.yml new file mode 100644 index 0000000..d466bee --- /dev/null +++ b/Thirdparty/Pangolin/.travis.yml @@ -0,0 +1,30 @@ +sudo: required +dist: xenial + +before_install: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt -qq update ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt install -qq --no-install-suggests --no-install-recommends libeigen3-dev libglew-dev libc++-dev libwayland-dev libxkbcommon-dev wayland-protocols libegl1-mesa-dev; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pyenv versions && pyenv global system 3.7; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install eigen glew ; fi + +language: cpp + +matrix: + include: + - os: linux + compiler: gcc + env: PARALLEL_BUILD="-- -j 8" + - os: linux + compiler: clang + env: PARALLEL_BUILD="-- -j 8" + - os: osx + env: PARALLEL_BUILD="-- -j 8" + - os: windows + env: PARALLEL_BUILD="--parallel 8" + +script: + - mkdir build + - cd build + - cmake -D CMAKE_BUILD_TYPE=Release .. + - cmake --build . $PARALLEL_BUILD diff --git a/Thirdparty/Pangolin/CMakeLists.txt b/Thirdparty/Pangolin/CMakeLists.txt new file mode 100644 index 0000000..0e13110 --- /dev/null +++ b/Thirdparty/Pangolin/CMakeLists.txt @@ -0,0 +1,109 @@ +cmake_minimum_required(VERSION 2.8.12) +project("Pangolin") +set(PANGOLIN_VERSION_MAJOR 0) +set(PANGOLIN_VERSION_MINOR 6) +set(PANGOLIN_VERSION ${PANGOLIN_VERSION_MAJOR}.${PANGOLIN_VERSION_MINOR}) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/") + +# Platform configuration vars +include(SetPlatformVars) + +SET(CPACK_GENERATOR "DEB") + +SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Steven Lovegrove") +SET(CPACK_PACKAGE_VERSION_MAJOR ${PANGOLIN_VERSION_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${PANGOLIN_VERSION_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH "0") +include(CPack) + +option( BUILD_TESTS "Build Tests" ON ) +option( BUILD_TOOLS "Build Examples" ON ) +option( BUILD_EXAMPLES "Build Tools" ON ) + +set (CMAKE_CXX_STANDARD 14) + +if(_WIN_) + option( BUILD_SHARED_LIBS "Build Shared Library" OFF) + option( BUILD_EXTERN_GLEW "Automatically download, build and compile GLEW" ON) + option( BUILD_EXTERN_LIBPNG "Automatically download, build and compile libpng" ON) + option( BUILD_EXTERN_LIBJPEG "Automatically download, build and compile libjpeg" ON) + option( MSVC_USE_STATIC_CRT "Use static C Runtime with MSVC, /MT instead of /MD" ON) + + # Make sure there are no erroneous C Runtime flags + list(APPEND FLAG_VARS + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + ) + if(MSVC_USE_STATIC_CRT) + foreach(FLAG_VAR ${FLAG_VARS}) + string(REGEX REPLACE "/MD" "/MT" NEW_FLAGS "${${FLAG_VAR}}") + set(${FLAG_VAR} "${NEW_FLAGS}" CACHE STRING "" FORCE) + endforeach() + else() + foreach(FLAG_VAR ${FLAG_VARS}) + string(REGEX REPLACE "/MT" "/MD" NEW_FLAGS "${${FLAG_VAR}}") + set(${FLAG_VAR} "${NEW_FLAGS}" CACHE STRING "" FORCE) + endforeach() + endif() +else() + option( BUILD_SHARED_LIBS "Build Shared Library" ON) +endif() + +if(NOT MSVC) + set( CMAKE_CXX_FLAGS "-Wall -Wextra ${CMAKE_CXX_FLAGS}" ) +endif() + +if(ANDROID) + set(ANDROID_PACKAGE_NAME "com.github.stevenlovegrove.pangolin") + include(AndroidUtils) +endif() + +if(ANDROID OR IOS) + set(HAVE_GLES 1) + option(BUILD_FOR_GLES_2 "Build for OpenGL ES 2 instead of ES 1" ON ) + if(BUILD_FOR_GLES_2) + set(HAVE_GLES_2 1) + endif() +endif() + +if(_OSX_) + set(CMAKE_MACOSX_RPATH ON) +endif() + +# Overide with cmake -DCMAKE_BUILD_TYPE=Debug {dir} +if( NOT CMAKE_BUILD_TYPE AND NOT _WIN_ ) + message("Build type not set (defaults to release)") + message("-DCMAKE_BUILD_TYPE=Debug for debug") + set( CMAKE_BUILD_TYPE Release ) +endif() + +string(TOLOWER ${PROJECT_NAME} LIBRARY_NAME) + +# make an uninstall target +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY +) + +add_custom_target(pangolin_uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + +add_subdirectory("external") +add_subdirectory("src") + +if(BUILD_TESTS) + set(Pangolin_DIR ${Pangolin_BINARY_DIR}/src) + add_subdirectory("test") +endif() + +if(BUILD_TOOLS) + set(Pangolin_DIR ${Pangolin_BINARY_DIR}/src) + add_subdirectory(tools) +endif() + +if(BUILD_EXAMPLES) + set(Pangolin_DIR ${Pangolin_BINARY_DIR}/src) + add_subdirectory(examples) +endif() diff --git a/Thirdparty/Pangolin/LICENCE b/Thirdparty/Pangolin/LICENCE new file mode 100644 index 0000000..9b3c900 --- /dev/null +++ b/Thirdparty/Pangolin/LICENCE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Steven Lovegrove and Richard Newcombe + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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 OR COPYRIGHT +HOLDERS 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. diff --git a/Thirdparty/Pangolin/README.md b/Thirdparty/Pangolin/README.md new file mode 100644 index 0000000..5ef465b --- /dev/null +++ b/Thirdparty/Pangolin/README.md @@ -0,0 +1,176 @@ +What is Pangolin +==================================== + +Pangolin is a lightweight portable rapid development library for managing OpenGL +display / interaction and abstracting video input. At its heart is a simple +OpenGl viewport manager which can help to modularise 3D visualisation without +adding to its complexity, and offers an advanced but intuitive 3D navigation +handler. Pangolin also provides a mechanism for manipulating program variables +through config files and ui integration, and has a flexible real-time plotter +for visualising graphical data. + +The ethos of Pangolin is to reduce the boilerplate code that normally +gets written to visualise and interact with (typically image and 3D +based) systems, without compromising performance. It also enables write-once +code for a number of platforms, currently including Windows, Linux, OSX, Android +and IOS. + +## Code ## + +Find the latest version on [Github](http://github.com/stevenlovegrove/Pangolin): + +``` +git clone https://github.com/stevenlovegrove/Pangolin.git +``` + +## Dependencies ## + +Optional dependencies are enabled when found, otherwise they are silently disabled. +Check the CMake configure output for details. + +### Required Dependencies ### + +* C++11 + +* OpenGL (Desktop / ES / ES2) + * (lin) `sudo apt install libgl1-mesa-dev` + +* Glew + * (win) built automatically (assuming git is on your path) + * (deb) `sudo apt install libglew-dev` + * (mac) `sudo port install glew` + +* CMake (for build environment) + * (win) http://www.cmake.org/cmake/resources/software.html + * (deb) `sudo apt install cmake` + * (mac) `sudo port install cmake` + +### Recommended Dependencies ### + +* Python2 / Python3, for drop-down interactive console + * (win) http://www.python.org/downloads/windows + * (deb) `sudo apt install libpython2.7-dev` + * (mac) preinstalled with osx + * (for pybind11) `git submodule init && git submodule update` + * (useful modules) `sudo python -mpip install numpy pyopengl Pillow pybind11` + +* Wayland + * pkg-config: `sudo apt install pkg-config` + * Wayland and EGL:`sudo apt install libegl1-mesa-dev libwayland-dev libxkbcommon-dev wayland-protocols` + +### Optional Dependencies for video input ### + +* FFMPEG (For video decoding and image rescaling) + * (deb) `sudo apt install ffmpeg libavcodec-dev libavutil-dev libavformat-dev libswscale-dev libavdevice-dev` + +* DC1394 (For firewire input) + * (deb) `sudo apt install libdc1394-22-dev libraw1394-dev` + +* libuvc (For cross-platform webcam video input via libusb) + * git://github.com/ktossell/libuvc.git + +* libjpeg, libpng, libtiff, libopenexr (For reading still-image sequences) + * (deb) `sudo apt install libjpeg-dev libpng12-dev libtiff5-dev libopenexr-dev` + +* OpenNI / OpenNI2 (For Kinect / Xtrion / Primesense capture) + +* DepthSense SDK + +### Very Optional Dependencies ### + +* Eigen / TooN (These matrix types supported in the Pangolin API.) + +* CUDA Toolkit >= 3.2 (Some CUDA header-only interop utilities included) + * http://developer.nvidia.com/cuda-downloads + +* Doxygen for generating html / pdf documentation. + +## Building ## + +Pangolin uses the CMake portable pre-build tool. To checkout and build pangolin in the +directory 'build', execute the following at a shell (or the equivelent using a GUI): + +``` +git clone https://github.com/stevenlovegrove/Pangolin.git +cd Pangolin +mkdir build +cd build +cmake .. +cmake --build . +``` + +If you would like to build the documentation and you have Doxygen installed, you +can execute: + +``` +cmake --build . --target pangolin_doc +``` + +**On Windows**, Pangolin will attempt to download and build *glew*, *libjpeg*, *libpng* and *zlib* automatically. It does so assuming that git is available on the path - this assumption may be wrong for windows users who have downloaded Pangolin via a zip file on github. You will instead need to download and compile the dependencies manually, and set the BUILD_EXTERN_(lib) options to false for these libraries. The alternate and recommended approach is to install [gitbash](https://git-scm.com/downloads) and work from within their provided console. + +## Issues ## + +Please visit [Github Issues](https://github.com/stevenlovegrove/Pangolin/issues) to view and report problems with Pangolin. Issues and pull requests should be raised against the master branch which contains the current development version. + +Please note; most Pangolin dependencies are optional - to disable a dependency which may be causing trouble on your machine, set the BUILD_PANGOLIN_(option) variable to false with a cmake configuration tool (e.g. ccmake or cmake-gui). + +## Contributions and Continuous Integration ## + +For CI, Pangolin uses [travis-ci.org](https://travis-ci.org/stevenlovegrove/Pangolin) for Ubuntu, OSX and [ci.appveyor.com](https://ci.appveyor.com/project/stevenlovegrove/pangolin) for Windows. + +To contribute to Pangolin, I would appreciate pull requests against the master branch. This will trigger CI builds for your changes automatically, and help me to merge with confidence. + +## Binaries ## + +Binaries are available for Windows x64, as output by the Windows CI server: [Appveyor Artifacts](https://ci.appveyor.com/project/stevenlovegrove/pangolin/build/artifacts). + +## Bindings ## + +### Python ### + +Pangolin python bindings are enabled via [pybind11](www.pybind11.com). These bindings can be used both standalone and from within Pangolin's drop-down console (press the back-tick key, `). + +To enable the bindings, you must checkout the pybind submodule. To use pangolin in python, it's recommend to install a few other python packages too: + +``` +sudo python -mpip install numpy pyopengl Pillow pybind11 +git submodule init && git submodule update +``` + +The python module pypangolin must be on your python path, either through installation, or by setting it explicitly: + +``` +import sys +sys.path.append('path/of/pypangolin.so') +``` + +## Scheme syntax for windowing and video + +Pangolin uses 'URI' syntax for modularising video drivers and windowing backends. The syntax follows along the lines of `module_name:[option1=value1,option2=value2,...]//module_resource_to_open`. Some examples for using this URI syntax with the VideoViewer tool is as follows: + +``` +VideoViewer test:// +VideoViewer uvc:[size=640x480]///dev/video0 +VideoViewer flip://debayer:[tile=rggb,method=downsample]//file://~/somefile.pango +``` + +Notice that for video, some modules support chaining to construct a simple filter graph. See include/pangolin/video/video.h for more examples. + +For windowing, you can also customize default arguments for Pangolin applications by setting the `PANGOLIN_WINDOW_URI` environment variable. For instance, on high-DPI screens (in this example on OSX), you could set: + + +``` +setenv PANGOLIN_WINDOW_URI "cocoa:[HIGHRES=true]//" +``` + +Some window parameters that may be interesting to override are `DISPLAYNAME`, `DOUBLEBUFFER`, `SAMPLE_BUFFERS`, `SAMPLES`, `HIGHRES`. Window modules currently include `x11`, `winapi`, `cocoa`. + +## Acknowledgements ## + +I'd like to thank the growing number of kind contributors to Pangolin for helping to make it more stable and feature rich. Many features of Pangolin have been influenced by other projects such as GFlags, GLConsole, and libcvd in particular. I'd also like to thank the FOSS projects on which Pangolin depends. + +For a summary of those who have made code contributions, execute: + +``` +git shortlog -sne +``` diff --git a/Thirdparty/Pangolin/appveyor.yml b/Thirdparty/Pangolin/appveyor.yml new file mode 100644 index 0000000..313a193 --- /dev/null +++ b/Thirdparty/Pangolin/appveyor.yml @@ -0,0 +1,25 @@ +os: Visual Studio 2015 + +clone_folder: c:/projects/Pangolin + +platform: x64 +configuration: Release + +build: + verbosity: minimal + project: c:/projects/Pangolin/build/Pangolin.sln + +install: + - ps: wget http://bitbucket.org/eigen/eigen/get/3.2.10.zip -outfile eigen3.zip + - cmd: 7z x eigen3.zip -o"C:/projects" -y > nul + +before_build: + - cd c:/projects/Pangolin + - mkdir bin + - mkdir build + - cd build + - cmake -G "Visual Studio 14 2015 Win64" -D EIGEN3_INCLUDE_DIR=C:/projects/eigen-eigen-b9cd8366d4e8 -D CMAKE_INSTALL_PREFIX=../bin .. + +on_success: + - 7z a pangolin_build.zip "c:/projects/Pangolin/build/src/include" "c:/projects/Pangolin/build/src/Release/pangolin.lib" "c:/projects/Pangolin/build/tools/*/Release/*.exe" "c:/projects/Pangolin/build/examples/*/Release/*.exe" + - appveyor PushArtifact pangolin_build.zip diff --git a/Thirdparty/Pangolin/cmake_uninstall.cmake.in b/Thirdparty/Pangolin/cmake_uninstall.cmake.in new file mode 100644 index 0000000..6dc0777 --- /dev/null +++ b/Thirdparty/Pangolin/cmake_uninstall.cmake.in @@ -0,0 +1,25 @@ +# ----------------------------------------------- +# File that provides "make uninstall" target +# We use the file 'install_manifest.txt' +# ----------------------------------------------- +IF(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/Thirdparty/Pangolin/external/CMakeLists.txt b/Thirdparty/Pangolin/external/CMakeLists.txt new file mode 100644 index 0000000..c247f4c --- /dev/null +++ b/Thirdparty/Pangolin/external/CMakeLists.txt @@ -0,0 +1,153 @@ +include(ExternalProject) + +set(ExternConfig "") + +if( BUILD_EXTERN_GLEW ) + +######################################################### +# GLEW +######################################################### +ExternalProject_Add( __glew + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/glew" + GIT_REPOSITORY https://github.com/Perlmint/glew-cmake.git + GIT_TAG 7574ab4d00b683e56adbfdec7da636529dfe65d8 + INSTALL_DIR ${CMAKE_INSTALL_PREFIX} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} +) + +add_library(_glew STATIC IMPORTED GLOBAL) +add_dependencies(_glew __glew) +set_target_properties(_glew PROPERTIES + IMPORTED_LOCATION_RELWITHDEBINFO ${CMAKE_INSTALL_PREFIX}/lib/glew.lib + IMPORTED_LOCATION_RELEASE ${CMAKE_INSTALL_PREFIX}/lib/glew.lib + IMPORTED_LOCATION_DEBUG ${CMAKE_INSTALL_PREFIX}/lib/glewd.lib +) + +set(GLEW_FOUND true PARENT_SCOPE) +set(GLEW_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" PARENT_SCOPE) +set(GLEW_LIBRARY _glew PARENT_SCOPE) +set(GLEW_STATIC 1 PARENT_SCOPE) +set(ExternConfig "${ExternConfig} + add_library(_glew STATIC IMPORTED) + set_target_properties(_glew PROPERTIES + IMPORTED_LOCATION_RELWITHDEBINFO \"${CMAKE_INSTALL_PREFIX}/lib/glew.lib\" + IMPORTED_LOCATION_RELEASE \"${CMAKE_INSTALL_PREFIX}/lib/glew.lib\" + IMPORTED_LOCATION_DEBUG \"${CMAKE_INSTALL_PREFIX}/lib/glewd.lib\" + )") +endif() + +if( BUILD_EXTERN_LIBPNG ) + +######################################################### +# zlib +######################################################### + +ExternalProject_Add( __zlib + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/zlib" + GIT_REPOSITORY https://github.com/madler/zlib.git + GIT_TAG v1.2.8 + INSTALL_DIR ${CMAKE_INSTALL_PREFIX} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} +) +add_library(_zlib STATIC IMPORTED GLOBAL) +add_dependencies(_zlib __zlib) +set_target_properties(_zlib PROPERTIES + IMPORTED_LOCATION_RELEASE ${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib + IMPORTED_LOCATION_RELWITHDEBINFO ${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib + IMPORTED_LOCATION_DEBUG ${CMAKE_INSTALL_PREFIX}/lib/zlibstaticd.lib +) + +######################################################### +# libpng +######################################################### + +ExternalProject_Add( __libpng + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/libpng" + GIT_REPOSITORY https://github.com/glennrp/libpng.git + GIT_TAG v1.6.18 + INSTALL_DIR ${CMAKE_INSTALL_PREFIX} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DZLIB_INCLUDE_DIR=${CMAKE_INSTALL_PREFIX}/include + -DZLIB_LIBRARY=${CMAKE_INSTALL_PREFIX}/lib/zlibstatic*.lib + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} + DEPENDS __zlib +) + +add_library(_libpng STATIC IMPORTED GLOBAL) +add_dependencies(_libpng __libpng) +set_target_properties(_libpng PROPERTIES + IMPORTED_LOCATION_RELWITHDEBINFO ${CMAKE_INSTALL_PREFIX}/lib/libpng16_static.lib + IMPORTED_LOCATION_RELEASE ${CMAKE_INSTALL_PREFIX}/lib/libpng16_static.lib + IMPORTED_LOCATION_DEBUG ${CMAKE_INSTALL_PREFIX}/lib/libpng16_staticd.lib +) + +set(PNG_FOUND true PARENT_SCOPE) +set(PNG_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" PARENT_SCOPE) +set(PNG_LIBRARY _libpng PARENT_SCOPE) +set(ZLIB_LIBRARY _zlib PARENT_SCOPE) +set(ExternConfig "${ExternConfig} + add_library(_zlib STATIC IMPORTED) + set_target_properties(_zlib PROPERTIES + IMPORTED_LOCATION_RELEASE \"${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib\" + IMPORTED_LOCATION_RELWITHDEBINFO \"${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib\" + IMPORTED_LOCATION_DEBUG \"${CMAKE_INSTALL_PREFIX}/lib/zlibstaticd.lib\" + ) + add_library(_libpng STATIC IMPORTED) + set_target_properties(_libpng PROPERTIES + IMPORTED_LOCATION_RELEASE \"${CMAKE_INSTALL_PREFIX}/lib/libpng16_static.lib\" + IMPORTED_LOCATION_RELWITHDEBINFO \"${CMAKE_INSTALL_PREFIX}/lib/libpng16_static.lib\" + IMPORTED_LOCATION_DEBUG \"${CMAKE_INSTALL_PREFIX}/lib/libpng16_staticd.lib\" + )") +endif() + +if( BUILD_EXTERN_LIBJPEG ) + +######################################################### +# libjpg +######################################################### + +ExternalProject_Add( __libjpeg + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/libjpeg" + GIT_REPOSITORY https://github.com/LuaDist/libjpeg.git + GIT_TAG bc8f8be222287fec977ec3f47a5cb065cceb2ee9 + INSTALL_DIR ${CMAKE_INSTALL_PREFIX} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DBUILD_SHARED_LIBS=false + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} +) + +add_library(_libjpeg STATIC IMPORTED GLOBAL) +add_dependencies(_libjpeg __libjpeg) +set_target_properties(_libjpeg PROPERTIES + IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/jpeg.lib +) + +set(JPEG_FOUND true PARENT_SCOPE) +set(JPEG_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" PARENT_SCOPE) +set(JPEG_LIBRARY _libjpeg PARENT_SCOPE) +set(ExternConfig "${ExternConfig} + add_library(_libjpeg STATIC IMPORTED) + set_target_properties(_libjpeg PROPERTIES + IMPORTED_LOCATION \"${CMAKE_INSTALL_PREFIX}/lib/jpeg.lib\" + )") +endif() + +set(ExternConfig "${ExternConfig}" PARENT_SCOPE) diff --git a/Thirdparty/Pangolin/include/experimental/optional.hpp b/Thirdparty/Pangolin/include/experimental/optional.hpp new file mode 100644 index 0000000..e3722b0 --- /dev/null +++ b/Thirdparty/Pangolin/include/experimental/optional.hpp @@ -0,0 +1,1067 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# ifndef ___OPTIONAL_HPP___ +# define ___OPTIONAL_HPP___ + +# include +# include +# include +# include +# include +# include +# include + +# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if (defined __cplusplus) && (__cplusplus == 201103L) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +namespace std{ + +namespace experimental{ + +// BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template + using is_trivially_destructible = std::has_trivial_destructor; +# endif +// END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + +// workaround for missing traits in GCC and CLANG +template +struct is_nothrow_move_constructible +{ + constexpr static bool value = std::is_nothrow_constructible::value; +}; + + +template +struct is_assignable +{ + template + constexpr static bool has_assign(...) { return false; } + + template () = std::declval(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign(true); +}; + + +template +struct is_nothrow_move_assignable +{ + template + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template + struct has_nothrow_move_assign { + constexpr static bool value = noexcept( std::declval() = std::declval() ); + }; + + constexpr static bool value = has_nothrow_move_assign::value>::value; +}; +// end workaround + + +# endif + + + +// 20.5.4, optional for object types +template class optional; + +// 20.5.5, optional for lvalue reference types +template class optional; + + +// workaround: std utility functions aren't constexpr yet +template inline constexpr T&& constexpr_forward(typename std::remove_reference::type& t) noexcept +{ + return static_cast(t); +} + +template inline constexpr T&& constexpr_forward(typename std::remove_reference::type&& t) noexcept +{ + static_assert(!std::is_lvalue_reference::value, "!!"); + return static_cast(t); +} + +template inline constexpr typename std::remove_reference::type&& constexpr_move(T&& t) noexcept +{ + return static_cast::type&&>(t); +} + + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + +namespace detail_ +{ + +// static_addressof: a constexpr version of addressof +template +struct has_overloaded_addressof +{ + template + constexpr static bool has_overload(...) { return false; } + + template ().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload(true); +}; + +template )> +constexpr T* static_addressof(T& ref) +{ + return &ref; +} + +template )> +T* static_addressof(T& ref) +{ + return std::addressof(ref); +} + + +// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +template +constexpr U convert(U v) { return v; } + + +namespace swap_ns +{ + using std::swap; + + template + void adl_swap(T& t, T& u) noexcept(noexcept(swap(t, u))) + { + swap(t, u); + } + +} // namespace swap_ns + +} // namespace detail + + +constexpr struct trivial_init_t{} trivial_init{}; + + +// 20.5.6, In-place construction +constexpr struct in_place_t{} in_place{}; + + +// 20.5.7, Disengaged state indicator +struct nullopt_t +{ + struct init{}; + constexpr explicit nullopt_t(init){} +}; +constexpr nullopt_t nullopt{nullopt_t::init()}; + + +// 20.5.8, class bad_optional_access +class bad_optional_access : public logic_error { +public: + explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} +}; + + +template +union storage_t +{ + unsigned char dummy_; + T value_; + + constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template + constexpr storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + + ~storage_t(){} +}; + + +template +union constexpr_storage_t +{ + unsigned char dummy_; + T value_; + + constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template + constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + + ~constexpr_storage_t() = default; +}; + + +template +struct optional_base +{ + bool init_; + storage_t storage_; + + constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) {} + + template >)> + explicit optional_base(in_place_t, std::initializer_list il, Args&&... args) + : init_(true), storage_(il, std::forward(args)...) {} + + ~optional_base() { if (init_) storage_.value_.T::~T(); } +}; + + +template +struct constexpr_optional_base +{ + bool init_; + constexpr_storage_t storage_; + + constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list il, Args&&... args) + : init_(true), storage_(il, std::forward(args)...) {} + + ~constexpr_optional_base() = default; +}; + +template +using OptionalBase = typename std::conditional< + is_trivially_destructible::value, // if possible + constexpr_optional_base::type>, // use base with trivial destructor + optional_base::type> +>::type; + + + +template +class optional : private OptionalBase +{ + static_assert( !std::is_same::type, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same::type, in_place_t>::value, "bad T" ); + + + constexpr bool initialized() const noexcept { return OptionalBase::init_; } + typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage_.value_; } +# else + T& contained_val() & { return OptionalBase::storage_.value_; } + T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase::storage_.value_; } + T& contained_val() { return OptionalBase::storage_.value_; } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase::init_ = false; + } + + template + void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(std::forward(args)...); + OptionalBase::init_ = true; + } + + template + void initialize(std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(il, std::forward(args)...); + OptionalBase::init_ = true; + } + +public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase() {}; + + optional(const optional& rhs) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + optional(optional&& rhs) noexcept(is_nothrow_move_constructible::value) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(std::move(*rhs)); + OptionalBase::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase(v) {} + + constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} + + template + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase(in_place_t{}, constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list il, Args&&... args) + : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(is_nothrow_move_assignable::value && is_nothrow_move_constructible::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); + return *this; + } + + template + auto operator=(U&& v) + -> typename enable_if + < + is_same::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = std::forward(v); } + else { initialize(std::forward(v)); } + return *this; + } + + + template + void emplace(Args&&... args) + { + clear(); + initialize(std::forward(args)...); + } + + template + void emplace(initializer_list il, Args&&... args) + { + clear(); + initialize(il, std::forward(args)...); + } + + // 20.5.4.4, Swap + void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value + && noexcept(detail_::swap_ns::adl_swap(declval(), declval()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + constexpr bool has_value() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert (initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert (initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + if (!initialized()) throw bad_optional_access("bad optional access"); + return std::move(contained_val()); + } + +# else + + T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert (initialized()); + return contained_val(); + } + + constexpr T const& value() const { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + T& value() { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# else + + template + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# endif + +# else + + template + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# endif + + // 20.6.3.6, modifiers + void reset() noexcept { clear(); } +}; + + +template +class optional +{ + static_assert( !std::is_same::value, "bad T" ); + static_assert( !std::is_same::value, "bad T" ); + T* ref; + +public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + is_same::type, optional>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + !is_same::type, optional>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + + void swap(optional& rhs) noexcept + { + std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + constexpr bool has_value() const noexcept { + return ref != nullptr; + } + + template + constexpr typename decay::type value_or(V&& v) const + { + return *this ? **this : detail_::convert::type>(constexpr_forward(v)); + } + + // x.x.x.x, modifiers + void reset() noexcept { ref = nullptr; } +}; + + +template +class optional +{ + static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); +}; + + +// 20.5.8, Relational operators +template constexpr bool operator==(const optional& x, const optional& y) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template constexpr bool operator!=(const optional& x, const optional& y) +{ + return !(x == y); +} + +template constexpr bool operator<(const optional& x, const optional& y) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template constexpr bool operator>(const optional& x, const optional& y) +{ + return (y < x); +} + +template constexpr bool operator<=(const optional& x, const optional& y) +{ + return !(y < x); +} + +template constexpr bool operator>=(const optional& x, const optional& y) +{ + return !(x < y); +} + + +// 20.5.9, Comparison with nullopt +template constexpr bool operator==(const optional& x, nullopt_t) noexcept +{ + return (!x); +} + +template constexpr bool operator==(nullopt_t, const optional& x) noexcept +{ + return (!x); +} + +template constexpr bool operator!=(const optional& x, nullopt_t) noexcept +{ + return bool(x); +} + +template constexpr bool operator!=(nullopt_t, const optional& x) noexcept +{ + return bool(x); +} + +template constexpr bool operator<(const optional&, nullopt_t) noexcept +{ + return false; +} + +template constexpr bool operator<(nullopt_t, const optional& x) noexcept +{ + return bool(x); +} + +template constexpr bool operator<=(const optional& x, nullopt_t) noexcept +{ + return (!x); +} + +template constexpr bool operator<=(nullopt_t, const optional&) noexcept +{ + return true; +} + +template constexpr bool operator>(const optional& x, nullopt_t) noexcept +{ + return bool(x); +} + +template constexpr bool operator>(nullopt_t, const optional&) noexcept +{ + return false; +} + +template constexpr bool operator>=(const optional&, nullopt_t) noexcept +{ + return true; +} + +template constexpr bool operator>=(nullopt_t, const optional& x) noexcept +{ + return (!x); +} + + + +// 20.5.10, Comparison with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + + +// Comparison of optional with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + +// Comparison of optional with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + + +// 20.5.12, Specialized algorithms +template +void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) +{ + x.swap(y); +} + + +template +constexpr optional::type> make_optional(T&& v) +{ + return optional::type>(constexpr_forward(v)); +} + +template +constexpr optional make_optional(reference_wrapper v) +{ + return optional(v.get()); +} + + +} // namespace experimental +} // namespace std + +namespace std +{ + template + struct hash> + { + typedef typename hash::result_type result_type; + typedef std::experimental::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash{}(*arg) : result_type{}; + } + }; + + template + struct hash> + { + typedef typename hash::result_type result_type; + typedef std::experimental::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash{}(*arg) : result_type{}; + } + }; +} + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif //___OPTIONAL_HPP___ + diff --git a/Thirdparty/Pangolin/include/mpark/variant.hpp b/Thirdparty/Pangolin/include/mpark/variant.hpp new file mode 100644 index 0000000..fb2cf06 --- /dev/null +++ b/Thirdparty/Pangolin/include/mpark/variant.hpp @@ -0,0 +1,2468 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_VARIANT_HPP +#define MPARK_VARIANT_HPP + +/* + variant synopsis + +namespace std { + + // 20.7.2, class template variant + template + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template constexpr variant(T&&) noexcept(see below); + + template + constexpr explicit variant(in_place_type_t, Args&&...); + + template + constexpr explicit variant( + in_place_type_t, initializer_list, Args&&...); + + template + constexpr explicit variant(in_place_index_t, Args&&...); + + template + constexpr explicit variant( + in_place_index_t, initializer_list, Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template + T& emplace(Args&&...); + + template + T& emplace(initializer_list, Args&&...); + + template + variant_alternative& emplace(Args&&...); + + template + variant_alternative& emplace(initializer_list, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template struct variant_size; // undefined + + template + constexpr size_t variant_size_v = variant_size::value; + + template struct variant_size; + template struct variant_size; + template struct variant_size; + + template + struct variant_size>; + + template struct variant_alternative; // undefined + + template + using variant_alternative_t = typename variant_alternative::type; + + template struct variant_alternative; + template struct variant_alternative; + template struct variant_alternative; + + template + struct variant_alternative>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template + constexpr bool holds_alternative(const variant&) noexcept; + + template + constexpr variant_alternative_t>& + get(variant&); + + template + constexpr variant_alternative_t>&& + get(variant&&); + + template + constexpr variant_alternative_t> const& + get(const variant&); + + template + constexpr variant_alternative_t> const&& + get(const variant&&); + + template + constexpr T& get(variant&); + + template + constexpr T&& get(variant&&); + + template + constexpr const T& get(const variant&); + + template + constexpr const T&& get(const variant&&); + + template + constexpr add_pointer_t>> + get_if(variant*) noexcept; + + template + constexpr add_pointer_t>> + get_if(const variant*) noexcept; + + template + constexpr add_pointer_t + get_if(variant*) noexcept; + + template + constexpr add_pointer_t + get_if(const variant*) noexcept; + + // 20.7.5, relational operators + template + constexpr bool operator==(const variant&, const variant&); + + template + constexpr bool operator!=(const variant&, const variant&); + + template + constexpr bool operator<(const variant&, const variant&); + + template + constexpr bool operator>(const variant&, const variant&); + + template + constexpr bool operator<=(const variant&, const variant&); + + template + constexpr bool operator>=(const variant&, const variant&); + + // 20.7.6, visitation + template + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template + void swap(variant&, variant&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template struct hash; + template struct hash>; + template <> struct hash; + +} // namespace std + +*/ + +#include +#include +#include +#include +#include +#include +#include + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_CONFIG_HPP +#define MPARK_CONFIG_HPP + +// MSVC 2015 Update 3. +#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) +#error "MPark.Variant requires C++11 support." +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_include +#define __has_include(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_builtin(__builtin_addressof) || \ + (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) +#define MPARK_BUILTIN_ADDRESSOF +#endif + +#if __has_builtin(__builtin_unreachable) +#define MPARK_BUILTIN_UNREACHABLE +#endif + +#if __has_builtin(__type_pack_element) +#define MPARK_TYPE_PACK_ELEMENT +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 +#define MPARK_CPP14_CONSTEXPR +#endif + +#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ + (defined(_MSC_VER) && defined(_CPPUNWIND)) +#define MPARK_EXCEPTIONS +#endif + +#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) +#define MPARK_GENERIC_LAMBDAS +#endif + +#if defined(__cpp_lib_integer_sequence) +#define MPARK_INTEGER_SEQUENCE +#endif + +#if defined(__cpp_return_type_deduction) || defined(_MSC_VER) +#define MPARK_RETURN_TYPE_DEDUCTION +#endif + +#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) +#define MPARK_TRANSPARENT_OPERATORS +#endif + +#if defined(__cpp_variable_templates) || defined(_MSC_VER) +#define MPARK_VARIABLE_TEMPLATES +#endif + +#if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 +#define MPARK_TRIVIALITY_TYPE_TRAITS +#endif + +#endif // MPARK_CONFIG_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_IN_PLACE_HPP +#define MPARK_IN_PLACE_HPP + +#include + + +namespace mpark { + + struct in_place_t { explicit in_place_t() = default; }; + + template + struct in_place_index_t { explicit in_place_index_t() = default; }; + + template + struct in_place_type_t { explicit in_place_type_t() = default; }; + +#ifdef MPARK_VARIABLE_TEMPLATES + constexpr in_place_t in_place{}; + + template constexpr in_place_index_t in_place_index{}; + + template constexpr in_place_type_t in_place_type{}; +#endif + +} // namespace mpark + +#endif // MPARK_IN_PLACE_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_LIB_HPP +#define MPARK_LIB_HPP + +#include +#include +#include +#include + + +#define RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +namespace mpark { + namespace lib { + template + struct identity { using type = T; }; + + inline namespace cpp14 { + template + struct array { + constexpr const T &operator[](std::size_t index) const { + return data[index]; + } + + T data[N == 0 ? 1 : N]; + }; + + template + using add_pointer_t = typename std::add_pointer::type; + + template + using common_type_t = typename std::common_type::type; + + template + using decay_t = typename std::decay::type; + + template + using enable_if_t = typename std::enable_if::type; + + template + using remove_const_t = typename std::remove_const::type; + + template + using remove_reference_t = typename std::remove_reference::type; + + template + inline constexpr T &&forward(remove_reference_t &t) noexcept { + return static_cast(t); + } + + template + inline constexpr T &&forward(remove_reference_t &&t) noexcept { + static_assert(!std::is_lvalue_reference::value, + "can not forward an rvalue as an lvalue"); + return static_cast(t); + } + + template + inline constexpr remove_reference_t &&move(T &&t) noexcept { + return static_cast &&>(t); + } + +#ifdef MPARK_INTEGER_SEQUENCE + using std::integer_sequence; + using std::index_sequence; + using std::make_index_sequence; + using std::index_sequence_for; +#else + template + struct integer_sequence { + using value_type = T; + static constexpr std::size_t size() noexcept { return sizeof...(Is); } + }; + + template + using index_sequence = integer_sequence; + + template + struct make_index_sequence_concat; + + template + struct make_index_sequence_concat, + index_sequence> + : identity> {}; + + template + struct make_index_sequence_impl; + + template + using make_index_sequence = typename make_index_sequence_impl::type; + + template + struct make_index_sequence_impl + : make_index_sequence_concat, + make_index_sequence> {}; + + template <> + struct make_index_sequence_impl<0> : identity> {}; + + template <> + struct make_index_sequence_impl<1> : identity> {}; + + template + using index_sequence_for = make_index_sequence; +#endif + + // +#ifdef MPARK_TRANSPARENT_OPERATORS + using equal_to = std::equal_to<>; +#else + struct equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) == lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using not_equal_to = std::not_equal_to<>; +#else + struct not_equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) != lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less = std::less<>; +#else + struct less { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) < lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater = std::greater<>; +#else + struct greater { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) > lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less_equal = std::less_equal<>; +#else + struct less_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) <= lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater_equal = std::greater_equal<>; +#else + struct greater_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) >= lib::forward(rhs)) + }; +#endif + } // namespace cpp14 + + inline namespace cpp17 { + + // + template + using bool_constant = std::integral_constant; + + template + struct voider : identity {}; + + template + using void_t = typename voider::type; + + namespace detail { + namespace swappable { + + using std::swap; + + template + struct is_swappable { + private: + template (), + std::declval()))> + inline static std::true_type test(int); + + template + inline static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template ::value> + struct is_nothrow_swappable { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnoexcept" +#endif + static constexpr bool value = + noexcept(swap(std::declval(), std::declval())); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + }; + + template + struct is_nothrow_swappable : std::false_type {}; + + } // namespace swappable + } // namespace detail + + using detail::swappable::is_swappable; + using detail::swappable::is_nothrow_swappable; + + // +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline constexpr auto invoke(F &&f, As &&... as) + RETURN(lib::forward(f)(lib::forward(as)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + inline constexpr auto invoke(T B::*pmv, D &&d) + RETURN(lib::forward(d).*pmv) + + template + inline constexpr auto invoke(Pmv pmv, Ptr &&ptr) + RETURN((*lib::forward(ptr)).*pmv) + + template + inline constexpr auto invoke(T B::*pmf, D &&d, As &&... as) + RETURN((lib::forward(d).*pmf)(lib::forward(as)...)) + + template + inline constexpr auto invoke(Pmf pmf, Ptr &&ptr, As &&... as) + RETURN(((*lib::forward(ptr)).*pmf)(lib::forward(as)...)) + + namespace detail { + + template + struct invoke_result {}; + + template + struct invoke_result(), std::declval()...))>, + F, + Args...> + : identity(), std::declval()...))> {}; + + } // namespace detail + + template + using invoke_result = detail::invoke_result; + + template + using invoke_result_t = typename invoke_result::type; + + namespace detail { + + template + struct is_invocable : std::false_type {}; + + template + struct is_invocable>, F, Args...> + : std::true_type {}; + + template + struct is_invocable_r : std::false_type {}; + + template + struct is_invocable_r>, + R, + F, + Args...> + : std::is_convertible, R> {}; + + } // namespace detail + + template + using is_invocable = detail::is_invocable; + + template + using is_invocable_r = detail::is_invocable_r; + + // +#ifdef MPARK_BUILTIN_ADDRESSOF + template + inline constexpr T *addressof(T &arg) noexcept { + return __builtin_addressof(arg); + } +#else + namespace detail { + + namespace has_addressof_impl { + + struct fail; + + template + inline fail operator&(T &&); + + template + inline static constexpr bool impl() { + return (std::is_class::value || std::is_union::value) && + !std::is_same()), fail>::value; + } + + } // namespace has_addressof_impl + + template + using has_addressof = bool_constant()>; + + template + inline constexpr T *addressof(T &arg, std::true_type) noexcept { + return std::addressof(arg); + } + + template + inline constexpr T *addressof(T &arg, std::false_type) noexcept { + return &arg; + } + + } // namespace detail + + template + inline constexpr T *addressof(T &arg) noexcept { + return detail::addressof(arg, detail::has_addressof{}); + } +#endif + + template + inline constexpr T *addressof(const T &&) = delete; + + } // namespace cpp17 + + template + struct remove_all_extents : identity {}; + + template + struct remove_all_extents> : remove_all_extents {}; + + template + using remove_all_extents_t = typename remove_all_extents::type; + + template + using size_constant = std::integral_constant; + + template + struct indexed_type : size_constant, identity {}; + + template + using all = std::is_same, + integer_sequence>; + +#ifdef MPARK_TYPE_PACK_ELEMENT + template + using type_pack_element_t = __type_pack_element; +#else + template + struct type_pack_element_impl { + private: + template + struct set; + + template + struct set> : indexed_type... {}; + + template + inline static std::enable_if impl(indexed_type); + + inline static std::enable_if impl(...); + + public: + using type = decltype(impl(set>{})); + }; + + template + using type_pack_element = typename type_pack_element_impl::type; + + template + using type_pack_element_t = typename type_pack_element::type; +#endif + +#ifdef MPARK_TRIVIALITY_TYPE_TRAITS + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; + using std::is_trivially_copy_assignable; + using std::is_trivially_move_assignable; +#else + template + struct is_trivially_copy_constructible + : bool_constant< + std::is_copy_constructible::value && __has_trivial_copy(T)> {}; + + template + struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; + + template + struct is_trivially_copy_assignable + : bool_constant< + std::is_copy_assignable::value && __has_trivial_assign(T)> {}; + + template + struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; +#endif + + template + struct dependent_type : T {}; + + template + struct push_back; + + template + using push_back_t = typename push_back::type; + + template + struct push_back, J> { + using type = index_sequence; + }; + + } // namespace lib +} // namespace mpark + +#undef RETURN + +#endif // MPARK_LIB_HPP + + +namespace mpark { + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + +#define AUTO auto +#define AUTO_RETURN(...) { return __VA_ARGS__; } + +#define AUTO_REFREF auto && +#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } + +#define DECLTYPE_AUTO decltype(auto) +#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } + +#else + +#define AUTO auto +#define AUTO_RETURN(...) \ + -> lib::decay_t { return __VA_ARGS__; } + +#define AUTO_REFREF auto +#define AUTO_REFREF_RETURN(...) \ + -> decltype((__VA_ARGS__)) { \ + static_assert(std::is_reference::value, ""); \ + return __VA_ARGS__; \ + } + +#define DECLTYPE_AUTO auto +#define DECLTYPE_AUTO_RETURN(...) \ + -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +#endif + + class bad_variant_access : public std::exception { + public: + virtual const char *what() const noexcept { return "bad_variant_access"; } + }; + + [[noreturn]] inline void throw_bad_variant_access() { +#ifdef MPARK_EXCEPTIONS + throw bad_variant_access{}; +#else + std::terminate(); +#ifdef MPARK_BUILTIN_UNREACHABLE + __builtin_unreachable(); +#endif +#endif + } + + template + class variant; + + template + struct variant_size; + +#ifdef MPARK_VARIABLE_TEMPLATES + template + constexpr std::size_t variant_size_v = variant_size::value; +#endif + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size> : lib::size_constant {}; + + template + struct variant_alternative; + + template + using variant_alternative_t = typename variant_alternative::type; + + template + struct variant_alternative + : std::add_const> {}; + + template + struct variant_alternative + : std::add_volatile> {}; + + template + struct variant_alternative + : std::add_cv> {}; + + template + struct variant_alternative> { + static_assert(I < sizeof...(Ts), + "Index out of bounds in std::variant_alternative<>"); + using type = lib::type_pack_element_t; + }; + + constexpr std::size_t variant_npos = static_cast(-1); + + namespace detail { + + constexpr std::size_t not_found = static_cast(-1); + constexpr std::size_t ambiguous = static_cast(-2); + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr std::size_t find_index() { + constexpr lib::array matches = { + {std::is_same::value...} + }; + std::size_t result = not_found; + for (std::size_t i = 0; i < sizeof...(Ts); ++i) { + if (matches[i]) { + if (result != not_found) { + return ambiguous; + } + result = i; + } + } + return result; + } +#else + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t) { + return result; + } + + template + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t idx, + bool b, + Bs... bs) { + return b ? (result != not_found ? ambiguous + : find_index_impl(idx, idx + 1, bs...)) + : find_index_impl(result, idx + 1, bs...); + } + + template + inline constexpr std::size_t find_index() { + return find_index_impl(not_found, 0, std::is_same::value...); + } +#endif + + template + using find_index_sfinae_impl = + lib::enable_if_t>; + + template + using find_index_sfinae = find_index_sfinae_impl()>; + + template + struct find_index_checked_impl : lib::size_constant { + static_assert(I != not_found, "the specified type is not found."); + static_assert(I != ambiguous, "the specified type is ambiguous."); + }; + + template + using find_index_checked = find_index_checked_impl()>; + + struct valueless_t {}; + + enum class Trait { TriviallyAvailable, Available, Unavailable }; + + template class IsTriviallyAvailable, + template class IsAvailable> + inline constexpr Trait trait() { + return IsTriviallyAvailable::value + ? Trait::TriviallyAvailable + : IsAvailable::value ? Trait::Available + : Trait::Unavailable; + } + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr Trait common_trait(Traits... traits) { + Trait result = Trait::TriviallyAvailable; + for (Trait t : {traits...}) { + if (static_cast(t) > static_cast(result)) { + result = t; + } + } + return result; + } +#else + inline constexpr Trait common_trait_impl(Trait result) { return result; } + + template + inline constexpr Trait common_trait_impl(Trait result, + Trait t, + Traits... ts) { + return static_cast(t) > static_cast(result) + ? common_trait_impl(t, ts...) + : common_trait_impl(result, ts...); + } + + template + inline constexpr Trait common_trait(Traits... ts) { + return common_trait_impl(Trait::TriviallyAvailable, ts...); + } +#endif + + template + struct traits { + static constexpr Trait copy_constructible_trait = + common_trait(trait()...); + + static constexpr Trait move_constructible_trait = + common_trait(trait()...); + + static constexpr Trait copy_assignable_trait = + common_trait(copy_constructible_trait, + trait()...); + + static constexpr Trait move_assignable_trait = + common_trait(move_constructible_trait, + trait()...); + + static constexpr Trait destructible_trait = + common_trait(trait()...); + }; + + namespace access { + + struct recursive_union { +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { + return lib::forward(v).head_; + } + + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { + return get_alt(lib::forward(v).tail_, in_place_index_t{}); + } +#else + template + struct get_alt_impl { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) + }; + + template + struct get_alt_impl<0, Dummy> { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(lib::forward(v).head_) + }; + + template + inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) +#endif + }; + + struct base { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(recursive_union::get_alt( + data(lib::forward(v)), in_place_index_t{})) + }; + + struct variant { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) + }; + + } // namespace access + + namespace visitation { + + struct base { + template + inline static constexpr const T &at(const T &elem) noexcept { + return elem; + } + + template + inline static constexpr const lib::remove_all_extents_t &at( + const lib::array &elems, std::size_t i, Is... is) noexcept { + return at(elems[i], is...); + } + + template + inline static constexpr int visit_visitor_return_type_check() { + static_assert(lib::all::value...>::value, + "`mpark::visit` requires the visitor to have a single " + "return type."); + return 0; + } + + template + inline static constexpr lib::array< + lib::common_type_t...>, + sizeof...(Fs)> + make_farray(Fs &&... fs) { + using result = lib::array...>, + sizeof...(Fs)>; + return visit_visitor_return_type_check...>(), + result{{lib::forward(fs)...}}; + } + + template + struct dispatcher { + template + struct impl { + inline static constexpr DECLTYPE_AUTO dispatch(F f, Vs... vs) + DECLTYPE_AUTO_RETURN(lib::invoke( + static_cast(f), + access::base::get_alt(static_cast(vs))...)) + }; + }; + + template + inline static constexpr AUTO make_dispatch(lib::index_sequence) + AUTO_RETURN(&dispatcher::template impl::dispatch) + + template + inline static constexpr AUTO make_fdiagonal_impl() + AUTO_RETURN(make_dispatch( + lib::index_sequence::value...>{})) + + template + inline static constexpr AUTO make_fdiagonal_impl( + lib::index_sequence) + AUTO_RETURN(make_farray(make_fdiagonal_impl()...)) + + template + inline static constexpr /* auto * */ auto make_fdiagonal() + -> decltype(make_fdiagonal_impl( + lib::make_index_sequence::size()>{})) { + static_assert(lib::all<(lib::decay_t::size() == + lib::decay_t::size())...>::value, + "all of the variants must be the same size."); + return make_fdiagonal_impl( + lib::make_index_sequence::size()>{}); + } + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto make_fmatrix_impl(Is is) { + return make_dispatch(is); + } + + template + inline static constexpr auto make_fmatrix_impl( + Is, lib::index_sequence, Ls... ls) { + return make_farray(make_fmatrix_impl( + lib::push_back_t{}, ls...)...); + } + + template + inline static constexpr auto make_fmatrix() { + return make_fmatrix_impl( + lib::index_sequence<>{}, + lib::make_index_sequence::size()>{}...); + } +#else + template + struct make_fmatrix_impl { + template + struct impl; + + template + struct impl { + inline constexpr AUTO operator()() const + AUTO_RETURN(make_dispatch(Is{})) + }; + + template + struct impl, Ls...> { + inline constexpr AUTO operator()() const + AUTO_RETURN( + make_farray(impl, Ls...>{}()...)) + }; + }; + + template + inline static constexpr AUTO make_fmatrix() + AUTO_RETURN( + typename make_fmatrix_impl::template impl< + lib::index_sequence<>, + lib::make_index_sequence::size()>...>{}()) +#endif + }; // namespace base + + template + using FDiagonal = decltype(base::make_fdiagonal()); + + template + struct fdiagonal { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4268) +#endif + static constexpr FDiagonal value = + base::make_fdiagonal(); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + constexpr FDiagonal fdiagonal::value; + + template + using FMatrix = decltype(base::make_fmatrix()); + + template + struct fmatrix { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4268) +#endif + static constexpr FMatrix value = + base::make_fmatrix(); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + constexpr FMatrix fmatrix::value; + + struct alt { + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + fdiagonal(vs)))...>::value, + index)(lib::forward(visitor), + as_base(lib::forward(vs))...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + fmatrix(vs)))...>::value, + vs.index()...)(lib::forward(visitor), + as_base(lib::forward(vs))...)) + }; + + struct variant { + private: + template + struct visit_exhaustive_visitor_check { + static_assert( + lib::is_invocable::value, + "`mpark::visit` requires the visitor to be exhaustive."); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + inline constexpr DECLTYPE_AUTO operator()(Visitor &&visitor, + Values &&... values) const + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), + lib::forward(values)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + struct value_visitor { + Visitor &&visitor_; + + template + inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const + DECLTYPE_AUTO_RETURN( + visit_exhaustive_visitor_check< + Visitor, + decltype((lib::forward(alts).value))...>{}( + lib::forward(visitor_), + lib::forward(alts).value...)) + }; + + template + inline static constexpr AUTO make_value_visitor(Visitor &&visitor) + AUTO_RETURN(value_visitor{lib::forward(visitor)}) + + public: + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + alt::visit_alt_at(index, + lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt_at(index, + make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt(make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + }; + + } // namespace visitation + + template + struct alt { + using value_type = T; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + template + inline explicit constexpr alt(in_place_t, Args &&... args) + : value(lib::forward(args)...) {} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + T value; + }; + + template + union recursive_union; + + template + union recursive_union {}; + +#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ + template \ + union recursive_union { \ + public: \ + inline explicit constexpr recursive_union(valueless_t) noexcept \ + : dummy_{} {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t<0>, \ + Args &&... args) \ + : head_(in_place_t{}, lib::forward(args)...) {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t, \ + Args &&... args) \ + : tail_(in_place_index_t{}, lib::forward(args)...) {} \ + \ + recursive_union(const recursive_union &) = default; \ + recursive_union(recursive_union &&) = default; \ + \ + destructor \ + \ + recursive_union &operator=(const recursive_union &) = default; \ + recursive_union &operator=(recursive_union &&) = default; \ + \ + private: \ + char dummy_; \ + alt head_; \ + recursive_union tail_; \ + \ + friend struct access::recursive_union; \ + } + + MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, + ~recursive_union() = default;); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, + ~recursive_union() {}); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, + ~recursive_union() = delete;); + +#undef MPARK_VARIANT_RECURSIVE_UNION + + using index_t = unsigned int; + + template + class base { + public: + inline explicit constexpr base(valueless_t tag) noexcept + : data_(tag), index_(static_cast(-1)) {} + + template + inline explicit constexpr base(in_place_index_t, Args &&... args) + : data_(in_place_index_t{}, lib::forward(args)...), + index_(I) {} + + inline constexpr bool valueless_by_exception() const noexcept { + return index_ == static_cast(-1); + } + + inline constexpr std::size_t index() const noexcept { + return valueless_by_exception() ? variant_npos : index_; + } + + protected: + using data_t = recursive_union; + + friend inline constexpr base &as_base(base &b) { return b; } + friend inline constexpr const base &as_base(const base &b) { return b; } + friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } + friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } + + friend inline constexpr data_t &data(base &b) { return b.data_; } + friend inline constexpr const data_t &data(const base &b) { return b.data_; } + friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } + friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } + + inline static constexpr std::size_t size() { return sizeof...(Ts); } + + data_t data_; + index_t index_; + + friend struct access::base; + friend struct visitation::base; + }; + + struct dtor { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + +#if defined(_MSC_VER) && _MSC_VER < 1910 +#define INHERITING_CTOR(type, base) \ + template \ + inline explicit constexpr type(Args &&... args) \ + : base(lib::forward(args)...) {} +#else +#define INHERITING_CTOR(type, base) using base::base; +#endif + + template + class destructor; + +#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ + template \ + class destructor, destructible_trait> \ + : public base { \ + using super = base; \ + \ + public: \ + INHERITING_CTOR(destructor, super) \ + using super::operator=; \ + \ + destructor(const destructor &) = default; \ + destructor(destructor &&) = default; \ + definition \ + destructor &operator=(const destructor &) = default; \ + destructor &operator=(destructor &&) = default; \ + \ + protected: \ + destroy \ + } + + MPARK_VARIANT_DESTRUCTOR( + Trait::TriviallyAvailable, + ~destructor() = default;, + inline void destroy() noexcept { + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Available, + ~destructor() { destroy(); }, + inline void destroy() noexcept { + if (!this->valueless_by_exception()) { + visitation::alt::visit_alt(dtor{}, *this); + } + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Unavailable, + ~destructor() = delete;, + inline void destroy() noexcept = delete;); + +#undef MPARK_VARIANT_DESTRUCTOR + + template + class constructor : public destructor { + using super = destructor; + + public: + INHERITING_CTOR(constructor, super) + using super::operator=; + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + struct ctor { + template + inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { + constructor::construct_alt(lhs_alt, + lib::forward(rhs_alt).value); + } + }; +#endif + + template + inline static T &construct_alt(alt &a, Args &&... args) { + ::new (static_cast(lib::addressof(a))) + alt(in_place_t{}, lib::forward(args)...); + return a.value; + } + + template + inline static void generic_construct(constructor &lhs, Rhs &&rhs) { + lhs.destroy(); + if (!rhs.valueless_by_exception()) { + visitation::alt::visit_alt_at( + rhs.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &lhs_alt, auto &&rhs_alt) { + constructor::construct_alt( + lhs_alt, lib::forward(rhs_alt).value); + } +#else + ctor{} +#endif + , + lhs, + lib::forward(rhs)); + lhs.index_ = rhs.index_; + } + } + }; + + template + class move_constructor; + +#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ + template \ + class move_constructor, move_constructible_trait> \ + : public constructor> { \ + using super = constructor>; \ + \ + public: \ + INHERITING_CTOR(move_constructor, super) \ + using super::operator=; \ + \ + move_constructor(const move_constructor &) = default; \ + definition \ + ~move_constructor() = default; \ + move_constructor &operator=(const move_constructor &) = default; \ + move_constructor &operator=(move_constructor &&) = default; \ + } + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::TriviallyAvailable, + move_constructor(move_constructor &&that) = default;); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Available, + move_constructor(move_constructor &&that) noexcept( + lib::all::value...>::value) + : move_constructor(valueless_t{}) { + this->generic_construct(*this, lib::move(that)); + }); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Unavailable, + move_constructor(move_constructor &&) = delete;); + +#undef MPARK_VARIANT_MOVE_CONSTRUCTOR + + template + class copy_constructor; + +#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ + template \ + class copy_constructor, copy_constructible_trait> \ + : public move_constructor> { \ + using super = move_constructor>; \ + \ + public: \ + INHERITING_CTOR(copy_constructor, super) \ + using super::operator=; \ + \ + definition \ + copy_constructor(copy_constructor &&) = default; \ + ~copy_constructor() = default; \ + copy_constructor &operator=(const copy_constructor &) = default; \ + copy_constructor &operator=(copy_constructor &&) = default; \ + } + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::TriviallyAvailable, + copy_constructor(const copy_constructor &that) = default;); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Available, + copy_constructor(const copy_constructor &that) + : copy_constructor(valueless_t{}) { + this->generic_construct(*this, that); + }); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Unavailable, + copy_constructor(const copy_constructor &) = delete;); + +#undef MPARK_VARIANT_COPY_CONSTRUCTOR + + template + class assignment : public copy_constructor { + using super = copy_constructor; + + public: + INHERITING_CTOR(assignment, super) + using super::operator=; + + template + inline /* auto & */ auto emplace(Args &&... args) + -> decltype(this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...)) { + this->destroy(); + auto &result = this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...); + this->index_ = I; + return result; + } + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + template + struct assigner { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { + self->assign_alt(this_alt, lib::forward(that_alt).value); + } + assignment *self; + }; +#endif + + template + inline void assign_alt(alt &a, Arg &&arg) { + if (this->index() == I) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + a.value = lib::forward(arg); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + struct { + void operator()(std::true_type) const { + this_->emplace(lib::forward(arg_)); + } + void operator()(std::false_type) const { + this_->emplace(T(lib::forward(arg_))); + } + assignment *this_; + Arg &&arg_; + } impl{this, lib::forward(arg)}; + impl(lib::bool_constant< + std::is_nothrow_constructible::value || + !std::is_nothrow_move_constructible::value>{}); + } + } + + template + inline void generic_assign(That &&that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (that.valueless_by_exception()) { + this->destroy(); + } else { + visitation::alt::visit_alt_at( + that.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [this](auto &this_alt, auto &&that_alt) { + this->assign_alt( + this_alt, lib::forward(that_alt).value); + } +#else + assigner{this} +#endif + , + *this, + lib::forward(that)); + } + } + }; + + template + class move_assignment; + +#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ + template \ + class move_assignment, move_assignable_trait> \ + : public assignment> { \ + using super = assignment>; \ + \ + public: \ + INHERITING_CTOR(move_assignment, super) \ + using super::operator=; \ + \ + move_assignment(const move_assignment &) = default; \ + move_assignment(move_assignment &&) = default; \ + ~move_assignment() = default; \ + move_assignment &operator=(const move_assignment &) = default; \ + definition \ + } + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::TriviallyAvailable, + move_assignment &operator=(move_assignment &&that) = default;); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Available, + move_assignment & + operator=(move_assignment &&that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value)...>::value) { + this->generic_assign(lib::move(that)); + return *this; + }); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Unavailable, + move_assignment &operator=(move_assignment &&) = delete;); + +#undef MPARK_VARIANT_MOVE_ASSIGNMENT + + template + class copy_assignment; + +#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ + template \ + class copy_assignment, copy_assignable_trait> \ + : public move_assignment> { \ + using super = move_assignment>; \ + \ + public: \ + INHERITING_CTOR(copy_assignment, super) \ + using super::operator=; \ + \ + copy_assignment(const copy_assignment &) = default; \ + copy_assignment(copy_assignment &&) = default; \ + ~copy_assignment() = default; \ + definition \ + copy_assignment &operator=(copy_assignment &&) = default; \ + } + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::TriviallyAvailable, + copy_assignment &operator=(const copy_assignment &that) = default;); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Available, + copy_assignment &operator=(const copy_assignment &that) { + this->generic_assign(that); + return *this; + }); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Unavailable, + copy_assignment &operator=(const copy_assignment &) = delete;); + +#undef MPARK_VARIANT_COPY_ASSIGNMENT + + template + class impl : public copy_assignment> { + using super = copy_assignment>; + + public: + INHERITING_CTOR(impl, super) + using super::operator=; + + template + inline void assign(Arg &&arg) { + this->assign_alt(access::base::get_alt(*this), + lib::forward(arg)); + } + + inline void swap(impl &that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == that.index()) { + visitation::alt::visit_alt_at(this->index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &this_alt, auto &that_alt) { + using std::swap; + swap(this_alt.value, + that_alt.value); + } +#else + swapper{} +#endif + , + *this, + that); + } else { + impl *lhs = this; + impl *rhs = lib::addressof(that); + if (lhs->move_nothrow() && !rhs->move_nothrow()) { + std::swap(lhs, rhs); + } + impl tmp(lib::move(*rhs)); +#ifdef MPARK_EXCEPTIONS + // EXTENSION: When the move construction of `lhs` into `rhs` throws + // and `tmp` is nothrow move constructible then we move `tmp` back + // into `rhs` and provide the strong exception safety guarantee. + try { + this->generic_construct(*rhs, lib::move(*lhs)); + } catch (...) { + if (tmp.move_nothrow()) { + this->generic_construct(*rhs, lib::move(tmp)); + } + throw; + } +#else + this->generic_construct(*rhs, lib::move(*lhs)); +#endif + this->generic_construct(*lhs, lib::move(tmp)); + } + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct swapper { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { + using std::swap; + swap(this_alt.value, that_alt.value); + } + }; +#endif + + inline constexpr bool move_nothrow() const { + return this->valueless_by_exception() || + lib::array{ + {std::is_nothrow_move_constructible::value...} + }[this->index()]; + } + }; + + template + struct overload_leaf { + using F = lib::size_constant (*)(T); + operator F() const { return nullptr; } + }; + + template + struct overload_impl { + private: + template + struct impl; + + template + struct impl> : overload_leaf... {}; + + public: + using type = impl>; + }; + + template + using overload = typename overload_impl::type; + + template + using best_match = lib::invoke_result_t, T &&>; + + template + struct is_in_place_index : std::false_type {}; + + template + struct is_in_place_index> : std::true_type {}; + + template + struct is_in_place_type : std::false_type {}; + + template + struct is_in_place_type> : std::true_type {}; + + } // detail + + template + class variant { + static_assert(0 < sizeof...(Ts), + "variant must consist of at least one alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have an array type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a void type as an alternative."); + + public: + template < + typename Front = lib::type_pack_element_t<0, Ts...>, + lib::enable_if_t::value, int> = 0> + inline constexpr variant() noexcept( + std::is_nothrow_default_constructible::value) + : impl_(in_place_index_t<0>{}) {} + + variant(const variant &) = default; + variant(variant &&) = default; + + template < + typename Arg, + typename Decayed = lib::decay_t, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline constexpr variant(Arg &&arg) noexcept( + std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(arg)) {} + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_index_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_index_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_type_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_type_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + ~variant() = default; + + variant &operator=(const variant &) = default; + variant &operator=(variant &&) = default; + + template , variant>::value, + int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t<(std::is_assignable::value && + std::is_constructible::value), + int> = 0> + inline variant &operator=(Arg &&arg) noexcept( + (std::is_nothrow_assignable::value && + std::is_nothrow_constructible::value)) { + impl_.template assign(lib::forward(arg)); + return *this; + } + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + inline constexpr bool valueless_by_exception() const noexcept { + return impl_.valueless_by_exception(); + } + + inline constexpr std::size_t index() const noexcept { + return impl_.index(); + } + + template , + Dummy>::value && + lib::dependent_type, + Dummy>::value)...>::value, + int> = 0> + inline void swap(variant &that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + lib::is_nothrow_swappable::value)...>::value) { + impl_.swap(that.impl_); + } + + private: + detail::impl impl_; + + friend struct detail::access::variant; + friend struct detail::visitation::variant; + }; + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return v.index() == I; + } + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return holds_alternative::value>(v); + } + + namespace detail { + template + struct generic_get_impl { + constexpr generic_get_impl(int) noexcept {} + + constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN( + access::variant::get_alt(lib::forward(v)).value) + }; + + template + inline constexpr AUTO_REFREF generic_get(V &&v) + AUTO_REFREF_RETURN(generic_get_impl( + holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( + lib::forward(v))) + } // namespace detail + + template + inline constexpr variant_alternative_t> &get( + variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr variant_alternative_t> &&get( + variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr const variant_alternative_t> &get( + const variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr const variant_alternative_t> &&get( + const variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr T &get(variant &v) { + return get::value>(v); + } + + template + inline constexpr T &&get(variant &&v) { + return get::value>(lib::move(v)); + } + + template + inline constexpr const T &get(const variant &v) { + return get::value>(v); + } + + template + inline constexpr const T &&get(const variant &&v) { + return get::value>(lib::move(v)); + } + + namespace detail { + + template + inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept + AUTO_RETURN(v && holds_alternative(*v) + ? lib::addressof(access::variant::get_alt(*v).value) + : nullptr) + + } // namespace detail + + template + inline constexpr lib::add_pointer_t>> + get_if(variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t< + const variant_alternative_t>> + get_if(const variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(variant *v) noexcept { + return get_if::value>(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(const variant *v) noexcept { + return get_if::value>(v); + } + + template + inline constexpr bool operator==(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::equal_to; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return false; + if (lhs.valueless_by_exception()) return true; + return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); +#else + return lhs.index() == rhs.index() && + (lhs.valueless_by_exception() || + variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator!=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::not_equal_to; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); +#else + return lhs.index() != rhs.index() || + (!lhs.valueless_by_exception() && + variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator<(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::less; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); +#else + return !rhs.valueless_by_exception() && + (lhs.valueless_by_exception() || lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator>(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::greater; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return false; + if (rhs.valueless_by_exception()) return true; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); +#else + return !lhs.valueless_by_exception() && + (rhs.valueless_by_exception() || lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator<=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::less_equal; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); +#else + return lhs.valueless_by_exception() || + (!rhs.valueless_by_exception() && + (lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); +#endif + } + + template + inline constexpr bool operator>=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::greater_equal; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return true; + if (lhs.valueless_by_exception()) return false; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); +#else + return rhs.valueless_by_exception() || + (!lhs.valueless_by_exception() && + (lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at( + lhs.index(), greater_equal{}, lhs, rhs)))); +#endif + } + + struct monostate {}; + + inline constexpr bool operator<(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator>(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator<=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator>=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator==(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator!=(monostate, monostate) noexcept { + return false; + } + +#ifdef MPARK_CPP14_CONSTEXPR + namespace detail { + + inline constexpr bool all(std::initializer_list bs) { + for (bool b : bs) { + if (!b) { + return false; + } + } + return true; + } + + } // namespace detail + + template + inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { + return (detail::all({!vs.valueless_by_exception()...}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value( + lib::forward(visitor), lib::forward(vs)...); + } +#else + namespace detail { + + template + inline constexpr bool all_impl(const lib::array &bs, + std::size_t idx) { + return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); + } + + template + inline constexpr bool all(const lib::array &bs) { + return all_impl(bs, 0); + } + + } // namespace detail + + template + inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN( + (detail::all( + lib::array{{!vs.valueless_by_exception()...}}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value(lib::forward(visitor), + lib::forward(vs)...)) +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnoexcept" +#endif + template + inline auto swap(variant &lhs, + variant &rhs) noexcept(noexcept(lhs.swap(rhs))) + -> decltype(lhs.swap(rhs)) { + lhs.swap(rhs); + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + namespace detail { + + template + using enabled_type = T; + + namespace hash { + + template + constexpr bool meets_requirements() noexcept { + return std::is_copy_constructible::value && + std::is_move_constructible::value && + lib::is_invocable_r::value; + } + + template + constexpr bool is_enabled() noexcept { + using H = std::hash; + return meets_requirements() && + std::is_default_constructible::value && + std::is_copy_assignable::value && + std::is_move_assignable::value; + } + + } // namespace hash + + } // namespace detail + +#undef AUTO +#undef AUTO_RETURN + +#undef AUTO_REFREF +#undef AUTO_REFREF_RETURN + +#undef DECLTYPE_AUTO +#undef DECLTYPE_AUTO_RETURN + +} // namespace mpark + +namespace std { + + template + struct hash, + mpark::lib::enable_if_t>()...>::value>>> { + using argument_type = mpark::variant; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &v) const { + using mpark::detail::visitation::variant; + std::size_t result = + v.valueless_by_exception() + ? 299792458 // Random value chosen by the universe upon creation + : variant::visit_alt( +#ifdef MPARK_GENERIC_LAMBDAS + [](const auto &alt) { + using alt_type = mpark::lib::decay_t; + using value_type = mpark::lib::remove_const_t< + typename alt_type::value_type>; + return hash{}(alt.value); + } +#else + hasher{} +#endif + , + v); + return hash_combine(result, hash{}(v.index())); + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct hasher { + template + inline std::size_t operator()(const Alt &alt) const { + using alt_type = mpark::lib::decay_t; + using value_type = + mpark::lib::remove_const_t; + return hash{}(alt.value); + } + }; +#endif + + static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { + return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); + } + }; + + template <> + struct hash { + using argument_type = mpark::monostate; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &) const noexcept { + return 66740831; // return a fundamentally attractive random value. + } + }; + +} // namespace std + +#endif // MPARK_VARIANT_HPP diff --git a/Thirdparty/Pangolin/include/pangolin/compat/glutbitmap.h b/Thirdparty/Pangolin/include/pangolin/compat/glutbitmap.h new file mode 100644 index 0000000..b4661b0 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/compat/glutbitmap.h @@ -0,0 +1,92 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#ifdef HAVE_GLES +GLfloat g_raster_pos[4]; + +inline void glRasterPos3f(GLfloat x, GLfloat y, GLfloat z) +{ + // find object point (x,y,z)' in pixel coords + GLdouble projection[16]; + GLdouble modelview[16]; + GLint view[4]; + +#ifdef HAVE_GLES_2 + std::copy(pangolin::glEngine().projection.top().m, pangolin::glEngine().projection.top().m+16, projection); + std::copy(pangolin::glEngine().modelview.top().m, pangolin::glEngine().modelview.top().m+16, modelview); +#else + glGetDoublev(GL_PROJECTION_MATRIX, projection ); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview ); +#endif + glGetIntegerv(GL_VIEWPORT, view ); + + pangolin::glProject(x, y, z, modelview, projection, view, + g_raster_pos, g_raster_pos + 1, g_raster_pos + 2); +} + +inline void glRasterPos2f(GLfloat x, GLfloat y) +{ + glRasterPos3f(x,y,1.0f); +} + +inline void glRasterPos2i(GLint x, GLint y) +{ + glRasterPos3f((GLfloat)x, (GLfloat)y, 1.0f ); +} + +inline void glRasterPos3fv(const GLfloat *v){ + glRasterPos3f(v[0],v[1],v[2]); +} + +inline void glRasterPos2fv(const GLfloat *v){ + glRasterPos3f(v[0],v[1],1.0f); +} +#endif // HAVE_GLES + +inline void glutBitmapString(void * /*font*/, const unsigned char *str) +{ +#ifndef HAVE_GLES + float g_raster_pos[4]; + glGetFloatv(GL_CURRENT_RASTER_POSITION, g_raster_pos); +#endif + + pangolin::GlFont::I().Text( (const char *)str ).DrawWindow( + g_raster_pos[0], g_raster_pos[1], g_raster_pos[2] + ); +} + +inline int glutBitmapLength(void * /*font*/, const unsigned char *str) +{ + return (int)(pangolin::GlFont::I().Text((const char *)str).Width()); +} + +#define GLUT_BITMAP_HELVETICA_12 0; diff --git a/Thirdparty/Pangolin/include/pangolin/compat/optional.h b/Thirdparty/Pangolin/include/pangolin/compat/optional.h new file mode 100644 index 0000000..5d021d7 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/compat/optional.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +// Use either C++17 optional, or the standalone backwards compatible version +#if (__cplusplus >= 201703L) +# include +#else +# include +#endif + +namespace pangolin { +#if (__cplusplus >= 201703L) +template +using optional = std::optional; +#else +template +using optional = std::experimental::optional; +#endif +} diff --git a/Thirdparty/Pangolin/include/pangolin/compat/type_traits.h b/Thirdparty/Pangolin/include/pangolin/compat/type_traits.h new file mode 100644 index 0000000..30bec5b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/compat/type_traits.h @@ -0,0 +1,49 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include + +#include + +// enable_if From Boost +namespace pangolin +{ + template + struct enable_if_c { + typedef T type; + }; + + template + struct enable_if_c {}; + + template + struct enable_if : public enable_if_c {}; +} diff --git a/Thirdparty/Pangolin/include/pangolin/compat/variant.h b/Thirdparty/Pangolin/include/pangolin/compat/variant.h new file mode 100644 index 0000000..84ee74b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/compat/variant.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +// Use either C++17 variant, or the standalone backwards compatible version +// of M. Park. +#if (__cplusplus >= 201703L) +# include +#else +# include +#endif + +namespace pangolin { +#if (__cplusplus >= 201703L) +using std::variant; +using std::get; +using std::get_if; +using std::visit; +#else +using mpark::variant; +using mpark::get; +using mpark::get_if; +using mpark::visit; +#endif +} diff --git a/Thirdparty/Pangolin/include/pangolin/console/ConsoleInterpreter.h b/Thirdparty/Pangolin/include/pangolin/console/ConsoleInterpreter.h new file mode 100644 index 0000000..31d1e10 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/console/ConsoleInterpreter.h @@ -0,0 +1,80 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +enum ConsoleLineType +{ + ConsoleLineTypeCmd, + ConsoleLineTypeCmdOptions, + ConsoleLineTypeStdout, + ConsoleLineTypeStderr, + ConsoleLineTypeOutput, + ConsoleLineTypeHelp, +}; + +class ConsoleLine +{ +public: + inline ConsoleLine() + : linetype(ConsoleLineTypeCmd) + { + } + + inline ConsoleLine(std::string text, ConsoleLineType linetype = ConsoleLineTypeOutput) + : text(text), linetype(linetype) + { + } + + std::string text; + ConsoleLineType linetype; +}; + +class ConsoleInterpreter +{ +public: + inline virtual ~ConsoleInterpreter() + { + } + + virtual void PushCommand(const std::string& cmd) = 0; + + virtual bool PullLine(ConsoleLine& line) = 0; + + virtual std::vector Complete( + const std::string& cmd, int max_options = 20 + ) = 0; + +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/console/ConsoleView.h b/Thirdparty/Pangolin/include/pangolin/console/ConsoleView.h new file mode 100644 index 0000000..e45feab --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/console/ConsoleView.h @@ -0,0 +1,109 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace pangolin +{ + +class ConsoleView : public pangolin::View, pangolin::Handler +{ +public: + struct Line + { + Line() + : linetype(ConsoleLineTypeCmd) + { + } + + Line(const GlText& text, ConsoleLineType linetype = ConsoleLineTypeCmd ) + : text(text), linetype(linetype) + { + } + + GlText text; + ConsoleLineType linetype; + }; + + + // Construct with interpreter (and take ownership) + ConsoleView(ConsoleInterpreter* interpreter); + + ~ConsoleView(); + + View& ShowWithoutAnimation(bool show=true); + + // Replace implementation in View to account for hiding animation + View& Show(bool show=true); + + // Replace implementation in View to account for hiding animation + void ToggleShow(); + + // Replace implementation in View to account for hiding animation + bool IsShown() const; + + void Render() override; + + void Keyboard(View&, unsigned char key, int x, int y, bool pressed) override; + +private: + void DrawLine(const ConsoleView::Line& l, int carat); + + void ProcessOutputLines(); + + void AddLine(const std::string& text, ConsoleLineType linetype = ConsoleLineTypeCmd); + + Line* GetLine(int id, ConsoleLineType line_type, const std::string& prefix = ""); + + ConsoleInterpreter* interpreter; + + GlFont& font; + + int carat; + Line current_line; + std::deque line_buffer; + + bool hiding; + GLfloat bottom; + + Colour background_colour; + std::map line_colours; + float animation_speed; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/attach.h b/Thirdparty/Pangolin/include/pangolin/display/attach.h new file mode 100644 index 0000000..1bc776c --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/attach.h @@ -0,0 +1,86 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin +{ + +/// Units for measuring screen distances. +enum Unit { + Fraction, + Pixel, + ReversePixel +}; + +/// Defines absolute or relative position from parent viewport edge. +/// Constructors distinguised by whole pixels, or floating +/// fraction in interval [0,1] +struct PANGOLIN_EXPORT Attach { + /// Attach to Left/Bottom edge + Attach() : unit(Fraction), p(0) {} + + /// General constructor + Attach(Unit unit, GLfloat p) : unit(unit), p(p) {} + + /// Specify relative position in range [0,1]. + /// 0 represents leftmost / bottom-most edge, + /// 1 represents rightmost / topmost edge + Attach(GLfloat p) : unit(Fraction), p(p) { + // Allow for numerical imprecision when checking usage. + if( p < -1E-3 || 1.001 < p ) { + std::cerr << "Pangolin API Change: Display::SetBounds must be used with Attach::Pix or Attach::ReversePix to specify pixel bounds relative to an edge. See the code samples for details." << std::endl; + throw std::exception(); + } + } + + /// Specify absolute position from leftmost / bottom-most edge. + static Attach Pix(int p) { + return Attach(p >=0 ? Pixel : ReversePixel, std::abs((float)p)); + } + + /// Specify absolute position from rightmost / topmost edge. + static Attach ReversePix(int p) { + return Attach(ReversePixel, (GLfloat)p); + } + + /// Specify relative position in range [0,1]. + /// 0 represents leftmost / bottom-most edge, + /// 1 represents rightmost / topmost edge + static Attach Frac(float frac) { + return Attach(frac); + } + + Unit unit; + GLfloat p; +}; + +} // namespace pangolin diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/OsxWindow.h b/Thirdparty/Pangolin/include/pangolin/display/device/OsxWindow.h new file mode 100644 index 0000000..4d1be5d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/device/OsxWindow.h @@ -0,0 +1,68 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin +{ + +struct OsxWindow : public PangolinGl +{ + OsxWindow(const std::string& title, int width, int height, bool USE_RETINA); + + ~OsxWindow(); + + void StartFullScreen(); + + void StopFullScreen(); + + void ToggleFullscreen() override; + + void Move(int x, int y) override; + + void Resize(unsigned int w, unsigned int h) override; + + void MakeCurrent() override; + + void RemoveCurrent() override; + + void SwapBuffers() override; + + void ProcessEvents() override; + +private: + NSWindow* _window; + PangolinNSGLView *view; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSApplication.h b/Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSApplication.h new file mode 100644 index 0000000..799f375 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSApplication.h @@ -0,0 +1,59 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#import +#import + +//////////////////////////////////////////////////////////////////// +// PangolinNSApplication +//////////////////////////////////////////////////////////////////// + +@interface PangolinNSApplication : NSObject { +} + ++ (void)run_pre; ++ (void)run_step; + +@end + +//////////////////////////////////////////////////////////////////// +// PangolinWindowDelegate +//////////////////////////////////////////////////////////////////// + +@interface PangolinWindowDelegate : NSObject + +@end + +//////////////////////////////////////////////////////////////////// +// PangolinAppDelegate +//////////////////////////////////////////////////////////////////// + +@interface PangolinAppDelegate : NSObject + +@end diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSGLView.h b/Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSGLView.h new file mode 100644 index 0000000..5b8cef5 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/device/PangolinNSGLView.h @@ -0,0 +1,45 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#import +#import + +#include + +//////////////////////////////////////////////////////////////////// +// PangolinNSGLView +//////////////////////////////////////////////////////////////////// + +@interface PangolinNSGLView : NSOpenGLView +{ + pangolin::PangolinGl* context; + float backing_scale; +} +@end + diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/WinWindow.h b/Thirdparty/Pangolin/include/pangolin/display/device/WinWindow.h new file mode 100644 index 0000000..35e85ad --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/device/WinWindow.h @@ -0,0 +1,89 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace pangolin +{ + +struct WinWindow : public PangolinGl +{ + WinWindow( + const std::string& title, int width, int height + ); + + ~WinWindow(); + + void StartFullScreen(); + + void StopFullScreen(); + + void ToggleFullscreen() override; + + void Move(int x, int y) override; + + void Resize(unsigned int w, unsigned int h) override; + + void MakeCurrent() override; + + void RemoveCurrent() override; + + void SwapBuffers() override; + + void ProcessEvents() override; + + HGLRC GetGLRenderContext() + { + return hGLRC; + } + +private: + static LRESULT APIENTRY WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + + LRESULT HandleWinMessages(UINT message, WPARAM wParam, LPARAM lParam); + + void RegisterThisClass(HMODULE hCurrentInst); + + void SetupPixelFormat(HDC hdc); + + void SetupPalette(HDC hDC); + + // Owns the Window + HWND hWnd; + HDC hDC; + HGLRC hGLRC; + HPALETTE hPalette; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/X11GlContext.h b/Thirdparty/Pangolin/include/pangolin/display/device/X11GlContext.h new file mode 100644 index 0000000..e69de29 diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/X11Window.h b/Thirdparty/Pangolin/include/pangolin/display/device/X11Window.h new file mode 100644 index 0000000..c34c724 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/device/X11Window.h @@ -0,0 +1,109 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace pangolin +{ + +struct X11Display +{ + X11Display(const char* name = 0) { + XInitThreads(); + display = XOpenDisplay(name); + if (!display) { + throw std::runtime_error("Pangolin X11: Failed to open X display"); + } + } + + ~X11Display() { + XCloseDisplay(display); + } + + // Owns the display + ::Display* display; +}; + +struct X11GlContext : public GlContextInterface +{ + X11GlContext(std::shared_ptr &d, ::GLXFBConfig chosenFbc, std::shared_ptr shared_context = std::shared_ptr() ); + ~X11GlContext(); + + std::shared_ptr display; + + std::shared_ptr shared_context; + + // Owns the OpenGl Context + ::GLXContext glcontext; +}; + +struct X11Window : public PangolinGl +{ + X11Window( + const std::string& title, int width, int height, + std::shared_ptr& display, ::GLXFBConfig chosenFbc + ); + + ~X11Window(); + + void ToggleFullscreen() override; + + void Move(int x, int y) override; + + void Resize(unsigned int w, unsigned int h) override; + + void MakeCurrent(GLXContext ctx); + + void MakeCurrent() override; + + void RemoveCurrent() override; + + void SwapBuffers() override; + + void ProcessEvents() override; + + // References the X11 display and context. + std::shared_ptr display; + std::shared_ptr glcontext; + + // Owns the X11 Window and Colourmap + ::Window win; + ::Colormap cmap; + + Atom delete_message; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/device/display_android.h b/Thirdparty/Pangolin/include/pangolin/display/device/display_android.h new file mode 100644 index 0000000..b98a9b8 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/device/display_android.h @@ -0,0 +1,333 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "pango", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "pango", __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "pango", __VA_ARGS__)) + +/* For debug builds, always enable the debug traces in this library */ +#undef NDEBUG +#ifndef NDEBUG +# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "pango", __VA_ARGS__)) +#else +# define LOGV(...) ((void)0) +#endif + +template inline +void Log(T v) { + const std::string sv = pangolin::Convert::Do(v); + LOGI(sv.c_str()); +} + +template inline +void Log(const std::string& str, T v) +{ + const std::string sv = pangolin::Convert::Do(v); + LOGI((str + ":" + sv).c_str()); +} + +namespace pangolin +{ + void CreateAndroidWindowAndBind(std::string name); + void ProcessAndroidEvents(); + void FinishAndroidFrame(); +} + + +#ifdef __cplusplus +extern "C" { +#endif + +struct android_app; + +/** + * Data associated with an ALooper fd that will be returned as the "outData" + * when that source has data ready. + */ +struct android_poll_source { + // The identifier of this source. May be LOOPER_ID_MAIN or + // LOOPER_ID_INPUT. + int32_t id; + + // The android_app this ident is associated with. + struct android_app* app; + + // Function to call to perform the standard processing of data from + // this source. + void (*process)(struct android_app* app, struct android_poll_source* source); +}; + +/** + * This is the interface for the standard glue code of a threaded + * application. In this model, the application's code is running + * in its own thread separate from the main thread of the process. + * It is not required that this thread be associated with the Java + * VM, although it will need to be in order to make JNI calls any + * Java objects. + */ +struct android_app { + // The application can place a pointer to its own state object + // here if it likes. + void* userData; + + // Fill this in with the function to process main app commands (APP_CMD_*) + void (*onAppCmd)(struct android_app* app, int32_t cmd); + + // Fill this in with the function to process input events. At this point + // the event has already been pre-dispatched, and it will be finished upon + // return. Return 1 if you have handled the event, 0 for any default + // dispatching. + int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event); + + // The ANativeActivity object instance that this app is running in. + ANativeActivity* activity; + + // The current configuration the app is running in. + AConfiguration* config; + + // This is the last instance's saved state, as provided at creation time. + // It is NULL if there was no state. You can use this as you need; the + // memory will remain around until you call android_app_exec_cmd() for + // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. + // These variables should only be changed when processing a APP_CMD_SAVE_STATE, + // at which point they will be initialized to NULL and you can malloc your + // state and place the information here. In that case the memory will be + // freed for you later. + void* savedState; + size_t savedStateSize; + + // The ALooper associated with the app's thread. + ALooper* looper; + + // When non-NULL, this is the input queue from which the app will + // receive user input events. + AInputQueue* inputQueue; + + // When non-NULL, this is the window surface that the app can draw in. + ANativeWindow* window; + + // Current content rectangle of the window; this is the area where the + // window's content should be placed to be seen by the user. + ARect contentRect; + + // Current state of the app's activity. May be either APP_CMD_START, + // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. + int activityState; + + // This is non-zero when the application's NativeActivity is being + // destroyed and waiting for the app thread to complete. + int destroyRequested; + + // ------------------------------------------------- + // Below are "private" implementation of the glue code. + + pthread_mutex_t mutex; + pthread_cond_t cond; + + int msgread; + int msgwrite; + + pthread_t thread; + + struct android_poll_source cmdPollSource; + struct android_poll_source inputPollSource; + + int running; + int stateSaved; + int destroyed; + int redrawNeeded; + AInputQueue* pendingInputQueue; + ANativeWindow* pendingWindow; + ARect pendingContentRect; + + const char* application_so; +}; + +enum { + /** + * Looper data ID of commands coming from the app's main thread, which + * is returned as an identifier from ALooper_pollOnce(). The data for this + * identifier is a pointer to an android_poll_source structure. + * These can be retrieved and processed with android_app_read_cmd() + * and android_app_exec_cmd(). + */ + LOOPER_ID_MAIN = 1, + + /** + * Looper data ID of events coming from the AInputQueue of the + * application's window, which is returned as an identifier from + * ALooper_pollOnce(). The data for this identifier is a pointer to an + * android_poll_source structure. These can be read via the inputQueue + * object of android_app. + */ + LOOPER_ID_INPUT = 2, + + /** + * Start of user-defined ALooper identifiers. + */ + LOOPER_ID_USER = 3, +}; + +enum { + /** + * Command from main thread: the AInputQueue has changed. Upon processing + * this command, android_app->inputQueue will be updated to the new queue + * (or NULL). + */ + APP_CMD_INPUT_CHANGED, + + /** + * Command from main thread: a new ANativeWindow is ready for use. Upon + * receiving this command, android_app->window will contain the new window + * surface. + */ + APP_CMD_INIT_WINDOW, + + /** + * Command from main thread: the existing ANativeWindow needs to be + * terminated. Upon receiving this command, android_app->window still + * contains the existing window; after calling android_app_exec_cmd + * it will be set to NULL. + */ + APP_CMD_TERM_WINDOW, + + /** + * Command from main thread: the current ANativeWindow has been resized. + * Please redraw with its new size. + */ + APP_CMD_WINDOW_RESIZED, + + /** + * Command from main thread: the system needs that the current ANativeWindow + * be redrawn. You should redraw the window before handing this to + * android_app_exec_cmd() in order to avoid transient drawing glitches. + */ + APP_CMD_WINDOW_REDRAW_NEEDED, + + /** + * Command from main thread: the content area of the window has changed, + * such as from the soft input window being shown or hidden. You can + * find the new content rect in android_app::contentRect. + */ + APP_CMD_CONTENT_RECT_CHANGED, + + /** + * Command from main thread: the app's activity window has gained + * input focus. + */ + APP_CMD_GAINED_FOCUS, + + /** + * Command from main thread: the app's activity window has lost + * input focus. + */ + APP_CMD_LOST_FOCUS, + + /** + * Command from main thread: the current device configuration has changed. + */ + APP_CMD_CONFIG_CHANGED, + + /** + * Command from main thread: the system is running low on memory. + * Try to reduce your memory use. + */ + APP_CMD_LOW_MEMORY, + + /** + * Command from main thread: the app's activity has been started. + */ + APP_CMD_START, + + /** + * Command from main thread: the app's activity has been resumed. + */ + APP_CMD_RESUME, + + /** + * Command from main thread: the app should generate a new saved state + * for itself, to restore from later if needed. If you have saved state, + * allocate it with malloc and place it in android_app.savedState with + * the size in android_app.savedStateSize. The will be freed for you + * later. + */ + APP_CMD_SAVE_STATE, + + /** + * Command from main thread: the app's activity has been paused. + */ + APP_CMD_PAUSE, + + /** + * Command from main thread: the app's activity has been stopped. + */ + APP_CMD_STOP, + + /** + * Command from main thread: the app's activity is being destroyed, + * and waiting for the app thread to clean up and exit before proceeding. + */ + APP_CMD_DESTROY, +}; + +/** + * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next + * app command message. + */ +int8_t android_app_read_cmd(struct android_app* android_app); + +/** + * Call with the command returned by android_app_read_cmd() to do the + * initial pre-processing of the given command. You can perform your own + * actions for the command after calling this function. + */ +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); + +/** + * Call with the command returned by android_app_read_cmd() to do the + * final post-processing of the given command. You must have done your own + * actions for the command before calling this function. + */ +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); + +#ifdef __cplusplus +} +#endif diff --git a/Thirdparty/Pangolin/include/pangolin/display/display.h b/Thirdparty/Pangolin/include/pangolin/display/display.h new file mode 100644 index 0000000..987b90b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/display.h @@ -0,0 +1,219 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove, Richard Newcombe + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file display.h + * This file contains a number of global methods for creating and + * querying window state as well as handling user input. + */ + +namespace pangolin +{ + + // CreateWindowAndBind parameter key names. + // X11 Window options: + extern const char* PARAM_DISPLAYNAME; // std::string + extern const char* PARAM_DOUBLEBUFFER; // bool + extern const char* PARAM_SAMPLE_BUFFERS; // int + extern const char* PARAM_SAMPLES; // int + extern const char* PARAM_HIGHRES; // bool - Apple Retina screens only + + // Forward Declarations + struct View; + struct Viewport; + class UserApp; + + /// Give this OpenGL context a name or switch contexts. + /// This is required to initialise Pangolin for use with an + /// externally defined OpenGL context. You needn't call it + /// if you have used CreateWindowAndBind() to create a window + /// or launched a pangolin::UserApp + PANGOLIN_EXPORT + WindowInterface& BindToContext(std::string name); + + /// Initialise OpenGL window (determined by platform) and bind context. + /// This method will choose an available windowing system if one is present. + PANGOLIN_EXPORT + WindowInterface& CreateWindowAndBind(std::string window_title, int w = 640, int h = 480, const Params& params = Params()); + + /// Return pointer to current Pangolin Window context, or nullptr if none bound. + PANGOLIN_EXPORT + WindowInterface* GetBoundWindow(); + + PANGOLIN_EXPORT + void DestroyWindow(const std::string& window_title); + + /// Launch users derived UserApp, controlling OpenGL event loop. + /// This method will block until the application exits, calling app's + /// Init() method to start and Render() method subsequently to draw each frame. + /// @return exit code for use when returning from main. Currently always 0. + PANGOLIN_EXPORT + int LaunchUserApp(UserApp& app); + + /// Perform any post rendering, event processing and frame swapping. + PANGOLIN_EXPORT + void FinishFrame(); + + /// Request that the window close. + PANGOLIN_EXPORT + void Quit(); + + /// Request that all windows close. + PANGOLIN_EXPORT + void QuitAll(); + + /// Returns true if user has requested to close OpenGL window. + PANGOLIN_EXPORT + bool ShouldQuit(); + + /// Returns true if user has interacted with the window since this was last called. + PANGOLIN_EXPORT + bool HadInput(); + + /// Returns true if user has resized the window. + PANGOLIN_EXPORT + bool HasResized(); + + /// Renders any views with default draw methods. + PANGOLIN_EXPORT + void RenderViews(); + + /// Perform any post render events, such as screen recording. + PANGOLIN_EXPORT + void PostRender(); + + /// Request to be notified via functor when key is pressed. + /// Functor may take one parameter which will equal the key pressed + PANGOLIN_EXPORT + void RegisterKeyPressCallback(int key, std::function func); + + /// Save window contents to image. + PANGOLIN_EXPORT + void SaveWindowOnRender(std::string filename_prefix); + + PANGOLIN_EXPORT + void SaveFramebuffer(std::string prefix, const Viewport& v); + + namespace process + { + /// Tell pangolin to process input to drive display. + /// You will need to call this manually if you haven't let + /// Pangolin register callbacks from your windowing system + PANGOLIN_EXPORT + void Keyboard( unsigned char key, int x, int y); + + PANGOLIN_EXPORT + void KeyboardUp(unsigned char key, int x, int y); + + PANGOLIN_EXPORT + void SpecialFunc(int key, int x, int y); + + PANGOLIN_EXPORT + void SpecialFuncUp(int key, int x, int y); + + /// Tell pangolin base window size has changed + /// You will need to call this manually if you haven't let + /// Pangolin register callbacks from your windowing system + PANGOLIN_EXPORT + void Resize(int width, int height); + + /// Event based rendering entry point. Not currently supported. + PANGOLIN_EXPORT + void Display(); + + PANGOLIN_EXPORT + void Mouse( int button, int state, int x, int y); + + PANGOLIN_EXPORT + void MouseMotion( int x, int y); + + PANGOLIN_EXPORT + void PassiveMouseMotion(int x, int y); + + PANGOLIN_EXPORT + void Scroll(float x, float y); + + PANGOLIN_EXPORT + void Zoom(float m); + + PANGOLIN_EXPORT + void Rotate(float r); + + PANGOLIN_EXPORT + void SubpixMotion(float x, float y, float pressure, float rotation, float tiltx, float tilty); + + PANGOLIN_EXPORT + void SpecialInput(InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4); + + } + + /// Retrieve 'base' display, corresponding to entire window. + PANGOLIN_EXPORT + View& DisplayBase(); + + /// Create or retrieve named display managed by pangolin (automatically deleted). + PANGOLIN_EXPORT + View& Display(const std::string& name); + + /// Create unnamed display managed by pangolin (automatically deleted). + PANGOLIN_EXPORT + View& CreateDisplay(); + + /// Switch between windowed and fullscreen mode. + PANGOLIN_EXPORT + void ToggleFullscreen(); + + /// Switch windows/fullscreenmode = fullscreen. + PANGOLIN_EXPORT + void SetFullscreen(bool fullscreen = true); + + /// Toggle display of Pangolin console + PANGOLIN_EXPORT + void ToggleConsole(); + + /// Convenience functor for toggling pangolin::View. + /// Use with RegisterKeyPressCallback for example + struct ToggleViewFunctor { + inline ToggleViewFunctor(View& view); + inline ToggleViewFunctor(const std::string& name); + void operator()(); + View& view; + }; + +} + diff --git a/Thirdparty/Pangolin/include/pangolin/display/display_internal.h b/Thirdparty/Pangolin/include/pangolin/display/display_internal.h new file mode 100644 index 0000000..a39dea5 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/display_internal.h @@ -0,0 +1,138 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef BUILD_PANGOLIN_VIDEO +# include +#endif // BUILD_PANGOLIN_VIDEO + + +namespace pangolin +{ + +// Forward Declarations +#ifdef HAVE_PYTHON +class ConsoleView; +#endif // HAVE_PYTHON +class GlFont; + +typedef std::map ViewMap; +typedef std::map > KeyhookMap; + +struct PANGOLIN_EXPORT PangolinGl : public WindowInterface +{ + PangolinGl(); + ~PangolinGl(); + + // Base container for displays + View base; + + // Named views which are managed by pangolin (i.e. created / deleted by pangolin) + ViewMap named_managed_views; + + // Optional user app + UserApp* user_app; + + // Global keypress hooks + KeyhookMap keypress_hooks; + + // Manage fullscreen (ToggleFullscreen is quite new) + bool is_double_buffered; + bool is_fullscreen; + GLint windowed_size[2]; + bool is_high_res; + + // State relating to interactivity + bool quit; + int had_input; + int has_resized; + int mouse_state; + View* activeDisplay; + + std::queue > screen_capture; + +#ifdef BUILD_PANGOLIN_VIDEO + View* record_view; + VideoOutput recorder; +#endif + +#ifdef HAVE_PYTHON + ConsoleView* console_view; +#endif + + std::shared_ptr font; + + virtual void ToggleFullscreen() override { + pango_print_warn("ToggleFullscreen: Not available with non-pangolin window.\n"); + } + + virtual void ProcessEvents() override { + pango_print_warn("ProcessEvents: Not available with non-pangolin window.\n"); + } + + virtual void SwapBuffers() override { + pango_print_warn("SwapBuffers: Not available with non-pangolin window.\n"); + } + + virtual void MakeCurrent() override { + pango_print_warn("MakeCurrent: Not available with non-pangolin window.\n"); + } + + virtual void RemoveCurrent() override { + pango_print_warn("RemoveCurrent: Not available with non-pangolin window.\n"); + } + + virtual void Move(int /*x*/, int /*y*/) override { + pango_print_warn("Move: Not available with non-pangolin window.\n"); + } + + virtual void Resize(unsigned int /*w*/, unsigned int /*h*/) override { + pango_print_warn("Resize: Not available with non-pangolin window.\n"); + } + + +}; + +PangolinGl* GetCurrentContext(); +void RegisterNewContext(const std::string& name, std::shared_ptr newcontext); +void DeleteContext(const std::string& name); +PangolinGl *FindContext(const std::string& name); + +} + diff --git a/Thirdparty/Pangolin/include/pangolin/display/image_view.h b/Thirdparty/Pangolin/include/pangolin/display/image_view.h new file mode 100644 index 0000000..ce53cad --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/image_view.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace pangolin +{ + +class ImageView : public pangolin::View, public pangolin::ImageViewHandler +{ + public: + ImageView(); + + ~ImageView(); + + void Render() override; + + void Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state) override; + + void Keyboard(View& view, unsigned char key, int x, int y, bool pressed) override; + + pangolin::GlTexture& Tex(); + + ImageView& SetImage(void* ptr, size_t w, size_t h, size_t pitch, pangolin::GlPixFormat img_fmt, bool delayed_upload = false); + + ImageView& SetImage(const pangolin::Image& img, const pangolin::GlPixFormat& glfmt, bool delayed_upload = false); + + template inline + ImageView& SetImage(const pangolin::Image& img, bool delayed_upload = false) + { + return SetImage(img.template UnsafeReinterpret(), GlPixFormat::FromType(), delayed_upload); + } + + ImageView& SetImage(const pangolin::TypedImage& img, bool delayed_upload = false); + + ImageView& SetImage(const pangolin::GlTexture& texture); + + void LoadPending(); + + ImageView& Clear(); + + std::pair& GetOffsetScale(); + + bool MouseReleased() const; + + bool MousePressed() const; + + void SetRenderOverlay(const bool& val); + +// private: + // img_to_load contains image data that should be uploaded to the texture on + // the next render cycle. The data is owned by this object and should be + // freed after use. + pangolin::ManagedImage img_to_load; + pangolin::GlPixFormat img_fmt_to_load; + + std::pair offset_scale; + pangolin::GlPixFormat fmt; + pangolin::GlTexture tex; + bool lastPressed; + bool mouseReleased; + bool mousePressed; + bool overlayRender; + + std::mutex texlock; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/opengl_render_state.h b/Thirdparty/Pangolin/include/pangolin/display/opengl_render_state.h new file mode 100644 index 0000000..60de1b9 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/opengl_render_state.h @@ -0,0 +1,446 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include + +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files +#define USE_EIGEN +#endif + +#ifdef USE_EIGEN +#include +#include +#endif + +#ifdef HAVE_TOON +#include +#include +#include +#endif + +#ifdef HAVE_OCULUS +#include +#endif + +namespace pangolin { + +#ifdef HAVE_GLES + typedef float GLprecision; +#else + typedef double GLprecision; +#endif + +/// Capture OpenGL matrix types in enum to typing. +enum OpenGlStack { + GlModelViewStack = 0x1700, // GL_MODELVIEW + GlProjectionStack = 0x1701, // GL_PROJECTION + GlTextureStack = 0x1702 // GL_TEXTURE +}; + +enum AxisDirection +{ + AxisNone, + AxisNegX, AxisX, + AxisNegY, AxisY, + AxisNegZ, AxisZ +}; + +struct CameraSpec { + GLprecision forward[3]; + GLprecision up[3]; + GLprecision right[3]; + GLprecision img_up[2]; + GLprecision img_right[2]; +}; + +const static CameraSpec CameraSpecOpenGl = {{0,0,-1},{0,1,0},{1,0,0},{0,1},{1,0}}; + +const static CameraSpec CameraSpecYDownZForward = {{0,0,1},{0,-1,0},{1,0,0},{0,-1},{1,0}}; + +/// Direction vector for each AxisDirection enum +const static GLprecision AxisDirectionVector[7][3] = { + {0,0,0}, + {-1,0,0}, {1,0,0}, + {0,-1,0}, {0,1,0}, + {0,0,-1}, {0,0,1} +}; + +/// Object representing OpenGl Matrix. +struct PANGOLIN_EXPORT OpenGlMatrix { + static OpenGlMatrix Translate(GLprecision x, GLprecision y, GLprecision z); + static OpenGlMatrix Scale(GLprecision x, GLprecision y, GLprecision z); + static OpenGlMatrix RotateX(GLprecision theta_rad); + static OpenGlMatrix RotateY(GLprecision theta_rad); + static OpenGlMatrix RotateZ(GLprecision theta_rad); + + + template + static OpenGlMatrix ColMajor4x4(const P* col_major_4x4); + + OpenGlMatrix(); + +#ifdef USE_EIGEN + template + OpenGlMatrix(const Eigen::Matrix& mat); + + template + OpenGlMatrix(const Eigen::Transform& mat) : OpenGlMatrix(mat.matrix()) { } + + template + operator Eigen::Matrix() const; + + template + operator Eigen::Transform() const; +#endif // USE_EIGEN + +#ifdef HAVE_TOON + OpenGlMatrix(const TooN::SE3<>& T); + OpenGlMatrix(const TooN::Matrix<4,4>& M); + operator const TooN::SE3<>() const; + operator const TooN::Matrix<4,4>() const; +#endif // HAVE_TOON + +#ifdef HAVE_OCULUS + OpenGlMatrix(const OVR::Matrix4f& M); + operator const OVR::Matrix4f() const; +#endif // HAVE_OCULUS + + // Load matrix on to OpenGl stack + void Load() const; + + void Multiply() const; + + void SetIdentity(); + + OpenGlMatrix Transpose() const; + + OpenGlMatrix Inverse() const; + + GLprecision& operator()(int r, int c) { + return m[4*c +r]; + } + + GLprecision operator()(int r, int c) const { + return m[4 * c + r]; + } + + // Column major Internal buffer + GLprecision m[16]; +}; + +PANGOLIN_EXPORT +OpenGlMatrix operator*(const OpenGlMatrix& lhs, const OpenGlMatrix& rhs); + +PANGOLIN_EXPORT +std::ostream& operator<<(std::ostream& os, const OpenGlMatrix& mat); + +/// Deprecated. +struct PANGOLIN_EXPORT OpenGlMatrixSpec : public OpenGlMatrix { + // Specify which stack this refers to + OpenGlStack type; +}; + +/// Object representing attached OpenGl Matrices / transforms. +class PANGOLIN_EXPORT OpenGlRenderState +{ +public: + OpenGlRenderState(); + OpenGlRenderState(const OpenGlMatrix& projection_matrix); + OpenGlRenderState(const OpenGlMatrix& projection_matrix, const OpenGlMatrix& modelview_matrix); + + static void ApplyIdentity(); + + void Apply() const; + OpenGlRenderState& SetProjectionMatrix(OpenGlMatrix m); + OpenGlRenderState& SetModelViewMatrix(OpenGlMatrix m); + + OpenGlMatrix& GetProjectionMatrix(); + OpenGlMatrix GetProjectionMatrix() const; + + OpenGlMatrix& GetModelViewMatrix(); + OpenGlMatrix GetModelViewMatrix() const; + + OpenGlMatrix GetProjectionModelViewMatrix() const; + OpenGlMatrix GetProjectiveTextureMatrix() const; + + void EnableProjectiveTexturing() const; + void DisableProjectiveTexturing() const; + + //! Seemlessly move OpenGl camera relative to changes in T_wc, + //! whilst still enabling interaction + void Follow(const OpenGlMatrix& T_wc, bool follow = true); + void Unfollow(); + + // Experimental - subject to change + OpenGlMatrix& GetProjectionMatrix(unsigned int view); + OpenGlMatrix GetProjectionMatrix(unsigned int view) const; + OpenGlMatrix& GetViewOffset(unsigned int view); + OpenGlMatrix GetViewOffset(unsigned int view) const; + OpenGlMatrix GetModelViewMatrix(int i) const; + void ApplyNView(int view) const; + + PANGOLIN_DEPRECATED + OpenGlRenderState& Set(OpenGlMatrixSpec spec); + +protected: + OpenGlMatrix modelview; + std::vector projection; + std::vector modelview_premult; + OpenGlMatrix T_cw; + bool follow; +}; + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixRUB_BottomLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixRUB_TopLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixRDF_TopLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixRDF_TopRight(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixRDF_BottomLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixRDF_BottomRight(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +//! Use OpenGl's default frame RUB_BottomLeft +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrix(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar ); + +PANGOLIN_EXPORT +OpenGlMatrixSpec ProjectionMatrixOrthographic(GLprecision l, GLprecision r, GLprecision b, GLprecision t, GLprecision n, GLprecision f ); + + +//! Generate glulookat style model view matrix, looking at (lx,ly,lz) +//! X-Right, Y-Up, Z-Back +PANGOLIN_EXPORT +OpenGlMatrix ModelViewLookAtRUB(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz); + +//! Generate glulookat style model view matrix, looking at (lx,ly,lz) +//! X-Right, Y-Down, Z-Forward +PANGOLIN_EXPORT +OpenGlMatrix ModelViewLookAtRDF(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz); + +//! Generate glulookat style model view matrix, OpenGL Default camera convention (XYZ=RUB), looking at (lx,ly,lz) +PANGOLIN_EXPORT +OpenGlMatrix ModelViewLookAt(GLprecision x, GLprecision y, GLprecision z, GLprecision lx, GLprecision ly, GLprecision lz, AxisDirection up); + +PANGOLIN_EXPORT +OpenGlMatrix ModelViewLookAt(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz); + + +PANGOLIN_EXPORT +OpenGlMatrix IdentityMatrix(); + +PANGOLIN_EXPORT +OpenGlMatrixSpec IdentityMatrix(OpenGlStack type); + +PANGOLIN_EXPORT +OpenGlMatrixSpec negIdentityMatrix(OpenGlStack type); + +#ifdef HAVE_TOON +OpenGlMatrixSpec FromTooN(const TooN::SE3<>& T_cw); +OpenGlMatrixSpec FromTooN(OpenGlStack type, const TooN::Matrix<4,4>& M); +TooN::Matrix<4,4> ToTooN(const OpenGlMatrixSpec& ms); +TooN::SE3<> ToTooN_SE3(const OpenGlMatrixSpec& ms); +#endif + +#ifdef HAVE_EIGEN +template +Eigen::Matrix ToEigen(const OpenGlMatrix& ms); +#endif + +} + +// Inline definitions +namespace pangolin +{ + +template +inline OpenGlMatrix OpenGlMatrix::ColMajor4x4(const P* col_major_4x4) +{ + OpenGlMatrix mat; + std::copy(col_major_4x4, col_major_4x4 + 16, mat.m); + return mat; +} + +inline OpenGlMatrix::OpenGlMatrix() { +} + +#ifdef USE_EIGEN +template inline +OpenGlMatrix::OpenGlMatrix(const Eigen::Matrix& mat) +{ + for(int r=0; r<4; ++r ) { + for(int c=0; c<4; ++c ) { + m[c*4+r] = mat(r,c); + } + } +} + +template +OpenGlMatrix::operator Eigen::Matrix() const +{ + return ToEigen

(*this); +} + +template +OpenGlMatrix::operator Eigen::Transform() const +{ + return Eigen::Transform(ToEigen

(*this)); +} + +template inline +Eigen::Matrix ToEigen(const OpenGlMatrix& ms) +{ + Eigen::Matrix mat; + for(int r=0; r<4; ++r ) { + for(int c=0; c<4; ++c ) { + mat(r,c) = (P)ms.m[c*4+r]; + } + } + return mat; +} + +#endif // USE_EIGEN + +#ifdef HAVE_TOON +inline OpenGlMatrix::OpenGlMatrix(const TooN::SE3<>& T) +{ + TooN::Matrix<4,4,GLprecision,TooN::ColMajor> M; + M.slice<0,0,3,3>() = T.get_rotation().get_matrix(); + M.T()[3].slice<0,3>() = T.get_translation(); + M[3] = TooN::makeVector(0,0,0,1); + std::memcpy(m, &(M[0][0]),16*sizeof(GLprecision)); +} + +inline OpenGlMatrix::OpenGlMatrix(const TooN::Matrix<4,4>& M) +{ + // Read in remembering col-major convension for our matrices + int el = 0; + for(int c=0; c<4; ++c) + for(int r=0; r<4; ++r) + m[el++] = M[r][c]; +} + +inline OpenGlMatrix::operator const TooN::SE3<>() const +{ + const TooN::Matrix<4,4> m = *this; + const TooN::SO3<> R(m.slice<0,0,3,3>()); + const TooN::Vector<3> t = m.T()[3].slice<0,3>(); + return TooN::SE3<>(R,t); +} + +inline OpenGlMatrix::operator const TooN::Matrix<4,4>() const +{ + TooN::Matrix<4,4> M; + int el = 0; + for( int c=0; c<4; ++c ) + for( int r=0; r<4; ++r ) + M(r,c) = m[el++]; + return M; +} + +PANGOLIN_DEPRECATED +inline OpenGlMatrixSpec FromTooN(const TooN::SE3<>& T_cw) +{ + TooN::Matrix<4,4,GLprecision,TooN::ColMajor> M; + M.slice<0,0,3,3>() = T_cw.get_rotation().get_matrix(); + M.T()[3].slice<0,3>() = T_cw.get_translation(); + M[3] = TooN::makeVector(0,0,0,1); + + OpenGlMatrixSpec P; + P.type = GlModelViewStack; + std::memcpy(P.m, &(M[0][0]),16*sizeof(GLprecision)); + return P; +} + +PANGOLIN_DEPRECATED +inline OpenGlMatrixSpec FromTooN(OpenGlStack type, const TooN::Matrix<4,4>& M) +{ + // Read in remembering col-major convension for our matrices + OpenGlMatrixSpec P; + P.type = type; + int el = 0; + for(int c=0; c<4; ++c) + for(int r=0; r<4; ++r) + P.m[el++] = M[r][c]; + return P; +} + +PANGOLIN_DEPRECATED +inline TooN::Matrix<4,4> ToTooN(const OpenGlMatrix& ms) +{ + TooN::Matrix<4,4> m; + int el = 0; + for( int c=0; c<4; ++c ) + for( int r=0; r<4; ++r ) + m(r,c) = ms.m[el++]; + return m; +} + +PANGOLIN_DEPRECATED +inline TooN::SE3<> ToTooN_SE3(const OpenGlMatrix& ms) +{ + TooN::Matrix<4,4> m = ms; + const TooN::SO3<> R(m.slice<0,0,3,3>()); + const TooN::Vector<3> t = m.T()[3].slice<0,3>(); + return TooN::SE3<>(R,t); +} + +#endif // HAVE_TOON + +#ifdef HAVE_OCULUS +inline OpenGlMatrix::OpenGlMatrix(const OVR::Matrix4f& mat) +{ + for(int r=0; r<4; ++r ) + for(int c=0; c<4; ++c ) + m[c*4+r] = mat.M[r][c]; +} + +inline OpenGlMatrix::operator const OVR::Matrix4f() const +{ + OVR::Matrix4f mat; + for(int r=0; r<4; ++r ) + for(int c=0; c<4; ++c ) + mat.M[r][c] = m[c*4+r]; + return mat; +} +#endif // HAVE_OCULUS + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/user_app.h b/Thirdparty/Pangolin/include/pangolin/display/user_app.h new file mode 100644 index 0000000..013ad26 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/user_app.h @@ -0,0 +1,43 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT UserApp +{ +public: + virtual ~UserApp() {} + virtual void Init() {} + virtual void Render() = 0; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/view.h b/Thirdparty/Pangolin/include/pangolin/display/view.h new file mode 100644 index 0000000..b1650a3 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/view.h @@ -0,0 +1,235 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin +{ + +enum Layout +{ + LayoutOverlay, + LayoutVertical, + LayoutHorizontal, + LayoutEqual, + LayoutEqualVertical, + LayoutEqualHorizontal +}; + +enum Lock { + LockLeft = 0, + LockBottom = 0, + LockCenter = 1, + LockRight = 2, + LockTop = 2 +}; + +// Forward declarations +struct Handler; + +class OpenGlRenderState; + +/// A Display manages the location and resizing of an OpenGl viewport. +struct PANGOLIN_EXPORT View +{ + View(double aspect=0.0) + : aspect(aspect), top(1.0),left(0.0),right(1.0),bottom(0.0), hlock(LockCenter),vlock(LockCenter), + layout(LayoutOverlay), scroll_offset(0), show(1), zorder(0), handler(0), scroll_show(1) {} + + virtual ~View() {} + + //! Activate Displays viewport for drawing within this area + void Activate() const; + + //! Activate Displays and set State Matrices + void Activate(const OpenGlRenderState& state ) const; + + //! Activate Displays viewport and Scissor for drawing within this area + void ActivateAndScissor() const; + + //! Activate Displays viewport and Scissor for drawing within this area + void ActivateScissorAndClear() const; + + //! Activate Display and set State Matrices + void ActivateAndScissor(const OpenGlRenderState& state ) const; + + //! Activate Display and set State Matrices + void ActivateScissorAndClear(const OpenGlRenderState& state ) const; + + //! Activate Display and setup coordinate system for 2d pixel View coordinates + void ActivatePixelOrthographic() const; + + //! Activate Display and reset coordinate system to OpenGL default + void ActivateIdentity() const; + + //! Return closest depth buffer value within radius of window (winx,winy) + GLfloat GetClosestDepth(int winx, int winy, int radius) const; + + //! Obtain camera space coordinates of scene at pixel (winx, winy, winzdepth) + //! winzdepth can be obtained from GetClosestDepth + void GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const; + + //! Obtain object space coordinates of scene at pixel (winx, winy, winzdepth) + //! winzdepth can be obtained from GetClosestDepth + void GetObjectCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const; + + //! Given the specification of Display, compute viewport + virtual void Resize(const Viewport& parent); + + //! Instruct all children to resize + virtual void ResizeChildren(); + + //! Perform any automatic rendering for this View. + //! Default implementation simply instructs children to render themselves. + virtual void Render(); + + //! Instruct all children to render themselves if appropriate + virtual void RenderChildren(); + + //! Set this view as the active View to receive input + View& SetFocus(); + + //! Returns true iff this view currently has focus and will receive user input + bool HasFocus() const; + + //! Set bounds for the View using mixed fractional / pixel coordinates (OpenGl view coordinates) + View& SetBounds(Attach bottom, Attach top, Attach left, Attach right); + + //! Set bounds for the View using mixed fractional / pixel coordinates (OpenGl view coordinates) + View& SetBounds(Attach bottom, Attach top, Attach left, Attach right, bool keep_aspect); + + //! Set bounds for the View using mixed fractional / pixel coordinates (OpenGl view coordinates) + View& SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect); + + //! Designate handler for accepting mouse / keyboard input. + View& SetHandler(Handler* handler); + + //! Set drawFunc as the drawing function for this view + View& SetDrawFunction(const std::function& drawFunc); + + //! Force this view to have the given aspect, whilst fitting snuggly + //! within the parent. A negative value with 'over-draw', fitting the + //! smaller side of the parent. + View& SetAspect(double aspect); + + //! Set how this view should be positioned relative to its parent + View& SetLock(Lock horizontal, Lock vertical ); + + //! Set layout policy for this view + View& SetLayout(Layout layout); + + //! Add view as child + View& AddDisplay(View& view); + + //! Show / hide this view + View& Show(bool show=true); + + //! Toggle this views visibility + void ToggleShow(); + + //! Return whether this view should be shown. + //! This method should be checked if drawing manually + bool IsShown() const; + + //! Returns viewport reflecting space that will actually get drawn + //! The minimum of vp and v + Viewport GetBounds() const; + + //! Specify that this views region in the framebuffer should be saved to + //! a file just before the buffer is flipped. + void SaveOnRender(const std::string& filename_prefix); + + //! Specify that this views region in the framebuffer should be saved to + //! a video just before the buffer is flipped + void RecordOnRender(const std::string& record_uri); + + //! Uses the views default render method to draw into an FBO 'scale' times + //! the size of the view and save to a file. + void SaveRenderNow(const std::string& filename_prefix, float scale = 1); + + //! Return number of child views attached to this view + size_t NumChildren() const; + + //! Return (i)th child of this view + View& operator[](size_t i); + + //! Return number of visible child views attached to this view. + size_t NumVisibleChildren() const; + + //! Return visible child by index. + View& VisibleChild(size_t i); + + //! Return visible child at window coords x,y + View* FindChild(int x, int y); + + // Desired width / height aspect (0 if dynamic) + double aspect; + + // Bounds to fit display within + Attach top, left, right, bottom; + Lock hlock; + Lock vlock; + Layout layout; + + int scroll_offset; + + // Cached client area (space allocated from parent) + Viewport vp; + + // Cached absolute viewport (recomputed on resize - respects aspect) + Viewport v; + + // Should this view be displayed? + bool show; + + // Child views are rendered in order of low to high z-order + // Views default to 0 z-order + int zorder; + + // Input event handler (if any) + Handler* handler; + + // Map for sub-displays (if any) + std::vector views; + + // External draw function + std::function extern_draw_function; + +private: + // Private copy constructor + View(View&) { /* Do Not copy - take reference instead*/ } + + bool scroll_show; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/viewport.h b/Thirdparty/Pangolin/include/pangolin/display/viewport.h new file mode 100644 index 0000000..f3d75f1 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/viewport.h @@ -0,0 +1,65 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +/// Encapsulates OpenGl Viewport. +struct PANGOLIN_EXPORT Viewport +{ + Viewport() : l(0),b(0),w(0),h(0) {} + Viewport(GLint l,GLint b,GLint w,GLint h) : l(l),b(b),w(w),h(h) {} + + void Activate() const; + void ActivateIdentity() const; + void ActivatePixelOrthographic() const; + + void Scissor() const; + void ActivateAndScissor() const; + + bool Contains(int x, int y) const; + + Viewport Inset(int i) const; + Viewport Inset(int horiz, int vert) const; + Viewport Intersect(const Viewport& vp) const; + + void GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const; + + static void DisableScissor(); + + GLint r() const { return l+w;} + GLint t() const { return b+h;} + GLfloat aspect() const { return (GLfloat)w / (GLfloat)h; } + GLint l,b,w,h; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/widgets/widgets.h b/Thirdparty/Pangolin/include/pangolin/display/widgets/widgets.h new file mode 100644 index 0000000..1991ee8 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/widgets/widgets.h @@ -0,0 +1,141 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace pangolin +{ + +PANGOLIN_EXPORT +View& CreatePanel(const std::string& name); + +struct PANGOLIN_EXPORT Panel : public View +{ + Panel(); + Panel(const std::string& auto_register_var_prefix); + void Render(); + void ResizeChildren(); + static void AddVariable(void* data, const std::string& name, VarValueGeneric& var, bool brand_new); +}; + +template +struct Widget : public View, Handler, Var +{ + Widget(std::string title, VarValueGeneric& tv) + : Var(tv), title(title) + { + handler = this; + } + + std::string title; +}; + +struct PANGOLIN_EXPORT Button : public Widget +{ + Button(std::string title, VarValueGeneric& tv); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void Render(); + + //Cache params on resize + void ResizeChildren(); + GlText gltext; + GLfloat raster[2]; + bool down; +}; + +struct PANGOLIN_EXPORT FunctionButton : public Widget > +{ + FunctionButton(std::string title, VarValueGeneric& tv); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void Render(); + + //Cache params on resize + void ResizeChildren(); + GlText gltext; + GLfloat raster[2]; + bool down; +}; + +struct PANGOLIN_EXPORT Checkbox : public Widget +{ + Checkbox(std::string title, VarValueGeneric& tv); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void Render(); + + //Cache params on resize + void ResizeChildren(); + GlText gltext; + GLfloat raster[2]; + Viewport vcb; +}; + +struct PANGOLIN_EXPORT Slider : public Widget +{ + Slider(std::string title, VarValueGeneric& tv); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void MouseMotion(View&, int x, int y, int mouse_state); + void Keyboard(View&, unsigned char key, int x, int y, bool pressed); + void Render(); + + //Cache params on resize + void ResizeChildren(); + GlText gltext; + GLfloat raster[2]; + bool lock_bounds; + bool logscale; + bool is_integral_type; +}; + +struct PANGOLIN_EXPORT TextInput : public Widget +{ + TextInput(std::string title, VarValueGeneric& tv); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void MouseMotion(View&, int x, int y, int mouse_state); + void Keyboard(View&, unsigned char key, int x, int y, bool pressed); + void Render(); + + std::string edit; + GlText gledit; + + //Cache params on resize + void ResizeChildren(); + GlText gltext; + GLfloat raster[2]; + bool can_edit; + bool do_edit; + int sel[2]; +}; + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/display/window.h b/Thirdparty/Pangolin/include/pangolin/display/window.h new file mode 100644 index 0000000..7e2dd59 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/display/window.h @@ -0,0 +1,90 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2016 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once +#include +#include +#include + +namespace pangolin +{ + +class GlContextInterface +{ +public: + virtual ~GlContextInterface() {} +}; + +class WindowInterface +{ +public: + virtual ~WindowInterface() {} + + virtual void ToggleFullscreen() = 0; + + virtual void Move(int x, int y) = 0; + + virtual void Resize(unsigned int w, unsigned int h) = 0; + + /** + * @brief MakeCurrent set the current context + * to be called in a thread before accessing OpenGL + */ + virtual void MakeCurrent() = 0; + + /** + * @brief RemoveCurrent remove the current context + * to be called at the end of a thread + */ + virtual void RemoveCurrent() = 0; + + virtual void ProcessEvents() = 0; + + virtual void SwapBuffers() = 0; +}; + + +struct PANGOLIN_EXPORT WindowException : std::exception +{ + WindowException(std::string str) : desc(str) {} + WindowException(std::string str, std::string detail) { + desc = str + "\n\t" + detail; + } + ~WindowException() throw() {} + const char* what() const throw() { return desc.c_str(); } + std::string desc; +}; + +struct PANGOLIN_EXPORT WindowExceptionNoKnownHandler : public WindowException +{ + WindowExceptionNoKnownHandler(const std::string& scheme) + : WindowException("No known window handler for URI '" + scheme + "'") + { + } +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/factory/factory_registry.h b/Thirdparty/Pangolin/include/pangolin/factory/factory_registry.h new file mode 100644 index 0000000..1ca8382 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/factory/factory_registry.h @@ -0,0 +1,114 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011-2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace pangolin +{ + +template +struct FactoryInterface +{ + typedef T FactoryItem; + + virtual ~FactoryInterface() = default; + virtual std::unique_ptr Open(const Uri& uri) = 0; +}; + +template +class FactoryRegistry +{ +public: + // IMPORTANT: Implement for each templated instantiation within a seperate compilation unit. + static FactoryRegistry& I(); + + ~FactoryRegistry() + { + } + + void RegisterFactory(std::shared_ptr> factory, uint32_t precedence, const std::string& scheme_name ) + { + FactoryItem item = {precedence, scheme_name, factory}; + factories.push_back( item ); + std::sort(factories.begin(), factories.end()); + } + + void UnregisterFactory(FactoryInterface* factory) + { + for( auto i = factories.end()-1; i != factories.begin(); --i) + { + if( i->factory.get() == factory ) { + factories.erase(i); + } + } + } + + void UnregisterAllFactories() + { + factories.clear(); + } + + std::unique_ptr Open(const Uri& uri) + { + // Iterate over all registered factories in order of precedence. + for(auto& item : factories) { + if( item.scheme == uri.scheme) { + std::unique_ptr video = item.factory->Open(uri); + if(video) { + return video; + } + } + } + + return std::unique_ptr(); + } + +private: + struct FactoryItem + { + uint32_t precedence; + std::string scheme; + std::shared_ptr> factory; + + bool operator<(const FactoryItem& rhs) const { + return precedence < rhs.precedence; + } + }; + + // Priority, Factory tuple + std::vector factories; +}; + +#define PANGOLIN_REGISTER_FACTORY(x) void Register ## x ## Factory() + +} diff --git a/Thirdparty/Pangolin/include/pangolin/geometry/geometry.h b/Thirdparty/Pangolin/include/pangolin/geometry/geometry.h new file mode 100644 index 0000000..be001d0 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/geometry/geometry.h @@ -0,0 +1,95 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#ifndef PANGOLIN_GEOMETRY_H +#define PANGOLIN_GEOMETRY_H + +#include +#include +#include +#include +#include + +#ifdef HAVE_EIGEN +#include +#endif + +namespace pangolin +{ + +struct Geometry +{ + struct Element : public ManagedImage { + Element() = default; + Element(Element&&) = default; + Element& operator=(Element&&) = default; + + Element(size_t stride_bytes, size_t num_elements) + : ManagedImage(stride_bytes, num_elements) + {} + + using Attribute = variant,Image,Image,Image>; + // "vertex", "rgb", "normal", "uv", "tris", "quads", ... + std::map attributes; + }; + + // Store vertices and attributes + std::map buffers; + // Stores index buffers for each sub-object + std::multimap objects; + // Stores pixmaps + std::map textures; +}; + +pangolin::Geometry::Element::Attribute MakeAttribute(uint32_t gldatatype, size_t num_items, size_t count_per_item, void* ptr, size_t pitch_bytes); + +pangolin::Geometry LoadGeometry(const std::string& filename); + +#ifdef HAVE_EIGEN +inline Eigen::AlignedBox3f GetAxisAlignedBox(const Geometry& geom) +{ + Eigen::AlignedBox3f box; + box.setEmpty(); + + for(const auto& b : geom.buffers) { + const auto& it_vert = b.second.attributes.find("vertex"); + if(it_vert != b.second.attributes.end()) { + const Image& vs = get>(it_vert->second); + for(size_t i=0; i < vs.h; ++i) { + const Eigen::Map v(vs.RowPtr(i)); + box.extend(v); + } + } + } + + return box; +} +#endif + +} + +#endif // PANGOLIN_GEOMETRY_H diff --git a/Thirdparty/Pangolin/include/pangolin/geometry/geometry_obj.h b/Thirdparty/Pangolin/include/pangolin/geometry/geometry_obj.h new file mode 100644 index 0000000..9e2570b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/geometry/geometry_obj.h @@ -0,0 +1,34 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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 + +namespace pangolin { + +pangolin::Geometry LoadGeometryObj(const std::string& filename); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/geometry/geometry_ply.h b/Thirdparty/Pangolin/include/pangolin/geometry/geometry_ply.h new file mode 100644 index 0000000..25194dd --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/geometry/geometry_ply.h @@ -0,0 +1,165 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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 + +namespace pangolin +{ + +#define PLY_GROUP_LIST(m) m(PlyHeader) m(PlyFormat) m(PlyType) +#define PLY_HEADER_LIST(m) m(ply) m(format) m(comment) m(property) m(element) m(end_header) +#define PLY_FORMAT_LIST(m) m(ascii) m(binary_big_endian) m(binary_little_endian) +#define PLY_TYPE_LIST(m) m(char) m(int8) m(uchar) m(uint8) m(short) m(int16) m(ushort) m(uint16) m(int) m(int32) m(uint) m(uint32) m(float) m(float32) m(double) m(float64) m(list) + +// Define Enums / strings +enum PlyHeader { +#define FORMAT_ENUM(x) PlyHeader_##x, + PLY_HEADER_LIST(FORMAT_ENUM) + PlyHeaderSize +#undef FORMAT_ENUM +}; + +enum PlyFormat { +#define FORMAT_ENUM(x) PlyFormat_##x, + PLY_FORMAT_LIST(FORMAT_ENUM) + PlyFormatSize +#undef FORMAT_ENUM +}; + +enum PlyType { +#define FORMAT_ENUM(x) PlyType_##x, + PLY_TYPE_LIST(FORMAT_ENUM) + PlyTypeSize +#undef FORMAT_ENUM +}; +const size_t PlyTypeGl[] = { +// char, int8 -> GL_BYTE + 0x1400, 0x1400, +// uchar, uint8 -> GL_UNSIGNED_BYTE + 0x1401, 0x1401, +// short, int16 -> GL_SHORT + 0x1402, 0x1402, +// ushort, uint16 -> GL_UNSIGNED_SHORT + 0x1403, 0x1403, +// int, int32 -> GL_INT + 0x1404, 0x1404, +// uint, uint32 -> GL_UNSIGNED_INT + 0x1405, 0x1405, +// float, float32 -> GL_FLOAT + 0x1406, 0x1406, +// double, float64 -> GL_DOUBLE + 0x140A, 0x140A, +// list -> GL_NONE + 0 +}; + +#undef FORMAT_ENUM + +struct PlyPropertyDetails +{ + std::string name; + + // Type of property (GLenum) + size_t type; + + // Type of list index if a list, or 0 otherwise. (GLenum) + size_t list_index_type; + + // Offset from element start + size_t offset_bytes; + + // Number of items in the list. 1 if not a list. -1 if unknown. + int num_items; + + bool isList() const { + return list_index_type > 0; + } +}; + +struct PlyElementDetails +{ + std::string name; + int num_items; + int stride_bytes; + std::vector properties; + + inline std::vector::iterator FindProperty(const std::string& name) + { + return std::find_if(properties.begin(), properties.end(), + [&name](const PlyPropertyDetails& p){ return p.name == name;} + ); + } +}; + +struct PlyHeaderDetails +{ + PlyFormat format; + std::string version; + std::vector elements; + + inline std::vector::iterator FindElement(const std::string& name) + { + return std::find_if(elements.begin(), elements.end(), + [&name](const PlyElementDetails& el){ return el.name == name;} + ); + } +}; + +void ParsePlyHeader(PlyHeaderDetails& ply, std::istream& is); + +struct PlyBuffer +{ + size_t index_size_bytes; + size_t element_item_size_bytes; + std::vector data; +}; + +void ParsePlyAscii(pangolin::Geometry& /*geom*/, const PlyHeaderDetails& /*ply*/, std::istream& /*is*/); + +// Convert Seperate "x","y","z" attributes into a single "vertex" attribute +void StandardizeXyzToVertex(pangolin::Geometry& geom); + +// The Artec scanner saves with these attributes, for example +void StandardizeMultiTextureFaceToXyzuv(pangolin::Geometry& geom); + +void Standardize(pangolin::Geometry& geom); + +void ParsePlyLE(pangolin::Geometry& geom, PlyHeaderDetails& ply, std::istream& is); + +void ParsePlyBE(pangolin::Geometry& /*geom*/, const PlyHeaderDetails& /*ply*/, std::istream& /*is*/); + +void AttachAssociatedTexturesPly(pangolin::Geometry& geom, const std::string& filename); + +pangolin::Geometry LoadGeometryPly(const std::string& filename); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/geometry/glgeometry.h b/Thirdparty/Pangolin/include/pangolin/geometry/glgeometry.h new file mode 100644 index 0000000..a034b0a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/geometry/glgeometry.h @@ -0,0 +1,87 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin { + +struct GlGeometry +{ + GlGeometry() = default; + GlGeometry(GlGeometry&&) = default; + GlGeometry& operator=(GlGeometry&&) = default; + + struct Element : public GlBufferData + { + Element() = default; + Element(Element&&) = default; + Element& operator=(Element&&) = default; + + Element(GlBufferType buffer_type, size_t size_bytes, GLenum gluse, uint8_t* data) + : GlBufferData(buffer_type, size_bytes, gluse, data) + {} + + inline bool HasAttribute(const std::string& name) const { + return attributes.find(name) != attributes.end(); + } + + struct Attribute { + // Stuff needed by glVertexAttribPointer + GLenum gltype; + size_t count_per_element; + size_t num_elements; + size_t offset; + size_t stride_bytes; + }; + std::map attributes; + }; + + inline bool HasAttribute(const std::string& name) const + { + for(const auto& b : buffers) if(b.second.HasAttribute(name)) return true; + return false; + } + + // Store vertices and attributes + std::map buffers; + // Stores index buffers for each sub-object + std::multimap objects; + // Stores pixmaps + std::map textures; +}; + +GlGeometry::Element ToGlGeometry(const Geometry::Element& el, GlBufferType buffertype); + +GlGeometry ToGlGeometry(const Geometry& geom); + +void GlDraw(GlSlProgram& prog, const GlGeometry& geom, const GlTexture *matcap); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/cg.h b/Thirdparty/Pangolin/include/pangolin/gl/cg.h new file mode 100644 index 0000000..dd83901 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/cg.h @@ -0,0 +1,283 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +// Cg includes +#include +#include + +#include "gl.h" + +#ifdef HAVE_TOON +#include +#endif // HAVE_TOON + +namespace pangolin +{ + +//////////////////////////////////////////////// +// Interface +//////////////////////////////////////////////// + +/// Lightweight object wrapper for NVidia Cg Shader program objects. +class CgProgram +{ + friend class CgLoader; +public: + void SetUniform(const std::string& name, GlTexture& tex); + void SetUniform(const std::string& name, float f); + void SetUniform(const std::string& name, float v0, float v1); + void SetUniform(const std::string& name, float v0, float v1, float v2, float v3); + +#ifdef HAVE_TOON + void SetUniform(const std::string& name, const TooN::Vector<2>& v ); + void SetUniform(const std::string& name, const TooN::Vector<3>& v ); + + template + void SetUniform(const std::string& name, const TooN::Matrix& M ); +#endif + + void UpdateParams(); + +protected: + CGprogram mProg; + CGcontext mContext; + CGprofile mProfile; +}; + +class CgLoader +{ +public: + CgLoader(); + ~CgLoader(); + + // Call AFTER glewInit (or similar) + void Initialise(); + + CgProgram LoadProgramFromFile(const std::string& file, const std::string& function, bool isVertexShader ); + + void EnableProgram(CgProgram program); + void DisablePrograms(); + + void RenderDummyQuad(); + void RenderDummyQuadWithTexCoords(int w, int h); + +protected: + CGcontext mContext; + CGprofile mFragmentProfile; + CGprofile mVertexProfile; +}; + + + + +//////////////////////////////////////////////// +// Implementation +//////////////////////////////////////////////// + +inline bool cgOkay() +{ + CGerror error; + const char *string = cgGetLastErrorString(&error); + + if (error != CG_NO_ERROR) { + std::cout << "CG Error: " << string << std::endl; + // assert(0); + return false; + } + return true; +} + +inline CgLoader::CgLoader() + :mContext(0) +{ +} + +inline CgLoader::~CgLoader() +{ + if(mContext) + { + // Destroying context destroys all programs associated with it + cgDestroyContext(mContext); + } +} + + +inline void CgLoader::Initialise() +{ + mContext = cgCreateContext(); + cgSetParameterSettingMode(mContext, CG_DEFERRED_PARAMETER_SETTING); + cgOkay(); + + mFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); + cgGLSetOptimalOptions(mFragmentProfile); + cgOkay(); + + mVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); + cgGLSetOptimalOptions(mVertexProfile); + cgOkay(); +} + +inline CgProgram CgLoader::LoadProgramFromFile(const std::string& file, const std::string& function, bool isVertexShader ) +{ + if( !mContext ) { + Initialise(); + } + + CgProgram prog; + + prog.mContext = mContext; + prog.mProfile = isVertexShader ? mVertexProfile : mFragmentProfile; + prog.mProg = cgCreateProgramFromFile( prog.mContext, CG_SOURCE, file.c_str(), prog.mProfile, function.c_str(), NULL); + + if( !cgOkay() ) + { + std::cout << cgGetLastListing(mContext) << std::endl; + assert(0); + } + + cgGLLoadProgram(prog.mProg); + if( !cgOkay() ) + { + const char* err = cgGetProgramString( prog.mProg, CG_COMPILED_PROGRAM ); + int pos; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); + std::cout << err << std::endl; + std::cout << "@ " << pos << std::endl; + assert(0); + } + return prog; +} + +inline void CgLoader::EnableProgram(CgProgram program) +{ + cgGLBindProgram(program.mProg); + cgGLEnableProfile(program.mProfile); + cgOkay(); +} + +inline void CgLoader::DisablePrograms() +{ + cgGLDisableProfile(mFragmentProfile); + cgGLDisableProfile(mVertexProfile); +} + +inline void CgLoader::RenderDummyQuad() +{ + glBegin(GL_QUADS); + glVertex2d(-1,1); + glVertex2d(1,1); + glVertex2d(1,-1); + glVertex2d(-1,-1); + glEnd(); +} + +inline void CgLoader::RenderDummyQuadWithTexCoords(int w, int h) +{ + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2d(-1,-1); + glTexCoord2f(w, 0); + glVertex2d(1,-1); + glTexCoord2f(w, h); + glVertex2d(1,1); + glTexCoord2f(0, h); + glVertex2d(-1,1); + glEnd(); +} + +void CgProgram::SetUniform(const std::string& name, float f) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + cgSetParameter1f( p, f ); + cgUpdateProgramParameters(mProg); +} + +void CgProgram::SetUniform(const std::string& name, GlTexture& tex) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + cgGLSetTextureParameter(p, tex.tid ); + cgGLEnableTextureParameter(p); + cgUpdateProgramParameters(mProg); +} + +void CgProgram::SetUniform(const std::string& name, float v0, float v1, float v2, float v3) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + cgGLSetParameter4f(p, v0,v1,v2,v3); + cgUpdateProgramParameters(mProg); +} + +void CgProgram::SetUniform(const std::string& name, float v0, float v1) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + cgGLSetParameter2f(p, v0,v1); + cgUpdateProgramParameters(mProg); +} + +#ifdef HAVE_TOON +void CgProgram::SetUniform(const std::string& name, const TooN::Vector<2>& v ) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + cgGLSetParameter2f(p, v[0],v[1] ); + cgUpdateProgramParameters(mProg); +} + +void CgProgram::SetUniform(const std::string& name, const TooN::Vector<3>& v ) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + cgGLSetParameter3f(p, v[0],v[1],v[2] ); + cgUpdateProgramParameters(mProg); +} + +template +void CgProgram::SetUniform(const std::string& name, const TooN::Matrix& M ) +{ + CGparameter p = cgGetNamedParameter( mProg, name.c_str()); + float Mdata[R*C]; + + int i=0; + for( int r=0; r + +#include + +namespace pangolin +{ + +/// Represent OpenGL floating point colour: Red, Green and Blue with alpha. +struct Colour +{ + inline static Colour White() { + return Colour(1.0f,1.0f,1.0f,1.0f); + } + inline static Colour Black() { + return Colour(0.0f,0.0f,0.0f,1.0f); + } + inline static Colour Red() { + return Colour(1.0f,0.0f,0.0f,1.0f); + } + inline static Colour Green() { + return Colour(0.0f,1.0f,0.0f,1.0f); + } + inline static Colour Blue() { + return Colour(0.0f,0.0f,1.0f,1.0f); + } + inline static Colour Unspecified() { + return Colour( + std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN() + ); + } + + /// Default constructs white. + inline Colour() + : red(1.0f), green(1.0f), blue(1.0f), alpha(1.0f) + { + } + + /// Construct from component values + inline Colour(const float red, const float green, const float blue, const float alpha = 1.0f) + : red(red), green(green), blue(blue), alpha(alpha) + { + } + + /// Construct from rgba array. + inline Colour(const float rgba[4]) + { + r = rgba[0]; + g = rgba[1]; + b = rgba[2]; + a = rgba[3]; + } + + /// Return pointer to OpenGL compatible RGBA array. + inline float* Get() + { + return c; + } + + /// Return this colour with alpha adjusted. + inline Colour WithAlpha(const float alpha) + { + return Colour(r,g,b,alpha); + } + + /// Construct from HSV Colour + /// @param hue Colour hue in range [0,1] + /// @param sat Saturation in range [0,1] + /// @param val Value / Brightness in range [0,1]. + static inline Colour Hsv(const float hue, const float sat = 1.0f, const float val = 1.0f, const float alpha = 1.0f) + { + const float h = 6.0f * hue; + const int i = (int)floor(h); + const float f = (i%2 == 0) ? 1-(h-i) : h-i; + const float m = val * (1-sat); + const float n = val * (1-sat*f); + + switch(i) + { + case 0: return Colour(val,n,m,alpha); + case 1: return Colour(n,val,m,alpha); + case 2: return Colour(m,val,n,alpha); + case 3: return Colour(m,n,val,alpha); + case 4: return Colour(n,m,val,alpha); + case 5: return Colour(val,m,n,alpha); + default: + throw std::runtime_error("Found extra colour in rainbow."); + } + } + + union { + struct { + float red; + float green; + float blue; + float alpha; + }; + struct { + float r; + float g; + float b; + float a; + }; + float c[4]; + }; + +}; + +/// A ColourWheel is like a continuous colour palate that can be sampled. +/// In the future, different ColourWheels will be supported, but this one +/// is based on sampling hues in HSV colourspace. An indefinite number of +/// unique colours are sampled using the golden angle. +class ColourWheel +{ +public: + /// Construct ColourWheel with Saturation, Value and Alpha constant. + inline ColourWheel(float saturation = 0.5f, float value = 1.0f, float alpha = 1.0f) + : unique_colours(0), sat(saturation), val(value), alpha(alpha) + { + + } + + /// Use Golden ratio (/angle) to pick well spaced colours. + inline Colour GetColourBin(int i) const + { + float hue = i * 0.5f * (3.0f - sqrt(5.0f)); + hue -= (int)hue; + return Colour::Hsv(hue,sat,val,alpha); + } + + /// Return next unique colour from ColourWheel. + inline Colour GetUniqueColour() + { + return GetColourBin(unique_colours++); + } + + /// Reset colour wheel counter to initial state + inline void Reset() { + unique_colours = 0; + } + +protected: + int unique_colours; + float sat; + float val; + float alpha; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/compat/gl2engine.h b/Thirdparty/Pangolin/include/pangolin/gl/compat/gl2engine.h new file mode 100644 index 0000000..184aa60 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/compat/gl2engine.h @@ -0,0 +1,320 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include + +namespace pangolin { + +class GlEngine +{ +public: + const char* vert = + "attribute vec4 a_position;\n" + "attribute vec4 a_color;\n" + "attribute vec3 a_normal;\n" + "attribute vec2 a_texcoord;\n" + "uniform vec4 u_color;\n" + "uniform mat4 u_modelViewMatrix;\n" + "uniform mat4 u_modelViewProjectionMatrix;\n" + "varying vec4 v_frontColor;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " gl_Position = u_modelViewProjectionMatrix * a_position;\n" + " v_frontColor = u_color;\n" + " v_texcoord = a_texcoord;\n" + "}\n"; + + const char* frag = + #ifdef HAVE_GLES_2 + "precision mediump float;\n" + #endif // HAVE_GLES_2 + "varying vec4 v_frontColor;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D u_texture;\n" + "uniform bool u_textureEnable;\n" + "void main() {\n" + " gl_FragColor = v_frontColor;\n" + " if(u_textureEnable) {\n" + " gl_FragColor *= texture2D(u_texture, v_texcoord);\n" + " }\n" + "}\n"; + + GlEngine() + { + // Initialise default state + projection.push(IdentityMatrix()); + modelview.push(IdentityMatrix()); + currentmatrix = &modelview; + + // Set GL_TEXTURE0 as default active texture + glActiveTexture(GL_TEXTURE0); + + // Compile and link shaders + prog_fixed.AddShader(GlSlVertexShader, vert); + prog_fixed.AddShader(GlSlFragmentShader, frag); + prog_fixed.BindPangolinDefaultAttribLocationsAndLink(); + + // Save locations of uniforms + u_color = prog_fixed.GetUniformHandle("u_color"); + u_modelViewMatrix = prog_fixed.GetUniformHandle("u_modelViewMatrix"); + u_modelViewProjectionMatrix = prog_fixed.GetUniformHandle("u_modelViewProjectionMatrix"); + u_texture = prog_fixed.GetUniformHandle("u_texture"); + u_textureEnable = prog_fixed.GetUniformHandle("u_textureEnable"); + + // Initialise default uniform values + UpdateMatrices(); + SetColor(1.0,1.0,1.0,1.0); + } + + void UpdateMatrices() + { + OpenGlMatrix pmv = projection.top() * modelview.top(); + prog_fixed.SaveBind(); + glUniformMatrix4fv( u_modelViewMatrix, 1, false, modelview.top().m ); + glUniformMatrix4fv( u_modelViewProjectionMatrix, 1, false, pmv.m ); + prog_fixed.Unbind(); + } + + void SetColor(float r, float g, float b, float a) + { + prog_fixed.SaveBind(); + glUniform4f( u_color, r, g, b, a); + prog_fixed.Unbind(); + } + + void EnableTexturing(GLboolean v) + { + prog_fixed.SaveBind(); + glUniform1i( u_textureEnable, v); + prog_fixed.Unbind(); + } + +//protected: + std::stack projection; + std::stack modelview; + std::stack* currentmatrix; + + GLenum matrixmode; + + float color[4]; + + GlSlProgram prog_fixed; + + GLint u_color; + GLint u_modelViewMatrix; + GLint u_modelViewProjectionMatrix; + GLint u_texture; + GLint u_textureEnable; +}; + +GlEngine& glEngine(); + +} + +/////////////////////////////////////////////////////////////////////////////// +// OpenGL 1.0 compatibility - Emulate fixed pipeline +/////////////////////////////////////////////////////////////////////////////// + +// Missing defines that we'll be using +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_SHADE_MODEL 0x0B54 +#define GL_POINT_SIZE 0x0B11 + +#define GL_MULTISAMPLE 0x809D + +#define GL_LIGHTING 0x0B50 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_MATERIAL 0x0B57 + +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 + +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +#define GL_ADD 0x0104 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV 0x2300 + +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_LINE_SMOOTH_HINT 0x0C52 + +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_TEXTURE_COORD_ARRAY 0x8078 + +inline void glEnableClientState(GLenum cap) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + if(cap == GL_VERTEX_ARRAY) { + glEnableVertexAttribArray(pangolin::DEFAULT_LOCATION_POSITION); + }else if(cap == GL_COLOR_ARRAY) { + glEnableVertexAttribArray(pangolin::DEFAULT_LOCATION_COLOUR); + }else if(cap == GL_NORMAL_ARRAY) { + glEnableVertexAttribArray(pangolin::DEFAULT_LOCATION_NORMAL); + }else if(cap == GL_TEXTURE_COORD_ARRAY) { + glEnableVertexAttribArray(pangolin::DEFAULT_LOCATION_TEXCOORD); + gl.EnableTexturing(true); + }else{ + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); + } +} + +inline void glDisableClientState(GLenum cap) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + if(cap == GL_VERTEX_ARRAY) { + glDisableVertexAttribArray(pangolin::DEFAULT_LOCATION_POSITION); + }else if(cap == GL_COLOR_ARRAY) { + glDisableVertexAttribArray(pangolin::DEFAULT_LOCATION_COLOUR); + }else if(cap == GL_NORMAL_ARRAY) { + glDisableVertexAttribArray(pangolin::DEFAULT_LOCATION_NORMAL); + }else if(cap == GL_TEXTURE_COORD_ARRAY) { + glDisableVertexAttribArray(pangolin::DEFAULT_LOCATION_TEXCOORD); + gl.EnableTexturing(false); + }else{ + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); + } +} + +inline void glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) +{ + glVertexAttribPointer(pangolin::DEFAULT_LOCATION_POSITION, size, type, GL_FALSE, stride, pointer); +} + +inline void glTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) +{ + glVertexAttribPointer(pangolin::DEFAULT_LOCATION_TEXCOORD, size, type, GL_FALSE, stride, pointer); +} + +inline void glMatrixMode(GLenum mode) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + gl.currentmatrix = (mode == pangolin::GlProjectionStack) ? &gl.projection : &gl.modelview; +} + +inline void glLoadIdentity() +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + gl.currentmatrix->top() = pangolin::IdentityMatrix(); + gl.UpdateMatrices(); +} + +inline void glLoadMatrixf(const GLfloat* m) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + pangolin::GLprecision* cm = gl.currentmatrix->top().m; + for(int i=0; i<16; ++i) cm[i] = (pangolin::GLprecision)m[i]; + gl.UpdateMatrices(); +} + +inline void glLoadMatrixd(const GLdouble* m) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + pangolin::GLprecision* cm = gl.currentmatrix->top().m; + for(int i=0; i<16; ++i) cm[i] = (pangolin::GLprecision)m[i]; + gl.UpdateMatrices(); +} + +inline void glMultMatrixf(const GLfloat* m) +{ +// pangolin::GlEngine& gl = pangolin::glEngine(); +// float res[16]; +// pangolin::MatMul<4,4,4,float>(res, m, gl.currentmatrix->m ); +// std::memcpy(gl.currentmatrix->m, res, sizeof(float) * 16 ); + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); +} + +inline void glMultMatrixd(const GLdouble* m) +{ + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); +} + +inline void glPushMatrix(void) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + gl.currentmatrix->push(gl.currentmatrix->top()); +} + +inline void glPopMatrix(void) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + gl.currentmatrix->pop(); + gl.UpdateMatrices(); +} + +inline void glTranslatef(GLfloat x, GLfloat y, GLfloat z ) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + pangolin::GLprecision* cm = gl.currentmatrix->top().m; + cm[12] += x; + cm[13] += y; + cm[14] += z; + gl.UpdateMatrices(); +} + +inline void glOrtho( + GLdouble l, GLdouble r, + GLdouble b, GLdouble t, + GLdouble n, GLdouble f) +{ + pangolin::GlEngine& gl = pangolin::glEngine(); + gl.currentmatrix->top() = pangolin::ProjectionMatrixOrthographic(l,r,b,t,n,f); + gl.UpdateMatrices(); +} + +inline void glColor4f( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + pangolin::glEngine().SetColor(red,green,blue,alpha); +} + +inline void glShadeModel( GLenum mode) +{ + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); +} + +inline void glPointSize(GLfloat size) +{ + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); +} + +inline void glTexEnvf( GLenum target, + GLenum pname, + GLfloat param) +{ + pango_print_error("Not Implemented: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/compat/gl_es_compat.h b/Thirdparty/Pangolin/include/pangolin/gl/compat/gl_es_compat.h new file mode 100644 index 0000000..1c1fdb3 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/compat/gl_es_compat.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +#define GLdouble GLfloat +#define glClearDepth glClearDepthf +#define glFrustum glFrustumf + +#define glColor4fv(a) glColor4f(a[0], a[1], a[2], a[3]) +#define glColor3fv(a) glColor4f(a[0], a[1], a[2], 1.0f) +#define glColor3f(a,b,c) glColor4f(a, b, c, 1.0f) + +#define GL_CLAMP GL_CLAMP_TO_EDGE + +#ifdef HAVE_GLES_2 + #define glGenFramebuffersEXT glGenFramebuffers + #define glDeleteFramebuffersEXT glDeleteFramebuffers + #define glBindFramebufferEXT glBindFramebuffer + #define glDrawBuffers glDrawBuffers + #define glFramebufferTexture2DEXT glFramebufferTexture2D + #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER + #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT16 // <---- + #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 + #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT +#else + #define glOrtho glOrthof + #define glGenFramebuffersEXT glGenFramebuffersOES + #define glDeleteFramebuffersEXT glDeleteFramebuffersOES + #define glBindFramebufferEXT glBindFramebufferOES + #define glDrawBuffers glDrawBuffersOES + #define glFramebufferTexture2DEXT glFramebufferTexture2DOES + #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES + #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES + #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES +#endif + +#define glGetDoublev glGetFloatv + +#ifdef HAVE_GLES_2 +#include +#endif + +inline void glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + GLfloat verts[] = { x1,y1, x2,y1, x2,y2, x1,y2 }; + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, verts); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableClientState(GL_VERTEX_ARRAY); +} + +inline void glRecti(int x1, int y1, int x2, int y2) +{ + GLfloat verts[] = { (float)x1,(float)y1, (float)x2,(float)y1, + (float)x2,(float)y2, (float)x1,(float)y2 }; + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, verts); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableClientState(GL_VERTEX_ARRAY); +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/gl.h b/Thirdparty/Pangolin/include/pangolin/gl/gl.h new file mode 100644 index 0000000..4330e73 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/gl.h @@ -0,0 +1,273 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files +#define USE_EIGEN +#endif + +#ifdef USE_EIGEN +#include +#endif + +#include +#include +#include + +namespace pangolin +{ + +//////////////////////////////////////////////// +// Interface +//////////////////////////////////////////////// + +class PANGOLIN_EXPORT GlTexture +{ +public: + //! internal_format normally one of GL_RGBA8, GL_LUMINANCE8, GL_INTENSITY16 + GlTexture(GLint width, GLint height, GLint internal_format = GL_RGBA8, bool sampling_linear = true, int border = 0, GLenum glformat = GL_RGBA, GLenum gltype = GL_UNSIGNED_BYTE, GLvoid* data = NULL ); + + // Construct this texture from a CPU image + GlTexture(const TypedImage& img, bool sampling_linear=true); + + //! Move Constructor / asignment + GlTexture(GlTexture&& tex); + GlTexture& operator=(GlTexture&& tex); + + //! Default constructor represents 'no texture' + GlTexture(); + virtual ~GlTexture(); + + bool IsValid() const; + + //! Delete OpenGL resources and fall back to representing 'no texture' + void Delete(); + + //! Reinitialise teture width / height / format + virtual void Reinitialise(GLsizei width, GLsizei height, GLint internal_format = GL_RGBA8, bool sampling_linear = true, int border = 0, GLenum glformat = GL_RGBA, GLenum gltype = GL_UNSIGNED_BYTE, GLvoid* data = NULL ); + + void Bind() const; + void Unbind() const; + + //! data_layout normally one of GL_LUMINANCE, GL_RGB, ... + //! data_type normally one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT + void Upload(const void* image, GLenum data_format = GL_LUMINANCE, GLenum data_type = GL_FLOAT); + + //! Upload data to texture, overwriting a sub-region of it. + //! data ptr contains packed data_w x data_h of pixel data. + void Upload(const void* data, + GLsizei tex_x_offset, GLsizei tex_y_offset, + GLsizei data_w, GLsizei data_h, + GLenum data_format, GLenum data_type + ); + + void Load(const TypedImage& image, bool sampling_linear = true); + + void LoadFromFile(const std::string& filename, bool sampling_linear = true); + + void Download(void* image, GLenum data_layout = GL_LUMINANCE, GLenum data_type = GL_FLOAT) const; + + void Download(TypedImage& image) const; + + void CopyFrom(const GlTexture& tex); + + void Save(const std::string& filename, bool top_line_first = true); + + void SetLinear(); + void SetNearestNeighbour(); + + void RenderToViewport(const bool flip) const; + void RenderToViewport() const; + void RenderToViewport(Viewport tex_vp, bool flipx=false, bool flipy=false) const; + void RenderToViewportFlipY() const; + void RenderToViewportFlipXFlipY() const; + + GLint internal_format; + GLuint tid; + GLint width; + GLint height; + +private: + // Private copy constructor + GlTexture(const GlTexture&) {} +}; + +struct PANGOLIN_EXPORT GlRenderBuffer +{ + GlRenderBuffer(); + GlRenderBuffer(GLint width, GLint height, GLint internal_format = GL_DEPTH_COMPONENT24); + + void Reinitialise(GLint width, GLint height, GLint internal_format = GL_DEPTH_COMPONENT24); + + //! Move Constructor + GlRenderBuffer(GlRenderBuffer&& tex); + + ~GlRenderBuffer(); + + GLint width; + GLint height; + GLuint rbid; + +private: + // Private copy constructor + GlRenderBuffer(const GlRenderBuffer&) {} +}; + +struct PANGOLIN_EXPORT GlFramebuffer +{ + GlFramebuffer(); + ~GlFramebuffer(); + + GlFramebuffer(GlTexture& colour, GlRenderBuffer& depth); + GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlRenderBuffer& depth); + GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlTexture& colour2, GlRenderBuffer& depth); + GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlTexture& colour2, GlTexture& colour3, GlRenderBuffer& depth); + + void Bind() const; + void Unbind() const; + + void Reinitialise(); + + // Attach Colour texture to frame buffer + // Return attachment texture is bound to (e.g. GL_COLOR_ATTACHMENT0_EXT) + GLenum AttachColour(GlTexture& tex); + + // Attach Depth render buffer to frame buffer + void AttachDepth(GlRenderBuffer& rb); + + GLuint fbid; + unsigned attachments; +}; + +enum GlBufferType +{ + GlUndefined = 0, + GlArrayBuffer = GL_ARRAY_BUFFER, // VBO's, CBO's, NBO's + GlElementArrayBuffer = GL_ELEMENT_ARRAY_BUFFER, // IBO's +#ifndef HAVE_GLES + GlPixelPackBuffer = GL_PIXEL_PACK_BUFFER, // PBO's + GlPixelUnpackBuffer = GL_PIXEL_UNPACK_BUFFER, + GlShaderStorageBuffer = GL_SHADER_STORAGE_BUFFER +#endif +}; + +// This encapsulates a GL Buffer object. +struct PANGOLIN_EXPORT GlBufferData +{ + //! Default constructor represents 'no buffer' + GlBufferData(); + GlBufferData(GlBufferType buffer_type, GLuint size_bytes, GLenum gluse = GL_DYNAMIC_DRAW, const unsigned char* data = 0 ); + virtual ~GlBufferData(); + void Free(); + + //! Move Constructor + GlBufferData(GlBufferData&& tex); + GlBufferData& operator=(GlBufferData&& tex); + + bool IsValid() const; + + size_t SizeBytes() const; + + void Reinitialise(GlBufferType buffer_type, GLuint size_bytes, GLenum gluse = GL_DYNAMIC_DRAW, const unsigned char* data = 0 ); + + void Bind() const; + void Unbind() const; + void Upload(const GLvoid* data, GLsizeiptr size_bytes, GLintptr offset = 0); + void Download(GLvoid* ptr, GLsizeiptr size_bytes, GLintptr offset = 0) const; + + GLuint bo; + GlBufferType buffer_type; + GLenum gluse; + GLuint size_bytes; + +private: + GlBufferData(const GlBufferData&) {} +}; + +// This encapsulates a GL Buffer object, also storing information about its contents. +// You should try to use GlBufferData instead. +struct PANGOLIN_EXPORT GlBuffer : public GlBufferData +{ + //! Default constructor represents 'no buffer' + GlBuffer(); + GlBuffer(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse = GL_DYNAMIC_DRAW ); + GlBuffer(const GlBuffer&) = delete; + + //! Move Constructor + GlBuffer(GlBuffer&& tex); + GlBuffer& operator=(GlBuffer&& tex); + + void Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse, const unsigned char* data = nullptr ); + void Reinitialise(GlBuffer const& other ); + void Resize(GLuint num_elements); + + GLenum datatype; + GLuint num_elements; + GLuint count_per_element; +}; + +class PANGOLIN_EXPORT GlSizeableBuffer + : public pangolin::GlBuffer +{ +public: + GlSizeableBuffer(pangolin::GlBufferType buffer_type, GLuint initial_num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse = GL_DYNAMIC_DRAW ); + + void Clear(); + +#ifdef USE_EIGEN + template + void Add(const Eigen::DenseBase& vec); + + template + void Update(const Eigen::DenseBase& vec, size_t position = 0); +#endif + + size_t start() const; + + size_t size() const; + +protected: + void CheckResize(size_t num_verts); + + size_t NextSize(size_t min_size) const; + + size_t m_num_verts; +}; + +size_t GlFormatChannels(GLenum data_layout); + +size_t GlDataTypeBytes(GLenum type); + +} + +// Include implementation +#include diff --git a/Thirdparty/Pangolin/include/pangolin/gl/gl.hpp b/Thirdparty/Pangolin/include/pangolin/gl/gl.hpp new file mode 100644 index 0000000..59571c7 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/gl.hpp @@ -0,0 +1,866 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace pangolin +{ + +//////////////////////////////////////////////// +// Implementation of gl.h +//////////////////////////////////////////////// + +#ifndef HAVE_GLES +const int MAX_ATTACHMENTS = 8; +const static GLuint attachment_buffers[] = { + GL_COLOR_ATTACHMENT0_EXT, + GL_COLOR_ATTACHMENT1_EXT, + GL_COLOR_ATTACHMENT2_EXT, + GL_COLOR_ATTACHMENT3_EXT, + GL_COLOR_ATTACHMENT4_EXT, + GL_COLOR_ATTACHMENT5_EXT, + GL_COLOR_ATTACHMENT6_EXT, + GL_COLOR_ATTACHMENT7_EXT +}; +#else // HAVE_GLES +const int MAX_ATTACHMENTS = 1; +const static GLuint attachment_buffers[] = { + GL_COLOR_ATTACHMENT0_EXT +}; +#endif // HAVE_GLES + +const static size_t datatype_bytes[] = { + 1, // #define GL_BYTE 0x1400 + 1, // #define GL_UNSIGNED_BYTE 0x1401 + 2, // #define GL_SHORT 0x1402 + 2, // #define GL_UNSIGNED_SHORT 0x1403 + 4, // #define GL_INT 0x1404 + 4, // #define GL_UNSIGNED_INT 0x1405 + 4, // #define GL_FLOAT 0x1406 + 2, // #define GL_2_BYTES 0x1407 + 3, // #define GL_3_BYTES 0x1408 + 4, // #define GL_4_BYTES 0x1409 + 8 // #define GL_DOUBLE 0x140A +}; + +const static size_t format_channels[] = { + 1, // #define GL_RED 0x1903 + 1, // #define GL_GREEN 0x1904 + 1, // #define GL_BLUE 0x1905 + 1, // #define GL_ALPHA 0x1906 + 3, // #define GL_RGB 0x1907 + 4, // #define GL_RGBA 0x1908 + 1, // #define GL_LUMINANCE 0x1909 + 2 // #define GL_LUMINANCE_ALPHA 0x190A +}; + +inline size_t GlDataTypeBytes(GLenum type) +{ + return datatype_bytes[type - GL_BYTE]; +} + +inline size_t GlFormatChannels(GLenum data_layout) +{ + if (data_layout == GL_BGR) return 3; + if (data_layout == GL_BGRA) return 4; + return format_channels[data_layout - GL_RED]; +} + +//template +//struct GlDataTypeTrait {}; +//template<> struct GlDataTypeTrait{ static const GLenum type = GL_FLOAT; }; +//template<> struct GlDataTypeTrait{ static const GLenum type = GL_INT; }; +//template<> struct GlDataTypeTrait{ static const GLenum type = GL_UNSIGNED_BYTE; }; + +inline GlTexture::GlTexture() + : internal_format(0), tid(0), width(0), height(0) +{ + // Not a texture constructor +} + +inline GlTexture::GlTexture(GLint width, GLint height, GLint internal_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid* data ) + : internal_format(0), tid(0) +{ + Reinitialise(width,height,internal_format,sampling_linear,border,glformat,gltype,data); +} + +inline GlTexture::GlTexture(const TypedImage& img, bool sampling_linear) +{ + this->Load(img, sampling_linear); +} + +inline GlTexture::GlTexture(GlTexture&& tex) +{ + *this = std::move(tex); +} + +inline GlTexture& GlTexture::operator=(GlTexture&& tex) +{ + if (&tex != this) { + internal_format = tex.internal_format; + tid = tex.tid; + width = tex.width; + height = tex.height; + + tex.internal_format = 0; + tex.tid = 0; + } + return *this; +} + +inline bool GlTexture::IsValid() const +{ + return tid != 0; +} + +inline void GlTexture::Delete() +{ + // We have no GL context whilst exiting. + if(internal_format!=0 && !pangolin::ShouldQuit() ) { + glDeleteTextures(1,&tid); + internal_format = 0; + tid = 0; + width = 0; + height = 0; + } +} + +inline GlTexture::~GlTexture() +{ + // We have no GL context whilst exiting. + if(internal_format!=0 && !pangolin::ShouldQuit() ) { + glDeleteTextures(1,&tid); + } +} + +inline void GlTexture::Bind() const +{ + glBindTexture(GL_TEXTURE_2D, tid); +} + +inline void GlTexture::Unbind() const +{ + glBindTexture(GL_TEXTURE_2D, 0); +} + +inline void GlTexture::Reinitialise(GLsizei w, GLsizei h, GLint int_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid* data ) +{ + if(tid!=0) { + glDeleteTextures(1,&tid); + } + + internal_format = int_format; + width = w; + height = h; + + glGenTextures(1,&tid); + Bind(); + + // GL_LUMINANCE and GL_FLOAT don't seem to actually affect buffer, but some values are required + // for call to succeed. + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, border, glformat, gltype, data); + + if(sampling_linear) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + }else{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + CheckGlDieOnError(); +} + +inline void GlTexture::Upload( + const void* data, + GLenum data_format, GLenum data_type +) { + Bind(); + glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,data_format,data_type,data); + CheckGlDieOnError(); +} + +inline void GlTexture::Upload( + const void* data, + GLsizei tex_x_offset, GLsizei tex_y_offset, + GLsizei data_w, GLsizei data_h, + GLenum data_format, GLenum data_type ) +{ + Bind(); + glTexSubImage2D(GL_TEXTURE_2D,0,tex_x_offset,tex_y_offset,data_w,data_h,data_format,data_type,data); + CheckGlDieOnError(); +} + +inline void GlTexture::Load(const TypedImage& image, bool sampling_linear) +{ + GlPixFormat fmt(image.fmt); + Reinitialise((GLint)image.w, (GLint)image.h, GL_RGBA32F, sampling_linear, 0, fmt.glformat, fmt.gltype, image.ptr ); +} + +inline void GlTexture::LoadFromFile(const std::string& filename, bool sampling_linear) +{ + TypedImage image = LoadImage(filename); + Load(image, sampling_linear); +} + +#ifndef HAVE_GLES +inline void GlTexture::Download(void* image, GLenum data_layout, GLenum data_type) const +{ + Bind(); + glGetTexImage(GL_TEXTURE_2D, 0, data_layout, data_type, image); + Unbind(); +} + +inline void GlTexture::Download(TypedImage& image) const +{ + switch (internal_format) + { + case GL_LUMINANCE8: + image.Reinitialise(width, height, PixelFormatFromString("GRAY8") ); + Download(image.ptr, GL_LUMINANCE, GL_UNSIGNED_BYTE); + break; + case GL_LUMINANCE16: + image.Reinitialise(width, height, PixelFormatFromString("GRAY16LE") ); + Download(image.ptr, GL_LUMINANCE, GL_UNSIGNED_SHORT); + break; + case GL_RGB8: + image.Reinitialise(width, height, PixelFormatFromString("RGB24")); + Download(image.ptr, GL_RGB, GL_UNSIGNED_BYTE); + break; + case GL_RGBA8: + image.Reinitialise(width, height, PixelFormatFromString("RGBA32")); + Download(image.ptr, GL_RGBA, GL_UNSIGNED_BYTE); + break; + case GL_RGB16: + image.Reinitialise(width, height, PixelFormatFromString("RGB48")); + Download(image.ptr, GL_RGB, GL_UNSIGNED_SHORT); + break; + case GL_RGBA16: + image.Reinitialise(width, height, PixelFormatFromString("RGBA64")); + Download(image.ptr, GL_RGBA, GL_UNSIGNED_SHORT); + break; + case GL_LUMINANCE: + case GL_LUMINANCE32F_ARB: + image.Reinitialise(width, height, PixelFormatFromString("GRAY32F")); + Download(image.ptr, GL_LUMINANCE, GL_FLOAT); + break; + case GL_RGB: + case GL_RGB32F: + image.Reinitialise(width, height, PixelFormatFromString("RGB96F")); + Download(image.ptr, GL_RGB, GL_FLOAT); + break; + case GL_RGBA: + case GL_RGBA32F: + image.Reinitialise(width, height, PixelFormatFromString("RGBA128F")); + Download(image.ptr, GL_RGBA, GL_FLOAT); + break; + default: + throw std::runtime_error( + "GlTexture::Download - Unknown internal format (" + + pangolin::Convert::Do(internal_format) + + ")" + ); + } + +} + +inline void GlTexture::CopyFrom(const GlTexture& tex) +{ + if(!tid || width != tex.width || height != tex.height || + internal_format != tex.internal_format) + { + Reinitialise(tex.width, tex.height, tex.internal_format, true); + } + + glCopyImageSubData(tex.tid, GL_TEXTURE_2D, 0, 0, 0, 0, + tid, GL_TEXTURE_2D, 0, 0, 0, 0, + width, height, 1); + CheckGlDieOnError(); +} + +inline void GlTexture::Save(const std::string& filename, bool top_line_first) +{ + TypedImage image; + Download(image); + pangolin::SaveImage(image, filename, top_line_first); +} +#endif // HAVE_GLES + +inline void GlTexture::SetLinear() +{ + Bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + Unbind(); +} + +inline void GlTexture::SetNearestNeighbour() +{ + Bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + Unbind(); +} + +inline void GlTexture::RenderToViewport(const bool flip) const +{ + if(flip) { + RenderToViewportFlipY(); + }else{ + RenderToViewport(); + } +} + +inline void GlTexture::RenderToViewport() const +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; + glVertexPointer(2, GL_FLOAT, 0, sq_vert); + glEnableClientState(GL_VERTEX_ARRAY); + + GLfloat sq_tex[] = { 0,0, 1,0, 1,1, 0,1 }; + glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnable(GL_TEXTURE_2D); + Bind(); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(GL_TEXTURE_2D); +} + +inline void GlTexture::RenderToViewport(Viewport tex_vp, bool flipx, bool flipy) const +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; + glVertexPointer(2, GL_FLOAT, 0, sq_vert); + glEnableClientState(GL_VERTEX_ARRAY); + + GLfloat l = tex_vp.l / (float)(width); + GLfloat b = tex_vp.b / (float)(height); + GLfloat r = (tex_vp.l+tex_vp.w) / (float)(width); + GLfloat t = (tex_vp.b+tex_vp.h) / (float)(height); + + if(flipx) std::swap(l,r); + if(flipy) std::swap(b,t); + + GLfloat sq_tex[] = { l,b, r,b, r,t, l,t }; + glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnable(GL_TEXTURE_2D); + Bind(); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(GL_TEXTURE_2D); +} + +inline void GlTexture::RenderToViewportFlipY() const +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; + glVertexPointer(2, GL_FLOAT, 0, sq_vert); + glEnableClientState(GL_VERTEX_ARRAY); + + GLfloat sq_tex[] = { 0,1, 1,1, 1,0, 0,0 }; + glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnable(GL_TEXTURE_2D); + Bind(); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(GL_TEXTURE_2D); +} + +inline void GlTexture::RenderToViewportFlipXFlipY() const +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLfloat sq_vert[] = { 1,1, -1,1, -1,-1, 1,-1 }; + glVertexPointer(2, GL_FLOAT, 0, sq_vert); + glEnableClientState(GL_VERTEX_ARRAY); + + GLfloat sq_tex[] = { 0,0, 1,0, 1,1, 0,1 }; + glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnable(GL_TEXTURE_2D); + Bind(); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(GL_TEXTURE_2D); +} + +//////////////////////////////////////////////////////////////////////////// + +inline GlRenderBuffer::GlRenderBuffer() + : width(0), height(0), rbid(0) +{ +} + +inline GlRenderBuffer::GlRenderBuffer(GLint width, GLint height, GLint internal_format ) + : width(0), height(0), rbid(0) +{ + Reinitialise(width,height,internal_format); +} + +#ifndef HAVE_GLES +inline void GlRenderBuffer::Reinitialise(GLint width, GLint height, GLint internal_format) +{ + if( this->width != 0 ) { + glDeleteRenderbuffersEXT(1, &rbid); + } + + this->width = width; + this->height = height; + glGenRenderbuffersEXT(1, &rbid); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbid); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internal_format, width, height); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); +} + +inline GlRenderBuffer::~GlRenderBuffer() +{ + // We have no GL context whilst exiting. + if( width!=0 && !pangolin::ShouldQuit() ) { + glDeleteRenderbuffersEXT(1, &rbid); + } +} +#else +inline void GlRenderBuffer::Reinitialise(GLint width, GLint height, GLint internal_format) +{ + if( width!=0 ) { + glDeleteTextures(1, &rbid); + } + + // Use a texture instead... + glGenTextures(1, &rbid); + glBindTexture(GL_TEXTURE_2D, rbid); + + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, + width, height, + 0, internal_format, GL_UNSIGNED_SHORT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} + +inline GlRenderBuffer::~GlRenderBuffer() +{ + // We have no GL context whilst exiting. + if( width!=0 && !pangolin::ShouldQuit() ) { + glDeleteTextures(1, &rbid); + } +} +#endif // HAVE_GLES + +inline GlRenderBuffer::GlRenderBuffer(GlRenderBuffer&& tex) + : width(tex.width), height(tex.height), rbid(tex.rbid) +{ + tex.rbid = tex.width = tex.height = 0; +} + +//////////////////////////////////////////////////////////////////////////// + +inline GlFramebuffer::GlFramebuffer() + : fbid(0), attachments(0) +{ +} + +inline GlFramebuffer::~GlFramebuffer() +{ + if(fbid) { + glDeleteFramebuffersEXT(1, &fbid); + } +} + +inline GlFramebuffer::GlFramebuffer(GlTexture& colour, GlRenderBuffer& depth) + : attachments(0) +{ + glGenFramebuffersEXT(1, &fbid); + AttachColour(colour); + AttachDepth(depth); + CheckGlDieOnError(); +} + +inline GlFramebuffer::GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlRenderBuffer& depth) + : attachments(0) +{ + glGenFramebuffersEXT(1, &fbid); + AttachColour(colour0); + AttachColour(colour1); + AttachDepth(depth); + CheckGlDieOnError(); +} + +inline GlFramebuffer::GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlTexture& colour2, GlRenderBuffer& depth) + : attachments(0) +{ + glGenFramebuffersEXT(1, &fbid); + AttachColour(colour0); + AttachColour(colour1); + AttachColour(colour2); + AttachDepth(depth); + CheckGlDieOnError(); +} + +inline GlFramebuffer::GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlTexture& colour2, GlTexture& colour3, GlRenderBuffer& depth) + : attachments(0) +{ + glGenFramebuffersEXT(1, &fbid); + AttachColour(colour0); + AttachColour(colour1); + AttachColour(colour2); + AttachColour(colour3); + AttachDepth(depth); + CheckGlDieOnError(); +} + +inline void GlFramebuffer::Bind() const +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbid); +#ifndef HAVE_GLES + glDrawBuffers( attachments, attachment_buffers ); +#endif +} + +inline void GlFramebuffer::Reinitialise() +{ + if(fbid) { + glDeleteFramebuffersEXT(1, &fbid); + } + glGenFramebuffersEXT(1, &fbid); +} + +inline void GlFramebuffer::Unbind() const +{ +#ifndef HAVE_GLES + glDrawBuffers( 1, attachment_buffers ); +#endif + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +} + +inline GLenum GlFramebuffer::AttachColour(GlTexture& tex ) +{ + if(!fbid) Reinitialise(); + + const GLenum color_attachment = GL_COLOR_ATTACHMENT0_EXT + attachments; + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbid); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, color_attachment, GL_TEXTURE_2D, tex.tid, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + attachments++; + CheckGlDieOnError(); + return color_attachment; +} + +inline void GlFramebuffer::AttachDepth(GlRenderBuffer& rb ) +{ + if(!fbid) Reinitialise(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbid); +#if !defined(HAVE_GLES) + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rb.rbid); +#elif defined(HAVE_GLES_2) + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, rb.rbid, 0); +#else + throw std::exception(); +#endif + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + CheckGlDieOnError(); +} + +//////////////////////////////////////////////////////////////////////////// + +inline GlBufferData::GlBufferData() + : bo(0) +{ +} + +inline GlBufferData::GlBufferData(GlBufferType buffer_type, GLuint size_bytes, GLenum gluse, const unsigned char* data ) + : bo(0) +{ + Reinitialise(buffer_type, size_bytes, gluse, data ); +} + +//! Move Constructor +inline GlBufferData::GlBufferData(GlBufferData&& tex) + : bo(0) +{ + *this = std::move(tex); +} +inline GlBufferData& GlBufferData::operator=(GlBufferData&& tex) +{ + Free(); + this->bo = tex.bo; + this->buffer_type = tex.buffer_type; + this->gluse = tex.gluse; + this->size_bytes = tex.size_bytes; + tex.bo = 0; + return *this; +} + +inline GlBufferData::~GlBufferData() +{ + Free(); +} + +inline void GlBufferData::Free() +{ + if(bo!=0) { + glDeleteBuffers(1, &bo); + } +} + +inline bool GlBufferData::IsValid() const +{ + return bo != 0; +} + +inline size_t GlBufferData::SizeBytes() const +{ + return size_bytes; +} + +inline void GlBufferData::Reinitialise(GlBufferType buffer_type, GLuint size_bytes, GLenum gluse, const unsigned char* data ) +{ + if(!bo) { + glGenBuffers(1, &bo); + } + + this->buffer_type = buffer_type; + this->gluse = gluse; + this->size_bytes = size_bytes; + + Bind(); + glBufferData(buffer_type, size_bytes, data, gluse); + Unbind(); +} + +inline void GlBufferData::Bind() const +{ + glBindBuffer(buffer_type, bo); +} + +inline void GlBufferData::Unbind() const +{ + glBindBuffer(buffer_type, 0); +} + +inline void GlBufferData::Upload(const GLvoid* data, GLsizeiptr size_bytes, GLintptr offset) +{ + if(offset + size_bytes > this->size_bytes) { + throw std::runtime_error("GlBufferData: Trying to upload past capacity."); + } + + Bind(); + glBufferSubData(buffer_type,offset,size_bytes,data); + Unbind(); +} + +inline void GlBufferData::Download(GLvoid* data, GLsizeiptr size_bytes, GLintptr offset) const +{ + Bind(); + glGetBufferSubData(buffer_type, offset, size_bytes, data); + Unbind(); +} + +//////////////////////////////////////////////////////////////////////////// + +inline GlBuffer::GlBuffer() + : GlBufferData(), num_elements(0) +{ +} + +inline GlBuffer::GlBuffer(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse ) + : GlBufferData(buffer_type, num_elements * count_per_element * GlDataTypeBytes(datatype), gluse), + datatype(datatype), num_elements(num_elements), count_per_element(count_per_element) +{ +} + + +inline GlBuffer::GlBuffer(GlBuffer&& o) + : GlBufferData() +{ + *this = std::move(o); +} + +inline GlBuffer& GlBuffer::operator=(GlBuffer&& o) +{ + datatype = o.datatype; + num_elements = o.num_elements; + count_per_element = o.count_per_element; + GlBufferData::operator =(std::move(o)); + return *this; +} + +inline void GlBuffer::Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse, const unsigned char* data ) +{ + this->datatype = datatype; + this->num_elements = num_elements; + this->count_per_element = count_per_element; + const GLuint size_bytes = num_elements * count_per_element * GlDataTypeBytes(datatype); + GlBufferData::Reinitialise(buffer_type, size_bytes, gluse, data); +} + +inline void GlBuffer::Reinitialise(GlBuffer const& other ) +{ + Reinitialise(other.buffer_type, other.num_elements, other.datatype, other.count_per_element, other.gluse); +} + +inline void GlBuffer::Resize(GLuint new_num_elements) +{ + if(bo!=0) { +#ifndef HAVE_GLES + // Backup current data, reinit memory, restore old data + const size_t backup_elements = std::min(new_num_elements,num_elements); + const size_t backup_size_bytes = backup_elements*GlDataTypeBytes(datatype)*count_per_element; + unsigned char* backup = new unsigned char[backup_size_bytes]; + Bind(); + glGetBufferSubData(buffer_type, 0, backup_size_bytes, backup); + glBufferData(buffer_type, new_num_elements*GlDataTypeBytes(datatype)*count_per_element, 0, gluse); + glBufferSubData(buffer_type, 0, backup_size_bytes, backup); + Unbind(); + delete[] backup; +#else + throw std::exception(); +#endif + }else{ + Reinitialise(buffer_type, new_num_elements, datatype, count_per_element, gluse); + } + num_elements = new_num_elements; +} + + +//////////////////////////////////////////////////////////////////////////// + +inline GlSizeableBuffer::GlSizeableBuffer(GlBufferType buffer_type, GLuint initial_num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse ) + : GlBuffer(buffer_type, initial_num_elements, datatype, count_per_element, gluse), m_num_verts(0) +{ + +} + +inline void GlSizeableBuffer::Clear() +{ + m_num_verts = 0; +} + +#ifdef USE_EIGEN +template inline +void GlSizeableBuffer::Add(const Eigen::DenseBase& vec) +{ + typedef typename Eigen::DenseBase::Scalar Scalar; + assert(vec.rows()==GlBuffer::count_per_element); + CheckResize(m_num_verts + 1); + // TODO: taking address of first element is really dodgey. Need to work out + // when this is okay! + Upload(&vec(0,0), sizeof(Scalar)*vec.rows()*vec.cols(), sizeof(Scalar)*vec.rows()*m_num_verts); + m_num_verts += vec.cols(); +} + +template inline +void GlSizeableBuffer::Update(const Eigen::DenseBase& vec, size_t position ) +{ + typedef typename Eigen::DenseBase::Scalar Scalar; + assert(vec.rows()==GlBuffer::count_per_element); + CheckResize(position + vec.cols() ); + // TODO: taking address of first element is really dodgey. Need to work out + // when this is okay! + Upload(&vec(0,0), sizeof(Scalar)*vec.rows()*vec.cols(), sizeof(Scalar)*vec.rows()*position ); + m_num_verts = std::max(position+vec.cols(), m_num_verts); +} +#endif + +inline size_t GlSizeableBuffer::start() const { + return 0; +} + +inline size_t GlSizeableBuffer::size() const { + return m_num_verts; +} + +inline void GlSizeableBuffer::CheckResize(size_t num_verts) +{ + if( num_verts > GlBuffer::num_elements) { + const size_t new_size = NextSize(num_verts); + GlBuffer::Resize((GLuint)new_size); + } +} + +inline size_t GlSizeableBuffer::NextSize(size_t min_size) const +{ + size_t new_size = std::max(GlBuffer::num_elements, 1u); + while(new_size < min_size) { + new_size *= 2; + } + return new_size; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glchar.h b/Thirdparty/Pangolin/include/pangolin/gl/glchar.h new file mode 100644 index 0000000..000d0da --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glchar.h @@ -0,0 +1,78 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin { + +struct PANGOLIN_EXPORT XYUV +{ + XYUV() {} + XYUV(GLfloat x, GLfloat y, GLfloat tu, GLfloat tv) + : x(x), y(y), tu(tu), tv(tv) {} + + XYUV operator+(float dx) const { + return XYUV(x+dx,y,tu,tv); + } + + GLfloat x, y, tu, tv; +}; + +class PANGOLIN_EXPORT GlChar +{ +public: + GlChar(); + GlChar(int tw, int th, int x, int y, int w, int h, GLfloat x_step, GLfloat ox, GLfloat oy); + + inline const XYUV& GetVert(size_t i) const { + return vs[i]; + } + + inline GLfloat StepX() const { + return x_step; + } + + inline GLfloat YMin() const { + return y_min; + } + + inline GLfloat YMax() const { + return y_max; + } + + void Draw() const; + +protected: + XYUV vs[4]; + GLfloat x_step; + GLfloat y_min, y_max; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glcuda.h b/Thirdparty/Pangolin/include/pangolin/gl/glcuda.h new file mode 100644 index 0000000..9fbf141 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glcuda.h @@ -0,0 +1,258 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include "gl.h" + +namespace pangolin +{ + +//////////////////////////////////////////////// +// Interface +//////////////////////////////////////////////// + +struct GlBufferCudaPtr : public GlBuffer +{ + //! Default constructor represents 'no buffer' + GlBufferCudaPtr(); + + GlBufferCudaPtr(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ); + GlBufferCudaPtr(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ); + + PANGOLIN_DEPRECATED + GlBufferCudaPtr(GlBufferType buffer_type, GLuint width, GLuint height, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ); + + ~GlBufferCudaPtr(); + + void Reinitialise(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ); + void Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ); + + /** + * Use parameters from another @c GlBufferCudaPtr to initialize this buffer. + */ + void Reinitialise(const GlBufferCudaPtr& other); + + unsigned int cuda_use; + cudaGraphicsResource* cuda_res; +}; + +struct GlTextureCudaArray : GlTexture +{ + GlTextureCudaArray(); + // Some internal_formats aren't accepted. I have trouble with GL_RGB8 + GlTextureCudaArray(int width, int height, GLint internal_format, bool sampling_linear = true, int border = 0, GLenum glformat = GL_RGBA, GLenum gltype = GL_UNSIGNED_BYTE, GLvoid* data = NULL); + ~GlTextureCudaArray(); + + void Reinitialise(int width, int height, GLint internal_format, bool sampling_linear = true, int border = 0, GLenum glformat = GL_RGBA, GLenum gltype = GL_UNSIGNED_BYTE, GLvoid* data = NULL) override; + cudaGraphicsResource* cuda_res; +}; + +struct CudaScopedMappedPtr +{ + CudaScopedMappedPtr(const GlBufferCudaPtr& buffer); + ~CudaScopedMappedPtr(); + void* operator*(); + cudaGraphicsResource* res; + +private: + CudaScopedMappedPtr(const CudaScopedMappedPtr&) {} +}; + +struct CudaScopedMappedArray +{ + CudaScopedMappedArray(const GlTextureCudaArray& tex); + ~CudaScopedMappedArray(); + cudaArray* operator*(); + cudaGraphicsResource* res; + +private: + CudaScopedMappedArray(const CudaScopedMappedArray&) {} +}; + +void CopyPboToTex(GlBufferCudaPtr& buffer, GlTexture& tex); + +void swap(GlBufferCudaPtr& a, GlBufferCudaPtr& b); + +//////////////////////////////////////////////// +// Implementation +//////////////////////////////////////////////// + +inline GlBufferCudaPtr::GlBufferCudaPtr() + : cuda_res(0) +{ +} + +inline GlBufferCudaPtr::GlBufferCudaPtr(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ) + : cuda_res(0) +{ + Reinitialise(buffer_type, size_bytes, cudause, gluse); +} + +inline GlBufferCudaPtr::GlBufferCudaPtr(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause, GLenum gluse ) + : cuda_res(0) +{ + Reinitialise(buffer_type, num_elements, datatype, count_per_element, cudause, gluse); +} + +inline GlBufferCudaPtr::GlBufferCudaPtr(GlBufferType buffer_type, GLuint width, GLuint height, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ) + : cuda_res(0) +{ + Reinitialise(buffer_type, width*height, datatype, count_per_element, cudause, gluse); +} + +inline GlBufferCudaPtr::~GlBufferCudaPtr() +{ + if(cuda_res) { + cudaGraphicsUnregisterResource(cuda_res); + } +} + +inline void GlBufferCudaPtr::Reinitialise(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ) +{ + GlBufferCudaPtr::Reinitialise(buffer_type, size_bytes, GL_BYTE, 1, cudause, gluse); +} + +inline void GlBufferCudaPtr::Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ ) +{ + if(cuda_res) { + cudaGraphicsUnregisterResource(cuda_res); + } + GlBuffer::Reinitialise(buffer_type, num_elements, datatype, count_per_element, gluse); + + cuda_use = cudause; + cudaGraphicsGLRegisterBuffer( &cuda_res, bo, cudause ); +} + +inline void GlBufferCudaPtr::Reinitialise(const GlBufferCudaPtr& other) +{ + Reinitialise(other.buffer_type, other.num_elements, other.datatype, other.count_per_element, other.cuda_use, other.gluse); +} + +inline GlTextureCudaArray::GlTextureCudaArray() + : GlTexture(), cuda_res(0) +{ + // Not a texture +} + +inline GlTextureCudaArray::GlTextureCudaArray(int width, int height, GLint internal_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid *data) + :GlTexture(width,height,internal_format, sampling_linear, border, glformat, gltype, data) +{ + // TODO: specify flags too + const cudaError_t err = cudaGraphicsGLRegisterImage(&cuda_res, tid, GL_TEXTURE_2D, cudaGraphicsMapFlagsNone); + if( err != cudaSuccess ) { + std::cout << "cudaGraphicsGLRegisterImage failed: " << err << std::endl; + } +} + +inline GlTextureCudaArray::~GlTextureCudaArray() +{ + if(cuda_res) { + cudaGraphicsUnregisterResource(cuda_res); + } +} + +inline void GlTextureCudaArray::Reinitialise(int width, int height, GLint internal_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid* data) +{ + if(cuda_res) { + cudaGraphicsUnregisterResource(cuda_res); + } + + GlTexture::Reinitialise(width, height, internal_format, sampling_linear, border, glformat, gltype, data); + + const cudaError_t err = cudaGraphicsGLRegisterImage(&cuda_res, tid, GL_TEXTURE_2D, cudaGraphicsMapFlagsNone); + if( err != cudaSuccess ) { + std::cout << "cudaGraphicsGLRegisterImage failed: " << err << std::endl; + } +} + +inline CudaScopedMappedPtr::CudaScopedMappedPtr(const GlBufferCudaPtr& buffer) + : res(buffer.cuda_res) +{ + cudaGraphicsMapResources(1, &res, 0); +} + +inline CudaScopedMappedPtr::~CudaScopedMappedPtr() +{ + cudaGraphicsUnmapResources(1, &res, 0); +} + +inline void* CudaScopedMappedPtr::operator*() +{ + size_t num_bytes; + void* d_ptr; + cudaGraphicsResourceGetMappedPointer(&d_ptr,&num_bytes,res); + return d_ptr; +} + +inline CudaScopedMappedArray::CudaScopedMappedArray(const GlTextureCudaArray& tex) + : res(tex.cuda_res) +{ + cudaGraphicsMapResources(1, &res); +} + +inline CudaScopedMappedArray::~CudaScopedMappedArray() +{ + cudaGraphicsUnmapResources(1, &res); +} + +inline cudaArray* CudaScopedMappedArray::operator*() +{ + cudaArray* array; + cudaGraphicsSubResourceGetMappedArray(&array, res, 0, 0); + return array; +} + +inline void CopyPboToTex(const GlBufferCudaPtr& buffer, GlTexture& tex, GLenum buffer_layout, GLenum buffer_data_type ) +{ + buffer.Bind(); + tex.Bind(); + glTexImage2D(GL_TEXTURE_2D, 0, tex.internal_format, tex.width, tex.height, 0, buffer_layout, buffer_data_type, 0); + buffer.Unbind(); + tex.Unbind(); +} + +template +inline void CopyDevMemtoTex(T* d_img, size_t pitch, GlTextureCudaArray& tex ) +{ + CudaScopedMappedArray arr_tex(tex); + cudaMemcpy2DToArray(*arr_tex, 0, 0, d_img, pitch, tex.width*sizeof(T), tex.height, cudaMemcpyDeviceToDevice ); +} + +inline void swap(GlBufferCudaPtr& a, GlBufferCudaPtr& b) +{ + std::swap(a.bo, b.bo); + std::swap(a.cuda_res, b.cuda_res); + std::swap(a.buffer_type, b.buffer_type); +} + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/gldraw.h b/Thirdparty/Pangolin/include/pangolin/gl/gldraw.h new file mode 100644 index 0000000..2ac0be7 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/gldraw.h @@ -0,0 +1,518 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files +#define USE_EIGEN +#endif + +#ifdef USE_EIGEN +#include +#include +#endif // USE_EIGEN + +namespace pangolin +{ + +// h [0,360) +// s [0,1] +// v [0,1] +inline void glColorHSV( GLfloat hue, GLfloat s=1.0f, GLfloat v=1.0f ) +{ + const GLfloat h = hue / 60.0f; + const int i = (int)floor(h); + const GLfloat f = (i%2 == 0) ? 1-(h-i) : h-i; + const GLfloat m = v * (1-s); + const GLfloat n = v * (1-s*f); + switch(i) + { + case 0: glColor4f(v,n,m,1); break; + case 1: glColor4f(n,v,m,1); break; + case 2: glColor4f(m,v,n,1); break; + case 3: glColor4f(m,n,v,1); break; + case 4: glColor4f(n,m,v,1); break; + case 5: glColor4f(v,m,n,1); break; + default: + break; + } +} + +inline void glColorBin( int bin, int max_bins, GLfloat sat=1.0f, GLfloat val=1.0f ) +{ + if( bin >= 0 ) { + const GLfloat hue = (GLfloat)(bin%max_bins) * 360.0f / (GLfloat)max_bins; + glColorHSV(hue,sat,val); + }else{ + glColor4f(1,1,1,1); + } +} + +template +inline void glDrawVertices( + size_t num_vertices, const T* const vertex_ptr, GLenum mode, + size_t elements_per_vertex = GlFormatTraits::components, + size_t vertex_stride_bytes = 0 ) +{ + if(num_vertices > 0) + { + PANGO_ENSURE(vertex_ptr != nullptr); + PANGO_ENSURE(mode != GL_LINES || num_vertices % 2 == 0, "number of vertices (%) must be even in GL_LINES mode", num_vertices ); + + glVertexPointer(elements_per_vertex, GlFormatTraits::gltype, vertex_stride_bytes, vertex_ptr); + glEnableClientState(GL_VERTEX_ARRAY); + glDrawArrays(mode, 0, num_vertices); + glDisableClientState(GL_VERTEX_ARRAY); + } +} + +template +inline void glDrawColoredVertices( + size_t num_vertices, const TV* const vertex_ptr, const TC* const color_ptr, GLenum mode, + size_t elements_per_vertex = GlFormatTraits::components, + size_t elements_per_color = GlFormatTraits::components, + size_t vertex_stride_bytes = 0, + size_t color_stride_bytes = 0 +) { + if(color_ptr) { + glColorPointer(elements_per_color, GlFormatTraits::gltype, color_stride_bytes, color_ptr); + glEnableClientState(GL_COLOR_ARRAY); + glDrawVertices(num_vertices, vertex_ptr, mode, elements_per_vertex, vertex_stride_bytes); + glDisableClientState(GL_COLOR_ARRAY); + }else{ + glDrawVertices(num_vertices, vertex_ptr, mode, elements_per_vertex, vertex_stride_bytes); + } +} + +inline void glDrawLine( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) +{ + const GLfloat verts[] = { x1,y1, x2,y2 }; + glDrawVertices(2, verts, GL_LINES, 2); +} + +inline void glDrawLine( GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) +{ + const GLfloat verts[] = { x1,y1,z1, x2,y2,z2 }; + glDrawVertices(2, verts, GL_LINES, 3); +} + +inline void glDrawCross( GLfloat x, GLfloat y, GLfloat rad ) +{ + const GLfloat verts[] = { x-rad,y, x+rad, y, x,y-rad, x, y+rad}; + glDrawVertices(4, verts, GL_LINES, 2); +} + +inline void glDrawCross( GLfloat x, GLfloat y, GLfloat z, GLfloat rad ) +{ + const GLfloat verts[] = { x-rad,y,z, x+rad,y,z, x,y-rad,z, x,y+rad,z, x,y,z-rad, x,y,z+rad }; + glDrawVertices(6, verts, GL_LINES, 3); +} + +inline void glDrawAxis(float s) +{ + const GLfloat cols[] = { 1,0,0, 1,0,0, 0,1,0, 0,1,0, 0,0,1, 0,0,1 }; + const GLfloat verts[] = { 0,0,0, s,0,0, 0,0,0, 0,s,0, 0,0,0, 0,0,s }; + glDrawColoredVertices(6, verts, cols, GL_LINES, 3, 3); +} + +inline void glDrawRect( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLenum mode = GL_TRIANGLE_FAN ) +{ + const GLfloat verts[] = { x1,y1, x2,y1, x2,y2, x1,y2 }; + glDrawVertices(4, verts, mode, 2); +} + +inline void glDrawRectPerimeter( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) +{ + glDrawRect(x1,y1, x2,y2, GL_LINE_LOOP); +} + +inline void glDrawCirclePerimeter( float x, float y, float rad ) +{ + const int N = 50; + GLfloat verts[N*2]; + + const float TAU_DIV_N = 2*(float)M_PI/N; + for(int i = 0; i < N*2; i+=2) { + verts[i] = x + rad * cos(i*TAU_DIV_N); + verts[i+1] = y + rad * sin(i*TAU_DIV_N); + } + + glDrawVertices(N, verts, GL_LINES, 2); +} + +inline void glDrawCircle( GLfloat x, GLfloat y, GLfloat rad ) +{ + const int N = 50; + GLfloat verts[N*2]; + + // Draw vertices anticlockwise for front face + const float TAU_DIV_N = 2*(float)M_PI/N; + for(int i = 0; i < N*2; i+=2) { + verts[i] = x + rad * cos(-i*TAU_DIV_N); + verts[i+1] = y + rad * sin(-i*TAU_DIV_N); + } + + // Render filled shape and outline (to make it look smooth) + glVertexPointer(2, GL_FLOAT, 0, verts); + glEnableClientState(GL_VERTEX_ARRAY); + glDrawArrays(GL_TRIANGLE_FAN, 0, N); + glDrawArrays(GL_LINE_STRIP, 0, N); + glDisableClientState(GL_VERTEX_ARRAY); +} + +inline void glDrawColouredCube(GLfloat axis_min=-0.5f, GLfloat axis_max = +0.5f) +{ + const GLfloat l = axis_min; + const GLfloat h = axis_max; + + const GLfloat verts[] = { + l,l,h, h,l,h, l,h,h, h,h,h, // FRONT + l,l,l, l,h,l, h,l,l, h,h,l, // BACK + l,l,h, l,h,h, l,l,l, l,h,l, // LEFT + h,l,l, h,h,l, h,l,h, h,h,h, // RIGHT + l,h,h, h,h,h, l,h,l, h,h,l, // TOP + l,l,h, l,l,l, h,l,h, h,l,l // BOTTOM + }; + + glVertexPointer(3, GL_FLOAT, 0, verts); + glEnableClientState(GL_VERTEX_ARRAY); + + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); + + glColor4f(0.0f, 1.0f, 0.0f, 1.0f); + glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); + + glColor4f(0.0f, 0.0f, 1.0f, 1.0f); + glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); + + glDisableClientState(GL_VERTEX_ARRAY); +} + +inline void glDraw_x0(GLfloat scale, int grid) +{ + const GLfloat maxord = grid*scale; + for (int i = -grid; i <= grid; ++i) { + glDrawLine(0.0, i*scale, -maxord, 0.0, i*scale, +maxord); + glDrawLine(0.0, -maxord, i*scale, 0.0, +maxord, i*scale); + } +} + +inline void glDraw_y0(GLfloat scale, int grid) +{ + const GLfloat maxord = grid*scale; + for (int i = -grid; i <= grid; ++i) { + glDrawLine(i*scale, 0.0, -maxord, i*scale, 0.0, +maxord); + glDrawLine(-maxord, 0.0, i*scale, +maxord, 0.0, i*scale); + } +} + +inline void glDraw_z0(GLfloat scale, int grid) +{ + const GLfloat maxord = grid*scale; + for(int i=-grid; i<=grid; ++i ) { + glDrawLine(i*scale,-maxord, i*scale,+maxord); + glDrawLine(-maxord, i*scale, +maxord, i*scale); + } +} + +inline void glDrawFrustum( GLfloat u0, GLfloat v0, GLfloat fu, GLfloat fv, int w, int h, GLfloat scale ) +{ + const GLfloat xl = scale * u0; + const GLfloat xh = scale * (w*fu + u0); + const GLfloat yl = scale * v0; + const GLfloat yh = scale * (h*fv + v0); + + const GLfloat verts[] = { + xl,yl,scale, xh,yl,scale, + xh,yh,scale, xl,yh,scale, + xl,yl,scale, 0,0,0, + xh,yl,scale, 0,0,0, + xl,yh,scale, 0,0,0, + xh,yh,scale + }; + + glDrawVertices(11, verts, GL_LINE_STRIP, 3); +} + +inline void glDrawTexture(GLenum target, GLuint texid) +{ + glBindTexture(target, texid); + glEnable(target); + + const GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; + glVertexPointer(2, GL_FLOAT, 0, sq_vert); + glEnableClientState(GL_VERTEX_ARRAY); + + const GLfloat sq_tex[] = { 0,0, 1,0, 1,1, 0,1 }; + glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glColor4f(1,1,1,1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(target); +} + +inline void glDrawTextureFlipY(GLenum target, GLuint texid) +{ + glBindTexture(target, texid); + glEnable(target); + + const GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; + glVertexPointer(2, GL_FLOAT, 0, sq_vert); + glEnableClientState(GL_VERTEX_ARRAY); + + const GLfloat sq_tex[] = { 0,1, 1,1, 1,0, 0,0 }; + glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glColor4f(1,1,1,1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(target); +} + + +#ifdef USE_EIGEN + +#ifndef HAVE_GLES +inline void glVertex( const Eigen::Vector3d& p ) +{ + glVertex3dv(p.data()); +} +#endif + +inline void glDrawLine( const Eigen::Vector2d& p1, const Eigen::Vector2d& p2 ) +{ + glDrawLine((GLfloat)p1(0), (GLfloat)p1(1), (GLfloat)p2(0), (GLfloat)p2(1)); +} + +// Draws a vector of 2d or 3d vertices using provided ``mode``. +// +// Preconditions: +// - ``mode`` must be GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, etc +// - If ``mode == GL_LINES``, then ``vertices.size()`` must be a multiple of 2. +// +template +void glDrawVertices(const std::vector, Allocator>& vertices, GLenum mode) +{ + glDrawVertices(vertices.size(), vertices.data(), mode); +} + +// Draws a vector of 2d or 3d points. +// +template +void glDrawPoints(const std::vector, Allocator>& vertices) +{ + glDrawVertices(vertices, GL_POINTS); +} + +// Draws a vector of 2d or 3d lines. +// +// Precondition: ``vertices.size()`` must be a multiple of 2. +// +template +void glDrawLines(const std::vector, Allocator>& vertices) +{ + glDrawVertices(vertices, GL_LINES); +} + +// Draws a 2d or 3d line strip. +// +template +void glDrawLineStrip(const std::vector, Allocator>& vertices) +{ + glDrawVertices(vertices, GL_LINE_STRIP); +} + +// Draws a 2d or 3d line loop. +// +template +void glDrawLineLoop(const std::vector, Allocator>& vertices) +{ + glDrawVertices(vertices, GL_LINE_LOOP); +} + +inline void glDrawCross( const Eigen::Vector2d& p, double r = 5.0 ) +{ + glDrawCross((GLfloat)p(0), (GLfloat)p(1), (GLfloat)r); +} + +inline void glDrawCross( const Eigen::Vector3d& p, double r = 5.0 ) +{ + glDrawCross((GLfloat)p(0), (GLfloat)p(1), (GLfloat)p(2), (GLfloat)r); +} + +inline void glDrawCircle( const Eigen::Vector2d& p, double radius = 5.0 ) +{ + glDrawCircle((GLfloat)p(0), (GLfloat)p(1), (GLfloat)radius); +} + +inline void glDrawCirclePerimeter( const Eigen::Vector2d& p, double radius = 5.0 ) +{ + glDrawCirclePerimeter((GLfloat)p(0), (GLfloat)p(1), (GLfloat)radius); +} + +inline void glSetFrameOfReference( const Eigen::Matrix4f& T_wf ) +{ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMultMatrixf( T_wf.data() ); +} + +inline void glSetFrameOfReference( const Eigen::Matrix4d& T_wf ) +{ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +#ifndef HAVE_GLES + glMultMatrixd( T_wf.data() ); +#else + const Eigen::Matrix4f fT_wf = T_wf.cast(); + glMultMatrixf( fT_wf.data() ); +#endif +} + +inline void glSetFrameOfReference( const pangolin::OpenGlMatrix& T_wf ) +{ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMultMatrixd( T_wf.m ); +} + +inline void glUnsetFrameOfReference() +{ + glPopMatrix(); +} + +template +inline void glDrawAxis( const T& T_wf, S scale ) +{ + glSetFrameOfReference(T_wf); + glDrawAxis(scale); + glUnsetFrameOfReference(); +} + +template +inline void glDrawFrustum( const Eigen::Matrix& Kinv, int w, int h, GLfloat scale ) +{ + glDrawFrustum((GLfloat)Kinv(0,2), (GLfloat)Kinv(1,2), (GLfloat)Kinv(0,0), (GLfloat)Kinv(1,1), w, h, scale); +} + +template +inline void glDrawFrustum( const Eigen::Matrix& Kinv, int w, int h, const Eigen::Matrix& T_wf, T scale ) +{ + glSetFrameOfReference(T_wf); + glDrawFrustum(Kinv,w,h,scale); + glUnsetFrameOfReference(); +} + +template +inline void glDrawAlignedBox( const Eigen::AlignedBox& box, GLenum mode = GL_TRIANGLE_FAN ) +{ + const Eigen::Matrix l = box.min().template cast(); + const Eigen::Matrix h = box.max().template cast(); + + GLfloat verts[] = { + l[0], l[1], + h[0], l[1], + h[0], h[1], + l[0], h[1] + }; + + glDrawVertices(4, verts, mode, 2); +} + +template +inline void glDrawAlignedBoxPerimeter( const Eigen::AlignedBox& box) +{ + glDrawAlignedBox(box, GL_LINE_LOOP); +} + +template +inline void glDrawAlignedBox( const Eigen::AlignedBox& box) +{ + const Eigen::Matrix l = box.min().template cast(); + const Eigen::Matrix h = box.max().template cast(); + + GLfloat verts[] = { + l[0], l[1], l[2], + l[0], l[1], h[2], + h[0], l[1], h[2], + h[0], l[1], l[2], + l[0], l[1], l[2], + l[0], h[1], l[2], + h[0], h[1], l[2], + h[0], l[1], l[2], + h[0], h[1], l[2], + h[0], h[1], h[2], + l[0], h[1], h[2], + l[0], h[1], l[2], + l[0], h[1], h[2], + l[0], l[1], h[2], + h[0], l[1], h[2], + h[0], h[1], h[2] + }; + + glDrawVertices(16, verts, GL_LINE_STRIP, 3); +} + +#endif // USE_EIGEN + +#ifndef HAVE_GLES +inline void glPixelTransferScale( float r, float g, float b ) +{ + glPixelTransferf(GL_RED_SCALE,r); + glPixelTransferf(GL_GREEN_SCALE,g); + glPixelTransferf(GL_BLUE_SCALE,b); +} + +inline void glPixelTransferScale( float scale ) +{ + glPixelTransferScale(scale,scale,scale); +} +#endif + +void glRecordGraphic(float x, float y, float radius); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glfont.h b/Thirdparty/Pangolin/include/pangolin/gl/glfont.h new file mode 100644 index 0000000..2304c2f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glfont.h @@ -0,0 +1,78 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2015 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include + +namespace pangolin { + +class PANGOLIN_EXPORT GlFont +{ +public: + // Singleton instance if requested. + static GlFont& I(); + + // Load GL Font data. Delay uploading as texture until first use. + GlFont(const unsigned char* ttf_buffer, float pixel_height, int tex_w=512, int tex_h=512); + GlFont(const std::string& filename, float pixel_height, int tex_w=512, int tex_h=512); + + virtual ~GlFont(); + + // Generate renderable GlText object from this font. + GlText Text( const char* fmt, ... ); + + GlText Text( const std::string& str ); + + inline float Height() const { + return font_height_px; + } + +protected: + void InitialiseFont(const unsigned char* ttf_buffer, float pixel_height, int tex_w, int tex_h); + + // This can only be called once GL context is initialised + void InitialiseGlTexture(); + + const static int FIRST_CHAR = 32; + const static int NUM_CHARS = 96; + + float font_height_px; + + int tex_w; + int tex_h; + unsigned char* font_bitmap; + GlTexture mTex; + + GlChar chardata[NUM_CHARS]; + GLfloat kern_table[NUM_CHARS*NUM_CHARS]; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glformattraits.h b/Thirdparty/Pangolin/include/pangolin/gl/glformattraits.h new file mode 100644 index 0000000..7c1dc58 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glformattraits.h @@ -0,0 +1,214 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#ifdef HAVE_EIGEN +# include +#endif + +namespace pangolin +{ + +template +struct GlFormatTraits; +//{ +// static const GLint glinternalformat = 0; +// static const GLenum glformat = 0; +// static const GLenum gltype = 0; +// static const T glmin = 0; +// static const T glmax = 0; +//}; + +template<> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_LUMINANCE8; + static const GLenum glformat = GL_LUMINANCE; + static const GLenum gltype = GL_UNSIGNED_BYTE; + static const size_t components = 1; +}; + +template<> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_LUMINANCE16; + static const GLenum glformat = GL_LUMINANCE; + static const GLenum gltype = GL_UNSIGNED_SHORT; + static const size_t components = 1; +}; + +template<> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_LUMINANCE32I_EXT; + static const GLenum glformat = GL_LUMINANCE; + static const GLenum gltype = GL_UNSIGNED_INT; + static const size_t components = 1; +}; + +template<> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_LUMINANCE32I_EXT; + static const GLenum glformat = GL_LUMINANCE; + static const GLenum gltype = GL_INT; + static const size_t components = 1; +}; + +template<> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_LUMINANCE32F_ARB; + static const GLenum glformat = GL_LUMINANCE; + static const GLenum gltype = GL_FLOAT; + static const size_t components = 1; +}; + +template<> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_LUMINANCE32F_ARB; + static const GLenum glformat = GL_LUMINANCE; + static const GLenum gltype = GL_DOUBLE; + static const size_t components = 1; +}; + + + +#ifdef HAVE_EIGEN + +////////////////////////////////////////////////////////////////// + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RG32I; + static const GLenum glformat = GL_RG; + static const GLenum gltype = GL_INT; + static const size_t components = 2; +}; + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RG32F; + static const GLenum glformat = GL_RG; + static const GLenum gltype = GL_FLOAT; + static const size_t components = 2; +}; + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RG32F; + static const GLenum glformat = GL_RG; + static const GLenum gltype = GL_DOUBLE; + static const size_t components = 2; +}; + +////////////////////////////////////////////////////////////////// + +template <> +struct GlFormatTraits> +{ + static const GLint glinternalformat = GL_RGB8; + static const GLenum glformat = GL_RGB; + static const GLenum gltype = GL_UNSIGNED_BYTE; + static const size_t components = 3; +}; + +template <> +struct GlFormatTraits> +{ + static const GLint glinternalformat = GL_RGBA16; + static const GLenum glformat = GL_RGB; + static const GLenum gltype = GL_UNSIGNED_SHORT; + static const size_t components = 3; +}; + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RGB32F; + static const GLenum glformat = GL_RGB; + static const GLenum gltype = GL_FLOAT; + static const size_t components = 3; +}; + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RGB32F; + static const GLenum glformat = GL_RGB; + static const GLenum gltype = GL_DOUBLE; + static const size_t components = 3; +}; + +////////////////////////////////////////////////////////////////// + +template <> +struct GlFormatTraits> +{ + static const GLint glinternalformat = GL_RGBA8; + static const GLenum glformat = GL_RGBA; + static const GLenum gltype = GL_UNSIGNED_BYTE; + static const size_t components = 4; +}; + +template <> +struct GlFormatTraits> +{ + static const GLint glinternalformat = GL_RGBA16; + static const GLenum glformat = GL_RGBA; + static const GLenum gltype = GL_UNSIGNED_SHORT; + static const size_t components = 4; +}; + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RGBA32F; + static const GLenum glformat = GL_RGBA; + static const GLenum gltype = GL_FLOAT; + static const size_t components = 4; +}; + +template <> +struct GlFormatTraits +{ + static const GLint glinternalformat = GL_RGBA32F; + static const GLenum glformat = GL_RGBA; + static const GLenum gltype = GL_DOUBLE; + static const size_t components = 4; +}; + +#endif // HAVE_EIGEN + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glinclude.h b/Thirdparty/Pangolin/include/pangolin/gl/glinclude.h new file mode 100644 index 0000000..fdd19ce --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glinclude.h @@ -0,0 +1,46 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove, Richard Newcombe + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#ifdef HAVE_GLES +#include +#endif + +#define CheckGlDieOnError() pangolin::_CheckGlDieOnError( __FILE__, __LINE__ ); +namespace pangolin { +inline void _CheckGlDieOnError( const char *sFile, const int nLine ) +{ + const GLenum glError = glGetError(); + if( glError != GL_NO_ERROR ) { + pango_print_error("OpenGL Error %x: %s\n", glError, glErrorString(glError)); + pango_print_error("In: %s, line %d\n", sFile, nLine); + } +} +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glpangoglu.h b/Thirdparty/Pangolin/include/pangolin/gl/glpangoglu.h new file mode 100644 index 0000000..bb29429 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glpangoglu.h @@ -0,0 +1,79 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin { + +PANGOLIN_EXPORT +const char* glErrorString(GLenum error); + +/// Clone of gluProject +PANGOLIN_EXPORT +GLint glProject( + float objx, float objy, float objz, + const float modelMatrix[16], + const float projMatrix[16], + const GLint viewport[4], + float* winx, float* winy, float* winz +); + + +/// Clone of gluUnProject +PANGOLIN_EXPORT +GLint glUnProject( + float winx, float winy, float winz, + const float modelMatrix[16], + const float projMatrix[16], + const GLint viewport[4], + float* objx, float* objy, float* objz +); + +/// Clone of gluProject +PANGOLIN_EXPORT +GLint glProject( + double objx, double objy, double objz, + const double modelMatrix[16], + const double projMatrix[16], + const GLint viewport[4], + double* winx, double* winy, double* winz +); + + +/// Clone of gluUnProject +PANGOLIN_EXPORT +GLint glUnProject( + double winx, double winy, double winz, + const double modelMatrix[16], + const double projMatrix[16], + const GLint viewport[4], + double* objx, double* objy, double* objz +); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glpixformat.h b/Thirdparty/Pangolin/include/pangolin/gl/glpixformat.h new file mode 100644 index 0000000..2ceebd5 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glpixformat.h @@ -0,0 +1,95 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace pangolin { + +// This class may dissapear in the future +struct GlPixFormat +{ + GlPixFormat() {} + + GlPixFormat(const PixelFormat& fmt) + { + switch( fmt.channels) { + case 1: glformat = GL_LUMINANCE; break; + case 3: glformat = (fmt.format == "BGR24" || fmt.format == "BGR48") ? GL_BGR : GL_RGB; break; + case 4: glformat = (fmt.format == "BGRA24" || fmt.format == "BGRA32" || fmt.format == "BGRA48") ? GL_BGRA : GL_RGBA; break; + default: throw std::runtime_error("Unable to form OpenGL format from video format: '" + fmt.format + "'."); + } + + const bool is_integral = fmt.format.find('F') == std::string::npos; + + switch (fmt.channel_bits[0]) { + case 8: gltype = GL_UNSIGNED_BYTE; break; + case 16: gltype = GL_UNSIGNED_SHORT; break; + case 32: gltype = (is_integral ? GL_UNSIGNED_INT : GL_FLOAT); break; + case 64: gltype = (is_integral ? GL_UNSIGNED_INT64_NV : GL_DOUBLE); break; + default: throw std::runtime_error("Unknown OpenGL data type for video format: '" + fmt.format + "'."); + } + + if(glformat == GL_LUMINANCE) { + if(gltype == GL_UNSIGNED_BYTE) { + scalable_internal_format = GL_LUMINANCE8; + }else if(gltype == GL_UNSIGNED_SHORT){ + scalable_internal_format = GL_LUMINANCE16; + }else{ + scalable_internal_format = GL_LUMINANCE32F_ARB; + } + }else{ + if(gltype == GL_UNSIGNED_BYTE) { + scalable_internal_format = GL_RGBA8; + }else if(gltype == GL_UNSIGNED_SHORT) { + scalable_internal_format = GL_RGBA16; + }else{ + scalable_internal_format = GL_RGBA32F; + } + } + } + + template + static GlPixFormat FromType() + { + GlPixFormat fmt; + fmt.glformat = GlFormatTraits::glformat; + fmt.gltype = GlFormatTraits::gltype; + fmt.scalable_internal_format = GlFormatTraits::glinternalformat; + return fmt; + } + + GLint glformat; + GLenum gltype; + GLint scalable_internal_format; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glplatform.h b/Thirdparty/Pangolin/include/pangolin/gl/glplatform.h new file mode 100644 index 0000000..caa0ad3 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glplatform.h @@ -0,0 +1,83 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +////////////////////////////////////////////////////////// +// Attempt to portably include Necessary OpenGL headers +////////////////////////////////////////////////////////// + +#include + +#ifdef _WIN_ + // Define maths quantities when using to match posix systems + #ifndef _USE_MATH_DEFINES + # define _USE_MATH_DEFINES + #endif + + // Don't define min / max macros in windows.h or other unnecessary macros + #ifndef NOMINMAX + # define NOMINMAX + #endif + #ifndef WIN32_LEAN_AND_MEAN + # define WIN32_LEAN_AND_MEAN + #endif + #include + + // Undef nuisance Windows.h macros which interfere with our methods + #undef LoadImage + #undef near + #undef far + #undef ERROR +#endif + +#include + +#ifdef HAVE_GLES + #if defined(_ANDROID_) + #include + #ifdef HAVE_GLES_2 + #include + #include + #else + #include + #define GL_GLEXT_PROTOTYPES + #include + #endif + #elif defined(_APPLE_IOS_) + #include + #include + #endif +#else + #ifdef _OSX_ + #include + #else + #include + #endif +#endif // HAVE_GLES + +#include diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glsl.h b/Thirdparty/Pangolin/include/pangolin/gl/glsl.h new file mode 100644 index 0000000..422bbb4 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glsl.h @@ -0,0 +1,738 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_GLES + #define GLhandleARB GLuint +#endif + +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files +#define USE_EIGEN +#endif + +#ifdef USE_EIGEN +#include +#endif // USE_EIGEN + +namespace pangolin +{ + +//////////////////////////////////////////////// +// Standard attribute locations +//////////////////////////////////////////////// + +const GLuint DEFAULT_LOCATION_POSITION = 0; +const GLuint DEFAULT_LOCATION_COLOUR = 1; +const GLuint DEFAULT_LOCATION_NORMAL = 2; +const GLuint DEFAULT_LOCATION_TEXCOORD = 3; + +const char DEFAULT_NAME_POSITION[] = "a_position"; +const char DEFAULT_NAME_COLOUR[] = "a_color"; +const char DEFAULT_NAME_NORMAL[] = "a_normal"; +const char DEFAULT_NAME_TEXCOORD[] = "a_texcoord"; + +//////////////////////////////////////////////// +// Interface +//////////////////////////////////////////////// + +enum GlSlShaderType +{ + GlSlAnnotatedShader = 0, + GlSlFragmentShader = GL_FRAGMENT_SHADER, + GlSlVertexShader = GL_VERTEX_SHADER, + GlSlGeometryShader = 0x8DD9 /*GL_GEOMETRY_SHADER*/, + GlSlComputeShader = 0x91B9 /*GL_COMPUTE_SHADER*/ +}; + +class GlSlProgram +{ +public: + GlSlProgram(); + + //! Move Constructor + GlSlProgram(GlSlProgram&& tex); + + ~GlSlProgram(); + + bool AddShader( + GlSlShaderType shader_type, + const std::string& source_code, + const std::map& program_defines = std::map(), + const std::vector& search_path = std::vector() + ); + + bool AddShaderFromFile( + GlSlShaderType shader_type, + const std::string& filename, + const std::map& program_defines = std::map(), + const std::vector& search_path = std::vector() + ); + + bool Link(); + + // Remove all shaders from this program, and reload from files. + bool ReloadShaderFiles(); + + GLint GetAttributeHandle(const std::string& name); + GLint GetUniformHandle(const std::string& name); + + // Before setting uniforms, be sure to Bind() the GlSl program first. + void SetUniform(const std::string& name, int x); + void SetUniform(const std::string& name, int x1, int x2); + void SetUniform(const std::string& name, int x1, int x2, int x3); + void SetUniform(const std::string& name, int x1, int x2, int x3, int x4); + + void SetUniform(const std::string& name, float f); + void SetUniform(const std::string& name, float f1, float f2); + void SetUniform(const std::string& name, float f1, float f2, float f3); + void SetUniform(const std::string& name, float f1, float f2, float f3, float f4); + + void SetUniform(const std::string& name, Colour c); + + void SetUniform(const std::string& name, const OpenGlMatrix& m); + +#ifdef HAVE_EIGEN + void SetUniform(const std::string& name, const Eigen::Matrix3f& m); + void SetUniform(const std::string& name, const Eigen::Matrix4f& m); + void SetUniform(const std::string& name, const Eigen::Matrix3d& m); + void SetUniform(const std::string& name, const Eigen::Matrix4d& m); +#endif + +#if GL_VERSION_4_3 + GLint GetProgramResourceIndex(const std::string& name); + void SetShaderStorageBlock(const std::string& name, const int& bindingIndex); +#endif + + void Bind(); + void SaveBind(); + void Unbind(); + + + void BindPangolinDefaultAttribLocationsAndLink(); + + // Unlink all shaders from program + void ClearShaders(); + + GLint ProgramId() const { + return prog; + } + + bool Valid() const { + return ProgramId() != 0; + } + +protected: + struct ShaderFileOrCode + { + GlSlShaderType shader_type; + std::string filename; + std::string code; + std::map program_defines; + std::vector search_path; + }; + + + // Convenience method to load shader description + bool AddShaderFile(const ShaderFileOrCode &shader_file); + + std::string ParseIncludeFilename( + const std::string& location + ); + + std::string SearchIncludePath( + const std::string& filename, + const std::vector& search_path, + const std::string& current_path + ); + + bool AddPreprocessedShader( + GlSlShaderType shader_type, + const std::string& source_code, + const std::string& name_for_errors + ); + + void PreprocessGLSL( + std::istream& input, + std::ostream& output, + const std::map& program_defines, + const std::vector& search_path, + const std::string& current_path + ); + + // Split 'code' into several code blocks per shader type + // shader blocks in 'code' must be annotated with: + // @start vertex, @start fragment, @start geometry or @start compute + static std::map + SplitAnnotatedShaders(const std::string& code); + + bool linked; + std::vector shaders; + GLenum prog; + GLint prev_prog; + std::vector shader_files; +}; + +class GlSlUtilities +{ +public: + inline static GlSlProgram& OffsetAndScale(float offset, float scale) { + GlSlProgram& prog = Instance().prog_offsetscale; + prog.Bind(); + prog.SetUniform("offset", offset); + prog.SetUniform("scale", scale); + return prog; + } + + inline static GlSlProgram& Scale(float scale, float bias = 0.0f) { + GlSlProgram& prog = Instance().prog_scale; + prog.Bind(); + prog.SetUniform("scale", scale); + prog.SetUniform("bias", bias); + return prog; + } + + inline static void UseNone() + { + glUseProgram(0); + } + +protected: + static GlSlUtilities& Instance() { + // TODO: BUG: The GlSLUtilities instance needs to be tied + // to the OpenGL context, not the thread, or globally. +#ifndef PANGO_NO_THREADLOCAL + thread_local +#else + static +#endif + GlSlUtilities instance; + return instance; + } + + // protected constructor + GlSlUtilities() { + const char* source_scale = + "uniform float scale;" + "uniform float bias;" + "uniform sampler2D tex;" + "void main() {" + " vec2 uv = gl_TexCoord[0].st;" + " if(0.0 <= uv.x && uv.x <= 1.0 && 0.0 <= uv.y && uv.y <= 1.0) {" + " gl_FragColor = texture2D(tex,uv);" + " gl_FragColor.xyz *= scale;" + " gl_FragColor.xyz += vec3(bias,bias,bias);" + " }else{" + " float v = 0.1;" + " gl_FragColor.xyz = vec3(v,v,v);" + " }" + "}"; + prog_scale.AddShader(GlSlFragmentShader, source_scale); + prog_scale.Link(); + + const char* source_offsetscale = + "uniform float offset;" + "uniform float scale;" + "uniform sampler2D tex;" + "void main() {" + " vec2 uv = gl_TexCoord[0].st;" + " if(0.0 <= uv.x && uv.x <= 1.0 && 0.0 <= uv.y && uv.y <= 1.0) {" + " gl_FragColor = texture2D(tex,gl_TexCoord[0].st);" + " gl_FragColor.xyz += vec3(offset,offset,offset);" + " gl_FragColor.xyz *= scale;" + " }else{" + " float v = 0.1;" + " gl_FragColor.xyz = vec3(v,v,v);" + " }" + "}"; + prog_offsetscale.AddShader(GlSlFragmentShader, source_offsetscale); + prog_offsetscale.Link(); + } + + GlSlProgram prog_scale; + GlSlProgram prog_offsetscale; +}; + + +//////////////////////////////////////////////// +// Implementation +//////////////////////////////////////////////// + +inline bool IsLinkSuccessPrintLog(GLhandleARB prog) +{ + GLint status; + glGetProgramiv(prog, GL_LINK_STATUS, &status); + if(status != GL_TRUE) { + pango_print_error("GLSL Program link failed: "); + const int PROGRAM_LOG_MAX_LEN = 10240; + char infolog[PROGRAM_LOG_MAX_LEN]; + GLsizei len; + glGetProgramInfoLog(prog, PROGRAM_LOG_MAX_LEN, &len, infolog); + if(len) { + pango_print_error("%s\n",infolog); + }else{ + pango_print_error("No details provided.\n"); + } + return false; + } + return true; +} + +inline bool IsCompileSuccessPrintLog(GLhandleARB shader, const std::string& name_for_errors) +{ + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(status != GL_TRUE) { + pango_print_error("GLSL Shader compilation failed: "); + const int SHADER_LOG_MAX_LEN = 10240; + char infolog[SHADER_LOG_MAX_LEN]; + GLsizei len; + glGetShaderInfoLog(shader, SHADER_LOG_MAX_LEN, &len, infolog); + if(len) { + pango_print_error("%s:\n%s\n",name_for_errors.c_str(), infolog); + }else{ + pango_print_error("%s:\nNo details provided.\n",name_for_errors.c_str()); + } + return false; + } + return true; +} + +inline GlSlProgram::GlSlProgram() + : linked(false), prog(0), prev_prog(0) +{ +} + +//! Move Constructor +inline GlSlProgram::GlSlProgram(GlSlProgram&& o) + : linked(o.linked), shaders(o.shaders), prog(o.prog), prev_prog(o.prev_prog) +{ + o.prog = 0; +} + +inline GlSlProgram::~GlSlProgram() +{ + if(prog) { + ClearShaders(); + glDeleteProgram(prog); + } +} + +inline void PrintSourceCode(const std::string& src) +{ + std::stringstream ss(src); + std::string line; + + for(int linenum=1; std::getline(ss,line,'\n'); ++linenum) { + std::cout << linenum << ":\t" << line << std::endl; + } +} + +inline bool GlSlProgram::AddPreprocessedShader( + GlSlShaderType shader_type, + const std::string& source_code, + const std::string& name_for_errors +) { + if(!prog) { + prog = glCreateProgram(); + } + +// PrintSourceCode(source_code); + + GLhandleARB shader = glCreateShader(shader_type); + const char* source = source_code.c_str(); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + bool success = IsCompileSuccessPrintLog(shader, name_for_errors); + if(success) { + glAttachShader(prog, shader); + shaders.push_back(shader); + linked = false; + } + return success; +} + +inline std::string GlSlProgram::ParseIncludeFilename(const std::string& location) +{ + size_t start = location.find_first_of("\"<"); + if(start != std::string::npos) { + size_t end = location.find_first_of("\">", start+1); + if(end != std::string::npos) { + return location.substr(start+1, end - start - 1); + } + } + throw std::runtime_error("GLSL Parser: Unable to parse include location " + location ); +} + +inline std::string GlSlProgram::SearchIncludePath( + const std::string& filename, + const std::vector& search_path, + const std::string& current_path +) { + if(FileExists(current_path + "/" + filename)) { + return current_path + "/" + filename; + }else{ + for(size_t i=0; i < search_path.size(); ++i) { + const std::string hypoth = search_path[i] + "/" + filename; + if( FileExists(hypoth) ) { + return hypoth; + } + } + } + return ""; +} + +inline void GlSlProgram::PreprocessGLSL( + std::istream& input, std::ostream& output, + const std::map& program_defines, + const std::vector &search_path, + const std::string ¤t_path +) { + const size_t MAXLINESIZE = 10240; + char line[MAXLINESIZE] = ""; + + while(!input.eof()) { + // Take like from source + input.getline(line,MAXLINESIZE); + + // Transform + if( !strncmp(line, "#include", 8 ) ) { + // C++ / G3D style include directive + const std::string import_file = ParseIncludeFilename(line+8); + const std::string resolved_file = SearchIncludePath(import_file, search_path, current_path); + + std::ifstream ifs(resolved_file.c_str()); + if(ifs.good()) { + const std::string file_path = pangolin::PathParent(resolved_file); + PreprocessGLSL(ifs, output, program_defines, search_path, file_path); + }else{ + throw std::runtime_error("GLSL Parser: Unable to open " + import_file ); + } + }else if( !strncmp(line, "#expect", 7) ) { + // G3D style 'expect' directive, annotating expected preprocessor + // definition with document string + + // Consume whitespace before token + size_t token_start = 7; + while( std::isspace(line[token_start]) ) ++token_start; + + // Iterate over contigous charecters until \0 or whitespace + size_t token_end = token_start; + while( line[token_end] && !std::isspace(line[token_end]) ) ++token_end; + + std::string token(line+token_start, line+token_end); + std::map::const_iterator it = program_defines.find(token); + if( it == program_defines.end() ) { + pango_print_warn("Expected define missing (defaulting to 0): '%s'\n%s\n", token.c_str(), line + token_end ); + output << "#define " << token << " 0" << std::endl; + }else{ + output << "#define " << token << " " << it->second << std::endl; + } + }else{ + // Output directly + output << line << std::endl; + } + } +} + +inline void GlSlProgram::ClearShaders() +{ + // Remove and delete each shader + for(size_t i=0; i"; + + if(shader_file.shader_type == GlSlAnnotatedShader) { + const std::map split_progs = SplitAnnotatedShaders(code); + for(const auto& type_code : split_progs) { + if(!AddPreprocessedShader(type_code.first, type_code.second, input_name )) { + return false; + } + } + return true; + }else{ + return AddPreprocessedShader(shader_file.shader_type, code, input_name); + } +} + +inline bool GlSlProgram::AddShaderFromFile( + GlSlShaderType shader_type, + const std::string& filename, + const std::map& program_defines, + const std::vector& search_path +) { + ShaderFileOrCode shader_file = { + shader_type, + pangolin::PathExpand(filename), + std::string(), + program_defines, + search_path + }; + shader_files.push_back(shader_file); + return AddShaderFile(shader_file); +} + +inline bool GlSlProgram::AddShader( + GlSlShaderType shader_type, + const std::string& source_code, + const std::map& program_defines, + const std::vector& search_path +) { + ShaderFileOrCode shader_file = { + shader_type, + std::string(), + source_code, + program_defines, + search_path + }; + shader_files.push_back(shader_file); + return AddShaderFile(shader_file); +} + +inline bool GlSlProgram::ReloadShaderFiles() +{ + ClearShaders(); + + for(const auto& sf : shader_files) { + if(!AddShaderFile(sf)) { + return false; + } + } + + Link(); + return true; +} + +inline std::map +GlSlProgram::SplitAnnotatedShaders(const std::string& code) +{ + std::map ret; + + std::stringstream input(code); + std::stringstream output; + + const size_t MAXLINESIZE = 10240; + char line[MAXLINESIZE]; + + GlSlShaderType current_type = GlSlAnnotatedShader; + auto finish_block = [&](GlSlShaderType type){ + if(current_type != GlSlAnnotatedShader) { + ret[current_type] = output.str(); + } + output.str(std::string()); + current_type = type; + }; + + while(!input.eof()) { + // Take like from source + input.getline(line,MAXLINESIZE); + + // Transform + if( !strncmp(line, "@start", 6 ) ) { + const std::string str_shader_type = pangolin::Trim(std::string(line).substr(6)); + if(str_shader_type == "vertex") { + finish_block(GlSlVertexShader); + }else if(str_shader_type == "fragment") { + finish_block(GlSlFragmentShader); + }else if(str_shader_type == "geometry") { + finish_block(GlSlGeometryShader); + }else if(str_shader_type == "compute") { + finish_block(GlSlComputeShader); + } + }else{ + output << line << std::endl; + } + } + + finish_block(GlSlAnnotatedShader); + + return ret; +} + +inline bool GlSlProgram::Link() +{ + glLinkProgram(prog); + return IsLinkSuccessPrintLog(prog); +} + +inline void GlSlProgram::Bind() +{ + prev_prog = 0; + glUseProgram(prog); +} + +inline void GlSlProgram::SaveBind() +{ + glGetIntegerv(GL_CURRENT_PROGRAM, &prev_prog); + glUseProgram(prog); +} + +inline void GlSlProgram::Unbind() +{ + glUseProgram(prev_prog); +} + +inline GLint GlSlProgram::GetAttributeHandle(const std::string& name) +{ + return glGetAttribLocation(prog, name.c_str()); +} + +inline GLint GlSlProgram::GetUniformHandle(const std::string& name) +{ + return glGetUniformLocation(prog, name.c_str()); +} + +inline void GlSlProgram::SetUniform(const std::string& name, int x) +{ + glUniform1i( GetUniformHandle(name), x); +} + +inline void GlSlProgram::SetUniform(const std::string& name, int x1, int x2) +{ + glUniform2i( GetUniformHandle(name), x1, x2); +} + +inline void GlSlProgram::SetUniform(const std::string& name, int x1, int x2, int x3) +{ + glUniform3i( GetUniformHandle(name), x1, x2, x3); +} + +inline void GlSlProgram::SetUniform(const std::string& name, int x1, int x2, int x3, int x4) +{ + glUniform4i( GetUniformHandle(name), x1, x2, x3, x4); +} + +inline void GlSlProgram::SetUniform(const std::string& name, float f) +{ + glUniform1f( GetUniformHandle(name), f); +} + +inline void GlSlProgram::SetUniform(const std::string& name, float f1, float f2) +{ + glUniform2f( GetUniformHandle(name), f1,f2); +} + +inline void GlSlProgram::SetUniform(const std::string& name, float f1, float f2, float f3) +{ + glUniform3f( GetUniformHandle(name), f1,f2,f3); +} + +inline void GlSlProgram::SetUniform(const std::string& name, float f1, float f2, float f3, float f4) +{ + glUniform4f( GetUniformHandle(name), f1,f2,f3,f4); +} + +inline void GlSlProgram::SetUniform(const std::string& name, Colour c) +{ + glUniform4f( GetUniformHandle(name), c.r, c.g, c.b, c.a); +} + +inline void GlSlProgram::SetUniform(const std::string& name, const OpenGlMatrix& mat) +{ + // glUniformMatrix4dv seems to be crashing... + float m[16]; + for (int i = 0; i < 16; ++i) { + m[i] = (float)mat.m[i]; + } + glUniformMatrix4fv( GetUniformHandle(name), 1, GL_FALSE, m); +} + +#ifdef HAVE_EIGEN +inline void GlSlProgram::SetUniform(const std::string& name, const Eigen::Matrix3f& m) +{ + glUniformMatrix3fv( GetUniformHandle(name), 1, GL_FALSE, m.data()); +} +inline void GlSlProgram::SetUniform(const std::string& name, const Eigen::Matrix4f& m) +{ + glUniformMatrix4fv( GetUniformHandle(name), 1, GL_FALSE, m.data()); +} +inline void GlSlProgram::SetUniform(const std::string& name, const Eigen::Matrix3d& m) +{ + glUniformMatrix3dv( GetUniformHandle(name), 1, GL_FALSE, m.data()); +} +inline void GlSlProgram::SetUniform(const std::string& name, const Eigen::Matrix4d& m) +{ + glUniformMatrix4dv( GetUniformHandle(name), 1, GL_FALSE, m.data()); +} +#endif + +inline void GlSlProgram::BindPangolinDefaultAttribLocationsAndLink() +{ + glBindAttribLocation(prog, DEFAULT_LOCATION_POSITION, DEFAULT_NAME_POSITION); + glBindAttribLocation(prog, DEFAULT_LOCATION_COLOUR, DEFAULT_NAME_COLOUR); + glBindAttribLocation(prog, DEFAULT_LOCATION_NORMAL, DEFAULT_NAME_NORMAL); + glBindAttribLocation(prog, DEFAULT_LOCATION_TEXCOORD, DEFAULT_NAME_TEXCOORD); + Link(); +} + +#if GL_VERSION_4_3 +inline GLint GlSlProgram::GetProgramResourceIndex(const std::string& name) +{ + return glGetProgramResourceIndex(prog, GL_SHADER_STORAGE_BLOCK, name.c_str()); +} + +inline void GlSlProgram::SetShaderStorageBlock(const std::string& name, const int& bindingIndex) +{ + glShaderStorageBlockBinding(prog, GetProgramResourceIndex(name), bindingIndex); +} +#endif + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glstate.h b/Thirdparty/Pangolin/include/pangolin/gl/glstate.h new file mode 100644 index 0000000..0757ba2 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glstate.h @@ -0,0 +1,220 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Vincent Mamo, Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +class GlState { + + class CapabilityState { + public: + + CapabilityState(GLenum cap, GLboolean enable) + : m_cap(cap), m_enable(enable) + { + + } + + void Apply() { + if(m_enable) { + ::glEnable(m_cap); + }else{ + ::glDisable(m_cap); + } + } + + void UnApply() { + if(m_enable) { + ::glDisable(m_cap); + }else{ + ::glEnable(m_cap); + } + } + + protected: + GLenum m_cap; + GLboolean m_enable; + }; + +public: + GlState() + : m_DepthMaskCalled(false), + m_ShadeModelCalled(false), + m_CullFaceCalled(false), + m_PointSizeCalled(false), + m_LineWidthCalled(false), + m_ColorMaskCalled(false), + m_ViewportCalled(false) + { + } + + ~GlState() { + // Restore original state + while (!m_history.empty()) { + m_history.top().UnApply(); + m_history.pop(); + } + + if (m_DepthMaskCalled) { + ::glDepthMask(m_OriginalDepthMask); + } + + if (m_ShadeModelCalled) { + ::glShadeModel(m_OriginalShadeModel); + } + + if (m_CullFaceCalled) { + ::glCullFace(m_OriginalCullFace); + } + + if(m_PointSizeCalled) { + ::glPointSize(m_OriginalPointSize); + } + + if(m_LineWidthCalled) { + ::glLineWidth(m_OriginalLineWidth); + } + + if (m_ColorMaskCalled) { + ::glColorMask(m_OriginalColorMask[0], m_OriginalColorMask[1], m_OriginalColorMask[2], m_OriginalColorMask[3]); + } + + if (m_ViewportCalled) { + ::glViewport(m_OriginalViewport[0], m_OriginalViewport[1], m_OriginalViewport[2], m_OriginalViewport[3]); + } + } + + static inline GLboolean IsEnabled(GLenum cap) + { + GLboolean curVal; + glGetBooleanv(cap, &curVal); + return curVal; + } + + inline void glEnable(GLenum cap) + { + if(!IsEnabled(cap)) { + m_history.push(CapabilityState(cap,true)); + ::glEnable(cap); + } + } + + inline void glDisable(GLenum cap) + { + if(IsEnabled(cap)) { + m_history.push(CapabilityState(cap,false)); + ::glDisable(cap); + } + } + + bool m_DepthMaskCalled; + GLboolean m_OriginalDepthMask; + inline void glDepthMask(GLboolean flag) + { + if(!m_DepthMaskCalled) { + m_DepthMaskCalled = true; + glGetBooleanv(GL_DEPTH_WRITEMASK, &m_OriginalDepthMask); + } + ::glDepthMask(flag); + } + + bool m_ShadeModelCalled; + GLint m_OriginalShadeModel; + inline void glShadeModel(GLint mode) + { + if(!m_ShadeModelCalled) { + m_ShadeModelCalled = true; + glGetIntegerv(GL_SHADE_MODEL, &m_OriginalShadeModel); + } + ::glShadeModel(mode); + } + + bool m_CullFaceCalled; + GLint m_OriginalCullFace; + void glCullFace(GLenum mode) + { + if(!m_ShadeModelCalled) { + m_ShadeModelCalled = true; + glGetIntegerv(GL_CULL_FACE_MODE, &m_OriginalCullFace); + } + ::glCullFace(mode); + } + + bool m_PointSizeCalled; + GLfloat m_OriginalPointSize; + void glPointSize(GLfloat size) + { + if(!m_PointSizeCalled) { + m_PointSizeCalled = true; + glGetFloatv(GL_POINT_SIZE, &m_OriginalPointSize); + } + ::glPointSize(size); + } + + bool m_LineWidthCalled; + GLfloat m_OriginalLineWidth; + void glLineWidth(GLfloat width) + { + if(!m_LineWidthCalled) { + m_LineWidthCalled = true; + glGetFloatv(GL_LINE_WIDTH, &m_OriginalLineWidth); + } + ::glLineWidth(width); + + } + + bool m_ColorMaskCalled; + GLboolean m_OriginalColorMask[4]; + inline void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) + { + if(!m_ColorMaskCalled) { + m_ColorMaskCalled = true; + glGetBooleanv(GL_COLOR_WRITEMASK, m_OriginalColorMask); + } + ::glColorMask(red, green, blue, alpha); + } + + bool m_ViewportCalled; + GLint m_OriginalViewport[4]; + inline void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) + { + if(!m_ViewportCalled) { + m_ViewportCalled = true; + glGetIntegerv(GL_VIEWPORT, m_OriginalViewport); + } + ::glViewport(x, y, width, height); + } + + std::stack m_history; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/gltext.h b/Thirdparty/Pangolin/include/pangolin/gl/gltext.h new file mode 100644 index 0000000..1c8f0b2 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/gltext.h @@ -0,0 +1,98 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin { + +class PANGOLIN_EXPORT GlText +{ +public: + GlText(); + + GlText(const GlText& txt); + + GlText(const GlTexture& font_tex); + + void AddSpace(GLfloat s); + + // Add specified charector to this string. + void Add(unsigned char c, const GlChar& glc); + + // Clear text + void Clear(); + + // Render without transform in text-centric pixel coordinates + void Draw() const; + void DrawGlSl() const; + +#ifdef BUILD_PANGOLIN_GUI + // Render at (x,y,z)' in object coordinates, + // keeping text size and orientation constant + void Draw(GLfloat x, GLfloat y, GLfloat z = 0.0f) const; + + // Render at (x,y,z)' in window coordinates. + void DrawWindow(GLfloat x, GLfloat y, GLfloat z = 0.0f) const; +#endif // BUILD_PANGOLIN_GUI + + // Return text that this object signifies. + const std::string& Text() const { + return str; + } + + // Return width in pixels of this text. + GLfloat Width() const { + return width; + } + + // Return height in pixels of this text. + GLfloat Height() const { + return ymax; + } + + // Return height in pixels of this text, including under baseline + GLfloat FullHeight() const { + return ymax - ymin; + } + +//protected: + const GlTexture* tex; + std::string str; + GLfloat width; + GLfloat ymin; + GLfloat ymax; + + std::vector vs; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/gltexturecache.h b/Thirdparty/Pangolin/include/pangolin/gl/gltexturecache.h new file mode 100644 index 0000000..f3ad303 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/gltexturecache.h @@ -0,0 +1,116 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT TextureCache +{ +public: + static TextureCache& I(); + + GlTexture& GlTex(GLsizei w, GLsizei h, GLint internal_format, GLint glformat, GLenum gltype) + { + const long key = + (((long)internal_format)<<20) ^ + (((long)glformat)<<10) ^ gltype; + + // Lookup texture + std::shared_ptr& ptex = texture_map[key]; + if(!ptex) { + ptex = std::shared_ptr(new GlTexture()); + } + GlTexture& tex = *ptex; + + // Initialise if it didn't already exist or the size was too small + if(!tex.tid || tex.width < w || tex.height < h) { + tex.Reinitialise( + std::max(tex.width,w), std::max(tex.height,h), + internal_format, default_sampling_linear, 0, + glformat, gltype + ); + } + + return tex; + } + + template + GlTexture& GlTex(GLsizei w, GLsizei h) + { + return GlTex( w, h, + GlFormatTraits::glinternalformat, + GlFormatTraits::glformat, + GlFormatTraits::gltype + ); + } + +protected: + bool default_sampling_linear; + std::map > texture_map; + + // Protected constructor + TextureCache() + : default_sampling_linear(true) + { + } +}; + +template +void RenderToViewport(Image& image, bool flipx=false, bool flipy=false) +{ + // Retrieve texture that is at least as large as image and of appropriate type. + GlTexture& tex = TextureCache::I().GlTex(image.w, image.h); + tex.Upload(image.ptr,0,0, image.w, image.h, GlFormatTraits::glformat, GlFormatTraits::gltype); + tex.RenderToViewport(Viewport(0,0,image.w, image.h), flipx, flipy); +} + +// This method may dissapear in the future +inline void RenderToViewport( + Image& image, + const pangolin::GlPixFormat& fmt, + bool flipx=false, bool flipy=false, + bool linear_sampling = true +) { + pangolin::GlTexture& tex = pangolin::TextureCache::I().GlTex((GLsizei)image.w, (GLsizei)image.h, fmt.scalable_internal_format, fmt.glformat, fmt.gltype); + tex.Bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_sampling ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_sampling ? GL_LINEAR : GL_NEAREST); + tex.Upload(image.ptr,0,0, (GLsizei)image.w, (GLsizei)image.h, fmt.glformat, fmt.gltype); + tex.RenderToViewport(pangolin::Viewport(0,0,(GLint)image.w, (GLint)image.h), flipx, flipy); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/gl/glvbo.h b/Thirdparty/Pangolin/include/pangolin/gl/glvbo.h new file mode 100644 index 0000000..546f6d5 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/gl/glvbo.h @@ -0,0 +1,225 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin +{ + +//////////////////////////////////////////////// +// Interface +//////////////////////////////////////////////// + +void MakeTriangleStripIboForVbo(GlBuffer& ibo, int w, int h); + +GlBuffer MakeTriangleStripIboForVbo(int w, int h); + +void RenderVbo(GlBuffer& vbo, GLenum mode = GL_POINTS); + +void RenderVboCbo(GlBuffer& vbo, GlBuffer& cbo, bool draw_color = true, GLenum mode = GL_POINTS); + +void RenderVboIbo(GlBuffer& vbo, GlBuffer& ibo, bool draw_mesh = true); + +void RenderVboIboCbo(GlBuffer& vbo, GlBuffer& ibo, GlBuffer& cbo, bool draw_mesh = true, bool draw_color = true); + +void RenderVboIboNbo(GlBuffer& vbo, GlBuffer& ibo, GlBuffer& nbo, bool draw_mesh = true, bool draw_normals = true); + +void RenderVboIboCboNbo(GlBuffer& vbo, GlBuffer& ibo, GlBuffer& cbo, GlBuffer& nbo, bool draw_mesh = true, bool draw_color = true, bool draw_normals = true); + +//////////////////////////////////////////////// +// Implementation +//////////////////////////////////////////////// + +inline void MakeTriangleStripIboForVbo(GlBuffer& ibo, int w, int h) +{ + const int num_elements = w*(h-1)*2; + unsigned int* buffer = new unsigned int[num_elements]; + unsigned int* ptr = buffer; + + for(int y=0; y < (h-1);) + { + for(int x=0; x=(h-1)) break; + for(int x=w-1; x>=0; --x) { + (*ptr++) = y*w+x; + (*ptr++) = (y+1)*w+x; + } + ++y; + } + + ibo.Reinitialise(GlElementArrayBuffer, num_elements, GL_UNSIGNED_INT, 1, GL_STATIC_DRAW ); + ibo.Upload(buffer, sizeof(unsigned int)*num_elements ); + + delete[] buffer; +} + +inline GlBuffer MakeTriangleStripIboForVbo(int w, int h) +{ + GlBuffer ibo; + MakeTriangleStripIboForVbo(ibo,w,h); + return ibo; +} + +inline void RenderVbo(GlBuffer& vbo, GLenum mode) +{ + vbo.Bind(); + glVertexPointer(vbo.count_per_element, vbo.datatype, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + + glDrawArrays(mode, 0, vbo.num_elements); + + glDisableClientState(GL_VERTEX_ARRAY); + vbo.Unbind(); +} + +inline void RenderVboCbo(GlBuffer& vbo, GlBuffer& cbo, bool draw_color, GLenum mode ) +{ + if(draw_color) { + cbo.Bind(); + glColorPointer(cbo.count_per_element, cbo.datatype, 0, 0); + glEnableClientState(GL_COLOR_ARRAY); + } + + RenderVbo(vbo,mode); + + if(draw_color) { + glDisableClientState(GL_COLOR_ARRAY); + cbo.Unbind(); + } +} + +inline void RenderVboIbo(GlBuffer& vbo, GlBuffer& ibo, bool draw_mesh) +{ + vbo.Bind(); + glVertexPointer(vbo.count_per_element, vbo.datatype, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + + if(draw_mesh) { + ibo.Bind(); + glDrawElements(GL_TRIANGLE_STRIP,ibo.num_elements, ibo.datatype, 0); + ibo.Unbind(); + }else{ + glDrawArrays(GL_POINTS, 0, vbo.num_elements); + } + + glDisableClientState(GL_VERTEX_ARRAY); + vbo.Unbind(); +} + +inline void RenderVboIboCbo(GlBuffer& vbo, GlBuffer& ibo, GlBuffer& cbo, bool draw_mesh, bool draw_color ) +{ + if(draw_color) { + cbo.Bind(); + glColorPointer(cbo.count_per_element, cbo.datatype, 0, 0); + glEnableClientState(GL_COLOR_ARRAY); + } + + RenderVboIbo(vbo,ibo,draw_mesh); + + if(draw_color) { + glDisableClientState(GL_COLOR_ARRAY); + cbo.Unbind(); + } +} + +inline void RenderVboIboCboNbo(GlBuffer& vbo, GlBuffer& ibo, GlBuffer& cbo, GlBuffer& nbo, bool draw_mesh, bool draw_color, bool draw_normals) +{ + if(draw_color) { + cbo.Bind(); + glColorPointer(cbo.count_per_element, cbo.datatype, 0, 0); + glEnableClientState(GL_COLOR_ARRAY); + } + + if(draw_normals) { + nbo.Bind(); + glNormalPointer(nbo.datatype, (GLsizei)(nbo.count_per_element * GlDataTypeBytes(nbo.datatype)),0); + glEnableClientState(GL_NORMAL_ARRAY); + } + + vbo.Bind(); + glVertexPointer(vbo.count_per_element, vbo.datatype, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + + if(draw_mesh) { + ibo.Bind(); + glDrawElements(GL_TRIANGLE_STRIP,ibo.num_elements, ibo.datatype, 0); + ibo.Unbind(); + }else{ + glDrawArrays(GL_POINTS, 0, vbo.num_elements); + } + + if(draw_color) { + glDisableClientState(GL_COLOR_ARRAY); + cbo.Unbind(); + } + + if(draw_normals) { + glDisableClientState(GL_NORMAL_ARRAY); + nbo.Unbind(); + } + + glDisableClientState(GL_VERTEX_ARRAY); + vbo.Unbind(); +} + +inline void RenderVboIboNbo(GlBuffer& vbo, GlBuffer& ibo, GlBuffer& nbo, bool draw_mesh, bool draw_normals) +{ + vbo.Bind(); + glVertexPointer(vbo.count_per_element, vbo.datatype, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + + if(draw_normals) { + nbo.Bind(); + glNormalPointer(nbo.datatype, (GLsizei)(nbo.count_per_element * GlDataTypeBytes(nbo.datatype)), 0); + glEnableClientState(GL_NORMAL_ARRAY); + } + + if(draw_mesh) { + ibo.Bind(); + glDrawElements(GL_TRIANGLE_STRIP,ibo.num_elements, ibo.datatype, 0); + ibo.Unbind(); + }else{ + glDrawArrays(GL_POINTS, 0, vbo.num_elements); + } + + if(draw_normals) { + glDisableClientState(GL_NORMAL_ARRAY); + nbo.Unbind(); + } + + glDisableClientState(GL_VERTEX_ARRAY); + vbo.Unbind(); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/handler/handler.h b/Thirdparty/Pangolin/include/pangolin/handler/handler.h new file mode 100644 index 0000000..4e1b326 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/handler/handler.h @@ -0,0 +1,116 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files +#define USE_EIGEN +#endif + +#ifdef USE_EIGEN +#include +#endif + +#ifdef _OSX_ +#define PANGO_DFLT_HANDLER3D_ZF (1.0f/50.0f) +#else +#define PANGO_DFLT_HANDLER3D_ZF (1.0f/10.0f) +#endif + +namespace pangolin +{ + +// Forward declarations +struct View; + +/// Input Handler base class. +/// Virtual methods which recurse into sub-displays. +struct PANGOLIN_EXPORT Handler +{ + virtual ~Handler() {} + virtual void Keyboard(View&, unsigned char key, int x, int y, bool pressed); + virtual void Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state); + virtual void MouseMotion(View&, int x, int y, int button_state); + virtual void PassiveMouseMotion(View&, int x, int y, int button_state); + virtual void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state); +}; + +struct PANGOLIN_EXPORT HandlerScroll : Handler +{ + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state); + void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state); +}; + +struct PANGOLIN_EXPORT Handler3D : Handler +{ + Handler3D(OpenGlRenderState& cam_state, AxisDirection enforce_up=AxisNone, float trans_scale=0.01f, float zoom_fraction= PANGO_DFLT_HANDLER3D_ZF); + + virtual bool ValidWinDepth(GLprecision depth); + virtual void PixelUnproject( View& view, GLprecision winx, GLprecision winy, GLprecision winz, GLprecision Pc[3]); + virtual void GetPosNormal(View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision nw[3], GLprecision default_z = 1.0); + + void Keyboard(View&, unsigned char key, int x, int y, bool pressed); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state); + void MouseMotion(View&, int x, int y, int button_state); + void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state); + +#ifdef USE_EIGEN + // Return selected point in world coordinates + inline Eigen::Vector3d Selected_P_w() const { + return Eigen::Map>(Pw).cast(); + } +#endif + inline int KeyState() const{ + return funcKeyState; + } + +protected: + OpenGlRenderState* cam_state; + const static int hwin = 8; + AxisDirection enforce_up; + float tf; // translation factor + float zf; // zoom fraction + CameraSpec cameraspec; + GLprecision last_z; + float last_pos[2]; + GLprecision rot_center[3]; + + GLprecision p[3]; + GLprecision Pw[3]; + GLprecision Pc[3]; + GLprecision n[3]; + + int funcKeyState; +}; + +static Handler StaticHandler; +static HandlerScroll StaticHandlerScroll; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/handler/handler_enums.h b/Thirdparty/Pangolin/include/pangolin/handler/handler_enums.h new file mode 100644 index 0000000..389040f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/handler/handler_enums.h @@ -0,0 +1,94 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +namespace pangolin +{ + +// Supported Key modifiers for GlobalKeyPressCallback. +// e.g. PANGO_CTRL + 'r', PANGO_SPECIAL + PANGO_KEY_RIGHT, etc. +const int PANGO_SPECIAL = 128; +const int PANGO_CTRL = -96; +const int PANGO_OPTN = 132; + +// Ordinary keys +const int PANGO_KEY_TAB = 9; +const int PANGO_KEY_ESCAPE = 27; + +// Special Keys (same as GLUT_ defines) +const int PANGO_KEY_F1 = 1; +const int PANGO_KEY_F2 = 2; +const int PANGO_KEY_F3 = 3; +const int PANGO_KEY_F4 = 4; +const int PANGO_KEY_F5 = 5; +const int PANGO_KEY_F6 = 6; +const int PANGO_KEY_F7 = 7; +const int PANGO_KEY_F8 = 8; +const int PANGO_KEY_F9 = 9; +const int PANGO_KEY_F10 = 10; +const int PANGO_KEY_F11 = 11; +const int PANGO_KEY_F12 = 12; +const int PANGO_KEY_LEFT = 100; +const int PANGO_KEY_UP = 101; +const int PANGO_KEY_RIGHT = 102; +const int PANGO_KEY_DOWN = 103; +const int PANGO_KEY_PAGE_UP = 104; +const int PANGO_KEY_PAGE_DOWN = 105; +const int PANGO_KEY_HOME = 106; +const int PANGO_KEY_END = 107; +const int PANGO_KEY_INSERT = 108; + +enum MouseButton +{ + MouseButtonLeft = 1, + MouseButtonMiddle = 2, + MouseButtonRight = 4, + MouseWheelUp = 8, + MouseWheelDown = 16, + MouseWheelRight = 32, + MouseWheelLeft = 64, +}; + +enum KeyModifier +{ + KeyModifierShift = 1<<16, + KeyModifierCtrl = 1<<17, + KeyModifierAlt = 1<<18, + KeyModifierCmd = 1<<19, + KeyModifierFnc = 1<<20 +}; + +enum InputSpecial +{ + InputSpecialScroll, + InputSpecialZoom, + InputSpecialRotate, + InputSpecialTablet +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/handler/handler_glbuffer.h b/Thirdparty/Pangolin/include/pangolin/handler/handler_glbuffer.h new file mode 100644 index 0000000..3d984f1 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/handler/handler_glbuffer.h @@ -0,0 +1,48 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#ifndef HANDLER_GLBUFFER_H +#define HANDLER_GLBUFFER_H + +#include +#include + +namespace pangolin +{ + +struct Handler3DFramebuffer : public pangolin::Handler3D +{ + Handler3DFramebuffer(GlFramebuffer& fb, pangolin::OpenGlRenderState& cam_state, pangolin::AxisDirection enforce_up=pangolin::AxisNone, float trans_scale=0.01f); + void GetPosNormal(pangolin::View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision /*n*/[3], GLprecision default_z); + +protected: + GlFramebuffer& fb; +}; + +} + +#endif // HANDLER_GLBUFFER_H diff --git a/Thirdparty/Pangolin/include/pangolin/handler/handler_image.h b/Thirdparty/Pangolin/include/pangolin/handler/handler_image.h new file mode 100644 index 0000000..0041278 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/handler/handler_image.h @@ -0,0 +1,162 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace pangolin +{ + +class ImageViewHandler : public Handler +{ +public: + struct EventData { + EventData(View& v, ImageViewHandler& h) : view(v), handler(h) {} + View& view; + ImageViewHandler& handler; + }; + + struct OnSelectionEventData : public EventData { + OnSelectionEventData(View& v, ImageViewHandler& h, bool dragging) + : EventData(v,h), dragging(dragging) {} + bool dragging; + }; + + typedef std::function OnSelectionCallbackFn; + + // Default constructor: User must call SetDimensions() once image dimensions are known. + // Default range is [0,1] in x and y. + ImageViewHandler(); + + // View ranges store extremes of image (boundary of pixels) + // in 'discrete' coords, where 0,0 is center of top-left pixel. + ImageViewHandler(size_t w, size_t h); + + void SetDimensions(size_t w, size_t h); + + void UpdateView(); + + void glSetViewOrtho(); + + void glRenderTexture(pangolin::GlTexture& tex); + void glRenderTexture(GLuint tex, GLint width, GLint height); + + void glRenderOverlay(); + + void ScreenToImage(Viewport& v, float xpix, float ypix, float& ximg, float& yimg); + + void ImageToScreen(Viewport& v, float ximg, float yimg, float& xpix, float& ypix); + + bool UseNN() const; + + bool& UseNN(); + + bool& FlipTextureX(); + + bool& FlipTextureY(); + + pangolin::XYRangef& GetViewToRender(); + + float GetViewScale(); + + pangolin::XYRangef& GetView(); + + pangolin::XYRangef& GetDefaultView(); + + pangolin::XYRangef& GetSelection(); + + void GetHover(float& x, float& y); + + void SetView(const pangolin::XYRangef& range); + + void SetViewSmooth(const pangolin::XYRangef& range); + + void ScrollView(float x, float y); + + void ScrollViewSmooth(float x, float y); + + void ScaleView(float x, float y, float cx, float cy); + + void ScaleViewSmooth(float x, float y, float cx, float cy); + + void ResetView(); + + /////////////////////////////////////////////////////// + /// pangolin::Handler + /////////////////////////////////////////////////////// + + void Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed) override; + + void Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state) override; + + void MouseMotion(View& view, int x, int y, int button_state) override; + + void PassiveMouseMotion(View&, int /*x*/, int /*y*/, int /*button_state*/) override; + + void Special(View& view, pangolin::InputSpecial inType, float x, float y, float p1, float p2, float /*p3*/, float /*p4*/, int /*button_state*/) override; + + /////////////////////////////////////////////////////// + /// Callbacks + /////////////////////////////////////////////////////// + + OnSelectionCallbackFn OnSelectionCallback; + +protected: + void FixSelection(XYRangef& sel); + + void AdjustScale(); + + void AdjustTranslation(); + + static ImageViewHandler* to_link; + static float animate_factor; + + ImageViewHandler* linked_view_handler; + + pangolin::XYRangef rview_default; + pangolin::XYRangef rview_max; + pangolin::XYRangef rview; + pangolin::XYRangef target; + pangolin::XYRangef selection; + + float hover_img[2]; + int last_mouse_pos[2]; + + bool use_nn; + bool flipTextureX; + bool flipTextureY; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/copy.h b/Thirdparty/Pangolin/include/pangolin/image/copy.h new file mode 100644 index 0000000..160fa6b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/copy.h @@ -0,0 +1,45 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +namespace pangolin { + +// Hold a reference to an object to be copied +template +struct CopyObject { + CopyObject(const T& obj) : obj(obj) { } + const T& obj; +}; + +// Return copy wrapper for assignment to another object. +template +typename pangolin::CopyObject Copy(const T& obj) { + return typename pangolin::CopyObject(obj); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/image.h b/Thirdparty/Pangolin/include/pangolin/image/image.h new file mode 100644 index 0000000..098638a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/image.h @@ -0,0 +1,428 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#ifdef PANGO_ENABLE_BOUNDS_CHECKS +# define PANGO_BOUNDS_ASSERT(...) PANGO_ENSURE(##__VA_ARGS__) +#else +# define PANGO_BOUNDS_ASSERT(...) ((void)0) +#endif + +// Allow user defined macro to be inserted into Image class. +#ifndef PANGO_EXTENSION_IMAGE +# define PANGO_EXTENSION_IMAGE +#endif + +namespace pangolin +{ + +// Simple image wrapper +template +struct Image +{ + using PixelType = T; + + inline Image() + : pitch(0), ptr(0), w(0), h(0) + { + } + + inline Image(T* ptr, size_t w, size_t h, size_t pitch) + : pitch(pitch), ptr(ptr), w(w), h(h) + { + } + + + PANGO_HOST_DEVICE inline + size_t SizeBytes() const + { + return pitch * h; + } + + PANGO_HOST_DEVICE inline + size_t Area() const + { + return w * h; + } + + PANGO_HOST_DEVICE inline + bool IsValid() const + { + return ptr != 0; + } + + PANGO_HOST_DEVICE inline + bool IsContiguous() const + { + return w*sizeof(T) == pitch; + } + + ////////////////////////////////////////////////////// + // Iterators + ////////////////////////////////////////////////////// + + PANGO_HOST_DEVICE inline + T* begin() + { + return ptr; + } + + PANGO_HOST_DEVICE inline + T* end() + { + return RowPtr(h-1) + w; + } + + PANGO_HOST_DEVICE inline + const T* begin() const + { + return ptr; + } + + PANGO_HOST_DEVICE inline + const T* end() const + { + return RowPtr(h-1) + w; + } + + PANGO_HOST_DEVICE inline + size_t size() const + { + return w*h; + } + + ////////////////////////////////////////////////////// + // Image transforms + ////////////////////////////////////////////////////// + + template + PANGO_HOST_DEVICE inline + void Transform(UnaryOperation unary_op) + { + PANGO_ASSERT(IsValid()); + + for(size_t y=0; y < h; ++y) { + T* el = RowPtr(y); + const T* el_end = el+w; + for( ; el != el_end; ++el) { + *el = unary_op(*el); + } + } + } + + PANGO_HOST_DEVICE inline + void Fill(const T& val) + { + Transform( [&](const T&) {return val;} ); + } + + PANGO_HOST_DEVICE inline + void Replace(const T& oldval, const T& newval) + { + Transform( [&](const T& val) { + return (val == oldval) ? newval : val; + }); + } + + inline + void Memset(unsigned char v = 0) + { + PANGO_ASSERT(IsValid()); + if(IsContiguous()) { + ::pangolin::Memset((char*)ptr, v, pitch*h); + }else{ + for(size_t y=0; y < h; ++y) { + ::pangolin::Memset((char*)RowPtr(y), v, pitch); + } + } + } + + inline + void CopyFrom(const Image& img) + { + if(IsValid() && img.IsValid()) { + PANGO_ASSERT(w >= img.w && h >= img.h); + PitchedCopy((char*)ptr,pitch,(char*)img.ptr,img.pitch, std::min(img.w,w)*sizeof(T), std::min(img.h,h) ); + }else if( img.IsValid() != IsValid() ){ + PANGO_ASSERT(false && "Cannot copy from / to an unasigned image." ); + } + } + + ////////////////////////////////////////////////////// + // Reductions + ////////////////////////////////////////////////////// + + template + PANGO_HOST_DEVICE inline + T Accumulate(const T init, BinaryOperation binary_op) + { + PANGO_ASSERT(IsValid()); + + T val = init; + for(size_t y=0; y < h; ++y) { + T* el = RowPtr(y); + const T* el_end = el+w; + for(; el != el_end; ++el) { + val = binary_op(val, *el); + } + } + return val; + } + + std::pair MinMax() const + { + PANGO_ASSERT(IsValid()); + + std::pair minmax(std::numeric_limits::max(), std::numeric_limits::lowest()); + for(size_t r=0; r < h; ++r) { + const T* ptr = RowPtr(r); + const T* end = ptr + w; + while( ptr != end) { + minmax.first = std::min(*ptr, minmax.first); + minmax.second = std::max(*ptr, minmax.second); + ++ptr; + } + } + return minmax; + } + + template + Tout Sum() const + { + return Accumulate((T)0, [](const T& lhs, const T& rhs){ return lhs + rhs; }); + } + + template + Tout Mean() const + { + return Sum() / Area(); + } + + + ////////////////////////////////////////////////////// + // Direct Pixel Access + ////////////////////////////////////////////////////// + + PANGO_HOST_DEVICE inline + T* RowPtr(size_t y) + { + return (T*)((unsigned char*)(ptr) + y*pitch); + } + + PANGO_HOST_DEVICE inline + const T* RowPtr(size_t y) const + { + return (T*)((unsigned char*)(ptr) + y*pitch); + } + + PANGO_HOST_DEVICE inline + T& operator()(size_t x, size_t y) + { + PANGO_BOUNDS_ASSERT( InBounds(x,y) ); + return RowPtr(y)[x]; + } + + PANGO_HOST_DEVICE inline + const T& operator()(size_t x, size_t y) const + { + PANGO_BOUNDS_ASSERT( InBounds(x,y) ); + return RowPtr(y)[x]; + } + + template + PANGO_HOST_DEVICE inline + T& operator()(const TVec& p) + { + PANGO_BOUNDS_ASSERT( InBounds(p[0],p[1]) ); + return RowPtr(p[1])[p[0]]; + } + + template + PANGO_HOST_DEVICE inline + const T& operator()(const TVec& p) const + { + PANGO_BOUNDS_ASSERT( InBounds(p[0],p[1]) ); + return RowPtr(p[1])[p[0]]; + } + + PANGO_HOST_DEVICE inline + T& operator[](size_t ix) + { + PANGO_BOUNDS_ASSERT( InImage(ptr+ix) ); + return ptr[ix]; + } + + PANGO_HOST_DEVICE inline + const T& operator[](size_t ix) const + { + PANGO_BOUNDS_ASSERT( InImage(ptr+ix) ); + return ptr[ix]; + } + + ////////////////////////////////////////////////////// + // Bounds Checking + ////////////////////////////////////////////////////// + + PANGO_HOST_DEVICE + bool InImage(const T* ptest) const + { + return ptr <= ptest && ptest < RowPtr(h); + } + + PANGO_HOST_DEVICE inline + bool InBounds(int x, int y) const + { + return 0 <= x && x < (int)w && 0 <= y && y < (int)h; + } + + PANGO_HOST_DEVICE inline + bool InBounds(float x, float y, float border) const + { + return border <= x && x < (w-border) && border <= y && y < (h-border); + } + + template + PANGO_HOST_DEVICE inline + bool InBounds( const TVec& p, const TBorder border = (TBorder)0 ) const + { + return border <= p[0] && p[0] < ((int)w - border) && border <= p[1] && p[1] < ((int)h - border); + } + + ////////////////////////////////////////////////////// + // Obtain slices / subimages + ////////////////////////////////////////////////////// + + PANGO_HOST_DEVICE inline + const Image SubImage(size_t x, size_t y, size_t width, size_t height) const + { + PANGO_ASSERT( (x+width) <= w && (y+height) <= h); + return Image( RowPtr(y)+x, width, height, pitch); + } + + PANGO_HOST_DEVICE inline + Image SubImage(size_t x, size_t y, size_t width, size_t height) + { + PANGO_ASSERT( (x+width) <= w && (y+height) <= h); + return Image( RowPtr(y)+x, width, height, pitch); + } + + PANGO_HOST_DEVICE inline + const Image Row(int y) const + { + return SubImage(0,y,w,1); + } + + PANGO_HOST_DEVICE inline + Image Row(int y) + { + return SubImage(0,y,w,1); + } + + PANGO_HOST_DEVICE inline + const Image Col(int x) const + { + return SubImage(x,0,1,h); + } + + PANGO_HOST_DEVICE inline + Image Col(int x) + { + return SubImage(x,0,1,h); + } + + ////////////////////////////////////////////////////// + // Data mangling + ////////////////////////////////////////////////////// + + template + PANGO_HOST_DEVICE inline + Image Reinterpret() const + { + PANGO_ASSERT(sizeof(TRecast) == sizeof(T), "sizeof(TRecast) must match sizeof(T): % != %", sizeof(TRecast), sizeof(T) ); + return UnsafeReinterpret(); + } + + template + PANGO_HOST_DEVICE inline + Image UnsafeReinterpret() const + { + return Image((TRecast*)ptr,w,h,pitch); + } + + ////////////////////////////////////////////////////// + // Deprecated methods + ////////////////////////////////////////////////////// + +// PANGOLIN_DEPRECATED inline + Image(size_t w, size_t h, size_t pitch, T* ptr) + : pitch(pitch), ptr(ptr), w(w), h(h) + { + } + + // Use RAII/move aware pangolin::ManagedImage instead +// PANGOLIN_DEPRECATED inline + void Dealloc() + { + if(ptr) { + ::operator delete(ptr); + ptr = nullptr; + } + } + + // Use RAII/move aware pangolin::ManagedImage instead +// PANGOLIN_DEPRECATED inline + void Alloc(size_t w, size_t h, size_t pitch) + { + Dealloc(); + this->w = w; + this->h = h; + this->pitch = pitch; + this->ptr = (T*)::operator new(h*pitch); + } + + ////////////////////////////////////////////////////// + // Data members + ////////////////////////////////////////////////////// + + size_t pitch; + T* ptr; + size_t w; + size_t h; + + PANGO_EXTENSION_IMAGE +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/image_convert.h b/Thirdparty/Pangolin/include/pangolin/image/image_convert.h new file mode 100644 index 0000000..36ae99f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/image_convert.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +namespace pangolin +{ + +template +void ImageConvert(Image& dst, const Image& src, To scale = 1.0) +{ + for(unsigned int y = 0; y < dst.h; ++y) + { + const T* prs = src.RowPtr(y); + To* prd = dst.RowPtr(y); + for(unsigned int x = 0; x < dst.w; ++x) + { + *(prd++) = scale * ComponentCast::cast(*(prs++)); + } + } +} + +template +ManagedImage ImageConvert(const Image& src, To scale = 1.0) +{ + ManagedImage dst(src.w, src.h); + ImageConvert(dst,src,scale); + return dst; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/image_io.h b/Thirdparty/Pangolin/include/pangolin/image/image_io.h new file mode 100644 index 0000000..fcc594b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/image_io.h @@ -0,0 +1,65 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include + +namespace pangolin { + +PANGOLIN_EXPORT +TypedImage LoadImage(std::istream& in, ImageFileType file_type); + +PANGOLIN_EXPORT +TypedImage LoadImage(const std::string& filename, ImageFileType file_type); + +PANGOLIN_EXPORT +TypedImage LoadImage(const std::string& filename); + +PANGOLIN_EXPORT +TypedImage LoadImage(const std::string& filename, const PixelFormat& raw_fmt, size_t raw_width, size_t raw_height, size_t raw_pitch); + +/// Quality \in [0..100] for lossy formats +PANGOLIN_EXPORT +void SaveImage(const Image& image, const pangolin::PixelFormat& fmt, std::ostream& out, ImageFileType file_type, bool top_line_first = true, float quality = 100.0f); + +/// Quality \in [0..100] for lossy formats +PANGOLIN_EXPORT +void SaveImage(const Image& image, const pangolin::PixelFormat& fmt, const std::string& filename, ImageFileType file_type, bool top_line_first = true, float quality = 100.0f); + +/// Quality \in [0..100] for lossy formats +PANGOLIN_EXPORT +void SaveImage(const Image& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first = true, float quality = 100.0f); + +/// Quality \in [0..100] for lossy formats +PANGOLIN_EXPORT +void SaveImage(const TypedImage& image, const std::string& filename, bool top_line_first = true, float quality = 100.0f); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/image_utils.h b/Thirdparty/Pangolin/include/pangolin/image/image_utils.h new file mode 100644 index 0000000..92b5984 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/image_utils.h @@ -0,0 +1,185 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace pangolin +{ + +namespace internal +{ + +template +std::pair GetMinMax(const Image& img, size_t channels) +{ + const size_t max_channels = 3; + const size_t colour_channels = std::min(channels, max_channels); + std::pair chan_mm[max_channels]; + for(size_t c = 0; c < max_channels; ++c) + { + chan_mm[c].first = +std::numeric_limits::max(); + chan_mm[c].second = -std::numeric_limits::max(); + } + + for(size_t y = 0; y < img.h; ++y) + { + T* pix = (T*)((char*)img.ptr + y * img.pitch); + for(size_t x = 0; x < img.w; ++x) + { + for(size_t c = 0; c < colour_channels; ++c) + { + if(pix[c] < chan_mm[c].first) + chan_mm[c].first = (float)pix[c]; + if(pix[c] > chan_mm[c].second) + chan_mm[c].second = (float)pix[c]; + } + + pix += channels; + } + } + + // Find min / max of all channels, ignoring 4th alpha channel + std::pair mm = chan_mm[0]; + for(size_t c = 1; c < colour_channels; ++c) + { + mm.first = std::min(mm.first, chan_mm[c].first); + mm.second = std::max(mm.second, chan_mm[c].second); + } + + return mm; +} + +template +pangolin::Image GetImageRoi( pangolin::Image img, size_t channels, const pangolin::XYRangei& roi ) +{ + return pangolin::Image( + img.RowPtr(std::min(roi.y.min,roi.y.max)) + channels*std::min(roi.x.min,roi.x.max), + roi.x.AbsSize(), roi.y.AbsSize(), + img.pitch + ); +} + +template +std::pair GetOffsetScale(const pangolin::Image& img, size_t channels, float type_max, float format_max) +{ + // Find min / max of all channels, ignoring 4th alpha channel + const std::pair mm = internal::GetMinMax(img,channels); + const float type_scale = format_max / type_max; + const float offset = -type_scale* mm.first; + const float scale = type_max / (mm.second - mm.first); + return std::pair(offset, scale); +} + +template +float GetScaleOnly(const pangolin::Image& img, size_t channels, float type_max, float /*format_max*/) +{ + // Find min / max of all channels, ignoring 4th alpha channel + const std::pair mm = internal::GetMinMax(img,channels); + const float scale = type_max / mm.second; + return scale; +} + +} // internal + +inline std::pair GetMinMax( + const Image& img, + XYRangei iroi, const GlPixFormat& glfmt +) { + using namespace internal; + + iroi.Clamp(0, (int)img.w - 1, 0, (int)img.h - 1); + + const size_t num_channels = pangolin::GlFormatChannels(glfmt.glformat); + + if(glfmt.gltype == GL_UNSIGNED_BYTE) { + return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); + } else if(glfmt.gltype == GL_UNSIGNED_SHORT) { + return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); + } else if(glfmt.gltype == GL_FLOAT) { + return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); + } else if(glfmt.gltype == GL_DOUBLE) { + return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); + } else { + return std::pair(std::numeric_limits::max(), std::numeric_limits::lowest()); + } +} + +inline std::pair GetOffsetScale( + const pangolin::Image& img, + pangolin::XYRangei iroi, const pangolin::GlPixFormat& glfmt +) { + using namespace internal; + + iroi.Clamp(0, (int)img.w-1, 0, (int)img.h-1 ); + + const size_t num_channels = pangolin::GlFormatChannels(glfmt.glformat); + + if(glfmt.gltype == GL_UNSIGNED_BYTE) { + return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 255.0f, 1.0f); + }else if(glfmt.gltype == GL_UNSIGNED_SHORT) { + return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 65535.0f, 1.0f); + }else if(glfmt.gltype == GL_FLOAT) { + return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); + }else if(glfmt.gltype == GL_DOUBLE) { + return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); + }else{ + return std::pair(0.0f, 1.0f); + } +} + +inline float GetScaleOnly( + const pangolin::Image& img, + pangolin::XYRangei iroi, const pangolin::GlPixFormat& glfmt +) { + using namespace internal; + + iroi.Clamp(0, (int)img.w-1, 0, (int)img.h-1 ); + + const size_t num_channels = pangolin::GlFormatChannels(glfmt.glformat); + + if(glfmt.gltype == GL_UNSIGNED_BYTE) { + return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 255.0f, 1.0f); + }else if(glfmt.gltype == GL_UNSIGNED_SHORT) { + return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 65535.0f, 1.0f); + }else if(glfmt.gltype == GL_FLOAT) { + return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); + }else if(glfmt.gltype == GL_DOUBLE) { + return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); + }else{ + return 1.0f; + } +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/managed_image.h b/Thirdparty/Pangolin/include/pangolin/image/managed_image.h new file mode 100644 index 0000000..dd21c43 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/managed_image.h @@ -0,0 +1,175 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin { + +template using DefaultImageAllocator = std::allocator; + +// Image that manages it's own memory, storing a strong pointer to it's memory +template > +class ManagedImage : public Image +{ +public: + // Destructor + inline + ~ManagedImage() + { + Deallocate(); + } + + // Null image + inline + ManagedImage() + { + } + + // Row image + inline + ManagedImage(size_t w) + : Image( + Allocator().allocate(w), + w, 1, w*sizeof(T) + ) + { + } + + inline + ManagedImage(size_t w, size_t h) + : Image( + Allocator().allocate(w*h), + w, h, w*sizeof(T) + ) + { + } + + inline + ManagedImage(size_t w, size_t h, size_t pitch_bytes) + : Image( + Allocator().allocate( (h*pitch_bytes) / sizeof(T) + 1), + w, h, pitch_bytes + ) + { + } + + // Not copy constructable + inline + ManagedImage( const ManagedImage& other ) = delete; + + // Move constructor + inline + ManagedImage(ManagedImage&& img) + { + *this = std::move(img); + } + + // Move asignment + inline + void operator=(ManagedImage&& img) + { + Deallocate(); + Image::pitch = img.pitch; + Image::ptr = img.ptr; + Image::w = img.w; + Image::h = img.h; + img.ptr = nullptr; + } + + // Explicit copy constructor + template + ManagedImage( const CopyObject& other ) + { + CopyFrom(other.obj); + } + + // Explicit copy assignment + template + void operator=(const CopyObject& other) + { + CopyFrom(other.obj); + } + + inline + void Swap(ManagedImage& img) + { + std::swap(img.pitch, Image::pitch); + std::swap(img.ptr, Image::ptr); + std::swap(img.w, Image::w); + std::swap(img.h, Image::h); + } + + inline + void CopyFrom(const Image& img) + { + if(!Image::IsValid() || Image::w != img.w || Image::h != img.h) { + Reinitialise(img.w,img.h); + } + Image::CopyFrom(img); + } + + inline + void Reinitialise(size_t w, size_t h) + { + if(!Image::ptr || Image::w != w || Image::h != h) { + *this = ManagedImage(w,h); + } + } + + inline + void Reinitialise(size_t w, size_t h, size_t pitch) + { + if(!Image::ptr || Image::w != w || Image::h != h || Image::pitch != pitch) { + *this = ManagedImage(w,h,pitch); + } + } + + inline void Deallocate() + { + if (Image::ptr) { + Allocator().deallocate(Image::ptr, (Image::h * Image::pitch) / sizeof(T) ); + Image::ptr = nullptr; + } + } + + // Move asignment + template inline + void OwnAndReinterpret(ManagedImage&& img) + { + Deallocate(); + Image::pitch = img.pitch; + Image::ptr = (T*)img.ptr; + Image::w = img.w; + Image::h = img.h; + img.ptr = nullptr; + } +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/memcpy.h b/Thirdparty/Pangolin/include/pangolin/image/memcpy.h new file mode 100644 index 0000000..88d3f0c --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/memcpy.h @@ -0,0 +1,110 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include + +#ifdef HAVE_CUDA +# include +#endif + +namespace pangolin { + +template +PANGO_HOST_DEVICE inline +bool IsDevicePtr(T* ptr) +{ +#ifdef HAVE_CUDA + cudaPointerAttributes attributes; + cudaError_t res = cudaPointerGetAttributes(&attributes,ptr); + + //Flushing the error flag for future CUDA error checks + if(res != cudaSuccess) + { + cudaGetLastError(); + return false; + } + + return attributes.memoryType == cudaMemoryTypeDevice; +#else + PANGOLIN_UNUSED(ptr); + return false; +#endif +} + +PANGO_HOST_DEVICE inline +void MemCopy(void *dst, const void *src, size_t size_bytes) +{ +#ifdef HAVE_CUDA + cudaMemcpy(dst,src, size_bytes, cudaMemcpyDefault); +#else + std::memcpy(dst, src, size_bytes); +#endif +} + +inline +void PitchedCopy(char* dst, unsigned int dst_pitch_bytes, const char* src, unsigned int src_pitch_bytes, unsigned int width_bytes, unsigned int height) +{ +#ifdef HAVE_CUDA + cudaMemcpy2D(dst, dst_pitch_bytes, src, src_pitch_bytes, width_bytes, height, cudaMemcpyDefault); +#else + if(dst_pitch_bytes == width_bytes && src_pitch_bytes == width_bytes ) { + std::memcpy(dst, src, height * width_bytes); + }else{ + for(unsigned int row=0; row < height; ++row) { + std::memcpy(dst, src, width_bytes); + dst += dst_pitch_bytes; + src += src_pitch_bytes; + } + } +#endif +} + +PANGO_HOST_DEVICE inline +void Memset(char* ptr, unsigned char v, size_t size_bytes) +{ +#ifdef __CUDA_ARCH__ + // Called in kernel + char* end = ptr + size_bytes; + for(char* p=ptr; p != end; ++p) *p = v; +#else +# ifdef HAVE_CUDA + if(IsDevicePtr(ptr)) + { + cudaMemset(ptr, v, size_bytes); + }else +# endif // HAVE_CUDA + { + std::memset(ptr, v, size_bytes); + } +#endif // __CUDA_ARCH__ +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/pixel_format.h b/Thirdparty/Pangolin/include/pangolin/image/pixel_format.h new file mode 100644 index 0000000..2494a3a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/pixel_format.h @@ -0,0 +1,66 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011-2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +struct PANGOLIN_EXPORT PixelFormat +{ + // Previously, VideoInterface::PixFormat returned a string. + // For compatibility, make this string convertable + inline operator std::string() const { return format; } + + std::string format; + unsigned int channels; + unsigned int channel_bits[4]; //Of the data type + unsigned int bpp; //Of the data type + unsigned int channel_bit_depth; //Of the data + bool planar; +}; + + +//! Return Pixel Format properties given string specification in +//! FFMPEG notation. +PANGOLIN_EXPORT +PixelFormat PixelFormatFromString(const std::string& format); + +//////////////////////////////////////////////////////////////////// +/// Deprecated aliases for above + +PANGOLIN_DEPRECATED +typedef PixelFormat VideoPixelFormat; +PANGOLIN_DEPRECATED +inline PixelFormat VideoFormatFromString(const std::string& format) { + return PixelFormatFromString(format); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/image/typed_image.h b/Thirdparty/Pangolin/include/pangolin/image/typed_image.h new file mode 100644 index 0000000..39e5062 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/image/typed_image.h @@ -0,0 +1,91 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin { + +struct TypedImage : public ManagedImage +{ + typedef ManagedImage Base; + + inline TypedImage() + : Base() + { + } + + inline TypedImage(size_t w, size_t h, const PixelFormat& fmt) + : Base(w,h,w*fmt.bpp/8), fmt(fmt) + { + } + + inline TypedImage(size_t w, size_t h, const PixelFormat& fmt, size_t pitch ) + : Base(w,h, pitch), fmt(fmt) + { + } + + inline + void Reinitialise(size_t w, size_t h, const PixelFormat& fmt) + { + Base::Reinitialise(w, h, w*fmt.bpp/8); + this->fmt = fmt; + } + + inline + void Reinitialise(size_t w, size_t h, const PixelFormat& fmt, size_t pitch) + { + Base::Reinitialise(w, h, pitch); + this->fmt = fmt; + } + + // Not copy constructable + inline + TypedImage( const TypedImage& other ) = delete; + + // Move constructor + inline + TypedImage(TypedImage&& img) + { + *this = std::move(img); + } + + // Move asignment + inline + void operator=(TypedImage&& img) + { + fmt = img.fmt; + Base::operator =( std::move(img)); + } + + + PixelFormat fmt; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/ios/PangolinAppDelegate.h b/Thirdparty/Pangolin/include/pangolin/ios/PangolinAppDelegate.h new file mode 100644 index 0000000..6bae208 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/ios/PangolinAppDelegate.h @@ -0,0 +1,36 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#import + +#import "PangolinUIView.h" + +@interface PangolinAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Thirdparty/Pangolin/include/pangolin/ios/PangolinUIView.h b/Thirdparty/Pangolin/include/pangolin/ios/PangolinUIView.h new file mode 100644 index 0000000..f7aea7f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/ios/PangolinUIView.h @@ -0,0 +1,22 @@ +// +// GlTestViewController.h +// gltest +// +// Created by Steven Lovegrove on 30/01/2014. +// Copyright (c) 2014 Steven Lovegrove. All rights reserved. +// + +#import + +#include +#include + +@interface PangolinUIView : UIView { + CAEAGLLayer* _eaglLayer; + EAGLContext* _context; + + GLuint _colorRenderBuffer; + GLuint _depthRenderBuffer; +} + +@end \ No newline at end of file diff --git a/Thirdparty/Pangolin/include/pangolin/log/packet.h b/Thirdparty/Pangolin/include/pangolin/log/packet.h new file mode 100644 index 0000000..a904373 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/packet.h @@ -0,0 +1,70 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include + +namespace pangolin { + +// Encapsulate serialized reading of Packet from stream. +struct Packet +{ + Packet(PacketStream& s, std::unique_lock&& mutex, std::vector& srcs); + Packet(const Packet&) = delete; + Packet(Packet&& o); + ~Packet(); + + size_t BytesRead() const; + int BytesRemaining() const; + + PacketStream& Stream() + { + return _stream; + } + + PacketStreamSourceId src; + int64_t time; + size_t size; + size_t sequence_num; + picojson::value meta; + std::streampos frame_streampos; + +private: + void ParsePacketHeader(PacketStream& s, std::vector& srcs); + void ReadRemaining(); + + PacketStream& _stream; + + std::unique_lock lock; + + std::streampos data_streampos; + size_t _data_len; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/packetstream.h b/Thirdparty/Pangolin/include/pangolin/log/packetstream.h new file mode 100644 index 0000000..1b9c0f3 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/packetstream.h @@ -0,0 +1,111 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include + +#include +#include + +namespace pangolin +{ + +class PacketStream: public std::ifstream +{ +public: + PacketStream() + : _is_pipe(false) + { + cclear(); + } + + PacketStream(const std::string& filename) + : Base(filename.c_str(), std::ios::in | std::ios::binary), + _is_pipe(IsPipe(filename)) + { + cclear(); + } + + bool seekable() const + { + return is_open() && !_is_pipe; + } + + void open(const std::string& filename) + { + close(); + _is_pipe = IsPipe(filename); + Base::open(filename.c_str(), std::ios::in | std::ios::binary); + } + + void close() + { + cclear(); + if (Base::is_open()) Base::close(); + } + + void seekg(std::streampos target); + + void seekg(std::streamoff off, std::ios_base::seekdir way); + + std::streampos tellg(); + + size_t read(char* target, size_t len); + + char get(); + + size_t skip(size_t len); + + size_t readUINT(); + + int64_t readTimestamp(); + + pangoTagType peekTag(); + + pangoTagType readTag(); + + pangoTagType readTag(pangoTagType); + + pangoTagType syncToTag(); + +private: + using Base = std::ifstream; + + bool _is_pipe; + pangoTagType _tag; + + // Amount of frame data left to read. Tracks our position within a data block. + + + void cclear() { + _tag = 0; + } +}; + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/packetstream_reader.h b/Thirdparty/Pangolin/include/pangolin/log/packetstream_reader.h new file mode 100644 index 0000000..d929eb4 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/packetstream_reader.h @@ -0,0 +1,120 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT PacketStreamReader +{ +public: + PacketStreamReader(); + + PacketStreamReader(const std::string& filename); + + ~PacketStreamReader(); + + void Open(const std::string& filename); + + void Close(); + + const std::vector& + Sources() const + { + return _sources; + } + + // Grab Next available frame packetstream + Packet NextFrame(); + + // Grab Next available frame in packetstream from src, discarding other frames. + Packet NextFrame(PacketStreamSourceId src); + + bool Good() const + { + return _stream.good(); + } + + // Jumps to a particular packet. + size_t Seek(PacketStreamSourceId src, size_t framenum); + + // Jumps to the first packet with time >= time + size_t Seek(PacketStreamSourceId src, SyncTime::TimePoint time); + + void FixFileIndex(); + +private: + bool GoodToRead(); + + bool SetupIndex(); + + void ParseHeader(); + + void ParseNewSource(); + + bool ParseIndex(); + + void RebuildIndex(); + + void AppendIndex(); + + std::streampos ParseFooter(); + + void SkipSync(); + + void ReSync() { + _stream.syncToTag(); + } + + std::string _filename; + std::vector _sources; + SyncTime::TimePoint packet_stream_start; + + PacketStream _stream; + std::recursive_mutex _mutex; + + bool _is_pipe; + int _pipe_fd; +}; + + + + + + + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/packetstream_source.h b/Thirdparty/Pangolin/include/pangolin/log/packetstream_source.h new file mode 100644 index 0000000..7a79e49 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/packetstream_source.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +namespace pangolin { + +using PacketStreamSourceId = size_t; + +struct PANGOLIN_EXPORT PacketStreamSource +{ + struct PacketInfo + { + std::streampos pos; + int64_t capture_time; + }; + + PacketStreamSource() + : id(static_cast(-1)), + version(0), + data_alignment_bytes(1), + data_size_bytes(0), + next_packet_id(0) + { + } + + std::streampos FindSeekLocation(size_t packet_id) + { + if(packet_id < index.size()) { + return index[packet_id].pos; + }else{ + return std::streampos(-1); + } + + } + + int64_t NextPacketTime() const + { + if(next_packet_id < index.size()) { + return index[next_packet_id].capture_time; + }else{ + return 0; + } + } + + std::string driver; + size_t id; + std::string uri; + picojson::value info; + int64_t version; + int64_t data_alignment_bytes; + std::string data_definitions; + int64_t data_size_bytes; + + // Index keyed by packet_id + std::vector index; + + // Based on current position in stream + size_t next_packet_id; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/packetstream_tags.h b/Thirdparty/Pangolin/include/pangolin/log/packetstream_tags.h new file mode 100644 index 0000000..13216f3 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/packetstream_tags.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace pangolin { + +using pangoTagType = uint32_t; + +const static std::string PANGO_MAGIC = "PANGO"; + +const static std::string pss_src_driver = "driver"; +const static std::string pss_src_id = "id"; +const static std::string pss_src_info = "info"; +const static std::string pss_src_uri = "uri"; +const static std::string pss_src_packet = "packet"; +const static std::string pss_src_version = "version"; +const static std::string pss_pkt_alignment_bytes = "alignment_bytes"; +const static std::string pss_pkt_definitions = "definitions"; +const static std::string pss_pkt_size_bytes = "size_bytes"; +const static std::string pss_pkt_format_written = "format_written"; + +const unsigned int TAG_LENGTH = 3; + +#define PANGO_TAG(a,b,c) ( (c<<16) | (b<<8) | a) +const uint32_t TAG_PANGO_HDR = PANGO_TAG('L', 'I', 'N'); +const uint32_t TAG_PANGO_MAGIC = PANGO_TAG('P', 'A', 'N'); +const uint32_t TAG_PANGO_SYNC = PANGO_TAG('S', 'Y', 'N'); +const uint32_t TAG_PANGO_STATS = PANGO_TAG('S', 'T', 'A'); +const uint32_t TAG_PANGO_FOOTER = PANGO_TAG('F', 'T', 'R'); +const uint32_t TAG_ADD_SOURCE = PANGO_TAG('S', 'R', 'C'); +const uint32_t TAG_SRC_JSON = PANGO_TAG('J', 'S', 'N'); +const uint32_t TAG_SRC_PACKET = PANGO_TAG('P', 'K', 'T'); +const uint32_t TAG_END = PANGO_TAG('E', 'N', 'D'); +#undef PANGO_TAG + +inline std::string tagName(int v) +{ + char b[4]; + b[0] = v&0xff; + b[1] = (v>>8)&0xff; + b[2] = (v>>16)&0xff; + b[3] = 0x00; + return std::string(b); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/packetstream_writer.h b/Thirdparty/Pangolin/include/pangolin/log/packetstream_writer.h new file mode 100644 index 0000000..195ff92 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/packetstream_writer.h @@ -0,0 +1,173 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT PacketStreamWriter +{ +public: + PacketStreamWriter() + : _stream(&_buffer), _indexable(false), _open(false), _bytes_written(0) + { + _stream.exceptions(std::ostream::badbit); + } + + PacketStreamWriter(const std::string& filename, size_t buffer_size = 100*1024*1024) + : _buffer(pangolin::PathExpand(filename), buffer_size), _stream(&_buffer), + _indexable(!IsPipe(filename)), _open(_stream.good()), _bytes_written(0) + { + _stream.exceptions(std::ostream::badbit); + WriteHeader(); + } + + ~PacketStreamWriter() { + Close(); + } + + void Open(const std::string& filename, size_t buffer_size = 100 * 1024 * 1024) + { + Close(); + _buffer.open(filename, buffer_size); + _open = _stream.good(); + _bytes_written = 0; + _indexable = !IsPipe(filename); + WriteHeader(); + } + + void Close() + { + if (_open) + { + if (_indexable) { + WriteEnd(); + } + _buffer.close(); + _open = false; + } + } + + // Does not write footer or index. + void ForceClose() + { + if (_open) + { + _buffer.force_close(); + Close(); + } + } + + + // Writes to the stream immediately upon add. Return source id # and writes + // source id # to argument struct + PacketStreamSourceId AddSource(PacketStreamSource& source); + + // If constructor is called inline + PacketStreamSourceId AddSource(const PacketStreamSource& source); + + void WriteSourcePacket( + PacketStreamSourceId src, const char* source,const int64_t receive_time_us, + size_t sourcelen, const picojson::value& meta = picojson::value() + ); + + // For stream read/write synchronization. Note that this is NOT the same as + // time synchronization on playback of iPacketStreams. + void WriteSync(); + + // Writes the end of the stream data, including the index. Does NOT close + // the underlying ostream. + void WriteEnd(); + + const std::vector& Sources() const { + return _sources; + } + + bool IsOpen() const { + return _open; + } + +private: + void WriteHeader(); + void Write(const PacketStreamSource&); + void WriteMeta(PacketStreamSourceId src, const picojson::value& data); + + threadedfilebuf _buffer; + std::ostream _stream; + bool _indexable, _open; + + std::vector _sources; + size_t _bytes_written; + std::recursive_mutex _lock; +}; + +inline void writeCompressedUnsignedInt(std::ostream& writer, size_t n) +{ + while (n >= 0x80) + { + writer.put(0x80 | (n & 0x7F)); + n >>= 7; + } + writer.put(static_cast(n)); +} + +inline void writeTimestamp(std::ostream& writer, int64_t time_us) +{ + writer.write(reinterpret_cast(&time_us), sizeof(decltype(time_us))); +} + +inline void writeTag(std::ostream& writer, const pangoTagType tag) +{ + writer.write(reinterpret_cast(&tag), TAG_LENGTH); +} + +inline picojson::value SourceStats(const std::vector& srcs) +{ + picojson::value stat; + stat["num_sources"] = srcs.size(); + stat["src_packet_index"] = picojson::array(); + stat["src_packet_times"] = picojson::array(); + + for(auto& src : srcs) { + picojson::array pkt_index, pkt_times; + for (const PacketStreamSource::PacketInfo& frame : src.index) { + pkt_index.emplace_back(frame.pos); + pkt_times.emplace_back(frame.capture_time); + } + stat["src_packet_index"].push_back(std::move(pkt_index)); + stat["src_packet_times"].push_back(std::move(pkt_times)); + } + return stat; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/playback_session.h b/Thirdparty/Pangolin/include/pangolin/log/playback_session.h new file mode 100644 index 0000000..fb28d13 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/playback_session.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace pangolin { + +class Params; + +class PlaybackSession +{ +public: + // Singleton Instance + static std::shared_ptr Default(); + + // Return thread-safe, shared instance of PacketStreamReader, providing + // serialised read for PacketStreamReader + std::shared_ptr Open(const std::string& filename) + { + const std::string path = SanitizePath(PathExpand(filename)); + + auto i = readers.find(path); + if(i == readers.end()) { + auto psr = std::make_shared(path); + readers[path] = psr; + return psr; + }else{ + return i->second; + } + } + + SyncTime& Time() + { + return time; + } + + static std::shared_ptr ChooseFromParams(const Params& params); + +private: + std::map> readers; + SyncTime time; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/log/sync_time.h b/Thirdparty/Pangolin/include/pangolin/log/sync_time.h new file mode 100644 index 0000000..10dfe71 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/log/sync_time.h @@ -0,0 +1,230 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace pangolin +{ + +// Lightweight timestamp class to allow synchronized playback from the same (or a different) stream. +// All playback functions called with the same SyncTime will be time-synchronized, and will remain synchronized on seek() if the SyncTime is passed in when seeking. +// Playback with multiple SyncTimes (on the same or different streams) should also be synced, even in different processes or systems (underlying clock sync is not required). +// However, playback with multiple SyncTimes will break on seek(). +class PANGOLIN_EXPORT SyncTime +{ +public: + using Clock = baseclock; + using Duration = Clock::duration; + using TimePoint = Clock::time_point; + + struct SeekInterruption: std::runtime_error + { + SeekInterruption() : std::runtime_error("Time queue invalidated by seek"){} + }; + + SyncTime(Duration virtual_clock_offset = std::chrono::milliseconds(0)) + : seeking(false) + { + SetOffset(virtual_clock_offset); + } + + // No copy constructor + SyncTime(const SyncTime&) = delete; + + void SetOffset(Duration virtual_clock_offset) + { + virtual_offset = virtual_clock_offset; + } + + void SetClock(TimePoint virtual_now) + { + virtual_offset = virtual_now - Clock::now(); + } + + TimePoint TimeNow() const + { + return Clock::now() + virtual_offset; + } + + TimePoint ToVirtual(TimePoint real) const + { + return real + virtual_offset; + } + + TimePoint ToReal(TimePoint virt) const + { + return virt - virtual_offset; + } + + void WaitUntil(TimePoint virtual_time) const + { + std::this_thread::sleep_until( ToReal(virtual_time) ); + } + + int64_t QueueEvent(int64_t new_event_time_us) + { + return WaitDequeueAndQueueEvent(0, new_event_time_us); + } + + void DequeueEvent(int64_t event_time_us) + { + std::unique_lock l(time_mutex); + auto i = std::find(time_queue_us.begin(), time_queue_us.end(), event_time_us); + PANGO_ENSURE(i != time_queue_us.end()); + time_queue_us.erase(i); + queue_changed.notify_all(); + } + + int64_t WaitDequeueAndQueueEvent(int64_t event_time_us, int64_t new_event_time_us =0 ) + { + std::unique_lock l(time_mutex); + + if(event_time_us) { + PANGO_ENSURE(time_queue_us.size()); + + // Wait until we're top the priority-queue + queue_changed.wait(l, [&](){ + if(seeking) { + // Time queue will be invalidated on seek. + // Unblock without action + throw SeekInterruption(); + } + return time_queue_us.back() == event_time_us; + }); + + // Dequeue + time_queue_us.pop_back(); + } + + if(new_event_time_us) { + // Add the new event whilst we still hold the lock, so that our + // event can't be missed + insert_sorted(time_queue_us, new_event_time_us, std::greater()); + + if(time_queue_us.back() == new_event_time_us) { + // Return to avoid yielding when we're next. + return new_event_time_us; + } + } + + // Only yield if another device is next + queue_changed.notify_all(); + return new_event_time_us; + } + + void NotifyAll() + { + queue_changed.notify_all(); + } + + std::mutex& TimeMutex() + { + return time_mutex; + } + + void Stop() + { + seeking = true; + OnTimeStop(); + queue_changed.notify_all(); + } + + void Start() + { + OnTimeStart(); + seeking=false; + } + + void Seek(TimePoint t) + { + Stop(); + OnSeek(t); + Start(); + } + + Signal<> OnTimeStart; + + Signal<> OnTimeStop; + + Signal OnSeek; + +private: + template< typename T, typename Pred > + static typename std::vector::iterator + insert_sorted( std::vector & vec, T const& item, Pred pred ) + { + return vec.insert ( + std::upper_bound( vec.begin(), vec.end(), item, pred ), item + ); + } + + std::vector time_queue_us; + Duration virtual_offset; + std::mutex time_mutex; + std::condition_variable queue_changed; + bool seeking; +}; + +struct SyncTimeEventPromise +{ + SyncTimeEventPromise(SyncTime& sync, int64_t time_us = 0) + : sync(sync), time_us(time_us) + { + sync.QueueEvent(time_us); + } + + ~SyncTimeEventPromise() + { + Cancel(); + } + + void Cancel() + { + if(time_us) { + sync.DequeueEvent(time_us); + time_us = 0; + } + } + + void WaitAndRenew(int64_t new_time_us) + { + time_us = sync.WaitDequeueAndQueueEvent(time_us, new_time_us); + } + +private: + SyncTime& sync; + int64_t time_us; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/pangolin.h b/Thirdparty/Pangolin/include/pangolin/pangolin.h new file mode 100644 index 0000000..370752a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/pangolin.h @@ -0,0 +1,64 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#ifdef BUILD_PANGOLIN_GUI + #include + #include + #include + #include + #include + #include + #include + #ifdef _ANDROID_ + #include + #endif + #if !defined(HAVE_GLES) || defined(HAVE_GLES_2) + #include + #endif +#endif // BUILD_PANGOLIN_GUI + +#ifdef BUILD_PANGOLIN_VARS + #include + #ifdef BUILD_PANGOLIN_GUI + #include + #endif // BUILD_PANGOLIN_GUI +#endif // BUILD_PANGOLIN_VARS + +#ifdef BUILD_PANGOLIN_VIDEO + #include + #include + #include +#endif // BUILD_PANGOLIN_VIDEO + +#include + +// Let other libraries headers know about Pangolin +#define HAVE_PANGOLIN diff --git a/Thirdparty/Pangolin/include/pangolin/platform.h b/Thirdparty/Pangolin/include/pangolin/platform.h new file mode 100644 index 0000000..b5a223b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/platform.h @@ -0,0 +1,81 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +// Include portable printf-style format macros +#define __STDC_FORMAT_MACROS + +#ifdef _GCC_ +# define PANGOLIN_DEPRECATED __attribute__((deprecated)) +#elif defined _MSVC_ +# define PANGOLIN_DEPRECATED __declspec(deprecated) +#else +# define PANGOLIN_DEPRECATED +#endif + +#ifdef _MSVC_ +# define __thread __declspec(thread) +# include +#else +# define PANGOLIN_EXPORT +#endif //_MSVC_ + +#define PANGOLIN_UNUSED(x) (void)(x) + +#ifdef _APPLE_IOS_ +// Not supported on this platform. +#define __thread +#endif // _APPLE_IOS_ + +// HOST / DEVICE Annotations +#ifdef __CUDACC__ +# include +# define PANGO_HOST_DEVICE __host__ __device__ +#else +# define PANGO_HOST_DEVICE +#endif + +// Non-standard check that header exists (Clang, GCC 5.X) +// Useful for +#if defined(__has_include) +# define PANGO_HEADER_EXISTS(x) __has_include(x) +#else +# define PANGO_HEADER_EXISTS(x) 0 +#endif + +// Workaround for Apple-Clangs lack of thread_local support +#if defined(_CLANG_) && defined(_OSX_) +# if !__has_feature(cxx_thread_local) +# define PANGO_NO_THREADLOCAL +# endif +#endif + +#include +#include diff --git a/Thirdparty/Pangolin/include/pangolin/plot/datalog.h b/Thirdparty/Pangolin/include/pangolin/plot/datalog.h new file mode 100644 index 0000000..d0120b0 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/plot/datalog.h @@ -0,0 +1,243 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include // std::min, std::max +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files +#define USE_EIGEN +#endif + +#ifdef USE_EIGEN +#include +#endif + +namespace pangolin +{ + +/// Simple statistics recorded for a logged input dimension. +struct DimensionStats +{ + DimensionStats() + { + Reset(); + } + + void Reset() + { + isMonotonic = true; + sum = 0.0f; + sum_sq = 0.0f; + min = std::numeric_limits::max(); + max = std::numeric_limits::lowest(); + } + + void Add(const float v) + { + isMonotonic = isMonotonic && (v >= max); + sum += v; + sum_sq += v*v; + min = std::min(min, v); + max = std::max(max, v); + } + + bool isMonotonic; + float sum; + float sum_sq; + float min; + float max; +}; + +class DataLogBlock +{ +public: + /// @param dim: dimension of sample + /// @param max_samples: maximum number of samples this block can hold + /// @param start_id: index of first sample (from entire dataset) in this buffer + DataLogBlock(size_t dim, size_t max_samples, size_t start_id) + : dim(dim), max_samples(max_samples), samples(0), + start_id(start_id) + { + sample_buffer = std::unique_ptr(new float[dim*max_samples]); +// stats = std::unique_ptr(new DimensionStats[dim]); + } + + ~DataLogBlock() + { + } + + size_t Samples() const + { + return samples; + } + + size_t MaxSamples() const + { + return max_samples; + } + + /// Return how many more samples can fit in this block + size_t SampleSpaceLeft() const + { + return MaxSamples()- Samples(); + } + + bool IsFull() const + { + return Samples() >= MaxSamples(); + } + + /// Add data to block + void AddSamples(size_t num_samples, size_t dimensions, const float* data_dim_major ); + + /// Delete all samples + void ClearLinked() + { + samples = 0; + nextBlock.reset(); + } + + DataLogBlock* NextBlock() const + { + return nextBlock.get(); + } + + size_t StartId() const + { + return start_id; + } + + float* DimData(size_t d) const + { + return sample_buffer.get() + d; + } + + size_t Dimensions() const + { + return dim; + } + + const float* Sample(size_t n) const + { + const int id = (int)n - (int)start_id; + + if( 0 <= id && id < (int)samples ) { + return sample_buffer.get() + dim*id; + }else{ + if(nextBlock) { + return nextBlock->Sample(n); + }else{ + throw std::out_of_range("Index out of range."); + } + } + } + +protected: + size_t dim; + size_t max_samples; + size_t samples; + size_t start_id; + std::unique_ptr sample_buffer; +// std::unique_ptr stats; + std::unique_ptr nextBlock; +}; + +/// A DataLog can efficiently record floating point sample data of any size. +/// Memory is allocated in blocks is transparent to the user. +class PANGOLIN_EXPORT DataLog +{ +public: + /// @param block_samples_alloc number of samples each memory block can hold. + DataLog(unsigned int block_samples_alloc = 10000 ); + + ~DataLog(); + + /// Provide textual labels corresponding to each dimension logged. + /// This information may be used by graphical interfaces to DataLog. + void SetLabels(const std::vector & labels); + const std::vector& Labels() const; + + void Log(size_t dimension, const float * vals, unsigned int samples = 1); + void Log(float v); + void Log(float v1, float v2); + void Log(float v1, float v2, float v3); + void Log(float v1, float v2, float v3, float v4); + void Log(float v1, float v2, float v3, float v4, float v5); + void Log(float v1, float v2, float v3, float v4, float v5, float v6); + void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7); + void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8); + void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9); + void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9, float v10); + void Log(const std::vector & vals); + +#ifdef USE_EIGEN + template + void Log(const Eigen::MatrixBase& M) + { + Log( M.rows() * M.cols(), M.template cast().eval().data() ); + } +#endif + + void Clear(); + void Save(std::string filename); + + // Return first block of stored data + const DataLogBlock* FirstBlock() const; + + // Return last block of stored data + const DataLogBlock* LastBlock() const; + + // Return number of samples stored in this DataLog + size_t Samples() const; + + // Return pointer to stored sample n + const float* Sample(int n) const; + + // Return stats computed for each dimension if enabled. + const DimensionStats& Stats(size_t dim) const; + + std::mutex access_mutex; + +protected: + unsigned int block_samples_alloc; + std::vector labels; + std::unique_ptr block0; + DataLogBlock* blockn; + std::vector stats; + bool record_stats; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/plot/plotter.h b/Thirdparty/Pangolin/include/pangolin/plot/plotter.h new file mode 100644 index 0000000..c9eff6b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/plot/plotter.h @@ -0,0 +1,282 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#ifndef PLOTTER_H +#define PLOTTER_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pangolin +{ + +enum DrawingMode +{ + DrawingModePoints = GL_POINTS, + DrawingModeDashed = GL_LINES, + DrawingModeLine = GL_LINE_STRIP, + DrawingModeNone, +}; + +struct Marker +{ + enum Direction + { + Horizontal, + Vertical + }; + + enum Equality + { + LessThan = -1, + Equal = 0, + GreaterThan = 1 + }; + + Marker(Direction d, float value, Equality leg = Equal, Colour c = Colour() ) + : colour(c) + { + if(d == Horizontal) { + range.x = Rangef::Open(); + range.y = Rangef::Containing(value); + if(leg == LessThan) { + range.y.Insert(std::numeric_limits::lowest() ); + }else if(leg == GreaterThan) { + range.y.Insert(std::numeric_limits::max() ); + } + }else if(d == Vertical) { + range.x = Rangef::Containing(value); + range.y = Rangef::Open(); + if(leg == LessThan) { + range.x.Insert(std::numeric_limits::lowest() ); + }else if(leg == GreaterThan) { + range.x.Insert(std::numeric_limits::max() ); + } + } + } + + Marker(const XYRangef& range, const Colour& c = Colour() ) + : range(range), colour(c) + { + } + + XYRangef range; + Colour colour; +}; + +class PANGOLIN_EXPORT Plotter : public View, Handler +{ +public: + Plotter( + DataLog* default_log, + float left=0, float right=600, float bottom=-1, float top=1, + float tickx=30, float ticky=0.5, + Plotter* linked_plotter_x = 0, + Plotter* linked_plotter_y = 0 + ); + + virtual ~Plotter(); + + void Render(); + + XYRangef& GetSelection(); + + XYRangef& GetDefaultView(); + void SetDefaultView(const XYRangef& range); + + XYRangef& GetView(); + void SetView(const XYRangef& range); + void SetViewSmooth(const XYRangef& range); + + void ScrollView(float x, float y); + void ScrollViewSmooth(float x, float y); + + void ScaleView(float x, float y, float cx, float cy); + void ScaleViewSmooth(float x, float y, float cx, float cy); + + void ResetView(); + + void SetTicks(float tickx, float ticky); + + void Track(const std::string& x="$i", const std::string& y = ""); + void ToggleTracking(); + + void Trigger(const std::string& x="$0", int edge = -1, float value = 0.0f); + void ToggleTrigger(); + + void SetBackgroundColour(const Colour& col); + void SetAxisColour(const Colour& col); + void SetTickColour(const Colour& col); + + void ScreenToPlot(int xpix, int ypix, float &xplot, float &yplot); + void Keyboard(View&, unsigned char key, int x, int y, bool pressed); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void MouseMotion(View&, int x, int y, int mouse_state); + void PassiveMouseMotion(View&, int x, int y, int button_state); + void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state); + + /// Remove all current series plots + void ClearSeries(); + + /// Add series X,Y plot from glsl compatible expressions x_expr, y_expr + /// $i refers to integral index of datum in log. + /// $0, $1, $2, ... refers to nth series in log. + /// e.g. x_expr = "$i", y_expr = "$0" // index - data[0] plot + /// e.g. x_expr = "$0", y_expr = "$1" // data[0], data[1] X-Y plot + /// e.g. x_exptr ="$i", y_expr = "sqrt($1)} // index - sqrt(data[0]) plot + void AddSeries(const std::string& x_expr, const std::string& y_expr, + DrawingMode drawing_mode = DrawingModeLine, Colour colour = Colour::Unspecified(), + const std::string &title = "$y", DataLog* log = nullptr + ); + + std::string PlotTitleFromExpr(const std::string& expr) const; + + /// Remove all current markers + void ClearMarkers(); + + /// Add horizontal or vertical inequality marker; equal-to, less-than, or greater than. + /// This is useful for annotating a critical point or valid region. + Marker& AddMarker( + Marker::Direction d, float value, + Marker::Equality leg = Marker::Equal, Colour c = Colour() + ); + + Marker& AddMarker( const Marker& marker ); + + void ClearImplicitPlots(); + void AddImplicitPlot(); + + /// Reset colour wheel to initial state. May be useful together with ClearSeries() / ClearMarkers() + void ResetColourWheel(); + +protected: + struct PANGOLIN_EXPORT Tick + { + float val; + float factor; + std::string symbol; + }; + + struct PANGOLIN_EXPORT PlotAttrib + { + PlotAttrib(std::string name, int plot_id, int location = -1) + : name(name), plot_id(plot_id), location(location) { } + + std::string name; + int plot_id; + int location; + }; + + struct PANGOLIN_EXPORT PlotSeries + { + PlotSeries(); + void CreatePlot(const std::string& x, const std::string& y, Colour c, std::string title); + + GlSlProgram prog; + GlText title; + bool contains_id; + std::vector attribs; + DataLog* log; + GLenum drawing_mode; + Colour colour; + bool used; + }; + + struct PANGOLIN_EXPORT PlotImplicit + { + // Assign to gl_FragColor + void CreatePlot(const std::string& code); + + // Expression uses x,y and assignes colours [0,1] to r,g,b,a + void CreateColouredPlot(const std::string& code); + + // Expression uses x,y and evaluates to true/false; + void CreateInequality(const std::string& ie, Colour c); + + // Expression uses x,y and evaluates to a number + void CreateDistancePlot(const std::string& dist); + + GlSlProgram prog; + }; + + void FixSelection(); + void UpdateView(); + Tick FindTickFactor(float tick); + + DataLog* default_log; + + ColourWheel colour_wheel; + Colour colour_bg; + Colour colour_tk; + Colour colour_ax; + + GlSlProgram prog_lines; + GlSlProgram prog_text; + + std::vector plotseries; + std::vector plotmarkers; + std::vector plotimplicits; + + Tick tick[2]; + XYRangef rview_default; + XYRangef rview; + XYRangef target; + XYRangef selection; + + void ComputeTrackValue( float track_val[2] ); + XYRangef ComputeAutoSelection(); + + bool track; + std::string track_x; + std::string track_y; + float last_track_val[2]; + + // -1: falling, -0:disable, 1: rising + int trigger_edge; + float trigger_value; + std::string trigger; + + float hover[2]; + int last_mouse_pos[2]; + + Plotter* linked_plotter_x; + Plotter* linked_plotter_y; +}; + +} // namespace pangolin + +#endif // PLOTTER_H diff --git a/Thirdparty/Pangolin/include/pangolin/plot/range.h b/Thirdparty/Pangolin/include/pangolin/plot/range.h new file mode 100644 index 0000000..ec2906e --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/plot/range.h @@ -0,0 +1,372 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include +#include + +//prevent including Eigen in cuda files +#if defined(HAVE_EIGEN) && !defined(__CUDACC__) +# define USE_EIGEN +#endif + +#ifdef USE_EIGEN +# include +# include +#endif // USE_EIGEN + +namespace pangolin +{ + + +template +struct Range +{ + static Range Open() + { + return Range(std::numeric_limits::lowest(), std::numeric_limits::max()); + } + + static Range Empty() + { + return Range(std::numeric_limits::max(), std::numeric_limits::lowest()); + } + + static Range Containing(T val) + { + return Range(val, val); + } + + Range() + : min(+std::numeric_limits::max()), + max(-std::numeric_limits::max()) + { + } + + Range(T rmin, T rmax) + : min(rmin), max(rmax) + { + } + + Range operator+(T v) + { + return Range(min+v, max+v); + } + + Range operator-(T v) + { + return Range(min-v, max-v); + } + + Range& operator+=(T v) + { + min += v; + max += v; + return *this; + } + + Range& operator-=(T v) + { + min -= v; + max -= v; + return *this; + } + + Range& operator*=(T v) + { + min *= v; + max *= v; + return *this; + } + + Range& operator/=(T v) + { + min /= v; + max /= v; + return *this; + } + + Range& operator+=(const Range& o) + { + min += o.min; + max += o.max; + return *this; + } + + Range& operator-=(const Range& o) + { + min -= o.min; + max -= o.max; + return *this; + } + + Range operator+(const Range& o) const + { + return Range(min + o.min, max + o.max); + } + + Range operator-(const Range& o) const + { + return Range(min - o.min, max - o.max); + } + + Range operator*(float s) const + { + return Range(T(s*min), T(s*max)); + } + + T Size() const + { + return max - min; + } + + T AbsSize() const + { + return std::abs(Size()); + } + + T Mid() const + { + return (min + max) / (T)2.0f; + } + + void Scale(float s, float center = 0.0f) + { + min = T(s*(min-center) + center); + max = T(s*(max-center) + center); + } + + void Insert(T v) + { + min = std::min(min,v); + max = std::max(max,v); + } + + void Insert(const Range& r) + { + Insert(r.min); + Insert(r.max); + } + + void Clamp(T vmin, T vmax) + { + min = std::min(std::max(vmin, min), vmax); + max = std::min(std::max(vmin, max), vmax); + } + + void Clamp(const Range& o) + { + Clamp(o.min, o.max); + } + + void Clear() + { + min = std::numeric_limits::max(); + max = std::numeric_limits::lowest(); + } + + bool Contains(T v) const + { + return min <= v && v <= max; + } + + bool ContainsWeak(T v) const + { + return (min <= v && v <= max) + || (max <= v && v <= min); + } + + template + Range Cast() const + { + return Range(To(min), To(max)); + } + + T min; + T max; +}; + +template +struct XYRange +{ + static XYRange Open() + { + return XYRange( + Range(std::numeric_limits::lowest(), std::numeric_limits::max()), + Range(std::numeric_limits::lowest(), std::numeric_limits::max()) + ); + } + + static XYRange Empty() + { + return XYRange( + Range(std::numeric_limits::max(), std::numeric_limits::lowest()), + Range(std::numeric_limits::max(), std::numeric_limits::lowest()) + ); + } + + static XYRange Containing(T x, T y) + { + return XYRange( + Range(x, x), + Range(y, y) + ); + } + + XYRange() + { + } + + XYRange(const Range& xrange, const Range& yrange) + : x(xrange), y(yrange) + { + } + + XYRange(T xmin, T xmax, T ymin, T ymax) + : x(xmin,xmax), y(ymin,ymax) + { + } + + XYRange operator-(const XYRange& o) const + { + return XYRange(x - o.x, y - o.y); + } + + XYRange operator*(float s) const + { + return XYRange(x*s, y*s); + } + + XYRange& operator+=(const XYRange& o) + { + x += o.x; + y += o.y; + return *this; + } + + void Scale(float sx, float sy, float centerx, float centery) + { + x.Scale(sx, centerx); + y.Scale(sy, centery); + } + + void Clear() + { + x.Clear(); + y.Clear(); + } + + void Clamp(T xmin, T xmax, T ymin, T ymax) + { + x.Clamp(xmin,xmax); + y.Clamp(ymin,ymax); + } + + void Clamp(const XYRange& o) + { + x.Clamp(o.x); + y.Clamp(o.y); + } + + void Insert(T xval, T yval) + { + x.Insert(xval); + y.Insert(yval); + } + + void Insert(XYRange r) + { + x.Insert(r.x); + y.Insert(r.y); + } + + float Area() const + { + return x.Size() * y.Size(); + } + + bool Contains(float px, float py) const + { + return x.Contains(px) && y.Contains(py); + } + + bool ContainsWeak(float px, float py) const + { + return x.ContainsWeak(px) && y.ContainsWeak(py); + } + + template + XYRange Cast() const + { + return XYRange( + x.template Cast(), + y.template Cast() + ); + } + +#ifdef USE_EIGEN + operator Eigen::AlignedBox() const { + return Eigen::AlignedBox( + Eigen::Matrix(x.min, y.min), + Eigen::Matrix(x.max, y.max) + ); + } + + Eigen::Matrix Center() const { + return Eigen::Matrix(x.Mid(), y.Mid()); + } +#endif + + Range x; + Range y; +}; + +typedef Range Rangei; +typedef Range Rangef; +typedef Range Ranged; + +typedef XYRange XYRangei; +typedef XYRange XYRangef; +typedef XYRange XYRanged; + +template inline +Rangei Round(const Range& r) +{ + return Rangei( int(r.min+0.5), int(r.max+0.5) ); +} + +template inline +XYRangei Round(const XYRange& r) +{ + return XYRangei( Round(r.x), Round(r.y) ); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/python/pyinterpreter.h b/Thirdparty/Pangolin/include/pangolin/python/pyinterpreter.h new file mode 100644 index 0000000..8d533bb --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/python/pyinterpreter.h @@ -0,0 +1,70 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace pangolin +{ + +class PyInterpreter : public ConsoleInterpreter +{ +public: + PyInterpreter(); + + ~PyInterpreter() override; + + void PushCommand(const std::string &cmd) override; + + bool PullLine(ConsoleLine& line) override; + + std::vector Complete( + const std::string& cmd, int max_options + ) override; + + static void AttachPrefix(void* data, const std::string& name, VarValueGeneric& var, bool brand_new ); + +private: + PyObject* pycompleter; + PyObject* pycomplete; + + std::string ToString(PyObject* py); + void CheckPrintClearError(); + PyUniqueObj EvalExec(const std::string& cmd); + + std::queue line_queue; + std::set base_prefixes; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/python/pypangoio.h b/Thirdparty/Pangolin/include/pangolin/python/pypangoio.h new file mode 100644 index 0000000..cdfee76 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/python/pypangoio.h @@ -0,0 +1,178 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include + +namespace pangolin +{ + +struct PyPangoIO { + PyObject_HEAD + + static PyTypeObject Py_type; + static PyMethodDef Py_methods[]; + + PyPangoIO(PyTypeObject *type, std::queue& line_queue, ConsoleLineType line_type) + : line_queue(line_queue), line_type(line_type) + { +#if PY_MAJOR_VERSION >= 3 + ob_base.ob_refcnt = 1; + ob_base.ob_type = type; +#else + ob_refcnt = 1; + ob_type = type; +#endif + } + + static void Py_dealloc(PyPangoIO* self) + { + delete self; + } + + static PyObject * Py_new(PyTypeObject */*type*/, PyObject */*args*/, PyObject */*kwds*/) + { + // Failure. Can only new in c++ + return 0; + } + + static int Py_init(PyPangoIO* /*self*/, PyObject* /*args*/, PyObject* /*kwds*/) + { + return 0; + } + + static PyObject* Py_getattr(PyPangoIO *self, char* name) + { +#if PY_MAJOR_VERSION >= 3 + PyObject* pystr = PyUnicode_FromString(name); +#else + PyObject* pystr = PyString_FromString(name); +#endif + return PyObject_GenericGetAttr((PyObject*)self, pystr ); + } + + static int Py_setattr(PyPangoIO *self, char* name, PyObject* val) + { +#if PY_MAJOR_VERSION >= 3 + PyObject* pystr = PyUnicode_FromString(name); +#else + PyObject* pystr = PyString_FromString(name); +#endif + return PyObject_GenericSetAttr((PyObject*)self, pystr, val); + } + + static PyObject* Py_write(PyPangoIO* self, PyObject *args) + { + const char *text = 0; + if (PyArg_ParseTuple(args, "s", &text)) { + self->buffer += std::string(text); + size_t nl = self->buffer.find_first_of('\n'); + while(nl != std::string::npos) { + const std::string line = self->buffer.substr(0,nl); + self->line_queue.push(ConsoleLine(line,self->line_type)); + self->buffer = self->buffer.substr(nl+1); + nl = self->buffer.find_first_of('\n'); + } + } + Py_RETURN_NONE; + } + + std::string buffer; + std::queue& line_queue; + ConsoleLineType line_type; +}; + +PyMethodDef PyPangoIO::Py_methods[] = { + {"write", (PyCFunction)PyPangoIO::Py_write, METH_VARARGS, "Write to console" }, + {NULL, NULL, 0, NULL} +}; + +#pragma GCC diagnostic push // Ignore python missing initializer warning. +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + +PyTypeObject PyPangoIO::Py_type = { + PyVarObject_HEAD_INIT(NULL,0) + "pangolin.PangoIO", /* tp_name*/ + sizeof(PyPangoIO), /* tp_basicsize*/ + 0, /* tp_itemsize*/ + (destructor)PyPangoIO::Py_dealloc, /* tp_dealloc*/ + 0, /* tp_print*/ + (getattrfunc)PyPangoIO::Py_getattr, /* tp_getattr*/ + (setattrfunc)PyPangoIO::Py_setattr, /* tp_setattr*/ + 0, /* tp_compare*/ + 0, /* tp_repr*/ + 0, /* tp_as_number*/ + 0, /* tp_as_sequence*/ + 0, /* tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call*/ + 0, /* tp_str*/ + 0, /* tp_getattro*/ + 0, /* tp_setattro*/ + 0, /* tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/ + "PyPangoIO object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyPangoIO::Py_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyPangoIO::Py_init, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)PyPangoIO::Py_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0 /* tp_version_tag */ +}; + +#pragma GCC diagnostic pop // Return to normal + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/python/pypangolin_init.h b/Thirdparty/Pangolin/include/pangolin/python/pypangolin_init.h new file mode 100644 index 0000000..8c972cd --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/python/pypangolin_init.h @@ -0,0 +1,40 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include + +namespace pangolin +{ + +PANGOLIN_EXPORT +PyMODINIT_FUNC InitPyPangolinModule(); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/python/pyuniqueobj.h b/Thirdparty/Pangolin/include/pangolin/python/pyuniqueobj.h new file mode 100644 index 0000000..cb3d3c9 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/python/pyuniqueobj.h @@ -0,0 +1,111 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +/// Class represents a reference counted PythonObject. +/// PythonObject is appropriately Py_INCREF'd and Py_DECREF'd +class PyUniqueObj +{ +public: + inline + PyUniqueObj() + : obj(0) + { + } + + /// Assumption: PythonObject has already been appropriately INCREF'd. + inline + PyUniqueObj(PyObject* obj) + : obj(obj) + { + } + + inline + PyUniqueObj(const PyUniqueObj& other) + :obj(other.obj) + { + if(obj) Py_INCREF(obj); + } + + inline + ~PyUniqueObj() + { + if(obj) Py_DECREF(obj); + } + + inline + PyUniqueObj(PyUniqueObj&& other) + : obj(other.obj) + { + other.obj = 0; + } + + inline + void operator=(PyUniqueObj&& other) + { + Release(); + obj = other.obj; + other.obj = 0; + } + + inline + void operator=(PyObject* obj) + { + Release(); + this->obj = obj; + } + + inline + void Release() { + if(obj) { + Py_DECREF(obj); + obj = 0; + } + } + + inline + PyObject* operator*() { + return obj; + } + + inline + operator PyObject*() { + return obj; + } + +private: + PyObject* obj; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/python/pyvar.h b/Thirdparty/Pangolin/include/pangolin/python/pyvar.h new file mode 100644 index 0000000..ebadd8a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/python/pyvar.h @@ -0,0 +1,271 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace pangolin +{ + +PyObject* GetPangoVarAsPython(const std::string& name) +{ + VarState::VarStoreContainer::iterator i = VarState::I().vars.find(name); + if(i != VarState::I().vars.end()) { + VarValueGeneric* var = i->second; + + try{ + if( !strcmp(var->TypeId(), typeid(bool).name() ) ) { + const bool val = Var(*var).Get(); + return PyBool_FromLong( val ); + }else if( !strcmp(var->TypeId(), typeid(short).name() ) || + !strcmp(var->TypeId(), typeid(int).name() ) || + !strcmp(var->TypeId(), typeid(long).name() ) ) { + const long val = Var(*var).Get(); + return PyLong_FromLong( val ); + }else if( !strcmp(var->TypeId(), typeid(double).name() ) || + !strcmp(var->TypeId(), typeid(float).name() ) ) { + const double val = Var(*var).Get(); + return PyFloat_FromDouble(val); + }else{ + const std::string val = var->str->Get(); +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromString(val.c_str()); +#else + return PyString_FromString(val.c_str()); +#endif + } + }catch(const std::exception&) { + } + } + + Py_RETURN_NONE; +} + +void SetPangoVarFromPython(const std::string& name, PyObject* val) +{ + try{ + if (PyFloat_Check(val)) { + pangolin::Var pango_var(name); + pango_var = PyFloat_AsDouble(val); + pango_var.Meta().gui_changed = true; + }else if (PyLong_Check(val)) { + pangolin::Var pango_var(name); + pango_var = PyLong_AsLong(val); + pango_var.Meta().gui_changed = true; + }else if (PyBool_Check(val)) { + pangolin::Var pango_var(name); + pango_var = (val == Py_True) ? true : false; + pango_var.Meta().gui_changed = true; + } +#if PY_MAJOR_VERSION >= 3 + else if (PyUnicode_Check(val)) { + pangolin::Var pango_var(name); + pango_var = PyUnicode_AsUTF8(val); + pango_var.Meta().gui_changed = true; + } +#else + else if (PyString_Check(val)) { + pangolin::Var pango_var(name); + pango_var = PyString_AsString(val); + pango_var.Meta().gui_changed = true; + } else if (PyInt_Check(val)) { + pangolin::Var pango_var(name); + pango_var = PyInt_AsLong(val); + pango_var.Meta().gui_changed = true; + } +#endif + else { + PyUniqueObj pystr = PyObject_Repr(val); +#if PY_MAJOR_VERSION >= 3 + const std::string str = PyUnicode_AsUTF8(pystr); +#else + const std::string str = PyString_AsString(pystr); +#endif + pangolin::Var pango_var(name); + pango_var = str; + pango_var.Meta().gui_changed = true; + } + FlagVarChanged(); + }catch(const std::exception& e) { + pango_print_error("%s\n", e.what()); + } +} + +struct PyVar { + static PyTypeObject Py_type; + PyObject_HEAD + + PyVar(PyTypeObject *type) + { +#if PY_MAJOR_VERSION >= 3 + ob_base.ob_refcnt = 1; + ob_base.ob_type = type; +#else + ob_refcnt = 1; + ob_type = type; +#endif + } + + static void Py_dealloc(PyVar* self) + { + delete self; + } + + static PyObject * Py_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) + { + PyVar* self = new PyVar(type); + return (PyObject *)self; + } + + static int Py_init(PyVar *self, PyObject *args, PyObject * /*kwds*/) + { + char* cNamespace = 0; + if (!PyArg_ParseTuple(args, "s", &cNamespace)) + return -1; + + self->ns = std::string(cNamespace); + + return 0; + } + + static PyObject* Py_getattr(PyVar *self, char* name) + { + const std::string prefix = self->ns + "."; + const std::string full_name = self->ns.empty() ? name : prefix + std::string(name); + + if( !strcmp(name, "__call__") || + !strcmp(name, "__dict__") || + !strcmp(name, "__methods__") || + !strcmp(name, "__class__") ) + { + // Default behaviour +#if PY_MAJOR_VERSION >= 3 + return PyObject_GenericGetAttr((PyObject*)self, PyUnicode_FromString(name)); +#else + return PyObject_GenericGetAttr((PyObject*)self, PyString_FromString(name)); +#endif + } else if( !strcmp(name, "__members__") ) { + const int nss = prefix.size(); + PyObject* l = PyList_New(0); + for(const std::string& s : VarState::I().var_adds) { + if(!s.compare(0, nss, prefix)) { + size_t dot = s.find_first_of('.', nss); + std::string val = (dot != std::string::npos) ? s.substr(nss, dot - nss) : s.substr(nss); +#if PY_MAJOR_VERSION >= 3 + PyList_Append(l, PyUnicode_FromString(val.c_str())); +#else + PyList_Append(l, PyString_FromString(val.c_str())); +#endif + } + } + + return l; + }else if( pangolin::VarState::I().Exists(full_name) ) { + return GetPangoVarAsPython(full_name); + }else{ + PyVar* obj = (PyVar*)PyVar::Py_new(&PyVar::Py_type,NULL,NULL); + if(obj) { + obj->ns = full_name; + return PyObject_Init((PyObject *)obj,&PyVar::Py_type); + } + return (PyObject *)obj; + } + + Py_RETURN_NONE; + } + + static int Py_setattr(PyVar *self, char* name, PyObject* val) + { + const std::string full_name = self->ns.empty() ? name : self->ns + "." + std::string(name); + SetPangoVarFromPython(full_name, val); + return 0; + } + + std::string ns; +}; + +// The uninitialized variable can be ignored. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + PyTypeObject PyVar::Py_type = { + PyVarObject_HEAD_INIT(NULL,0) + "pypangolin.Var", /* tp_name*/ + sizeof(PyVar), /* tp_basicsize*/ + 0, /* tp_itemsize*/ + (destructor)PyVar::Py_dealloc, /* tp_dealloc*/ + 0, /* tp_print*/ + (getattrfunc)PyVar::Py_getattr, /* tp_getattr*/ + (setattrfunc)PyVar::Py_setattr, /* tp_setattr*/ + 0, /* tp_compare*/ + 0, /* tp_repr*/ + 0, /* tp_as_number*/ + 0, /* tp_as_sequence*/ + 0, /* tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call*/ + 0, /* tp_str*/ + 0, /* tp_getattro*/ + 0, /* tp_setattro*/ + 0, /* tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/ + "PyVar object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyVar::Py_init, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)PyVar::Py_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0 /* tp_version_tag */ +}; +#pragma GCC diagnostic pop + +} diff --git a/Thirdparty/Pangolin/include/pangolin/scene/axis.h b/Thirdparty/Pangolin/include/pangolin/scene/axis.h new file mode 100644 index 0000000..a0a3388 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/scene/axis.h @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#ifdef HAVE_EIGEN +# include +#endif + +namespace pangolin { + +struct Axis : public Renderable, public Interactive +{ + Axis() + : axis_length(1.0), + label_x(InteractiveIndex::I().Store(this)), + label_y(InteractiveIndex::I().Store(this)), + label_z(InteractiveIndex::I().Store(this)) + { + } + + void Render(const RenderParams&) override { + glColor4f(1,0,0,1); + glPushName(label_x.Id()); + glDrawLine(0,0,0, axis_length,0,0); + glPopName(); + + glColor4f(0,1,0,1); + glPushName(label_y.Id()); + glDrawLine(0,0,0, 0,axis_length,0); + glPopName(); + + glColor4f(0,0,1,1); + glPushName(label_z.Id()); + glDrawLine(0,0,0, 0,0,axis_length); + glPopName(); + } + + bool Mouse( + int button, + const GLprecision /*win*/[3], const GLprecision /*obj*/[3], const GLprecision /*normal*/[3], + bool /*pressed*/, int button_state, int pickId + ) override + { + PANGOLIN_UNUSED(button); + PANGOLIN_UNUSED(button_state); + PANGOLIN_UNUSED(pickId); + +#ifdef HAVE_EIGEN + if((button == MouseWheelUp || button == MouseWheelDown) ) { + float scale = (button == MouseWheelUp) ? 0.01f : -0.01f; + if(button_state & KeyModifierShift) scale /= 10; + + Eigen::Vector3d rot = Eigen::Vector3d::Zero(); + Eigen::Vector3d xyz = Eigen::Vector3d::Zero(); + + + if(button_state & KeyModifierCtrl) { + // rotate + if(pickId == label_x.Id()) { + rot << 1,0,0; + }else if(pickId == label_y.Id()) { + rot << 0,1,0; + }else if(pickId == label_z.Id()) { + rot << 0,0,1; + }else{ + return false; + } + }else if(button_state & KeyModifierShift){ + // translate + if(pickId == label_x.Id()) { + xyz << 1,0,0; + }else if(pickId == label_y.Id()) { + xyz << 0,1,0; + }else if(pickId == label_z.Id()) { + xyz << 0,0,1; + }else{ + return false; + } + }else{ + return false; + } + + // old from new + Eigen::Matrix T_on = Eigen::Matrix::Identity(); + T_on.block<3,3>(0,0) = Eigen::AngleAxis(scale,rot).toRotationMatrix(); + T_on.block<3,1>(0,3) = scale*xyz; + + // Update + T_pc = (ToEigen(T_pc) * T_on.inverse()).eval(); + + return true; + } +#endif // HAVE_EIGEN + + return false; + } + + virtual bool MouseMotion( + const GLprecision /*win*/[3], const GLprecision /*obj*/[3], const GLprecision /*normal*/[3], + int /*button_state*/, int /*pickId*/ + ) override + { + return false; + } + + float axis_length; + const InteractiveIndex::Token label_x; + const InteractiveIndex::Token label_y; + const InteractiveIndex::Token label_z; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/scene/interactive.h b/Thirdparty/Pangolin/include/pangolin/scene/interactive.h new file mode 100644 index 0000000..6e6ffa2 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/scene/interactive.h @@ -0,0 +1,69 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin { + + +struct Interactive +{ + static __thread GLuint current_id; + + virtual ~Interactive() {} + + virtual bool Mouse( + int button, + const GLprecision win[3], const GLprecision obj[3], const GLprecision normal[3], + bool pressed, int button_state, int pickId + ) = 0; + + virtual bool MouseMotion( + const GLprecision win[3], const GLprecision obj[3], const GLprecision normal[3], + int button_state, int pickId + ) = 0; +}; + +struct RenderParams +{ + RenderParams() + : render_mode(GL_RENDER) + { + } + + GLint render_mode; +}; + +struct Manipulator : public Interactive +{ + virtual void Render(const RenderParams& params) = 0; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/scene/interactive_index.h b/Thirdparty/Pangolin/include/pangolin/scene/interactive_index.h new file mode 100644 index 0000000..af9862f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/scene/interactive_index.h @@ -0,0 +1,115 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include + +namespace pangolin { + +class InteractiveIndex +{ +public: + class Token + { + public: + friend class InteractiveIndex; + + Token() + : id(0) + { + } + + Token(Token&& o) + : id(o.id) + { + o.id = 0; + } + + GLint Id() const + { + return id; + } + + ~Token() + { + if(id) { + InteractiveIndex::I().Unstore(*this); + } + } + + private: + Token(GLint id) + : id(id) + { + } + + + GLint id; + }; + + static InteractiveIndex& I() + { + static InteractiveIndex instance; + return instance; + } + + Interactive* Find(GLuint id) + { + auto kv = index.find(id); + if(kv != index.end()) { + return kv->second; + } + return nullptr; + } + + Token Store(Interactive* r) + { + index[next_id] = r; + return Token(next_id++); + } + + void Unstore(Token& t) + { + index.erase(t.id); + t.id = 0; + } + +private: + // Private constructor. + InteractiveIndex() + : next_id(1) + { + } + + GLint next_id; + std::map index; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/scene/renderable.h b/Thirdparty/Pangolin/include/pangolin/scene/renderable.h new file mode 100644 index 0000000..3e21c72 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/scene/renderable.h @@ -0,0 +1,117 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace pangolin { + +class Renderable +{ +public: + using guid_t = GLuint; + + static guid_t UniqueGuid() + { + static std::random_device rd; + static std::mt19937 gen(rd()); + return (guid_t)gen(); + } + + Renderable(const std::weak_ptr& parent = std::weak_ptr()) + : guid(UniqueGuid()), parent(parent), T_pc(IdentityMatrix()), should_show(true) + { + } + + virtual ~Renderable() + { + } + + // Default implementation simply renders children. + virtual void Render(const RenderParams& params = RenderParams()) { + RenderChildren(params); + } + + void RenderChildren(const RenderParams& params) + { + for(auto& p : children) { + Renderable& r = *p.second; + if(r.should_show) { + glPushMatrix(); + r.T_pc.Multiply(); + r.Render(params); + if(r.manipulator) { + r.manipulator->Render(params); + } + glPopMatrix(); + } + } + } + + std::shared_ptr FindChild(guid_t guid) + { + auto o = children.find(guid); + if(o != children.end()) { + return o->second; + } + + for(auto& kv : children ) { + std::shared_ptr c = kv.second->FindChild(guid); + if(c) return c; + } + + return std::shared_ptr(); + } + + Renderable& Add(const std::shared_ptr& child) + { + if(child) { + children[child->guid] = child; + }; + return *this; + } + + // Renderable properties + const guid_t guid; + std::weak_ptr parent; + pangolin::OpenGlMatrix T_pc; + bool should_show; + + // Children + std::map> children; + + // Manipulator (handler, thing) + std::shared_ptr manipulator; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/scene/scenehandler.h b/Thirdparty/Pangolin/include/pangolin/scene/scenehandler.h new file mode 100644 index 0000000..c23f130 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/scene/scenehandler.h @@ -0,0 +1,182 @@ +#pragma once + +#include +#include +#include + +namespace pangolin { + +inline void gluPickMatrix( + GLdouble x, GLdouble y, + GLdouble width, GLdouble height, + GLint viewport[4] +) { + GLfloat m[16]; + GLfloat sx, sy; + GLfloat tx, ty; + sx = viewport[2] / (GLfloat)width; + sy = viewport[3] / (GLfloat)height; + tx = (viewport[2] + 2.0f * (viewport[0] - (GLfloat)x)) / (GLfloat)width; + ty = (viewport[3] + 2.0f * (viewport[1] - (GLfloat)y)) / (GLfloat)height; +#define M(row, col) m[col*4+row] + M(0, 0) = sx; + M(0, 1) = 0.0f; + M(0, 2) = 0.0f; + M(0, 3) = tx; + M(1, 0) = 0.0f; + M(1, 1) = sy; + M(1, 2) = 0.0f; + M(1, 3) = ty; + M(2, 0) = 0.0f; + M(2, 1) = 0.0f; + M(2, 2) = 1.0f; + M(2, 3) = 0.0f; + M(3, 0) = 0.0f; + M(3, 1) = 0.0f; + M(3, 2) = 0.0f; + M(3, 3) = 1.0f; +#undef M + glMultMatrixf(m); +} + + + +struct SceneHandler : public Handler3D +{ + SceneHandler( + Renderable& scene, + OpenGlRenderState& cam_state + ) : Handler3D(cam_state), scene(scene) + { + + } + + void ProcessHitBuffer(GLint hits, GLuint* buf, std::map& hit_map ) + { + GLuint* closestNames = 0; + GLuint closestNumNames = 0; + GLuint closestZ = std::numeric_limits::max(); + for (int i = 0; i < hits; i++) { + if (buf[1] < closestZ) { + closestNames = buf + 3; + closestNumNames = buf[0]; + closestZ = buf[1]; + } + buf += buf[0] + 3; + } + for (unsigned int i = 0; i < closestNumNames; i++) { + const int pickId = closestNames[i]; + hit_map[pickId] = InteractiveIndex::I().Find(pickId); + } + } + + void ComputeHits(pangolin::View& view, + const pangolin::OpenGlRenderState& cam_state, + int x, int y, int grab_width, + std::map& hit_objects ) + { + // Get views viewport / modelview /projection + GLint viewport[4] = {view.v.l, view.v.b, view.v.w, view.v.h}; + pangolin::OpenGlMatrix mv = cam_state.GetModelViewMatrix(); + pangolin::OpenGlMatrix proj = cam_state.GetProjectionMatrix(); + + // Prepare hit buffer object + const unsigned int MAX_SEL_SIZE = 64; + GLuint vSelectBuf[MAX_SEL_SIZE]; + glSelectBuffer(MAX_SEL_SIZE, vSelectBuf); + + // Load and adjust modelview projection matrices + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPickMatrix(x, y, grab_width, grab_width, viewport); + proj.Multiply(); + glMatrixMode(GL_MODELVIEW); + mv.Load(); + + // Render scenegraph in 'select' mode + glRenderMode(GL_SELECT); + glInitNames(); + RenderParams select; + select.render_mode = GL_SELECT; + scene.Render(select); + glFlush(); + + GLint nHits = glRenderMode(GL_RENDER); + // std::cout << " -- Number of Hits are: " << nHits << std::endl; + // std::cout << " -- size of hitobjects: " << hit_objects.size() << std::endl; + if (nHits > 0) { + ProcessHitBuffer(nHits, vSelectBuf, hit_objects); + } + } + + void Mouse(pangolin::View& view, pangolin::MouseButton button, + int x, int y, bool pressed, int button_state) + { + GetPosNormal(view, x, y, p, Pw, Pc, n); + bool handled = false; + + if (pressed) { + m_selected_objects.clear(); + ComputeHits(view, *cam_state, x, y, 2*hwin+1, m_selected_objects); + } + + for (auto kv : m_selected_objects) + { + Interactive* ir = dynamic_cast(kv.second); + handled |= ir && ir->Mouse( button, p, Pw, n, pressed, button_state, kv.first); + } + + if (!handled) { + Handler3D::Mouse(view, button, x, y, pressed, button_state); + } + } + + void MouseMotion(pangolin::View& view, int x, int y, int button_state) + { + GetPosNormal(view, x, y, p, Pw, Pc, n); + bool handled = false; + for (auto kv : m_selected_objects) + { + Interactive* ir = dynamic_cast(kv.second); + + handled |= ir && ir->MouseMotion( p, Pw, n, button_state, kv.first); + } + if (!handled) { + pangolin::Handler3D::MouseMotion(view, x, y, button_state); + } + } + + void Special(pangolin::View& view, pangolin::InputSpecial inType, + float x, float y, float p1, float p2, float p3, float p4, + int button_state) + { + GetPosNormal(view, (int)x, (int)y, p, Pw, Pc, n); + + bool handled = false; + + if (inType == pangolin::InputSpecialScroll) + { + m_selected_objects.clear(); + ComputeHits(view, *cam_state, (int)x, (int)y, 2*hwin+1, m_selected_objects); + + const MouseButton button = p2 > 0 ? MouseWheelUp : MouseWheelDown; + + for (auto kv : m_selected_objects) + { + Interactive* ir = dynamic_cast(kv.second); + handled |= ir && ir->Mouse( button, p, Pw, n, true, button_state, kv.first); + } + } + + if (!handled) { + pangolin::Handler3D::Special(view, inType, x, y, + p1, p2, p3, p4, button_state); + } + } + + std::map m_selected_objects; + Renderable& scene; + unsigned int grab_width; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/scene/tree.h b/Thirdparty/Pangolin/include/pangolin/scene/tree.h new file mode 100644 index 0000000..9797b86 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/scene/tree.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +namespace pangolin { + +template +struct TreeNode +{ + struct Edge + { + TEdge parent_child; + TreeNode node; + }; + + T item; + std::vector edges; +}; + +template +using NodeFunction = std::function&,const TEdge&)>; + +//template +//void VisitDepthFirst(TreeNode& node, const NodeFunction& func, const TEdge& T_root_node = TEdge()) +//{ +// func(node, T_root_node); +// for(auto& e : node.edges) { +// const TEdge T_root_child = T_root_node * e.parent_child; +// VisitDepthFirst(e.node, func, T_root_child); +// } +//} + +//void Eg() +//{ +// using RenderNode = TreeNode,OpenGlMatrix>; + +// RenderNode root; +// VisitDepthFirst,OpenGlMatrix>( +// root, [](RenderNode& node, const OpenGlMatrix& T_root_node) { +// if(node.item) { +// node.item->DoRender(); +// } +// }, IdentityMatrix()); + +//} + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/tools/video_viewer.h b/Thirdparty/Pangolin/include/pangolin/tools/video_viewer.h new file mode 100644 index 0000000..c72d171 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/tools/video_viewer.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace pangolin +{ + +PANGOLIN_EXPORT +class VideoViewer +{ +public: + typedef std::function >& images, + const picojson::value& properties)> FrameChangedCallbackFn; + + static constexpr int FRAME_SKIP = 30; + + VideoViewer(const std::string& window_name, const std::string& input_uri, const std::string& output_uri = "video.pango" ); + VideoViewer(const VideoViewer&) = delete; + + virtual ~VideoViewer(); + + void Run(); + void RunAsync(); + + void Quit(); + void QuitAndWait(); + + inline int TotalFrames() const + { + return video_playback ? video_playback->GetTotalFrames() : std::numeric_limits::max(); + } + + // Control playback + void OpenInput(const std::string& input_uri); + void CloseInput(); + + // Control recording + void Record(); + void RecordOneFrame(); + void StopRecording(); + + // Useful for user-control + void TogglePlay(); + void ToggleRecord(); + void ToggleDiscardBufferedFrames(); + void ToggleWaitForFrames(); + void SetDiscardBufferedFrames(bool new_state); + void SetWaitForFrames(bool new_state); + void Skip(int frames); + bool ChangeExposure(int delta_us); + bool ChangeGain(float delta); + void SetActiveCamera(int delta); + void DrawEveryNFrames(int n); + + + // Register to be notified of new image data + void SetFrameChangedCallback(FrameChangedCallbackFn cb); + + void WaitUntilExit(); + + + VideoInput& Video() {return video;} + const VideoInput& Video() const {return video;} + + void SetRecordNthFrame(int record_nth_frame_) { + record_nth_frame = record_nth_frame_; + } + + +protected: + void RegisterDefaultKeyShortcutsAndPangoVariables(); + + std::mutex control_mutex; + std::string window_name; + std::thread vv_thread; + + VideoInput video; + VideoPlaybackInterface* video_playback; + VideoInterface* video_interface; + + std::string output_uri; + + int current_frame; + int grab_until; + int record_nth_frame; + int draw_nth_frame; + bool video_grab_wait; + bool video_grab_newest; + bool should_run; + uint16_t active_cam; + + FrameChangedCallbackFn frame_changed_callback; +}; + + +void PANGOLIN_EXPORT RunVideoViewerUI(const std::string& input_uri, const std::string& output_uri); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/argagg.hpp b/Thirdparty/Pangolin/include/pangolin/utils/argagg.hpp new file mode 100644 index 0000000..70e2852 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/argagg.hpp @@ -0,0 +1,1548 @@ +/* + * @file + * @brief + * Defines a very simple command line argument parser. + * + * @copyright + * Copyright (c) 2017 Viet The Nguyen + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * 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 OR COPYRIGHT HOLDERS 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. + */ +#pragma once +#ifndef ARGAGG_ARGAGG_ARGAGG_HPP +#define ARGAGG_ARGAGG_ARGAGG_HPP + +#ifdef __unix__ +#include +#include +#endif // #ifdef __unix__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * @brief + * There are only two hard things in Computer Science: cache invalidation and + * naming things (Phil Karlton). + * + * The names of types have to be succint and clear. This has turned out to be a + * more difficult thing than I expected. Here you'll find a quick overview of + * the type names you'll find in this namespace (and thus "library"). + * + * When a program is invoked it is passed a number of "command line arguments". + * Each of these "arguments" is a string (C-string to be more precise). An + * "option" is a command line argument that has special meaning. This library + * recognizes a command line argument as a potential option if it starts with a + * dash ('-') or double-dash ('--'). + * + * A "parser" is a set of "definitions" (not a literal std::set but rather a + * std::vector). A parser is represented by the argagg::parser struct. + * + * A "definition" is a structure with four components that define what + * "options" are recognized. The four components are the name of the option, + * the strings that represent the option, the option's help text, and how many + * arguments the option should expect. "Flags" are the individual strings that + * represent the option ("-v" and "--verbose" are flags for the "verbose" + * option). A definition is represented by the argagg::definition struct. + * + * Note at this point that the word "option" can be used interchangeably to + * mean the notion of an option and the actual instance of an option given a + * set of command line arguments. To be unambiguous we use a "definition" to + * represent the notion of an option and an "option result" to represent an + * actual option parsed from a set of command line arguments. An "option + * result" is represented by the argagg::option_result struct. + * + * There's one more wrinkle to this: an option can show up multiple times in a + * given set of command line arguments. For example, "-n 1 -n 2 -n 3". This + * will parse into three distinct argagg::option_result instances, but all of + * them correspond to the same argagg::definition. We aggregate these into the + * argagg::option_results struct which represents "all parser results for a + * given option definition". This argagg::option_results is basically a + * std::vector of argagg::option_result. + * + * Options aren't the only thing parsed though. Positional arguments are also + * parsed. Thus a parser produces a result that contains both option results + * and positional arguments. The parser results are represented by the + * argagg::parser_results struct. All option results are stored in a mapping + * from option name to the argagg::option_results. All positional arguments are + * simply stored in a vector of C-strings. + */ +namespace argagg { + + +/** + * @brief + * This exception is thrown when a long option is parsed and is given an + * argument using the "=" syntax but the option doesn't expect an argument. + */ +struct unexpected_argument_error +: public std::runtime_error { + using std::runtime_error::runtime_error; +}; + + +/** + * @brief + * This exception is thrown when an option is parsed unexpectedly such as when + * an argument was expected for a previous option or if an option was found + * that has not been defined. + */ +struct unexpected_option_error +: public std::runtime_error { + using std::runtime_error::runtime_error; +}; + + +/** + * @brief + * This exception is thrown when an option requires an argument but is not + * provided one. This can happen if another flag was found after the option or + * if we simply reach the end of the command line arguments. + */ +struct option_lacks_argument_error +: public std::runtime_error { + using std::runtime_error::runtime_error; +}; + + +/** + * @brief + * This exception is thrown when an option's flag is invalid. This can be the + * case if the flag is not prefixed by one or two hyphens or contains non + * alpha-numeric characters after the hypens. See is_valid_flag_definition() + * for more details. + */ +struct invalid_flag +: public std::runtime_error { + using std::runtime_error::runtime_error; +}; + + +/** + * @brief + * The set of template instantiations that convert C-strings to other types for + * the option_result::as(), option_results::as(), parser_results::as(), and + * parser_results::all_as() methods are placed in this namespace. + */ +namespace convert { + + /** + * @brief + * Explicit instantiations of this function are used to convert arguments to + * types. + */ + template + T arg(const char* arg); + +} + + +/** + * @brief + * Represents a single option parse result. + * + * You can check if this has an argument by using the implicit boolean + * conversion. + */ +struct option_result { + + /** + * @brief + * Argument parsed for this single option. If no argument was parsed this + * will be set to nullptr. + */ + const char* arg; + + /** + * @brief + * Converts the argument parsed for this single option instance into the + * given type using the type matched conversion function + * argagg::convert::arg(). If there was not an argument parsed for this + * single option instance then a argagg::option_lacks_argument_error + * exception is thrown. The specific conversion function may throw other + * exceptions. + */ + template + T as() const; + + /** + * @brief + * Converts the argument parsed for this single option instance into the + * given type using the type matched conversion function + * argagg::convert::arg(). If there was not an argument parsed for this + * single option instance then the provided default value is returned + * instead. If the conversion function throws an exception then it is ignored + * and the default value is returned. + */ + template + T as(const T& t) const; + + /** + * @brief + * Since we have the argagg::option_result::as() API we might as well alias + * it as an implicit conversion operator. This performs implicit conversion + * using the argagg::option_result::as() method. + * + * @note + * An implicit boolean conversion specialization exists which returns false + * if there is no argument for this single option instance and true + * otherwise. This specialization DOES NOT convert the argument to a bool. If + * you need to convert the argument to a bool then use the as() API. + */ + template + operator T () const; + +}; + + +/** + * @brief + * Represents multiple option parse results for a single option. If treated as + * a single parse result it defaults to the last parse result. Note that an + * instance of this struct is always created even if no option results are + * parsed for a given definition. In that case it will simply be empty. + * + * To check if the associated option showed up at all simply use the implicit + * boolean conversion or check if count() is greater than zero. + */ +struct option_results { + + /** + * @brief + * All option parse results for this option. + */ + std::vector all; + + /** + * @brief + * Gets the number of times the option shows up. + */ + std::size_t count() const; + + /** + * @brief + * Gets a single option parse result by index. + */ + option_result& operator [] (std::size_t index); + + /** + * @brief + * Gets a single option result by index. + */ + const option_result& operator [] (std::size_t index) const; + + /** + * @brief + * Converts the argument parsed for the LAST option parse result for the + * parent definition to the provided type. For example, if this was for "-f 1 + * -f 2 -f 3" then calling this method for an integer type will return 3. If + * there are no option parse results then a std::out_of_range exception is + * thrown. Any exceptions thrown by option_result::as() are not + * handled. + */ + template + T as() const; + + /** + * @brief + * Converts the argument parsed for the LAST option parse result for the + * parent definition to the provided type. For example, if this was for "-f 1 + * -f 2 -f 3" then calling this method for an integer type will return 3. If + * there are no option parse results then the provided default value is + * returned instead. + */ + template + T as(const T& t) const; + + /** + * @brief + * Since we have the option_results::as() API we might as well alias + * it as an implicit conversion operator. This performs implicit conversion + * using the option_results::as() method. + * + * @note + * An implicit boolean conversion specialization exists which returns false + * if there is no argument for this single option instance and true + * otherwise. This specialization DOES NOT convert the argument to a bool. If + * you need to convert the argument to a bool then use the as() API. + */ + template + operator T () const; + +}; + + +/** + * @brief + * Represents all results of the parser including options and positional + * arguments. + */ +struct parser_results { + + /** + * @brief + * Returns the name of the program from the original arguments list. This is + * always the first argument. + */ + const char* program; + + /** + * @brief + * Maps from definition name to the structure which contains the parser + * results for that definition. + */ + std::unordered_map options; + + /** + * @brief + * Vector of positional arguments. + */ + std::vector pos; + + /** + * @brief + * Used to check if an option was specified at all. + */ + bool has_option(const std::string& name) const; + + /** + * @brief + * Get the parser results for the given definition. If the definition never + * showed up then the exception from the unordered_map access will bubble + * through so check if the flag exists in the first place with has_option(). + */ + option_results& operator [] (const std::string& name); + + /** + * @brief + * Get the parser results for the given definition. If the definition never + * showed up then the exception from the unordered_map access will bubble + * through so check if the flag exists in the first place with has_option(). + */ + const option_results& operator [] (const std::string& name) const; + + /** + * @brief + * Gets the number of positional arguments. + */ + std::size_t count() const; + + /** + * @brief + * Gets a positional argument by index. + */ + const char* operator [] (std::size_t index) const; + + /** + * @brief + * Gets a positional argument converted to the given type. + */ + template + T as(std::size_t i = 0) const; + + /** + * @brief + * Gets all positional arguments converted to the given type. + */ + template + std::vector all_as() const; + +}; + + +/** + * @brief + * An option definition which essentially represents what an option is. + */ +struct definition { + + /** + * @brief + * Name of the option. Option parser results are keyed by this name. + */ + const std::string name; + + /** + * @brief + * List of strings to match that correspond to this option. Should be fully + * specified with hyphens (e.g. "-v" or "--verbose"). + */ + std::vector flags; + + /** + * @brief + * Help string for this option. + */ + std::string help; + + /** + * @brief + * Number of arguments this option requires. Must be 0 or 1. All other values + * have undefined behavior. Okay, the code actually works with positive + * values in general, but it's unorthodox command line behavior. + */ + unsigned int num_args; + + /** + * @brief + * Returns true if this option does not want any arguments. + */ + bool wants_no_arguments() const; + + /** + * @brief + * Returns true if this option requires arguments. + */ + bool requires_arguments() const; + +}; + + +/** + * @brief + * Checks whether or not a command line argument should be processed as an + * option flag. This is very similar to is_valid_flag_definition() but must + * allow for short flag groups (e.g. "-abc") and equal-assigned long flag + * arguments (e.g. "--output=foo.txt"). + */ +bool cmd_line_arg_is_option_flag( + const char* s); + + +/** + * @brief + * Checks whether a flag in an option definition is valid. I suggest reading + * through the function source to understand what dictates a valid. + */ +bool is_valid_flag_definition( + const char* s); + + +/** + * @brief + * Tests whether or not a valid flag is short. Assumes the provided cstring is + * already a valid flag. + */ +bool flag_is_short( + const char* s); + + +/** + * @brief + * Contains two maps which aid in option parsing. The first map, @ref + * short_map, maps from a short flag (just a character) to a pointer to the + * original @ref definition that the flag represents. The second map, @ref + * long_map, maps from a long flag (an std::string) to a pointer to the + * original @ref definition that the flag represents. + * + * This object is usually a temporary that only exists during the parsing + * operation. It is typically constructed using @ref validate_definitions(). + */ +struct parser_map { + + /** + * @brief + * Maps from a short flag (just a character) to a pointer to the original + * @ref definition that the flag represents. + */ + std::array short_map; + + /** + * @brief + * Maps from a long flag (an std::string) to a pointer to the original @ref + * definition that the flag represents. + */ + std::unordered_map long_map; + + /** + * @brief + * Returns true if the provided short flag exists in the map object. + */ + bool known_short_flag( + const char flag) const; + + /** + * @brief + * If the short flag exists in the map object then it is returned by this + * method. If it doesn't then nullptr will be returned. + */ + const definition* get_definition_for_short_flag( + const char flag) const; + + /** + * @brief + * Returns true if the provided long flag exists in the map object. + */ + bool known_long_flag( + const std::string& flag) const; + + /** + * @brief + * If the long flag exists in the map object then it is returned by this + * method. If it doesn't then nullptr will be returned. + */ + const definition* get_definition_for_long_flag( + const std::string& flag) const; + +}; + + +/** + * @brief + * Validates a collection (specifically an std::vector) of @ref definition + * objects by checking if the contained flags are valid. If the set of @ref + * definition objects is not valid then an exception is thrown. Upon successful + * validation a @ref parser_map object is returned. + */ +parser_map validate_definitions( + const std::vector& definitions); + + +/** + * @brief + * A list of option definitions used to inform how to parse arguments. + */ +struct parser { + + /** + * @brief + * Vector of the option definitions which inform this parser how to parse + * the command line arguments. + */ + std::vector definitions; + + /** + * @brief + * Parses the provided command line arguments and returns the results as + * @ref parser_results. + * + * @note + * This method is not thread-safe and assumes that no modifications are made + * to the definitions member field during the extent of this method call. + */ + parser_results parse(int argc, const char** argv) const; + + /** + * @brief + * Through strict interpretation of pointer casting rules, despite this being + * a safe operation, C++ doesn't allow implicit casts from char** to + * const char** so here's an overload that performs a const_cast, + * which is typically frowned upon but is safe here. + */ + parser_results parse(int argc, char** argv) const; + +}; + + +/** + * @brief + * A convenience output stream that will accumulate what is streamed to it and + * then, on destruction, format the accumulated string using the fmt program + * (via the argagg::fmt_string() function) to the provided std::ostream. + * + * Example use: + * + * @code + * { + * argagg::fmt_ostream f(std::cerr); + * f << "Usage: " << really_long_string << std::endl; + * } // on destruction here the formatted string will be streamed to std::cerr + * @endcode + * + * @note + * This only has formatting behavior if the __unix__ preprocessor + * definition is defined since formatting relies on the POSIX API for forking, + * executing a process, and reading/writing to/from file descriptors. If that + * preprocessor definition is not defined then this class has the same overall + * behavior except the output string is not formatted (basically streams + * whatever the accumulated string is). See arggg::fmt_string(). + */ +struct fmt_ostream : public std::ostringstream { + + /** + * @brief + * Reference to the final output stream that the formatted string will be + * streamed to. + */ + std::ostream& output; + + /** + * @brief + * Construct to output to the provided output stream when this object is + * destroyed. + */ + fmt_ostream(std::ostream& output); + + /** + * @brief + * Special destructor that will format the accumulated string using fmt (via + * the argagg::fmt_string() function) and stream it to the std::ostream + * stored. + */ + ~fmt_ostream(); + +}; + + +/** + * @brief + * Processes the provided string using the fmt util and returns the resulting + * output as a string. Not the most efficient (in time or space) but gets the + * job done. + * + * This function is cowardly so if there are any errors encountered such as a + * syscall returning -1 then the input string is returned. + * + * @note + * This only has formatting behavior if the __unix__ preprocessor + * definition is defined since it relies on the POSIX API for forking, + * executing a process, reading/writing to/from file descriptors, and the + * existence of the fmt util. + */ +std::string fmt_string(const std::string& s); + + +} // namespace argagg + + +/** + * @brief + * Writes the option help to the given stream. + */ +std::ostream& operator << (std::ostream& os, const argagg::parser& x); + + +// ---- end of declarations, header-only implementations follow ---- + + +namespace argagg { + + +template +T option_result::as() const +{ + if (this->arg) { + return convert::arg(this->arg); + } else { + throw option_lacks_argument_error("option has no argument"); + } +} + + +template +T option_result::as(const T& t) const +{ + if (this->arg) { + try { + return convert::arg(this->arg); + } catch (...) { + return t; + } + } else { + // I actually think this will never happen. To call this method you have + // to access a specific option_result for an option. If there's a + // specific option_result then the option was found. If the option + // requires an argument then it will definitely have an argument + // otherwise the parser would have complained. + return t; + } +} + + +template +option_result::operator T () const +{ + return this->as(); +} + + +template <> inline +option_result::operator bool () const +{ + return this->arg != nullptr; +} + + +inline +std::size_t option_results::count() const +{ + return this->all.size(); +} + + +inline +option_result& option_results::operator [] (std::size_t index) +{ + return this->all[index]; +} + + +inline +const option_result& option_results::operator [] (std::size_t index) const +{ + return this->all[index]; +} + + +template +T option_results::as() const +{ + if (this->all.size() == 0) { + throw std::out_of_range("no option arguments to convert"); + } + return this->all.back().as(); +} + + +template +T option_results::as(const T& t) const +{ + if (this->all.size() == 0) { + return t; + } + return this->all.back().as(t); +} + + +template +option_results::operator T () const +{ + return this->as(); +} + + +template <> inline +option_results::operator bool () const +{ + return this->all.size() > 0; +} + + +inline +bool parser_results::has_option(const std::string& name) const +{ + const auto it = this->options.find(name); + return ( it != this->options.end()) && it->second.all.size() > 0; +} + + +inline +option_results& parser_results::operator [] (const std::string& name) +{ + return this->options.at(name); +} + + +inline +const option_results& +parser_results::operator [] (const std::string& name) const +{ + return this->options.at(name); +} + + +inline +std::size_t parser_results::count() const +{ + return this->pos.size(); +} + + +inline +const char* parser_results::operator [] (std::size_t index) const +{ + return this->pos[index]; +} + + +template +T parser_results::as(std::size_t i) const +{ + return convert::arg(this->pos[i]); +} + + +template +std::vector parser_results::all_as() const +{ + std::vector v(this->pos.size()); + std::transform( + this->pos.begin(), this->pos.end(), v.begin(), + [](const char* arg) { + return convert::arg(arg); + }); + return v; +} + + +inline +bool definition::wants_no_arguments() const +{ + return this->num_args == 0; +} + + +inline +bool definition::requires_arguments() const +{ + return this->num_args > 0; +} + + +inline +bool cmd_line_arg_is_option_flag( + const char* s) +{ + auto len = std::strlen(s); + + // The shortest possible flag has two characters: a hyphen and an + // alpha-numeric character. + if (len < 2) { + return false; + } + + // All flags must start with a hyphen. + if (s[0] != '-') { + return false; + } + + // Shift the name forward by a character to account for the initial hyphen. + // This means if s was originally "-v" then name will be "v". + const char* name = s + 1; + + // Check if we're dealing with a long flag. + bool is_long = false; + if (s[1] == '-') { + is_long = true; + + // Just -- is not a valid flag. + if (len == 2) { + return false; + } + + // Shift the name forward to account for the extra hyphen. This means if s + // was originally "--output" then name will be "output". + name = s + 2; + } + + // The first character of the flag name must be alpha-numeric. This is to + // prevent things like "---a" from being valid flags. + len = std::strlen(name); + if (!std::isalnum(name[0])) { + return false; + } + + // At this point in is_valid_flag_definition() we would check if the short + // flag has only one character. At command line specification you can group + // short flags together or even add an argument to a short flag without a + // space delimiter. Thus we don't check if this has only one character + // because it might not. + + // If this is a long flag then we expect all characters *up to* an equal sign + // to be alpha-numeric or a hyphen. After the equal sign you are specify the + // argument to a long flag which can be basically anything. + if (is_long) { + bool encountered_equal = false; + return std::all_of(name, name + len, [&](const char& c) { + if (encountered_equal) { + return true; + } else { + if (c == '=') { + encountered_equal = true; + return true; + } + return std::isalnum(c) || c == '-'; + } + }); + } + + // At this point we are not dealing with a long flag. We already checked that + // the first character is alpha-numeric so we've got the case of a single + // short flag covered. This might be a short flag group though and we might + // be tempted to check that each character of the short flag group is + // alpha-numeric. However, you can specify the argument for a short flag + // without a space delimiter (e.g. "-I/usr/local/include") so you can't tell + // if the rest of a short flag group is part of the argument or not unless + // you know what is a defined flag or not. We leave that kind of processing + // to the parser. + return true; +} + + +inline +bool is_valid_flag_definition( + const char* s) +{ + auto len = std::strlen(s); + + // The shortest possible flag has two characters: a hyphen and an + // alpha-numeric character. + if (len < 2) { + return false; + } + + // All flags must start with a hyphen. + if (s[0] != '-') { + return false; + } + + // Shift the name forward by a character to account for the initial hyphen. + // This means if s was originally "-v" then name will be "v". + const char* name = s + 1; + + // Check if we're dealing with a long flag. + bool is_long = false; + if (s[1] == '-') { + is_long = true; + + // Just -- is not a valid flag. + if (len == 2) { + return false; + } + + // Shift the name forward to account for the extra hyphen. This means if s + // was originally "--output" then name will be "output". + name = s + 2; + } + + // The first character of the flag name must be alpha-numeric. This is to + // prevent things like "---a" from being valid flags. + len = std::strlen(name); + if (!std::isalnum(name[0])) { + return false; + } + + // If this is a short flag then it must only have one character. + if (!is_long && len > 1) { + return false; + } + + // The rest of the characters must be alpha-numeric, but long flags are + // allowed to have hyphens too. + return std::all_of(name + 1, name + len, [&](const char& c) { + return std::isalnum(c) || (c == '-' && is_long); + }); +} + + +inline +bool flag_is_short( + const char* s) +{ + return s[0] == '-' && std::isalnum(s[1]); +} + + +inline +bool parser_map::known_short_flag( + const char flag) const +{ + return this->short_map[flag] != nullptr; +} + + +inline +const definition* parser_map::get_definition_for_short_flag( + const char flag) const +{ + return this->short_map[flag]; +} + + +inline +bool parser_map::known_long_flag( + const std::string& flag) const +{ + const auto existing_long_flag = this->long_map.find(flag); + return existing_long_flag != long_map.end(); +} + + +inline +const definition* parser_map::get_definition_for_long_flag( + const std::string& flag) const +{ + const auto existing_long_flag = this->long_map.find(flag); + if (existing_long_flag == long_map.end()) { + return nullptr; + } + return existing_long_flag->second; +} + + +inline +parser_map validate_definitions( + const std::vector& definitions) +{ + std::unordered_map long_map; + parser_map map {{{nullptr}}, std::move(long_map)}; + + for (auto& defn : definitions) { + + if (defn.flags.size() == 0) { + std::ostringstream msg; + msg << "option \"" << defn.name << "\" has no flag definitions"; + throw invalid_flag(msg.str()); + } + + for (auto& flag : defn.flags) { + + if (!is_valid_flag_definition(flag.data())) { + std::ostringstream msg; + msg << "flag \"" << flag << "\" specified for option \"" << defn.name + << "\" is invalid"; + throw invalid_flag(msg.str()); + } + + if (flag_is_short(flag.data())) { + const int short_flag_letter = flag[1]; + const auto existing_short_flag = map.short_map[short_flag_letter]; + bool short_flag_already_exists = (existing_short_flag != nullptr); + if (short_flag_already_exists) { + std::ostringstream msg; + msg << "duplicate short flag \"" << flag + << "\" found, specified by both option \"" << defn.name + << "\" and option \"" << existing_short_flag->name; + throw invalid_flag(msg.str()); + } + map.short_map[short_flag_letter] = &defn; + continue; + } + + // If we're here then this is a valid, long-style flag. + if (map.known_long_flag(flag)) { + const auto existing_long_flag = map.get_definition_for_long_flag(flag); + std::ostringstream msg; + msg << "duplicate long flag \"" << flag + << "\" found, specified by both option \"" << defn.name + << "\" and option \"" << existing_long_flag->name; + throw invalid_flag(msg.str()); + } + map.long_map.insert(std::make_pair(flag, &defn)); + } + } + + return map; +} + + +inline +parser_results parser::parse(int argc, const char** argv) const +{ + // Inspect each definition to see if its valid. You may wonder "why don't + // you do this validation on construction?" I had thought about it but + // realized that since I've made the parser an aggregate type (granted it + // just "aggregates" a single vector) I would need to track any changes to + // the definitions vector and re-run the validity check in order to + // maintain this expected "validity invariant" on the object. That would + // then require hiding the definitions vector as a private entry and then + // turning the parser into a thin interface (by re-exposing setters and + // getters) to the vector methods just so that I can catch when the + // definition has been modified. It seems much simpler to just enforce the + // validity when you actually want to parser because it's at the moment of + // parsing that you know the definitions are complete. + parser_map map = validate_definitions(this->definitions); + + // Initialize the parser results that we'll be returning. Store the program + // name (assumed to be the first command line argument) and initialize + // everything else as empty. + std::unordered_map options {}; + std::vector pos; + parser_results results {argv[0], std::move(options), std::move(pos)}; + + // Add an empty option result for each definition. + for (const auto& defn : this->definitions) { + option_results opt_results {{}}; + results.options.insert( + std::make_pair(defn.name, opt_results)); + } + + // Don't start off ignoring flags. We only ignore flags after a -- shows up + // in the command line arguments. + bool ignore_flags = false; + + // Keep track of any options that are expecting arguments. + const char* last_flag_expecting_args = nullptr; + option_result* last_option_expecting_args = nullptr; + unsigned int num_option_args_to_consume = 0; + + // Get pointers to pointers so we can treat the raw pointer array as an + // iterator for standard library algorithms. This isn't used yet but can be + // used to template this function to work on iterators over strings or + // C-strings. + const char** arg_i = argv + 1; + const char** arg_end = argv + argc; + + while (arg_i != arg_end) { + auto arg_i_cstr = *arg_i; + auto arg_i_len = std::strlen(arg_i_cstr); + + // Some behavior to note: if the previous option is expecting an argument + // then the next entry will be treated as a positional argument even if + // it looks like a flag. + bool treat_as_positional_argument = ( + ignore_flags + || num_option_args_to_consume > 0 + || !cmd_line_arg_is_option_flag(arg_i_cstr) + ); + if (treat_as_positional_argument) { + + // If last option is expecting some specific positive number of + // arguments then give this argument to that option, *regardless of + // whether or not the argument looks like a flag or is the special "--" + // argument*. + if (num_option_args_to_consume > 0) { + last_option_expecting_args->arg = arg_i_cstr; + --num_option_args_to_consume; + ++arg_i; + continue; + } + + // Now we check if this is just "--" which is a special argument that + // causes all following arguments to be treated as non-options and is + // itselve discarded. + if (std::strncmp(arg_i_cstr, "--", 2) == 0 && arg_i_len == 2) { + ignore_flags = true; + ++arg_i; + continue; + } + + // If there are no expectations for option arguments then simply use + // this argument as a positional argument. + results.pos.push_back(arg_i_cstr); + ++arg_i; + continue; + } + + // Reset the "expecting argument" state. + last_flag_expecting_args = nullptr; + last_option_expecting_args = nullptr; + num_option_args_to_consume = 0; + + // If we're at this point then we're definitely dealing with something + // that is flag-like and has hyphen as the first character and has a + // length of at least two characters. How we handle this potential flag + // depends on whether or not it is a long-option so we check that first. + bool is_long_flag = (arg_i_cstr[1] == '-'); + + if (is_long_flag) { + + // Long flags have a complication: their arguments can be specified + // using an '=' character right inside the argument. That means an + // argument like "--output=foobar.txt" is actually an option with flag + // "--output" and argument "foobar.txt". So we look for the first + // instance of the '=' character and keep it in long_flag_arg. If + // long_flag_arg is nullptr then we didn't find '='. We need the + // flag_len to construct long_flag_str below. + auto long_flag_arg = std::strchr(arg_i_cstr, '='); + std::size_t flag_len = arg_i_len; + if (long_flag_arg != nullptr) { + flag_len = long_flag_arg - arg_i_cstr; + } + std::string long_flag_str(arg_i_cstr, flag_len); + + if (!map.known_long_flag(long_flag_str)) { + std::ostringstream msg; + msg << "found unexpected flag: " << long_flag_str; + throw unexpected_option_error(msg.str()); + } + + const auto defn = map.get_definition_for_long_flag(long_flag_str); + + if (long_flag_arg != nullptr && defn->num_args == 0) { + std::ostringstream msg; + msg << "found argument for option not expecting an argument: " + << arg_i_cstr; + throw unexpected_argument_error(msg.str()); + } + + // We've got a legitimate, known long flag option so we add an option + // result. This option result initially has an arg of nullptr, but that + // might change in the following block. + auto& opt_results = results.options[defn->name]; + option_result opt_result {nullptr}; + opt_results.all.push_back(std::move(opt_result)); + + if (defn->requires_arguments()) { + bool there_is_an_equal_delimited_arg = (long_flag_arg != nullptr); + if (there_is_an_equal_delimited_arg) { + // long_flag_arg would be "=foo" in the "--output=foo" case so we + // increment by 1 to get rid of the equal sign. + opt_results.all.back().arg = long_flag_arg + 1; + } else { + last_flag_expecting_args = arg_i_cstr; + last_option_expecting_args = &(opt_results.all.back()); + num_option_args_to_consume = defn->num_args; + } + } + + ++arg_i; + continue; + } + + // If we've made it here then we're looking at either a short flag or a + // group of short flags. Short flags can be grouped together so long as + // they don't require any arguments unless the option that does is the + // last in the group ("-o x -v" is okay, "-vo x" is okay, "-ov x" is + // not). So starting after the dash we're going to process each character + // as if it were a separate flag. Note "sf_idx" stands for "short flag + // index". + for (std::size_t sf_idx = 1; sf_idx < arg_i_len; ++sf_idx) { + const auto short_flag = arg_i_cstr[sf_idx]; + + if (!std::isalnum(short_flag)) { + std::ostringstream msg; + msg << "found non-alphanumeric character '" << arg_i_cstr[sf_idx] + << "' in flag group '" << arg_i_cstr << "'"; + throw std::domain_error(msg.str()); + } + + if (!map.known_short_flag(short_flag)) { + std::ostringstream msg; + msg << "found unexpected flag '" << arg_i_cstr[sf_idx] + << "' in flag group '" << arg_i_cstr << "'"; + throw unexpected_option_error(msg.str()); + } + + auto defn = map.get_definition_for_short_flag(short_flag); + auto& opt_results = results.options[defn->name]; + + // Create an option result with an empty argument (for now) and add it + // to this option's results. + option_result opt_result {nullptr}; + opt_results.all.push_back(std::move(opt_result)); + + if (defn->requires_arguments()) { + + // If this short flag's option requires an argument and we're the + // last flag in the short flag group then just put the parser into + // "expecting argument for last option" state and move onto the next + // command line argument. + bool is_last_short_flag_in_group = (sf_idx == arg_i_len - 1); + if (is_last_short_flag_in_group) { + last_flag_expecting_args = arg_i_cstr; + last_option_expecting_args = &(opt_results.all.back()); + num_option_args_to_consume = defn->num_args; + break; + } + + // If this short flag's option requires an argument and we're NOT the + // last flag in the short flag group then we automatically consume + // the rest of the short flag group as the argument for this flag. + // This is how we get the POSIX behavior of being able to specify a + // flag's arguments without a white space delimiter (e.g. + // "-I/usr/local/include"). + opt_results.all.back().arg = arg_i_cstr + sf_idx + 1; + break; + } + } + + ++arg_i; + continue; + } + + // If we're done with all of the arguments but are still expecting + // arguments for a previous option then we haven't satisfied that option. + // This is an error. + if (num_option_args_to_consume > 0) { + std::ostringstream msg; + msg << "last option \"" << last_flag_expecting_args + << "\" expects an argument but the parser ran out of command line " + << "arguments to parse"; + throw option_lacks_argument_error(msg.str()); + } + + return results; +} + + +inline +parser_results parser::parse(int argc, char** argv) const +{ + return parse(argc, const_cast(argv)); +} + + +namespace convert { + + + /** + * @brief + * Templated function for conversion to T using the @ref std::strtol() + * function. This is used for anything long length or shorter (long, int, + * short, char). + */ + template inline + T long_(const char* arg) + { + char* endptr = nullptr; + errno = 0; + T ret = static_cast(std::strtol(arg, &endptr, 0)); + if (endptr == arg) { + std::ostringstream msg; + msg << "unable to convert argument to integer: \"" << arg << "\""; + throw std::invalid_argument(msg.str()); + } + if (errno == ERANGE) { + throw std::out_of_range("argument numeric value out of range"); + } + return ret; + } + + + /** + * @brief + * Templated function for conversion to T using the @ref std::strtoll() + * function. This is used for anything long long length or shorter (long + * long). + */ + template inline + T long_long_(const char* arg) + { + char* endptr = nullptr; + errno = 0; + T ret = static_cast(std::strtoll(arg, &endptr, 0)); + if (endptr == arg) { + std::ostringstream msg; + msg << "unable to convert argument to integer: \"" << arg << "\""; + throw std::invalid_argument(msg.str()); + } + if (errno == ERANGE) { + throw std::out_of_range("argument numeric value out of range"); + } + return ret; + } + + +#define DEFINE_CONVERSION_FROM_LONG_(TYPE) \ + template <> inline \ + TYPE arg(const char* arg) \ + { \ + return long_(arg); \ + } + + DEFINE_CONVERSION_FROM_LONG_(char) + DEFINE_CONVERSION_FROM_LONG_(unsigned char) + DEFINE_CONVERSION_FROM_LONG_(signed char) + DEFINE_CONVERSION_FROM_LONG_(short) + DEFINE_CONVERSION_FROM_LONG_(unsigned short) + DEFINE_CONVERSION_FROM_LONG_(int) + DEFINE_CONVERSION_FROM_LONG_(unsigned int) + DEFINE_CONVERSION_FROM_LONG_(long) + DEFINE_CONVERSION_FROM_LONG_(unsigned long) + +#undef DEFINE_CONVERSION_FROM_LONG_ + + +#define DEFINE_CONVERSION_FROM_LONG_LONG_(TYPE) \ + template <> inline \ + TYPE arg(const char* arg) \ + { \ + return long_long_(arg); \ + } + + DEFINE_CONVERSION_FROM_LONG_LONG_(long long) + DEFINE_CONVERSION_FROM_LONG_LONG_(unsigned long long) + +#undef DEFINE_CONVERSION_FROM_LONG_LONG_ + + + template <> inline + bool arg(const char* arg) + { + return argagg::convert::arg(arg) != 0; + } + + + template <> inline + float arg(const char* arg) + { + char* endptr = nullptr; + errno = 0; + float ret = std::strtof(arg, &endptr); + if (endptr == arg) { + std::ostringstream msg; + msg << "unable to convert argument to integer: \"" << arg << "\""; + throw std::invalid_argument(msg.str()); + } + if (errno == ERANGE) { + throw std::out_of_range("argument numeric value out of range"); + } + return ret; + } + + + template <> inline + double arg(const char* arg) + { + char* endptr = nullptr; + errno = 0; + double ret = std::strtod(arg, &endptr); + if (endptr == arg) { + std::ostringstream msg; + msg << "unable to convert argument to integer: \"" << arg << "\""; + throw std::invalid_argument(msg.str()); + } + if (errno == ERANGE) { + throw std::out_of_range("argument numeric value out of range"); + } + return ret; + } + + + template <> inline + const char* arg(const char* arg) + { + return arg; + } + + + template <> inline + std::string arg(const char* arg) + { + return std::string(arg); + } + +} + + +inline +fmt_ostream::fmt_ostream(std::ostream& output) +: std::ostringstream(), output(output) +{ +} + + +inline +fmt_ostream::~fmt_ostream() +{ + output << fmt_string(this->str()); +} + + +#ifdef __unix__ + + +inline +std::string fmt_string(const std::string& s) +{ + constexpr int read_end = 0; + constexpr int write_end = 1; + + // TODO (vnguyen): This function overall needs to handle possible error + // returns from the various syscalls. + + int read_pipe[2]; + int write_pipe[2]; + if (pipe(read_pipe) == -1) { + return s; + } + if (pipe(write_pipe) == -1) { + return s; + } + + auto parent_pid = fork(); + bool is_fmt_proc = (parent_pid == 0); + if (is_fmt_proc) { + dup2(write_pipe[read_end], STDIN_FILENO); + dup2(read_pipe[write_end], STDOUT_FILENO); + close(write_pipe[read_end]); + close(write_pipe[write_end]); + close(read_pipe[read_end]); + close(read_pipe[write_end]); + const char* argv[] = {"fmt", NULL}; + execvp(const_cast(argv[0]), const_cast(argv)); + } + + close(write_pipe[read_end]); + close(read_pipe[write_end]); + auto fmt_write_fd = write_pipe[write_end]; + auto write_result = write(fmt_write_fd, s.c_str(), s.length()); + if (write_result != static_cast(s.length())) { + return s; + } + close(fmt_write_fd); + + auto fmt_read_fd = read_pipe[read_end]; + std::ostringstream os; + char buf[64]; + while (true) { + auto read_count = read( + fmt_read_fd, reinterpret_cast(buf), sizeof(buf)); + if (read_count <= 0) { + break; + } + os.write(buf, static_cast(read_count)); + } + close(fmt_read_fd); + + return os.str(); +} + + +#else // #ifdef __unix__ + + +inline +std::string fmt_string(const std::string& s) +{ + return s; +} + + +#endif // #ifdef __unix__ + + +} // namespace argagg + + +inline +std::ostream& operator << (std::ostream& os, const argagg::parser& x) +{ + for (auto& definition : x.definitions) { + os << " "; + for (auto& flag : definition.flags) { + os << flag; + if (flag != definition.flags.back()) { + os << ", "; + } + } + os << std::endl; + os << " " << definition.help << std::endl; + } + return os; +} + + +#endif // ARGAGG_ARGAGG_ARGAGG_HPP diff --git a/Thirdparty/Pangolin/include/pangolin/utils/assert.h b/Thirdparty/Pangolin/include/pangolin/utils/assert.h new file mode 100644 index 0000000..f0e7097 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/assert.h @@ -0,0 +1,60 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Hauke Strasdat, Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#ifdef __GNUC__ +# define PANGO_FUNCTION __PRETTY_FUNCTION__ +#elif (_MSC_VER >= 1310) +# define PANGO_FUNCTION __FUNCTION__ +#else +# define PANGO_FUNCTION "unknown" +#endif + +namespace pangolin { + +template PANGO_HOST_DEVICE +void abort(const char* function, const char* file, int line, Args&&... args) +{ + std::printf("pangolin::abort() in function '%s', file '%s', line %d.\n", function, file, line); +#ifndef __CUDACC__ + std::cout << FormatString(std::forward(args)...) << std::endl; + std::abort(); +#endif +} + +} + +// Always check, even in debug +#define PANGO_ENSURE(expr, ...) ((expr) ? ((void)0) : pangolin::abort(PANGO_FUNCTION, __FILE__, __LINE__, ##__VA_ARGS__)) + +// May be disabled for optimisation +#define PANGO_ASSERT(expr, ...) ((expr) ? ((void)0) : pangolin::abort(PANGO_FUNCTION, __FILE__, __LINE__, ##__VA_ARGS__)) diff --git a/Thirdparty/Pangolin/include/pangolin/utils/compontent_cast.h b/Thirdparty/Pangolin/include/pangolin/utils/compontent_cast.h new file mode 100644 index 0000000..9482f23 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/compontent_cast.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#ifdef HAVE_EIGEN +# include +#endif + +namespace pangolin +{ + +// Scalar / Vector agnostic static_cast-like thing +// +// e.g. Promote float to double: +// ComponentCast::cast(0.14f); +// +// e.g. Promote Eigen::Vector2f to Eigen::Vector2d: +// ComponentCast::cast(Eigen::Vector2f(0.1,0.2); + +template +struct ComponentCast +{ + PANGO_HOST_DEVICE + static To cast(const From& val) + { + return static_cast(val); + } +}; + +#ifdef HAVE_EIGEN +template +struct ComponentCast > +{ + PANGO_HOST_DEVICE + static To cast(const Eigen::MatrixBase& val) + { + return val.template cast(); + } +}; +#endif + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/file_extension.h b/Thirdparty/Pangolin/include/pangolin/utils/file_extension.h new file mode 100644 index 0000000..2912fac --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/file_extension.h @@ -0,0 +1,74 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +enum ImageFileType +{ + ImageFileTypePpm, + ImageFileTypeTga, + ImageFileTypePng, + ImageFileTypeJpg, + ImageFileTypeTiff, + ImageFileTypeGif, + ImageFileTypeExr, + ImageFileTypePango, + ImageFileTypePvn, + ImageFileTypeZstd, + ImageFileTypeLz4, + ImageFileTypeP12b, + ImageFileTypePly, + ImageFileTypeObj, + ImageFileTypeUnknown +}; + + +PANGOLIN_EXPORT +std::string ImageFileTypeToName(ImageFileType); + +PANGOLIN_EXPORT +ImageFileType NameToImageFileType(const std::string&); + +PANGOLIN_EXPORT +std::string FileLowercaseExtention(const std::string& filename); + +PANGOLIN_EXPORT +ImageFileType FileTypeMagic(const unsigned char data[], size_t bytes); + +PANGOLIN_EXPORT +ImageFileType FileTypeExtension(const std::string& ext); + +PANGOLIN_EXPORT +ImageFileType FileType(const std::string& filename); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/file_utils.h b/Thirdparty/Pangolin/include/pangolin/utils/file_utils.h new file mode 100644 index 0000000..16905ab --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/file_utils.h @@ -0,0 +1,151 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace pangolin +{ + +PANGOLIN_EXPORT +std::vector& Split(const std::string& s, char delim, std::vector& elements); + +PANGOLIN_EXPORT +std::vector Split(const std::string &s, char delim); + +PANGOLIN_EXPORT +std::vector Expand(const std::string &s, char open='[', char close=']', char delim=','); + +PANGOLIN_EXPORT +std::string SanitizePath(const std::string& path); + +PANGOLIN_EXPORT +std::string PathParent(const std::string& path, int levels = 1); + +PANGOLIN_EXPORT +bool FileExists(const std::string& filename); + +PANGOLIN_EXPORT +std::string FindPath(const std::string& child_path, const std::string& signature_path); + +PANGOLIN_EXPORT +std::string PathExpand(const std::string& sPath); + +PANGOLIN_EXPORT +bool MatchesWildcard(const std::string& str, const std::string& wildcard); + +// Fill 'file_vec' with the files that match the glob-like 'wildcard_file_path' +// ? can be used to match any single charector +// * can be used to match any sequence of charectors in a directory +// ** can be used to match any directories across any number of levels +// e.g. FilesMatchingWildcard("~/*/code/*.h", vec); +// e.g. FilesMatchingWildcard("~/**/*.png", vec); +PANGOLIN_EXPORT +bool FilesMatchingWildcard(const std::string& wildcard_file_path, std::vector& file_vec); + +PANGOLIN_EXPORT +std::string MakeUniqueFilename(const std::string& filename); + +PANGOLIN_EXPORT +bool IsPipe(const std::string& file); + +PANGOLIN_EXPORT +bool IsPipe(int fd); + +PANGOLIN_EXPORT +int WritablePipeFileDescriptor(const std::string& file); + +/** + * Open the file for reading. Note that it is opened with O_NONBLOCK. The pipe + * open is done in two stages so that the producer knows a reader is waiting + * (but not blocked). The reader then checks PipeHasDataToRead() until it + * returns true. The file can then be opened. Note that the file descriptor + * should be closed after the read stream has been created so that the write + * side of the pipe does not get signaled. + */ +PANGOLIN_EXPORT +int ReadablePipeFileDescriptor(const std::string& file); + +PANGOLIN_EXPORT +bool PipeHasDataToRead(int fd); + +PANGOLIN_EXPORT +void FlushPipe(const std::string& file); + +// TODO: Tidy these inlines up / move them + +inline bool StartsWith(const std::string& str, const std::string& prefix) +{ + return !str.compare(0, prefix.size(), prefix); +} + +inline bool EndsWith(const std::string& str, const std::string& prefix) +{ + return !str.compare(str.size() - prefix.size(), prefix.size(), prefix); +} + +inline std::string Trim(const std::string& str, const std::string& delimiters = " \f\n\r\t\v" ) +{ + const size_t f = str.find_first_not_of( delimiters ); + return f == std::string::npos ? + "" : + str.substr( f, str.find_last_not_of( delimiters ) + 1 ); +} + +inline void ToUpper( std::string& str ) +{ + std::transform(str.begin(), str.end(), str.begin(), ::toupper); +} + +inline void ToLower( std::string& str ) +{ + std::transform(str.begin(), str.end(), str.begin(), ::tolower); +} + +inline std::string ToUpperCopy( const std::string& str ) +{ + std::string out; + out.resize(str.size()); + std::transform(str.begin(), str.end(), out.begin(), ::toupper); + return out; +} + +inline std::string ToLowerCopy( const std::string& str ) +{ + std::string out; + out.resize(str.size()); + std::transform(str.begin(), str.end(), out.begin(), ::tolower); + return out; +} + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/fix_size_buffer_queue.h b/Thirdparty/Pangolin/include/pangolin/utils/fix_size_buffer_queue.h new file mode 100644 index 0000000..ce4d932 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/fix_size_buffer_queue.h @@ -0,0 +1,153 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace pangolin +{ + +template +class FixSizeBuffersQueue +{ + +public: + FixSizeBuffersQueue() {} + + ~FixSizeBuffersQueue() { + } + + BufPType getNewest() { + std::lock_guard vlock(vMtx); + std::lock_guard elock(eMtx); + if(validBuffers.size() == 0) { + // Empty queue. + return 0; + } else { + // Requeue all but newest buffers. + while(validBuffers.size() > 1) { + emptyBuffers.push_back(std::move(validBuffers.front())); + validBuffers.pop_front(); + } + // Return newest buffer. + BufPType bp = std::move(validBuffers.front()); + validBuffers.pop_front(); + return bp; + } + } + + BufPType getNext() { + std::lock_guard vlock(vMtx); + if(validBuffers.size() == 0) { + // Empty queue. + return 0; + } else { + // Return oldest buffer. + BufPType bp = std::move(validBuffers.front()); + validBuffers.pop_front(); + return bp; + } + } + + BufPType getFreeBuffer() { + std::lock_guard vlock(vMtx); + std::lock_guard elock(eMtx); + if(emptyBuffers.size() > 0) { + // Simply get a free buffer from the free buffers list. + BufPType bp = std::move(emptyBuffers.front()); + emptyBuffers.pop_front(); + return bp; + } else { + if(validBuffers.size() == 0) { + // Queue not yet initialized. + throw std::runtime_error("Queue not yet initialised."); + } else { + std::cerr << "Out of free buffers." << std::endl; + // No free buffers return oldest among the valid buffers. + BufPType bp = std::move(validBuffers.front()); + validBuffers.pop_front(); + return bp; + } + } + } + + void addValidBuffer(BufPType bp) { + // Add buffer to valid buffers queue. + std::lock_guard vlock(vMtx); + validBuffers.push_back(std::move(bp)); + } + + void returnOrAddUsedBuffer(BufPType bp) { + // Add buffer back to empty buffers queue. + std::lock_guard elock(eMtx); + emptyBuffers.push_back(std::move(bp)); + } + + size_t AvailableFrames() const { + std::lock_guard vlock(vMtx); + return validBuffers.size(); + } + + size_t EmptyBuffers() const { + std::lock_guard elock(eMtx); + return emptyBuffers.size(); + } + + bool DropNFrames(size_t n) { + std::lock_guard vlock(vMtx); + if(validBuffers.size() < n) { + return false; + } else { + std::lock_guard elock(eMtx); + // Requeue all but newest buffers. + for(unsigned int i=0; i validBuffers; + std::list emptyBuffers; + mutable std::mutex vMtx; + mutable std::mutex eMtx; +// unsigned int maxNumBuffers; +// unsigned int bufferSizeBytes; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/format_string.h b/Thirdparty/Pangolin/include/pangolin/utils/format_string.h new file mode 100644 index 0000000..7b39f9a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/format_string.h @@ -0,0 +1,87 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Hauke Strasdat, Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin { +namespace details { + +// Following: http://stackoverflow.com/a/22759544 +template +class IsStreamable { +private: + template + static auto test(int) -> decltype( (std::declval() << std::declval(), std::true_type()) ); + + template + static auto test(...) -> std::false_type; + +public: + static const bool value = decltype(test(0))::value; +}; + +inline void FormatStream(std::stringstream& stream, const char* text) +{ + stream << text; +} + +// Following: http://en.cppreference.com/w/cpp/language/parameter_pack +template +void FormatStream(std::stringstream& stream, const char* text, T arg, Args... args) +{ + static_assert(IsStreamable::value, + "One of the args has not an ostream overload!"); + for (; *text != '\0'; ++text) { + if (*text == '%') { + stream << arg; + FormatStream(stream, text + 1, args...); + return; + } + stream << *text; + } + stream << "\nFormat-Warning: There are " << sizeof...(Args) + 1 + << " args unused."; +} + +} // namespace details + +template +std::string FormatString(const char* text, Args... args) +{ + std::stringstream stream; + details::FormatStream(stream, text, args...); + return stream.str(); +} + +inline std::string FormatString() +{ + return std::string(); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/log.h b/Thirdparty/Pangolin/include/pangolin/utils/log.h new file mode 100644 index 0000000..e9e3536 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/log.h @@ -0,0 +1,44 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +// TODO: Something a bit more useful here, probably using format_string.h + +#pragma once + +#ifndef _ANDROID_ +# include +# define pango_print_debug(...) printf(__VA_ARGS__) +# define pango_print_info(...) printf(__VA_ARGS__) +# define pango_print_error(...) fprintf(stderr, __VA_ARGS__) +# define pango_print_warn(...) fprintf(stderr, __VA_ARGS__) +#else +# include +# define pango_print_debug(...) __android_log_print(ANDROID_LOG_DEBUG, "pango", __VA_ARGS__ ); +# define pango_print_info(...) __android_log_print(ANDROID_LOG_INFO, "pango", __VA_ARGS__ ); +# define pango_print_error(...) __android_log_print(ANDROID_LOG_ERROR, "pango", __VA_ARGS__ ); +# define pango_print_warn(...) __android_log_print(ANDROID_LOG_ERROR, "pango", __VA_ARGS__ ); +#endif diff --git a/Thirdparty/Pangolin/include/pangolin/utils/memstreambuf.h b/Thirdparty/Pangolin/include/pangolin/utils/memstreambuf.h new file mode 100644 index 0000000..7cdafb4 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/memstreambuf.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +namespace pangolin { + +// A simple streambuf wrapper around std::vector for memory buffer use +struct memstreambuf : public std::streambuf +{ +public: + memstreambuf(size_t initial_buffer_size) + { + buffer.reserve(initial_buffer_size); + } + + // Avoiding use of std::streambuf's move constructor, since it is missing for old GCC + memstreambuf(memstreambuf&& o) + : buffer(std::move(o.buffer)) + { + pubseekpos(o.pubseekoff(0, std::ios_base::cur)); + } + + size_t size() const + { + return buffer.size(); + } + + const unsigned char* data() const + { + return buffer.data(); + } + + void clear() + { + buffer.clear(); + } + + std::vector buffer; + +protected: + std::streamsize xsputn(const char_type* __s, std::streamsize __n) override + { + buffer.insert(buffer.end(), __s, __s + __n); + return __n; + } + + int_type overflow(int_type __c) override + { + buffer.push_back( static_cast(__c) ); + return __c; + } +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/params.h b/Thirdparty/Pangolin/include/pangolin/utils/params.h new file mode 100644 index 0000000..beebeae --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/params.h @@ -0,0 +1,80 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT Params +{ +public: + typedef std::vector> ParamMap; + + Params() + { + } + + Params(std::initializer_list> l) + : params(l) + { + } + + bool Contains(const std::string& key) const + { + for(ParamMap::const_iterator it = params.begin(); it!=params.end(); ++it) { + if(it->first == key) return true; + } + return false; + } + + template + T Get(const std::string& key, T default_val) const + { + // Return last value passed to the key. + for(ParamMap::const_reverse_iterator it = params.rbegin(); it!=params.rend(); ++it) { + if(it->first == key) return Convert::Do(it->second); + } + return default_val; + } + + template + void Set(const std::string& key, const T& val) + { + params.push_back(std::pair(key,Convert::Do(val))); + } + + ParamMap params; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/parse.h b/Thirdparty/Pangolin/include/pangolin/utils/parse.h new file mode 100644 index 0000000..eedbd35 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/parse.h @@ -0,0 +1,108 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#ifndef PANGOLIN_PARSE_H +#define PANGOLIN_PARSE_H + +#include +#include + +namespace pangolin +{ + +const unsigned int parse_max_token_size = 1024; + +inline void ConsumeWhitespace(std::istream& is) +{ + while(is.good() && std::isspace(is.peek()) ) { + is.get(); + } +} + +inline bool ConsumeToNewline(std::istream& is) +{ + while(is.good()) { + if(is.get() == '\n') { + return true; + } + } + return false; +} + +template inline +size_t ReadToken(std::istream& is, char buffer[buffer_size]) +{ + size_t r = 0; + while(is.good() && r < buffer_size-1) { + int c = is.peek(); + if( std::isgraph(c) ) { + buffer[r++] = (char)is.get(); + }else{ + break; + } + } + buffer[r] = '\0'; + return r; +} + +inline std::string ReadToken(std::istream &is) +{ + char str_token[parse_max_token_size]; + ReadToken(is, str_token); + return std::string(str_token); +} + +template inline +size_t ConsumeWhitespaceReadToken(std::istream& is, char buffer[buffer_size]) +{ + ConsumeWhitespace(is); + return ReadToken(is, buffer); +} + +inline int ParseToken(const char* token, const char* token_list[], size_t token_list_size) +{ + for(size_t i=0; i < token_list_size; ++i) { + if( strcmp(token, token_list[i]) == 0 ) { + return i; + } + } + return -1; +} + +#define PANGOLIN_DEFINE_PARSE_TOKEN(x) \ + inline x ParseToken##x(const char* token) { \ + return (x)ParseToken(token, x##String, x##Size); \ + } \ + inline x ParseToken##x(std::istream& is) { \ + char str_token[parse_max_token_size]; \ + ReadToken(is, str_token); \ + return ParseToken##x( str_token ); \ + } + +} + +#endif // PANGOLIN_PARSE_H diff --git a/Thirdparty/Pangolin/include/pangolin/utils/picojson.h b/Thirdparty/Pangolin/include/pangolin/utils/picojson.h new file mode 100644 index 0000000..8525269 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/picojson.h @@ -0,0 +1,1416 @@ +/* This is a (butchered) derivative of picojson, incorporated into the + * Pangolin Project (http://github.com/stevenlovegrove/Pangolin) + * + * Modifications Copyright (c) 2014 Steven Lovegrove, + * Original licence applies (below), https://github.com/kazuho/picojson + */ + +/* + * Copyright 2009-2010 Cybozu Labs, Inc. + * Copyright 2011-2014 Kazuho Oku + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef picojson_h +#define picojson_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Enable INT64 support +#define PICOJSON_USE_INT64 + +// for isnan/isinf +#if __cplusplus>=201103L +# include +#else +extern "C" { +# ifdef _MSC_VER +# include +# elif defined(__INTEL_COMPILER) +# include +# else +# include +# endif +} +#endif + +// experimental support for int64_t (see README.mkdn for detail) +#ifdef PICOJSON_USE_INT64 +# ifndef __STDC_FORMAT_MACROS +# define __STDC_FORMAT_MACROS +# endif +# include +# include +#endif // PICOJSON_USE_INT64 + +// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 +#ifndef PICOJSON_USE_LOCALE +# define PICOJSON_USE_LOCALE 1 +#endif // PICOJSON_USE_LOCALE + +#if PICOJSON_USE_LOCALE +extern "C" { +# include +} +#endif // PICOJSON_USE_LOCALE + +#ifndef PICOJSON_ASSERT +# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0) +#endif + +#ifdef _MSC_VER +#define SNPRINTF _snprintf_s +#pragma warning(push) +#pragma warning(disable : 4244) // conversion from int to char +#else +#define SNPRINTF snprintf +#endif + +#ifdef _MSC_VER +#define PICOJSON_FALSE_TEMPLATE_TYPE nullptr +#else +#define PICOJSON_FALSE_TEMPLATE_TYPE ((void*)0) +#endif + +namespace picojson { + +enum { + null_type, + boolean_type, + number_type, + string_type, + array_type, + object_type +#ifdef PICOJSON_USE_INT64 + , int64_type +#endif +}; + +enum { + INDENT_WIDTH = 2 +}; + +struct null {}; + +class value { +public: + typedef std::vector array; + typedef std::map object; + + union _storage { + bool boolean_; + double number_; +#ifdef PICOJSON_USE_INT64 + int64_t int64_; +#endif + std::string* string_; + array* array_; + object* object_; + }; +protected: + int type_; + _storage u_; +public: + + + ///////////////////////////// + // Constructors / Destructor + ///////////////////////////// + + ~value(); + value(); + value(int type, bool); + + ///////////////////////////// + // Implicit type constructors + ///////////////////////////// + + value(bool b) : type_(boolean_type) { + u_.boolean_ = b; + } + +#ifdef PICOJSON_USE_INT64 + value(short v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(unsigned short v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(int v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(unsigned int v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(long v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(unsigned long v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(long long v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } + value(unsigned long long v) : type_(int64_type) { + u_.int64_ = static_cast(v); + } +#endif + + value(float n) : type_(number_type) { + if ( + #ifdef _MSC_VER + ! _finite(n) + #elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf)) + std::isnan(n) || std::isinf(n) + #else + isnan(n) || isinf(n) + #endif + ) { + throw std::overflow_error(""); + } + u_.number_ = static_cast(n); + } + + value(double n) : type_(number_type) { + if ( + #ifdef _MSC_VER + ! _finite(n) + #elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf)) + std::isnan(n) || std::isinf(n) + #else + isnan(n) || isinf(n) + #endif + ) { + throw std::overflow_error(""); + } + u_.number_ = n; + } + + value(const array& a); + value(const object& o); + + value(const std::string& s); + value(const char* s); + value(const char* s, size_t len); + + value(const value& x); + value& operator=(const value& x); + + ///////////////////////////// + // Query / get type + ///////////////////////////// + + void swap(value& x); + template bool is() const; + template const T& get() const; + template T& get(); + bool evaluate_as_boolean() const; + size_t size() const; + + ///////////////////////////// + // Usage as array + ///////////////////////////// + + value& operator[](size_t idx); + const value& operator[](size_t idx) const; + bool contains(size_t idx) const; + value& push_back(const value& = value() ); + + ///////////////////////////// + // Usage as object + ///////////////////////////// + + value& operator[](const std::string& key); + const value& operator[](const std::string& key) const; + bool contains(const std::string& key) const; + + template + T get_value(const std::string& key, T default_value) const; + + ///////////////////////////// + // Serialization + ///////////////////////////// + + std::string to_str() const; + template void serialize(Iter os, bool prettify = false) const; + std::string serialize(bool prettify = false) const; +private: + template value(const T*); // intentionally defined to block implicit conversion of pointer to bool + template static void _indent(Iter os, int indent); + template void _serialize(Iter os, int indent) const; + std::string _serialize(int indent) const; +}; + +typedef value::array array; +typedef value::object object; + +inline value::value() : type_(null_type), u_({false}) {} + +inline value::value(int type, bool) : type_(type) { + switch (type) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(boolean_, false); + INIT(number_, 0.0); +#ifdef PICOJSON_USE_INT64 + INIT(int64_, 0); +#endif + INIT(string_, new std::string()); + INIT(array_, new array()); + INIT(object_, new object()); +#undef INIT + default: break; + } +} + +inline value::value(const std::string& s) : type_(string_type) { + u_.string_ = new std::string(s); +} + +inline value::value(const array& a) : type_(array_type) { + u_.array_ = new array(a); +} + +inline value::value(const object& o) : type_(object_type) { + u_.object_ = new object(o); +} + +inline value::value(const char* s) : type_(string_type) { + u_.string_ = new std::string(s); +} + +inline value::value(const char* s, size_t len) : type_(string_type) { + u_.string_ = new std::string(s, len); +} + +inline value::~value() { + switch (type_) { +#define DEINIT(p) case p##type: delete u_.p; break + DEINIT(string_); + DEINIT(array_); + DEINIT(object_); +#undef DEINIT + default: break; + } +} + +inline value::value(const value& x) : type_(x.type_) { + switch (type_) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(string_, new std::string(*x.u_.string_)); + INIT(array_, new array(*x.u_.array_)); + INIT(object_, new object(*x.u_.object_)); +#undef INIT + default: + u_ = x.u_; + break; + } +} + +inline value& value::operator=(const value& x) { + if (this != &x) { + this->~value(); + new (this) value(x); + } + return *this; +} + +inline void value::swap(value& x) { + std::swap(type_, x.type_); + std::swap(u_, x.u_); +} + +#define IS(ctype, jtype) \ + template <> inline bool value::is() const { \ + return type_ == jtype##_type; \ +} +IS(null, null) +IS(bool, boolean) +#ifdef PICOJSON_USE_INT64 +IS(int64_t, int64) +#endif +IS(std::string, string) +IS(array, array) +IS(object, object) +#undef IS +template <> inline bool value::is() const { + return type_ == number_type + #ifdef PICOJSON_USE_INT64 + || type_ == int64_type + #endif + ; +} + +#define GET(ctype, var) \ + template <> inline const ctype& value::get() const { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ +} \ + template <> inline ctype& value::get() { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ +} +GET(bool, u_.boolean_) +GET(std::string, *u_.string_) +GET(array, *u_.array_) +GET(object, *u_.object_) +#ifdef PICOJSON_USE_INT64 +GET(double, (type_ == int64_type && (const_cast(this)->type_ = number_type, const_cast(this)->u_.number_ = u_.int64_), u_.number_)) +GET(int64_t, u_.int64_) +#else +GET(double, u_.number_) +#endif +#undef GET + +inline bool value::evaluate_as_boolean() const { + switch (type_) { + case null_type: + return false; + case boolean_type: + return u_.boolean_; + case number_type: + return u_.number_ != 0; + case string_type: + return ! u_.string_->empty(); + default: + return true; + } +} + +inline size_t value::size() const +{ + PICOJSON_ASSERT("Type mismatch! Not array." && is()); + return u_.array_->size(); +} + +inline const value& value::operator[](size_t idx) const { + PICOJSON_ASSERT("Type mismatch! Not array." && is()); + PICOJSON_ASSERT("Out of bounds." && idx < u_.array_->size() ); + return (*u_.array_)[idx]; +} + +inline value& value::operator[](size_t idx) { + if( type_ == null_type ) { + // instantiate as array + type_ = array_type; + u_.array_ = new array(); + } + + PICOJSON_ASSERT("Type mismatch! Not array." && is()); + PICOJSON_ASSERT("Out of bounds." && idx < u_.array_->size() ); + return (*u_.array_)[idx]; +} + +inline bool value::contains(size_t idx) const { + if( type_ == array_type) { + return idx < u_.array_->size(); + }else{ + return false; + } +} + +inline value& value::push_back(const value& val) +{ + if( type_ == null_type ) { + // instantiate as array + type_ = array_type; + u_.array_ = new array(); + } + PICOJSON_ASSERT("Type mismatch! Not array." && is()); + u_.array_->push_back( val ); + return u_.array_->back(); +} + +inline const value& value::operator[](const std::string& key) const { + PICOJSON_ASSERT("Type mismatch! Not object." && is() ); + object::const_iterator i = u_.object_->find(key); + PICOJSON_ASSERT("Key not found." && i != u_.object_->end() ); + return i->second; +} + +inline value& value::operator[](const std::string& key) { + if( type_ == null_type ) { + // instantiate as object + type_ = object_type; + u_.object_ = new object(); + } + PICOJSON_ASSERT("Type mismatch! Not object." && is()); + return u_.object_->operator [](key); +} + +inline bool value::contains(const std::string& key) const { + if( type_ == object_type) { + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end(); + }else{ + return false; + } +} + +template +inline T value::get_value(const std::string& key, T default_value) const { + if(contains(key)) { + return (*this)[key].get(); + }else{ + return default_value; + } +} + +inline std::string value::to_str() const { + switch (type_) { + case null_type: return "null"; + case boolean_type: return u_.boolean_ ? "true" : "false"; +#ifdef PICOJSON_USE_INT64 + case int64_type: { + char buf[sizeof("-9223372036854775808")]; + SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); + return buf; + } +#endif + case number_type: { + char buf[256]; + double tmp; + SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); +#if PICOJSON_USE_LOCALE + char *decimal_point = localeconv()->decimal_point; + if (strcmp(decimal_point, ".") != 0) { + size_t decimal_point_len = strlen(decimal_point); + for (char *p = buf; *p != '\0'; ++p) { + if (strncmp(p, decimal_point, decimal_point_len) == 0) { + return std::string(buf, p) + "." + (p + decimal_point_len); + } + } + } +#endif + return buf; + } + case string_type: return *u_.string_; + case array_type: return "array"; + case object_type: return "object"; + default: PICOJSON_ASSERT("value::to_str() assert failed." && 0); +#ifdef _MSC_VER + __assume(0); +#endif + } +} + +template void copy(const std::string& s, Iter oi) { + std::copy(s.begin(), s.end(), oi); +} + +template void serialize_str(const std::string& s, Iter oi) { + *oi++ = '"'; + for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { + switch (*i) { +#define MAP(val, sym) case val: copy(sym, oi); break + MAP('"', "\\\""); + MAP('\\', "\\\\"); + MAP('/', "\\/"); + MAP('\b', "\\b"); + MAP('\f', "\\f"); + MAP('\n', "\\n"); + MAP('\r', "\\r"); + MAP('\t', "\\t"); +#undef MAP + default: + if (static_cast(*i) < 0x20 || *i == 0x7f) { + char buf[7]; + SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); + copy(buf, buf + 6, oi); + } else { + *oi++ = *i; + } + break; + } + } + *oi++ = '"'; +} + +template void value::serialize(Iter oi, bool prettify) const { + return _serialize(oi, prettify ? 0 : -1); +} + +inline std::string value::serialize(bool prettify) const { + return _serialize(prettify ? 0 : -1); +} + +template void value::_indent(Iter oi, int indent) { + *oi++ = '\n'; + for (int i = 0; i < indent * INDENT_WIDTH; ++i) { + *oi++ = ' '; + } +} + +template void value::_serialize(Iter oi, int indent) const { + switch (type_) { + case string_type: + serialize_str(*u_.string_, oi); + break; + case array_type: { + *oi++ = '['; + if (indent != -1) { + ++indent; + } + for (array::const_iterator i = u_.array_->begin(); + i != u_.array_->end(); + ++i) { + if (i != u_.array_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + i->_serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (! u_.array_->empty()) { + _indent(oi, indent); + } + } + *oi++ = ']'; + break; + } + case object_type: { + *oi++ = '{'; + if (indent != -1) { + ++indent; + } + for (object::const_iterator i = u_.object_->begin(); + i != u_.object_->end(); + ++i) { + if (i != u_.object_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + serialize_str(i->first, oi); + *oi++ = ':'; + if (indent != -1) { + *oi++ = ' '; + } + i->second._serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (! u_.object_->empty()) { + _indent(oi, indent); + } + } + *oi++ = '}'; + break; + } + default: + copy(to_str(), oi); + break; + } + if (indent == 0) { + *oi++ = '\n'; + } +} + +inline std::string value::_serialize(int indent) const { + std::string s; + _serialize(std::back_inserter(s), indent); + return s; +} + +template class input { +protected: + Iter cur_, end_; + int last_ch_; + bool ungot_; + int line_; +public: + input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} + int getc() { + if (ungot_) { + ungot_ = false; + return last_ch_; + } + if (cur_ == end_) { + last_ch_ = -1; + return -1; + } + if (last_ch_ == '\n') { + line_++; + } + last_ch_ = *cur_ & 0xff; + ++cur_; + return last_ch_; + } + void ungetc() { + if (last_ch_ != -1) { + PICOJSON_ASSERT(! ungot_); + ungot_ = true; + } + } + Iter cur() const { return cur_; } + int line() const { return line_; } + void skip_ws() { + while (1) { + int ch = getc(); + if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + ungetc(); + break; + } + } + } + bool expect(int expect) { + skip_ws(); + if (getc() != expect) { + ungetc(); + return false; + } + return true; + } + bool match(const std::string& pattern) { + for (std::string::const_iterator pi(pattern.begin()); + pi != pattern.end(); + ++pi) { + if (getc() != *pi) { + ungetc(); + return false; + } + } + return true; + } +}; + +template inline int _parse_quadhex(input &in) { + int uni_ch = 0, hex; + for (int i = 0; i < 4; i++) { + if ((hex = in.getc()) == -1) { + return -1; + } + if ('0' <= hex && hex <= '9') { + hex -= '0'; + } else if ('A' <= hex && hex <= 'F') { + hex -= 'A' - 0xa; + } else if ('a' <= hex && hex <= 'f') { + hex -= 'a' - 0xa; + } else { + in.ungetc(); + return -1; + } + uni_ch = uni_ch * 16 + hex; + } + return uni_ch; +} + +template inline bool _parse_codepoint(String& out, input& in) { + int uni_ch; + if ((uni_ch = _parse_quadhex(in)) == -1) { + return false; + } + if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { + if (0xdc00 <= uni_ch) { + // a second 16-bit of a surrogate pair appeared + return false; + } + // first 16-bit of surrogate pair, get the next one + if (in.getc() != '\\' || in.getc() != 'u') { + in.ungetc(); + return false; + } + int second = _parse_quadhex(in); + if (! (0xdc00 <= second && second <= 0xdfff)) { + return false; + } + uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); + uni_ch += 0x10000; + } + if (uni_ch < 0x80) { + out.push_back(uni_ch); + } else { + if (uni_ch < 0x800) { + out.push_back(0xc0 | (uni_ch >> 6)); + } else { + if (uni_ch < 0x10000) { + out.push_back(0xe0 | (uni_ch >> 12)); + } else { + out.push_back(0xf0 | (uni_ch >> 18)); + out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); + } + out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); + } + out.push_back(0x80 | (uni_ch & 0x3f)); + } + return true; +} + +template inline bool _parse_string(String& out, input& in, int delim='"') { + while (1) { + int ch = in.getc(); + if (ch < ' ') { + in.ungetc(); + return false; + } else if (ch == delim) { + return true; + } else if (ch == '\\') { + if ((ch = in.getc()) == -1) { + return false; + } + switch (ch) { +#define MAP(sym, val) case sym: out.push_back(val); break + MAP('"', '\"'); + MAP('\\', '\\'); + MAP('/', '/'); + MAP('b', '\b'); + MAP('f', '\f'); + MAP('n', '\n'); + MAP('r', '\r'); + MAP('t', '\t'); +#undef MAP + case 'u': + if (! _parse_codepoint(out, in)) { + return false; + } + break; + default: + return false; + } + } else { + out.push_back(ch); + } + } +} + +template inline bool _parse_array(Context& ctx, input& in) { + if (! ctx.parse_array_start()) { + return false; + } + size_t idx = 0; + if (in.expect(']')) { + return ctx.parse_array_stop(idx); + } + do { + if (! ctx.parse_array_item(in, idx)) { + return false; + } + idx++; + } while (in.expect(',')); + return in.expect(']') && ctx.parse_array_stop(idx); +} + +template inline bool _parse_object(Context& ctx, input& in) { + if (! ctx.parse_object_start()) { + return false; + } + if (in.expect('}')) { + return true; + } + do { + std::string key; + // Support " and ' delimited strings + if( in.expect('"') ) { + if( !_parse_string(key, in, '"') ) + return false; + }else if (!in.expect('\'') || !_parse_string(key, in,'\'') ) { + return false; + } + if (!in.expect(':') || !ctx.parse_object_item(in, key)) { + return false; + } + } while (in.expect(',')); + return in.expect('}'); +} + +template inline std::string _parse_number(input& in) { + std::string num_str; + while (1) { + int ch = in.getc(); + if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' + || ch == 'e' || ch == 'E') { + num_str.push_back(ch); + } else if (ch == '.') { +#if PICOJSON_USE_LOCALE + num_str += localeconv()->decimal_point; +#else + num_str.push_back('.'); +#endif + } else { + in.ungetc(); + break; + } + } + return num_str; +} + +template inline bool _parse(Context& ctx, input& in) { + in.skip_ws(); + int ch = in.getc(); + switch (ch) { +#define IS(ch, text, op) case ch: \ + if (in.match(text) && op) { \ + return true; \ + } else { \ + return false; \ + } + IS('n', "ull", ctx.set_null()); + IS('f', "alse", ctx.set_bool(false)); + IS('t', "rue", ctx.set_bool(true)); +#undef IS + case '"': + return ctx.parse_string(in); + case '[': + return _parse_array(ctx, in); + case '{': + return _parse_object(ctx, in); + default: + if (('0' <= ch && ch <= '9') || ch == '-') { + double f; + char *endp; + in.ungetc(); + std::string num_str = _parse_number(in); + if (num_str.empty()) { + return false; + } +#ifdef PICOJSON_USE_INT64 + { + errno = 0; + intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); + if (errno == 0 + && std::numeric_limits::min() <= ival + && ival <= std::numeric_limits::max() + && endp == num_str.c_str() + num_str.size()) { + ctx.set_int64(ival); + return true; + } + } +#endif + f = strtod(num_str.c_str(), &endp); + if (endp == num_str.c_str() + num_str.size()) { + ctx.set_number(f); + return true; + } + return false; + } + break; + } + in.ungetc(); + return false; +} + +class deny_parse_context { +public: + bool set_null() { return false; } + bool set_bool(bool) { return false; } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { return false; } +#endif + bool set_number(double) { return false; } + template bool parse_string(input&) { return false; } + bool parse_array_start() { return false; } + template bool parse_array_item(input&, size_t) { + return false; + } + bool parse_array_stop(size_t) { return false; } + bool parse_object_start() { return false; } + template bool parse_object_item(input&, const std::string&) { + return false; + } +}; + +class default_parse_context { +protected: + value* out_; +public: + default_parse_context(value* out) : out_(out) {} + bool set_null() { + *out_ = value(); + return true; + } + bool set_bool(bool b) { + *out_ = value(b); + return true; + } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t i) { + *out_ = value(i); + return true; + } +#endif + bool set_number(double f) { + *out_ = value(f); + return true; + } + template bool parse_string(input& in) { + *out_ = value(string_type, false); + return _parse_string(out_->get(), in); + } + bool parse_array_start() { + *out_ = value(array_type, false); + return true; + } + template bool parse_array_item(input& in, size_t) { + array& a = out_->get(); + a.push_back(value()); + default_parse_context ctx(&a.back()); + return _parse(ctx, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { + *out_ = value(object_type, false); + return true; + } + template bool parse_object_item(input& in, const std::string& key) { + object& o = out_->get(); + default_parse_context ctx(&o[key]); + return _parse(ctx, in); + } +private: + default_parse_context(const default_parse_context&); + default_parse_context& operator=(const default_parse_context&); +}; + +class null_parse_context { +public: + struct dummy_str { + void push_back(int) {} + }; +public: + null_parse_context() {} + bool set_null() { return true; } + bool set_bool(bool) { return true; } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { return true; } +#endif + bool set_number(double) { return true; } + template bool parse_string(input& in) { + dummy_str s; + return _parse_string(s, in); + } + bool parse_array_start() { return true; } + template bool parse_array_item(input& in, size_t) { + return _parse(*this, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { return true; } + template bool parse_object_item(input& in, const std::string&) { + return _parse(*this, in); + } +private: + null_parse_context(const null_parse_context&); + null_parse_context& operator=(const null_parse_context&); +}; + +// obsolete, use the version below +template inline std::string parse(value& out, Iter& pos, const Iter& last) { + std::string err; + pos = parse(out, pos, last, &err); + return err; +} + +template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { + input in(first, last); + if (! _parse(ctx, in) && err != NULL) { + char buf[64]; + SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); + *err = buf; + while (1) { + int ch = in.getc(); + if (ch == -1 || ch == '\n') { + break; + } else if (ch >= ' ') { + err->push_back(ch); + } + } + } + return in.cur(); +} + +template inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { + default_parse_context ctx(&out); + return _parse(ctx, first, last, err); +} + +inline std::string parse(value &out, const std::string &s) { + std::string err; + parse(out, s.begin(), s.end(), &err); + return err; +} + +inline std::string parse(value& out, std::istream& is) { + std::string err; + parse(out, std::istreambuf_iterator(is.rdbuf()), + std::istreambuf_iterator(), &err); + return err; +} + +template struct last_error_t { + static std::string s; +}; +template std::string last_error_t::s; + +inline void set_last_error(const std::string& s) { + last_error_t::s = s; +} + +inline const std::string& get_last_error() { + return last_error_t::s; +} + +inline bool operator==(const value& x, const value& y) { + if (x.is()) + return y.is(); +#define PICOJSON_CMP(type) \ + if (x.is()) \ + return y.is() && x.get() == y.get() + PICOJSON_CMP(bool); + PICOJSON_CMP(double); + PICOJSON_CMP(std::string); + PICOJSON_CMP(array); + PICOJSON_CMP(object); +#undef PICOJSON_CMP + PICOJSON_ASSERT(0); +#ifdef _MSC_VER + __assume(0); +#endif +} + +inline bool operator!=(const value& x, const value& y) { + return ! (x == y); +} + +} // namespace json + +inline std::istream& operator>>(std::istream& is, picojson::value& x) +{ + picojson::set_last_error(std::string()); + std::string err = picojson::parse(x, is); + if (! err.empty()) { + picojson::set_last_error(err); + is.setstate(std::ios::failbit); + } + return is; +} + +inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) +{ + x.serialize(std::ostream_iterator(os)); + return os; +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // picojson_h + + + + +#ifdef TEST_PICOJSON + +#ifdef _MSC_VER +#pragma warning(disable : 4127) // conditional expression is constant +#endif // _MSC_VER + +using namespace std; + +static bool success = true; +static int test_num = 0; + +static void ok(bool b, const char* name = "") +{ + if (! b) + success = false; + printf("%s %d - %s\n", b ? "ok" : "ng", ++test_num, name); +} + +static void done_testing() +{ + printf("1..%d\n", test_num); +} + +template void is(const T& x, const T& y, const char* name = "") +{ + if (x == y) { + ok(true, name); + } else { + ok(false, name); + } +} + +#include +#include +#include +#include + +int main(void) +{ +#if PICOJSON_USE_LOCALE + setlocale(LC_ALL, ""); +#endif // PICOJSON_USE_LOCALE + + // constructors +#define TEST(expr, expected) \ + is(picojson::value expr .serialize(), string(expected), "picojson::value" #expr) + + TEST( (true), "true"); + TEST( (false), "false"); + TEST( (42.0), "42"); + TEST( (string("hello")), "\"hello\""); + TEST( ("hello"), "\"hello\""); + TEST( ("hello", 4), "\"hell\""); + + { + double a = 1; + for (int i = 0; i < 1024; i++) { + picojson::value vi(a); + std::stringstream ss; + ss << vi; + picojson::value vo; + ss >> vo; + double b = vo.get(); + if ((i < 53 && a != b) || fabs(a - b) / b > 1e-8) { + printf("ng i=%d a=%.18e b=%.18e\n", i, a, b); + } + a *= 2; + } + } + +#undef TEST + +#define TEST(in, type, cmp, serialize_test) { \ + picojson::value v; \ + const char* s = in; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + ok(err.empty(), in " no error"); \ + ok(v.is(), in " check type"); \ + is(v.get(), cmp, in " correct output"); \ + is(*s, '\0', in " read to eof"); \ + if (serialize_test) { \ + is(v.serialize(), string(in), in " serialize"); \ +} \ +} + TEST("false", bool, false, true); + TEST("true", bool, true, true); + TEST("90.5", double, 90.5, false); + TEST("1.7976931348623157e+308", double, DBL_MAX, false); + TEST("\"hello\"", string, string("hello"), true); + TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"), + true); + TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string, + string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false); + TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false); +#ifdef PICOJSON_USE_INT64 + TEST("0", int64_t, 0, true); + TEST("-9223372036854775808", int64_t, std::numeric_limits::min(), true); + TEST("9223372036854775807", int64_t, std::numeric_limits::max(), true); +#endif // PICOJSON_USE_INT64 + +#undef TEST + +#define TEST(type, expr) { \ + picojson::value v; \ + const char *s = expr; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + ok(err.empty(), "empty " #type " no error"); \ + ok(v.is(), "empty " #type " check type"); \ + ok(v.get().empty(), "check " #type " array size"); \ +} + TEST(array, "[]"); + TEST(object, "{}"); +#undef TEST + + { + picojson::value v; + const char *s = "[1,true,\"hello\"]"; + string err = picojson::parse(v, s, s + strlen(s)); + ok(err.empty(), "array no error"); + ok(v.is(), "array check type"); + is(v.get().size(), size_t(3), "check array size"); + ok(v.contains(0), "check contains array[0]"); + ok(v.get(0).is(), "check array[0] type"); + is(v.get(0).get(), 1.0, "check array[0] value"); + ok(v.contains(1), "check contains array[1]"); + ok(v.get(1).is(), "check array[1] type"); + ok(v.get(1).get(), "check array[1] value"); + ok(v.contains(2), "check contains array[2]"); + ok(v.get(2).is(), "check array[2] type"); + is(v.get(2).get(), string("hello"), "check array[2] value"); + ok(!v.contains(3), "check not contains array[3]"); + } + + { + picojson::value v; + const char *s = "{ \"a\": true }"; + string err = picojson::parse(v, s, s + strlen(s)); + ok(err.empty(), "object no error"); + ok(v.is(), "object check type"); + is(v.get().size(), size_t(1), "check object size"); + ok(v.contains("a"), "check contains property"); + ok(v.get("a").is(), "check bool property exists"); + is(v.get("a").get(), true, "check bool property value"); + is(v.serialize(), string("{\"a\":true}"), "serialize object"); + ok(!v.contains("z"), "check not contains property"); + } + +#define TEST(json, msg) do { \ + picojson::value v; \ + const char *s = json; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + is(err, string("syntax error at line " msg), msg); \ +} while (0) + TEST("falsoa", "1 near: oa"); + TEST("{]", "1 near: ]"); + TEST("\n\bbell", "2 near: bell"); + TEST("\"abc\nd\"", "1 near: "); +#undef TEST + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 == v2), "check == operator in deep comparison"); + } + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 != v2), "check != operator for array in deep comparison"); + } + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 != v2), "check != operator for object in deep comparison"); + } + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + picojson::object& o = v1.get(); + o.erase("b"); + picojson::array& a = o["a"].get(); + picojson::array::iterator i; + i = std::remove(a.begin(), a.end(), picojson::value(std::string("three"))); + a.erase(i, a.end()); + s = "{ \"a\": [1,2], \"d\": 2 }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 == v2), "check erase()"); + } + + ok(picojson::value(3.0).serialize() == "3", + "integral number should be serialized as a integer"); + + { + const char* s = "{ \"a\": [1,2], \"d\": 2 }"; + picojson::null_parse_context ctx; + string err; + picojson::_parse(ctx, s, s + strlen(s), &err); + ok(err.empty(), "null_parse_context"); + } + + { + picojson::value v; + const char *s = "{ \"a\": 1, \"b\": [ 2, { \"b1\": \"abc\" } ], \"c\": {}, \"d\": [] }"; + string err; + err = picojson::parse(v, s, s + strlen(s)); + ok(err.empty(), "parse test data for prettifying output"); + ok(v.serialize() == "{\"a\":1,\"b\":[2,{\"b1\":\"abc\"}],\"c\":{},\"d\":[]}", "non-prettifying output"); + ok(v.serialize(true) == "{\n \"a\": 1,\n \"b\": [\n 2,\n {\n \"b1\": \"abc\"\n }\n ],\n \"c\": {},\n \"d\": []\n}\n", "prettifying output"); + } + + try { + picojson::value v(std::numeric_limits::quiet_NaN()); + ok(false, "should not accept NaN"); + } catch (std::overflow_error e) { + ok(true, "should not accept NaN"); + } + + try { + picojson::value v(std::numeric_limits::infinity()); + ok(false, "should not accept infinity"); + } catch (std::overflow_error e) { + ok(true, "should not accept infinity"); + } + + try { + picojson::value v(123.); + ok(! v.is(), "is() should return false"); + v.get(); + ok(false, "get() should raise an error"); + } catch (std::runtime_error e) { + ok(true, "get() should raise an error"); + } + +#ifdef PICOJSON_USE_INT64 + { + picojson::value v1((int64_t)123); + ok(v1.is(), "is int64_t"); + ok(v1.is(), "is double as well"); + ok(v1.serialize() == "123", "serialize the value"); + ok(v1.get() == 123, "value is correct as int64_t"); + ok(v1.get(), "value is correct as double"); + + ok(! v1.is(), "is no more int64_type once get() is called"); + ok(v1.is(), "and is still a double"); + + const char *s = "-9223372036854775809"; + ok(picojson::parse(v1, s, s + strlen(s)).empty(), "parse underflowing int64_t"); + ok(! v1.is(), "underflowing int is not int64_t"); + ok(v1.is(), "underflowing int is double"); + ok(v1.get() + 9.22337203685478e+18 < 65536, "double value is somewhat correct"); + } +#endif // PICOJSON_USE_INT64 + + done_testing(); + + return success ? 0 : 1; +} + +#endif // TEST_PICOJSON diff --git a/Thirdparty/Pangolin/include/pangolin/utils/posix/condition_variable.h b/Thirdparty/Pangolin/include/pangolin/utils/posix/condition_variable.h new file mode 100644 index 0000000..77e1b9f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/posix/condition_variable.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace pangolin +{ + +class ConditionVariableInterface +{ +public: + virtual ~ConditionVariableInterface() + { + } + + virtual void wait() = 0; + virtual bool wait(timespec t) = 0; + virtual void signal() = 0; + virtual void broadcast() = 0; +}; + +std::shared_ptr create_named_condition_variable(const + std::string& name); +std::shared_ptr open_named_condition_variable(const + std::string& name); +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/posix/semaphore.h b/Thirdparty/Pangolin/include/pangolin/utils/posix/semaphore.h new file mode 100644 index 0000000..8563d2b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/posix/semaphore.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +namespace pangolin +{ + + class SemaphoreInterface + { + public: + + virtual ~SemaphoreInterface() { + } + + virtual bool tryAcquire() = 0; + virtual void acquire() = 0; + virtual void release() = 0; + }; + + std::shared_ptr create_named_semaphore(const std::string& name, + unsigned int value); + std::shared_ptr open_named_semaphore(const std::string& name); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/posix/shared_memory_buffer.h b/Thirdparty/Pangolin/include/pangolin/utils/posix/shared_memory_buffer.h new file mode 100644 index 0000000..8ece2bb --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/posix/shared_memory_buffer.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include + +namespace pangolin +{ + class SharedMemoryBufferInterface + { + public: + virtual ~SharedMemoryBufferInterface() { + } + virtual bool tryLock() = 0; + virtual void lock() = 0; + virtual void unlock() = 0; + virtual unsigned char *ptr() = 0; + virtual std::string name() = 0; + }; + + std::shared_ptr create_named_shared_memory_buffer(const + std::string& name, size_t size); + std::shared_ptr open_named_shared_memory_buffer(const + std::string& name, bool readwrite); +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/registration.h b/Thirdparty/Pangolin/include/pangolin/utils/registration.h new file mode 100644 index 0000000..70a3cae --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/registration.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +namespace pangolin { + +template +class Registration +{ +public: + using UnregisterFunc = std::function; + + Registration() + : token() + { + } + + Registration(TokenType token, UnregisterFunc unregister) + : token(token), unregister(unregister) + { + + } + + // No copy constructor + Registration(const Registration&) = delete; + + // Default move constructor + Registration(Registration&& o) + { + *this = std::move(o); + } + + Registration& operator =(Registration&& o) + { + token = o.token; + unregister = std::move(o.unregister); + o.unregister = nullptr; + return *this; + } + + ~Registration() + { + Release(); + } + + void Release() + { + if(unregister) { + unregister(token); + token = TokenType(); + } + } + + const TokenType& Token() + { + return token; + } + +private: + TokenType token; + UnregisterFunc unregister; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/signal_slot.h b/Thirdparty/Pangolin/include/pangolin/utils/signal_slot.h new file mode 100644 index 0000000..2d20c39 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/signal_slot.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +#include + +namespace pangolin { + +// Based on http://simmesimme.github.io/tutorials/2015/09/20/signal-slot +template +class Signal +{ +public: + using Id = size_t; + using Reg = Registration; + + Signal() + : current_id_(0) + { + } + + Signal(const Signal&) = delete; + + Signal(Signal&&) = default; + + // connects a std::function to the signal. The returned + // value can be used to disconnect the function again + Reg Connect(const std::function& slot) const { + slots_.insert(std::make_pair(++current_id_, slot)); + return Reg(current_id_, [this](Id id){ Disconnect(id);}); + } + + // disconnects a previously connected function + void Disconnect(Id id) const { + slots_.erase(id); + } + + // disconnects all previously connected functions + void DisconnectAll() const { + slots_.clear(); + } + + // calls all connected functions + void operator()(Args... p) { + for(auto it : slots_) { + it.second(p...); + } + } + +private: + mutable std::map> slots_; + mutable Id current_id_; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/sigstate.h b/Thirdparty/Pangolin/include/pangolin/utils/sigstate.h new file mode 100644 index 0000000..0ea68fd --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/sigstate.h @@ -0,0 +1,75 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#ifndef SIGPIPE +# define SIGPIPE 13 +#endif // !SIGPIPE + +namespace pangolin +{ + +typedef void (*SigCallbackFn)(int); + +struct PANGOLIN_EXPORT SigCallback +{ + SigCallback(const int & sig, SigCallbackFn fn, void* data) + : sig(sig), fn(fn), data(data), value(false) + { + std::signal(sig, fn); + } + + int sig; + SigCallbackFn fn; + void * data; + volatile sig_atomic_t value; +}; + +class PANGOLIN_EXPORT SigState +{ +public: + static SigState& I(); + + SigState(); + ~SigState(); + + void Clear(); + + std::map sig_callbacks; +}; + +PANGOLIN_EXPORT +void RegisterNewSigCallback(SigCallbackFn callback, void* data, const int signal); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/simple_math.h b/Thirdparty/Pangolin/include/pangolin/utils/simple_math.h new file mode 100644 index 0000000..eff7a43 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/simple_math.h @@ -0,0 +1,446 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace pangolin +{ + +static const double Identity3d[] = {1,0,0, 0,1,0, 0,0,1}; +static const double Zero3d[] = {0,0,0, 0,0,0, 0,0,0}; +static const double Identity4d[] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; +static const double Zero4d[] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; + +static const float Identity3f[] = {1,0,0, 0,1,0, 0,0,1}; +static const float Zero3f[] = {0,0,0, 0,0,0, 0,0,0}; +static const float Identity4f[] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; +static const float Zero4f[] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; + +template +void MatPrint(const P m[R*C]) +{ + for( int r=0; r < R; ++r) + { + for( int c=0; c < C; ++c ) + std::cout << m[R*c+r] << " "; + std::cout << std::endl; + } + std::cout << std::endl; +} + +template +void MatPrint(const P m[R*C], std::string name) +{ + std::cout << name << " = [" << std::endl; + for( int r=0; r < R; ++r) + { + for( int c=0; c < C; ++c ) + std::cout << m[R*c+r] << " "; + std::cout << std::endl; + } + std::cout << std::endl << "]" << std::endl; +} + +// Set array using varadic arguments +template +void MatSet(P m[R*C], ...) +{ + va_list ap; + va_start(ap,m); + for( int i=0; i< R*C; ++i ) + { + *m = (P)va_arg(ap,double); + ++m; + } +} + +// m = zeroes(N) +template +void SetZero(P m[R*C] ) +{ + std::fill_n(m,R*C,0); +} + +// m = identity(N) +template +void SetIdentity(P m[N*N] ) +{ + std::fill_n(m,N*N,0); + for( int i=0; i< N; ++i ) + m[N*i+i] = 1; +} + +// mo = m1 * m2 +template +void MatMul(P mo[R*C], const P m1[R*M], const P m2[M*C] ) +{ + for( int r=0; r < R; ++r) + for( int c=0; c < C; ++c ) + { + mo[R*c+r] = 0; + for( int m=0; m < M; ++ m) mo[R*c+r] += m1[R*m+r] * m2[M*c+m]; + } +} + +// mo = m1 * m2 * s +template +void MatMul(P mo[R*C], const P m1[R*M], const P m2[M*C], P s ) +{ + for( int r=0; r < R; ++r) + for( int c=0; c < C; ++c ) + { + mo[R*c+r] = 0; + for( int m=0; m < M; ++ m) mo[R*c+r] += m1[R*m+r] * m2[M*c+m] * s; + } +} + +// mo = m1 * transpose(m2) +template +void MatMulTranspose(P mo[R*C], const P m1[R*M], const P m2[C*M] ) +{ + for( int r=0; r < R; ++r) + for( int c=0; c < C; ++c ) + { + mo[R*c+r] = 0; + for( int m=0; m < M; ++ m) mo[R*c+r] += m1[R*m+r] * m2[C*m+c]; + } +} + +// m = m1 + m2 +template +void MatAdd(P m[R*C], const P m1[R*C], const P m2[R*C]) +{ + for( int i=0; i< R*C; ++i ) + m[i] = m1[i] + m2[i]; +} + +// m = m1 - m2 +template +void MatSub(P m[R*C], const P m1[R*C], const P m2[R*C]) +{ + for( int i=0; i< R*C; ++i ) + m[i] = m1[i] - m2[i]; +} + +// m = m1 * scalar +template +void MatMul(P m[R*C], const P m1[R*C], P scalar) +{ + for( int i=0; i< R*C; ++i ) + m[i] = m1[i] * scalar; +} + +// m = m1 + m2 +template +void MatMul(P m[R*C], P scalar) +{ + for( int i=0; i< R*C; ++i ) + m[i] *= scalar; +} + +template +void MatTranspose(P out[N*N], const P in[N*N] ) +{ + for( int c=0; c +void MatTranspose(P m[N*N] ) +{ + for( int c=0; c(m[N*c+r],m[N*r+c]); +} + +// m = a x b +template +void VecCross3(P m[3], const P a[3], const P b[3]) +{ + m[0] = a[1]*b[2] - a[2]*b[1]; + m[1] = a[2]*b[0] - a[0]*b[2]; + m[2] = a[0]*b[1] - a[1]*b[0]; +} + +// s = skewSymetrixMatrix(v) +template +void MatSkew(P s[3*3], const P v[3] ) +{ + s[0] = 0; + s[1] = v[2]; + s[2] = -v[1]; + s[3] = -v[2]; + s[4] = 0; + s[5] = v[0]; + s[6] = v[1]; + s[7] = -v[0]; + s[8] = 0; +} + +template +void MatOrtho( P m[N*N] ) +{ + // http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/index.htm + P Itimes3[N*N]; + SetIdentity(Itimes3); + MatMul(Itimes3,(P)3.0); + + P mmT[N*N]; + MatMulTranspose(mmT,m,m); + + P _c[N*N]; + MatSub(_c,Itimes3,mmT); + P _m[N*N]; + MatMul(_m,m,_c,(P)0.5); + std::copy(_m,_m+(N*N),m); +} + +template +void Rotation(P R[3*3], P x, P y, P z) +{ + P sx = sin(x); + P sy = sin(y); + P sz = sin(z); + P cx = cos(x); + P cy = cos(y); + P cz = cos(z); + // P cx = sqrt( (P)1.0 - sx * sx); + // P cy = sqrt( (P)1.0 - sy * sy); + // P cz = sqrt( (P)1.0 - sz * sz); + R[0] = cy * cz; + R[1] = sx * sy * cz + cx * sz; + R[2] = -cx * sy * cz + sx * sz; + R[3] = -cy * sz; + R[4] = -sx * sy * sz + cx * cz; + R[5] = cx * sy * sz + sx * cz; + R[6] = sy; + R[7] = -sx * cy; + R[8] = cx * cy; +} + +template +void LieSetIdentity(P T_ba[3*4] ) +{ + SetIdentity<3>(T_ba); + std::fill_n(T_ba+(3*3),3,0); +} + +template +void LieSetRotation(P T_ba[3*4], const P R_ba[3*3] ) +{ + std::copy(R_ba,R_ba+(3*3),T_ba); +} + +template +void LieSetTranslation(P T_ba[3*4], const P a_b[3] ) +{ + std::copy(a_b, a_b+3, T_ba+(3*3)); +} + +template +void LieSetSE3(P T_ba[3*4], const P R_ba[3*3], const P a_b[3] ) +{ + LieSetRotation

(T_ba,R_ba); + LieSetTranslation

(T_ba,a_b); +} + +template +void LieGetRotation(P R_ba[3*3], const P T_ba[3*4] ) +{ + std::copy(T_ba,T_ba+(3*3),R_ba); +} + +template +void LieApplySO3( P out[3], const P R_ba[3*3], const P in[3] ) +{ + MatMul<3,3,1,P>(out,R_ba,in); +} + +template +void LieApplySE3vec( P x_b[3], const P T_ba[3*4], const P x_a[3] ) +{ + P rot[3]; + MatMul<3,3,1,P>(rot,T_ba,x_a); + MatAdd<3,1,P>(x_b,rot,T_ba+(3*3)); +} + +template +void LieApplySE34x4vec3( P x_b[3], const P T_ba[4*4], const P x_a[3] ) +{ + x_b[0] = T_ba[0]*x_a[0] + T_ba[4]*x_a[1] + T_ba[8]*x_a[2] + T_ba[12]; + x_b[1] = T_ba[1]*x_a[0] + T_ba[5]*x_a[1] + T_ba[9]*x_a[2] + T_ba[13]; + x_b[2] = T_ba[2]*x_a[0] + T_ba[6]*x_a[1] + T_ba[10]*x_a[2] + T_ba[14]; +} + +template +void LieMulSO3( P R_ca[3*3], const P R_cb[3*3], const P R_ba[3*3] ) +{ + MatMul<3,3,3>(R_ca,R_cb,R_ba); +} + +template +void LieMulSE3( P T_ca[3*4], const P T_cb[3*4], const P T_ba[3*4] ) +{ + LieMulSO3<>(T_ca,T_cb,T_ba); + P R_cb_times_a_b[3]; + LieApplySO3<>(R_cb_times_a_b,T_cb,T_ba+(3*3)); + MatAdd<3,1>(T_ca+(3*3),R_cb_times_a_b,T_cb+(3*3)); +} + +template +void LiePutSE3in4x4(P out[4*4], const P in[3*4] ) +{ + SetIdentity<4>(out); + std::copy(in,in+3, out); + std::copy(in+3,in+6, out+4); + std::copy(in+6,in+9, out+8); + std::copy(in+9,in+12, out+12); +} + +template +void LieSE3from4x4(P out[3*4], const P in[4*4] ) +{ + std::copy(in,in+3, out); + std::copy(in+4,in+7, out+3); + std::copy(in+8,in+11, out+6); + std::copy(in+12,in+15, out+9); +} + +template +void LieMul4x4bySE3( P T_ca[4*4], const P T_cb[3*4], const P T_ba[4*4] ) +{ + // TODO: fast + P T_cb4[4*4]; + LiePutSE3in4x4<>(T_cb4,T_cb); + P res[4*4]; + MatMul<4,4,4>(res,T_cb4,T_ba); + std::copy(res,res+(4*4),T_ca); +} + +template +void LieTransposeSO3( P R_ab[3*3], const P R_ba[3*3] ) +{ + MatTranspose<3,P>(R_ab,R_ba); +} + +template +void LieInverseSE3( P T_ab[3*4], const P T_ba[3*4] ) +{ + LieTransposeSO3

(T_ab,T_ba); + P minus_b_a[3]; + LieApplySO3(minus_b_a, T_ab, T_ba+(3*3)); + MatMul<3,1,P>(T_ab+(3*3),minus_b_a, -1); +} + +// c = a x b +template +void CrossProduct( P c[3], const P a[3], const P b[3] ) +{ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; +} + +template +P Length( P v[R] ) +{ + P sum_sq = 0; + + for(size_t r = 0; r < R; ++r ) { + sum_sq += v[r] * v[r]; + } + + return sqrt(sum_sq); +} + + +template +void Normalise( P v[R] ) +{ + const P length = Length(v); + + for(size_t r = 0; r < R; ++r ) { + v[r] /= length; + } +} + +template +void EnforceUpT_wc(P T_wc[3*4], const P up_w[3]) +{ + // Copy R_wc + P R_wc[3*3]; + std::copy(T_wc,T_wc+3*3,R_wc); + + // New R_wc should go into T_wc + P* NR_wc = T_wc; + + // // cx_w,cy_w,cz_w are camera axis in world coordinates + // // Calculate new camera coordinates (ncx_w,ncy_w,ncz_w) + + // ncx_w = up_w x cz_w + CrossProduct(NR_wc + 0*3, up_w, R_wc + 2*3); + + // ncy_w = cz_w x ncx_w + CrossProduct(NR_wc + 1*3, R_wc + 2*3, NR_wc + 0*3); + + // ncz_w = cz_w + std::copy(R_wc + 2*3, R_wc + 3*3, NR_wc + 2*3); + + Normalise<3,P>(NR_wc + 0*3); + Normalise<3,P>(NR_wc + 1*3); + Normalise<3,P>(NR_wc + 2*3); +} + +template +void EnforceUpT_cw(P T_cw_4x4[4*4], const P up_w[3]) +{ + // 3x4 from 4x4 + P T_cw[3*4]; + LieSE3from4x4

(T_cw,T_cw_4x4); + + // Invert T_cw + P T_wc[3*4]; + LieInverseSE3

(T_wc, T_cw); + + // Enforce up for T_wc + EnforceUpT_wc

(T_wc, up_w); + + // Invert + LieInverseSE3

(T_cw, T_wc); + + // 4x4 from 3x4 + LiePutSE3in4x4

(T_cw_4x4,T_cw); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/threadedfilebuf.h b/Thirdparty/Pangolin/include/pangolin/utils/threadedfilebuf.h new file mode 100644 index 0000000..a8eb2ac --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/threadedfilebuf.h @@ -0,0 +1,97 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef _LINUX_ +// On linux, using posix file i/o to allow sync writes. +#define USE_POSIX_FILE_IO +#endif + +namespace pangolin +{ + +class PANGOLIN_EXPORT threadedfilebuf : public std::streambuf +{ +public: + ~threadedfilebuf(); + threadedfilebuf(); + threadedfilebuf(const std::string& filename, size_t buffer_size_bytes); + + void open(const std::string& filename, size_t buffer_size_bytes); + void close(); + void force_close(); + + void operator()(); + +protected: + void soft_close(); + + //! Override streambuf::xsputn for asynchronous write + std::streamsize xsputn(const char * s, std::streamsize n) override; + + //! Override streambuf::overflow for asynchronous write + int overflow(int c) override; + + std::streampos seekoff( + std::streamoff off, std::ios_base::seekdir way, + std::ios_base::openmode which = std::ios_base::in | std::ios_base::out + ) override; + +#ifdef USE_POSIX_FILE_IO + int filenum = -1; +#else + std::filebuf file; +#endif + + char* mem_buffer; + std::streamsize mem_size; + std::streamsize mem_max_size; + std::streamsize mem_start; + std::streamsize mem_end; + + std::streampos input_pos; + + std::mutex update_mutex; + std::condition_variable cond_queued; + std::condition_variable cond_dequeued; + std::thread write_thread; + + bool should_run; + bool is_pipe; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/timer.h b/Thirdparty/Pangolin/include/pangolin/utils/timer.h new file mode 100644 index 0000000..6b0418b --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/timer.h @@ -0,0 +1,116 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include + +namespace pangolin +{ + +// These methods exist for backwards compatibility. +// They are deprecated in favour of direct use of std::chrono in C++11 + +using baseclock = std::chrono::steady_clock; +using basetime = baseclock::time_point; +static_assert(baseclock::is_steady, "baseclock must be steady to be robust against system time settings"); + +inline basetime TimeNow() +{ + return baseclock::now(); +} + +inline double Time_s(basetime t) +{ + using namespace std::chrono; + return duration_cast( t.time_since_epoch() ).count(); +} + +inline int64_t Time_us(basetime t) +{ + using namespace std::chrono; + return duration_cast( t.time_since_epoch() ).count(); +} + +inline double TimeDiff_s(basetime start, basetime end) +{ + const baseclock::duration d = end - start; + return Time_s( basetime() + d); +} + +inline int64_t TimeDiff_us(basetime start, basetime end) +{ + const baseclock::duration d = end - start; + return Time_us( basetime() + d); +} + +inline basetime TimeAdd(basetime t1, basetime t2) +{ + + return t1 + t2.time_since_epoch(); +} + +inline double TimeNow_s() +{ + return Time_s(TimeNow()); +} + +inline int64_t TimeNow_us() +{ + return Time_us(TimeNow()); +} + +inline basetime WaitUntil(basetime t) +{ + std::this_thread::sleep_until(t); + return TimeNow(); +} + +struct Timer +{ + Timer() { + Reset(); + } + + void Reset() + { + start = TimeNow(); + } + + double Elapsed_s() + { + basetime currtime = TimeNow(); + return TimeDiff_s(start,currtime); + } + + basetime start; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/transform.h b/Thirdparty/Pangolin/include/pangolin/utils/transform.h new file mode 100644 index 0000000..b29c1e9 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/transform.h @@ -0,0 +1,102 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +// Find the open brace preceeded by '$' +inline const char* FirstOpenBrace(const char* str, char token = '$', char open = '{') +{ + bool symbol = false; + + for(; *str != '\0'; ++str ) { + if( *str == token) { + symbol = true; + }else{ + if( symbol ) { + if( *str == open ) { + return str; + } else { + symbol = false; + } + } + } + } + return 0; +} + +// Find the first matching end brace. str includes open brace +inline const char* MatchingEndBrace(const char* str, char open = '{', char close = '}') +{ + int b = 0; + for(; *str != '\0'; ++str ) { + if( *str == open ) { + ++b; + }else if( *str == close ) { + --b; + if( b == 0 ) { + return str; + } + } + } + return 0; +} + +inline std::string Transform(const std::string& val, std::function dictionary, char token = '$', char open = '{', char close = '}') +{ + std::string expanded = val; + + while(true) + { + const char* brace = FirstOpenBrace(expanded.c_str(), token, open); + if(brace) + { + const char* endbrace = MatchingEndBrace(brace); + if( endbrace ) + { + std::ostringstream oss; + oss << std::string(expanded.c_str(), brace-1); + + const std::string inexpand = Transform( std::string(brace+1,endbrace), dictionary, token, open, close ); + oss << dictionary(inexpand); + oss << std::string(endbrace+1, expanded.c_str() + expanded.length() ); + expanded = oss.str(); + continue; + } + } + break; + } + + return expanded; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/type_convert.h b/Thirdparty/Pangolin/include/pangolin/utils/type_convert.h new file mode 100644 index 0000000..93d026f --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/type_convert.h @@ -0,0 +1,210 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin +{ +struct BadInputException : std::exception { + char const* what() const throw() { return "Failed to serialise type"; } +}; +} + +namespace std +{ +// Dummy methods to serialise functions / functors / lambdas etc +#ifdef CALLEE_HAS_VARIADIC_TEMPLATES +template +inline std::istream& operator>>(std::istream& /*is*/, std::function& /*f*/) { + throw pangolin::BadInputException(); +} +template +inline std::ostream& operator<<(std::ostream& /*os*/, const std::function& /*f*/) { + throw pangolin::BadInputException(); +} +#else +template +inline std::istream& operator>>(std::istream& /*is*/, std::function& /*f*/) { + throw pangolin::BadInputException(); +} +template +inline std::ostream& operator<<(std::ostream& /*os*/, const std::function& /*f*/) { + throw pangolin::BadInputException(); +} +inline std::istream& operator>>(std::istream& /*is*/, std::function& /*f*/) { + throw pangolin::BadInputException(); +} +inline std::ostream& operator<<(std::ostream& /*os*/, const std::function& /*f*/) { + throw pangolin::BadInputException(); +} +#endif +} + +namespace pangolin +{ + +template +struct Convert; + +// Generic conversion through serialisation from / to string +template +struct Convert { + static T Do(const S& src) + { + std::ostringstream oss; + oss << src; + std::istringstream iss(oss.str()); + T target; + iss >> target; + + if(iss.fail()) + throw BadInputException(); + + return target; + } +}; + +// Between the same types is just a copy +template +struct Convert { + static T Do(const T& src) + { + return src; + } +}; + +// Apply bool alpha IO manipulator for bool types +template<> +struct Convert { + static bool Do(const std::string& src) + { + bool target; + std::istringstream iss(src); + iss >> target; + + if(iss.fail()) + { + std::istringstream iss2(src); + iss2 >> std::boolalpha >> target; + if( iss2.fail()) + throw BadInputException(); + } + + return target; + } +}; + +// From strings +template +struct Convert::value + >::type > { + static T Do(const std::string& src) + { + T target; + std::istringstream iss(src); + iss >> target; + + if(iss.fail()) + throw BadInputException(); + + return target; + } +}; + +// To strings +template +struct Convert::value + >::type > { + static std::string Do(const S& src) + { + std::ostringstream oss; + oss << src; + return oss.str(); + } +}; + +// Between scalars +template +struct Convert::value && !std::is_same::value && + std::is_scalar::value && !std::is_same::value && + !std::is_same::value + >::type > { + static T Do(const S& src) + { + return static_cast(src); + } +}; + +// From Scalars to bool (different than scalar definition to avoid MSVC Warnings) +template +struct Convert::value && + std::is_scalar::value && + !std::is_same::value +>::type > { + static T Do(const S& src) + { + return src != static_cast(0); + } +}; + +// From bool to Scalars (different than scalar definition to avoid MSVC Warnings) +template +struct Convert::value && + std::is_same::value && + !std::is_same::value +>::type > { + static T Do(const S& src) + { + return src ? static_cast(0) : static_cast(1); + } +}; + +template +std::string ToString(const S& src) +{ + return Convert::Do(src); +} + +template +T FromString(const std::string& src) +{ + return Convert::Do(src); +} + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/uri.h b/Thirdparty/Pangolin/include/pangolin/utils/uri.h new file mode 100644 index 0000000..0ea376e --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/uri.h @@ -0,0 +1,49 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT Uri : public Params +{ +public: + std::string scheme; + std::string url; + std::string full_uri; +}; + +//! Parse string as Video URI +PANGOLIN_EXPORT +Uri ParseUri(const std::string& str_uri); + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/variadic_all.h b/Thirdparty/Pangolin/include/pangolin/utils/variadic_all.h new file mode 100644 index 0000000..3cc0681 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/variadic_all.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +namespace pangolin { + +template +bool all_of(TPred pred, const T& i) +{ + return pred(i); +} + +template +bool all_of(const TPred& pred, const T& i, const Targs& ... ins) +{ + return pred(i) && all_of(pred, ins...); +} + +template +bool any_of(TPred pred, const T& i) +{ + return pred(i); +} + +template +bool any_of(const TPred& pred, const T& i, Targs& ... ins) +{ + return pred(i) || any_of(pred, ins...); +} + +template +bool all_found(const TContainer& c, const Targs& ... its) +{ + using T1 = typename std::tuple_element<0, std::tuple>::type; + return all_of([&c](const T1& it){return it != c.end();}, its...); +} + +template +bool all_equal(const T& v1, const Targs& ... its) +{ + return all_of([v1](const T& o){return v1 == o;}, its...); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/utils/xml/license.txt b/Thirdparty/Pangolin/include/pangolin/utils/xml/license.txt new file mode 100644 index 0000000..1409831 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/xml/license.txt @@ -0,0 +1,52 @@ +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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 OR COPYRIGHT HOLDERS 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. diff --git a/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml.hpp b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml.hpp new file mode 100644 index 0000000..252e344 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml.hpp @@ -0,0 +1,2635 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new + #include // for conversion between types +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

+ //! This function cannot return. If it does, the results are undefined. + //!

+ //! A very simple definition might look like that: + //!

+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! 
+ //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

+ //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

+ //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

+ //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

+ //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
    + //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • + //!
  • entities will not be translated
  • + //!
  • whitespace will not be normalized
  • + //!
+ //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

+ //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

+ //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Command option default defaults + + //! Default case sensitivity when searching for node / attribute names. + const bool default_case_sensitivity = false; + + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

+ //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

+ //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

+ //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

+ //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

+ //! User defined allocation functions must have the following forms: + //!
+ //!
void *allocate(std::size_t size); + //!
void free(void *pointer); + //!

+ //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + //! Gets value of node converted to type T. + //! \return Value of node converted to type T or default_val if no value exists. + //! \throws parse_error iff conversion to type T fails. + template + T valueT(T default_val = T() ) + { + if(m_value) { + std::istringstream ss( std::string(m_value, m_value_size) ); + T ret_val; + ss >> ret_val; + if(ss.fail()) { + RAPIDXML_PARSE_ERROR("error converting value in valueT()", m_value); + } + return ret_val; + } + return default_val; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

+ //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = default_case_sensitivity) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + //! Gets first attribute of node, optionally matching attribute name, converting to type T + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param default_val value to return if attribute is not found or if it has no value + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Converted value of attribute, or default_val if attribute not found or it has no value + template + T first_attribute_value(const Ch *name = 0, std::size_t name_size = 0, T default_val = T(), bool case_sensitive = default_case_sensitivity ) + { + rapidxml::xml_attribute<>* a = first_attribute( name, name_size, case_sensitive ); + return a ? a->valueT(default_val) : default_val; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

+ //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_iterators.hpp b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_iterators.hpp new file mode 100644 index 0000000..52ebc29 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml +{ + + //! Iterator of child nodes of xml_node + template + class node_iterator + { + + public: + + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node *node) + : m_node(node->first_node()) + { + } + + reference operator *() const + { + assert(m_node); + return *m_node; + } + + pointer operator->() const + { + assert(m_node); + return m_node; + } + + node_iterator& operator++() + { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator& operator--() + { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const node_iterator &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node *m_node; + + }; + + //! Iterator of child attributes of xml_node + template + class attribute_iterator + { + + public: + + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node *node) + : m_attribute(node->first_attribute()) + { + } + + reference operator *() const + { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const + { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator& operator++() + { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator& operator--() + { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const attribute_iterator &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute *m_attribute; + + }; + +} + +#endif diff --git a/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_print.hpp b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_print.hpp new file mode 100644 index 0000000..0ae2b14 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_print.hpp @@ -0,0 +1,421 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include + #include +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + // Print node + template + inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + + // Print children of the node + template + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) + { + for (xml_node *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) + { + for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template + inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template + inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template + inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template + inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template + inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template + inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template + inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template + inline OutIt print(OutIt out, const xml_node &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template + inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) + { + print(std::ostream_iterator(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template + inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_utils.hpp b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_utils.hpp new file mode 100644 index 0000000..4de0763 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/utils/xml/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = (size_t)stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/Thirdparty/Pangolin/include/pangolin/var/input_record_repeat.h b/Thirdparty/Pangolin/include/pangolin/var/input_record_repeat.h new file mode 100644 index 0000000..b8df0c5 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/input_record_repeat.h @@ -0,0 +1,86 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace pangolin +{ + +struct FrameInput +{ + int index; + std::string var; + std::string val; +}; + +struct PANGOLIN_EXPORT InputRecordRepeat +{ + InputRecordRepeat(const std::string& var_record_prefix); + ~InputRecordRepeat(); + + void SetIndex(int id); + + void Record(); + void Stop(); + + void LoadBuffer(const std::string& filename); + void SaveBuffer(const std::string& filename); + void ClearBuffer(); + + void PlayBuffer(); + void PlayBuffer(size_t start, size_t end); + + void UpdateVariable(const std::string& name ); + + template + inline void UpdateVariable(const Var& var ) { + GuiVarChanged((void*)this, var.var->Meta().full_name, *var.var); + } + + size_t Size(); + +protected: + bool record; + bool play; + + int index; + std::ofstream file; + std::string filename; + + std::list play_queue; + std::list record_queue; + + static void GuiVarChanged(void* data, const std::string& name, VarValueGeneric& var); +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/var.h b/Thirdparty/Pangolin/include/pangolin/var/var.h new file mode 100644 index 0000000..42c5388 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/var.h @@ -0,0 +1,340 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace pangolin +{ + +template +inline void InitialiseNewVarMetaGeneric( + VarValue& v, const std::string& name +) { + // Initialise meta parameters + const std::vector parts = pangolin::Split(name,'.'); + v.Meta().full_name = name; + v.Meta().friendly = parts.size() > 0 ? parts[parts.size()-1] : ""; + v.Meta().range[0] = 0.0; + v.Meta().range[1] = 0.0; + v.Meta().increment = 0.0; + v.Meta().flags = META_FLAG_NONE; + v.Meta().logscale = false; + v.Meta().generic = true; + + VarState::I().NotifyNewVar(name, v); +} + +template +inline void InitialiseNewVarMeta( + VarValue& v, const std::string& name, + double min = 0, double max = 0, int flags = META_FLAG_TOGGLE, + bool logscale = false +) { + // Initialise meta parameters + const std::vector parts = pangolin::Split(name,'.'); + v.Meta().full_name = name; + v.Meta().friendly = parts.size() > 0 ? parts[parts.size()-1] : ""; + v.Meta().range[0] = min; + v.Meta().range[1] = max; + if (std::is_integral::value) { + v.Meta().increment = 1.0; + } else { + v.Meta().increment = (max - min) / 100.0; + } + v.Meta().flags = flags; + v.Meta().logscale = logscale; + v.Meta().generic = false; + + VarState::I().NotifyNewVar(name, v); +} + +template +class Var +{ +public: + static T& Attach( + const std::string& name, T& variable, + double min, double max, bool logscale = false + ) { + // Find name in VarStore + VarValueGeneric*& v = VarState::I()[name]; + if(v) { + throw std::runtime_error(std::string("Var with the following name already exists: ") + name); + }else{ + // new VarRef (owned by VarStore) + VarValue* nv = new VarValue(variable); + v = nv; + if(logscale) { + if (min <= 0 || max <= 0) { + throw std::runtime_error("LogScale: range of numbers must be positive!"); + } + InitialiseNewVarMeta(*nv, name, std::log(min), std::log(max), META_FLAG_TOGGLE, logscale); + }else{ + InitialiseNewVarMeta(*nv, name, min, max, META_FLAG_TOGGLE, logscale); + } + } + return variable; + } + + static T& Attach( + const std::string& name, T& variable, int flags = META_FLAG_NONE + ) { + // Find name in VarStore + VarValueGeneric*& v = VarState::I()[name]; + if (v) { + throw std::runtime_error(std::string("Var with the following name already exists: ") + name); + } + else{ + // new VarRef (owned by VarStore) + VarValue* nv = new VarValue(variable); + v = nv; + InitialiseNewVarMeta(*nv, name, 0.0, 0.0, flags); + } + return variable; + } + + static T& Attach( + const std::string& name, T& variable, bool toggle + ) { + return Attach(name, variable, toggle ? META_FLAG_TOGGLE : META_FLAG_NONE); + } + + ~Var() + { + delete ptr; + } + + Var( VarValueGeneric& v ) + : ptr(0) + { + InitialiseFromGeneric(&v); + } + + + Var( const std::string& name ) + : ptr(0) + { + // Find name in VarStore + VarValueGeneric*& v = VarState::I()[name]; + if(v && !v->Meta().generic) { + InitialiseFromGeneric(v); + }else{ + // new VarValue (owned by VarStore) + VarValue* nv; + if(v) { + // Specialise generic variable + nv = new VarValue( Convert::Do( v->str->Get() ) ); + delete v; + }else{ + nv = new VarValue( T() ); + } + v = nv; + var = nv; + InitialiseNewVarMeta(*nv, name); + } + } + + Var(const std::string& name, const T& value, int flags = META_FLAG_NONE) + : ptr(0) + { + // Find name in VarStore + VarValueGeneric*& v = VarState::I()[name]; + if(v && !v->Meta().generic) { + InitialiseFromGeneric(v); + }else{ + // new VarValue (owned by VarStore) + VarValue* nv; + if(v) { + // Specialise generic variable + nv = new VarValue( Convert::Do( v->str->Get() ) ); + delete v; + }else{ + nv = new VarValue(value); + } + v = nv; + var = nv; + InitialiseNewVarMeta(*nv, name, 0, 1, flags); + } + } + + Var(const std::string& name, const T& value, bool toggle) + : Var(name, value, toggle ? META_FLAG_TOGGLE : META_FLAG_NONE) + { + } + + Var( + const std::string& name, const T& value, + double min, double max, bool logscale = false + ) : ptr(0) + { + // Find name in VarStore + VarValueGeneric*& v = VarState::I()[name]; + if(v && !v->Meta().generic) { + InitialiseFromGeneric(v); + }else{ + // new VarValue (owned by VarStore) + VarValue* nv; + if(v) { + // Specialise generic variable + nv = new VarValue( Convert::Do( v->str->Get() ) ); + delete v; + }else{ + nv = new VarValue(value); + } + var = nv; + v = nv; + if(logscale) { + if (min <= 0 || max <= 0) { + throw std::runtime_error("LogScale: range of numbers must be positive!"); + } + InitialiseNewVarMeta(*nv, name, std::log(min), std::log(max), META_FLAG_TOGGLE, true); + }else{ + InitialiseNewVarMeta(*nv, name, min, max); + } + } + } + + void Reset() + { + var->Reset(); + } + + const T& Get() const + { + try{ + return var->Get(); + }catch(const BadInputException&) + { + const_cast *>(this)->Reset(); + return var->Get(); + } + } + + operator const T& () const + { + return Get(); + } + + const T* operator->() + { + try{ + return &(var->Get()); + }catch(const BadInputException&) + { + Reset(); + return &(var->Get()); + } + } + + void operator=(const T& val) + { + var->Set(val); + } + + void operator=(const Var& v) + { + var->Set(v.var->Get()); + } + + VarMeta& Meta() + { + return var->Meta(); + } + + bool GuiChanged() + { + if(var->Meta().gui_changed) { + var->Meta().gui_changed = false; + return true; + } + return false; + } + + VarValueT& Ref() + { + return *var; + } + +protected: + // Initialise from existing variable, obtain data / accessor + void InitialiseFromGeneric(VarValueGeneric* v) + { + if( !strcmp(v->TypeId(), typeid(T).name()) ) { + // Same type + var = (VarValueT*)(v); + }else if( std::is_same::value ) { + // Use types string accessor + var = (VarValueT*)(v->str); + }else if( !strcmp(v->TypeId(), typeid(bool).name() ) ) { + // Wrapper, owned by this object + ptr = new VarWrapper( *(VarValueT*)v ); + var = ptr; + }else if( !strcmp(v->TypeId(), typeid(short).name() ) ) { + // Wrapper, owned by this object + ptr = new VarWrapper( *(VarValueT*)v ); + var = ptr; + }else if( !strcmp(v->TypeId(), typeid(int).name() ) ) { + // Wrapper, owned by this object + ptr = new VarWrapper( *(VarValueT*)v ); + var = ptr; + }else if( !strcmp(v->TypeId(), typeid(long).name() ) ) { + // Wrapper, owned by this object + ptr = new VarWrapper( *(VarValueT*)v ); + var = ptr; + }else if( !strcmp(v->TypeId(), typeid(float).name() ) ) { + // Wrapper, owned by this object + ptr = new VarWrapper( *(VarValueT*)v ); + var = ptr; + }else if( !strcmp(v->TypeId(), typeid(double).name() ) ) { + // Wrapper, owned by this object + ptr = new VarWrapper( *(VarValueT*)v ); + var = ptr; + }else{ + // other types: have to go via string + // Wrapper, owned by this object + ptr = new VarWrapper( *(v->str) ); + var = ptr; + } + } + + // Holds reference to stored variable object + // N.B. mutable because it is a cached value and Get() is advertised as const. + mutable VarValueT* var; + + // ptr is non-zero if this object owns the object variable (a wrapper) + VarValueT* ptr; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/varextra.h b/Thirdparty/Pangolin/include/pangolin/var/varextra.h new file mode 100644 index 0000000..6388262 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/varextra.h @@ -0,0 +1,92 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin +{ + +PANGOLIN_EXPORT +void ParseVarsFile(const std::string& filename); + +PANGOLIN_EXPORT +void LoadJsonFile(const std::string& filename, const std::string& prefix=""); + +PANGOLIN_EXPORT +void SaveJsonFile(const std::string& filename, const std::string& prefix=""); + +PANGOLIN_EXPORT +void ProcessHistoricCallbacks(NewVarCallbackFn callback, void* data, const std::string& filter = ""); + +PANGOLIN_EXPORT +void RegisterNewVarCallback(NewVarCallbackFn callback, void* data, const std::string& filter = ""); + +PANGOLIN_EXPORT +void RegisterGuiVarChangedCallback(GuiVarChangedCallbackFn callback, void* data, const std::string& filter = ""); + +template +struct SetVarFunctor +{ + SetVarFunctor(const std::string& name, T val) : varName(name), setVal(val) {} + void operator()() { Var(varName).Ref().Set(setVal); } + std::string varName; + T setVal; +}; + +struct ToggleVarFunctor +{ + ToggleVarFunctor(const std::string& name) : varName(name) {} + void operator()() { Var val(varName,false); val = !val; } + std::string varName; +}; + +inline bool Pushed(Var& button) +{ + bool val = button; + button = false; + return val; +} + +inline bool Pushed(bool& button) +{ + bool val = button; + button = false; + return val; +} + +template +inline std::ostream& operator<<(std::ostream& s, Var& rhs) +{ + s << rhs.operator const T &(); + return s; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/varstate.h b/Thirdparty/Pangolin/include/pangolin/var/varstate.h new file mode 100644 index 0000000..90d7e2c --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/varstate.h @@ -0,0 +1,130 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace pangolin +{ + +typedef void (*NewVarCallbackFn)(void* data, const std::string& name, VarValueGeneric& var, bool brand_new); +typedef void (*GuiVarChangedCallbackFn)(void* data, const std::string& name, VarValueGeneric& var); + +struct PANGOLIN_EXPORT NewVarCallback +{ + NewVarCallback(const std::string& filter, NewVarCallbackFn fn, void* data) + :filter(filter),fn(fn),data(data) {} + std::string filter; + NewVarCallbackFn fn; + void* data; +}; + +struct PANGOLIN_EXPORT GuiVarChangedCallback +{ + GuiVarChangedCallback(const std::string& filter, GuiVarChangedCallbackFn fn, void* data) + :filter(filter),fn(fn),data(data) {} + std::string filter; + GuiVarChangedCallbackFn fn; + void* data; +}; + +class PANGOLIN_EXPORT VarState +{ +public: + static VarState& I(); + + VarState(); + ~VarState(); + + void Clear(); + + template + void NotifyNewVar(const std::string& name, VarValue& var ) + { + var_adds.push_back(name); + + // notify those watching new variables + for(std::vector::iterator invc = new_var_callbacks.begin(); invc != new_var_callbacks.end(); ++invc) { + if( StartsWith(name,invc->filter) ) { + invc->fn( invc->data, name, var, true); + } + } + } + + VarValueGeneric*& operator[](const std::string& str) + { + VarStoreContainer::iterator it = vars.find(str); + if (it == vars.end()) { + vars[str] = nullptr; + } + return vars[str]; + } + + bool Exists(const std::string& str) const + { + return vars.find(str) != vars.end(); + } + + void FlagVarChanged() + { + varHasChanged = true; + } + + bool VarHasChanged() + { + const bool has_changed = varHasChanged; + varHasChanged = false; + return has_changed; + } + +//protected: + typedef std::map VarStoreContainer; + typedef std::vector VarStoreAdditions; + + VarStoreContainer vars; + VarStoreAdditions var_adds; + + std::vector new_var_callbacks; + std::vector gui_var_changed_callbacks; + + bool varHasChanged; +}; + +inline bool GuiVarHasChanged() { + return VarState::I().VarHasChanged(); +} + +inline void FlagVarChanged() { + VarState::I().FlagVarChanged(); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/varvalue.h b/Thirdparty/Pangolin/include/pangolin/var/varvalue.h new file mode 100644 index 0000000..ee3193d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/varvalue.h @@ -0,0 +1,114 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +template +class VarValue : public VarValueT::type> +{ +public: + typedef typename std::remove_reference::type VarT; + + ~VarValue() + { + delete str_ptr; + } + + VarValue() + { + Init(); + } + + VarValue(const T& value) + : value(value), default_value(value) + { + Init(); + } + + VarValue(const T& value, const VarT& default_value) + : value(value), default_value(default_value) + { + Init(); + } + + const char* TypeId() const + { + return typeid(VarT).name(); + } + + void Reset() + { + value = default_value; + } + + VarMeta& Meta() + { + return meta; + } + + const VarT& Get() const + { + return value; + } + + VarT& Get() + { + return value; + } + + void Set(const VarT& val) + { + value = val; + } + +protected: + void Init() + { + if(std::is_same::value) { + str_ptr = 0; + this->str = (VarValueT*)this; + }else{ + str_ptr = new VarWrapper(*this); + this->str = str_ptr; + } + } + + // If non-zero, this class owns this str pointer in the base-class. + VarValueT* str_ptr; + + T value; + VarT default_value; + VarMeta meta; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/varvaluegeneric.h b/Thirdparty/Pangolin/include/pangolin/var/varvaluegeneric.h new file mode 100644 index 0000000..fe81402 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/varvaluegeneric.h @@ -0,0 +1,87 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin +{ +constexpr int META_FLAG_NONE = 0x0000; +constexpr int META_FLAG_TOGGLE = 0x0001; +constexpr int META_FLAG_READONLY = 0x0002; + +struct VarMeta +{ + VarMeta() : + increment(0.), + flags(META_FLAG_NONE), + gui_changed(false), + logscale(false), + generic(false) + { + range[0] = 0.; + range[1] = 0.; + } + + std::string full_name; + std::string friendly; + double range[2]; + double increment; + int flags; + bool gui_changed; + bool logscale; + bool generic; +}; + +// Forward declaration +template +class VarValueT; + +//! Abstract base class for named Pangolin variables +class VarValueGeneric +{ +public: + VarValueGeneric() + : str(0) + { + } + + virtual ~VarValueGeneric() + { + } + + virtual const char* TypeId() const = 0; + virtual void Reset() = 0; + virtual VarMeta& Meta() = 0; + +//protected: + // String serialisation object. + VarValueT* str; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/varvaluet.h b/Thirdparty/Pangolin/include/pangolin/var/varvaluet.h new file mode 100644 index 0000000..5b7a45c --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/varvaluet.h @@ -0,0 +1,46 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +template +class VarValueT : public VarValueGeneric +{ +public: + typedef typename std::remove_reference::type VarT; + + virtual const VarT& Get() const = 0; + virtual void Set(const VarT& val) = 0; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/var/varwrapper.h b/Thirdparty/Pangolin/include/pangolin/var/varwrapper.h new file mode 100644 index 0000000..02faacd --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/var/varwrapper.h @@ -0,0 +1,91 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin +{ + +template +class VarWrapper : public VarValueT +{ +public: + typedef typename std::remove_reference::type VarS; + + VarWrapper(VarValueT& src) + : src(src) + { + this->str = src.str; + } + + const char* TypeId() const + { + return typeid(T).name(); + } + + void Reset() + { + src.Reset(); + + // If reset throws, it will go up to the user, since there is nothing + // more we can do + cache = Convert::Do(src.Get()); + } + + VarMeta& Meta() + { + return src.Meta(); + } + + const T& Get() const + { + // This might throw, but we can't reset because this is a const method + cache = Convert::Do(src.Get()); + return cache; + } + + void Set(const T& val) + { + cache = val; + try { + src.Set( Convert::Do(val) ); + }catch(const BadInputException&) { + pango_print_warn("Unable to set variable with type %s from %s. Resetting.", typeid(VarS).name(), typeid(T).name() ); + Reset(); + } + } + +protected: + mutable T cache; + VarValueT& src; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/debayer.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/debayer.h new file mode 100644 index 0000000..4d4d9bf --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/debayer.h @@ -0,0 +1,116 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +// Enum to match libdc1394's dc1394_bayer_method_t +typedef enum { + BAYER_METHOD_NEAREST = 0, + BAYER_METHOD_SIMPLE, + BAYER_METHOD_BILINEAR, + BAYER_METHOD_HQLINEAR, + BAYER_METHOD_DOWNSAMPLE_, + BAYER_METHOD_EDGESENSE, + BAYER_METHOD_VNG, + BAYER_METHOD_AHD, + + // Pangolin custom defines + BAYER_METHOD_NONE = 512, + BAYER_METHOD_DOWNSAMPLE, + BAYER_METHOD_DOWNSAMPLE_MONO +} bayer_method_t; + +// Enum to match libdc1394's dc1394_color_filter_t +typedef enum { + DC1394_COLOR_FILTER_RGGB = 512, + DC1394_COLOR_FILTER_GBRG, + DC1394_COLOR_FILTER_GRBG, + DC1394_COLOR_FILTER_BGGR +} color_filter_t; + +// Video class that debayers its video input using the given method. +class PANGOLIN_EXPORT DebayerVideo : + public VideoInterface, + public VideoFilterInterface, + public BufferAwareVideoInterface +{ +public: + DebayerVideo(std::unique_ptr& videoin, const std::vector &method, color_filter_t tile); + ~DebayerVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + std::vector& InputStreams(); + + static color_filter_t ColorFilterFromString(std::string str); + + static bayer_method_t BayerMethodFromString(std::string str); + + uint32_t AvailableFrames() const; + + bool DropNFrames(uint32_t n); + +protected: + void ProcessStreams(unsigned char* out, const unsigned char* in); + + std::unique_ptr src; + std::vector videoin; + std::vector streams; + + size_t size_bytes; + std::unique_ptr buffer; + + std::vector methods; + color_filter_t tile; + + picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/deinterlace.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/deinterlace.h new file mode 100644 index 0000000..4098ef3 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/deinterlace.h @@ -0,0 +1,62 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT DeinterlaceVideo + : public VideoInterface +{ +public: + DeinterlaceVideo(std::unique_ptr& videoin); + ~DeinterlaceVideo(); + + size_t SizeBytes() const; + + const std::vector& Streams() const; + + void Start(); + + void Stop(); + + bool GrabNext( unsigned char* image, bool wait = true ); + + bool GrabNewest( unsigned char* image, bool wait = true ); + +protected: + std::unique_ptr videoin; + std::vector streams; + unsigned char* buffer; +}; + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/depthsense.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/depthsense.h new file mode 100644 index 0000000..13a90c9 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/depthsense.h @@ -0,0 +1,171 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +// DepthSense SDK for SoftKinetic cameras from Creative +#include + +namespace pangolin +{ + +enum DepthSenseSensorType +{ + DepthSenseUnassigned = -1, + DepthSenseRgb = 0, + DepthSenseDepth +}; + +// Video class that outputs test video signal. +class PANGOLIN_EXPORT DepthSenseVideo : + public VideoInterface, public VideoPropertiesInterface +{ +public: + DepthSenseVideo(DepthSense::Device device, DepthSenseSensorType s1, DepthSenseSensorType s2, ImageDim dim1, ImageDim dim2, unsigned int fps1, unsigned int fps2, const Uri& uri); + ~DepthSenseVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::DeviceProperties() + const picojson::value& DeviceProperties() const { + return device_properties; + } + + //! Implement VideoInput::DeviceProperties() + const picojson::value& FrameProperties() const { + return frame_properties; + } +protected: + void onNewColorSample(DepthSense::ColorNode node, DepthSense::ColorNode::NewSampleReceivedData data); + void onNewDepthSample(DepthSense::DepthNode node, DepthSense::DepthNode::NewSampleReceivedData data); + + struct SensorConfig + { + DepthSenseSensorType type; + ImageDim dim; + unsigned int fps; + }; + + void UpdateParameters(const DepthSense::Node& node, const Uri& uri); + void ConfigureNodes(const Uri& uri); + void ConfigureDepthNode(const SensorConfig& sensorConfig, const Uri& uri); + void ConfigureColorNode(const SensorConfig& sensorConfig, const Uri& uri); + + double GetDeltaTime() const; + + std::vector streams; + picojson::value device_properties; + picojson::value frame_properties; + picojson::value* streams_properties; + + + DepthSense::Device device; + DepthSense::DepthNode g_dnode; + DepthSense::ColorNode g_cnode; + + unsigned char* fill_image; + + int depthmap_stream; + int rgb_stream; + + int gotDepth; + int gotColor; + std::mutex update_mutex; + std::condition_variable cond_image_filled; + std::condition_variable cond_image_requested; + + SensorConfig sensorConfig[2]; + + bool enableDepth; + bool enableColor; + double depthTs; + double colorTs; + + size_t size_bytes; +}; + +class DepthSenseContext +{ + friend class DepthSenseVideo; + +public: + // Singleton Instance + static DepthSenseContext& I(); + + DepthSenseVideo* GetDepthSenseVideo(size_t device_num, DepthSenseSensorType s1, DepthSenseSensorType s2, ImageDim dim1, ImageDim dim2, unsigned int fps1, unsigned int fps2, const Uri& uri); + +protected: + // Protected Constructor + DepthSenseContext(); + ~DepthSenseContext(); + + DepthSense::Context& Context(); + + void NewDeviceRunning(); + void DeviceClosing(); + + void StartNodes(); + void StopNodes(); + + void EventLoop(); + + void onDeviceConnected(DepthSense::Context context, DepthSense::Context::DeviceAddedData data); + void onDeviceDisconnected(DepthSense::Context context, DepthSense::Context::DeviceRemovedData data); + + DepthSense::Context g_context; + + std::thread event_thread; + bool is_running; + + int running_devices; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/ffmpeg.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/ffmpeg.h new file mode 100644 index 0000000..aeb0cf9 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/ffmpeg.h @@ -0,0 +1,207 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +extern "C" +{ + +// HACK for some versions of FFMPEG +#ifndef INT64_C +#define INT64_C(c) (c ## LL) +#define UINT64_C(c) (c ## ULL) +#endif + +#include +#include +#include +#include +} + +#ifndef HAVE_FFMPEG_AVPIXELFORMAT +# define AVPixelFormat PixelFormat +#endif + +namespace pangolin +{ + +class PANGOLIN_EXPORT FfmpegVideo : public VideoInterface +{ +public: + FfmpegVideo(const std::string filename, const std::string fmtout = "RGB24", const std::string codec_hint = "", bool dump_info = false, int user_video_stream = -1, ImageDim size = ImageDim(0,0)); + ~FfmpegVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + +protected: + void InitUrl(const std::string filename, const std::string fmtout = "RGB24", const std::string codec_hint = "", bool dump_info = false , int user_video_stream = -1, ImageDim size= ImageDim(0,0)); + + std::vector streams; + + SwsContext *img_convert_ctx; + AVFormatContext *pFormatCtx; + int videoStream; + int audioStream; + AVCodecContext *pVidCodecCtx; + AVCodecContext *pAudCodecCtx; + AVCodec *pVidCodec; + AVCodec *pAudCodec; + AVFrame *pFrame; + AVFrame *pFrameOut; + AVPacket packet; + int numBytesOut; + uint8_t *buffer; + AVPixelFormat fmtout; +}; + +enum FfmpegMethod +{ + FFMPEG_FAST_BILINEAR = 1, + FFMPEG_BILINEAR = 2, + FFMPEG_BICUBIC = 4, + FFMPEG_X = 8, + FFMPEG_POINT = 0x10, + FFMPEG_AREA = 0x20, + FFMPEG_BICUBLIN = 0x40, + FFMPEG_GAUSS = 0x80, + FFMPEG_SINC =0x100, + FFMPEG_LANCZOS =0x200, + FFMPEG_SPLINE =0x400 +}; + +class PANGOLIN_EXPORT FfmpegConverter : public VideoInterface +{ +public: + FfmpegConverter(std::unique_ptr& videoin, const std::string pixelfmtout = "RGB24", FfmpegMethod method = FFMPEG_POINT); + ~FfmpegConverter(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + +protected: + std::vector streams; + + struct ConvertContext + { + SwsContext* img_convert_ctx; + AVPixelFormat fmtsrc; + AVPixelFormat fmtdst; + AVFrame* avsrc; + AVFrame* avdst; + size_t w,h; + size_t src_buffer_offset; + size_t dst_buffer_offset; + + void convert(const unsigned char * src, unsigned char* dst); + + }; + + std::unique_ptr videoin; + std::unique_ptr input_buffer; + + std::vector converters; + //size_t src_buffer_size; + size_t dst_buffer_size; +}; + +#if (LIBAVFORMAT_VERSION_MAJOR > 55) || ((LIBAVFORMAT_VERSION_MAJOR == 55) && (LIBAVFORMAT_VERSION_MINOR >= 7)) +typedef AVCodecID CodecID; +#endif + +// Forward declaration +class FfmpegVideoOutputStream; + +class PANGOLIN_EXPORT FfmpegVideoOutput + : public VideoOutputInterface +{ + friend class FfmpegVideoOutputStream; +public: + FfmpegVideoOutput( const std::string& filename, int base_frame_rate, int bit_rate, bool flip = false ); + ~FfmpegVideoOutput(); + + const std::vector& Streams() const override; + + void SetStreams(const std::vector& streams, const std::string& uri, const picojson::value& properties) override; + + int WriteStreams(const unsigned char* data, const picojson::value& frame_properties) override; + + bool IsPipe() const override; + +protected: + void Initialise(std::string filename); + void StartStream(); + void Close(); + + std::string filename; + bool started; + AVFormatContext *oc; + std::vector streams; + std::vector strs; + + int frame_count; + + int base_frame_rate; + int bit_rate; + bool is_pipe; + bool flip; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/firewire.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/firewire.h new file mode 100644 index 0000000..a631a22 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/firewire.h @@ -0,0 +1,254 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include + +#ifndef _WIN32 +#include +#endif + + + +namespace pangolin +{ + +PANGOLIN_EXPORT +std::string Dc1394ColorCodingToString(dc1394color_coding_t coding); + +PANGOLIN_EXPORT +dc1394color_coding_t Dc1394ColorCodingFromString(std::string coding); + +PANGOLIN_EXPORT +void Dc1394ModeDetails(dc1394video_mode_t mode, unsigned& w, unsigned& h, std::string& format ); + +class PANGOLIN_EXPORT FirewireFrame +{ + friend class FirewireVideo; +public: + bool isValid() { return frame; } + unsigned char* Image() { return frame ? frame->image : 0; } + unsigned Width() const { return frame ? frame->size[0] : 0; } + unsigned Height() const { return frame ? frame->size[1] : 0; } + unsigned ImageBytes() const { return frame ? frame->image_bytes : 0; } + int FramesBehind() const { return frame ? frame->frames_behind : -1; } + unsigned Timestamp() const { return frame ? frame->timestamp : 0; } + int Id() const { return frame ? frame->id : -1; } +protected: + FirewireFrame(dc1394video_frame_t* frame) : frame(frame) {} + dc1394video_frame_t *frame; +}; + +struct PANGOLIN_EXPORT Guid +{ + Guid(uint64_t guid):guid(guid){} + uint64_t guid; +}; + +class PANGOLIN_EXPORT FirewireVideo : public VideoInterface +{ +public: + const static int MAX_FR = -1; + const static int EXT_TRIG = -1; + const static uint32_t GPIO_CTRL_PIN0 = 0x1110; + const static uint32_t GPIO_CTRL_PIN1 = 0x1120; + const static uint32_t GPIO_CTRL_PIN2 = 0x1130; + const static uint32_t GPIO_CTRL_PIN3 = 0x1140; + + FirewireVideo( + unsigned deviceid = 0, + dc1394video_mode_t video_mode = DC1394_VIDEO_MODE_640x480_RGB8, + dc1394framerate_t framerate = DC1394_FRAMERATE_30, + dc1394speed_t iso_speed = DC1394_ISO_SPEED_400, + int dma_buffers = 10 + ); + + FirewireVideo( + Guid guid, + dc1394video_mode_t video_mode = DC1394_VIDEO_MODE_640x480_RGB8, + dc1394framerate_t framerate = DC1394_FRAMERATE_30, + dc1394speed_t iso_speed = DC1394_ISO_SPEED_400, + int dma_buffers = 10 + ); + + FirewireVideo( + Guid guid, + dc1394video_mode_t video_mode, + float framerate, + uint32_t width, uint32_t height, + uint32_t left, uint32_t top, + dc1394speed_t iso_speed, + int dma_buffers, bool reset_at_boot=false + ); + + FirewireVideo( + unsigned deviceid, + dc1394video_mode_t video_mode, + float framerate, + uint32_t width, uint32_t height, + uint32_t left, uint32_t top, + dc1394speed_t iso_speed, + int dma_buffers, bool reset_at_boot=false + ); + + ~FirewireVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! (deprecated: use Streams[i].Width()) + //! Return image width + unsigned Width() const { return width; } + + //! (deprecated: use Streams[i].Height()) + //! Return image height + unsigned Height() const { return height; } + + //! Return object containing reference to image data within + //! DMA buffer. The FirewireFrame must be returned to + //! signal that it can be reused with a corresponding PutFrame() + FirewireFrame GetNext(bool wait = true); + + //! Return object containing reference to newest image data within + //! DMA buffer discarding old images. The FirewireFrame must be + //! returned to signal that it can be reused with a corresponding PutFrame() + FirewireFrame GetNewest(bool wait = true); + + //! Return FirewireFrame object. Data held by FirewireFrame is + //! invalidated on return. + void PutFrame(FirewireFrame& frame); + + //! return absolute shutter value + float GetShutterTime() const; + + //! set absolute shutter value + void SetShutterTime(float val); + + //! set auto shutter value + void SetAutoShutterTime(); + + //! return absolute gain value + float GetGain() const; + + //! set absolute gain value + void SetGain(float val); + + //! set auto gain value + void SetAutoGain(); + + //! return absolute brightness value + float GetBrightness() const; + + //! set absolute brightness value + void SetBrightness(float val); + + //! set auto brightness + void SetAutoBrightness(); + + //! return absolute gamma value + float GetGamma() const; + + //! return quantised shutter value + void SetShutterTimeQuant(int shutter); + + //! set the trigger to internal, i.e. determined by video mode + void SetInternalTrigger(); + + //! set the trigger to external + void SetExternalTrigger( + dc1394trigger_mode_t mode=DC1394_TRIGGER_MODE_0, + dc1394trigger_polarity_t polarity=DC1394_TRIGGER_ACTIVE_HIGH, + dc1394trigger_source_t source=DC1394_TRIGGER_SOURCE_0 + ); + + //! set a camera register + void SetRegister(uint64_t offset, uint32_t value); + + //! read camera register + uint32_t GetRegister(uint64_t offset); + + //! set a camera control register + void SetControlRegister(uint64_t offset, uint32_t value); + + //! read camera control register + uint32_t GetControlRegister(uint64_t offset); + +protected: + void init_stream_info(); + + void init_camera( + uint64_t guid, int dma_frames, + dc1394speed_t iso_speed, + dc1394video_mode_t video_mode, + dc1394framerate_t framerate + ); + + void init_format7_camera( + uint64_t guid, int dma_frames, + dc1394speed_t iso_speed, + dc1394video_mode_t video_mode, + float framerate, + uint32_t width, uint32_t height, + uint32_t left, uint32_t top, bool reset_at_boot + ); + + static int nearest_value(int value, int step, int min, int max); + static double bus_period_from_iso_speed(dc1394speed_t iso_speed); + + size_t frame_size_bytes; + std::vector streams; + + bool running; + dc1394camera_t *camera; + unsigned width, height, top, left; + //dc1394featureset_t features; + dc1394_t * d; + dc1394camera_list_t * list; + mutable dc1394error_t err; + +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/images.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/images.h new file mode 100644 index 0000000..2ba4e0e --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/images.h @@ -0,0 +1,121 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace pangolin +{ + +// Video class that outputs test video signal. +class PANGOLIN_EXPORT ImagesVideo : public VideoInterface, public VideoPlaybackInterface, public VideoPropertiesInterface +{ +public: + ImagesVideo(const std::string& wildcard_path); + ImagesVideo(const std::string& wildcard_path, const PixelFormat& raw_fmt, size_t raw_width, size_t raw_height); + + // Explicitly delete copy ctor and assignment operator. + // See http://stackoverflow.com/questions/29565299/how-to-use-a-vector-of-unique-pointers-in-a-dll-exported-class-with-visual-studi + // >> It appears adding __declspec(dllexport) forces the compiler to define the implicitly-declared copy constructor and copy assignment operator + ImagesVideo(const ImagesVideo&) = delete; + ImagesVideo& operator=(const ImagesVideo&) = delete; + + ~ImagesVideo(); + + /////////////////////////////////// + // Implement VideoInterface + + void Start() override; + + void Stop() override; + + size_t SizeBytes() const override; + + const std::vector& Streams() const override; + + bool GrabNext( unsigned char* image, bool wait = true ) override; + + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + /////////////////////////////////// + // Implement VideoPlaybackInterface + + size_t GetCurrentFrameId() const override; + + size_t GetTotalFrames() const override; + + size_t Seek(size_t frameid) override; + + /////////////////////////////////// + // Implement VideoPropertiesInterface + + const picojson::value& DeviceProperties() const override; + + const picojson::value& FrameProperties() const override; + +protected: + typedef std::vector Frame; + + const std::string& Filename(size_t frameNum, size_t channelNum) { + return filenames[channelNum][frameNum]; + } + + void PopulateFilenames(const std::string& wildcard_path); + + void PopulateFilenamesFromJson(const std::string& filename); + + bool LoadFrame(size_t i); + + void ConfigureStreamSizes(); + + std::vector streams; + size_t size_bytes; + + size_t num_files; + size_t num_channels; + size_t next_frame_id; + std::vector > filenames; + std::vector loaded; + + bool unknowns_are_raw; + PixelFormat raw_fmt; + size_t raw_width; + size_t raw_height; + + // Load any json properties if they are defined + picojson::value device_properties; + picojson::value json_frames; + picojson::value null_props; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/images_out.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/images_out.h new file mode 100644 index 0000000..ad6f662 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/images_out.h @@ -0,0 +1,60 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT ImagesVideoOutput : public VideoOutputInterface +{ +public: + ImagesVideoOutput(const std::string& image_folder, const std::string& json_file_out, const std::string &image_file_extension); + ~ImagesVideoOutput(); + + const std::vector& Streams() const override; + void SetStreams(const std::vector& streams, const std::string& uri, const picojson::value& device_properties) override; + int WriteStreams(const unsigned char* data, const picojson::value& frame_properties) override; + bool IsPipe() const override; + +protected: + std::vector streams; + std::string input_uri; + picojson::value device_properties; + picojson::value json_frames; + + size_t image_index; + std::string image_folder; + std::string image_file_extension; + std::ofstream file; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/join.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/join.h new file mode 100644 index 0000000..8eb383d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/join.h @@ -0,0 +1,78 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT JoinVideo + : public VideoInterface, public VideoFilterInterface +{ +public: + JoinVideo(std::vector> &src); + + ~JoinVideo(); + + // Explicitly delete copy ctor and assignment operator. + // See http://stackoverflow.com/questions/29565299/how-to-use-a-vector-of-unique-pointers-in-a-dll-exported-class-with-visual-studi + // >> It appears adding __declspec(dllexport) forces the compiler to define the implicitly-declared copy constructor and copy assignment operator + JoinVideo(const JoinVideo&) = delete; + JoinVideo& operator=(const JoinVideo&) = delete; + + size_t SizeBytes() const; + + const std::vector& Streams() const; + + void Start(); + + void Stop(); + + bool Sync(int64_t tolerance_us, double transfer_bandwidth_gbps = 0); + + bool GrabNext( unsigned char* image, bool wait = true ); + + bool GrabNewest( unsigned char* image, bool wait = true ); + + std::vector& InputStreams(); + +protected: + int64_t GetAdjustedCaptureTime(size_t src_index); + + std::vector> storage; + std::vector src; + std::vector streams; + size_t size_bytes; + + int64_t sync_tolerance_us; + int64_t transfer_bandwidth_bytes_per_us; +}; + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/merge.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/merge.h new file mode 100644 index 0000000..fd3cc07 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/merge.h @@ -0,0 +1,70 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +namespace pangolin +{ + +// Take N streams, and place them into one big buffer. +class PANGOLIN_EXPORT MergeVideo : public VideoInterface, public VideoFilterInterface +{ +public: + MergeVideo(std::unique_ptr& src, const std::vector& stream_pos, size_t w, size_t h); + ~MergeVideo(); + + void Start() override; + + void Stop() override; + + size_t SizeBytes() const override; + + const std::vector& Streams() const override; + + bool GrabNext( unsigned char* image, bool wait = true ) override; + + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + std::vector& InputStreams() override; + +protected: + void CopyBuffer(unsigned char* dst_bytes, unsigned char* src_bytes); + + std::unique_ptr src; + std::vector videoin; + std::unique_ptr buffer; + std::vector stream_pos; + + std::vector streams; + size_t size_bytes; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/mirror.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/mirror.h new file mode 100644 index 0000000..5d04054 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/mirror.h @@ -0,0 +1,96 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +enum MirrorOptions +{ + MirrorOptionsNone = 0, + MirrorOptionsFlipX, + MirrorOptionsFlipY, + MirrorOptionsFlipXY, + MirrorOptionsTranspose, + MirrorOptionsRotateCW, + MirrorOptionsRotateCCW, +}; + +// Video class that debayers its video input using the given method. +class PANGOLIN_EXPORT MirrorVideo : + public VideoInterface, + public VideoFilterInterface, + public BufferAwareVideoInterface +{ +public: + MirrorVideo(std::unique_ptr& videoin, const std::vector& flips); + ~MirrorVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! Implement VideoFilterInterface method + std::vector& InputStreams(); + + uint32_t AvailableFrames() const; + + bool DropNFrames(uint32_t n); + +protected: + void Process(unsigned char* image, const unsigned char* buffer); + + std::unique_ptr videoin; + std::vector inputs; + std::vector streams; + std::vector flips; + size_t size_bytes; + unsigned char* buffer; + + picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/openni.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/openni.h new file mode 100644 index 0000000..195f1d9 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/openni.h @@ -0,0 +1,72 @@ +#pragma once + +#include + +#include +#include + +// Workaround poor OpenNI Platform test on Linux before including XnCppWrapper.h +// See https://github.com/dennishamester/OpenNI/commit/ca99f6181234c682bba42a6ba +#ifdef _LINUX_ +#define linux 1 +#endif // _LINUX_ + +// OpenNI generates SO MANY warnings, we'll just disable all for this header(!) +// GCC and clang will listen to this pramga. +#ifndef _MSVC_ +#pragma GCC system_header +#endif +#include + +namespace pangolin +{ + +//! Interface to video capture sources +struct PANGOLIN_EXPORT OpenNiVideo : public VideoInterface +{ +public: + OpenNiVideo(OpenNiSensorType s1, OpenNiSensorType s2, ImageDim dim = ImageDim(640,480), int fps = 30); + ~OpenNiVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + void SetAutoExposure(bool enabled) + { +#if XN_MINOR_VERSION > 5 || (XN_MINOR_VERSION == 5 && XN_BUILD_VERSION >= 7) + if(imageNode.IsValid()) { + imageNode.GetAutoExposureCap().Set(enabled ? 1 : 0); + } +#else + throw pangolin::VideoException("SetAutoExposure Not supported for this version of OpenNI."); +#endif + } + +protected: + std::vector streams; + OpenNiSensorType sensor_type[2]; + + xn::Context context; + xn::DepthGenerator depthNode; + xn::ImageGenerator imageNode; + xn::IRGenerator irNode; + + size_t sizeBytes; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/openni2.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/openni2.h new file mode 100644 index 0000000..d3874aa --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/openni2.h @@ -0,0 +1,147 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Richard Newcombe + * 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace pangolin +{ +const int MAX_OPENNI2_STREAMS = 2 * ONI_MAX_SENSORS; + +//! Interface to video capture sources +struct OpenNi2Video : public VideoInterface, public VideoPropertiesInterface, public VideoPlaybackInterface +{ +public: + + // Open all RGB and Depth streams from all devices + OpenNi2Video(ImageDim dim=ImageDim(640,480), ImageRoi roi=ImageRoi(0,0,0,0), int fps=30); + + // Open streams specified + OpenNi2Video(std::vector& stream_modes); + + // Open openni file + OpenNi2Video(const std::string& filename); + + // Open openni file with certain params + OpenNi2Video(const std::string& filename, std::vector& stream_modes); + + void UpdateProperties(); + + void SetMirroring(bool enable); + void SetAutoExposure(bool enable); + void SetAutoWhiteBalance(bool enable); + void SetDepthCloseRange(bool enable); + void SetDepthHoleFilter(bool enable); + void SetDepthColorSyncEnabled(bool enable); + void SetFastCrop(bool enable); + void SetRegisterDepthToImage(bool enable); + void SetPlaybackSpeed(float speed); + void SetPlaybackRepeat(bool enabled); + + ~OpenNi2Video(); + + //! Implement VideoInput::Start() + void Start() override; + + //! Implement VideoInput::Stop() + void Stop() override; + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const override; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const override; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ) override; + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + //! Implement VideoPropertiesInterface::Properties() + const picojson::value& DeviceProperties() const override{ + return device_properties; + } + + //! Implement VideoPropertiesInterface::Properties() + const picojson::value& FrameProperties() const override{ + return frame_properties; + } + + //! Implement VideoPlaybackInterface::GetCurrentFrameId + size_t GetCurrentFrameId() const override; + + //! Implement VideoPlaybackInterface::GetTotalFrames + size_t GetTotalFrames() const override; + + //! Implement VideoPlaybackInterface::Seek + size_t Seek(size_t frameid) override; + + openni::VideoStream* GetVideoStream(int stream); + +protected: + void InitialiseOpenNI(); + int AddDevice(const std::string& device_uri); + void AddStream(const OpenNiStreamMode& mode); + void SetupStreamModes(); + void PrintOpenNI2Modes(openni::SensorType sensorType); + openni::VideoMode FindOpenNI2Mode(openni::Device &device, openni::SensorType sensorType, int width, int height, int fps, openni::PixelFormat fmt ); + + size_t numDevices; + size_t numStreams; + + openni::Device devices[ONI_MAX_SENSORS]; + OpenNiStreamMode sensor_type[ONI_MAX_SENSORS]; + + openni::VideoStream video_stream[ONI_MAX_SENSORS]; + openni::VideoFrameRef video_frame[ONI_MAX_SENSORS]; + + std::vector streams; + size_t sizeBytes; + + picojson::value device_properties; + picojson::value frame_properties; + picojson::value* streams_properties; + + bool use_depth; + bool use_ir; + bool use_rgb; + bool depth_to_color; + bool use_ir_and_rgb; + + size_t current_frame_index; + size_t total_frames; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/openni_common.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/openni_common.h new file mode 100644 index 0000000..c93183e --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/openni_common.h @@ -0,0 +1,153 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * 2015 Richard Newcombe + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include + +namespace pangolin +{ + +enum OpenNiSensorType +{ + OpenNiUnassigned = -1, + OpenNiRgb = 0, + OpenNiIr, + OpenNiDepth_1mm, + OpenNiDepth_1mm_Registered, + OpenNiDepth_100um, + OpenNiIr8bit, + OpenNiIr24bit, + OpenNiIrProj, + OpenNiIr8bitProj, + OpenNiGrey +}; + +struct PANGOLIN_EXPORT OpenNiStreamMode +{ + OpenNiStreamMode( + OpenNiSensorType sensor_type=OpenNiUnassigned, + ImageDim dim=ImageDim(640,480), ImageRoi roi=ImageRoi(0,0,0,0), int fps=30, int device=0 + ) + : sensor_type(sensor_type), dim(dim), roi(roi), fps(fps), device(device) + { + + } + + OpenNiSensorType sensor_type; + ImageDim dim; + ImageRoi roi; + int fps; + int device; +}; + +inline OpenNiSensorType openni_sensor(const std::string& str) +{ + if( !str.compare("grey") || !str.compare("gray") ) { + return OpenNiGrey; + }else if( !str.compare("rgb") ) { + return OpenNiRgb; + }else if( !str.compare("ir") ) { + return OpenNiIr; + }else if( !str.compare("depth1mm") || !str.compare("depth") ) { + return OpenNiDepth_1mm; + }else if( !str.compare("depth100um") ) { + return OpenNiDepth_100um; + }else if( !str.compare("depth_reg") || !str.compare("reg_depth")) { + return OpenNiDepth_1mm_Registered; + }else if( !str.compare("ir8") ) { + return OpenNiIr8bit; + }else if( !str.compare("ir24") ) { + return OpenNiIr24bit; + }else if( !str.compare("ir+") ) { + return OpenNiIrProj; + }else if( !str.compare("ir8+") ) { + return OpenNiIr8bitProj; + }else if( str.empty() ) { + return OpenNiUnassigned; + }else{ + throw pangolin::VideoException("Unknown OpenNi sensor", str ); + } +} + +// Find prefix character key +// Given arguments "depth!5:320x240@15", "!:@", would return map +// \0->"depth", !->"5", :->"320x240", @->"15" +inline std::map GetTokenSplits(const std::string& str, const std::string& tokens) +{ + std::map splits; + + char last_token = 0; + size_t last_start = 0; + for(unsigned int i=0; i> (std::istream &is, OpenNiStreamMode& fmt) +{ + std::string str; + is >> str; + + std::map splits = GetTokenSplits(str, "!:@#"); + + if(splits.count(0)) { + fmt.sensor_type = openni_sensor(splits[0]); + } + + if(splits.count('@')) { + fmt.fps = pangolin::Convert::Do(splits['@']); + } + + if(splits.count(':')) { + fmt.dim = pangolin::Convert::Do(splits[':']); + } + + if(splits.count('!')) { + fmt.device = pangolin::Convert::Do(splits['!']); + } + + if(splits.count('#')) { + fmt.roi = pangolin::Convert::Do(splits['#']); + } + + return is; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/pack.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/pack.h new file mode 100644 index 0000000..3bfb1f8 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/pack.h @@ -0,0 +1,84 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +// Video class that packs its video input using the given method. +class PANGOLIN_EXPORT PackVideo : + public VideoInterface, + public VideoFilterInterface, + public BufferAwareVideoInterface +{ +public: + PackVideo(std::unique_ptr& videoin, PixelFormat new_fmt); + ~PackVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! Implement VideoFilterInterface method + std::vector& InputStreams(); + + uint32_t AvailableFrames() const; + + bool DropNFrames(uint32_t n); + +protected: + void Process(unsigned char* image, const unsigned char* buffer); + + std::unique_ptr src; + std::vector videoin; + std::vector streams; + size_t size_bytes; + unsigned char* buffer; + + picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/pango.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/pango.h new file mode 100644 index 0000000..f6fecbe --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/pango.h @@ -0,0 +1,104 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT PangoVideo + : public VideoInterface, public VideoPropertiesInterface, public VideoPlaybackInterface +{ +public: + PangoVideo(const std::string& filename, std::shared_ptr playback_session); + ~PangoVideo(); + + // Implement VideoInterface + + size_t SizeBytes() const override; + + const std::vector& Streams() const override; + + void Start() override; + + void Stop() override; + + bool GrabNext( unsigned char* image, bool wait = true ) override; + + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + // Implement VideoPropertiesInterface + const picojson::value& DeviceProperties() const override { + if (-1 == _src_id) throw std::runtime_error("Not initialised"); + return _device_properties; + } + + const picojson::value& FrameProperties() const override { + return _frame_properties; + } + + // Implement VideoPlaybackInterface + + size_t GetCurrentFrameId() const override; + + size_t GetTotalFrames() const override; + + size_t Seek(size_t frameid) override; + + std::string GetSourceUri(); + +private: + void HandlePipeClosed(); + +protected: + int FindPacketStreamSource(); + void SetupStreams(const PacketStreamSource& src); + + const std::string _filename; + std::shared_ptr _playback_session; + std::shared_ptr _reader; + SyncTimeEventPromise _event_promise; + int _src_id; + const PacketStreamSource* _source; + + size_t _size_bytes; + bool _fixed_size; + std::vector _streams; + std::vector stream_decoder; + picojson::value _device_properties; + picojson::value _frame_properties; + std::string _source_uri; + + Registration session_seek; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/pango_video_output.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/pango_video_output.h new file mode 100644 index 0000000..a986a70 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/pango_video_output.h @@ -0,0 +1,70 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT PangoVideoOutput : public VideoOutputInterface +{ +public: + PangoVideoOutput(const std::string& filename, size_t buffer_size_bytes, const std::map &stream_encoder_uris); + ~PangoVideoOutput(); + + const std::vector& Streams() const override; + void SetStreams(const std::vector& streams, const std::string& uri, const picojson::value& device_properties) override; + int WriteStreams(const unsigned char* data, const picojson::value& frame_properties) override; + bool IsPipe() const override; + +protected: +// void WriteHeader(); + + std::vector streams; + std::string input_uri; + const std::string filename; + picojson::value device_properties; + + PacketStreamWriter packetstream; + size_t packetstream_buffer_size_bytes; + int packetstreamsrcid; + size_t total_frame_size; + bool is_pipe; + + bool fixed_size; + std::map stream_encoder_uris; + std::vector stream_encoders; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/pleora.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/pleora.h new file mode 100644 index 0000000..4b45744 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/pleora.h @@ -0,0 +1,196 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2015 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace pangolin +{ + +struct GrabbedBuffer { + + inline GrabbedBuffer(PvBuffer* b,PvResult r,bool v) + : buff(b), res(r), valid(v) + { + } + + PvBuffer* buff; + PvResult res; + bool valid; + +}; + +typedef std::list GrabbedBufferList; + +typedef std::list BufferList; + +class PANGOLIN_EXPORT PleoraVideo : public VideoInterface, public VideoPropertiesInterface, + public BufferAwareVideoInterface, public GenicamVideoInterface +{ +public: + + static const size_t DEFAULT_BUFFER_COUNT = 30; + + PleoraVideo(const Params& p); + + ~PleoraVideo(); + + void Start(); + + void Stop(); + + size_t SizeBytes() const; + + const std::vector& Streams() const; + + bool GrabNext( unsigned char* image, bool wait = true ); + + bool GrabNewest( unsigned char* image, bool wait = true ); + + std::string GetParameter(const std::string& name); + + void SetParameter(const std::string& name, const std::string& value); + + void SetGain(int64_t val); + + int64_t GetGain(); + + void SetAnalogBlackLevel(int64_t val); + + int64_t GetAnalogBlackLevel(); + + void SetExposure(double val); + + double GetExposure(); + + void SetGamma(double val); + + double GetGamma(); + + + + void SetupTrigger(bool triggerActive, int64_t triggerSource, int64_t acquisitionMode); + + const picojson::value& DeviceProperties() const { + return device_properties; + } + + const picojson::value& FrameProperties() const { + return frame_properties; + } + + uint32_t AvailableFrames() const; + + bool DropNFrames(uint32_t n); + +protected: + + void InitDevice(const char *model_name, const char *serial_num, size_t index); + + void DeinitDevice(); + + void SetDeviceParams(Params& p); + + void InitStream(); + + void DeinitStream(); + + void InitPangoStreams(); + + void InitPangoDeviceProperties(); + + void InitBuffers(size_t buffer_count); + + void DeinitBuffers(); + + template + T DeviceParam(const char* name); + + template + bool SetDeviceParam(const char* name, T val); + + template + T StreamParam(const char* name); + + template + bool SetStreamParam(const char* name, T val); + + bool ParseBuffer(PvBuffer* lBuffer, unsigned char* image); + + void RetriveAllAvailableBuffers(uint32_t timeout); + + std::vector streams; + picojson::value device_properties; + picojson::value frame_properties; + + size_t size_bytes; + + // Pleora handles + PvSystem* lPvSystem; + const PvDeviceInfo* lDeviceInfo; + PvDevice* lDevice; + PvStream* lStream; + + // Genicam device parameters + PvGenParameterArray* lDeviceParams; + PvGenCommand* lStart; + PvGenCommand* lStop; + + PvGenInteger* lAnalogGain; + PvGenInteger* lAnalogBlackLevel; + PvGenFloat* lExposure; + PvGenFloat* lGamma; + PvGenEnum* lAquisitionMode; + PvGenEnum* lTriggerSource; + PvGenEnum* lTriggerMode; + PvGenFloat* lTemperatureCelcius; + bool getTemp; + + // Genicam stream parameters + PvGenParameterArray* lStreamParams; + + BufferList lBufferList; + GrabbedBufferList lGrabbedBuffList; + uint32_t validGrabbedBuffers; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/pvn.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/pvn.h new file mode 100644 index 0000000..8e47e54 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/pvn.h @@ -0,0 +1,77 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT PvnVideo : public VideoInterface +{ +public: + PvnVideo(const std::string& filename, bool realtime = false); + ~PvnVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + +protected: + int frames; + std::ifstream file; + + std::vector streams; + size_t frame_size_bytes; + + bool realtime; + pangolin::basetime frame_interval; + pangolin::basetime last_frame; + + void ReadFileHeader(); +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/realsense.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/realsense.h new file mode 100644 index 0000000..064bc7a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/realsense.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +#include + +#include + +namespace rs { +class context; +class device; +} + +namespace pangolin +{ + +//! Interface to video capture sources +struct RealSenseVideo : public VideoInterface, public VideoPropertiesInterface, public VideoPlaybackInterface +{ +public: + + // Open all RGB and Depth streams from all devices + RealSenseVideo(ImageDim dim=ImageDim(640,480), int fps=30); + + // Open streams specified + // TODO + //RealSenseVideo(std::vector& stream_modes); + + ~RealSenseVideo(); + + //! Implement VideoInput::Start() + void Start() override; + + //! Implement VideoInput::Stop() + void Stop() override; + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const override; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const override; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ) override; + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + //! Implement VideoPropertiesInterface::Properties() + const picojson::value& DeviceProperties() const override { + return device_properties; + } + + //! Implement VideoPropertiesInterface::Properties() + const picojson::value& FrameProperties() const override { + return frame_properties; + } + + //! Implement VideoPlaybackInterface::GetCurrentFrameId + size_t GetCurrentFrameId() const override; + + //! Implement VideoPlaybackInterface::GetTotalFrames + size_t GetTotalFrames() const override; + + //! Implement VideoPlaybackInterface::Seek + size_t Seek(size_t frameid) override; + +protected: + size_t sizeBytes; + + std::vector streams; + + picojson::value device_properties; + picojson::value frame_properties; + picojson::value* streams_properties; + + size_t current_frame_index; + size_t total_frames; + + rs::context* ctx_; + std::vector devs_; + + ImageDim dim_; + size_t fps_; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/realsense2.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/realsense2.h new file mode 100644 index 0000000..589f73c --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/realsense2.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +#include + +#include + +namespace rs2 { +class pipeline; +class config; +} + +namespace pangolin +{ + +//! Interface to video capture sources +struct RealSense2Video : public VideoInterface, public VideoPropertiesInterface, public VideoPlaybackInterface +{ +public: + + // Open all RGB and Depth streams from all devices + RealSense2Video(ImageDim dim=ImageDim(640,480), int fps=30); + + // Open streams specified + // TODO + //RealSense2Video(std::vector& stream_modes); + + ~RealSense2Video(); + + //! Implement VideoInput::Start() + void Start() override; + + //! Implement VideoInput::Stop() + void Stop() override; + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const override; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const override; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ) override; + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + //! Implement VideoPropertiesInterface::Properties() + const picojson::value& DeviceProperties() const override { + return device_properties; + } + + //! Implement VideoPropertiesInterface::Properties() + const picojson::value& FrameProperties() const override { + return frame_properties; + } + + //! Implement VideoPlaybackInterface::GetCurrentFrameId + size_t GetCurrentFrameId() const override; + + //! Implement VideoPlaybackInterface::GetTotalFrames + size_t GetTotalFrames() const override; + + //! Implement VideoPlaybackInterface::Seek + size_t Seek(size_t frameid) override; + +protected: + size_t sizeBytes; + + std::vector streams; + + picojson::value device_properties; + picojson::value frame_properties; + picojson::value* streams_properties; + + size_t current_frame_index; + size_t total_frames; + + rs2::pipeline* pipe; + rs2::config* cfg; + + ImageDim dim_; + size_t fps_; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/shared_memory.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/shared_memory.h new file mode 100644 index 0000000..66f27dc --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/shared_memory.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace pangolin +{ + +class SharedMemoryVideo : public VideoInterface +{ +public: + SharedMemoryVideo(size_t w, size_t h, std::string pix_fmt, + const std::shared_ptr& shared_memory, + const std::shared_ptr& buffer_full); + ~SharedMemoryVideo(); + + size_t SizeBytes() const; + const std::vector& Streams() const; + void Start(); + void Stop(); + bool GrabNext(unsigned char *image, bool wait); + bool GrabNewest(unsigned char *image, bool wait); + +private: + PixelFormat _fmt; + size_t _frame_size; + std::vector _streams; + std::shared_ptr _shared_memory; + std::shared_ptr _buffer_full; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/shift.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/shift.h new file mode 100644 index 0000000..ed7f510 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/shift.h @@ -0,0 +1,73 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +// Video class that debayers its video input using the given method. +class PANGOLIN_EXPORT ShiftVideo : public VideoInterface, public VideoFilterInterface +{ +public: + ShiftVideo(std::unique_ptr& videoin, PixelFormat new_fmt, int shift_right_bits = 0, unsigned int mask = 0xFFFF); + ~ShiftVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + std::vector& InputStreams(); + +protected: + std::unique_ptr src; + std::vector videoin; + std::vector streams; + size_t size_bytes; + unsigned char* buffer; + int shift_right_bits; + unsigned int mask; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/split.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/split.h new file mode 100644 index 0000000..a567458 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/split.h @@ -0,0 +1,65 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT SplitVideo + : public VideoInterface, public VideoFilterInterface +{ +public: + SplitVideo(std::unique_ptr& videoin, const std::vector& streams); + + ~SplitVideo(); + + size_t SizeBytes() const; + + const std::vector& Streams() const; + + void Start(); + + void Stop(); + + bool GrabNext( unsigned char* image, bool wait = true ); + + bool GrabNewest( unsigned char* image, bool wait = true ); + + std::vector& InputStreams(); + +protected: + std::unique_ptr src; + std::vector videoin; + std::vector streams; +}; + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/teli.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/teli.h new file mode 100644 index 0000000..e0f851d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/teli.h @@ -0,0 +1,118 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2015 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace pangolin +{ + +// Video class that outputs test video signal. +class PANGOLIN_EXPORT TeliVideo : public VideoInterface, public VideoPropertiesInterface, + public BufferAwareVideoInterface, public GenicamVideoInterface +{ +public: + TeliVideo(const Params &p); + ~TeliVideo(); + + Params OpenCameraAndGetRemainingParameters(Params ¶ms); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + inline Teli::CAM_HANDLE GetCameraHandle() { + return cam; + } + + inline Teli::CAM_STRM_HANDLE GetCameraStreamHandle() { + return strm; + } + + bool GetParameter(const std::string& name, std::string& result); + + bool SetParameter(const std::string& name, const std::string& value); + + //! Returns number of available frames + uint32_t AvailableFrames() const; + + //! Drops N frames in the queue starting from the oldest + //! returns false if less than n frames arae available + bool DropNFrames(uint32_t n); + + //! Access JSON properties of device + const picojson::value& DeviceProperties() const; + + //! Access JSON properties of most recently captured frame + const picojson::value& FrameProperties() const; + + void PopulateEstimatedCenterCaptureTime(pangolin::basetime host_reception_time); + +protected: + void Initialise(); + void InitPangoDeviceProperties(); + void SetDeviceParams(const Params &p); + void SetNodeValStr(Teli::CAM_HANDLE cam, Teli::CAM_NODE_HANDLE node, std::string node_str, std::string val_str); + + std::vector streams; + size_t size_bytes; + + Teli::CAM_HANDLE cam; + Teli::CAM_STRM_HANDLE strm; + +#ifdef _WIN_ + HANDLE hStrmCmpEvt; +#endif +#ifdef _LINUX_ + Teli::SIGNAL_HANDLE hStrmCmpEvt; +#endif + double transfer_bandwidth_gbps; + int exposure_us; + picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/test.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/test.h new file mode 100644 index 0000000..02646f6 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/test.h @@ -0,0 +1,66 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +// Video class that outputs test video signal. +class PANGOLIN_EXPORT TestVideo : public VideoInterface +{ +public: + TestVideo(size_t w, size_t h, size_t n, std::string pix_fmt); + ~TestVideo(); + + //! Implement VideoInput::Start() + void Start() override; + + //! Implement VideoInput::Stop() + void Stop() override; + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const override; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const override; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ) override; + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ) override; + +protected: + std::vector streams; + size_t size_bytes; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/thread.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/thread.h new file mode 100644 index 0000000..ddd0242 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/thread.h @@ -0,0 +1,112 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin +{ + + +// Video class that creates a thread that keeps pulling frames and processing from its children. +class PANGOLIN_EXPORT ThreadVideo : public VideoInterface, public VideoPropertiesInterface, + public BufferAwareVideoInterface, public VideoFilterInterface +{ +public: + ThreadVideo(std::unique_ptr& videoin, size_t num_buffers); + ~ThreadVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + const picojson::value& DeviceProperties() const; + + const picojson::value& FrameProperties() const; + + uint32_t AvailableFrames() const; + + bool DropNFrames(uint32_t n); + + void operator()(); + + std::vector& InputStreams(); + +protected: + struct GrabResult + { + GrabResult(const size_t buffer_size) + : return_status(false), + buffer(new unsigned char[buffer_size]) + { + } + + // No copy constructor. + GrabResult(const GrabResult& o) = delete; + + // Default move constructor + GrabResult(GrabResult&& o) = default; + + bool return_status; + std::unique_ptr buffer; + picojson::value frame_properties; + }; + + std::unique_ptr src; + std::vector videoin; + + bool quit_grab_thread; + FixSizeBuffersQueue queue; + + std::condition_variable cv; + std::mutex cvMtx; + std::thread grab_thread; + + mutable picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/truncate.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/truncate.h new file mode 100644 index 0000000..cfdd3c0 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/truncate.h @@ -0,0 +1,71 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT TruncateVideo + : public VideoInterface, public VideoFilterInterface +{ +public: + TruncateVideo(std::unique_ptr& videoin, size_t begin, size_t end); + + ~TruncateVideo(); + + size_t SizeBytes() const; + + const std::vector& Streams() const; + + void Start(); + + void Stop(); + + bool GrabNext( unsigned char* image, bool wait = true ); + + bool GrabNewest( unsigned char* image, bool wait = true ); + + std::vector& InputStreams(); + +protected: + std::unique_ptr src; + std::vector videoin; + std::vector streams; + + size_t begin; + size_t end; + size_t next_frame_to_grab; + + inline VideoPlaybackInterface* GetVideoPlaybackInterface(){ return dynamic_cast(src.get()); } +}; + + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/unpack.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/unpack.h new file mode 100644 index 0000000..4f0826c --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/unpack.h @@ -0,0 +1,84 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2014 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +// Video class that debayers its video input using the given method. +class PANGOLIN_EXPORT UnpackVideo : + public VideoInterface, + public VideoFilterInterface, + public BufferAwareVideoInterface +{ +public: + UnpackVideo(std::unique_ptr& videoin, PixelFormat new_fmt); + ~UnpackVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! Implement VideoFilterInterface method + std::vector& InputStreams(); + + uint32_t AvailableFrames() const; + + bool DropNFrames(uint32_t n); + +protected: + void Process(unsigned char* image, const unsigned char* buffer); + + std::unique_ptr src; + std::vector videoin; + std::vector streams; + size_t size_bytes; + unsigned char* buffer; + + picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/uvc.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/uvc.h new file mode 100644 index 0000000..148a6f7 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/uvc.h @@ -0,0 +1,115 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include + +#ifdef _MSC_VER +// Define missing timeval struct +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; +#endif // _MSC_VER + +#include + +namespace pangolin +{ + +class PANGOLIN_EXPORT UvcVideo : public VideoInterface, public VideoUvcInterface, public VideoPropertiesInterface +{ +public: + UvcVideo(int vendor_id, int product_id, const char* sn, int deviceid, int width, int height, int fps); + ~UvcVideo(); + + void InitDevice(int vid, int pid, const char* sn, int deviceid, int width, int height, int fps); + void DeinitDevice(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! Implement VideoUvcInterface::GetCtrl() + int IoCtrl(uint8_t unit, uint8_t ctrl, unsigned char* data, int len, UvcRequestCode req_code); + + //! Implement VideoUvcInterface::GetExposure() + bool GetExposure(int& exp_us); + + //! Implement VideoUvcInterface::SetExposure() + bool SetExposure(int exp_us); + + //! Implement VideoUvcInterface::GetGain() + bool GetGain(float& gain); + + //! Implement VideoUvcInterface::SetGain() + bool SetGain(float gain); + + //! Access JSON properties of device + const picojson::value& DeviceProperties() const; + + //! Access JSON properties of most recently captured frame + const picojson::value& FrameProperties() const; + +protected: + void InitPangoDeviceProperties(); + static uvc_error_t FindDevice( + uvc_context_t *ctx, uvc_device_t **dev, + int vid, int pid, const char *sn, int device_id); + + std::vector streams; + size_t size_bytes; + + uvc_context* ctx_; + uvc_device* dev_; + uvc_device_handle* devh_; + uvc_stream_handle* strm_; + uvc_stream_ctrl_t ctrl_; + uvc_frame_t* frame_; + picojson::value device_properties; + picojson::value frame_properties; + bool is_streaming; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/uvc_mediafoundation.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/uvc_mediafoundation.h new file mode 100644 index 0000000..dfa6f12 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/uvc_mediafoundation.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include + +struct IMFActivate; +struct IMFMediaSource; +struct IMFSourceReader; +struct IBaseFilter; +struct IKsControl; + +namespace pangolin +{ + +class PANGOLIN_EXPORT UvcMediaFoundationVideo + : public pangolin::VideoInterface, public pangolin::VideoUvcInterface, public pangolin::VideoPropertiesInterface +{ + public: + UvcMediaFoundationVideo(int vendorId, int productId, int deviceId, size_t width, size_t height, int fps); + ~UvcMediaFoundationVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext(unsigned char* image, bool wait = true); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest(unsigned char* image, bool wait = true); + + //! Implement VideoUvcInterface::GetCtrl() + int IoCtrl(uint8_t unit, uint8_t ctrl, unsigned char* data, int len, pangolin::UvcRequestCode req_code); + + //! Implement VideoUvcInterface::GetExposure() + bool GetExposure(int& exp_us); + + //! Implement VideoUvcInterface::SetExposure() + bool SetExposure(int exp_us); + + //! Implement VideoUvcInterface::GetGain() + bool GetGain(float& gain); + + //! Implement VideoUvcInterface::SetGain() + bool SetGain(float gain); + + //! Access JSON properties of device + const picojson::value& DeviceProperties() const; + + //! Access JSON properties of most recently captured frame + const picojson::value& FrameProperties() const; + + protected: + bool FindDevice(int vendorId, int productId, int deviceId); + void InitDevice(size_t width, size_t height, int fps); + void DeinitDevice(); + + static bool DeviceMatches(const std::wstring& symLink, int vendorId, int productId); + static bool SymLinkIDMatches(const std::wstring& symLink, const wchar_t* idStr, int id); + + std::vector streams; + size_t size_bytes; + + IMFMediaSource* mediaSource; + IMFSourceReader* sourceReader; + IBaseFilter* baseFilter; + IKsControl* ksControl; + DWORD ksControlNodeId; + + picojson::value device_properties; + picojson::value frame_properties; +}; +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/drivers/v4l.h b/Thirdparty/Pangolin/include/pangolin/video/drivers/v4l.h new file mode 100644 index 0000000..a2ed55a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/drivers/v4l.h @@ -0,0 +1,128 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace pangolin +{ + +typedef enum { + IO_METHOD_READ, + IO_METHOD_MMAP, + IO_METHOD_USERPTR, +} io_method; + +struct buffer { + void* start; + size_t length; +}; + +class PANGOLIN_EXPORT V4lVideo : public VideoInterface, public VideoUvcInterface, public VideoPropertiesInterface +{ +public: + V4lVideo(const char* dev_name, io_method io = IO_METHOD_MMAP, unsigned iwidth=0, unsigned iheight=0); + ~V4lVideo(); + + //! Implement VideoInput::Start() + void Start(); + + //! Implement VideoInput::Stop() + void Stop(); + + //! Implement VideoInput::SizeBytes() + size_t SizeBytes() const; + + //! Implement VideoInput::Streams() + const std::vector& Streams() const; + + //! Implement VideoInput::GrabNext() + bool GrabNext( unsigned char* image, bool wait = true ); + + //! Implement VideoInput::GrabNewest() + bool GrabNewest( unsigned char* image, bool wait = true ); + + //! Implement VideoUvcInterface::IoCtrl() + int IoCtrl(uint8_t unit, uint8_t ctrl, unsigned char* data, int len, UvcRequestCode req_code); + + bool GetExposure(int& exp_us); + + bool SetExposure(int exp_us); + + bool GetGain(float& gain); + + bool SetGain(float gain); + + int GetFileDescriptor() const{ + return fd; + } + + //! Access JSON properties of device + const picojson::value& DeviceProperties() const; + + //! Access JSON properties of most recently captured frame + const picojson::value& FrameProperties() const; + +protected: + void InitPangoDeviceProperties(); + + + int ReadFrame(unsigned char* image); + void Mainloop(); + + void init_read(unsigned int buffer_size); + void init_mmap(const char* dev_name); + void init_userp(const char* dev_name, unsigned int buffer_size); + + void init_device(const char* dev_name, unsigned iwidth, unsigned iheight, unsigned ifps, unsigned v4l_format = V4L2_PIX_FMT_YUYV, v4l2_field field = V4L2_FIELD_INTERLACED); + void uninit_device(); + + void open_device(const char* dev_name); + void close_device(); + + std::vector streams; + + io_method io; + int fd; + buffer* buffers; + unsigned int n_buffers; + bool running; + unsigned width; + unsigned height; + float fps; + size_t image_size; + + picojson::value device_properties; + picojson::value frame_properties; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/iostream_operators.h b/Thirdparty/Pangolin/include/pangolin/video/iostream_operators.h new file mode 100644 index 0000000..600e06e --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/iostream_operators.h @@ -0,0 +1,132 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2015 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace pangolin +{ + +struct PANGOLIN_EXPORT Point +{ + inline Point() : x(0), y(0) {} + inline Point(size_t x, size_t y) : x(x), y(y) {} + size_t x; + size_t y; +}; + +typedef Point ImageDim; + +struct PANGOLIN_EXPORT ImageRoi +{ + inline ImageRoi() : x(0), y(0), w(0), h(0) {} + inline ImageRoi(size_t x, size_t y, size_t w, size_t h) : x(x), y(y), w(w), h(h) {} + size_t x; size_t y; + size_t w; size_t h; +}; + +inline std::istream& operator>> (std::istream &is, ImageDim &dim) +{ + if(std::isdigit(is.peek()) ) { + // Expect 640x480, 640*480, ... + is >> dim.x; is.get(); is >> dim.y; + }else{ + // Expect 'VGA', 'QVGA', etc + std::string sdim; + is >> sdim; + ToUpper(sdim); + + if( !sdim.compare("QQVGA") ) { + dim = ImageDim(160,120); + }else if( !sdim.compare("HQVGA") ) { + dim = ImageDim(240,160); + }else if( !sdim.compare("QVGA") ) { + dim = ImageDim(320,240); + }else if( !sdim.compare("WQVGA") ) { + dim = ImageDim(360,240); + }else if( !sdim.compare("HVGA") ) { + dim = ImageDim(480,320); + }else if( !sdim.compare("VGA") ) { + dim = ImageDim(640,480); + }else if( !sdim.compare("WVGA") ) { + dim = ImageDim(720,480); + }else if( !sdim.compare("SVGA") ) { + dim = ImageDim(800,600); + }else if( !sdim.compare("DVGA") ) { + dim = ImageDim(960,640); + }else if( !sdim.compare("WSVGA") ) { + dim = ImageDim(1024,600); + }else{ + throw VideoException("Unrecognised image-size string."); + } + } + return is; +} + +inline std::istream& operator>> (std::istream &is, ImageRoi &roi) +{ + is >> roi.x; is.get(); is >> roi.y; is.get(); + is >> roi.w; is.get(); is >> roi.h; + return is; +} + +inline std::istream& operator>> (std::istream &is, PixelFormat& fmt) +{ + std::string sfmt; + is >> sfmt; + fmt = PixelFormatFromString(sfmt); + return is; +} + +inline std::istream& operator>> (std::istream &is, Image& img) +{ + size_t offset; + is >> offset; is.get(); + img.ptr = (unsigned char*)(offset); + is >> img.w; is.get(); + is >> img.h; is.get(); + is >> img.pitch; + return is; +} + +inline std::istream& operator>> (std::istream &is, StreamInfo &stream) +{ + PixelFormat fmt; + Image img_offset; + is >> img_offset; is.get(); + is >> fmt; + stream = StreamInfo(fmt, img_offset); + return is; +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/stream_encoder_factory.h b/Thirdparty/Pangolin/include/pangolin/video/stream_encoder_factory.h new file mode 100644 index 0000000..b6f7efe --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/stream_encoder_factory.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include + +namespace pangolin { + +using ImageEncoderFunc = std::function&)>; +using ImageDecoderFunc = std::function; + +class StreamEncoderFactory +{ +public: + static StreamEncoderFactory& I(); + + ImageEncoderFunc GetEncoder(const std::string& encoder_spec, const PixelFormat& fmt); + + ImageDecoderFunc GetDecoder(const std::string& encoder_spec, const PixelFormat& fmt); +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/stream_info.h b/Thirdparty/Pangolin/include/pangolin/video/stream_info.h new file mode 100644 index 0000000..d141d7a --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/stream_info.h @@ -0,0 +1,100 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin { + +class PANGOLIN_EXPORT StreamInfo +{ +public: + inline StreamInfo() + : fmt(PixelFormatFromString("GRAY8")) {} + + inline StreamInfo(PixelFormat fmt, const Image img_offset ) + : fmt(fmt), img_offset(img_offset) {} + + inline StreamInfo(PixelFormat fmt, size_t w, size_t h, size_t pitch, unsigned char* offset = 0) + : fmt(fmt), img_offset(offset,w,h,pitch) {} + + //! Format representing how image is laid out in memory + inline const PixelFormat &PixFormat() const { return fmt; } + + //! Image width in pixels + inline size_t Width() const { return img_offset.w; } + + //! Image height in pixels + inline size_t Height() const { return img_offset.h; } + + inline double Aspect() const { return (double)Width() / (double)Height(); } + + //! Pitch: Number of bytes between one image row and the next + inline size_t Pitch() const { return img_offset.pitch; } + + //! Number of contiguous bytes in memory that the image occupies + inline size_t RowBytes() const { + // Row size without padding + return (fmt.bpp*img_offset.w)/8; + } + + //! Returns true iff image contains padding or stridded access + //! This implies that the image data is not contiguous in memory. + inline bool IsPitched() const { + return Pitch() != RowBytes(); + } + + //! Number of contiguous bytes in memory that the image occupies + inline size_t SizeBytes() const { + return (img_offset.h-1) * img_offset.pitch + RowBytes(); + } + + //! Offset in bytes relative to start of frame buffer + inline unsigned char* Offset() const { return img_offset.ptr; } + + //! Return Image wrapper around raw base pointer + inline Image StreamImage(unsigned char* base_ptr) const { + Image img = img_offset; + img.ptr += (size_t)base_ptr; + return img; + } + + //! Return Image wrapper around raw base pointer + inline const Image StreamImage(const unsigned char* base_ptr) const { + Image img = img_offset; + img.ptr += (size_t)base_ptr; + return img; + } + +protected: + PixelFormat fmt; + Image img_offset; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/video.h b/Thirdparty/Pangolin/include/pangolin/video/video.h new file mode 100644 index 0000000..46e982d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video.h @@ -0,0 +1,261 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +// Pangolin video supports various cameras and file formats through +// different 3rd party libraries. +// +// Video URI's take the following form: +// scheme:[param1=value1,param2=value2,...]//device +// +// scheme = file | files | pango | shmem | dc1394 | uvc | v4l | openni2 | +// openni | depthsense | pleora | teli | mjpeg | test | +// thread | convert | debayer | split | join | shift | mirror | unpack +// +// file/files - read one or more streams from image file(s) / video +// e.g. "files://~/data/dataset/img_*.jpg" +// e.g. "files://~/data/dataset/img_[left,right]_*.pgm" +// e.g. "files:///home/user/sequence/foo%03d.jpeg" +// +// e.g. "file:[fmt=GRAY8,size=640x480]///home/user/raw_image.bin" +// e.g. "file:[realtime=1]///home/user/video/movie.pango" +// e.g. "file:[stream=1]///home/user/video/movie.avi" +// +// dc1394 - capture video through a firewire camera +// e.g. "dc1394:[fmt=RGB24,size=640x480,fps=30,iso=400,dma=10]//0" +// e.g. "dc1394:[fmt=FORMAT7_1,size=640x480,pos=2+2,iso=400,dma=10]//0" +// e.g. "dc1394:[fmt=FORMAT7_3,deinterlace=1]//0" +// +// v4l - capture video from a Video4Linux (USB) camera (normally YUVY422 format) +// method=mmap|read|userptr +// e.g. "v4l:///dev/video0" +// e.g. "v4l[method=mmap]:///dev/video0" +// +// openni2 - capture video / depth from OpenNI2 SDK (Kinect / Xtrion etc) +// imgN=grey|rgb|ir|ir8|ir24|depth|reg_depth +// e.g. "openni2://' +// e.g. "openni2:[img1=rgb,img2=depth,coloursync=true]//" +// e.g. "openni2:[img1=depth,close=closerange,holefilter=true]//" +// e.g. "openni2:[size=320x240,fps=60,img1=ir]//" +// +// openni - capture video / depth from OpenNI 1.0 SDK (Kinect / Xtrion etc) +// Sensor modes containing '8' will truncate to 8-bits. +// Sensor modes containing '+' explicitly enable IR illuminator +// imgN=rgb|ir|ir8|ir+|ir8+|depth|reg_depth +// autoexposure=true|false +// e.g. "openni://' +// e.g. "openni:[img1=rgb,img2=depth]//" +// e.g. "openni:[size=320x240,fps=60,img1=ir]//" +// +// depthsense - capture video / depth from DepthSense SDK. +// DepthSenseViewer can be used to alter capture settings. +// imgN=depth|rgb +// sizeN=QVGA|320x240|... +// fpsN=25|30|60|... +// e.g. "depthsense://" +// e.g. "depthsense:[img1=depth,img2=rgb]//" +// +// pleora - USB 3 vision cameras accepts any option in the same format reported by eBUSPlayer +// e.g. for lightwise cameras: "pleora:[size=512x256,pos=712x512,sn=00000274,ExposureTime=10000,PixelFormat=Mono12p,AcquisitionMode=SingleFrame,TriggerSource=Line0,TriggerMode=On]//" +// e.g. for toshiba cameras: "pleora:[size=512x256,pos=712x512,sn=0300056,PixelSize=Bpp12,ExposureTime=10000,ImageFormatSelector=Format1,BinningHorizontal=2,BinningVertical=2]//" +// e.g. toshiba alternated "pleora:[UserSetSelector=UserSet1,ExposureTime=10000,PixelSize=Bpp12,Width=1400,OffsetX=0,Height=1800,OffsetY=124,LineSelector=Line1,LineSource=ExposureActive,LineSelector=Line2,LineSource=Off,LineModeAll=6,LineInverterAll=6,UserSetSave=Execute, +// UserSetSelector=UserSet2,PixelSize=Bpp12,Width=1400,OffsetX=1048,Height=1800,OffsetY=124,ExposureTime=10000,LineSelector=Line1,LineSource=Off,LineSelector=Line2,LineSource=ExposureActive,LineModeAll=6,LineInverterAll=6,UserSetSave=Execute, +// SequentialShutterIndex=1,SequentialShutterEntry=1,SequentialShutterIndex=2,SequentialShutterEntry=2,SequentialShutterTerminateAt=2,SequentialShutterEnable=On,,AcquisitionFrameRateControl=Manual,AcquisitionFrameRate=70]//" +// +// thread - thread that continuously pulls from the child streams so that data in, unpacking, debayering etc can be decoupled from the main application thread +// e.g. thread://pleora:// +// e.g. thread://unpack://pleora:[PixelFormat=Mono12p]// +// +// convert - use FFMPEG to convert between video pixel formats +// e.g. "convert:[fmt=RGB24]//v4l:///dev/video0" +// e.g. "convert:[fmt=GRAY8]//v4l:///dev/video0" +// +// mjpeg - capture from (possibly networked) motion jpeg stream using FFMPEG +// e.g. "mjpeg://http://127.0.0.1/?action=stream" +// +// debayer - debayer an input video stream +// e.g. "debayer:[tile="BGGR",method="downsample"]//v4l:///dev/video0 +// +// split - split an input video into a one or more streams based on Region of Interest / memory specification +// roiN=X+Y+WxH +// memN=Offset:WxH:PitchBytes:Format +// e.g. "split:[roi1=0+0+640x480,roi2=640+0+640x480]//files:///home/user/sequence/foo%03d.jpeg" +// e.g. "split:[mem1=307200:640x480:1280:GRAY8,roi2=640+0+640x480]//files:///home/user/sequence/foo%03d.jpeg" +// e.g. "split:[stream1=2,stream2=1]//pango://video.pango" +// +// truncate - select a subregion of a video based on start and end (last index+1) index +// e.g. Generate 30 random frames: "truncate:[end=30]//test://" +// e.g. "truncate:[begin=100,end=120]" +// +// join - join streams +// e.g. "join:[sync_tolerance_us=100, sync_continuously=true]//{pleora:[sn=00000274]//}{pleora:[sn=00000275]//}" +// +// test - output test video sequence +// e.g. "test://" +// e.g. "test:[size=640x480,fmt=RGB24]//" + +#include +#include +#include +#include + +namespace pangolin +{ + +//! Open Video Interface from string specification (as described in this files header) +PANGOLIN_EXPORT +std::unique_ptr OpenVideo(const std::string& uri); + +//! Open Video Interface from Uri specification +PANGOLIN_EXPORT +std::unique_ptr OpenVideo(const Uri& uri); + +//! Open VideoOutput Interface from string specification (as described in this files header) +PANGOLIN_EXPORT +std::unique_ptr OpenVideoOutput(const std::string& str_uri); + +//! Open VideoOutput Interface from Uri specification +PANGOLIN_EXPORT +std::unique_ptr OpenVideoOutput(const Uri& uri); + +//! Create vector of matching interfaces either through direct cast or filter interface. +template +std::vector FindMatchingVideoInterfaces( VideoInterface& video ) +{ + std::vector matches; + + T* vid = dynamic_cast(&video); + if(vid) { + matches.push_back(vid); + } + + VideoFilterInterface* vidf = dynamic_cast(&video); + if(vidf) { + std::vector fmatches = vidf->FindMatchingStreams(); + matches.insert(matches.begin(), fmatches.begin(), fmatches.end()); + } + + return matches; +} + +template +T* FindFirstMatchingVideoInterface( VideoInterface& video ) +{ + T* vid = dynamic_cast(&video); + if(vid) { + return vid; + } + + VideoFilterInterface* vidf = dynamic_cast(&video); + if(vidf) { + std::vector fmatches = vidf->FindMatchingStreams(); + if(fmatches.size()) { + return fmatches[0]; + } + } + + return 0; +} + +inline +picojson::value GetVideoFrameProperties(VideoInterface* video) +{ + VideoPropertiesInterface* pi = dynamic_cast(video); + VideoFilterInterface* fi = dynamic_cast(video); + + if(pi) { + return pi->FrameProperties(); + }else if(fi){ + if(fi->InputStreams().size() == 1) { + return GetVideoFrameProperties(fi->InputStreams()[0]); + }else if(fi->InputStreams().size() > 0){ + picojson::value streams; + + for(size_t i=0; i< fi->InputStreams().size(); ++i) { + const picojson::value dev_props = GetVideoFrameProperties(fi->InputStreams()[i]); + if(dev_props.contains("streams")) { + const picojson::value& dev_streams = dev_props["streams"]; + for(size_t j=0; j < dev_streams.size(); ++j) { + streams.push_back(dev_streams[j]); + } + }else{ + streams.push_back(dev_props); + } + } + + if(streams.size() > 1) { + picojson::value json = streams[0]; + json["streams"] = streams; + return json; + }else{ + return streams[0]; + } + } + } + return picojson::value(); +} + +inline +picojson::value GetVideoDeviceProperties(VideoInterface* video) +{ + VideoPropertiesInterface* pi = dynamic_cast(video); + VideoFilterInterface* fi = dynamic_cast(video); + + if(pi) { + return pi->DeviceProperties(); + }else if(fi){ + if(fi->InputStreams().size() == 1) { + return GetVideoDeviceProperties(fi->InputStreams()[0]); + }else if(fi->InputStreams().size() > 0){ + picojson::value streams; + + for(size_t i=0; i< fi->InputStreams().size(); ++i) { + const picojson::value dev_props = GetVideoDeviceProperties(fi->InputStreams()[i]); + if(dev_props.contains("streams")) { + const picojson::value& dev_streams = dev_props["streams"]; + for(size_t j=0; j < dev_streams.size(); ++j) { + streams.push_back(dev_streams[j]); + } + }else{ + streams.push_back(dev_props); + } + } + + if(streams.size() > 1) { + picojson::value json = streams[0]; + json["streams"] = streams; + return json; + }else{ + return streams[0]; + } + } + } + return picojson::value(); +} + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/video_exception.h b/Thirdparty/Pangolin/include/pangolin/video/video_exception.h new file mode 100644 index 0000000..60208c2 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video_exception.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +namespace pangolin { + +struct PANGOLIN_EXPORT VideoException : std::exception +{ + VideoException(std::string str) : desc(str) {} + VideoException(std::string str, std::string detail) { + desc = str + "\n\t" + detail; + } + ~VideoException() throw() {} + const char* what() const throw() { return desc.c_str(); } + std::string desc; +}; + +struct PANGOLIN_EXPORT VideoExceptionNoKnownHandler : public VideoException +{ + VideoExceptionNoKnownHandler(const std::string& scheme) + : VideoException("No known video handler for URI '" + scheme + "'") + { + } +}; + +} + diff --git a/Thirdparty/Pangolin/include/pangolin/video/video_input.h b/Thirdparty/Pangolin/include/pangolin/video/video_input.h new file mode 100644 index 0000000..11f9ee4 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video_input.h @@ -0,0 +1,140 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +namespace pangolin +{ + +struct PANGOLIN_EXPORT VideoInput + : public VideoInterface, + public VideoFilterInterface +{ + ///////////////////////////////////////////////////////////// + // VideoInterface Methods + ///////////////////////////////////////////////////////////// + + size_t SizeBytes() const override; + const std::vector& Streams() const override; + void Start() override; + void Stop() override; + bool GrabNext( unsigned char* image, bool wait = true ) override; + bool GrabNewest( unsigned char* image, bool wait = true ) override; + + ///////////////////////////////////////////////////////////// + // VideoFilterInterface Methods + ///////////////////////////////////////////////////////////// + + std::vector& InputStreams() override + { + return videos; + } + + ///////////////////////////////////////////////////////////// + // VideoInput Methods + ///////////////////////////////////////////////////////////// + + VideoInput(); + VideoInput(VideoInput&& other) = default; + VideoInput(const std::string &input_uri, const std::string &output_uri = "pango:[buffer_size_mb=100]//video_log.pango"); + ~VideoInput(); + + void Open(const std::string &input_uri, const std::string &output_uri = "pango:[buffer_size_mb=100]//video_log.pango"); + void Close(); + + // experimental - not stable + bool Grab( unsigned char* buffer, std::vector >& images, bool wait = true, bool newest = false); + + // Return details of first stream + unsigned int Width() const { + return (unsigned int)Streams()[0].Width(); + } + unsigned int Height() const { + return (unsigned int)Streams()[0].Height(); + } + PixelFormat PixFormat() const { + return Streams()[0].PixFormat(); + } + const Uri& VideoUri() const { + return uri_input; + } + + void Reset() { + Close(); + Open(uri_input.full_uri, uri_output.full_uri); + } + + // Return pointer to inner video class as VideoType + template + VideoType* Cast() { + return dynamic_cast(video_src.get()); + } + + const std::string& LogFilename() const; + std::string& LogFilename(); + + // Switch to live video and record output to file + void Record(); + + // Switch to live video and record a single frame + void RecordOneFrame(); + + // Specify that one in n frames are logged to file. Default is 1. + void SetTimelapse(size_t one_in_n_frames); + + // True iff grabbed live frames are being logged to file + bool IsRecording() const; + +protected: + void InitialiseRecorder(); + + Uri uri_input; + Uri uri_output; + + std::unique_ptr video_src; + std::unique_ptr video_recorder; + + // Use to store either video_src or video_file for VideoFilterInterface, + // depending on which is active + std::vector videos; + + int buffer_size_bytes; + + int frame_num; + size_t record_frame_skip; + + bool record_once; + bool record_continuous; +}; + +// VideoInput subsumes the previous VideoRecordRepeat class. +typedef VideoInput VideoRecordRepeat; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/video_interface.h b/Thirdparty/Pangolin/include/pangolin/video/video_interface.h new file mode 100644 index 0000000..f37302d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video_interface.h @@ -0,0 +1,183 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include + +#include +#include + +#define PANGO_HAS_TIMING_DATA "has_timing_data" +#define PANGO_HOST_RECEPTION_TIME_US "host_reception_time_us" +#define PANGO_CAPTURE_TIME_US "capture_time_us" +#define PANGO_EXPOSURE_US "exposure_us" +#define PANGO_GAMMA "gamma" +// analog gain is in linear scale and not dB +#define PANGO_ANALOG_GAIN "analog_gain" +#define PANGO_ANALOG_BLACK_LEVEL "analog_black_level" +#define PANGO_SENSOR_TEMPERATURE_C "sensor_temperature_C" +#define PANGO_ESTIMATED_CENTER_CAPTURE_TIME_US "estimated_center_capture_time_us" +#define PANGO_JOIN_OFFSET_US "join_offset_us" +#define PANGO_FRAME_COUNTER "frame_counter" + +namespace pangolin { + +//! Interface to video capture sources +struct PANGOLIN_EXPORT VideoInterface +{ + virtual ~VideoInterface() {} + + //! Required buffer size to store all frames + virtual size_t SizeBytes() const = 0; + + //! Get format and dimensions of all video streams + virtual const std::vector& Streams() const = 0; + + //! Start Video device + virtual void Start() = 0; + + //! Stop Video device + virtual void Stop() = 0; + + //! Copy the next frame from the camera to image. + //! Optionally wait for a frame if one isn't ready + //! Returns true iff image was copied + virtual bool GrabNext( unsigned char* image, bool wait = true ) = 0; + + //! Copy the newest frame from the camera to image + //! discarding all older frames. + //! Optionally wait for a frame if one isn't ready + //! Returns true iff image was copied + virtual bool GrabNewest( unsigned char* image, bool wait = true ) = 0; +}; + +//! Interface to GENICAM video capture sources +struct PANGOLIN_EXPORT GenicamVideoInterface +{ + virtual ~GenicamVideoInterface() {} + + virtual bool GetParameter(const std::string& name, std::string& result) = 0; + + virtual bool SetParameter(const std::string& name, const std::string& value) = 0; + + virtual size_t CameraCount() const + { + return 1; + } +}; + +struct PANGOLIN_EXPORT BufferAwareVideoInterface +{ + virtual ~BufferAwareVideoInterface() {} + + //! Returns number of available frames + virtual uint32_t AvailableFrames() const = 0; + + //! Drops N frames in the queue starting from the oldest + //! returns false if less than n frames arae available + virtual bool DropNFrames(uint32_t n) = 0; +}; + +struct PANGOLIN_EXPORT VideoPropertiesInterface +{ + virtual ~VideoPropertiesInterface() {} + + //! Access JSON properties of device + virtual const picojson::value& DeviceProperties() const = 0; + + //! Access JSON properties of most recently captured frame + virtual const picojson::value& FrameProperties() const = 0; +}; + +enum UvcRequestCode { + UVC_RC_UNDEFINED = 0x00, + UVC_SET_CUR = 0x01, + UVC_GET_CUR = 0x81, + UVC_GET_MIN = 0x82, + UVC_GET_MAX = 0x83, + UVC_GET_RES = 0x84, + UVC_GET_LEN = 0x85, + UVC_GET_INFO = 0x86, + UVC_GET_DEF = 0x87 +}; + +struct PANGOLIN_EXPORT VideoFilterInterface +{ + virtual ~VideoFilterInterface() {} + + template + std::vector FindMatchingStreams() + { + std::vector matches; + std::vector children = InputStreams(); + for(size_t c=0; c < children.size(); ++c) { + T* concrete_video = dynamic_cast(children[c]); + if(concrete_video) { + matches.push_back(concrete_video); + }else{ + VideoFilterInterface* filter_video = dynamic_cast(children[c]); + if(filter_video) { + std::vector child_matches = filter_video->FindMatchingStreams(); + matches.insert(matches.end(), child_matches.begin(), child_matches.end()); + } + } + } + return matches; + } + + virtual std::vector& InputStreams() = 0; +}; + +struct PANGOLIN_EXPORT VideoUvcInterface +{ + virtual ~VideoUvcInterface() {} + virtual int IoCtrl(uint8_t unit, uint8_t ctrl, unsigned char* data, int len, UvcRequestCode req_code) = 0; + virtual bool GetExposure(int& exp_us) = 0; + virtual bool SetExposure(int exp_us) = 0; + virtual bool GetGain(float& gain) = 0; + virtual bool SetGain(float gain) = 0; +}; + +struct PANGOLIN_EXPORT VideoPlaybackInterface +{ + virtual ~VideoPlaybackInterface() {} + + /// Return monotonic id of current frame + /// The 'current frame' is the frame returned from the last successful call to Grab + virtual size_t GetCurrentFrameId() const = 0; + + /// Return total number of frames to be captured from device, + /// or 0 if unknown. + virtual size_t GetTotalFrames() const = 0; + + /// Return frameid on success, or next frame on failure + virtual size_t Seek(size_t frameid) = 0; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/video_output.h b/Thirdparty/Pangolin/include/pangolin/video/video_output.h new file mode 100644 index 0000000..04c79e7 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video_output.h @@ -0,0 +1,93 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011-2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +// Pangolin video output supports various formats using +// different 3rd party libraries. (Only one right now) +// +// VideoOutput URI's take the following form: +// scheme:[param1=value1,param2=value2,...]//device +// +// scheme = ffmpeg +// +// ffmpeg - encode to compressed file using ffmpeg +// fps : fps to embed in encoded file. +// bps : bits per second +// unique_filename : append unique suffix if file already exists +// +// e.g. ffmpeg://output_file.avi +// e.g. ffmpeg:[fps=30,bps=1000000,unique_filename]//output_file.avi + +#include +#include +#include + +namespace pangolin +{ + +//! VideoOutput wrap to generically construct instances of VideoOutputInterface. +class PANGOLIN_EXPORT VideoOutput : public VideoOutputInterface +{ +public: + VideoOutput(); + VideoOutput(VideoOutput&& other) = default; + VideoOutput(const std::string& uri); + ~VideoOutput(); + + bool IsOpen() const; + void Open(const std::string& uri); + void Close(); + + const std::vector& Streams() const override; + + void SetStreams(const std::vector& streams, const std::string& uri = "", const picojson::value& properties = picojson::value() ) override; + + int WriteStreams(const unsigned char* data, const picojson::value& frame_properties = picojson::value() ) override; + + bool IsPipe() const override; + + void AddStream(const PixelFormat& pf, size_t w,size_t h,size_t pitch); + + void AddStream(const PixelFormat& pf, size_t w,size_t h); + + void SetStreams(const std::string& uri = "", const picojson::value& properties = picojson::value() ); + + size_t SizeBytes(void) const ; + + std::vector> GetOutputImages(unsigned char* buffer) const ; + + std::vector> GetOutputImages(std::vector& buffer) const ; + + +protected: + std::vector streams; + Uri uri; + std::unique_ptr recorder; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/video_output_interface.h b/Thirdparty/Pangolin/include/pangolin/video/video_output_interface.h new file mode 100644 index 0000000..efbec4d --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video_output_interface.h @@ -0,0 +1,52 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011-2013 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace pangolin { + +//! Interface to video recording destinations +struct PANGOLIN_EXPORT VideoOutputInterface +{ + virtual ~VideoOutputInterface() {} + + //! Get format and dimensions of all video streams + virtual const std::vector& Streams() const = 0; + + virtual void SetStreams(const std::vector& streams, const std::string& uri ="", const picojson::value& properties = picojson::value() ) = 0; + + virtual int WriteStreams(const unsigned char* data, const picojson::value& frame_properties = picojson::value() ) = 0; + + virtual bool IsPipe() const = 0; +}; + +} diff --git a/Thirdparty/Pangolin/include/pangolin/video/video_record_repeat.h b/Thirdparty/Pangolin/include/pangolin/video/video_record_repeat.h new file mode 100644 index 0000000..79e8571 --- /dev/null +++ b/Thirdparty/Pangolin/include/pangolin/video/video_record_repeat.h @@ -0,0 +1,31 @@ +/* This file is part of the Pangolin Project. + * http://github.com/stevenlovegrove/Pangolin + * + * Copyright (c) 2011 Steven Lovegrove + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT + * HOLDERS 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. + */ + +#pragma once + +// VideoInput subsumes the previous VideoRecordRepeat class. +#include diff --git a/Thirdparty/Pangolin/include/tinyobj/tiny_obj_loader.h b/Thirdparty/Pangolin/include/tinyobj/tiny_obj_loader.h new file mode 100644 index 0000000..d19040c --- /dev/null +++ b/Thirdparty/Pangolin/include/tinyobj/tiny_obj_loader.h @@ -0,0 +1,2547 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-2018 Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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 OR COPYRIGHT HOLDERS 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. +*/ + +// +// version 1.3.1 : Make ParseTextureNameAndOption API public +// version 1.3.0 : Separate warning and error message(breaking API of LoadObj) +// version 1.2.3 : Added color space extension('-colorspace') to tex opts. +// version 1.2.2 : Parse multiple group names. +// version 1.2.1 : Added initial support for line('l') primitive(PR #178) +// version 1.2.0 : Hardened implementation(#175) +// version 1.1.1 : Support smoothing groups(#162) +// version 1.1.0 : Support parsing vertex color(#144) +// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138) +// version 1.0.7 : Support multiple tex options(#126) +// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124) +// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43) +// version 1.0.4 : Support multiple filenames for 'mtllib'(#112) +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#pragma clang diagnostic ignored "-Wpadded" + +#endif + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost real_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right +// +// TinyObjLoader extension. +// +// -colorspace SPACE # Color space of the texture. e.g. +// 'sRGB` or 'linear' +// + +#ifdef TINYOBJLOADER_USE_DOUBLE +//#pragma message "using double" +typedef double real_t; +#else +//#pragma message "using float" +typedef float real_t; +#endif + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +typedef struct { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + real_t sharpness; // -boost (default 1.0?) + real_t brightness; // base_value in -mm option (default 0) + real_t contrast; // gain_value in -mm option (default 1) + real_t origin_offset[3]; // -o u [v [w]] (default 0 0 0) + real_t scale[3]; // -s u [v [w]] (default 1 1 1) + real_t turbulence[3]; // -t u [v [w]] (default 0 0 0) + // int texture_resolution; // -texres resolution (default = ?) TODO + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + real_t bump_multiplier; // -bm (for bump maps only, default 1.0) + + // extension + std::string colorspace; // Explicitly specify color space of stored value. + // Usually `sRGB` or `linear` (default empty). +} texture_option_t; + +typedef struct { + std::string name; + + real_t ambient[3]; + real_t diffuse[3]; + real_t specular[3]; + real_t transmittance[3]; + real_t emission[3]; + real_t shininess; + real_t ior; // index of refraction + real_t dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, map_Bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + std::string reflection_texname; // refl + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + texture_option_t reflection_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + real_t roughness; // [0, 1] default 0 + real_t metallic; // [0, 1] default 0 + real_t sheen; // [0, 1] default 0 + real_t clearcoat_thickness; // [0, 1] default 0 + real_t clearcoat_roughness; // [0, 1] default 0 + real_t anisotropy; // aniso. [0, 1] default 0 + real_t anisotropy_rotation; // anisor. [0, 1] default 0 + real_t pad0; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; +} material_t; + +typedef struct { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +} tag_t; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +typedef struct { + int vertex_index; + int normal_index; + int texcoord_index; +} index_t; + +typedef struct { + std::vector indices; + std::vector num_face_vertices; // The number of vertices per + // face. 3 = polygon, 4 = quad, + // ... Up to 255. + std::vector material_ids; // per-face material ID + std::vector smoothing_group_ids; // per-face smoothing group + // ID(0 = off. positive value + // = group id) + std::vector tags; // SubD tag +} mesh_t; + +typedef struct { + std::vector indices; // pairs of indices for lines +} path_t; + +typedef struct { + std::string name; + mesh_t mesh; + path_t path; +} shape_t; + +// Vertex attributes +typedef struct { + std::vector vertices; // 'v' + std::vector normals; // 'vn' + std::vector texcoords; // 'vt' + std::vector colors; // extension: vertex colors +} attrib_t; + +typedef struct callback_t_ { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void *user_data, real_t x, real_t y, real_t z, real_t w); + void (*normal_cb)(void *user_data, real_t x, real_t y, real_t z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void *user_data, real_t x, real_t y, real_t z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void *user_data, index_t *indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void *user_data, const char *name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void *user_data, const material_t *materials, + int num_materials); + // There may be multiple group names + void (*group_cb)(void *user_data, const char **names, int num_names); + void (*object_cb)(void *user_data, const char *name); + + callback_t_() + : vertex_cb(NULL), + normal_cb(NULL), + texcoord_cb(NULL), + index_cb(NULL), + usemtl_cb(NULL), + mtllib_cb(NULL), + group_cb(NULL), + object_cb(NULL) {} +} callback_t; + +class MaterialReader { + public: + MaterialReader() {} + virtual ~MaterialReader(); + + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *warn, + std::string *err) = 0; +}; + +class MaterialFileReader : public MaterialReader { + public: + explicit MaterialFileReader(const std::string &mtl_basedir) + : m_mtlBaseDir(mtl_basedir) {} + virtual ~MaterialFileReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *warn, + std::string *err); + + private: + std::string m_mtlBaseDir; +}; + +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream &inStream) + : m_inStream(inStream) {} + virtual ~MaterialStreamReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *warn, + std::string *err); + + private: + std::istream &m_inStream; +}; + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning message into `warn`, and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working +/// directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +/// Option 'default_vcols_fallback' specifies whether vertex colors should +/// always be defined, even if no colors are given (fallback to white). +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, const char *filename, + const char *mtl_basedir = NULL, bool triangulate = true, + bool default_vcols_fallback = true); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning message into `warn`, and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data = NULL, + MaterialReader *readMatFn = NULL, + std::string *warn = NULL, std::string *err = NULL); + +/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, std::istream *inStream, + MaterialReader *readMatFn = NULL, bool triangulate = true, + bool default_vcols_fallback = true); + +/// Loads materials into std::map +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream, + std::string *warning, std::string *err); + +/// +/// Parse texture name and texture option for custom texture parameter through material::unknown_parameter +/// +/// @param[out] texname Parsed texture name +/// @param[out] texopt Parsed texopt +/// @param[in] linebuf Input string +/// @param[in] is_bump Is this texture bump/normal? +/// +bool ParseTextureNameAndOption(std::string *texname, + texture_option_t *texopt, + const char *linebuf, + const bool is_bump); +} // namespace tinyobj + +#endif // TINY_OBJ_LOADER_H_ + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace tinyobj { + +MaterialReader::~MaterialReader() {} + +struct vertex_index_t { + int v_idx, vt_idx, vn_idx; + vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index_t(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +// Internal data structure for face representation +// index + smoothing group. +struct face_t { + unsigned int + smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. + int pad_; + std::vector vertex_indices; // face vertex indices. + + face_t() : smoothing_group_id(0) {} +}; + +struct line_t { + int idx0; + int idx1; +}; + +struct tag_sizes { + tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {} + int num_ints; + int num_reals; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + if (se) { + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } + } + + return is; +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) \ + (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline bool fixIndex(int idx, int n, int *ret) { + if (!ret) { + return false; + } + + if (idx > 0) { + (*ret) = idx - 1; + return true; + } + + if (idx == 0) { + // zero is not allowed according to the spec. + return false; + } + + if (idx < 0) { + (*ret) = n + idx; // negative value = relative + return true; + } + + return false; // never reach here. +} + +static inline std::string parseString(const char **token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char **token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char *s, const char *s_end, double *result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) goto fail; + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * + (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) goto fail; + } + +assemble: + *result = (sign == '+' ? 1 : -1) * + (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) + : mantissa); + return true; +fail: + return false; +} + +static inline real_t parseReal(const char **token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + real_t f = static_cast(val); + (*token) = end; + return f; +} + +static inline bool parseReal(const char **token, real_t *out) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val; + bool ret = tryParseDouble((*token), end, &val); + if (ret) { + real_t f = static_cast(val); + (*out) = f; + } + (*token) = end; + return ret; +} + +static inline void parseReal2(real_t *x, real_t *y, const char **token, + const double default_x = 0.0, + const double default_y = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); +} + +static inline void parseReal3(real_t *x, real_t *y, real_t *z, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); +} + +static inline void parseV(real_t *x, real_t *y, real_t *z, real_t *w, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + (*w) = parseReal(token, default_w); +} + +// Extension: parse vertex with colors(6 items) +static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, + real_t *r, real_t *g, real_t *b, + const char **token, + const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + + const bool found_color = + parseReal(token, r) && parseReal(token, g) && parseReal(token, b); + + if (!found_color) { + (*r) = (*g) = (*b) = 1.0; + } + + return found_color; +} + +static inline bool parseOnOff(const char **token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == strncmp((*token), "on", 2))) { + ret = true; + } else if ((0 == strncmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType( + const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char **token) { + tag_sizes ts; + + (*token) += strspn((*token), " \t"); + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + + (*token)++; // Skip '/' + + (*token) += strspn((*token), " \t"); + ts.num_reals = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; // Skip '/' + + ts.num_strings = parseInt(token); + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, + vertex_index_t *ret) { + if (!ret) { + return false; + } + + vertex_index_t vi(-1); + + if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + (*ret) = vi; + return true; + } + + // i/j/k or i/j + if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + + // i/j/k + (*token)++; // skip '/' + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + + (*ret) = vi; + + return true; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index_t parseRawTriple(const char **token) { + vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +bool ParseTextureNameAndOption(std::string *texname, + texture_option_t *texopt, + const char *linebuf, const bool is_bump) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + // Fill with default value for texopt. + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = static_cast(1.0); + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = static_cast(1.0); + texopt->brightness = static_cast(0.0); + texopt->contrast = static_cast(1.0); + texopt->origin_offset[0] = static_cast(0.0); + texopt->origin_offset[1] = static_cast(0.0); + texopt->origin_offset[2] = static_cast(0.0); + texopt->scale[0] = static_cast(1.0); + texopt->scale[1] = static_cast(1.0); + texopt->scale[2] = static_cast(1.0); + texopt->turbulence[0] = static_cast(0.0); + texopt->turbulence[1] = static_cast(0.0); + texopt->turbulence[2] = static_cast(0.0); + texopt->type = TEXTURE_TYPE_NONE; + + const char *token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + token += strspn(token, " \t"); // skip space + if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseReal(&token, 1.0); + } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseReal(&token, 1.0); + } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), + &(texopt->origin_offset[2]), &token); + } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), + &token, 1.0, 1.0, 1.0); + } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), + &(texopt->turbulence[2]), &token); + } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char *end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else if ((0 == strncmp(token, "-colorspace", 11)) && + IS_SPACE((token[11]))) { + token += 12; + texopt->colorspace = parseString(&token); + } else { +// Assume texture filename +#if 0 + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space +#else + // Read filename until line end to parse filename containing whitespace + // TODO(syoyo): Support parsing texture option flag after the filename. + texture_name = std::string(token); + token += texture_name.length(); +#endif + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitMaterial(material_t *material) { + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->reflection_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = static_cast(0.0); + material->diffuse[i] = static_cast(0.0); + material->specular[i] = static_cast(0.0); + material->transmittance[i] = static_cast(0.0); + material->emission[i] = static_cast(0.0); + } + material->illum = 0; + material->dissolve = static_cast(1.0); + material->shininess = static_cast(1.0); + material->ior = static_cast(1.0); + + material->roughness = static_cast(0.0); + material->metallic = static_cast(0.0); + material->sheen = static_cast(0.0); + material->clearcoat_thickness = static_cast(0.0); + material->clearcoat_roughness = static_cast(0.0); + material->anisotropy_rotation = static_cast(0.0); + material->anisotropy = static_cast(0.0); + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html +template +static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) { + int i, j, c = 0; + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if (((verty[i] > testy) != (verty[j] > testy)) && + (testx < + (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + + vertx[i])) + c = !c; + } + return c; +} + +// TODO(syoyo): refactor function. +static bool exportGroupsToShape(shape_t *shape, + const std::vector &faceGroup, + std::vector &lineGroup, + const std::vector &tags, + const int material_id, const std::string &name, + bool triangulate, + const std::vector &v) { + if (faceGroup.empty() && lineGroup.empty()) { + return false; + } + + if (!faceGroup.empty()) { + // Flatten vertices and indices + for (size_t i = 0; i < faceGroup.size(); i++) { + const face_t &face = faceGroup[i]; + + size_t npolys = face.vertex_indices.size(); + + if (npolys < 3) { + // Face must have 3+ vertices. + continue; + } + + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face.vertex_indices[1]; + + if (triangulate) { + // find the two axes to work in + size_t axes[2] = {1, 2}; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + i2 = face.vertex_indices[(k + 2) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + + if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || + ((3 * vi2 + 2) >= v.size())) { + // Invalid triangle. + // FIXME(syoyo): Is it ok to simply skip this invalid triangle? + continue; + } + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t e0x = v1x - v0x; + real_t e0y = v1y - v0y; + real_t e0z = v1z - v0z; + real_t e1x = v2x - v1x; + real_t e1y = v2y - v1y; + real_t e1z = v2z - v1z; + real_t cx = std::fabs(e0y * e1z - e0z * e1y); + real_t cy = std::fabs(e0z * e1x - e0x * e1z); + real_t cz = std::fabs(e0x * e1y - e0y * e1x); + const real_t epsilon = std::numeric_limits::epsilon(); + if (cx > epsilon || cy > epsilon || cz > epsilon) { + // found a corner + if (cx > cy && cx > cz) { + } else { + axes[0] = 0; + if (cz > cx && cz > cy) axes[1] = 1; + } + break; + } + } + + real_t area = 0; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + if (((vi0 * 3 + axes[0]) >= v.size()) || + ((vi0 * 3 + axes[1]) >= v.size()) || + ((vi1 * 3 + axes[0]) >= v.size()) || + ((vi1 * 3 + axes[1]) >= v.size())) { + // Invalid index. + continue; + } + real_t v0x = v[vi0 * 3 + axes[0]]; + real_t v0y = v[vi0 * 3 + axes[1]]; + real_t v1x = v[vi1 * 3 + axes[0]]; + real_t v1y = v[vi1 * 3 + axes[1]]; + area += (v0x * v1y - v0y * v1x) * static_cast(0.5); + } + + int maxRounds = 10; // arbitrary max loop count to protect against + // unexpected errors + + face_t remainingFace = face; // copy + size_t guess_vert = 0; + vertex_index_t ind[3]; + real_t vx[3]; + real_t vy[3]; + while (remainingFace.vertex_indices.size() > 3 && maxRounds > 0) { + npolys = remainingFace.vertex_indices.size(); + if (guess_vert >= npolys) { + maxRounds -= 1; + guess_vert -= npolys; + } + for (size_t k = 0; k < 3; k++) { + ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys]; + size_t vi = size_t(ind[k].v_idx); + if (((vi * 3 + axes[0]) >= v.size()) || + ((vi * 3 + axes[1]) >= v.size())) { + // ??? + vx[k] = static_cast(0.0); + vy[k] = static_cast(0.0); + } else { + vx[k] = v[vi * 3 + axes[0]]; + vy[k] = v[vi * 3 + axes[1]]; + } + } + real_t e0x = vx[1] - vx[0]; + real_t e0y = vy[1] - vy[0]; + real_t e1x = vx[2] - vx[1]; + real_t e1y = vy[2] - vy[1]; + real_t cross = e0x * e1y - e0y * e1x; + // if an internal angle + if (cross * area < static_cast(0.0)) { + guess_vert += 1; + continue; + } + + // check all other verts in case they are inside this triangle + bool overlap = false; + for (size_t otherVert = 3; otherVert < npolys; ++otherVert) { + size_t idx = (guess_vert + otherVert) % npolys; + + if (idx >= remainingFace.vertex_indices.size()) { + // ??? + continue; + } + + size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx); + + if (((ovi * 3 + axes[0]) >= v.size()) || + ((ovi * 3 + axes[1]) >= v.size())) { + // ??? + continue; + } + real_t tx = v[ovi * 3 + axes[0]]; + real_t ty = v[ovi * 3 + axes[1]]; + if (pnpoly(3, vx, vy, tx, ty)) { + overlap = true; + break; + } + } + + if (overlap) { + guess_vert += 1; + continue; + } + + // this triangle is an ear + { + index_t idx0, idx1, idx2; + idx0.vertex_index = ind[0].v_idx; + idx0.normal_index = ind[0].vn_idx; + idx0.texcoord_index = ind[0].vt_idx; + idx1.vertex_index = ind[1].v_idx; + idx1.normal_index = ind[1].vn_idx; + idx1.texcoord_index = ind[1].vt_idx; + idx2.vertex_index = ind[2].v_idx; + idx2.normal_index = ind[2].vn_idx; + idx2.texcoord_index = ind[2].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + + // remove v1 from the list + size_t removed_vert_index = (guess_vert + 1) % npolys; + while (removed_vert_index + 1 < npolys) { + remainingFace.vertex_indices[removed_vert_index] = + remainingFace.vertex_indices[removed_vert_index + 1]; + removed_vert_index += 1; + } + remainingFace.vertex_indices.pop_back(); + } + + if (remainingFace.vertex_indices.size() == 3) { + i0 = remainingFace.vertex_indices[0]; + i1 = remainingFace.vertex_indices[1]; + i2 = remainingFace.vertex_indices[2]; + { + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + } + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face.vertex_indices[k].v_idx; + idx.normal_index = face.vertex_indices[k].vn_idx; + idx.texcoord_index = face.vertex_indices[k].vt_idx; + shape->mesh.indices.push_back(idx); + } + + shape->mesh.num_face_vertices.push_back( + static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); // per face + } + } + + shape->name = name; + shape->mesh.tags = tags; + } + + if (!lineGroup.empty()) { + shape->path.indices.swap(lineGroup); + } + + return true; +} + +// Split a string with specified delimiter character. +// http://stackoverflow.com/questions/236129/split-a-string-in-c +static void SplitString(const std::string &s, char delim, + std::vector &elems) { + std::stringstream ss; + ss.str(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } +} + +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream, + std::string *warning, std::string *err) { + (void)err; + + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification. + bool has_d = false; + bool has_tr = false; + + std::stringstream warn_ss; + + size_t line_no = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + line_no++; + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + has_d = false; + has_tr = false; + + // set new mtl name + token += 7; + { + std::stringstream sstr; + sstr << token; + material.name = sstr.str(); + } + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || + (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseReal(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseReal(&token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseReal(&token); + + if (has_tr) { + warn_ss << "Both `d` and `Tr` parameters defined for \"" + << material.name << "\". Use the value of `d` for dissolve (line " + << line_no << " in .mtl.)" + << std::endl; + } + has_d = true; + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + if (has_d) { + // `d` wins. Ignore `Tr` value. + warn_ss << "Both `d` and `Tr` parameters defined for \"" + << material.name << "\". Use the value of `d` for dissolve (line " + << line_no << " in .mtl.)" + << std::endl; + } else { + // We invert value of Tr(assume Tr is in range [0, 1]) + // NOTE: Interpretation of Tr is application(exporter) dependent. For + // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43) + material.dissolve = static_cast(1.0) - parseReal(&token); + } + has_tr = true; + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseReal(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseReal(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseReal(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseReal(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseReal(&token); + continue; + } + + // PBR: anisotropy + if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseReal(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseReal(&token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), + &(material.ambient_texopt), token, + /* is_bump */ false); + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), + &(material.diffuse_texopt), token, + /* is_bump */ false); + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), + &(material.specular_texopt), token, + /* is_bump */ false); + continue; + } + + // specular highlight texture + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), + &(material.specular_highlight_texopt), token, + /* is_bump */ false); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_Bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // bump texture + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // alpha texture + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), + &(material.alpha_texopt), token, + /* is_bump */ false); + continue; + } + + // displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), + &(material.displacement_texopt), token, + /* is_bump */ false); + continue; + } + + // reflection map + if ((0 == strncmp(token, "refl", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.reflection_texname), + &(material.reflection_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: roughness texture + if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), + &(material.roughness_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: metallic texture + if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), + &(material.metallic_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: sheen texture + if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), + &(material.sheen_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: emissive texture + if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), + &(material.emissive_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: normal map texture + if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption( + &(material.normal_texname), &(material.normal_texopt), token, + /* is_bump */ false); // @fixme { is_bump will be true? } + continue; + } + + // unknown parameter + const char *_space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert( + std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + + if (warning) { + (*warning) = warn_ss.str(); + } +} + +bool MaterialFileReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *warn, std::string *err) { + std::string filepath; + + if (!m_mtlBaseDir.empty()) { + filepath = std::string(m_mtlBaseDir) + matId; + } else { + filepath = matId; + } + + std::ifstream matIStream(filepath.c_str()); + if (!matIStream) { + std::stringstream ss; + ss << "Material file [ " << filepath << " ] not found." << std::endl; + if (warn) { + (*warn) += ss.str(); + } + return false; + } + + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; +} + +bool MaterialStreamReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *warn, std::string *err) { + (void)err; + (void)matId; + if (!m_inStream) { + std::stringstream ss; + ss << "Material stream in error state. " << std::endl; + if (warn) { + (*warn) += ss.str(); + } + return false; + } + + LoadMtl(matMap, materials, &m_inStream, warn, err); + + return true; +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, const char *filename, const char *mtl_basedir, + bool trianglulate, bool default_vcols_fallback) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + attrib->colors.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]" << std::endl; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir = mtl_basedir ? mtl_basedir : ""; + if (!baseDir.empty()) { +#ifndef _WIN32 + const char dirsep = '/'; +#else + const char dirsep = '\\'; +#endif + if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader, + trianglulate, default_vcols_fallback); +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, std::istream *inStream, + MaterialReader *readMatFn /*= NULL*/, bool triangulate, + bool default_vcols_fallback) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector vc; + std::vector tags; + std::vector faceGroup; + std::vector lineGroup; + std::string name; + + // material + std::map material_map; + int material = -1; + + // smoothing group id + unsigned int current_smoothing_id = + 0; // Initial value. 0 means no smoothing. + + int greatest_v_idx = -1; + int greatest_vn_idx = -1; + int greatest_vt_idx = -1; + + shape_t shape; + + bool found_all_colors = true; + + size_t line_num = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + line_num++; + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + real_t x, y, z; + real_t r, g, b; + + found_all_colors &= parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token); + + v.push_back(x); + v.push_back(y); + v.push_back(z); + + if (found_all_colors || default_vcols_fallback) { + vc.push_back(r); + vc.push_back(g); + vc.push_back(b); + } + + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y; + parseReal2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // line + if (token[0] == 'l' && IS_SPACE((token[1]))) { + token += 2; + + line_t line_cache; + bool end_line_bit = 0; + while (!IS_NEW_LINE(token[0])) { + // get index from string + int idx = 0; + fixIndex(parseInt(&token), 0, &idx); + + size_t n = strspn(token, " \t\r"); + token += n; + + if (!end_line_bit) { + line_cache.idx0 = idx; + } else { + line_cache.idx1 = idx; + lineGroup.push_back(line_cache.idx0); + lineGroup.push_back(line_cache.idx1); + line_cache = line_t(); + } + end_line_bit = !end_line_bit; + } + + continue; + } + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + face_t face; + + face.smoothing_group_id = current_smoothing_id; + face.vertex_indices.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `f' line(e.g. zero value for face index. line " << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx; + greatest_vn_idx = + greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx; + greatest_vt_idx = + greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx; + + face.vertex_indices.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + faceGroup.push_back(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + std::stringstream ss; + ss << token; + std::string namebuf = ss.str(); + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportGroupsToShape()` call. + exportGroupsToShape(&shape, faceGroup, lineGroup, tags, material, name, + triangulate, v); + faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', filenames); + + if (filenames.empty()) { + if (warn) { + std::stringstream ss; + ss << "Looks like empty filename for mtllib. Use default " + "material (line " << line_num << ".)\n"; + + (*warn) += ss.str(); + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), materials, + &material_map, &warn_mtl, &err_mtl); + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, + material, name, triangulate, v); + (void)ret; // return value not used. + + if (shape.mesh.indices.size() > 0) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + faceGroup.clear(); + + std::vector names; + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + // names[0] must be 'g' + + if (names.size() < 2) { + // 'g' with empty names + if (warn) { + std::stringstream ss; + ss << "Empty group name. line: " << line_num << "\n"; + (*warn) += ss.str(); + name = ""; + } + } else { + std::stringstream ss; + ss << names[1]; + + // tinyobjloader does not support multiple groups for a primitive. + // Currently we concatinate multiple group names with a space to get + // single group name. + + for (size_t i = 2; i < names.size(); i++) { + ss << " " << names[i]; + } + + name = ss.str(); + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, + material, name, triangulate, v); + if (ret) { + shapes->push_back(shape); + } + + // material = -1; + faceGroup.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + token += 2; + std::stringstream ss; + ss << token; + name = ss.str(); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + const int max_tag_nums = 8192; // FIXME(syoyo): Parameterize. + tag_t tag; + + token += 2; + + tag.name = parseString(&token); + + tag_sizes ts = parseTagTriple(&token); + + if (ts.num_ints < 0) { + ts.num_ints = 0; + } + if (ts.num_ints > max_tag_nums) { + ts.num_ints = max_tag_nums; + } + + if (ts.num_reals < 0) { + ts.num_reals = 0; + } + if (ts.num_reals > max_tag_nums) { + ts.num_reals = max_tag_nums; + } + + if (ts.num_strings < 0) { + ts.num_strings = 0; + } + if (ts.num_strings > max_tag_nums) { + ts.num_strings = max_tag_nums; + } + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = parseInt(&token); + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + tag.stringValues[i] = parseString(&token); + } + + tags.push_back(tag); + + continue; + } + + if (token[0] == 's' && IS_SPACE(token[1])) { + // smoothing group id + token += 2; + + // skip space. + token += strspn(token, " \t"); // skip space + + if (token[0] == '\0') { + continue; + } + + if (token[0] == '\r' || token[1] == '\n') { + continue; + } + + if (strlen(token) >= 3) { + if (token[0] == 'o' && token[1] == 'f' && token[2] == 'f') { + current_smoothing_id = 0; + } + } else { + // assume number + int smGroupId = parseInt(&token); + if (smGroupId < 0) { + // parse error. force set to 0. + // FIXME(syoyo): Report warning. + current_smoothing_id = 0; + } else { + current_smoothing_id = static_cast(smGroupId); + } + } + + continue; + } // smoothing group id + + // Ignore unknown command. + } + + // not all vertices have colors, no default colors desired? -> clear colors + if (!found_all_colors && !default_vcols_fallback) { + vc.clear(); + } + + if (greatest_v_idx >= static_cast(v.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex indices out of bounds (line " << line_num << ".)\n" << std::endl; + (*warn) += ss.str(); + } + } + if (greatest_vn_idx >= static_cast(vn.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex normal indices out of bounds (line " << line_num << ".)\n" << std::endl; + (*warn) += ss.str(); + } + } + if (greatest_vt_idx >= static_cast(vt.size() / 2)) { + if (warn) { + std::stringstream ss; + ss << "Vertex texcoord indices out of bounds (line " << line_num << ".)\n" << std::endl; + (*warn) += ss.str(); + } + } + + bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, material, + name, triangulate, v); + // exportGroupsToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.indices.size()) { + shapes->push_back(shape); + } + faceGroup.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + attrib->colors.swap(vc); + + return true; +} + +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data /*= NULL*/, + MaterialReader *readMatFn /*= NULL*/, + std::string *warn, /* = NULL*/ + std::string *err /*= NULL*/) { + std::stringstream errss; + + // material + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + // TODO(syoyo): Support parsing vertex color extension. + real_t x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; // y and z are optional. default = 0.0 + parseReal3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), + static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + std::stringstream ss; + ss << token; + std::string namebuf = ss.str(); + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf.c_str(), material_id); + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', filenames); + + if (filenames.empty()) { + if (warn) { + (*warn) += + "Looks like empty filename for mtllib. Use default " + "material. \n"; + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), &materials, + &material_map, &warn_mtl, &err_mtl); + + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; // This should be warn message. + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } else { + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), + static_cast(materials.size())); + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), + static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + token += 2; + + std::stringstream ss; + ss << token; + std::string object_name = ss.str(); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + token += 2; + std::stringstream ss; + ss << token; + tag.name = ss.str(); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + std::stringstream ss; + ss << token; + tag.stringValues[i] = ss.str(); + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace tinyobj + +#endif diff --git a/Thirdparty/Pangolin/package.xml b/Thirdparty/Pangolin/package.xml new file mode 100644 index 0000000..5fe505a --- /dev/null +++ b/Thirdparty/Pangolin/package.xml @@ -0,0 +1,16 @@ + + + pangolin + 0.6.0 + pangolin + Steven Lovegrove + Steven Lovegrove + MIT + cmake + libglew-dev + cmake + python3-dev + + cmake + + diff --git a/Thirdparty/Pangolin/pyexamples/SimpleDisplay.py b/Thirdparty/Pangolin/pyexamples/SimpleDisplay.py new file mode 100644 index 0000000..1c2a4da --- /dev/null +++ b/Thirdparty/Pangolin/pyexamples/SimpleDisplay.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +import sys + +sys.path.append("../build/src") + +import pypangolin as pango +from OpenGL.GL import * + + +def a_callback(): + print("a pressed") + + +def main(): + win = pango.CreateWindowAndBind("pySimpleDisplay", 640, 480) + glEnable(GL_DEPTH_TEST) + + pm = pango.ProjectionMatrix(640, 480, 420, 420, 320, 240, 0.1, 1000) + mv = pango.ModelViewLookAt(-0, 0.5, -3, 0, 0, 0, pango.AxisY) + s_cam = pango.OpenGlRenderState(pm, mv) + + ui_width = 180 + + handler = pango.Handler3D(s_cam) + d_cam = ( + pango.CreateDisplay() + .SetBounds( + pango.Attach(0), + pango.Attach(1), + pango.Attach.Pix(ui_width), + pango.Attach(1), + -640.0 / 480.0, + ) + .SetHandler(handler) + ) + + pango.CreatePanel("ui").SetBounds( + pango.Attach(0), pango.Attach(1), pango.Attach(0), pango.Attach.Pix(ui_width) + ) + var_ui = pango.Var("ui") + var_ui.a_Button = False + var_ui.a_double = (0.0, pango.VarMeta(0, 5)) + var_ui.an_int = (2, pango.VarMeta(0, 5)) + var_ui.a_double_log = (3.0, pango.VarMeta(1, 1e4, logscale=True)) + var_ui.a_checkbox = (False, pango.VarMeta(toggle=True)) + var_ui.an_int_no_input = 2 + var_ui.a_str = "sss" + + ctrl = -96 + pango.RegisterKeyPressCallback(ctrl + ord("a"), a_callback) + + while not pango.ShouldQuit(): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + if var_ui.a_checkbox: + var_ui.an_int = var_ui.a_double + + var_ui.an_int_no_input = var_ui.an_int + + d_cam.Activate(s_cam) + pango.glDrawColouredCube() + pango.FinishFrame() + + +if __name__ == "__main__": + main() diff --git a/Thirdparty/Pangolin/pyexamples/SimplePlot.py b/Thirdparty/Pangolin/pyexamples/SimplePlot.py new file mode 100644 index 0000000..e86d402 --- /dev/null +++ b/Thirdparty/Pangolin/pyexamples/SimplePlot.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +import sys +sys.path.append('../build/src') + +from OpenGL.GL import * +import pypangolin as pango +import math + +def main(): + win = pango.CreateWindowAndBind("main py_pangolin", 640, 480) + log = pango.DataLog() + log.SetLabels(["sin(t)", "cos(t)", "sin(t)+cos(t)"]) + + t=0; + tinc=0.01 + + plotter = pango.Plotter(log,0,4*math.pi/tinc,-2,2,math.pi/(4*tinc),0.5); + plotter.Track("$i") + plotter.AddMarker(pango.Marker.Vertical, -1000, pango.Marker.LessThan, pango.Colour.Blue().WithAlpha(0.2)) + plotter.AddMarker(pango.Marker.Horizontal, 100, pango.Marker.GreaterThan, pango.Colour.Red().WithAlpha(0.2)) + plotter.AddMarker(pango.Marker.Horizontal, 10, pango.Marker.Equal, pango.Colour.Green().WithAlpha(0.2)) + plotter.SetBounds(pango.Attach(0), pango.Attach(1), + pango.Attach(0), pango.Attach(1)) + + pango.DisplayBase().AddDisplay(plotter) + + while not pango.ShouldQuit(): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + log.Log(math.sin(t), math.cos(t), math.sin(t)+math.cos(t)) + t+=tinc + + pango.FinishFrame() + +if __name__ == "__main__": + main() diff --git a/Thirdparty/Pangolin/pyexamples/SimpleVideo.py b/Thirdparty/Pangolin/pyexamples/SimpleVideo.py new file mode 100644 index 0000000..54f0239 --- /dev/null +++ b/Thirdparty/Pangolin/pyexamples/SimpleVideo.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +import sys +import os +import argparse +import numpy as np +import time +import json + +# If this example doesn't work, it's probably because this path is wrong... +sys.path.append('../build/src') + +import pypangolin as pango + +def main(flags): + vid_uri = flags.pango + vout_uri = flags.pangoOut + + vid = pango.VideoInput(vid_uri) + vout = pango.VideoOutput(vout_uri) if vout_uri else None + + device_properties = vid.DeviceProperties() + + # print metadata + print("Opened video uri: '{}' with {} x {} dimensions".format( vid_uri,vid.Width(),vid.Height())) + + # user specified initial frame + vid.Seek(flags.startFrame) + + # show each frame + streamsBitDepth = vid.GetStreamsBitDepth() + + for frame in vid: + if vout: + vout.WriteStreams(frame, streamsBitDepth, vid.FrameProperties(), device_properties); + + # frame is a list of Images! One per stream + # process(frame) + + # printing + sys.stdout.write('\rframe: {} / {}'.format(vid.GetCurrentFrameId(), vid.GetTotalFrames())) + + print('\nDONE') + +if __name__ == "__main__": + # input flags + parser = argparse.ArgumentParser('Read a .pango file frame by frame. Optionally stream to another video output.') + parser.add_argument( + '--pango', type=str, + help='path to the input pango file.') + parser.add_argument( + '--startFrame', type=int, default=0, + help='index of the start frame (inclusive)') + parser.add_argument( + '--pangoOut', type=str, default=None, + help='path to the output pango file.') + + # main function + main(parser.parse_args()) diff --git a/Thirdparty/Pangolin/src/CMakeLists.txt b/Thirdparty/Pangolin/src/CMakeLists.txt new file mode 100644 index 0000000..a2c60ea --- /dev/null +++ b/Thirdparty/Pangolin/src/CMakeLists.txt @@ -0,0 +1,776 @@ +####################################################### +## Library sources + +macro( append_glob list glob ) + file(GLOB files ${glob}) + set(${list} "${${list}};${files}") +endmacro() + +## Header only includes / core headers +set( INCDIR "../include/pangolin" ) +set( HEADERS + ${INCDIR}/pangolin.h + ${INCDIR}/platform.h +) +append_glob(HEADERS ${INCDIR}/utils/*.h*) +append_glob(HEADERS ${INCDIR}/image/*.h*) +append_glob(HEADERS ${INCDIR}/log/*.h*) +append_glob(HEADERS ${INCDIR}/geometry/*.h*) + +### Store list of source files +append_glob(SOURCES utils/*.cpp) +append_glob(SOURCES image/*.cpp) +append_glob(SOURCES log/*.cpp) +append_glob(SOURCES geometry/*.cpp) + +### Store list of Video factory registery methods to call for init. +include(CreateMethodCallFile) +set( VIDEO_FACTORY_REG "" ) +set( WINDOW_FACTORY_REG "" ) + +####################################################### +## User build options + +option(BUILD_PANGOLIN_GUI "Build support for Pangolin GUI" ON) +if(BUILD_PANGOLIN_GUI) + append_glob(HEADERS ${INCDIR}/gl/*.h*) + append_glob(HEADERS ${INCDIR}/display/*.h*) + append_glob(HEADERS ${INCDIR}/handler/*.h*) + + append_glob(SOURCES gl/*.cpp) + append_glob(SOURCES display/*.cpp) + append_glob(SOURCES handler/*.cpp) + + if(NOT HAVE_GLES OR HAVE_GLES_2) + append_glob(HEADERS ${INCDIR}/plot/*.h*) + append_glob(SOURCES plot/*.cpp) + endif() + +endif() + +option(BUILD_PANGOLIN_VARS "Build support for Pangolin Vars" ON) +if(BUILD_PANGOLIN_VARS) + append_glob(HEADERS ${INCDIR}/var/*.h*) + append_glob(SOURCES var/*.cpp) + + if(BUILD_PANGOLIN_GUI) + list(APPEND HEADERS ${INCDIR}/display/widgets/widgets.h ) + list(APPEND SOURCES display/widgets/widgets.cpp ) + endif() +endif() + +option(BUILD_PANGOLIN_VIDEO "Build support for Pangolin Video Utilities" ON) +if(BUILD_PANGOLIN_VIDEO) + # Generic video includes + append_glob(HEADERS ${INCDIR}/video/*.h*) + append_glob(SOURCES video/*.cpp) + + # Generic video drivers + list(APPEND HEADERS + ${INCDIR}/video/drivers/test.h + ${INCDIR}/video/drivers/images.h + ${INCDIR}/video/drivers/images_out.h + ${INCDIR}/video/drivers/split.h + ${INCDIR}/video/drivers/truncate.h + ${INCDIR}/video/drivers/pvn.h + ${INCDIR}/video/drivers/pango.h + ${INCDIR}/video/drivers/pango_video_output.h + ${INCDIR}/video/drivers/debayer.h + ${INCDIR}/video/drivers/shift.h + ${INCDIR}/video/drivers/mirror.h + ${INCDIR}/video/drivers/unpack.h + ${INCDIR}/video/drivers/pack.h + ${INCDIR}/video/drivers/join.h + ${INCDIR}/video/drivers/merge.h + ${INCDIR}/video/drivers/thread.h + ) + list(APPEND SOURCES + video/drivers/test.cpp + video/drivers/images.cpp + video/drivers/images_out.cpp + video/drivers/split.cpp + video/drivers/truncate.cpp + video/drivers/pvn.cpp + video/drivers/pango.cpp + video/drivers/pango_video_output.cpp + video/drivers/debayer.cpp + video/drivers/shift.cpp + video/drivers/mirror.cpp + video/drivers/unpack.cpp + video/drivers/pack.cpp + video/drivers/join.cpp + video/drivers/merge.cpp + video/drivers/json.cpp + video/drivers/thread.cpp + ) + + list(APPEND VIDEO_FACTORY_REG + RegisterTestVideoFactory + RegisterImagesVideoFactory + RegisterImagesVideoOutputFactory + RegisterSplitVideoFactory + RegisterTruncateVideoFactory + RegisterPvnVideoFactory + RegisterPangoVideoFactory + RegisterPangoVideoOutputFactory + RegisterDebayerVideoFactory + RegisterShiftVideoFactory + RegisterMirrorVideoFactory + RegisterUnpackVideoFactory + RegisterPackVideoFactory + RegisterJoinVideoFactory + RegisterMergeVideoFactory + RegisterJsonVideoFactory + RegisterThreadVideoFactory + ) + + if(_LINUX_) + list(APPEND HEADERS ${INCDIR}/video/drivers/shared_memory.h) + list(APPEND SOURCES video/drivers/shared_memory.cpp) + # Required for shared memory API using some versions of glibc + list(APPEND LINK_LIBS rt pthread) + endif() + +endif() + +if(BUILD_PANGOLIN_GUI AND BUILD_PANGOLIN_VARS AND BUILD_PANGOLIN_VIDEO ) + list(APPEND HEADERS ${INCDIR}/tools/video_viewer.h) + list(APPEND SOURCES tools/video_viewer.cpp) +endif() + +if(_LINUX_) + set(OpenGL_GL_PREFERENCE "GLVND") +endif() + +####################################################### +## Setup required includes / link info + +option(DISPLAY_X11 "X11 Window Interface" ON) +option(DISPLAY_WAYLAND "Wayland Window Interface" OFF) + +if(BUILD_PANGOLIN_GUI) + if( ANDROID ) + # Android specific display code + list(APPEND HEADERS ${INCDIR}/display/device/display_android.h ) + list(APPEND SOURCES display/device/display_android.cpp ) + list(APPEND WINDOW_FACTORY_REG RegisterAndroidWindowFactory) + + if(HAVE_GLES_2) + list(APPEND LINK_LIBS "-lEGL;-lGLESv2" ) + else() + list(APPEND LINK_LIBS "-lEGL;-lGLESv1_CM" ) + endif() + elseif( IOS ) + list(APPEND LINK_LIBS "-framework OpenGLES" ) + list(APPEND HEADERS "${INCDIR}/ios/PangolinAppDelegate.h" "${INCDIR}/ios/PangolinViewController.h" ) + list(APPEND SOURCES "ios/PangolinAppDelegate.mm" "ios/PangolinViewController.mm" ) + list(APPEND WINDOW_FACTORY_REG RegisterIosWindowFactory) + else() + find_package(OpenGL REQUIRED) + list(APPEND USER_INC ${OPENGL_INCLUDE_DIR}) + list(APPEND LINK_LIBS ${OPENGL_LIBRARIES}) + + if(NOT BUILD_EXTERN_GLEW) + find_package(GLEW REQUIRED) + endif() + list(APPEND USER_INC ${GLEW_INCLUDE_DIR}) + list(APPEND LINK_LIBS ${GLEW_LIBRARY}) + endif() + + if( HAVE_GLES_2 ) + # Add Pangolins backwards compat layer. + list(APPEND HEADERS ${INCDIR}/gl2engine.h ) + list(APPEND SOURCES gl2engine.cpp) + endif() + + # headless offscreen rendering via EGL + find_package(OpenGL QUIET COMPONENTS EGL) + if(OpenGL_EGL_FOUND) + list(APPEND WINDOW_FACTORY_REG RegisterNoneWindowFactory) + list(APPEND SOURCES display/device/display_headless.cpp) + list(APPEND LINK_LIBS ${OPENGL_egl_LIBRARY} ) + endif() +endif() + +####################################################### +## Find optional dependencies + +if(ANDROID) + # Fix issue with thread local storage on android. + add_definitions(-fno-data-sections) + list(APPEND LINK_LIBS android log) +elseif(IOS) + # Nothing specific in here yet. +else() + if(BUILD_PANGOLIN_GUI) + if(_WIN_) + list(APPEND WINDOW_FACTORY_REG RegisterWinWindowFactory) + list(APPEND SOURCES display/device/display_win.cpp ) + elseif(_OSX_) + list(APPEND WINDOW_FACTORY_REG RegisterOsxWindowFactory) + list(APPEND SOURCES display/device/display_osx.mm display/device/PangolinNSApplication.mm display/device/PangolinNSGLView.mm ) + list(APPEND LINK_LIBS "-framework Cocoa" ) + elseif(_LINUX_) + # Wayland + if(DISPLAY_WAYLAND) + find_package(Wayland QUIET) + if(WAYLAND_CLIENT_FOUND) + find_package(Wayland REQUIRED) + find_package(PkgConfig) + pkg_check_modules(xkbcommon REQUIRED xkbcommon) + pkg_check_modules(egl QUIET egl) + + # find Wayland protocols + pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) + + # generate header for protocol 'xdg_shell' + set(XDG_PROT_DEF "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml") + if(EXISTS ${XDG_PROT_DEF}) + # use the 'xdg_shell' protocol + add_definitions(-DUSE_WL_XDG=1) + + # find 'wayland-scanner' executable + pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner) + + # generate protocol implementation + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h + COMMAND ${WAYLAND_SCANNER} client-header ${XDG_PROT_DEF} xdg-shell-client-protocol.h) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-protocol.c + COMMAND ${WAYLAND_SCANNER} private-code ${XDG_PROT_DEF} xdg-shell-protocol.c + DEPENDS xdg-shell-client-protocol.h) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + list(APPEND SOURCES xdg-shell-protocol.c) + + else() + # use deprecated 'wl_shell' interface + add_definitions(-DUSE_WL_XDG=0) + endif() + + list(APPEND WINDOW_FACTORY_REG RegisterWaylandWindowFactory) + list(APPEND SOURCES display/device/display_wayland.cpp) + list(APPEND LINK_LIBS + ${WAYLAND_CLIENT_LIBRARIES} + ${WAYLAND_EGL_LIBRARIES} + ${WAYLAND_CURSOR_LIBRARIES} + ${egl_LIBRARIES} + ${xkbcommon_LIBRARIES} + ) + list(APPEND INTERNAL_INC + ${WAYLAND_CLIENT_INCLUDE_DIR} + ${WAYLAND_EGL_INCLUDE_DIR} + ${WAYLAND_CURSOR_INCLUDE_DIR} + ${egl_INCLUDE_DIRS} + ${xkbcommon_INCLUDE_DIRS} + ) + endif() + endif() + + # X11 + find_package(X11 QUIET) + if(DISPLAY_X11 AND X11_FOUND) + list(APPEND WINDOW_FACTORY_REG RegisterX11WindowFactory) + list(APPEND USER_INC ${X11_INCLUDE_DIR}) + list(APPEND SOURCES display/device/display_x11.cpp ) + list(APPEND LINK_LIBS ${X11_LIBRARIES} ) + endif() + endif() + endif() +endif() + +if(UNIX) + append_glob(HEADERS ${INCDIR}/utils/posix/*.h*) + append_glob(SOURCES utils/posix/*.cpp) + if(_LINUX_) + # Required for shared memory API using some versions of glibc + list(APPEND LINK_LIBS rt pthread) + endif() +endif() + +option(BUILD_PANGOLIN_PYTHON "Build support for Pangolin Interactive Console" ON) +if(BUILD_PANGOLIN_PYTHON AND BUILD_PANGOLIN_GUI AND BUILD_PANGOLIN_VARS AND NOT _WIN_) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../external/pybind11/CMakeLists.txt") + add_subdirectory("../external/pybind11" "${CMAKE_CURRENT_BINARY_DIR}/external/pybind11") + set( pybind11_FOUND true) + else() + find_package(pybind11 QUIET) + endif() + + if(pybind11_FOUND) + set(HAVE_PYTHON 1) + + file(GLOB pypangolin_SRC "python/pypangolin/*.cpp" ) + file(GLOB pypangolin_HDR "python/pypangolin/*.hpp" ) + list(APPEND HEADERS + ${INCDIR}/console/ConsoleInterpreter.h + ${INCDIR}/console/ConsoleView.h + ${INCDIR}/python/pyinterpreter.h + ${INCDIR}/python/pypangolin_init.h + ${INCDIR}/python/pyuniqueobj.h + ${INCDIR}/python/pyvar.h + ${INCDIR}/python/pypangoio.h + ${pypangolin_HDR} + ) + list(APPEND SOURCES + console/ConsoleView.cpp + python/pyinterpreter.cpp + python/pypangolin_init.cpp + ${pypangolin_SRC} + ) + + # pybind11 stuff + list(APPEND INTERNAL_INC ${PYBIND11_INCLUDE_DIR}) + list(APPEND LINK_LIBS PRIVATE ${pybind11_LIBRARIES}) + + if(_GCC_) + set_source_files_properties(python/PyInterpreter.cpp PROPERTIES COMPILE_FLAGS "-Wno-missing-field-initializers") + set_source_files_properties(python/PyModulePangolin.cpp PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -Wno-missing-field-initializers") + endif() + list(APPEND INTERNAL_INC ${PYTHON_INCLUDE_DIRS}) + list(APPEND LINK_LIBS ${PYTHON_LIBRARIES}) + message(STATUS "Python Found and Enabled (with pybind11)") + endif() +endif() + +option(BUILD_PANGOLIN_EIGEN "Build support for Eigen matrix types" ON) +if(BUILD_PANGOLIN_EIGEN) + find_package(Eigen QUIET) + if(EIGEN_FOUND) + set(HAVE_EIGEN 1) + list(APPEND USER_INC ${EIGEN_INCLUDE_DIR} ) + if(_CLANG_) + # Eigen causes many of these errors. Suppress. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register") + endif() + message(STATUS "Eigen Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_TOON "Build support for TooN matrix types" ON) +if(BUILD_PANGOLIN_TOON) + find_package(TooN QUIET) + if(TooN_FOUND) + set(HAVE_TOON 1) + list(APPEND USER_INC ${TooN_INCLUDE_DIR} ) + message(STATUS "TooN Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBDC1394 "Build support for libdc1394 video input" ON) +if(BUILD_PANGOLIN_LIBDC1394 AND BUILD_PANGOLIN_VIDEO) + find_package(DC1394 QUIET) + if(DC1394_FOUND) + set(HAVE_DC1394 1) + list(APPEND INTERNAL_INC ${DC1394_INCLUDE_DIR} ) + list(APPEND LINK_LIBS ${DC1394_LIBRARY} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/firewire.h ${INCDIR}/video/drivers/deinterlace.h ) + list(APPEND SOURCES video/drivers/firewire.cpp video/drivers/deinterlace.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterFirewireVideoFactory ) + message(STATUS "libdc1394 Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_V4L "Build support for V4L video input" ON) +if(BUILD_PANGOLIN_V4L AND BUILD_PANGOLIN_VIDEO AND _LINUX_) + set(HAVE_V4L 1) + list(APPEND HEADERS ${INCDIR}/video/drivers/v4l.h) + list(APPEND SOURCES video/drivers/v4l.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterV4lVideoFactory ) + message(STATUS "V4L Found and Enabled") +endif() + +option(BUILD_PANGOLIN_FFMPEG "Build support for ffmpeg video input" ON) +if(BUILD_PANGOLIN_FFMPEG AND BUILD_PANGOLIN_VIDEO) + find_package(FFMPEG QUIET) + if(FFMPEG_FOUND) + set(HAVE_FFMPEG 1) + list(APPEND INTERNAL_INC ${FFMPEG_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${FFMPEG_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/ffmpeg.h) + list(APPEND SOURCES video/drivers/ffmpeg.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterFfmpegVideoFactory ) + list(APPEND VIDEO_FACTORY_REG RegisterFfmpegVideoOutputFactory ) + + if(_GCC_) + # FFMPEG is a real pain for deprecating the API. + set_source_files_properties(video/drivers/ffmpeg.cpp PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations") + endif() + message(STATUS "ffmpeg Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBREALSENSE "Build support for LibRealSense video input" ON) +if(BUILD_PANGOLIN_LIBREALSENSE AND BUILD_PANGOLIN_VIDEO) + find_package(LibRealSense QUIET) + if(LIBREALSENSE_FOUND) + set(HAVE_LIBREALSENSE 1) + list(APPEND INTERNAL_INC ${LIBREALSENSE_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${LIBREALSENSE_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/realsense.h ) + list(APPEND SOURCES video/drivers/realsense.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterRealSenseVideoFactory ) + message(STATUS "LibRealSense Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBREALSENSE2 "Build support for LibRealSense2 video input" ON) +if(BUILD_PANGOLIN_LIBREALSENSE2 AND BUILD_PANGOLIN_VIDEO) + find_package(LibRealSense2 QUIET) + if(LIBREALSENSE2_FOUND) + set(HAVE_LIBREALSENSE2 1) + list(APPEND INTERNAL_INC ${LIBREALSENSE2_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${LIBREALSENSE2_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/realsense2.h ) + list(APPEND SOURCES video/drivers/realsense2.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterRealSense2VideoFactory ) + message(STATUS "LibRealSense2 Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_OPENNI "Build support for OpenNI video input" ON) +if(BUILD_PANGOLIN_OPENNI AND BUILD_PANGOLIN_VIDEO) + find_package(OpenNI QUIET) + if(OPENNI_FOUND) + set(HAVE_OPENNI 1) + if(_LINUX_) + add_definitions(-Dlinux=1) + endif() + list(APPEND INTERNAL_INC ${OPENNI_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${OPENNI_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/openni.h ) + list(APPEND SOURCES video/drivers/openni.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterOpenNiVideoFactory ) + message(STATUS "OpenNI Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_OPENNI2 "Build support for OpenNI2 video input" ON) +if(BUILD_PANGOLIN_OPENNI2 AND BUILD_PANGOLIN_VIDEO) + find_package(OpenNI2 QUIET) + if(OPENNI2_FOUND) + set(HAVE_OPENNI2 1) + if(_LINUX_) + add_definitions(-Dlinux=1) + endif() + list(APPEND INTERNAL_INC ${OPENNI2_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${OPENNI2_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/openni2.h ) + list(APPEND SOURCES video/drivers/openni2.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterOpenNi2VideoFactory ) + message(STATUS "OpenNI2 Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBUVC "Build support for libuvc video input" ON) +if(BUILD_PANGOLIN_LIBUVC AND BUILD_PANGOLIN_VIDEO) + find_package(uvc QUIET) + if(uvc_FOUND) + set(HAVE_UVC 1) + list(APPEND INTERNAL_INC ${uvc_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${uvc_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/uvc.h ) + list(APPEND SOURCES video/drivers/uvc.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterUvcVideoFactory ) + if(_WIN_) + find_package(pthread REQUIRED QUIET) + list(APPEND LINK_LIBS ${pthread_LIBRARIES} ) + + find_package(libusb1 REQUIRED QUIET) + list(APPEND LINK_LIBS ${libusb1_LIBRARIES} ) + endif() + message(STATUS "libuvc Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_UVC_MEDIAFOUNDATION "Build support for MediaFoundation UVC input" ON) +if (BUILD_PANGOLIN_UVC_MEDIAFOUNDATION AND BUILD_PANGOLIN_VIDEO) + find_package(MediaFoundation QUIET) + if (MediaFoundation_FOUND) + list(APPEND LINK_LIBS ${MediaFoundation_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/uvc_mediafoundation.h ) + list(APPEND SOURCES video/drivers/uvc_mediafoundation.cpp ) + list(APPEND VIDEO_FACTORY_REG RegisterUvcMediaFoundationVideoFactory ) + message(STATUS "MediaFoundation Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_DEPTHSENSE "Build support for DepthSense video input" ON) +if(BUILD_PANGOLIN_DEPTHSENSE AND BUILD_PANGOLIN_VIDEO) + find_package(DepthSense QUIET) + if(DepthSense_FOUND) + set(HAVE_DEPTHSENSE 1) + list(APPEND INTERNAL_INC ${DepthSense_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${DepthSense_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/depthsense.h ) + list(APPEND SOURCES video/drivers/depthsense.cpp) + list(APPEND VIDEO_FACTORY_REG RegisterDepthSenseVideoFactory ) + message(STATUS "DepthSense Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_TELICAM "Build support for TeliCam video input" ON) +if(BUILD_PANGOLIN_TELICAM AND BUILD_PANGOLIN_VIDEO) + find_package(TeliCam QUIET) + if(TeliCam_FOUND) + set(HAVE_TELICAM 1) + list(APPEND INTERNAL_INC ${TeliCam_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${TeliCam_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/teli.h ) + list(APPEND SOURCES video/drivers/teli.cpp ) + list(APPEND VIDEO_FACTORY_REG RegisterTeliVideoFactory ) + + message(STATUS "TeliCam Found and Enabled" ) + endif() +endif() + +option(BUILD_PANGOLIN_PLEORA "Build support for Pleora video input" ON) +if(BUILD_PANGOLIN_PLEORA AND BUILD_PANGOLIN_VIDEO) + find_package(Pleora QUIET) + if(Pleora_FOUND) + set(HAVE_PLEORA 1) + list(APPEND INTERNAL_INC ${Pleora_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${Pleora_LIBRARIES} ) + list(APPEND HEADERS ${INCDIR}/video/drivers/pleora.h ) + list(APPEND SOURCES video/drivers/pleora.cpp ) + list(APPEND VIDEO_FACTORY_REG RegisterPleoraVideoFactory ) + + if(_GCC_) + # Suppress warnings generated from Pleora SDK. + set_source_files_properties(video/drivers/pleora.cpp PROPERTIES COMPILE_FLAGS -Wno-unknown-pragmas) + set_source_files_properties(video/video.cpp PROPERTIES COMPILE_FLAGS -Wno-unknown-pragmas) + endif() + message(STATUS "Pleora Found and Enabled" ) + endif() +endif() + +option(BUILD_PANGOLIN_LIBPNG "Build support for libpng image input" ON) +if(BUILD_PANGOLIN_LIBPNG) + if(NOT BUILD_EXTERN_LIBPNG) + find_package(PNG QUIET) + endif() + if(PNG_FOUND) + # (ZLIB is also found by FindPNG.cmake as its dependency) + set(HAVE_PNG 1) + list(APPEND INTERNAL_INC ${PNG_INCLUDE_DIR} ) + list(APPEND LINK_LIBS ${PNG_LIBRARY} ${ZLIB_LIBRARY} ) + message(STATUS "libpng Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBJPEG "Build support for libjpeg image input" ON) +if(BUILD_PANGOLIN_LIBJPEG) + if(NOT BUILD_EXTERN_LIBJPEG) + find_package(JPEG QUIET) + endif() + if(JPEG_FOUND) + set(HAVE_JPEG 1) + list(APPEND INTERNAL_INC ${JPEG_INCLUDE_DIR} ) + list(APPEND LINK_LIBS ${JPEG_LIBRARY} ) + message(STATUS "libjpeg Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBTIFF "Build support for libtiff image input" ON) +if(BUILD_PANGOLIN_LIBTIFF) + find_package(TIFF QUIET) + if(TIFF_FOUND) + set(HAVE_TIFF 1) + list(APPEND INTERNAL_INC ${TIFF_INCLUDE_DIR} ) + list(APPEND LINK_LIBS ${TIFF_LIBRARY} ) + message(STATUS "libtiff Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LIBOPENEXR "Build support for libopenexr image input" ON) +if(BUILD_PANGOLIN_LIBOPENEXR) + find_package(OpenEXR QUIET) + if(OpenEXR_FOUND) + set(HAVE_OPENEXR 1) + list(APPEND INTERNAL_INC ${OpenEXR_INCLUDE_DIR} ) + list(APPEND LINK_LIBS ${OpenEXR_LIBRARY} ) + message(STATUS "libopenexr Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_ZSTD "Build support for libzstd compression" ON) +if(BUILD_PANGOLIN_ZSTD) + find_package(zstd QUIET) + if(zstd_FOUND) + set(HAVE_ZSTD 1) + list(APPEND INTERNAL_INC ${zstd_INCLUDE_DIR} ) + list(APPEND LINK_LIBS ${zstd_LIBRARY} ) + message(STATUS "libzstd Found and Enabled") + endif() +endif() + +option(BUILD_PANGOLIN_LZ4 "Build support for liblz4 compression" ON) +if(BUILD_PANGOLIN_LZ4) + find_package(Lz4 QUIET) + if(Lz4_FOUND) + set(HAVE_LZ4 1) + list(APPEND INTERNAL_INC ${Lz4_INCLUDE_DIRS} ) + list(APPEND LINK_LIBS ${Lz4_LIBRARIES} ) + message(STATUS "liblz4 Found and Enabled") + endif() +endif() + +####################################################### +## Embed resource binary files + +include(EmbedBinaryFiles) + +if(BUILD_PANGOLIN_GUI) + embed_binary_files( "_embed_/fonts/*.ttf" "${CMAKE_CURRENT_BINARY_DIR}/fonts.cpp" ) + list(APPEND SOURCES "${CMAKE_CURRENT_BINARY_DIR}/fonts.cpp" ) +endif() + +####################################################### +## Add Libraries / Include Directories / Link directories + +set(INSTALL_INCLUDE_DIR "include") + +add_library(${LIBRARY_NAME} ${SOURCES} ${HEADERS}) +# 'System' includes shield us from warnings in those includes. +target_include_directories(${LIBRARY_NAME} SYSTEM PUBLIC ${USER_INC} PRIVATE ${INTERNAL_INC}) +target_include_directories(${LIBRARY_NAME} PUBLIC $ + $ + $) +target_link_libraries(${LIBRARY_NAME} PUBLIC ${LINK_LIBS}) + +## Generate symbol export helper header on MSVC +IF(MSVC) + string(TOUPPER ${LIBRARY_NAME} LIBRARY_NAME_CAPS) + include(GenerateExportHeader) + GENERATE_EXPORT_HEADER( ${LIBRARY_NAME} + BASE_NAME ${LIBRARY_NAME_CAPS} + EXPORT_MACRO_NAME ${LIBRARY_NAME_CAPS}_EXPORT + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/${LIBRARY_NAME}/${LIBRARY_NAME}_export.h" + STATIC_DEFINE ${LIBRARY_NAME_CAPS}_BUILT_AS_STATIC + ) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/${LIBRARY_NAME}/${LIBRARY_NAME}_export.h" + DESTINATION ${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}/${LIBRARY_NAME} + ) +ENDIF() + +## Set Special Compiler flags +if(MSVC) + set(CMAKE_CXX_FLAGS "/EHs ${CMAKE_CXX_FLAGS}") +elseif(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "-Wall -Wno-error=deprecated-declarations ${CMAKE_CXX_FLAGS}") +endif() + +####################################################### +## Create config.h file for inclusion in library + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/include/${LIBRARY_NAME}/config.h" +) + +####################################################### +## Create video_drivers.h file for inclusion in library +## This loads video driver factories based on cmake configuration + +CreateMethodCallFile( + "${CMAKE_CURRENT_BINARY_DIR}/include/${LIBRARY_NAME}/video_drivers.h" + "pangolin" "LoadBuiltInVideoDrivers" "${VIDEO_FACTORY_REG}" +) + +####################################################### +## Create window_frameworks.h file for inclusion in library +## This loads windowing framwork factories based on cmake configuration + +CreateMethodCallFile( + "${CMAKE_CURRENT_BINARY_DIR}/include/${LIBRARY_NAME}/window_frameworks.h" + "pangolin" "LoadBuiltInWindowFrameworks" "${WINDOW_FACTORY_REG}" +) + +####################################################### +## Python wrapper + +option(BUILD_PYPANGOLIN_MODULE "Python wrapper for Pangolin" ON) +if(BUILD_PYPANGOLIN_MODULE AND HAVE_PYTHON ) + file(GLOB pypangolin_SRC "python/pypangolin/*.hpp" "python/pypangolin/*.cpp" "python/pypangolin_module.cpp") + pybind11_add_module(pypangolin ${pypangolin_SRC}) + target_link_libraries(pypangolin PRIVATE ${LIBRARY_NAME}) + target_include_directories(pypangolin PRIVATE "${USER_INC}") +endif() + +####################################################### +## Generate Doxygen documentation target (make pangolin_doc) +find_package(Doxygen) +if(DOXYGEN_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../doc ) + add_custom_target(pangolin_doc + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../doc + COMMENT "Generating API documentation with Doxygen" VERBATIM + ) +endif() + +####################################################### + +# This relative path allows installed files to be relocatable. +set( CMAKECONFIG_INSTALL_DIR lib/cmake/${PROJECT_NAME} ) +file( RELATIVE_PATH REL_INCLUDE_DIR + "${CMAKE_INSTALL_PREFIX}/${CMAKECONFIG_INSTALL_DIR}" + "${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}" +) + +# Export library for easy inclusion from other cmake projects. APPEND allows +# call to function even as subdirectory of larger project. +FILE(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") +export( TARGETS ${LIBRARY_NAME} + APPEND FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake" ) + +# Version information +configure_file(${PROJECT_NAME}ConfigVersion.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" @ONLY) + +# Build tree config +set( EXPORT_LIB_INC_DIR "${PROJECT_SOURCE_DIR}/include;${CMAKE_CURRENT_BINARY_DIR}/include" ) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY IMMEDIATE ) + +# Install tree config +set( EXPORT_LIB_INC_DIR "\${PROJECT_CMAKE_DIR}/${REL_INCLUDE_DIR}" ) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake @ONLY ) + +# Add package to CMake package registery for use from the build tree +option( EXPORT_${PROJECT_NAME} + "Should the ${PROJECT_NAME} package be exported for use by other software" ON ) + +if( EXPORT_${PROJECT_NAME} ) + export( PACKAGE ${PROJECT_NAME} ) +endif() + +####################################################### +## Install headers / targets + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/${LIBRARY_NAME}/config.h" + DESTINATION ${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}/${LIBRARY_NAME} +) +install(DIRECTORY ${INCDIR} + DESTINATION ${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR} +) +install(TARGETS ${LIBRARY_NAME} + EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib + ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib +) + +####################################################### +## Install CMake config + +install( + FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION ${CMAKECONFIG_INSTALL_DIR} +) +install( + EXPORT ${PROJECT_NAME}Targets DESTINATION ${CMAKECONFIG_INSTALL_DIR} +) diff --git a/Thirdparty/Pangolin/src/Doxyfile.in b/Thirdparty/Pangolin/src/Doxyfile.in new file mode 100644 index 0000000..8146355 --- /dev/null +++ b/Thirdparty/Pangolin/src/Doxyfile.in @@ -0,0 +1,2281 @@ +# Doxyfile 1.8.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Pangolin" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Pangolin is a lightweight rapid development library for managing OpenGL display / interaction and video input" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- +# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, +# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, +# Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../include +INPUT += @CMAKE_CURRENT_SOURCE_DIR@/../README.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.h *.md + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = *internal* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = android_app android_poll_source PangolinAppDelegate + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /