This commit is contained in:
Ivan
2022-04-05 11:42:28 +03:00
commit 6dc0eb0fcf
5565 changed files with 1200500 additions and 0 deletions

776
thirdparty/Pangolin/src/CMakeLists.txt vendored Normal file
View File

@@ -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 $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}>)
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}
)

2281
thirdparty/Pangolin/src/Doxyfile.in vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
# Compute paths
get_filename_component( PROJECT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH )
SET( Pangolin_INCLUDE_DIRS "@EXPORT_LIB_INC_DIR@;@USER_INC@" )
SET( Pangolin_INCLUDE_DIR "@EXPORT_LIB_INC_DIR@;@USER_INC@" )
# Library dependencies (contains definitions for IMPORTED targets)
if( NOT TARGET @LIBRARY_NAME@ AND NOT @PROJECT_NAME@_BINARY_DIR )
include( "${PROJECT_CMAKE_DIR}/@PROJECT_NAME@Targets.cmake" )
@ExternConfig@
endif()
SET( Pangolin_LIBRARIES @LIBRARY_NAME@ )
SET( Pangolin_LIBRARY @LIBRARY_NAME@ )
SET( Pangolin_CMAKEMODULES @CMAKE_CURRENT_SOURCE_DIR@/../CMakeModules )

View File

@@ -0,0 +1,17 @@
set(PACKAGE_VERSION "@PANGOLIN_VERSION@")
# Check build type is valid
if( "System:${CMAKE_SYSTEM_NAME},Win64:${CMAKE_CL_64},Android:${ANDROID},iOS:${IOS}" STREQUAL
"System:@CMAKE_SYSTEM_NAME@,Win64:@CMAKE_CL_64@,Android:@ANDROID@,iOS:@IOS@" )
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()

Binary file not shown.

View File

@@ -0,0 +1,94 @@
Copyright (c) 2009, Mark Simonson (http://www.ms-studio.com, mark@marksimonson.com),
with Reserved Font Name Anonymous Pro.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

72
thirdparty/Pangolin/src/config.h.in vendored Normal file
View File

@@ -0,0 +1,72 @@
#ifndef PANGOLIN_CONFIG_H
#define PANGOLIN_CONFIG_H
/*
* Configuration Header for Pangolin
*/
/// Version
#define PANGOLIN_VERSION_MAJOR @PANGOLIN_VERSION_MAJOR@
#define PANGOLIN_VERSION_MINOR @PANGOLIN_VERSION_MINOR@
#define PANGOLIN_VERSION_STRING "@PANGOLIN_VERSION@"
/// Pangolin options
#cmakedefine BUILD_PANGOLIN_GUI
#cmakedefine BUILD_PANGOLIN_VARS
#cmakedefine BUILD_PANGOLIN_VIDEO
/// Configured libraries
#cmakedefine HAVE_CUDA
#cmakedefine HAVE_PYTHON
#cmakedefine HAVE_EIGEN
#cmakedefine HAVE_TOON
#cmakedefine HAVE_DC1394
#cmakedefine HAVE_V4L
#cmakedefine HAVE_OPENNI
#cmakedefine HAVE_LIBREALSENSE
#cmakedefine HAVE_OPENNI2
#cmakedefine HAVE_UVC
#cmakedefine HAVE_DEPTHSENSE
#cmakedefine HAVE_TELICAM
#cmakedefine HAVE_PLEORA
#cmakedefine HAVE_FFMPEG
#cmakedefine HAVE_FFMPEG_MAX_ANALYZE_DURATION2
#cmakedefine HAVE_FFMPEG_AVFORMAT_ALLOC_OUTPUT_CONTEXT2
#cmakedefine HAVE_FFMPEG_AVPIXELFORMAT
#cmakedefine HAVE_GLEW
#cmakedefine GLEW_STATIC
#cmakedefine HAVE_APPLE_OPENGL_FRAMEWORK
#cmakedefine HAVE_GLES
#cmakedefine HAVE_GLES_2
#cmakedefine HAVE_OCULUS
#cmakedefine HAVE_PNG
#cmakedefine HAVE_JPEG
#cmakedefine HAVE_TIFF
#cmakedefine HAVE_OPENEXR
#cmakedefine HAVE_ZSTD
#cmakedefine HAVE_LZ4
/// Platform
#cmakedefine _UNIX_
#cmakedefine _WIN_
#cmakedefine _OSX_
#cmakedefine _LINUX_
#cmakedefine _ANDROID_
#cmakedefine _IOS_
/// Compiler
#cmakedefine _GCC_
#cmakedefine _CLANG_
#cmakedefine _MSVC_
#if (__cplusplus > 199711L) || (_MSC_VER >= 1800)
#define CALLEE_HAS_VARIADIC_TEMPLATES
#endif
#endif //PANGOLIN_CONFIG_H

View File

@@ -0,0 +1,327 @@
#include <iterator>
#include <pangolin/console/ConsoleView.h>
#include <pangolin/utils/picojson.h>
#include <pangolin/gl/gldraw.h>
namespace pangolin
{
inline Colour ParseJson(const picojson::value& val)
{
return Colour(
val.contains("r") ? val["r"].get<double>() : 0.0,
val.contains("g") ? val["g"].get<double>() : 0.0,
val.contains("b") ? val["b"].get<double>() : 0.0,
val.contains("a") ? val["a"].get<double>() : 1.0
);
}
inline picojson::value toJson(const Colour& colour)
{
picojson::value ret(picojson::object_type,true);
ret["r"] = colour.r;
ret["g"] = colour.g;
ret["b"] = colour.b;
ret["a"] = colour.a;
return ret;
}
inline std::ostream& operator<<(std::ostream& os, const Colour& colour)
{
os << toJson(colour).serialize();
return os;
}
inline std::istream& operator>>(std::istream& is, Colour& colour)
{
picojson::value val;
picojson::parse(val,is);
colour = ParseJson(val);
return is;
}
inline void glColour(const Colour& c)
{
glColor4f(c.r,c.g,c.b,c.a);
}
ConsoleView::ConsoleView(ConsoleInterpreter* interpreter)
: interpreter(interpreter),
font(GlFont::I()),
carat(0),
hiding(false),
bottom(1.0f),
background_colour(0.2f, 0.0f, 0.0f, 0.6f),
animation_speed(0.2)
{
SetHandler(this);
line_colours[ConsoleLineTypeCmd] = Colour(1.0f,1.0f,1.0f,1.0f);
line_colours[ConsoleLineTypeCmdOptions] = Colour(0.9f,0.9f,0.9f,1.0f);
line_colours[ConsoleLineTypeOutput] = Colour(0.0f,1.0f,1.0f,1.0f);
line_colours[ConsoleLineTypeHelp] = Colour(1.0f,0.8f,1.0f,1.0f);
line_colours[ConsoleLineTypeStdout] = Colour(0.0f,0.0f,1.0f,1.0f);
line_colours[ConsoleLineTypeStderr] = Colour(1.0f,0.8f,0.8f,1.0f);
Var<Colour>::Attach("pangolin.console.colours.Background", background_colour);
Var<Colour>::Attach("pangolin.console.colours.Cmd", line_colours[ConsoleLineTypeCmd]);
Var<Colour>::Attach("pangolin.console.colours.CmdOptions", line_colours[ConsoleLineTypeCmdOptions]);
Var<Colour>::Attach("pangolin.console.colours.Stdout", line_colours[ConsoleLineTypeStdout]);
Var<Colour>::Attach("pangolin.console.colours.Stderr", line_colours[ConsoleLineTypeStderr]);
Var<Colour>::Attach("pangolin.console.colours.Output", line_colours[ConsoleLineTypeOutput]);
Var<Colour>::Attach("pangolin.console.colours.Help", line_colours[ConsoleLineTypeHelp]);
Var<float>::Attach("pango.console.animation_speed", animation_speed);
AddLine("Pangolin Python Command Prompt:", ConsoleLineTypeHelp);
AddLine("===============================", ConsoleLineTypeHelp);
}
ConsoleView::~ConsoleView() {
delete interpreter;
}
void ConsoleView::ProcessOutputLines()
{
// empty output queue
ConsoleLine line_in;
while(interpreter->PullLine(line_in))
{
AddLine(line_in.text, line_in.linetype);
}
}
View& ConsoleView::ShowWithoutAnimation(bool should_show){
Show(should_show);
bottom = show ? 1.0 : 0.0;
return *this;
}
View& ConsoleView::Show(bool should_show)
{
if(should_show) {
hiding = false;
show = true;
}else{
hiding = true;
}
return *this;
}
void ConsoleView::ToggleShow()
{
Show(!IsShown());
}
bool ConsoleView::IsShown() const
{
return show && !hiding;
}
void ConsoleView::DrawLine(const ConsoleView::Line& l, int carat=-1)
{
glColour(line_colours[l.linetype]);
l.text.Draw();
if(carat >= 0) {
const double w = font.Text(l.text.str.substr(0,carat)).Width();
glDrawLine(w,-2,w,font.Height()-4);
}
}
void ConsoleView::Render()
{
if(hiding) {
bottom += (1.0f - bottom) * animation_speed;
if(1.0 - bottom < 0.01) {
bottom = 1.0;
show = false;
hiding = false;
return;
}
}else{
if(bottom > 0.01f) {
bottom -= bottom*animation_speed;
}else{
bottom = 0.0f;
}
}
ProcessOutputLines();
#ifndef HAVE_GLES
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT | GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
#endif
this->ActivatePixelOrthographic();
glDisable(GL_DEPTH_TEST );
glDisable(GL_LIGHTING);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_LINE_SMOOTH);
glDisable( GL_COLOR_MATERIAL );
glLineWidth(1.0);
glEnable(GL_BLEND);
glBlendFunc( GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA );
glColour(background_colour);
GLfloat verts[] = { 0.0f, (GLfloat)v.h,
(GLfloat)v.w, (GLfloat)v.h,
(GLfloat)v.w, bottom*v.h,
0.0f, bottom*v.h };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, verts);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
const double line_space = font.Height();
glTranslated(10.0, 10.0 + bottom*v.h, 0.0 );
DrawLine(current_line, carat);
glTranslated(0.0, line_space, 0.0);
for(size_t l=0; l < line_buffer.size(); ++l) {
DrawLine(line_buffer[l]);
glTranslated(0.0, line_space, 0.0);
}
#ifndef HAVE_GLES
glPopAttrib();
#endif
}
inline std::string CommonPrefix(const std::vector<std::string>& vec)
{
if(!vec.size()) return "";
size_t cmn = vec[0].size();
for(size_t i=1; i<vec.size(); ++i) {
cmn = std::min(vec[i].size(), cmn);
for(size_t p=0; p < cmn; ++p) {
if(vec[i][p] != vec[0][p]) {
cmn = p;
break;
}
}
}
return vec[0].substr(0,cmn);
}
void ConsoleView::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
{
static int hist_id = -1;
static std::string prefix;
static bool edited = true;
if(pressed) {
if(key=='\r') key = '\n';
GlText& txt = current_line.text;
const std::string cmd = txt.Text();
if(key=='`') {
ToggleShow();
} else if(key=='\n') {
interpreter->PushCommand(cmd);
line_buffer.push_front(current_line);
hist_id = -1;
prefix = "";
edited = true;
carat = 0;
txt.Clear();
}else if(key=='\t') {
std::vector<std::string> options = interpreter->Complete(cmd,100);
if(options.size()) {
const std::string common = CommonPrefix(options);
if(common.size() > cmd.size()) {
current_line = font.Text("%s", common.c_str());
carat = common.size();
}else{
std::stringstream s;
std::copy(options.begin(), options.end(), std::ostream_iterator<std::string>(s,", "));
AddLine(s.str(), ConsoleLineTypeCmdOptions);
}
}
}else if(key==PANGO_SPECIAL + PANGO_KEY_UP) {
if(edited) {
prefix = cmd;
edited = false;
}
Line* hist_line = GetLine(hist_id+1, ConsoleLineTypeCmd, prefix);
if(hist_line) {
current_line = *hist_line;
hist_id++;
}
}else if(key==PANGO_SPECIAL + PANGO_KEY_DOWN) {
if(edited) {
prefix = cmd;
edited = false;
}
Line* hist_line = GetLine(hist_id-1, ConsoleLineTypeCmd, prefix);
if(hist_line) {
current_line = *hist_line;
hist_id--;
}
}else if(key==PANGO_SPECIAL + PANGO_KEY_LEFT) {
if(carat > 0) carat--;
}else if(key==PANGO_SPECIAL + PANGO_KEY_RIGHT) {
if(carat < (int)txt.str.size()) carat++;
}else if(key==PANGO_SPECIAL + PANGO_KEY_HOME) {
carat = 0;
}else if(key==PANGO_SPECIAL + PANGO_KEY_END) {
carat = txt.Text().size();
}else if(key=='\b') {
if(carat > 0) {
std::string newstr = txt.Text();
newstr.erase(newstr.begin()+carat-1);
txt = font.Text("%s", newstr.c_str() );
carat--;
edited = true;
}
}else if(key==127) { // delete
if(carat < (int)txt.Text().size() ) {
std::string newstr = txt.Text();
newstr.erase(newstr.begin()+carat);
txt = font.Text("%s", newstr.c_str() );
edited = true;
}
}else if(key==PANGO_CTRL + 'c') {
txt = font.Text("");
carat = 0;
edited = true;
}else if(key < PANGO_SPECIAL){
std::string newstr = txt.Text();
newstr.insert(carat, 1, key);
txt = font.Text("%s", newstr.c_str());
++carat;
edited = true;
}
}
}
void ConsoleView::AddLine(const std::string& text, ConsoleLineType linetype )
{
line_buffer.push_front( Line( font.Text("%s",text.c_str()), linetype) );
}
ConsoleView::Line* ConsoleView::GetLine(int id, ConsoleLineType line_type, const std::string& prefix )
{
int match = 0;
for(Line& l : line_buffer)
{
if(l.linetype == line_type) {
const std::string substr = l.text.Text().substr(0,prefix.size());
if(substr == prefix ) {
if(id == match) {
return &l;
}else{
++match;
}
}
}
}
return nullptr;
}
}

View File

@@ -0,0 +1,95 @@
/* 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 <pangolin/platform.h>
#include <pangolin/display/display.h>
#include <pangolin/display/device/PangolinNSApplication.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
# define NSAnyEventMask NSEventMaskAny
#endif
////////////////////////////////////////////////////////////////////
// PangolinNSApplication
////////////////////////////////////////////////////////////////////
@implementation PangolinNSApplication
+ (void)run_pre
{
[[NSNotificationCenter defaultCenter]
postNotificationName:NSApplicationWillFinishLaunchingNotification
object:NSApp];
[[NSNotificationCenter defaultCenter]
postNotificationName:NSApplicationDidFinishLaunchingNotification
object:NSApp];
}
+ (void)run_step
{
NSEvent *event;
do{
event = [NSApp
nextEventMatchingMask:NSAnyEventMask
untilDate:nil
// untilDate: [NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
[NSApp sendEvent:event];
[NSApp updateWindows];
}while(event != nil);
}
@end
////////////////////////////////////////////////////////////////////
// PangolinWindowDelegate
////////////////////////////////////////////////////////////////////
@implementation PangolinWindowDelegate
- (BOOL)windowShouldClose:(id)sender {
PANGOLIN_UNUSED(sender);
pangolin::Quit();
return YES;
}
@end
////////////////////////////////////////////////////////////////////
// PangolinAppDelegate
////////////////////////////////////////////////////////////////////
@implementation PangolinAppDelegate
- (void)dealloc
{
[super dealloc];
}
@end

View File

@@ -0,0 +1,325 @@
#include <pangolin/platform.h>
#include <pangolin/gl/glinclude.h>
#include <pangolin/display/device/PangolinNSGLView.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/handler/handler_enums.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
# define NSDeviceIndependentModifierFlagsMask NSEventModifierFlagDeviceIndependentFlagsMask
# define NSShiftKeyMask NSEventModifierFlagShift
# define NSControlKeyMask NSEventModifierFlagControl
# define NSAlternateKeyMask NSEventModifierFlagOption
# define NSCommandKeyMask NSEventModifierFlagCommand
# define NSFunctionKeyMask NSEventModifierFlagFunction
#endif
namespace pangolin
{
extern __thread PangolinGl* context;
}
////////////////////////////////////////////////////////////////////
// Input maps
////////////////////////////////////////////////////////////////////
inline
int mapMouseButton(int osx_button )
{
const int map[] = {0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10};
return map[osx_button];
}
inline
int mapKeymap(int osx_key)
{
if(osx_key == NSUpArrowFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_UP;
else if(osx_key == NSDownArrowFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_DOWN;
else if(osx_key == NSLeftArrowFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_LEFT;
else if(osx_key == NSRightArrowFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_RIGHT;
else if(osx_key == NSPageUpFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_PAGE_UP;
else if(osx_key == NSPageDownFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_PAGE_DOWN;
else if(osx_key == NSHomeFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_HOME;
else if(osx_key == NSEndFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_END;
else if(osx_key == NSInsertFunctionKey)
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_INSERT;
else if(osx_key == NSDeleteCharacter )
return NSBackspaceCharacter;
else if(osx_key == NSDeleteFunctionKey)
return NSDeleteCharacter;
else {
return osx_key;
}
}
////////////////////////////////////////////////////////////////////
// PangolinNSGLView
////////////////////////////////////////////////////////////////////
@implementation PangolinNSGLView
-(id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat *)format
{
self = [super initWithFrame:frameRect pixelFormat:format];
context = pangolin::context;
return(self);
}
- (void)prepareOpenGL
{
[super prepareOpenGL];
}
-(void)reshape
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if ( [self wantsBestResolutionOpenGLSurface] && [ self.window respondsToSelector:@selector(backingScaleFactor) ] )
backing_scale = [self.window backingScaleFactor];
else
#endif
backing_scale = 1.0;
pangolin::process::Resize(self.bounds.size.width * backing_scale, self.bounds.size.height * backing_scale);
[[self openGLContext] update];
}
-(BOOL)acceptsFirstResponder
{
return(YES);
}
-(BOOL)becomeFirstResponder
{
return(YES);
}
-(BOOL)resignFirstResponder
{
return(YES);
}
-(BOOL)isFlipped
{
return(YES);
}
-(NSPoint)_Location:(NSEvent *)theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
location.x *= backing_scale;
location.y *= backing_scale;
return location;
}
////////////////////////////////////////////////////////////////////
// Keyboard
////////////////////////////////////////////////////////////////////
-(void)keyDown:(NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
NSString *str = [theEvent characters];
int len = (int)[str length];
for(int i = 0; i < len; i++)
{
const int osx_key = [str characterAtIndex:i];
pangolin::process::Keyboard(mapKeymap(osx_key), location.x, location.y);
}
}
-(void)keyUp:(NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
NSString *str = [theEvent characters];
int len = (int)[str length];
for(int i = 0; i < len; i++)
{
const int osx_key = [str characterAtIndex:i];
pangolin::process::KeyboardUp(mapKeymap(osx_key), location.x, location.y);
}
}
- (void)flagsChanged:(NSEvent *)event
{
unsigned int flags = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
if(flags&NSShiftKeyMask) {
context->mouse_state |= pangolin::KeyModifierShift;
}else{
context->mouse_state &= ~pangolin::KeyModifierShift;
}
if(flags&NSControlKeyMask) {
context->mouse_state |= pangolin::KeyModifierCtrl;
}else{
context->mouse_state &= ~pangolin::KeyModifierCtrl;
}
if(flags&NSAlternateKeyMask) {
context->mouse_state |= pangolin::KeyModifierAlt;
}else{
context->mouse_state &= ~pangolin::KeyModifierAlt;
}
if(flags&NSCommandKeyMask) {
context->mouse_state |= pangolin::KeyModifierCmd;
}else{
context->mouse_state &= ~pangolin::KeyModifierCmd;
}
if(flags&NSFunctionKeyMask) {
context->mouse_state |= pangolin::KeyModifierFnc;
}else{
context->mouse_state &= ~pangolin::KeyModifierFnc;
}
}
////////////////////////////////////////////////////////////////////
// Mouse Input
////////////////////////////////////////////////////////////////////
-(void)mouseDownCommon:(NSEvent *)theEvent
{
const int button = (int)[theEvent buttonNumber];
const NSPoint location = [self _Location: theEvent];
pangolin::process::Mouse(mapMouseButton(button), 0, location.x, location.y);
}
-(void)mouseUpCommon:(NSEvent *)theEvent
{
const int button = (int)[theEvent buttonNumber];
const NSPoint location = [self _Location: theEvent];
pangolin::process::Mouse(mapMouseButton(button), 1, location.x, location.y);
}
- (void)mouseDraggedCommon: (NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
pangolin::process::MouseMotion(location.x, location.y);
// pangolin::process::SubpixMotion(location.x, location.y, 1.0, 0.0, 0.0, 0.0);
}
-(void)mouseDown:(NSEvent *)theEvent
{
[self mouseDownCommon:theEvent];
}
-(void)mouseUp:(NSEvent *)theEvent
{
[self mouseUpCommon:theEvent];
}
- (void)mouseDragged: (NSEvent *)theEvent
{
[self mouseDraggedCommon:theEvent];
}
-(void)rightMouseDown:(NSEvent *)theEvent
{
[self mouseDownCommon:theEvent];
}
-(void)rightMouseUp:(NSEvent *)theEvent
{
[self mouseUpCommon:theEvent];
}
- (void)rightMouseDragged: (NSEvent *)theEvent
{
[self mouseDraggedCommon:theEvent];
}
-(void)otherMouseDown:(NSEvent *)theEvent
{
[self mouseDownCommon:theEvent];
}
-(void)otherMouseUp:(NSEvent *)theEvent
{
[self mouseUpCommon:theEvent];
}
- (void)otherMouseDragged: (NSEvent *)theEvent
{
[self mouseDraggedCommon:theEvent];
}
- (void)mouseMoved: (NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
// pangolin::process::PassiveMouseMotion(location.x, location.y);
pangolin::process::SubpixMotion(location.x, location.y, 0.0, 0.0, 0.0, 0.0);
}
- (void)scrollWheel:(NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
float dx, dy;
if([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
dx = theEvent.scrollingDeltaX; dy = theEvent.scrollingDeltaY;
} else {
dx = theEvent.deltaX; dy = theEvent.deltaY;
}
if(dx != 0.0f || dy != 0.0f) {
pangolin::process::SpecialInput(
pangolin::InputSpecialScroll,
location.x, context->base.v.h - location.y,
dx, dy,
0, 0
);
}
}
- (void)magnifyWithEvent: (NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
const float dm = theEvent.magnification;
if(dm != 0.0f) {
pangolin::process::SpecialInput(
pangolin::InputSpecialZoom,
location.x, context->base.v.h - location.y,
dm, 0.0f, 0.0f, 0.0f
);
}
}
- (void)rotateWithEvent: (NSEvent *)theEvent
{
const NSPoint location = [self _Location: theEvent];
const float dr = theEvent.rotation;
if(dr != 0.0f) {
pangolin::process::SpecialInput(
pangolin::InputSpecialRotate,
location.x, context->base.v.h - location.y,
dr, 0.0f, 0.0f, 0.0f
);
}
}
- (void)mouseEntered: (NSEvent *)theEvent
{
PANGOLIN_UNUSED(theEvent);
}
- (void)mouseExited: (NSEvent *)theEvent
{
PANGOLIN_UNUSED(theEvent);
}
-(void)dealloc
{
[super dealloc];
}
@end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
#include <pangolin/display/display_internal.h>
#include <pangolin/factory/factory_registry.h>
#include <EGL/egl.h>
namespace pangolin {
extern __thread PangolinGl* context;
namespace headless {
class EGLDisplayHL {
public:
EGLDisplayHL(const int width, const int height);
~EGLDisplayHL();
void swap();
void makeCurrent();
void removeCurrent();
private:
EGLSurface egl_surface;
EGLContext egl_context;
EGLDisplay egl_display;
static constexpr EGLint attribs[] = {
EGL_SURFACE_TYPE , EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE , EGL_OPENGL_BIT,
EGL_RED_SIZE , 8,
EGL_GREEN_SIZE , 8,
EGL_BLUE_SIZE , 8,
EGL_ALPHA_SIZE , 8,
EGL_DEPTH_SIZE , 24,
EGL_STENCIL_SIZE , 8,
EGL_NONE
};
};
constexpr EGLint EGLDisplayHL::attribs[];
struct HeadlessWindow : public PangolinGl {
HeadlessWindow(const int width, const int height);
~HeadlessWindow() override;
void ToggleFullscreen() override;
void Move(const int x, const int y) override;
void Resize(const unsigned int w, const unsigned int h) override;
void MakeCurrent() override;
void RemoveCurrent() override;
void SwapBuffers() override;
void ProcessEvents() override;
EGLDisplayHL display;
};
EGLDisplayHL::EGLDisplayHL(const int width, const int height) {
egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(!egl_display) {
std::cerr << "Failed to open EGL display" << std::endl;
}
EGLint major, minor;
if(eglInitialize(egl_display, &major, &minor)==EGL_FALSE) {
std::cerr << "EGL init failed" << std::endl;
}
if(eglBindAPI(EGL_OPENGL_API)==EGL_FALSE) {
std::cerr << "EGL bind failed" << std::endl;
}
EGLint count;
eglGetConfigs(egl_display, nullptr, 0, &count);
std::vector<EGLConfig> egl_configs(count);
EGLint numConfigs;
eglChooseConfig(egl_display, attribs, egl_configs.data(), count, &numConfigs);
egl_context = eglCreateContext(egl_display, egl_configs[0], EGL_NO_CONTEXT, nullptr);
const EGLint pbufferAttribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_NONE,
};
egl_surface = eglCreatePbufferSurface(egl_display, egl_configs[0], pbufferAttribs);
if (egl_surface == EGL_NO_SURFACE) {
std::cerr << "Cannot create EGL surface" << std::endl;
}
}
EGLDisplayHL::~EGLDisplayHL() {
if(egl_context) eglDestroyContext(egl_display, egl_context);
if(egl_surface) eglDestroySurface(egl_display, egl_surface);
if(egl_display) eglTerminate(egl_display);
}
void EGLDisplayHL::swap() {
eglSwapBuffers(egl_display, egl_surface);
}
void EGLDisplayHL::makeCurrent() {
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
}
void EGLDisplayHL::removeCurrent() {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
HeadlessWindow::HeadlessWindow(const int w, const int h) : display(w, h) {
windowed_size[0] = w;
windowed_size[1] = h;
}
HeadlessWindow::~HeadlessWindow() { }
void HeadlessWindow::MakeCurrent() {
display.makeCurrent();
context = this;
}
void HeadlessWindow::RemoveCurrent() {
display.removeCurrent();
}
void HeadlessWindow::ToggleFullscreen() { }
void HeadlessWindow::Move(const int /*x*/, const int /*y*/) { }
void HeadlessWindow::Resize(const unsigned int /*w*/, const unsigned int /*h*/) { }
void HeadlessWindow::ProcessEvents() { }
void HeadlessWindow::SwapBuffers() {
display.swap();
MakeCurrent();
}
} // namespace headless
PANGOLIN_REGISTER_FACTORY(NoneWindow) {
struct HeadlessWindowFactory : public FactoryInterface<WindowInterface> {
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
return std::unique_ptr<WindowInterface>(new headless::HeadlessWindow(uri.Get<int>("w", 640), uri.Get<int>("h", 480)));
}
virtual ~HeadlessWindowFactory() { }
};
auto factory = std::make_shared<HeadlessWindowFactory>();
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 1, "none");
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 1, "nogui");
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 1, "headless");
}
} // namespace pangolin

View File

@@ -0,0 +1,249 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 2011-2018 Steven Lovegrove, Andrey Mnatsakanov
*
* 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.
*/
// Silence all the OSX GL deprecation messages.
#define GL_SILENCE_DEPRECATION
#include <pangolin/factory/factory_registry.h>
#include <pangolin/platform.h>
#include <pangolin/gl/glinclude.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/display/device/OsxWindow.h>
#include <pangolin/display/device/PangolinNSGLView.h>
#include <pangolin/display/device/PangolinNSApplication.h>
#include <memory>
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
# define NSFullScreenWindowMask NSWindowStyleMaskFullScreen
# define NSTitledWindowMask NSWindowStyleMaskTitled
# define NSMiniaturizableWindowMask NSWindowStyleMaskMiniaturizable
# define NSResizableWindowMask NSWindowStyleMaskResizable
# define NSClosableWindowMask NSWindowStyleMaskClosable
#endif
// Hack to fix window focus issue
// http://www.miscdebris.net/blog/2010/03/30/solution-for-my-mac-os-x-gui-program-doesnt-get-focus-if-its-outside-an-application-bundle/
extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
inline void FixOsxFocus()
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
ProcessSerialNumber psn;
GetCurrentProcess( &psn );
CPSEnableForegroundOperation( &psn );
SetFrontProcess( &psn );
#pragma clang diagnostic pop
}
namespace pangolin
{
extern __thread PangolinGl* context;
std::unique_ptr<WindowInterface> CreateOsxWindowAndBind(std::string window_title, int w, int h, const bool is_highres)
{
OsxWindow* win = new OsxWindow(window_title, w, h, is_highres);
return std::unique_ptr<WindowInterface>(win);
}
OsxWindow::OsxWindow(
const std::string& title, int width, int height, bool USE_RETINA
) {
context = this;
PangolinGl::is_double_buffered = true;
PangolinGl::windowed_size[0] = width;
PangolinGl::windowed_size[1] = height;
// // These are important I think!
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// [pool release];
///////////////////////////////////////////////////////////////////////
// Make sure Application is initialised correctly.
// This can be run repeatedly.
[NSApplication sharedApplication];
PangolinAppDelegate *delegate = [[PangolinAppDelegate alloc] init];
[NSApp setDelegate:delegate];
[NSApp setPresentationOptions:NSFullScreenWindowMask];
[PangolinNSApplication run_pre];
[PangolinNSApplication run_step];
///////////////////////////////////////////////////////////////////////
// Create Window
NSRect viewRect = NSMakeRect( 0.0, 0.0, width, height );
_window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:YES];
[_window setTitle:[NSString stringWithUTF8String:title.c_str()]];
[_window setOpaque:YES];
[_window makeKeyAndOrderFront:NSApp];
[_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
PangolinWindowDelegate *windelegate = [[PangolinWindowDelegate alloc] init];
[_window setDelegate:windelegate];
///////////////////////////////////////////////////////////////////////
// Setup Menu
// NSMenu *mainMenuBar;
// NSMenu *appMenu;
// NSMenuItem *menuItem;
// mainMenuBar = [[NSMenu alloc] init];
// appMenu = [[NSMenu alloc] initWithTitle:@"Pangolin Application"];
// menuItem = [appMenu addItemWithTitle:@"Quit Pangolin Application" action:@selector(terminate:) keyEquivalent:@"q"];
// [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
// menuItem = [[NSMenuItem alloc] init];
// [menuItem setSubmenu:appMenu];
// [mainMenuBar addItem:menuItem];
// //[NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu];
// [appMenu release];
// [NSApp setMainMenu:mainMenuBar];
///////////////////////////////////////////////////////////////////////
// Create OpenGL View for Window
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
0
};
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
view = [[PangolinNSGLView alloc] initWithFrame:_window.frame pixelFormat:format];
[format release];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if( USE_RETINA && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
[view setWantsBestResolutionOpenGLSurface:YES];
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
[_window setContentView:view];
[PangolinNSApplication run_step];
glewInit();
FixOsxFocus();
}
OsxWindow::~OsxWindow()
{
// Not sure how to deallocate...
}
void OsxWindow::StartFullScreen()
{
if(!is_fullscreen) {
[_window toggleFullScreen:nil];
is_fullscreen = true;
}
}
void OsxWindow::StopFullScreen()
{
if(is_fullscreen) {
[_window toggleFullScreen:nil];
is_fullscreen = false;
}
}
void OsxWindow::ToggleFullscreen()
{
[_window toggleFullScreen:nil];
PangolinGl::is_fullscreen = !PangolinGl::is_fullscreen;
}
void OsxWindow::Move(int x, int y)
{
[_window setFrame:CGRectMake(x, y, [_window frame].size.width,
[_window frame].size.height) display:NO];
}
void OsxWindow::Resize(unsigned int w, unsigned int h)
{
[_window setFrame:CGRectMake([_window frame].origin.x,
[_window frame].origin.y, w, h) display:NO];
}
void OsxWindow::MakeCurrent()
{
[[view openGLContext] makeCurrentContext];
context = this;
}
void OsxWindow::RemoveCurrent()
{
[NSOpenGLContext clearCurrentContext];
}
void OsxWindow::SwapBuffers()
{
[[view openGLContext] flushBuffer];
// [[view openGLContext] update];
// [view setNeedsDisplay:YES];
}
void OsxWindow::ProcessEvents()
{
[PangolinNSApplication run_step];
}
PANGOLIN_REGISTER_FACTORY(OsxWindow)
{
struct OsxWindowFactory : public FactoryInterface<WindowInterface> {
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
const std::string window_title = uri.Get<std::string>("window_title", "window");
const int w = uri.Get<int>("w", 640);
const int h = uri.Get<int>("h", 480);
const bool is_highres = uri.Get<bool>(PARAM_HIGHRES, false);
return std::unique_ptr<WindowInterface>(CreateOsxWindowAndBind(window_title, w, h, is_highres));
}
};
auto factory = std::make_shared<OsxWindowFactory>();
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "cocoa");
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 100, "default");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,599 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 2011-2018 Steven Lovegrove, Andrey Mnatsakanov
*
* 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 <pangolin/factory/factory_registry.h>
#include <pangolin/platform.h>
#include <pangolin/gl/glinclude.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/display/device/WinWindow.h>
#include <memory>
#define CheckWGLDieOnError() pangolin::_CheckWLDieOnError( __FILE__, __LINE__ );
namespace pangolin {
inline void _CheckWLDieOnError( const char *sFile, const int nLine )
{
DWORD errorCode = GetLastError();
if(errorCode!=0) {
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf, 0, NULL);
// MessageBox( NULL, (LPCTSTR)lpMsgBuf, ("Error "+std::to_string(errorCode)).c_str(), MB_OK | MB_ICONINFORMATION );
pango_print_error("Error %i: %s", errorCode, (char *)lpMsgBuf);
pango_print_error("In: %s, line %d\n", sFile, nLine);
// exit(EXIT_FAILURE);
}
}
}
namespace pangolin
{
const char *className = "Pangolin";
extern __thread PangolinGl* context;
////////////////////////////////////////////////////////////////////////
// Utils
////////////////////////////////////////////////////////////////////////
unsigned char GetPangoKey(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case VK_F1: return PANGO_SPECIAL + PANGO_KEY_F1;
case VK_F2: return PANGO_SPECIAL + PANGO_KEY_F2;
case VK_F3: return PANGO_SPECIAL + PANGO_KEY_F3;
case VK_F4: return PANGO_SPECIAL + PANGO_KEY_F4;
case VK_F5: return PANGO_SPECIAL + PANGO_KEY_F5;
case VK_F6: return PANGO_SPECIAL + PANGO_KEY_F6;
case VK_F7: return PANGO_SPECIAL + PANGO_KEY_F7;
case VK_F8: return PANGO_SPECIAL + PANGO_KEY_F8;
case VK_F9: return PANGO_SPECIAL + PANGO_KEY_F9;
case VK_F10: return PANGO_SPECIAL + PANGO_KEY_F10;
case VK_F11: return PANGO_SPECIAL + PANGO_KEY_F11;
case VK_F12: return PANGO_SPECIAL + PANGO_KEY_F12;
case VK_LEFT: return PANGO_SPECIAL + PANGO_KEY_LEFT;
case VK_UP: return PANGO_SPECIAL + PANGO_KEY_UP;
case VK_RIGHT: return PANGO_SPECIAL + PANGO_KEY_RIGHT;
case VK_DOWN: return PANGO_SPECIAL + PANGO_KEY_DOWN;
case VK_HOME: return PANGO_SPECIAL + PANGO_KEY_HOME;
case VK_END: return PANGO_SPECIAL + PANGO_KEY_END;
case VK_INSERT: return PANGO_SPECIAL + PANGO_KEY_INSERT;
case VK_DELETE: return 127;
default:
const int lBufferSize = 2;
WCHAR lBuffer[lBufferSize];
BYTE State[256];
GetKeyboardState(State);
const UINT scanCode = (lParam >> 8) & 0xFFFFFF00;
if( ToUnicode((UINT)wParam, scanCode, State, lBuffer, lBufferSize, 0) >=1 ) {
return (unsigned char)lBuffer[0];
}
}
return 0;
}
int GetMouseModifierKey(WPARAM wParam)
{
//maps windows key modifier to glutGetModifiers values
int gluKeyModVal = 0;
if (wParam & MK_SHIFT) gluKeyModVal += 1;
if (wParam & MK_CONTROL) gluKeyModVal += 2;
if (HIBYTE(GetKeyState(VK_MENU))) gluKeyModVal += 4;
return gluKeyModVal << 4;
}
////////////////////////////////////////////////////////////////////////
// WinWindow Implementation
////////////////////////////////////////////////////////////////////////
void WinWindow::SetupPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), /* size */
1, /* version */
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER, /* support double-buffering */
PFD_TYPE_RGBA, /* color type */
24, /* prefered color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
8, /* alpha bits */
0, /* alpha shift (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
32, /* depth buffer */
0, /* no stencil buffer */
0, /* no auxiliary buffers */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
0, 0, 0, /* no layer, visible, damage masks */
};
int pixelFormat;
pixelFormat = ChoosePixelFormat(hDC, &pfd);
if (pixelFormat == 0) {
MessageBoxA(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
CheckWGLDieOnError();
exit(1);
}
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
MessageBoxA(WindowFromDC(hDC), "SetPixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
CheckWGLDieOnError();
exit(1);
}
}
void WinWindow::SetupPalette(HDC hDC)
{
int pixelFormat = GetPixelFormat(hDC);
if(!pixelFormat) {
std::cerr << "GetPixelFormat() failed" << std::endl;
CheckWGLDieOnError();
}
PIXELFORMATDESCRIPTOR pfd;
LOGPALETTE* pPal;
int paletteSize;
if(!DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
std::cerr << "DescribePixelFormat() failed" << std::endl;
CheckWGLDieOnError();
}
if (pfd.dwFlags & PFD_NEED_PALETTE) {
paletteSize = 1 << pfd.cColorBits;
}
else {
return;
}
pPal = (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = paletteSize;
/* build a simple RGB color palette */
{
int redMask = (1 << pfd.cRedBits) - 1;
int greenMask = (1 << pfd.cGreenBits) - 1;
int blueMask = (1 << pfd.cBlueBits) - 1;
int i;
for (i = 0; i<paletteSize; ++i) {
pPal->palPalEntry[i].peRed =
(((i >> pfd.cRedShift) & redMask) * 255) / redMask;
pPal->palPalEntry[i].peGreen =
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
pPal->palPalEntry[i].peBlue =
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
pPal->palPalEntry[i].peFlags = 0;
}
}
hPalette = CreatePalette(pPal);
free(pPal);
if (hPalette) {
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
}
else {
std::cerr << "CreatePalette() failed" << std::endl;
}
}
WinWindow::WinWindow(
const std::string& window_title, int width, int height
) : hWnd(0)
{
const HMODULE hCurrentInst = GetModuleHandleA(nullptr);
if(hCurrentInst==NULL) {
std::cerr << "GetModuleHandle() failed" << std::endl;
CheckWGLDieOnError();
}
RegisterThisClass(hCurrentInst);
HWND thishwnd = CreateWindowA(
className, window_title.c_str(),
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, width, height,
NULL, NULL, hCurrentInst, this);
if(thishwnd==NULL) {
std::cerr << "CreateWindow() failed" << std::endl;
CheckWGLDieOnError();
}
if( thishwnd != hWnd ) {
throw std::runtime_error("Pangolin Window Creation Failed.");
}
// Gets the size of the window, excluding the top bar
RECT cRect;
GetClientRect(thishwnd, &cRect);
PangolinGl::windowed_size[0] = cRect.right;
PangolinGl::windowed_size[1] = cRect.bottom;
// Display Window
ShowWindow(hWnd, SW_SHOW);
PangolinGl::is_double_buffered = true;
}
WinWindow::~WinWindow()
{
if(!DestroyWindow(hWnd)) {
std::cerr << "DestroyWindow() failed" << std::endl;
CheckWGLDieOnError();
}
}
void WinWindow::RegisterThisClass(HMODULE hCurrentInst)
{
WNDCLASSA wndClass;
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WinWindow::WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hCurrentInst;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = className;
if(!RegisterClassA(&wndClass)) {
std::cerr << "RegisterClass() failed" << std::endl;
CheckWGLDieOnError();
}
}
LRESULT APIENTRY
WinWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WinWindow* self = 0;
if (uMsg == WM_NCCREATE) {
auto lpcs = reinterpret_cast<LPCREATESTRUCTA>(lParam);
self = reinterpret_cast<WinWindow*>(lpcs->lpCreateParams);
if(self) {
self->hWnd = hwnd;
SetWindowLongPtrA(hwnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(self));
}
} else {
self = reinterpret_cast<WinWindow*>(GetWindowLongPtrA(hwnd, GWLP_USERDATA));
}
if (self) {
return self->HandleWinMessages(uMsg, wParam, lParam);
} else {
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
}
LRESULT WinWindow::HandleWinMessages(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CREATE:
/* initialize OpenGL rendering */
hDC = GetDC(hWnd);
if(hDC==NULL) {
std::cerr << "WM_CREATE GetDC() failed" << std::endl;
}
SetupPixelFormat(hDC);
SetupPalette(hDC);
hGLRC = wglCreateContext(hDC);
if(!hGLRC) {
std::cerr << "WM_CREATE wglCreateContext() failed" << std::endl;
CheckWGLDieOnError();
}
if(!wglMakeCurrent(hDC, hGLRC)) {
std::cerr << "WM_CREATE wglMakeCurrent() failed" << std::endl;
CheckWGLDieOnError();
}
return 0;
case WM_DESTROY:
/* finish OpenGL rendering */
if (hGLRC) {
if(!wglMakeCurrent(NULL, NULL)) {
std::cerr << "WM_DESTROY wglMakeCurrent() failed" << std::endl;
CheckWGLDieOnError();
}
if(!wglDeleteContext(hGLRC)) {
std::cerr << "WM_DESTROY wglDeleteContext() failed" << std::endl;
CheckWGLDieOnError();
}
}
if (hPalette) {
DeleteObject(hPalette);
}
ReleaseDC(hWnd, hDC);
PostQuitMessage(0);
return 0;
case WM_SIZE:
/* track window size changes */
if (context == this) {
process::Resize((int)LOWORD(lParam), (int)HIWORD(lParam));
}
return 0;
case WM_PALETTECHANGED:
/* realize palette if this is *not* the current window */
if (hGLRC && hPalette && (HWND)wParam != hWnd) {
if(!UnrealizeObject(hPalette)) {
std::cerr << "WM_PALETTECHANGED UnrealizeObject() failed" << std::endl;
}
if(!SelectPalette(hDC, hPalette, FALSE)) {
std::cerr << "WM_PALETTECHANGED SelectPalette() failed" << std::endl;
}
if(RealizePalette(hDC)==GDI_ERROR) {
std::cerr << "WM_PALETTECHANGED RealizePalette() failed" << std::endl;
}
//redraw();
break;
}
break;
case WM_QUERYNEWPALETTE:
/* realize palette if this is the current window */
if (hGLRC && hPalette) {
if(!UnrealizeObject(hPalette)) {
std::cerr << "WM_QUERYNEWPALETTE UnrealizeObject() failed" << std::endl;
}
if(!SelectPalette(hDC, hPalette, FALSE)) {
std::cerr << "WM_QUERYNEWPALETTE SelectPalette() failed" << std::endl;
}
if(RealizePalette(hDC)==GDI_ERROR) {
std::cerr << "WM_QUERYNEWPALETTE RealizePalette() failed" << std::endl;
}
//redraw();
return TRUE;
}
break;
case WM_PAINT:
{
//PAINTSTRUCT ps;
//BeginPaint(hWnd, &ps);
//if (hGLRC) {
// redraw();
//}
//EndPaint(hWnd, &ps);
//return 0;
}
break;
case WM_KEYDOWN:
{
unsigned char key = GetPangoKey(wParam, lParam);
if(key>0) process::Keyboard(key, 1, 1);
return 0;
}
case WM_KEYUP:
{
unsigned char key = GetPangoKey(wParam, lParam);
if (key>0) process::KeyboardUp(key, 1, 1);
return 0;
}
case WM_LBUTTONDOWN:
process::Mouse(0 | GetMouseModifierKey(wParam), 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_MBUTTONDOWN:
process::Mouse(1 | GetMouseModifierKey(wParam), 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_RBUTTONDOWN:
process::Mouse(2 | GetMouseModifierKey(wParam), 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_LBUTTONUP:
process::Mouse(0 | GetMouseModifierKey(wParam), 1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_MBUTTONUP:
process::Mouse(1 | GetMouseModifierKey(wParam), 1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_RBUTTONUP:
process::Mouse(2 | GetMouseModifierKey(wParam), 1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_MOUSEMOVE:
if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) ) {
process::MouseMotion(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
} else{
process::PassiveMouseMotion(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
}
return 0;
case WM_MOUSEWHEEL:
process::Scroll(0.0f, GET_WHEEL_DELTA_WPARAM(wParam) / 5.0f );
return 0;
case WM_MOUSEHWHEEL:
process::Scroll(GET_WHEEL_DELTA_WPARAM(wParam) / 5.0f, 0.0f);
return 0;
default:
break;
}
return DefWindowProcA(hWnd, message, wParam, lParam);
}
void WinWindow::StartFullScreen() {
LONG dwExStyle = GetWindowLongA(hWnd, GWL_EXSTYLE)
& ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
if(dwExStyle==0) {
std::cerr << "GetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
LONG dwStyle = GetWindowLongA(hWnd, GWL_STYLE)
& ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
if(dwStyle==0) {
std::cerr << "GetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
if(!SetWindowLongA(hWnd, GWL_EXSTYLE, dwExStyle)) {
std::cerr << "SetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
if(!SetWindowLongA(hWnd, GWL_STYLE, dwStyle)) {
std::cerr << "SetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
GLint prev[2];
std::memcpy(prev, context->windowed_size, sizeof(prev));
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
std::memcpy(context->windowed_size, prev, sizeof(prev));
}
void WinWindow::StopFullScreen() {
ChangeDisplaySettings(NULL, 0);
ShowCursor(TRUE);
LONG dwExStyle = GetWindowLongA(hWnd, GWL_EXSTYLE) | WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
LONG dwStyle = GetWindowLongA(hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW;
if(dwExStyle==0) {
std::cerr << "GetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
if(dwStyle==0) {
std::cerr << "GetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
if(!SetWindowLongA(hWnd, GWL_EXSTYLE, dwExStyle)) {
std::cerr << "SetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
if(!SetWindowLongA(hWnd, GWL_STYLE, dwStyle)) {
std::cerr << "SetWindowLongA() failed" << std::endl;
CheckWGLDieOnError();
}
if(!SetWindowPos(hWnd, HWND_TOP, 0, 0, context->windowed_size[0], context->windowed_size[1], SWP_FRAMECHANGED)) {
std::cerr << "SetWindowPos() failed" << std::endl;
CheckWGLDieOnError();
}
}
void WinWindow::ToggleFullscreen()
{
if(!context->is_fullscreen) {
StartFullScreen();
context->is_fullscreen = true;
}else{
StopFullScreen();
context->is_fullscreen = false;
}
}
void WinWindow::Move(int x, int y)
{
if( !SetWindowPos(hWnd, 0, x, y, 0, 0, SWP_NOSIZE) ) {
std::cerr << "WinWindow::Move failed" << std::endl;
CheckWGLDieOnError();
}
}
void WinWindow::Resize(unsigned int w, unsigned int h)
{
if( !SetWindowPos(hWnd, 0, 0, 0, w, h, SWP_NOMOVE) ) {
std::cerr << "WinWindow::Resize failed" << std::endl;
CheckWGLDieOnError();
}
}
void WinWindow::MakeCurrent()
{
if(wglMakeCurrent(hDC, hGLRC)==FALSE) {
std::cerr << "wglMakeCurrent() failed" << std::endl;
CheckWGLDieOnError();
}
// Setup threadlocal context as this
context = this;
RECT rect;
if(!GetWindowRect(hWnd, &rect)) {
std::cerr << "GetWindowRect() failed" << std::endl;
CheckWGLDieOnError();
}
Resize(rect.right - rect.left, rect.bottom - rect.top);
}
void WinWindow::RemoveCurrent()
{
if(wglMakeCurrent(NULL, NULL)==0) {
std::cerr << "wglMakeCurrent() failed" << std::endl;
CheckWGLDieOnError();
}
}
void WinWindow::SwapBuffers()
{
if(!::SwapBuffers(hDC)) {
std::cerr << "SwapBuffers() failed" << std::endl;
CheckWGLDieOnError();
}
}
void WinWindow::ProcessEvents()
{
MSG msg;
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
pangolin::Quit();
break;
}
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
}
std::unique_ptr<WindowInterface> CreateWinWindowAndBind(std::string window_title, int w, int h)
{
WinWindow* win = new WinWindow(window_title, w, h);
return std::unique_ptr<WindowInterface>(win);
}
PANGOLIN_REGISTER_FACTORY(WinWindow)
{
struct WinWindowFactory : public FactoryInterface<WindowInterface> {
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
const std::string window_title = uri.Get<std::string>("window_title", "window");
const int w = uri.Get<int>("w", 640);
const int h = uri.Get<int>("h", 480);
return std::unique_ptr<WindowInterface>(CreateWinWindowAndBind(window_title, w, h));
}
};
auto factory = std::make_shared<WinWindowFactory>();
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "winapi");
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 100, "default");
}
}

View File

@@ -0,0 +1,530 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 2011-2018 Steven Lovegrove, Andrey Mnatsakanov
*
* 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.
*/
// Code based on public domain sample at
// https://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_%28GLX%29
#include <pangolin/factory/factory_registry.h>
#include <pangolin/platform.h>
#include <pangolin/gl/glinclude.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/display/window.h>
#include <pangolin/display/device/X11Window.h>
#include <mutex>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <GL/glx.h>
namespace pangolin
{
extern __thread PangolinGl* context;
std::mutex window_mutex;
std::weak_ptr<X11GlContext> global_gl_context;
const long EVENT_MASKS = ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|FocusChangeMask;
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(::Display*, ::GLXFBConfig, ::GLXContext, Bool, const int*);
// Adapted from: http://www.opengl.org/resources/features/OGLextensions/
bool isExtensionSupported(const char *extList, const char *extension)
{
/* Extension names should not have spaces. */
const char* where = strchr(extension, ' ');
if (where || *extension == '\0') {
return false;
}
for(const char* start=extList;;) {
where = strstr(start, extension);
if (!where) {
break;
}
const char *terminator = where + strlen(extension);
if ( where == start || *(where - 1) == ' ' ) {
if ( *terminator == ' ' || *terminator == '\0' ) {
return true;
}
}
start = terminator;
}
return false;
}
::GLXFBConfig ChooseFrameBuffer(
::Display *display, bool glx_doublebuffer,
int glx_sample_buffers, int glx_samples
) {
// Desired attributes
int visual_attribs[] =
{
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , glx_doublebuffer ? True : False,
None
};
int fbcount;
GLXFBConfig* fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount);
if (!fbc) {
throw std::runtime_error("Pangolin X11: Unable to retrieve framebuffer options");
}
int best_fbc = -1;
int worst_fbc = -1;
int best_num_samp = -1;
int worst_num_samp = 999;
// Enumerate framebuffer options, storing the best and worst that match our attribs
for (int i=0; i<fbcount; ++i)
{
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
if ( vi )
{
int samp_buf, samples;
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
// Filter for the best available.
if ( samples > best_num_samp ) {
best_fbc = i;
best_num_samp = samples;
}
// Filter lowest settings which match minimum user requirement.
if ( samp_buf >= glx_sample_buffers && samples >= glx_samples && samples < worst_num_samp ) {
worst_fbc = i;
worst_num_samp = samples;
}
}
XFree( vi );
}
// Select the minimum suitable option. The 'best' is often too slow.
int chosen_fbc_id = worst_fbc;
// If minimum requested isn't available, return the best that is.
if(chosen_fbc_id < 0) {
pango_print_warn("Framebuffer with requested attributes not available. Using available framebuffer. You may see visual artifacts.");
chosen_fbc_id = best_fbc;
}
::GLXFBConfig chosenFbc = fbc[ chosen_fbc_id ];
XFree( fbc );
return chosenFbc;
}
static bool ctxErrorOccurred = false;
static int ctxErrorHandler( ::Display * /*dpy*/, ::XErrorEvent * ev )
{
const int buffer_size = 10240;
char buffer[buffer_size];
XGetErrorText(ev->display, ev->error_code, buffer, buffer_size );
pango_print_error("X11 Error: %s\n", buffer);
ctxErrorOccurred = true;
return 0;
}
GLXContext CreateGlContext(::Display *display, ::GLXFBConfig chosenFbc, GLXContext share_context = 0)
{
int glx_major, glx_minor;
if ( !glXQueryVersion( display, &glx_major, &glx_minor ) ||
( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) )
{
throw std::runtime_error("Pangolin X11: Invalid GLX version. Require GLX >= 1.3");
}
GLXContext new_ctx;
// Get the default screen's GLX extension list
const char *glxExts = glXQueryExtensionsString( display, DefaultScreen( display ) );
glXCreateContextAttribsARBProc glXCreateContextAttribsARB =
(glXCreateContextAttribsARBProc) glXGetProcAddressARB(
(const GLubyte *) "glXCreateContextAttribsARB"
);
// Install an X error handler so the application won't exit if GL 3.0
// context allocation fails. Handler is global and shared across all threads.
ctxErrorOccurred = false;
int (*oldHandler)(::Display*, ::XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
if ( isExtensionSupported( glxExts, "GLX_ARB_create_context" ) && glXCreateContextAttribsARB )
{
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
new_ctx = glXCreateContextAttribsARB( display, chosenFbc, share_context, True, context_attribs );
// Sync to ensure any errors generated are processed.
XSync( display, False );
if ( ctxErrorOccurred || !new_ctx ) {
ctxErrorOccurred = false;
// Fall back to old-style 2.x context. Implementations will return the newest
// context version compatible with OpenGL versions less than version 3.0.
context_attribs[1] = 1; // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
context_attribs[3] = 0; // GLX_CONTEXT_MINOR_VERSION_ARB = 0
new_ctx = glXCreateContextAttribsARB( display, chosenFbc, share_context, True, context_attribs );
}
} else {
// Fallback to GLX 1.3 Context
new_ctx = glXCreateNewContext( display, chosenFbc, GLX_RGBA_TYPE, share_context, True );
}
// Sync to ensure any errors generated are processed.
XSync( display, False );
// Restore the original error handler
XSetErrorHandler( oldHandler );
if ( ctxErrorOccurred || !new_ctx ) {
throw std::runtime_error("Pangolin X11: Failed to create an OpenGL context");
}
// Verifying that context is a direct context
if ( ! glXIsDirect ( display, new_ctx ) ) {
pango_print_warn("Pangolin X11: Indirect GLX rendering context obtained\n");
}
return new_ctx;
}
X11GlContext::X11GlContext(std::shared_ptr<X11Display>& d, ::GLXFBConfig chosenFbc, std::shared_ptr<X11GlContext> shared_context)
: display(d), shared_context(shared_context)
{
// prevent chained sharing
while(shared_context && shared_context->shared_context) {
shared_context = shared_context->shared_context;
}
// Contexts can't be shared across different displays.
if(shared_context && shared_context->display != d) {
shared_context.reset();
}
glcontext = CreateGlContext(display->display, chosenFbc, shared_context ? shared_context->glcontext : 0);
}
X11GlContext::~X11GlContext()
{
glXDestroyContext( display->display, glcontext );
}
X11Window::X11Window(
const std::string& title, int width, int height,
std::shared_ptr<X11Display>& display, ::GLXFBConfig chosenFbc
) : display(display), glcontext(0), win(0), cmap(0)
{
PangolinGl::windowed_size[0] = width;
PangolinGl::windowed_size[1] = height;
// Get a visual
XVisualInfo *vi = glXGetVisualFromFBConfig( display->display, chosenFbc );
// Create colourmap
XSetWindowAttributes swa;
swa.background_pixmap = None;
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
swa.colormap = cmap = XCreateColormap( display->display,
RootWindow( display->display, vi->screen ),
vi->visual, AllocNone );
// Create window
win = XCreateWindow( display->display, RootWindow( display->display, vi->screen ),
0, 0, width, height, 0, vi->depth, InputOutput,
vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa );
XFree( vi );
if ( !win ) {
throw std::runtime_error("Pangolin X11: Failed to create window." );
}
XStoreName( display->display, win, title.c_str() );
XMapWindow( display->display, win );
// Request to be notified of these events
XSelectInput(display->display, win, EVENT_MASKS );
delete_message = XInternAtom(display->display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display->display, win, &delete_message, 1);
}
X11Window::~X11Window()
{
glXMakeCurrent( display->display, 0, 0 );
XDestroyWindow( display->display, win );
XFreeColormap( display->display, cmap );
}
void X11Window::MakeCurrent(GLXContext ctx)
{
glXMakeCurrent( display->display, win, ctx );
context = this;
}
void X11Window::MakeCurrent()
{
MakeCurrent(glcontext ? glcontext->glcontext : global_gl_context.lock()->glcontext);
}
void X11Window::RemoveCurrent()
{
glXMakeCurrent(display->display, 0, nullptr);
}
void X11Window::ToggleFullscreen()
{
const Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(display->display, "_NET_WM_STATE_FULLSCREEN", True);
const Atom _NET_WM_STATE = XInternAtom(display->display, "_NET_WM_STATE", True);
XEvent e;
e.xclient.type = ClientMessage;
e.xclient.window = win;
e.xclient.message_type = _NET_WM_STATE;
e.xclient.format = 32;
e.xclient.data.l[0] = 2; // Toggle
e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
e.xclient.data.l[2] = 0;
e.xclient.data.l[3] = 1;
e.xclient.data.l[4] = 0;
XSendEvent(display->display, DefaultRootWindow(display->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &e);
XMoveResizeWindow(display->display, win, 0, 0, windowed_size[0], windowed_size[1]);
}
void X11Window::Move(int x, int y)
{
XMoveWindow(display->display, win, x, y);
}
void X11Window::Resize(unsigned int w, unsigned int h)
{
XResizeWindow(display->display, win, w, h);
}
void X11Window::ProcessEvents()
{
XEvent ev;
while(!pangolin::ShouldQuit() && XPending(display->display) > 0)
{
XNextEvent(display->display, &ev);
switch(ev.type){
case ConfigureNotify:
pangolin::process::Resize(ev.xconfigure.width, ev.xconfigure.height);
break;
case ClientMessage:
// We've only registered to receive WM_DELETE_WINDOW, so no further checks needed.
pangolin::Quit();
break;
case ButtonPress:
case ButtonRelease:
{
const int button = ev.xbutton.button-1;
pangolin::process::Mouse(
button,
ev.xbutton.type == ButtonRelease,
ev.xbutton.x, ev.xbutton.y
);
break;
}
case FocusOut:
pangolin::context->mouse_state = 0;
break;
case MotionNotify:
if(ev.xmotion.state & (Button1Mask|Button2Mask|Button3Mask) ) {
pangolin::process::MouseMotion(ev.xmotion.x, ev.xmotion.y);
}else{
pangolin::process::PassiveMouseMotion(ev.xmotion.x, ev.xmotion.y);
}
break;
case KeyPress:
case KeyRelease:
int key;
char ch;
KeySym sym;
if( XLookupString(&ev.xkey,&ch,1,&sym,0) == 0) {
switch (sym) {
case XK_F1: key = PANGO_SPECIAL + PANGO_KEY_F1 ; break;
case XK_F2: key = PANGO_SPECIAL + PANGO_KEY_F2 ; break;
case XK_F3: key = PANGO_SPECIAL + PANGO_KEY_F3 ; break;
case XK_F4: key = PANGO_SPECIAL + PANGO_KEY_F4 ; break;
case XK_F5: key = PANGO_SPECIAL + PANGO_KEY_F5 ; break;
case XK_F6: key = PANGO_SPECIAL + PANGO_KEY_F6 ; break;
case XK_F7: key = PANGO_SPECIAL + PANGO_KEY_F7 ; break;
case XK_F8: key = PANGO_SPECIAL + PANGO_KEY_F8 ; break;
case XK_F9: key = PANGO_SPECIAL + PANGO_KEY_F9 ; break;
case XK_F10: key = PANGO_SPECIAL + PANGO_KEY_F10 ; break;
case XK_F11: key = PANGO_SPECIAL + PANGO_KEY_F11 ; break;
case XK_F12: key = PANGO_SPECIAL + PANGO_KEY_F12 ; break;
case XK_Left: key = PANGO_SPECIAL + PANGO_KEY_LEFT ; break;
case XK_Up: key = PANGO_SPECIAL + PANGO_KEY_UP ; break;
case XK_Right: key = PANGO_SPECIAL + PANGO_KEY_RIGHT ; break;
case XK_Down: key = PANGO_SPECIAL + PANGO_KEY_DOWN ; break;
case XK_Page_Up: key = PANGO_SPECIAL + PANGO_KEY_PAGE_UP ; break;
case XK_Page_Down: key = PANGO_SPECIAL + PANGO_KEY_PAGE_DOWN ; break;
case XK_Home: key = PANGO_SPECIAL + PANGO_KEY_HOME ; break;
case XK_End: key = PANGO_SPECIAL + PANGO_KEY_END ; break;
case XK_Insert: key = PANGO_SPECIAL + PANGO_KEY_INSERT ; break;
case XK_Shift_L:
case XK_Shift_R:
key = -1;
if(ev.type==KeyPress) {
pangolin::context->mouse_state |= pangolin::KeyModifierShift;
}else{
pangolin::context->mouse_state &= ~pangolin::KeyModifierShift;
}
break;
case XK_Control_L:
case XK_Control_R:
key = -1;
if(ev.type==KeyPress) {
pangolin::context->mouse_state |= pangolin::KeyModifierCtrl;
}else{
pangolin::context->mouse_state &= ~pangolin::KeyModifierCtrl;
}
break;
case XK_Alt_L:
case XK_Alt_R:
key = -1;
if(ev.type==KeyPress) {
pangolin::context->mouse_state |= pangolin::KeyModifierAlt;
}else{
pangolin::context->mouse_state &= ~pangolin::KeyModifierAlt;
}
break;
case XK_Super_L:
case XK_Super_R:
key = -1;
if(ev.type==KeyPress) {
pangolin::context->mouse_state |= pangolin::KeyModifierCmd;
}else{
pangolin::context->mouse_state &= ~pangolin::KeyModifierCmd;
}
break;
default: key = -1; break;
}
}else{
key = ch;
}
if(key >=0) {
if(ev.type == KeyPress) {
pangolin::process::Keyboard(key, ev.xkey.x, ev.xkey.y);
}else{
pangolin::process::KeyboardUp(key, ev.xkey.x, ev.xkey.y);
}
}
break;
}
}
}
void X11Window::SwapBuffers() {
glXSwapBuffers(display->display, win);
}
std::unique_ptr<WindowInterface> CreateX11WindowAndBind(const std::string& window_title, const int w, const int h, const std::string& display_name, const bool double_buffered, const int sample_buffers, const int samples)
{
std::shared_ptr<X11Display> newdisplay = std::make_shared<X11Display>(display_name.empty() ? NULL : display_name.c_str() );
if (!newdisplay) {
throw std::runtime_error("Pangolin X11: Failed to open X display");
}
::GLXFBConfig newfbc = ChooseFrameBuffer(newdisplay->display, double_buffered, sample_buffers, samples);
window_mutex.lock();
std::shared_ptr<X11GlContext> newglcontext = std::make_shared<X11GlContext>(
newdisplay, newfbc, global_gl_context.lock()
);
if(!global_gl_context.lock()) {
global_gl_context = newglcontext;
}
window_mutex.unlock();
X11Window* win = new X11Window(window_title, w, h, newdisplay, newfbc);
win->glcontext = newglcontext;
win->is_double_buffered = double_buffered;
return std::unique_ptr<WindowInterface>(win);
}
PANGOLIN_REGISTER_FACTORY(X11Window)
{
struct X11WindowFactory : public FactoryInterface<WindowInterface> {
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
const std::string window_title = uri.Get<std::string>("window_title", "window");
const int w = uri.Get<int>("w", 640);
const int h = uri.Get<int>("h", 480);
const std::string display_name = uri.Get<std::string>("display_name", "");
const bool double_buffered = uri.Get<bool>("double_buffered", true);
const int sample_buffers = uri.Get<int>("sample_buffers", 1);
const int samples = uri.Get<int>("samples", 1);
return std::unique_ptr<WindowInterface>(CreateX11WindowAndBind(window_title, w, h, display_name, double_buffered, sample_buffers, samples));
}
};
auto factory = std::make_shared<X11WindowFactory>();
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "x11");
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "linux");
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 100, "default");
}
}

View File

@@ -0,0 +1,660 @@
/* 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.
*/
#include <pangolin/platform.h>
#ifdef HAVE_PYTHON
#include <pangolin/python/pyinterpreter.h>
#include <pangolin/console/ConsoleView.h>
#endif // HAVE_PYTHON
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <mutex>
#include <cstdlib>
#include <pangolin/factory/factory_registry.h>
#include <pangolin/window_frameworks.h>
#include <pangolin/gl/glinclude.h>
#include <pangolin/gl/gldraw.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/handler/handler.h>
#include <pangolin/utils/simple_math.h>
#include <pangolin/utils/timer.h>
#include <pangolin/utils/type_convert.h>
#include <pangolin/image/image_io.h>
#ifdef BUILD_PANGOLIN_VARS
#include <pangolin/var/var.h>
#endif
namespace pangolin
{
#ifdef BUILD_PANGOLIN_VIDEO
// Forward declaration.
void SaveFramebuffer(VideoOutput& video, const Viewport& v);
#endif // BUILD_PANGOLIN_VIDEO
const char* PARAM_DISPLAYNAME = "DISPLAYNAME";
const char* PARAM_DOUBLEBUFFER = "DOUBLEBUFFER";
const char* PARAM_SAMPLE_BUFFERS = "SAMPLE_BUFFERS";
const char* PARAM_SAMPLES = "SAMPLES";
const char* PARAM_HIGHRES = "HIGHRES";
typedef std::map<std::string,std::shared_ptr<PangolinGl> > ContextMap;
// Map of active contexts
ContextMap contexts;
std::recursive_mutex contexts_mutex;
bool one_time_window_frameworks_init = false;
// Context active for current thread
__thread PangolinGl* context = 0;
PangolinGl::PangolinGl()
: user_app(0), is_high_res(false), quit(false), mouse_state(0),activeDisplay(0)
#ifdef BUILD_PANGOLIN_VIDEO
, record_view(0)
#endif
#ifdef HAVE_PYTHON
, console_view(0)
#endif
{
}
PangolinGl::~PangolinGl()
{
// Free displays owned by named_managed_views
for(ViewMap::iterator iv = named_managed_views.begin(); iv != named_managed_views.end(); ++iv) {
delete iv->second;
}
named_managed_views.clear();
}
PangolinGl* GetCurrentContext()
{
return context;
}
PangolinGl *FindContext(const std::string& name)
{
contexts_mutex.lock();
ContextMap::iterator ic = contexts.find(name);
PangolinGl* context = (ic == contexts.end()) ? 0 : ic->second.get();
contexts_mutex.unlock();
return context;
}
WindowInterface& CreateWindowAndBind(std::string window_title, int w, int h, const Params& params)
{
std::unique_lock<std::recursive_mutex> l(contexts_mutex);
if(!one_time_window_frameworks_init) {
one_time_window_frameworks_init = LoadBuiltInWindowFrameworks();
}
pangolin::Uri win_uri;
if(const char* extra_params = std::getenv("PANGOLIN_WINDOW_URI"))
{
// Take any defaults from the environment
win_uri = pangolin::ParseUri(extra_params);
}else{
// Otherwise revert to 'default' scheme.
win_uri.scheme = "default";
}
// Allow params to override
win_uri.scheme = params.Get("scheme", win_uri.scheme);
// Override with anything the program specified
win_uri.params.insert(std::end(win_uri.params), std::begin(params.params), std::end(params.params));
win_uri.Set("w", w);
win_uri.Set("h", h);
win_uri.Set("window_title", window_title);
std::unique_ptr<WindowInterface> window = FactoryRegistry<WindowInterface>::I().Open(win_uri);
// We're expecting not only a WindowInterface, but a PangolinGl.
if(!window || !dynamic_cast<PangolinGl*>(window.get())) {
throw WindowExceptionNoKnownHandler(win_uri.scheme);
}
std::shared_ptr<PangolinGl> context(dynamic_cast<PangolinGl*>(window.release()));
RegisterNewContext(window_title, context );
// is_high_res will alter default font size and a few other gui elements.
context->is_high_res = win_uri.Get(PARAM_HIGHRES,false);
context->MakeCurrent();
context->ProcessEvents();
glewInit();
return *context;
}
// Assumption: unique lock is held on contexts_mutex for multi-threaded operation
void RegisterNewContext(const std::string& name, std::shared_ptr<PangolinGl> newcontext)
{
// Set defaults
newcontext->base.left = 0.0;
newcontext->base.bottom = 0.0;
newcontext->base.top = 1.0;
newcontext->base.right = 1.0;
newcontext->base.aspect = 0;
newcontext->base.handler = &StaticHandler;
newcontext->is_fullscreen = false;
// Create and add
if( contexts.find(name) != contexts.end() ) {
throw std::runtime_error("Context already exists.");
}
contexts[name] = newcontext;
// Process the following as if this context is now current.
PangolinGl *oldContext = context;
context = newcontext.get();
process::Resize(
newcontext->windowed_size[0],
newcontext->windowed_size[1]
);
// Default key bindings can be overridden
RegisterKeyPressCallback(PANGO_KEY_ESCAPE, Quit );
RegisterKeyPressCallback('\t', ToggleFullscreen );
RegisterKeyPressCallback('`', ToggleConsole );
context = oldContext;
}
WindowInterface* GetBoundWindow()
{
return context;
}
void DestroyWindow(const std::string& name)
{
contexts_mutex.lock();
ContextMap::iterator ic = contexts.find(name);
PangolinGl *context_to_destroy = (ic == contexts.end()) ? 0 : ic->second.get();
if (context_to_destroy == context) {
context = nullptr;
}
size_t erased = contexts.erase(name);
if(erased == 0) {
pango_print_warn("Context '%s' doesn't exist for deletion.\n", name.c_str());
}
contexts_mutex.unlock();
}
WindowInterface& BindToContext(std::string name)
{
std::unique_lock<std::recursive_mutex> l(contexts_mutex);
// N.B. context is modified prior to invoking MakeCurrent so that
// state management callbacks (such as Resize()) can be correctly
// processed.
PangolinGl *context_to_bind = FindContext(name);
if( !context_to_bind )
{
std::shared_ptr<PangolinGl> newcontext(new PangolinGl());
RegisterNewContext(name, newcontext);
return *(newcontext.get());
}else{
context_to_bind->MakeCurrent();
return *context_to_bind;
}
}
void Quit()
{
context->quit = true;
}
void QuitAll()
{
for(auto nc : contexts) {
nc.second->quit = true;
}
}
bool ShouldQuit()
{
return !context || context->quit;
}
bool HadInput()
{
if( context->had_input > 0 )
{
--context->had_input;
return true;
}
return false;
}
bool HasResized()
{
if( context->has_resized > 0 )
{
--context->has_resized;
return true;
}
return false;
}
void StartFullScreen() {
if(!context->is_fullscreen) {
context->ToggleFullscreen();
context->is_fullscreen = true;
}
}
void StopFullScreen() {
if(context->is_fullscreen) {
context->ToggleFullscreen();
context->is_fullscreen = false;
}
}
void SetFullscreen(bool fullscreen)
{
if(fullscreen) {
StartFullScreen();
}else{
StopFullScreen();
}
}
void RenderViews()
{
Viewport::DisableScissor();
DisplayBase().Render();
}
void RenderRecordGraphic(const Viewport& v)
{
const float r = 7;
v.ActivatePixelOrthographic();
glRecordGraphic(v.w-2*r, v.h-2*r, r);
}
void PostRender()
{
while(context->screen_capture.size()) {
std::pair<std::string,Viewport> fv = context->screen_capture.front();
context->screen_capture.pop();
SaveFramebuffer(fv.first, fv.second);
}
#ifdef BUILD_PANGOLIN_VIDEO
if(context->recorder.IsOpen()) {
SaveFramebuffer(context->recorder, context->record_view->GetBounds() );
RenderRecordGraphic(context->record_view->GetBounds());
}
#endif // BUILD_PANGOLIN_VIDEO
// Disable scissor each frame
Viewport::DisableScissor();
}
void FinishFrame()
{
RenderViews();
PostRender();
context->SwapBuffers();
context->ProcessEvents();
}
View& DisplayBase()
{
return context->base;
}
View& CreateDisplay()
{
int iguid = rand();
std::stringstream ssguid;
ssguid << iguid;
return Display(ssguid.str());
}
void ToggleConsole()
{
#ifdef HAVE_PYTHON
if( !context->console_view) {
// Create console and let the pangolin context take ownership
context->console_view = new ConsoleView(new PyInterpreter());
context->named_managed_views["pangolin_console"] = context->console_view;
context->console_view->SetFocus();
context->console_view->zorder = std::numeric_limits<int>::max();
DisplayBase().AddDisplay(*context->console_view);
}else{
context->console_view->ToggleShow();
if(context->console_view->IsShown()) {
context->console_view->SetFocus();
}
}
#endif
}
void ToggleFullscreen()
{
SetFullscreen(!context->is_fullscreen);
}
View& Display(const std::string& name)
{
// Get / Create View
ViewMap::iterator vi = context->named_managed_views.find(name);
if( vi != context->named_managed_views.end() )
{
return *(vi->second);
}else{
View * v = new View();
context->named_managed_views[name] = v;
v->handler = &StaticHandler;
context->base.views.push_back(v);
return *v;
}
}
void RegisterKeyPressCallback(int key, std::function<void(void)> func)
{
context->keypress_hooks[key] = func;
}
void SaveWindowOnRender(std::string prefix)
{
context->screen_capture.push(std::pair<std::string,Viewport>(prefix, context->base.v) );
}
void SaveFramebuffer(std::string prefix, const Viewport& v)
{
PANGOLIN_UNUSED(prefix);
PANGOLIN_UNUSED(v);
#ifndef HAVE_GLES
#ifdef HAVE_PNG
PixelFormat fmt = PixelFormatFromString("RGBA32");
TypedImage buffer(v.w, v.h, fmt );
glReadBuffer(GL_BACK);
glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this?
glReadPixels(v.l, v.b, v.w, v.h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.ptr );
SaveImage(buffer, fmt, prefix + ".png", false);
#endif // HAVE_PNG
#endif // HAVE_GLES
}
#ifdef BUILD_PANGOLIN_VIDEO
void SaveFramebuffer(VideoOutput& video, const Viewport& v)
{
#ifndef HAVE_GLES
const StreamInfo& si = video.Streams()[0];
if(video.Streams().size()==0 || (int)si.Width() != v.w || (int)si.Height() != v.h) {
video.Close();
return;
}
static basetime last_time = TimeNow();
const basetime time_now = TimeNow();
last_time = time_now;
static std::vector<unsigned char> img;
img.resize(v.w*v.h*4);
glReadBuffer(GL_BACK);
glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this?
glReadPixels(v.l, v.b, v.w, v.h, GL_RGB, GL_UNSIGNED_BYTE, &img[0] );
video.WriteStreams(&img[0]);
#endif // HAVE_GLES
}
#endif // BUILD_PANGOLIN_VIDEO
namespace process
{
float last_x = 0;
float last_y = 0;
void Keyboard( unsigned char key, int x, int y)
{
// Force coords to match OpenGl Window Coords
y = context->base.v.h - y;
#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
// Switch backspace and delete for OSX!
if(key== '\b') {
key = 127;
}else if(key == 127) {
key = '\b';
}
#endif
context->had_input = context->is_double_buffered ? 2 : 1;
// Check if global key hook exists
const KeyhookMap::iterator hook = context->keypress_hooks.find(key);
#ifdef HAVE_PYTHON
// Console receives all input when it is open
if( context->console_view && context->console_view->IsShown() ) {
context->console_view->Keyboard(*(context->console_view),key,x,y,true);
}else
#endif
if(hook != context->keypress_hooks.end() ) {
hook->second();
} else if(context->activeDisplay && context->activeDisplay->handler) {
context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,true);
}
}
void KeyboardUp(unsigned char key, int x, int y)
{
// Force coords to match OpenGl Window Coords
y = context->base.v.h - y;
if(context->activeDisplay && context->activeDisplay->handler)
{
context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,false);
}
}
void SpecialFunc(int key, int x, int y)
{
Keyboard(key+128,x,y);
}
void SpecialFuncUp(int key, int x, int y)
{
KeyboardUp(key+128,x,y);
}
void Mouse( int button_raw, int state, int x, int y)
{
// Force coords to match OpenGl Window Coords
y = context->base.v.h - y;
last_x = (float)x;
last_y = (float)y;
const MouseButton button = (MouseButton)(1 << (button_raw & 0xf) );
const bool pressed = (state == 0);
context->had_input = context->is_double_buffered ? 2 : 1;
const bool fresh_input = ( (context->mouse_state & 7) == 0);
if( pressed ) {
context->mouse_state |= (button&7);
}else{
context->mouse_state &= ~(button&7);
}
#if defined(_WIN_)
context->mouse_state &= 0x0000ffff;
context->mouse_state |= (button_raw >> 4) << 16;
#endif
if(fresh_input) {
context->base.handler->Mouse(context->base,button,x,y,pressed,context->mouse_state);
}else if(context->activeDisplay && context->activeDisplay->handler) {
context->activeDisplay->handler->Mouse(*(context->activeDisplay),button,x,y,pressed,context->mouse_state);
}
}
void MouseMotion( int x, int y)
{
// Force coords to match OpenGl Window Coords
y = context->base.v.h - y;
last_x = (float)x;
last_y = (float)y;
context->had_input = context->is_double_buffered ? 2 : 1;
if( context->activeDisplay)
{
if( context->activeDisplay->handler )
context->activeDisplay->handler->MouseMotion(*(context->activeDisplay),x,y,context->mouse_state);
}else{
context->base.handler->MouseMotion(context->base,x,y,context->mouse_state);
}
}
void PassiveMouseMotion(int x, int y)
{
// Force coords to match OpenGl Window Coords
y = context->base.v.h - y;
context->base.handler->PassiveMouseMotion(context->base,x,y,context->mouse_state);
last_x = (float)x;
last_y = (float)y;
}
void Display()
{
// No implementation
}
void Resize( int width, int height )
{
if( !context->is_fullscreen )
{
context->windowed_size[0] = width;
context->windowed_size[1] = height;
}
// TODO: Fancy display managers seem to cause this to mess up?
context->had_input = 20; //context->is_double_buffered ? 2 : 1;
context->has_resized = 20; //context->is_double_buffered ? 2 : 1;
Viewport win(0,0,width,height);
context->base.Resize(win);
}
void SpecialInput(InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4)
{
// Assume coords already match OpenGl Window Coords
context->had_input = context->is_double_buffered ? 2 : 1;
const bool fresh_input = (context->mouse_state == 0);
if(fresh_input) {
context->base.handler->Special(context->base,inType,x,y,p1,p2,p3,p4,context->mouse_state);
}else if(context->activeDisplay && context->activeDisplay->handler) {
context->activeDisplay->handler->Special(*(context->activeDisplay),inType,x,y,p1,p2,p3,p4,context->mouse_state);
}
}
void Scroll(float x, float y)
{
SpecialInput(InputSpecialScroll, last_x, last_y, x, y, 0, 0);
}
void Zoom(float m)
{
SpecialInput(InputSpecialZoom, last_x, last_y, m, 0, 0, 0);
}
void Rotate(float r)
{
SpecialInput(InputSpecialRotate, last_x, last_y, r, 0, 0, 0);
}
void SubpixMotion(float x, float y, float pressure, float rotation, float tiltx, float tilty)
{
// Force coords to match OpenGl Window Coords
y = context->base.v.h - y;
SpecialInput(InputSpecialTablet, x, y, pressure, rotation, tiltx, tilty);
}
}
void DrawTextureToViewport(GLuint texid)
{
OpenGlRenderState::ApplyIdentity();
glBindTexture(GL_TEXTURE_2D, texid);
glEnable(GL_TEXTURE_2D);
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);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
ToggleViewFunctor::ToggleViewFunctor(View& view)
: view(view)
{
}
ToggleViewFunctor::ToggleViewFunctor(const std::string& name)
: view(Display(name))
{
}
void ToggleViewFunctor::operator()()
{
view.ToggleShow();
}
}

View File

@@ -0,0 +1,223 @@
#include <pangolin/display/image_view.h>
#include <pangolin/image/image_utils.h>
#include <pangolin/image/image_convert.h>
namespace pangolin
{
ImageView::ImageView()
: offset_scale(0.0f, 1.0f), lastPressed(false), mouseReleased(false), mousePressed(false), overlayRender(true)
{
SetHandler(this);
}
ImageView::~ImageView()
{
}
void ImageView::Render()
{
LoadPending();
glPushAttrib(GL_DEPTH_BITS);
glDisable(GL_DEPTH_TEST);
Activate();
this->UpdateView();
this->glSetViewOrtho();
if(tex.IsValid())
{
if(offset_scale.first != 0.0 || offset_scale.second != 1.0)
{
pangolin::GlSlUtilities::OffsetAndScale(offset_scale.first, offset_scale.second);
}
else
{
glColor4f(1, 1, 1, 1);
}
this->glRenderTexture(tex);
pangolin::GlSlUtilities::UseNone();
}
if(overlayRender)
{
this->glRenderOverlay();
}
if(extern_draw_function)
{
extern_draw_function(*this);
}
glPopAttrib();
}
void ImageView::Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state)
{
ImageViewHandler::Mouse(view, button, x, y, pressed, button_state);
mouseReleased = (!pressed && lastPressed);
mousePressed = lastPressed = (pressed && button == pangolin::MouseButtonLeft);
}
void ImageView::Keyboard(View& view, unsigned char key, int x, int y, bool pressed)
{
if(key == 'a')
{
if(!tex.IsValid())
{
std::cerr << "ImageViewHandler does not contain valid texture." << std::endl;
return;
}
// compute scale
const bool have_selection = std::isfinite(GetSelection().Area()) && std::abs(GetSelection().Area()) >= 4;
const pangolin::XYRangef froi = have_selection ? GetSelection() : GetViewToRender();
// Download texture so that we can take min / max
pangolin::TypedImage img;
tex.Download(img);
offset_scale = pangolin::GetOffsetScale(img, pangolin::Round(froi), img.fmt);
}
else if(key == 'b')
{
if(!tex.IsValid())
{
std::cerr << "ImageViewHandler does not contain valid texture." << std::endl;
return;
}
// compute scale
const bool have_selection = std::isfinite(GetSelection().Area()) && std::abs(GetSelection().Area()) >= 4;
const pangolin::XYRangef froi = have_selection ? GetSelection() : GetViewToRender();
// Download texture so that we can take min / max
pangolin::TypedImage img;
tex.Download(img);
std::pair<float, float> mm = pangolin::GetMinMax(img, pangolin::Round(froi), img.fmt);
printf("Min / Max in Region: %f / %f\n", mm.first, mm.second);
}
else
{
pangolin::ImageViewHandler::Keyboard(view, key, x, y, pressed);
}
}
pangolin::GlTexture& ImageView::Tex() {
return tex;
}
ImageView& ImageView::SetImage(void* ptr, size_t w, size_t h, size_t pitch, pangolin::GlPixFormat img_fmt, bool delayed_upload )
{
const size_t pix_bytes =
pangolin::GlFormatChannels(img_fmt.glformat) * pangolin::GlDataTypeBytes(img_fmt.gltype);
const bool convert_first = (img_fmt.gltype == GL_DOUBLE);
if(delayed_upload || !pangolin::GetBoundWindow() || IsDevicePtr(ptr) || convert_first )
{
texlock.lock();
if(!convert_first) {
img_to_load = ManagedImage<unsigned char>(w,h,w*pix_bytes);
PitchedCopy((char*)img_to_load.ptr, img_to_load.pitch, (char*)ptr, pitch, w * pix_bytes, h);
img_fmt_to_load = img_fmt;
}else if(img_fmt.gltype == GL_DOUBLE) {
Image<double> double_image( (double*)ptr, w, h, pitch);
img_to_load.OwnAndReinterpret(ImageConvert<float>(double_image));
img_fmt_to_load = GlPixFormat::FromType<float>();
}else{
pango_print_warn("TextureView: Unable to display image.\n");
}
texlock.unlock();
return *this;
}
PANGO_ASSERT(pitch % pix_bytes == 0);
const size_t stride = pitch / pix_bytes;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
// Initialise if it didn't already exist or the size was too small
if(!tex.tid || tex.width != (int)w || tex.height != (int)h ||
tex.internal_format != img_fmt.scalable_internal_format)
{
fmt = img_fmt;
SetDimensions(w, h);
SetAspect((float)w / (float)h);
tex.Reinitialise(w, h, img_fmt.scalable_internal_format, true, 0, img_fmt.glformat, img_fmt.gltype, ptr);
}
else
{
tex.Upload(ptr, img_fmt.glformat, img_fmt.gltype);
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
return *this;
}
ImageView& ImageView::SetImage(const pangolin::Image<unsigned char>& img, const pangolin::GlPixFormat& glfmt, bool delayed_upload )
{
return SetImage(img.ptr, img.w, img.h, img.pitch, glfmt, delayed_upload);
}
ImageView& ImageView::SetImage(const pangolin::TypedImage& img, bool delayed_upload )
{
return SetImage(img.ptr, img.w, img.h, img.pitch, pangolin::GlPixFormat(img.fmt), delayed_upload);
}
ImageView& ImageView::SetImage(const pangolin::GlTexture& texture)
{
// Initialise if it didn't already exist or the size was too small
if(!tex.tid || tex.width != texture.width || tex.height != texture.height ||
tex.internal_format != texture.internal_format)
{
SetDimensions(texture.width, texture.height);
SetAspect((float)texture.width / (float)texture.height);
tex.Reinitialise(texture.width, texture.height, texture.internal_format, true);
}
glCopyImageSubData(
texture.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tex.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tex.width, tex.height, 1);
return *this;
}
void ImageView::LoadPending()
{
if(img_to_load.ptr)
{
// Scoped lock
texlock.lock();
SetImage(img_to_load, img_fmt_to_load, false);
img_to_load.Deallocate();
texlock.unlock();
}
}
ImageView& ImageView::Clear()
{
tex.Delete();
return *this;
}
std::pair<float, float>& ImageView::GetOffsetScale() {
return offset_scale;
}
bool ImageView::MouseReleased() const {
return mouseReleased;
}
bool ImageView::MousePressed() const {
return mousePressed;
}
void ImageView::SetRenderOverlay(const bool& val) {
overlayRender = val;
}
}

View File

@@ -0,0 +1,707 @@
/* 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.
*/
#include <pangolin/display/opengl_render_state.h>
#include <pangolin/gl/glinclude.h>
#include <stdexcept>
namespace pangolin
{
inline void glLoadMatrix(const float* m) { glLoadMatrixf(m); }
inline void glMultMatrix(const float* m) { glMultMatrixf(m); }
#ifndef HAVE_GLES
inline void glLoadMatrix(const double* m) { glLoadMatrixd(m); }
inline void glMultMatrix(const double* m) { glMultMatrixd(m); }
#endif
OpenGlMatrix OpenGlMatrix::Translate(GLprecision x, GLprecision y, GLprecision z)
{
OpenGlMatrix mat;
mat.SetIdentity();
mat(0, 3) = x;
mat(1, 3) = y;
mat(2, 3) = z;
return mat;
}
OpenGlMatrix OpenGlMatrix::Scale(GLprecision x, GLprecision y, GLprecision z)
{
OpenGlMatrix mat;
mat.SetIdentity();
mat(0, 0) = x;
mat(1, 1) = y;
mat(2, 2) = z;
return mat;
}
OpenGlMatrix OpenGlMatrix::RotateX(GLprecision theta_rad)
{
OpenGlMatrix mat;
mat.SetIdentity();
const GLprecision costh = cos(theta_rad);
const GLprecision sinth = sin(theta_rad);
mat(1, 1) = costh;
mat(1, 2) = -sinth;
mat(2, 1) = sinth;
mat(2, 2) = costh;
return mat;
}
OpenGlMatrix OpenGlMatrix::RotateY(GLprecision theta_rad)
{
OpenGlMatrix mat;
mat.SetIdentity();
const GLprecision costh = cos(theta_rad);
const GLprecision sinth = sin(theta_rad);
mat(0, 0) = costh;
mat(0, 2) = sinth;
mat(2, 0) = -sinth;
mat(2, 2) = costh;
return mat;
}
OpenGlMatrix OpenGlMatrix::RotateZ(GLprecision theta_rad)
{
OpenGlMatrix mat;
mat.SetIdentity();
const GLprecision costh = cos(theta_rad);
const GLprecision sinth = sin(theta_rad);
mat(0, 0) = costh;
mat(0, 1) = -sinth;
mat(1, 0) = sinth;
mat(1, 1) = costh;
return mat;
}
void OpenGlMatrix::Load() const
{
glLoadMatrix(m);
}
void OpenGlMatrix::Multiply() const
{
glMultMatrix(m);
}
void OpenGlMatrix::SetIdentity()
{
m[0] = 1.0f; m[1] = 0.0f; m[2] = 0.0f; m[3] = 0.0f;
m[4] = 0.0f; m[5] = 1.0f; m[6] = 0.0f; m[7] = 0.0f;
m[8] = 0.0f; m[9] = 0.0f; m[10] = 1.0f; m[11] = 0.0f;
m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
}
OpenGlMatrix OpenGlMatrix::Transpose() const
{
OpenGlMatrix trans;
trans.m[0] = m[0]; trans.m[4] = m[1]; trans.m[8] = m[2]; trans.m[12] = m[3];
trans.m[1] = m[4]; trans.m[5] = m[5]; trans.m[9] = m[6]; trans.m[13] = m[7];
trans.m[2] = m[8]; trans.m[6] = m[9]; trans.m[10] = m[10]; trans.m[14] = m[11];
trans.m[3] = m[12]; trans.m[7] = m[13]; trans.m[11] = m[14]; trans.m[15] = m[15];
return trans;
}
OpenGlMatrix OpenGlMatrix::Inverse() const
{
OpenGlMatrix inv;
inv.m[0] = m[0]; inv.m[4] = m[1]; inv.m[8] = m[2]; inv.m[12] = -(m[0]*m[12] + m[1]*m[13] + m[2]*m[14]);
inv.m[1] = m[4]; inv.m[5] = m[5]; inv.m[9] = m[6]; inv.m[13] = -(m[4]*m[12] + m[5]*m[13] + m[6]*m[14]);
inv.m[2] = m[8]; inv.m[6] = m[9]; inv.m[10] = m[10]; inv.m[14] = -(m[8]*m[12] + m[9]*m[13] + m[10]*m[14]);
inv.m[3] = 0; inv.m[7] = 0; inv.m[11] = 0; inv.m[15] = 1;
return inv;
}
std::ostream& operator<<(std::ostream& os, const OpenGlMatrix& mat)
{
for(int r=0; r< 4; ++r) {
for(int c=0; c<4; ++c) {
std::cout << mat.m[4*c+r] << '\t';
}
std::cout << std::endl;
}
return os;
}
void OpenGlRenderState::Apply() const
{
glMatrixMode(GL_PROJECTION);
projection[0].Load();
// Leave in MODEVIEW mode
glMatrixMode(GL_MODELVIEW);
modelview.Load();
if(follow) {
T_cw.Multiply();
}
}
OpenGlMatrix& OpenGlRenderState::GetProjectionMatrix(unsigned int view)
{
if( projection.size() <= view ) {
projection.resize(view+1);
}
return projection[view];
}
OpenGlMatrix OpenGlRenderState::GetProjectionMatrix(unsigned int view) const
{
if( projection.size() <= view ) {
return IdentityMatrix();
}
return projection[view];
}
OpenGlMatrix& OpenGlRenderState::GetViewOffset(unsigned int view)
{
if( modelview_premult.size() <= view ) {
modelview_premult.resize(view+1);
}
return modelview_premult[view];
}
OpenGlMatrix OpenGlRenderState::GetViewOffset(unsigned int view) const
{
if( modelview_premult.size() <= view ) {
return IdentityMatrix();
}
return modelview_premult[view];
}
void OpenGlRenderState::ApplyNView(int view) const
{
glMatrixMode(GL_PROJECTION);
projection[view].Load();
// Leave in MODEVIEW mode
glMatrixMode(GL_MODELVIEW);
OpenGlMatrix m = GetModelViewMatrix(view);
m.Load();
if(follow) {
T_cw.Multiply();
}
}
OpenGlRenderState::OpenGlRenderState()
: modelview(IdentityMatrix()), follow(false)
{
projection.push_back( IdentityMatrix() );
}
OpenGlRenderState::OpenGlRenderState(const OpenGlMatrix& projection_matrix)
: modelview(IdentityMatrix()), follow(false)
{
projection.push_back( projection_matrix );
}
OpenGlRenderState::OpenGlRenderState(const OpenGlMatrix& projection_matrix, const OpenGlMatrix& modelview_matrx)
: modelview(modelview_matrx), follow(false)
{
projection.push_back( projection_matrix );
}
void OpenGlRenderState::ApplyIdentity()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
OpenGlRenderState& OpenGlRenderState::SetProjectionMatrix(OpenGlMatrix m)
{
projection[0] = m;
return *this;
}
OpenGlRenderState& OpenGlRenderState::SetModelViewMatrix(OpenGlMatrix m)
{
modelview = m;
return *this;
}
OpenGlRenderState& OpenGlRenderState::Set(OpenGlMatrixSpec m)
{
switch (m.type) {
case GlProjectionStack:
projection[0] = m;
break;
case GlModelViewStack:
modelview = m;
break;
default:
throw std::runtime_error("Unexpected matrix type");
break;
}
return *this;
}
OpenGlMatrix operator*(const OpenGlMatrix& lhs, const OpenGlMatrix& rhs)
{
OpenGlMatrix ret;
pangolin::MatMul<4,4,4>(ret.m, lhs.m, rhs.m);
return ret;
}
OpenGlMatrix& OpenGlRenderState::GetProjectionMatrix()
{
// guarenteed to have at least one projection matrix element
return projection[0];
}
OpenGlMatrix OpenGlRenderState::GetProjectionMatrix() const
{
// guarenteed to have at least one projection matrix element
return projection[0];
}
OpenGlMatrix& OpenGlRenderState::GetModelViewMatrix()
{
return modelview;
}
OpenGlMatrix OpenGlRenderState::GetModelViewMatrix() const
{
return modelview;
}
OpenGlMatrix OpenGlRenderState::GetModelViewMatrix(int i) const
{
return modelview_premult[i] * modelview;
}
OpenGlMatrix OpenGlRenderState::GetProjectionModelViewMatrix() const
{
return GetProjectionMatrix() * GetModelViewMatrix();
}
OpenGlMatrix OpenGlRenderState::GetProjectiveTextureMatrix() const
{
return OpenGlMatrix::Translate(0.5,0.5,0.5) * OpenGlMatrix::Scale(0.5,0.5,0.5) * GetProjectionModelViewMatrix();
}
void OpenGlRenderState::EnableProjectiveTexturing() const
{
#ifndef HAVE_GLES
const pangolin::OpenGlMatrix projmattrans = GetProjectiveTextureMatrix().Transpose();
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
glTexGendv(GL_S, GL_EYE_PLANE, projmattrans.m);
glTexGendv(GL_T, GL_EYE_PLANE, projmattrans.m+4);
glTexGendv(GL_R, GL_EYE_PLANE, projmattrans.m+8);
glTexGendv(GL_Q, GL_EYE_PLANE, projmattrans.m+12);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
#endif
}
void OpenGlRenderState::DisableProjectiveTexturing() const
{
#ifndef HAVE_GLES
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
#endif
}
void OpenGlRenderState::Follow(const OpenGlMatrix& T_wc, bool follow)
{
this->T_cw = T_wc.Inverse();
if(follow != this->follow) {
if(follow) {
const OpenGlMatrix T_vc = GetModelViewMatrix() * T_wc;
SetModelViewMatrix(T_vc);
this->follow = true;
}else{
Unfollow();
}
}
}
void OpenGlRenderState::Unfollow()
{
const OpenGlMatrix T_vw = GetModelViewMatrix() * T_cw;
SetModelViewMatrix(T_vw);
this->follow = false;
}
// Use OpenGl's default frame of reference
OpenGlMatrixSpec ProjectionMatrix(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
return ProjectionMatrixRUB_BottomLeft(w,h,fu,fv,u0,v0,zNear,zFar);
}
OpenGlMatrixSpec ProjectionMatrixOrthographic(GLprecision l, GLprecision r, GLprecision b, GLprecision t, GLprecision n, GLprecision f )
{
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
P.m[0] = 2/(r-l);
P.m[1] = 0;
P.m[2] = 0;
P.m[3] = 0;
P.m[4] = 0;
P.m[5] = 2/(t-b);
P.m[6] = 0;
P.m[7] = 0;
P.m[8] = 0;
P.m[9] = 0;
P.m[10] = -2/(f-n);
P.m[11] = 0;
P.m[12] = -(r+l)/(r-l);
P.m[13] = -(t+b)/(t-b);
P.m[14] = -(f+n)/(f-n);
P.m[15] = 1;
return P;
}
// Camera Axis:
// X - Right, Y - Up, Z - Back
// Image Origin:
// Bottom Left
// Caution: Principal point defined with respect to image origin (0,0) at
// top left of top-left pixel (not center, and in different frame
// of reference to projection function image)
OpenGlMatrixSpec ProjectionMatrixRUB_BottomLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
// http://www.songho.ca/opengl/gl_projectionmatrix.html
const GLprecision L = +(u0) * zNear / -fu;
const GLprecision T = +(v0) * zNear / fv;
const GLprecision R = -(w-u0) * zNear / -fu;
const GLprecision B = -(h-v0) * zNear / fv;
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
std::fill_n(P.m,4*4,0);
P.m[0*4+0] = 2 * zNear / (R-L);
P.m[1*4+1] = 2 * zNear / (T-B);
P.m[2*4+2] = -(zFar +zNear) / (zFar - zNear);
P.m[2*4+0] = (R+L)/(R-L);
P.m[2*4+1] = (T+B)/(T-B);
P.m[2*4+3] = -1.0;
P.m[3*4+2] = -(2*zFar*zNear)/(zFar-zNear);
return P;
}
// Camera Axis:
// X - Right, Y - Up, Z - Back
// Image Origin:
// Top Left
// Caution: Principal point defined with respect to image origin (0,0) at
// top left of top-left pixel (not center, and in different frame
// of reference to projection function image)
OpenGlMatrixSpec ProjectionMatrixRUB_TopLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
// http://www.songho.ca/opengl/gl_projectionmatrix.html
const GLprecision L = +(u0) * zNear / -fu;
const GLprecision R = -(w-u0) * zNear / -fu;
const GLprecision T = -(h-v0) * zNear / fv;
const GLprecision B = +(v0) * zNear / fv;
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
std::fill_n(P.m,4*4,0);
P.m[0*4+0] = 2 * zNear / (R-L);
P.m[1*4+1] = 2 * zNear / (T-B);
P.m[2*4+2] = -(zFar +zNear) / (zFar - zNear);
P.m[2*4+0] = (R+L)/(R-L);
P.m[2*4+1] = (T+B)/(T-B);
P.m[2*4+3] = -1.0;
P.m[3*4+2] = -(2*zFar*zNear)/(zFar-zNear);
return P;
}
// Camera Axis:
// X - Right, Y - Down, Z - Forward
// Image Origin:
// Top Left
// Pricipal point specified with image origin (0,0) at top left of top-left pixel (not center)
OpenGlMatrixSpec ProjectionMatrixRDF_TopLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
// http://www.songho.ca/opengl/gl_projectionmatrix.html
const GLprecision L = -(u0) * zNear / fu;
const GLprecision R = +(w-u0) * zNear / fu;
const GLprecision T = -(v0) * zNear / fv;
const GLprecision B = +(h-v0) * zNear / fv;
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
std::fill_n(P.m,4*4,0);
P.m[0*4+0] = 2 * zNear / (R-L);
P.m[1*4+1] = 2 * zNear / (T-B);
P.m[2*4+0] = (R+L)/(L-R);
P.m[2*4+1] = (T+B)/(B-T);
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
P.m[2*4+3] = 1.0;
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
return P;
}
// Camera Axis:
// X - Right, Y - Down, Z - Forward
// Image Origin:
// Top Right
// Pricipal point specified with image origin (0,0) at top right of top-right pixel (not center)
OpenGlMatrixSpec ProjectionMatrixRDF_TopRight(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
// http://www.songho.ca/opengl/gl_projectionmatrix.html
const GLprecision L = +(w-u0) * zNear / fu;
const GLprecision R = -(u0) * zNear / fu;
const GLprecision T = -(v0) * zNear / fv;
const GLprecision B = +(h-v0) * zNear / fv;
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
std::fill_n(P.m,4*4,0);
P.m[0*4+0] = 2 * zNear / (R-L);
P.m[1*4+1] = 2 * zNear / (T-B);
P.m[2*4+0] = (R+L)/(L-R);
P.m[2*4+1] = (T+B)/(B-T);
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
P.m[2*4+3] = 1.0;
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
return P;
}
// Camera Axis:
// X - Right, Y - Down, Z - Forward
// Image Origin:
// Bottom Left
// Pricipal point specified with image origin (0,0) at top left of top-left pixel (not center)
OpenGlMatrixSpec ProjectionMatrixRDF_BottomLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
// http://www.songho.ca/opengl/gl_projectionmatrix.html
const GLprecision L = -(u0) * zNear / fu;
const GLprecision R = +(w-u0) * zNear / fu;
const GLprecision B = -(v0) * zNear / fv;
const GLprecision T = +(h-v0) * zNear / fv;
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
std::fill_n(P.m,4*4,0);
P.m[0*4+0] = 2 * zNear / (R-L);
P.m[1*4+1] = 2 * zNear / (T-B);
P.m[2*4+0] = (R+L)/(L-R);
P.m[2*4+1] = (T+B)/(B-T);
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
P.m[2*4+3] = 1.0;
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
return P;
}
// Camera Axis:
// X - Right, Y - Down, Z - Forward
// Image Origin:
// Bottom Right
// Pricipal point specified with image origin (0,0) at top right of top-right pixel (not center)
OpenGlMatrixSpec ProjectionMatrixRDF_BottomRight(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
{
// http://www.songho.ca/opengl/gl_projectionmatrix.html
const GLprecision R = -(u0) * zNear / fu;
const GLprecision L = +(w-u0) * zNear / fu;
const GLprecision B = -(v0) * zNear / fv;
const GLprecision T = +(h-v0) * zNear / fv;
OpenGlMatrixSpec P;
P.type = GlProjectionStack;
std::fill_n(P.m,4*4,0);
P.m[0*4+0] = 2 * zNear / (R-L);
P.m[1*4+1] = 2 * zNear / (T-B);
P.m[2*4+0] = (R+L)/(L-R);
P.m[2*4+1] = (T+B)/(B-T);
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
P.m[2*4+3] = 1.0;
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
return P;
}
OpenGlMatrix ModelViewLookAtRUB(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz)
{
OpenGlMatrix mat;
GLprecision* m = mat.m;
const GLprecision u_o[3] = {ux,uy,uz};
GLprecision x[3], y[3];
GLprecision z[] = {ex - lx, ey - ly, ez - lz};
Normalise<3>(z);
CrossProduct(x,u_o,z);
CrossProduct(y,z,x);
// Normalize x, y
const GLprecision lenx = Length<3>(x);
const GLprecision leny = Length<3>(y);
if( lenx > 0 && leny > 0) {
for(size_t r = 0; r < 3; ++r ) {
x[r] /= lenx;
y[r] /= leny;
}
#define M(row,col) m[col*4+row]
M(0,0) = x[0];
M(0,1) = x[1];
M(0,2) = x[2];
M(1,0) = y[0];
M(1,1) = y[1];
M(1,2) = y[2];
M(2,0) = z[0];
M(2,1) = z[1];
M(2,2) = z[2];
M(3,0) = 0.0;
M(3,1) = 0.0;
M(3,2) = 0.0;
M(0,3) = -(M(0,0)*ex + M(0,1)*ey + M(0,2)*ez);
M(1,3) = -(M(1,0)*ex + M(1,1)*ey + M(1,2)*ez);
M(2,3) = -(M(2,0)*ex + M(2,1)*ey + M(2,2)*ez);
M(3,3) = 1.0;
#undef M
return mat;
}else{
throw std::invalid_argument("'Look' and 'up' vectors cannot be parallel when calling ModelViewLookAt.");
}
}
OpenGlMatrix ModelViewLookAtRDF(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz)
{
OpenGlMatrix mat;
GLprecision* m = mat.m;
const GLprecision u_o[3] = {ux,uy,uz};
GLprecision x[3], y[3];
GLprecision z[] = {lx - ex, ly - ey, lz - ez};
Normalise<3>(z);
CrossProduct(x,z,u_o);
CrossProduct(y,z,x);
// Normalize x, y
const GLprecision lenx = Length<3>(x);
const GLprecision leny = Length<3>(y);
if( lenx > 0 && leny > 0) {
for(size_t r = 0; r < 3; ++r ) {
x[r] /= lenx;
y[r] /= leny;
}
#define M(row,col) m[col*4+row]
M(0,0) = x[0];
M(0,1) = x[1];
M(0,2) = x[2];
M(1,0) = y[0];
M(1,1) = y[1];
M(1,2) = y[2];
M(2,0) = z[0];
M(2,1) = z[1];
M(2,2) = z[2];
M(3,0) = 0.0;
M(3,1) = 0.0;
M(3,2) = 0.0;
M(0,3) = -(M(0,0)*ex + M(0,1)*ey + M(0,2)*ez);
M(1,3) = -(M(1,0)*ex + M(1,1)*ey + M(1,2)*ez);
M(2,3) = -(M(2,0)*ex + M(2,1)*ey + M(2,2)*ez);
M(3,3) = 1.0;
#undef M
return mat;
}else{
throw std::invalid_argument("'Look' and 'up' vectors cannot be parallel when calling ModelViewLookAt.");
}
}
OpenGlMatrix ModelViewLookAt(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz)
{
return ModelViewLookAtRUB(ex,ey,ez,lx,ly,lz,ux,uy,uz);
}
OpenGlMatrix ModelViewLookAt(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, AxisDirection up)
{
const GLprecision* u = AxisDirectionVector[up];
return ModelViewLookAtRUB(ex,ey,ez,lx,ly,lz,u[0],u[1],u[2]);
}
OpenGlMatrix IdentityMatrix()
{
OpenGlMatrix P;
std::fill_n(P.m,4*4,0);
for( int i=0; i<4; ++i ) P.m[i*4+i] = 1;
return P;
}
OpenGlMatrixSpec IdentityMatrix(OpenGlStack type)
{
OpenGlMatrixSpec P;
P.type = type;
std::fill_n(P.m,4*4,0);
for( int i=0; i<4; ++i ) P.m[i*4+i] = 1;
return P;
}
OpenGlMatrixSpec negIdentityMatrix(OpenGlStack type)
{
OpenGlMatrixSpec P;
P.type = type;
std::fill_n(P.m,4*4,0);
for( int i=0; i<4; ++i ) P.m[i*4+i] = -1;
P.m[3*4+3] =1;
return P;
}
}

583
thirdparty/Pangolin/src/display/view.cpp vendored Normal file
View File

@@ -0,0 +1,583 @@
/* 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 <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/display/opengl_render_state.h>
#include <pangolin/display/view.h>
#include <pangolin/display/viewport.h>
#include <pangolin/gl/gl.h>
#include <pangolin/platform.h>
#include <stdexcept>
namespace pangolin
{
// Pointer to context defined in display.cpp
extern __thread PangolinGl* context;
const int panal_v_margin = 6;
int AttachAbs( int low, int high, Attach a)
{
if( a.unit == Pixel ) return low + (int)a.p;
if( a.unit == ReversePixel ) return high - (int)a.p;
return (int)(low + a.p * (high - low));
}
double AspectAreaWithinTarget(double target, double test)
{
if( test < target )
return test / target;
else
return target / test;
}
void SaveViewFromFbo(std::string prefix, View& view, float scale)
{
PANGOLIN_UNUSED(prefix);
#ifndef HAVE_GLES
const Viewport orig = view.v;
view.v.l = 0;
view.v.b = 0;
view.v.w = (int)(view.v.w * scale);
view.v.h = (int)(view.v.h * scale);
const int w = view.v.w;
const int h = view.v.h;
float origLineWidth;
glGetFloatv(GL_LINE_WIDTH, &origLineWidth);
glLineWidth(origLineWidth * scale);
float origPointSize;
glGetFloatv(GL_POINT_SIZE, &origPointSize);
glPointSize(origPointSize * scale);
// Create FBO
GlTexture color(w,h);
GlRenderBuffer depth(w,h);
GlFramebuffer fbo(color, depth);
// Render into FBO
fbo.Bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
view.Render();
glFlush();
#ifdef HAVE_PNG
const PixelFormat fmt = PixelFormatFromString("RGBA32");
TypedImage buffer(w, h, fmt );
glReadBuffer(GL_BACK);
glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this?
glReadPixels(0,0,w,h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.ptr );
SaveImage(buffer, fmt, prefix + ".png", false);
#endif // HAVE_PNG
// unbind FBO
fbo.Unbind();
// restore viewport / line width
view.v = orig;
glLineWidth(origLineWidth);
glPointSize(origPointSize);
#endif // HAVE_GLES
}
void View::Resize(const Viewport& p)
{
// Compute Bounds based on specification
v.l = AttachAbs(p.l,p.r(),left);
v.b = AttachAbs(p.b,p.t(),bottom);
int r = AttachAbs(p.l,p.r(),right);
int t = AttachAbs(p.b,p.t(),top);
// Make sure left and right, top and bottom are correct order
if( t < v.b ) std::swap(t,v.b);
if( r < v.l ) std::swap(r,v.l);
v.w = r - v.l;
v.h = t - v.b;
vp = v;
// Adjust based on aspect requirements
if( aspect != 0 )
{
const float current_aspect = (float)v.w / (float)v.h;
if( aspect > 0 )
{
// Fit to space
if( current_aspect < aspect )
{
//Adjust height
const int nh = (int)(v.w / aspect);
v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
v.h = nh;
}else if( current_aspect > aspect )
{
//Adjust width
const int nw = (int)(v.h * aspect);
v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
v.w = nw;
}
}else{
// Overfit
double true_aspect = -aspect;
if( current_aspect < true_aspect )
{
//Adjust width
const int nw = (int)(v.h * true_aspect);
v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
v.w = nw;
}else if( current_aspect > true_aspect )
{
//Adjust height
const int nh = (int)(v.w / true_aspect);
v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
v.h = nh;
}
}
}
ResizeChildren();
}
inline int zcompare(const View* lhs, const View* rhs)
{
return lhs->zorder < rhs->zorder;
}
void View::ResizeChildren()
{
if( layout == LayoutOverlay )
{
// Sort children into z-order
std::sort(views.begin(), views.end(), zcompare);
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv ) {
(*iv)->Resize(v);
}
}else if( layout == LayoutVertical )
{
// Allocate space incrementally
Viewport space = v.Inset(panal_v_margin);
int num_children = 0;
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
{
if (!(*iv)->show) continue;
num_children++;
if(scroll_offset >= num_children ) {
(*iv)->scroll_show = false;
}else{
(*iv)->scroll_show = true;
(*iv)->Resize(space);
space.h = (*iv)->v.b - panal_v_margin - space.b;
}
}
}else if(layout == LayoutHorizontal )
{
// Allocate space incrementally
const int margin = 8;
Viewport space = v.Inset(margin);
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
{
(*iv)->Resize(space);
space.w = (*iv)->v.l + margin + space.l;
}
}else if(layout == LayoutEqualVertical )
{
// Allocate vertical space equally
const size_t visiblechildren = NumVisibleChildren();
const float height = (float)v.h / (float)visiblechildren;
for( size_t i=0; i < visiblechildren; ++i) {
Viewport space(v.l, (GLint)(v.b+(visiblechildren-1-i)*height), v.w, (GLint)(height) );
VisibleChild(i).Resize(space);
}
}else if(layout == LayoutEqualHorizontal )
{
// Allocate vertical space equally
const size_t visiblechildren = NumVisibleChildren();
const float width = (float)v.w / (float)visiblechildren;
for( size_t i=0; i < visiblechildren; ++i) {
Viewport space( (GLint)(v.l+i*width), v.b, (GLint)width, v.h);
VisibleChild(i).Resize(space);
}
}else if(layout == LayoutEqual )
{
const size_t visiblechildren = NumVisibleChildren();
// TODO: Make this neater, and make fewer assumptions!
if( visiblechildren > 0 )
{
// This containers aspect
const double this_a = std::fabs(v.aspect());
// Use first child with fixed aspect for all children
double child_a = std::fabs(VisibleChild(0).aspect);
for(size_t i=1; (child_a==0) && i < visiblechildren; ++i ) {
child_a = std::fabs(VisibleChild(i).aspect);
}
if(child_a == 0) {
child_a = 1;
}
double a = visiblechildren*child_a;
double area = AspectAreaWithinTarget(this_a, a);
size_t cols = visiblechildren-1;
for(; cols > 0; --cols)
{
const size_t rows = visiblechildren / cols + (visiblechildren % cols == 0 ? 0 : 1);
const double na = cols * child_a / rows;
const double new_area = visiblechildren*AspectAreaWithinTarget(this_a,na)/(rows*cols);
if( new_area <= area )
break;
area = new_area;
a = na;
}
cols++;
const size_t rows = visiblechildren / cols + (visiblechildren % cols == 0 ? 0 : 1);
size_t cw, ch;
if( a > this_a )
{
cw = v.w / cols;
ch = (int)(cw / child_a); //v.h / rows;
}else{
ch = v.h / rows;
cw = (int)(ch * child_a);
}
for(size_t i=0; i< visiblechildren; ++i )
{
size_t c = i % cols;
size_t r = i / cols;
Viewport space( GLint(v.l + c*cw), GLint(v.t() - (r+1)*ch), GLint(cw), GLint(ch) );
VisibleChild(i).Resize(space);
}
}
}
}
void View::Render()
{
if(extern_draw_function && show && scroll_show) {
extern_draw_function(*this);
}
RenderChildren();
}
void View::RenderChildren()
{
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
{
if((*iv)->show && (*iv)->scroll_show) (*iv)->Render();
}
}
void View::Activate() const
{
v.Activate();
}
void View::ActivateAndScissor() const
{
vp.Scissor();
v.Activate();
}
void View::ActivateScissorAndClear() const
{
vp.Scissor();
v.Activate();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void View::Activate(const OpenGlRenderState& state ) const
{
v.Activate();
state.Apply();
}
void View::ActivateAndScissor(const OpenGlRenderState& state) const
{
vp.Scissor();
v.Activate();
state.Apply();
}
void View::ActivateScissorAndClear(const OpenGlRenderState& state ) const
{
vp.Scissor();
v.Activate();
state.Apply();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void View::ActivatePixelOrthographic() const
{
v.ActivatePixelOrthographic();
}
void View::ActivateIdentity() const
{
v.ActivateIdentity();
}
GLfloat View::GetClosestDepth(int x, int y, int radius) const
{
// TODO: Get to work on android
#ifdef _MSVC_
// MSVC Requires fixed sized arrays on stack
radius = 5;
const int zl = (5*2+1);
#else
const int zl = (radius*2+1);
#endif
const int zsize = zl*zl;
GLfloat zs[zsize];
#ifndef HAVE_GLES
glReadBuffer(GL_FRONT);
glReadPixels(x-radius,y-radius,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
#else
std::fill(zs,zs+zsize, 0.8);
#endif
const GLfloat mindepth = *(std::min_element(zs,zs+zsize));
return mindepth;
}
void View::GetObjectCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
{
const GLint viewport[4] = {v.l,v.b,v.w,v.h};
const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
const OpenGlMatrix mv = cam_state.GetModelViewMatrix();
glUnProject(winx, winy, winzdepth, mv.m, proj.m, viewport, &x, &y, &z);
}
void View::GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
{
v.GetCamCoordinates(cam_state, winx, winy, winzdepth, x, y, z);
}
View& View::SetFocus()
{
context->activeDisplay = this;
return *this;
}
bool View::HasFocus() const
{
return context->activeDisplay == this;
}
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right)
{
this->left = left;
this->top = top;
this->right = right;
this->bottom = bottom;
context->base.ResizeChildren();
return *this;
}
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, bool keep_aspect)
{
aspect = keep_aspect ? v.aspect() : 0;
SetBounds(top,bottom,left,right);
return *this;
}
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect)
{
this->aspect = aspect;
SetBounds(top,bottom,left,right);
return *this;
}
View& View::SetAspect(double aspect)
{
this->aspect = aspect;
context->base.ResizeChildren();
return *this;
}
View& View::SetLock(Lock horizontal, Lock vertical )
{
vlock = vertical;
hlock = horizontal;
return *this;
}
View& View::SetLayout(Layout l)
{
layout = l;
return *this;
}
View& View::AddDisplay(View& child)
{
// detach child from any other view, and add to this
std::vector<View*>::iterator f = std::find(
context->base.views.begin(), context->base.views.end(), &child
);
if( f != context->base.views.end() )
context->base.views.erase(f);
views.push_back(&child);
context->base.ResizeChildren();
return *this;
}
View& View::Show(bool show)
{
this->show = show;
context->base.ResizeChildren();
return *this;
}
void View::ToggleShow()
{
Show(!show);
}
bool View::IsShown() const
{
return show;
}
Viewport View::GetBounds() const
{
return Viewport( std::max(v.l, vp.l), std::max(v.b, vp.b), std::min(v.w, vp.w), std::min(v.h, vp.h) );
}
void View::SaveOnRender(const std::string& filename_prefix)
{
const Viewport tosave = this->v.Intersect(this->vp);
context->screen_capture.push(std::pair<std::string,Viewport>(filename_prefix,tosave ) );
}
void View::RecordOnRender(const std::string& record_uri)
{
PANGOLIN_UNUSED(record_uri);
#ifdef BUILD_PANGOLIN_VIDEO
if(!context->recorder.IsOpen()) {
Viewport area = GetBounds();
context->record_view = this;
try{
context->recorder.Open(record_uri);
std::vector<StreamInfo> streams;
const PixelFormat fmt = PixelFormatFromString("RGB24");
streams.push_back( StreamInfo(fmt, area.w, area.h, area.w * fmt.bpp / 8) );
context->recorder.SetStreams(streams);
}catch(const std::exception& e) {
pango_print_error("Unable to open VideoRecorder:\n\t%s\n", e.what());
}
}else{
context->recorder.Close();
}
#else
std::cerr << "Error: Video Support hasn't been built into this library." << std::endl;
#endif // BUILD_PANGOLIN_VIDEO
}
void View::SaveRenderNow(const std::string& filename_prefix, float scale)
{
SaveViewFromFbo(filename_prefix, *this, scale);
}
View& View::operator[](size_t i)
{
return *views[i];
}
size_t View::NumChildren() const
{
return views.size();
}
size_t View::NumVisibleChildren() const
{
int numvis = 0;
for(std::vector<View*>::const_iterator i=views.begin(); i!=views.end(); ++i)
{
if((*i)->show) {
numvis++;
}
}
return numvis;
}
View& View::VisibleChild(size_t i)
{
size_t numvis = 0;
for(size_t v=0; v < views.size(); ++v ) {
if(views[v]->show) {
if( i == numvis ) {
return *views[v];
}
numvis++;
}
}
// Shouldn't get here
throw std::out_of_range("No such child.");
}
View* View::FindChild(int x, int y)
{
// Find in reverse order to mirror draw order
for( std::vector<View*>::const_reverse_iterator i = views.rbegin(); i != views.rend(); ++i )
if( (*i)->show && (*i)->GetBounds().Contains(x,y) )
return (*i);
return 0;
}
View& View::SetHandler(Handler* h)
{
handler = h;
return *this;
}
View& View::SetDrawFunction(const std::function<void(View&)>& drawFunc)
{
extern_draw_function = drawFunc;
return *this;
}
}

View File

@@ -0,0 +1,113 @@
/* 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.
*/
#include <pangolin/display/viewport.h>
#include <algorithm>
#include <pangolin/utils/simple_math.h>
namespace pangolin {
void Viewport::Activate() const
{
glViewport(l,b,w,h);
}
void Viewport::Scissor() const
{
glEnable(GL_SCISSOR_TEST);
glScissor(l,b,w,h);
}
void Viewport::ActivateAndScissor() const
{
glViewport(l,b,w,h);
glEnable(GL_SCISSOR_TEST);
glScissor(l,b,w,h);
}
void Viewport::DisableScissor()
{
glDisable(GL_SCISSOR_TEST);
}
bool Viewport::Contains(int x, int y) const
{
return l <= x && x < (l+w) && b <= y && y < (b+h);
}
void Viewport::ActivatePixelOrthographic() const
{
Activate();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-0.5, w-0.5, -0.5, h-0.5, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Viewport::ActivateIdentity() const
{
Activate();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Viewport Viewport::Inset(int i) const
{
return Viewport(l+i, b+i, w-2*i, h-2*i);
}
Viewport Viewport::Inset(int horiz, int vert) const
{
return Viewport(l+horiz, b+vert, w-horiz, h-vert);
}
Viewport Viewport::Intersect(const Viewport& vp) const
{
GLint nl = std::max(l,vp.l);
GLint nr = std::min(r(),vp.r());
GLint nb = std::max(b,vp.b);
GLint nt = std::min(t(),vp.t());
return Viewport(nl,nb, nr-nl, nt-nb);
}
void Viewport::GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
{
const GLint viewport[4] = {l, b, w, h};
const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
#ifndef HAVE_GLES
glUnProject(winx, winy, winzdepth, Identity4d, proj.m, viewport, &x, &y, &z);
#else
glUnProject(winx, winy, winzdepth, Identity4f, proj.m, viewport, &x, &y, &z);
#endif
}
}

View File

@@ -0,0 +1,680 @@
/* 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 <pangolin/display/widgets/widgets.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/gl/gldraw.h>
#include <pangolin/var/varextra.h>
#include <pangolin/utils/file_utils.h>
#include <thread>
#include <mutex>
#include <iostream>
#include <iomanip>
using namespace std;
namespace pangolin
{
// Pointer to context defined in display.cpp
extern __thread PangolinGl* context;
const static GLfloat colour_s1[4] = {0.2f, 0.2f, 0.2f, 1.0f};
const static GLfloat colour_s2[4] = {0.6f, 0.6f, 0.6f, 1.0f};
const static GLfloat colour_bg[4] = {0.9f, 0.9f, 0.9f, 1.0f};
const static GLfloat colour_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
const static GLfloat colour_tx[4] = {0.0f, 0.0f, 0.0f, 1.0f};
const static GLfloat colour_dn[4] = {1.0f, 0.7f, 0.7f, 1.0f};
static inline GlFont& font()
{
return GlFont::I();
}
static inline int cb_height()
{
return (int)(font().Height() * 1.0);
}
static inline int tab_h()
{
return (int)(font().Height() * 1.4);
}
std::mutex display_mutex;
template<typename T>
void GuiVarChanged( Var<T>& var)
{
VarState::I().FlagVarChanged();
var.Meta().gui_changed = true;
for(std::vector<GuiVarChangedCallback>::iterator igvc = VarState::I().gui_var_changed_callbacks.begin(); igvc != VarState::I().gui_var_changed_callbacks.end(); ++igvc) {
if( StartsWith(var.Meta().full_name, igvc->filter) ) {
igvc->fn( igvc->data, var.Meta().full_name, var.Ref() );
}
}
}
void glRect(Viewport v)
{
GLfloat vs[] = { (float)v.l,(float)v.b,
(float)v.l,(float)v.t(),
(float)v.r(),(float)v.t(),
(float)v.r(),(float)v.b };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vs);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
}
void glRect(Viewport v, int inset)
{
glRect(v.Inset(inset));
}
void DrawShadowRect(Viewport& v)
{
glColor4fv(colour_s2);
glDrawRectPerimeter((GLfloat)v.l, (GLfloat)v.b, (GLfloat)v.r(), (GLfloat)v.t());
}
void DrawShadowRect(Viewport& v, bool pushed)
{
const GLfloat* c1 = pushed ? colour_s1 : colour_s2;
const GLfloat* c2 = pushed ? colour_s2 : colour_s1;
GLfloat vs[] = { (float)v.l,(float)v.b,
(float)v.l,(float)v.t(),
(float)v.r(),(float)v.t(),
(float)v.r(),(float)v.b,
(float)v.l,(float)v.b };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vs);
glColor4fv(c1);
glDrawArrays(GL_LINE_STRIP, 0, 3);
glColor4fv(c2);
glDrawArrays(GL_LINE_STRIP, 2, 3);
glDisableClientState(GL_VERTEX_ARRAY);
}
Panel::Panel()
{
handler = &StaticHandlerScroll;
layout = LayoutVertical;
}
Panel::Panel(const std::string& auto_register_var_prefix)
{
handler = &StaticHandlerScroll;
layout = LayoutVertical;
RegisterNewVarCallback(&Panel::AddVariable,(void*)this,auto_register_var_prefix);
ProcessHistoricCallbacks(&Panel::AddVariable,(void*)this,auto_register_var_prefix);
}
void Panel::AddVariable(void* data, const std::string& name, VarValueGeneric& var, bool /*brand_new*/)
{
Panel* thisptr = (Panel*)data;
const string& title = var.Meta().friendly;
display_mutex.lock();
ViewMap::iterator pnl = context->named_managed_views.find(name);
// Only add if a widget by the same name doesn't
// already exist
if( pnl == context->named_managed_views.end() )
{
View* nv = NULL;
if( !strcmp(var.TypeId(), typeid(bool).name()) ) {
nv = (var.Meta().flags & META_FLAG_TOGGLE) ? (View*)new Checkbox(title,var) : (View*)new Button(title,var);
} else if (!strcmp(var.TypeId(), typeid(double).name()) ||
!strcmp(var.TypeId(), typeid(float).name()) ||
!strcmp(var.TypeId(), typeid(int).name()) ||
!strcmp(var.TypeId(), typeid(unsigned int).name()))
{
nv = new Slider(title, var);
} else if (!strcmp(var.TypeId(), typeid(std::function<void(void)>).name() ) ) {
nv = (View*)new FunctionButton(title, var);
}else{
nv = new TextInput(title,var);
}
if(nv) {
context->named_managed_views[name] = nv;
thisptr->views.push_back( nv );
thisptr->ResizeChildren();
}
}
display_mutex.unlock();
}
void Panel::Render()
{
#ifndef HAVE_GLES
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT | GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
#endif
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DisplayBase().ActivatePixelOrthographic();
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_LINE_SMOOTH);
glDisable( GL_COLOR_MATERIAL );
glLineWidth(1.0);
glColor4fv(colour_bg);
glRect(v);
DrawShadowRect(v);
RenderChildren();
#ifndef HAVE_GLES
glPopAttrib();
#else
glEnable(GL_LINE_SMOOTH);
glEnable(GL_DEPTH_TEST);
#endif
}
void Panel::ResizeChildren()
{
View::ResizeChildren();
}
View& CreatePanel(const std::string& name)
{
if(context->named_managed_views.find(name) != context->named_managed_views.end()) {
throw std::runtime_error("Panel already registered with this name.");
}
Panel * p = new Panel(name);
context->named_managed_views[name] = p;
context->base.views.push_back(p);
return *p;
}
Button::Button(string title, VarValueGeneric& tv)
: Widget<bool>(title,tv), down(false)
{
top = 1.0; bottom = Attach::Pix(-tab_h());
left = 0.0; right = 1.0;
hlock = LockLeft;
vlock = LockBottom;
gltext = font().Text(title);
}
void Button::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
{
if(button == MouseButtonLeft )
{
down = pressed;
if( !pressed ) {
var->Set(!var->Get());
GuiVarChanged(*this);
}
}
}
void Button::Render()
{
glColor4fv(colour_fg );
glRect(v);
glColor4fv(colour_tx);
gltext.DrawWindow(raster[0],raster[1]-down);
DrawShadowRect(v, down);
}
void Button::ResizeChildren()
{
raster[0] = floor(v.l + (v.w-gltext.Width())/2.0f);
raster[1] = floor(v.b + (v.h-gltext.Height())/2.0f);
}
FunctionButton::FunctionButton(string title, VarValueGeneric& tv)
: Widget<std::function<void(void)> >(title, tv), down(false)
{
top = 1.0; bottom = Attach::Pix(-tab_h());
left = 0.0; right = 1.0;
hlock = LockLeft;
vlock = LockBottom;
gltext = font().Text(title);
}
void FunctionButton::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
{
if (button == MouseButtonLeft)
{
down = pressed;
if (!pressed) {
var->Get()();
GuiVarChanged(*this);
}
}
}
void FunctionButton::Render()
{
glColor4fv(colour_fg);
glRect(v);
glColor4fv(colour_tx);
gltext.DrawWindow(raster[0],raster[1]-down);
DrawShadowRect(v, down);
}
void FunctionButton::ResizeChildren()
{
raster[0] = v.l + (v.w - gltext.Width()) / 2.0f;
raster[1] = v.b + (v.h - gltext.Height()) / 2.0f;
}
Checkbox::Checkbox(std::string title, VarValueGeneric& tv)
: Widget<bool>(title,tv)
{
top = 1.0; bottom = Attach::Pix(-tab_h());
left = 0.0; right = 1.0;
hlock = LockLeft;
vlock = LockBottom;
handler = this;
gltext = font().Text(title);
}
void Checkbox::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
{
if( button == MouseButtonLeft && pressed ) {
var->Set(!var->Get());
GuiVarChanged(*this);
}
}
void Checkbox::ResizeChildren()
{
raster[0] = v.l + cb_height() + 4.0f;
raster[1] = v.b + (v.h-gltext.Height())/2.0f;
const int h = v.h;
const int t = (int)((h-cb_height()) / 2.0f);
vcb = Viewport(v.l,v.b+t,cb_height(),cb_height());
}
void Checkbox::Render()
{
const bool val = var->Get();
if( val )
{
glColor4fv(colour_dn);
glRect(vcb);
}
glColor4fv(colour_tx);
gltext.DrawWindow(raster[0],raster[1]);
DrawShadowRect(vcb, val);
}
inline bool IsIntegral(const char* typeidname)
{
// TODO: There must be a better way of doing this...
return !strcmp(typeidname, typeid(char).name()) ||
!strcmp(typeidname, typeid(short).name()) ||
!strcmp(typeidname, typeid(int).name()) ||
!strcmp(typeidname, typeid(long).name()) ||
!strcmp(typeidname, typeid(unsigned char).name()) ||
!strcmp(typeidname, typeid(unsigned short).name()) ||
!strcmp(typeidname, typeid(unsigned int).name()) ||
!strcmp(typeidname, typeid(unsigned long).name());
}
Slider::Slider(std::string title, VarValueGeneric& tv)
: Widget<double>(title+":", tv), lock_bounds(true)
{
top = 1.0; bottom = Attach::Pix(-tab_h());
left = 0.0; right = 1.0;
hlock = LockLeft;
vlock = LockBottom;
handler = this;
logscale = (int)tv.Meta().logscale;
gltext = font().Text(title);
is_integral_type = IsIntegral(tv.TypeId());
}
void Slider::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
{
if( pressed && var->Meta().range[0] < var->Meta().range[1] )
{
double val = !logscale ? var->Get() : log(var->Get());
if(key=='-' || key=='_' || key=='=' || key=='+') {
double inc = var->Meta().increment;
if (key == '-') inc *= -1.0;
if (key == '_') inc *= -0.1;
if (key == '+') inc *= 0.1;
const double newval = max(var->Meta().range[0], min(var->Meta().range[1], val + inc));
var->Set( logscale ? exp(newval) : newval );
}else if(key == 'r'){
Reset();
}else{
return;
}
GuiVarChanged(*this);
}
}
void Slider::Mouse(View& view, MouseButton button, int x, int y, bool pressed, int mouse_state)
{
if(pressed)
{
// Wheel
if( button == MouseWheelUp || button == MouseWheelDown )
{
// Change scale around current value
const double frac = max(0.0,min(1.0,(double)(x - v.l)/(double)v.w));
double val = frac * (var->Meta().range[1] - var->Meta().range[0]) + var->Meta().range[0];
if (logscale)
{
if (val<=0)
val = std::numeric_limits<double>::min();
else
val = log(val);
}
const double scale = (button == MouseWheelUp ? 1.2 : 1.0 / 1.2 );
var->Meta().range[1] = val + (var->Meta().range[1] - val)*scale;
var->Meta().range[0] = val - (val - var->Meta().range[0])*scale;
}else{
lock_bounds = (button == MouseButtonLeft);
MouseMotion(view,x,y,mouse_state);
}
}else{
if(!lock_bounds)
{
double val = !logscale ? var->Get() : log(var->Get());
var->Meta().range[0] = min(var->Meta().range[0], val);
var->Meta().range[1] = max(var->Meta().range[1], val);
}
}
}
void Slider::MouseMotion(View&, int x, int /*y*/, int /*mouse_state*/)
{
if( var->Meta().range[0] != var->Meta().range[1] )
{
const double range = (var->Meta().range[1] - var->Meta().range[0]);
const double frac = (double)(x - v.l)/(double)v.w;
double val;
if( lock_bounds )
{
const double bfrac = max(0.0,min(1.0,frac));
val = bfrac * range + var->Meta().range[0] ;
}else{
val = frac * range + var->Meta().range[0];
}
if (logscale) {
val = exp(val);
}
if( is_integral_type ) {
val = std::round(val);
}
var->Set(val);
GuiVarChanged(*this);
}
}
void Slider::ResizeChildren()
{
raster[0] = v.l + 2.0f;
raster[1] = v.b + (v.h-gltext.Height())/2.0f;
}
void Slider::Render()
{
const double val = var->Get();
if( var->Meta().range[0] != var->Meta().range[1] )
{
double rval = val;
if (logscale)
{
rval = log(val);
}
glColor4fv(colour_fg);
glRect(v);
glColor4fv(colour_dn);
const double norm_val = max(0.0,min(1.0,(rval - var->Meta().range[0]) / (var->Meta().range[1] - var->Meta().range[0])));
glRect(Viewport(v.l,v.b, (int)(v.w*norm_val),v.h));
DrawShadowRect(v);
}
glColor4fv(colour_tx);
if(gltext.Text() != var->Meta().friendly) {
gltext = font().Text(var->Meta().friendly);
}
gltext.DrawWindow(raster[0], raster[1]);
std::ostringstream oss;
oss << setprecision(4) << val;
string str = oss.str();
GlText glval = font().Text(str);
const float l = glval.Width() + 2.0f;
glval.DrawWindow( v.l + v.w - l, raster[1] );
}
TextInput::TextInput(std::string title, VarValueGeneric& tv)
: Widget<std::string>(title+":", tv), can_edit(!(tv.Meta().flags & META_FLAG_READONLY)), do_edit(false)
{
top = 1.0; bottom = Attach::Pix(-tab_h());
left = 0.0; right = 1.0;
hlock = LockLeft;
vlock = LockBottom;
handler = this;
sel[0] = -1;
sel[1] = -1;
gltext = font().Text(title);
}
void TextInput::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
{
if(can_edit && pressed && do_edit)
{
const bool selection = sel[1] > sel[0] && sel[0] >= 0;
if(key == 13)
{
var->Set(edit);
GuiVarChanged(*this);
do_edit = false;
sel[0] = sel[1] = -1;
}else if(key == 8) {
// backspace
if(selection)
{
edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
sel[1] = sel[0];
}else{
if(sel[0] >0)
{
edit = edit.substr(0,sel[0]-1) + edit.substr(sel[0],edit.length()-sel[0]);
sel[0]--;
sel[1]--;
}
}
}else if(key == 127){
// delete
if(selection)
{
edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
sel[1] = sel[0];
}else{
if(sel[0] < (int)edit.length())
{
edit = edit.substr(0,sel[0]) + edit.substr(sel[0]+1,edit.length()-sel[0]+1);
}
}
}else if(key == 230){
// right
sel[0] = min((int)edit.length(),sel[0]+1);
sel[1] = sel[0];
}else if(key == 228){
// left
sel[0] = max(0,sel[0]-1);
sel[1] = sel[0];
}else if(key == 234){
// home
sel[0] = sel[1] = 0;
}else if(key == 235){
// end
sel[0] = sel[1] = (int)edit.length();
}else if(key < PANGO_SPECIAL){
edit = edit.substr(0,sel[0]).append(1,key) + edit.substr(sel[1],edit.length()-sel[1]);
sel[1] = sel[0];
sel[0]++;
sel[1]++;
}
}
}
void TextInput::Mouse(View& /*view*/, MouseButton button, int x, int /*y*/, bool pressed, int /*mouse_state*/)
{
if(can_edit && button != MouseWheelUp && button != MouseWheelDown )
{
if(do_edit)
{
const int sl = (int)gledit.Width() + 2;
const int rl = v.l + v.w - sl;
int ep = (int)edit.length();
if( x < rl )
{
ep = 0;
}else{
for( unsigned i=0; i<edit.length(); ++i )
{
const int tl = (int)(rl + font().Text(edit.substr(0,i)).Width());
if(x < tl+2)
{
ep = i;
break;
}
}
}
if(pressed)
{
sel[0] = sel[1] = ep;
}else{
sel[1] = ep;
}
if(sel[0] > sel[1])
std::swap(sel[0],sel[1]);
}else{
do_edit = !pressed;
sel[0] = 0;
sel[1] = (int)edit.length();
}
}
}
void TextInput::MouseMotion(View&, int x, int /*y*/, int /*mouse_state*/)
{
if(can_edit && do_edit)
{
const int sl = (int)gledit.Width() + 2;
const int rl = v.l + v.w - sl;
int ep = (int)edit.length();
if( x < rl )
{
ep = 0;
}else{
for( unsigned i=0; i<edit.length(); ++i )
{
const int tl = (int)(rl + font().Text(edit.substr(0,i)).Width());
if(x < tl+2)
{
ep = i;
break;
}
}
}
sel[1] = ep;
}
}
void TextInput::ResizeChildren()
{
raster[0] = v.l + 2.0f;
raster[1] = v.b + (v.h-gltext.Height()) / 2.0f;
}
void TextInput::Render()
{
if(!do_edit) edit = var->Get();
gledit = font().Text(edit);
glColor4fv(colour_fg);
if(can_edit) glRect(v);
const int sl = (int)gledit.Width() + 2;
const int rl = v.l + v.w - sl;
if( do_edit && sel[0] >= 0)
{
const int tl = (int)(rl + font().Text(edit.substr(0,sel[0])).Width());
const int tr = (int)(rl + font().Text(edit.substr(0,sel[1])).Width());
glColor4fv(colour_dn);
glRect(Viewport(tl,v.b,tr-tl,v.h));
}
glColor4fv(colour_tx);
gltext.DrawWindow(raster[0], raster[1]);
gledit.DrawWindow((GLfloat)(rl), raster[1]);
if(can_edit) DrawShadowRect(v);
}
}

View File

@@ -0,0 +1,42 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 2011-2017 Steven Lovegrove, Andrey Mnatsakanov
*
* 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 <pangolin/display/window.h>
#include <pangolin/factory/factory_registry.h>
namespace pangolin
{
template<>
FactoryRegistry<WindowInterface>& FactoryRegistry<WindowInterface>::I()
{
// Singleton instance
static FactoryRegistry instance;
return instance;
}
}

View File

@@ -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.
*/
#include <pangolin/geometry/geometry.h>
#include <pangolin/geometry/geometry_ply.h>
#include <pangolin/geometry/geometry_obj.h>
#include <pangolin/utils/file_extension.h>
#include <pangolin/utils/file_utils.h>
// TODO: Should really get rid of this from API
#include <pangolin/gl/gl.h>
namespace pangolin {
// TODO: Replace this with proper factory registry
pangolin::Geometry LoadGeometry(const std::string& filename)
{
const std::string expanded_filename = PathExpand(filename);
const ImageFileType ft = FileType(expanded_filename);
if(ft == ImageFileTypePly) {
return LoadGeometryPly(expanded_filename);
}else if(ft == ImageFileTypeObj) {
return LoadGeometryObj(expanded_filename);
}else{
throw std::runtime_error("Unsupported geometry file type.");
}
}
pangolin::Geometry::Element::Attribute MakeAttribute(GLenum datatype, size_t num_items, size_t count_per_item, void* ptr, size_t pitch_bytes)
{
switch(datatype) {
case GL_FLOAT:
return Image<float> ( (float*)ptr, count_per_item, num_items, pitch_bytes);
case GL_INT:
case GL_UNSIGNED_INT:
return Image<uint32_t>( (uint32_t*)ptr, count_per_item, num_items, pitch_bytes);
case GL_SHORT:
case GL_UNSIGNED_SHORT:
return Image<uint16_t>( (uint16_t*)ptr, count_per_item, num_items, pitch_bytes);
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return Image<uint8_t> ( (uint8_t*)ptr, count_per_item, num_items, pitch_bytes);
default:
throw std::runtime_error("Unsupported type");
};
}
}

View File

@@ -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.
*/
#include <unordered_set>
#include <pangolin/geometry/geometry_obj.h>
#include <tinyobj/tiny_obj_loader.h>
#include <pangolin/utils/variadic_all.h>
#include <pangolin/utils/simple_math.h>
// Needed for enum type. TODO: Make this independent of GL
#include <pangolin/gl/glplatform.h>
#include <pangolin/image/image_io.h>
#include <pangolin/utils/file_utils.h>
namespace std {
template<>
struct hash<tinyobj::index_t> {
std::size_t operator()(const tinyobj::index_t & t) const noexcept {
static std::hash<int> h;
return h(t.vertex_index) ^ h(t.normal_index) ^ h(t.texcoord_index);
}
};
} // namespace std
namespace tinyobj {
bool operator==(const index_t a, const index_t b) {
return a.vertex_index == b.vertex_index && a.normal_index == b.normal_index && a.texcoord_index == b.texcoord_index;
}
} // namespace tinyobj
namespace pangolin {
template<typename T>
Geometry::Element ConvertVectorToGeometryElement(const std::vector<T>& v, size_t count_per_element, const std::string& attribute_name )
{
PANGO_ASSERT(v.size() % count_per_element == 0);
const size_t num_elements = v.size() / count_per_element;
// Allocate buffer and copy into it
Geometry::Element el(sizeof(T) * count_per_element, num_elements);
el.CopyFrom(Image<T>(v.data(), count_per_element, num_elements));
el.attributes[attribute_name] = el.template UnsafeReinterpret<T>();
return el;
}
template<typename T>
Image<T> GetImageWrapper(std::vector<T>& vec, size_t count_per_element)
{
PANGO_ASSERT(vec.size() % count_per_element == 0);
if(vec.size()) {
return Image<T>(vec.data(), count_per_element, vec.size() / count_per_element, count_per_element * sizeof(T));
}else{
return Image<T>();
}
}
pangolin::Geometry LoadGeometryObj(const std::string& filename)
{
pangolin::Geometry geom;
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn;
std::string err;
if(tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename.c_str(), PathParent(filename).c_str())) {
PANGO_ASSERT(attrib.vertices.size() % 3 == 0);
PANGO_ASSERT(attrib.normals.size() % 3 == 0);
PANGO_ASSERT(attrib.colors.size() % 3 == 0);
PANGO_ASSERT(attrib.texcoords.size() % 2 == 0);
// Load textures - a bit of a hack for now.
for(size_t i=0; i < materials.size(); ++i) {
if(!materials[i].diffuse_texname.empty()) {
const std::string tex_name = FormatString("texture_%",i);
try {
TypedImage& tex_image = geom.textures[tex_name];
tex_image = LoadImage(PathParent(filename) + "/" + materials[i].diffuse_texname);
const int row_bytes = tex_image.w * tex_image.fmt.bpp / 8;
std::vector<unsigned char> tmp_row(row_bytes);
for (std::size_t y=0; y < (tex_image.h >> 1); ++y) {
std::memcpy(tmp_row.data(), tex_image.RowPtr(y), row_bytes);
std::memcpy(tex_image.RowPtr(y), tex_image.RowPtr(tex_image.h - 1 - y), row_bytes);
std::memcpy(tex_image.RowPtr(tex_image.h - 1 - y), tmp_row.data(), row_bytes);
}
} catch(const std::exception& e) {
pango_print_warn("Unable to read texture '%s'\n", tex_name.c_str());
geom.textures.erase(tex_name);
}
}
}
// PANGO_ASSERT(all_of(
// [&](const size_t& v){return (v == 0) || (v == num_verts);},
// attrib.normals.size() / 3,
// attrib.colors.size() / 3));
// Get rid of color buffer if all elements are equal.
if ( std::adjacent_find( attrib.colors.begin(), attrib.colors.end(), std::not_equal_to<float>() ) == attrib.colors.end() )
{
attrib.colors.clear();
}
Image<float> tiny_vs = GetImageWrapper(attrib.vertices, 3);
Image<float> tiny_ns = GetImageWrapper(attrib.normals, 3);
Image<float> tiny_cs = GetImageWrapper(attrib.colors, 3);
Image<float> tiny_ts = GetImageWrapper(attrib.texcoords, 2);
// Some vertices are used with multiple texture coordinates or multiple normals, and will need to be split.
// First, we'll find the number of unique combinations of vertex, texture, and normal indices used, as each
// will result in a separate vertex in the buffers
std::unordered_map<tinyobj::index_t, std::size_t> reindex_map;
for(auto& shape : shapes) {
if(shape.mesh.indices.size() == 0) {
continue;
}
const size_t num_indices = shape.mesh.indices.size() ;
for(size_t i=0; i < num_indices; ++i) {
const tinyobj::index_t index = shape.mesh.indices[i];
if (reindex_map.find(index) == reindex_map.end()) {
reindex_map.insert(std::pair<tinyobj::index_t, std::size_t>(index, reindex_map.size()));
}
}
}
const int num_unique_verts = reindex_map.size();
// Create unified verts attribute
auto& verts = geom.buffers["geometry"];
Image<float> new_vs, new_ns, new_cs, new_ts;
{
verts.Reinitialise(sizeof(float)*(tiny_vs.w + tiny_ns.w + tiny_cs.w + tiny_ts.w),num_unique_verts);
size_t float_offset = 0;
if(tiny_vs.IsValid()) {
new_vs = verts.UnsafeReinterpret<float>().SubImage(float_offset,0,3,num_unique_verts);
verts.attributes["vertex"] = new_vs;
float_offset += 3;
for (auto& el : reindex_map) {
new_vs.Row(el.second).CopyFrom(tiny_vs.Row(el.first.vertex_index));
}
}
if(tiny_ns.IsValid()) {
new_ns = verts.UnsafeReinterpret<float>().SubImage(float_offset,0,3,num_unique_verts);
verts.attributes["normal"] = new_ns;
float_offset += 3;
for (auto& el : reindex_map) {
new_ns.Row(el.second).CopyFrom(tiny_ns.Row(el.first.normal_index));
}
}
if(tiny_cs.IsValid()) {
new_cs = verts.UnsafeReinterpret<float>().SubImage(float_offset,0,3,num_unique_verts);
verts.attributes["color"] = new_cs;
float_offset += 3;
for (auto& el : reindex_map) {
new_cs.Row(el.second).CopyFrom(tiny_cs.Row(el.first.vertex_index));
}
}
if(tiny_ts.IsValid()) {
new_ts = verts.UnsafeReinterpret<float>().SubImage(float_offset,0,2,num_unique_verts);
verts.attributes["uv"] = new_ts;
float_offset += 2;
for (auto& el : reindex_map) {
new_ts.Row(el.second).CopyFrom(tiny_ts.Row(el.first.texcoord_index));
}
}
PANGO_ASSERT(float_offset * sizeof(float) == verts.w);
}
for(auto& shape : shapes) {
if(shape.mesh.indices.size() == 0) {
continue;
}
auto faces = geom.objects.emplace(shape.name, Geometry::Element());
if(std::all_of( shape.mesh.num_face_vertices.begin(), shape.mesh.num_face_vertices.end(),
[](unsigned char num){return num==3;}
)) {
// tri mesh
const size_t num_indices = shape.mesh.indices.size() ;
const size_t num_faces = shape.mesh.indices.size() / 3;
PANGO_ASSERT(num_indices % 3 == 0);
// Use vert_ibo as our new IBO
faces->second.Reinitialise(3*sizeof(uint32_t), num_faces);
Image<uint32_t> new_ibo = faces->second.UnsafeReinterpret<uint32_t>().SubImage(0,0,3,num_faces);
for(size_t f=0; f < num_faces; ++f) {
for(size_t v=0; v < 3; ++v) {
new_ibo(v,f) = reindex_map[shape.mesh.indices[3 * f + v]];
}
}
faces->second.attributes["vertex_indices"] = new_ibo;
}else if(std::all_of( shape.mesh.num_face_vertices.begin(), shape.mesh.num_face_vertices.end(),
[](unsigned char num){return num==4;}
)) {
// Quad mesh
throw std::runtime_error("Do not support quad meshes yet.");
}else{
// ???
throw std::runtime_error("Do not support meshes with mixed triangles and quads.");
}
}
}else{
throw std::runtime_error(FormatString("Unable to load OBJ file '%'. Error: '%'", filename, err));
}
return geom;
}
}

View File

@@ -0,0 +1,483 @@
/* 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 <pangolin/geometry/geometry_ply.h>
#include <pangolin/utils/file_utils.h>
#include <pangolin/utils/variadic_all.h>
#include <pangolin/utils/parse.h>
#include <pangolin/utils/type_convert.h>
#include <pangolin/utils/simple_math.h>
// TODO: Should really remove need for GL here.
#include <pangolin/gl/gl.h>
namespace pangolin {
#define FORMAT_STRING_LIST(x) #x,
const char* PlyHeaderString[] = {
PLY_HEADER_LIST(FORMAT_STRING_LIST)
};
const char* PlyFormatString[] = {
PLY_FORMAT_LIST(FORMAT_STRING_LIST)
};
const char* PlyTypeString[] = {
PLY_TYPE_LIST(FORMAT_STRING_LIST)
};
#undef FORMAT_STRING_LIST
PLY_GROUP_LIST(PANGOLIN_DEFINE_PARSE_TOKEN)
void ParsePlyHeader(PlyHeaderDetails& ply, std::istream& is)
{
// 'Active' element for property definitions.
int current_element = -1;
// Check header is correct
PlyHeader token = ParseTokenPlyHeader(is);
if( token != PlyHeader_ply) {
throw std::runtime_error("Bad PLY header magic.");
}
ConsumeToNewline(is);
while(is.good() && token != PlyHeader_end_header) {
token = ParseTokenPlyHeader(is);
switch (token) {
case PlyHeader_format:
// parse PLY format and version
ConsumeWhitespace(is);
ply.format = ParseTokenPlyFormat(is);
ConsumeWhitespace(is);
ply.version = ReadToken(is);
break;
case PlyHeader_element:
{
current_element = ply.elements.size();
PlyElementDetails el;
el.stride_bytes = 0;
ConsumeWhitespace(is);
el.name = ReadToken(is);
ConsumeWhitespace(is);
el.num_items = FromString<int>(ReadToken(is));
ply.elements.push_back(el);
break;
}
case PlyHeader_property:
if(current_element >= 0) {
PlyElementDetails& el = ply.elements[current_element];
PlyPropertyDetails prop;
ConsumeWhitespace(is);
const PlyType t = ParseTokenPlyType(is);
if( t == PlyType_list) {
ConsumeWhitespace(is);
const PlyType idtype = ParseTokenPlyType(is);
ConsumeWhitespace(is);
const PlyType itemtype = ParseTokenPlyType(is);
prop.list_index_type = PlyTypeGl[idtype];
prop.type = PlyTypeGl[itemtype];
prop.offset_bytes = el.stride_bytes;
prop.num_items = -1;
el.stride_bytes = -1;
}else{
prop.type = PlyTypeGl[t];
prop.list_index_type = GL_NONE;
prop.offset_bytes = el.stride_bytes;
prop.num_items = 1;
const size_t size_bytes = GlDataTypeBytes(prop.type);
if( el.stride_bytes >= 0) {
el.stride_bytes += size_bytes;
}
}
ConsumeWhitespace(is);
prop.name = ReadToken(is);
el.properties.push_back(prop);
}else{
pango_print_warn("PLY Parser: property declaration before element. Ignoring line.");
}
break;
case PlyHeader_comment:
case PlyHeader_end_header:
break;
default:
pango_print_warn("PLY Parser: Unknown token - ignoring line.");
}
ConsumeToNewline(is);
}
}
void ParsePlyAscii(pangolin::Geometry& /*geom*/, const PlyHeaderDetails& /*ply*/, std::istream& /*is*/)
{
throw std::runtime_error("Not implemented.");
}
void AddVertexNormals(pangolin::Geometry& geom)
{
auto it_geom = geom.buffers.find("geometry");
auto it_face = geom.objects.find("default");
if(it_geom != geom.buffers.end() && it_face != geom.objects.end())
{
const auto it_vbo = it_geom->second.attributes.find("vertex");
const auto it_ibo = it_face->second.attributes.find("vertex_indices");
if(it_vbo != it_geom->second.attributes.end() && it_ibo != it_face->second.attributes.end()) {
const auto& ibo = get<Image<uint32_t>>(it_ibo->second);
const auto& vbo = get<Image<float>>(it_vbo->second);
// Assume we have triangles.
PANGO_ASSERT(ibo.w == 3 && vbo.w == 3);
ManagedImage<float> vert_normals(3, vbo.h);
ManagedImage<size_t> vert_face_count(1, vbo.h);
vert_normals.Fill(0.0f);
vert_face_count.Fill(0);
float ab[3];
float ac[3];
float fn[3];
for(size_t i=0; i < ibo.h; ++i) {
uint32_t i0 = ibo(0,i);
uint32_t i1 = ibo(1,i);
uint32_t i2 = ibo(2,i);
MatSub<3,1>(ab, vbo.RowPtr(i1), vbo.RowPtr(i0));
MatSub<3,1>(ac, vbo.RowPtr(i2), vbo.RowPtr(i0));
VecCross3(fn, ab, ac);
Normalise<3>(fn);
for(size_t v=0; v < 3; ++v) {
MatAdd<3,1>(vert_normals.RowPtr(ibo(v,i)), vert_normals.RowPtr(ibo(v,i)), fn);
++vert_face_count(0,ibo(v,i));
}
}
for(size_t v=0; v < vert_normals.h; ++v) {
// Compute average
MatMul<3,1>(vert_normals.RowPtr(v), 1.0f / vert_face_count(0,v));
}
auto& el = geom.buffers["normal"];
(ManagedImage<float>&)el = std::move(vert_normals);
auto& attr_norm = el.attributes["normal"];
attr_norm = MakeAttribute(GL_FLOAT, el.h, 3, el.ptr, el.pitch);
}
}
}
void StandardizeXyzToVertex(pangolin::Geometry& geom)
{
auto it_verts = geom.buffers.find("geometry");
if(it_verts != geom.buffers.end()) {
auto& verts = it_verts->second;
auto it_x = verts.attributes.find("x");
auto it_y = verts.attributes.find("y");
auto it_z = verts.attributes.find("z");
if(all_found(verts.attributes, it_x, it_y, it_z)) {
if(verts.attributes.find("vertex") == verts.attributes.end()) {
auto& vertex = verts.attributes["vertex"];
auto& imx = get<Image<float>>(it_x->second);
auto& imy = get<Image<float>>(it_y->second);
auto& imz = get<Image<float>>(it_z->second);
if(imx.ptr + 1 == imy.ptr && imy.ptr + 1 == imz.ptr) {
vertex = MakeAttribute(GL_FLOAT, verts.h, 3, imx.ptr, imx.pitch);
}else{
throw std::runtime_error("Ooops");
}
}
verts.attributes.erase(it_x);
verts.attributes.erase(it_y);
verts.attributes.erase(it_z);
}
}
}
void StandardizeRgbToColor(pangolin::Geometry& geom)
{
auto it_verts = geom.buffers.find("geometry");
if(it_verts != geom.buffers.end()) {
auto& verts = it_verts->second;
auto it_r = verts.attributes.find("r");
auto it_g = verts.attributes.find("g");
auto it_b = verts.attributes.find("b");
auto it_a = verts.attributes.find("a");
if(!all_found(verts.attributes, it_r, it_b, it_g)) {
it_r = verts.attributes.find("red");
it_g = verts.attributes.find("green");
it_b = verts.attributes.find("blue");
it_a = verts.attributes.find("alpha");
}
if(all_found(verts.attributes, it_r, it_g, it_b)) {
const bool have_alpha = it_a != verts.attributes.end();
if(verts.attributes.find("color") == verts.attributes.end()) {
Geometry::Element::Attribute& red = it_r->second;
Geometry::Element::Attribute& color = verts.attributes["color"];
// TODO: Check that these really are contiguous in memory...
if(auto attrib = get_if<Image<float>>(&red)) {
color = Image<float>(attrib->ptr, have_alpha ? 4 : 3, verts.h, verts.pitch);
}else if(auto attrib = get_if<Image<uint8_t>>(&red)) {
color = Image<uint8_t>(attrib->ptr, have_alpha ? 4 : 3, verts.h, verts.pitch);
}else if(auto attrib = get_if<Image<uint16_t>>(&red)) {
color = Image<uint16_t>(attrib->ptr, have_alpha ? 4 : 3, verts.h, verts.pitch);
}else if(auto attrib = get_if<Image<uint32_t>>(&red)) {
color = Image<uint32_t>(attrib->ptr, have_alpha ? 4 : 3, verts.h, verts.pitch);
}
}
verts.attributes.erase(it_r);
verts.attributes.erase(it_g);
verts.attributes.erase(it_b);
if(have_alpha) verts.attributes.erase(it_a);
}
}
}
void StandardizeMultiTextureFaceToXyzuv(pangolin::Geometry& geom)
{
const auto it_multi_texture_face = geom.buffers.find("multi_texture_face");
const auto it_multi_texture_vertex = geom.buffers.find("multi_texture_vertex");
const auto it_geom = geom.buffers.find("geometry");
const auto it_face = geom.objects.find("default");
if(it_geom != geom.buffers.end() && it_face != geom.objects.end())
{
const auto it_vbo = it_geom->second.attributes.find("vertex");
const auto it_ibo = it_face->second.attributes.find("vertex_indices");
if(all_found(geom.buffers, it_multi_texture_face, it_multi_texture_vertex) &&
it_vbo != it_geom->second.attributes.end() &&
it_ibo != it_face->second.attributes.end()
) {
const auto it_uv_ibo = it_multi_texture_face->second.attributes.find("texture_vertex_indices");
const auto it_tx = it_multi_texture_face->second.attributes.find("tx");
const auto it_tn = it_multi_texture_face->second.attributes.find("tn");
const auto it_u = it_multi_texture_vertex->second.attributes.find("u");
const auto it_v = it_multi_texture_vertex->second.attributes.find("v");
if(all_found(it_multi_texture_vertex->second.attributes, it_u, it_v) &&
it_uv_ibo != it_multi_texture_face->second.attributes.end()
) {
// We're going to create a new vertex buffer to hold uv's too
auto& orig_ibo = get<Image<uint32_t>>(it_ibo->second);
const auto& orig_xyz = get<Image<float>>(it_vbo->second);
const auto& uv_ibo = get<Image<uint32_t>>(it_uv_ibo->second);
const auto& u = get<Image<float>>(it_u->second);
const auto& v = get<Image<float>>(it_v->second);
const auto& tx = get<Image<uint8_t>>(it_tx->second);
const auto& tn = get<Image<uint32_t>>(it_tn->second);
PANGO_ASSERT(u.h == v.h);
PANGO_ASSERT(orig_ibo.w == 3 && uv_ibo.w == 3);
pangolin::Geometry::Element new_xyzuv(5*sizeof(float), u.h);
Image<float> new_xyz = new_xyzuv.UnsafeReinterpret<float>().SubImage(0,0,3,new_xyzuv.h);
Image<float> new_uv = new_xyzuv.UnsafeReinterpret<float>().SubImage(3,0,2,new_xyzuv.h);
new_xyzuv.attributes["vertex"] = new_xyz;
new_xyzuv.attributes["uv"] = new_uv;
for(size_t face=0; face < orig_ibo.h; ++face) {
uint32_t vtn = tn(0,face);
uint8_t vtx = tx(0,face);
PANGO_ASSERT(vtx==0, "Haven't implemented multi-texture yet.");
for(size_t vert=0; vert < 3; ++vert)
{
uint32_t& orig_xyz_index = orig_ibo(vert,vtn);
const uint32_t uv_index = uv_ibo(vert,face);
PANGO_ASSERT(uv_index < new_xyzuv.h && orig_xyz_index < orig_xyz.h);
for(int el=0; el < 3; ++el) {
new_xyz(el,uv_index) = orig_xyz(el,orig_xyz_index);
}
new_uv(0,uv_index) = u(0,uv_index);
new_uv(1,uv_index) = v(0,uv_index);
orig_xyz_index = uv_index;
}
}
geom.buffers["geometry"] = std::move(new_xyzuv);
geom.buffers.erase(it_multi_texture_face);
geom.buffers.erase(it_multi_texture_vertex);
}
}
}
}
void Standardize(pangolin::Geometry& geom)
{
StandardizeXyzToVertex(geom);
StandardizeRgbToColor(geom);
StandardizeMultiTextureFaceToXyzuv(geom);
AddVertexNormals(geom);
}
inline int ReadGlIntType(GLenum type, std::istream& is)
{
// TODO: This seems really dodgey...
// int may not be big enough and if the datatype is smaller will it be padded?
int v = 0;
is.read( (char*)&v, GlDataTypeBytes(type));
return v;
}
inline void ReadInto(std::vector<unsigned char>& vec, std::istream& is, size_t num_bytes)
{
const size_t current_size = vec.size();
vec.resize(current_size + num_bytes);
is.read((char*)vec.data() + current_size, num_bytes);
}
void ParsePlyLE(pangolin::Geometry& geom, PlyHeaderDetails& ply, std::istream& is)
{
std::vector<uint8_t> buffer;
for(auto& el : ply.elements) {
pangolin::Geometry::Element geom_el;
if(el.stride_bytes > 0) {
// This will usually be the case for vertex buffers with a known number of attributes
PANGO_ASSERT(el.num_items > 0);
geom_el.Reinitialise(el.stride_bytes, el.num_items);
is.read((char*)geom_el.ptr, geom_el.Area());
}else {
// This will generally be the case for face data (containing a list of vertex indices)
// Reserve enough space for a list of quads
buffer.clear();
buffer.reserve(el.num_items * el.properties.size() * 4);
for(int i=0; i< el.num_items; ++i) {
size_t offset_bytes = 0;
for(auto& prop : el.properties) {
if(prop.isList()) {
const int list_items = ReadGlIntType(prop.list_index_type, is);
if(prop.num_items == -1) {
prop.num_items = list_items;
prop.offset_bytes = offset_bytes;
}else{
PANGO_ASSERT(prop.num_items == list_items);
}
}
const size_t num_bytes = prop.num_items * GlDataTypeBytes(prop.type);
ReadInto(buffer, is, num_bytes);
offset_bytes += num_bytes;
}
}
// Update element stride now we know
el.stride_bytes = 0;
for(auto& prop : el.properties) {
el.stride_bytes += prop.num_items * GlDataTypeBytes(prop.type);
}
geom_el.Reinitialise(el.stride_bytes, el.num_items);
PANGO_ASSERT(geom_el.SizeBytes() == buffer.size());
std::memcpy(geom_el.ptr, buffer.data(), buffer.size());
}
for(auto& prop : el.properties) {
geom_el.attributes[prop.name] = MakeAttribute(
prop.type, el.num_items, prop.num_items, geom_el.ptr + prop.offset_bytes, geom_el.pitch
);
}
if(el.name == "vertex") {
geom.buffers["geometry"] = std::move(geom_el);
}else if(el.name == "face") {
geom.objects.emplace("default", std::move(geom_el));
}else{
geom.buffers[el.name] = std::move(geom_el);
}
}
Standardize(geom);
}
void ParsePlyBE(pangolin::Geometry& /*geom*/, const PlyHeaderDetails& /*ply*/, std::istream& /*is*/)
{
throw std::runtime_error("Not implemented.");
}
void AttachAssociatedTexturesPly(pangolin::Geometry& geom, const std::string& filename)
{
// For PLY, texture names are generally implicit
auto dot = filename.find_last_of('.');
if(dot != filename.npos) {
const std::string base = filename.substr(0, dot);
for(int i=0; i < 10; ++i) {
const std::string glob = FormatString("%_%.*", base, i);
std::vector<std::string> file_vec;
if(FilesMatchingWildcard(glob, file_vec)) {
for(const auto& file : file_vec) {
try {
geom.textures[FormatString("texture_%",i)] = LoadImage(file);
break;
}catch(std::runtime_error&)
{
}
}
}
}
}
}
pangolin::Geometry LoadGeometryPly(const std::string& filename)
{
std::ifstream bFile( filename.c_str(), std::ios::in | std::ios::binary );
if( !bFile.is_open() ) throw std::runtime_error("Unable to open PLY file: " + filename);
PlyHeaderDetails ply;
ParsePlyHeader(ply, bFile);
// Initialise geom object
pangolin::Geometry geom;
// Fill in geometry from file.
if(ply.format == PlyFormat_ascii) {
ParsePlyAscii(geom, ply, bFile);
}else if(ply.format == PlyFormat_binary_little_endian) {
ParsePlyLE(geom, ply, bFile);
}else if(ply.format == PlyFormat_binary_big_endian) {
ParsePlyBE(geom, ply, bFile);
}
AttachAssociatedTexturesPly(geom, filename);
return geom;
}
}

View File

@@ -0,0 +1,142 @@
/* 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 <pangolin/geometry/glgeometry.h>
#include <pangolin/gl/glformattraits.h>
namespace pangolin {
GlGeometry::Element ToGlGeometryElement(const Geometry::Element& el, GlBufferType buffertype)
{
GlGeometry::Element glel(buffertype, el.SizeBytes(), GL_STATIC_DRAW, el.ptr );
for(const auto& attrib_variant : el.attributes) {
visit([&](auto&& attrib){
using T = std::decay_t<decltype(attrib)>;
auto& glattrib = glel.attributes[attrib_variant.first];
glattrib.gltype = GlFormatTraits<typename T::PixelType>::gltype;
glattrib.count_per_element = attrib.w;
glattrib.num_elements = attrib.h;
glattrib.offset = (uint8_t*)attrib.ptr - el.ptr;
glattrib.stride_bytes = attrib.pitch;
}, attrib_variant.second);
}
return glel;
}
GlGeometry ToGlGeometry(const Geometry& geom)
{
GlGeometry gl;
for(const auto& b : geom.buffers)
gl.buffers[b.first] = ToGlGeometryElement(b.second, GlArrayBuffer);
for(const auto& b : geom.objects)
gl.objects.emplace(b.first, ToGlGeometryElement(b.second, GlElementArrayBuffer));
for(const auto& tex : geom.textures) {
auto& gltex = gl.textures[tex.first];
gltex.Load(tex.second);
}
return gl;
}
void BindGlElement(GlSlProgram& prog, const GlGeometry::Element& el)
{
el.Bind();
for(auto& a : el.attributes) {
const GLint attrib_handle = prog.GetAttributeHandle(a.first);
const GlGeometry::Element::Attribute& attr = a.second;
if(attrib_handle >= 0) {
glEnableVertexAttribArray(attrib_handle);
glVertexAttribPointer(
attrib_handle, attr.count_per_element, attr.gltype, GL_TRUE,
attr.stride_bytes,
(uint8_t*)0 + attr.offset
);
}
}
}
void UnbindGlElements(GlSlProgram& prog, const GlGeometry::Element& el)
{
for(auto& a : el.attributes) {
const GLint attrib_handle = prog.GetAttributeHandle(a.first);
if(attrib_handle >= 0) {
glDisableVertexAttribArray(attrib_handle);
}
}
el.Unbind();
}
void GlDraw(GlSlProgram& prog, const GlGeometry& geom, const GlTexture* matcap)
{
// Bind textures
int num_tex_bound = 0;
for(auto& tex : geom.textures) {
glActiveTexture(GL_TEXTURE0 + num_tex_bound);
tex.second.Bind();
prog.SetUniform(tex.first, (int)num_tex_bound);
++num_tex_bound;
}
if(matcap) {
glActiveTexture(GL_TEXTURE0 + num_tex_bound);
matcap->Bind();
prog.SetUniform("matcap", (int)num_tex_bound);
++num_tex_bound;
}
// Bind all attribute buffers
for(auto& buffer : geom.buffers) {
BindGlElement(prog, buffer.second);
}
// Draw all geometry
for(auto& buffer : geom.objects) {
auto it_indices = buffer.second.attributes.find("vertex_indices");
if(it_indices != buffer.second.attributes.end()) {
buffer.second.Bind();
auto& attrib = it_indices->second;
glDrawElements(
GL_TRIANGLES, attrib.count_per_element * attrib.num_elements,
attrib.gltype, (uint8_t*)0 + attrib.offset
);
buffer.second.Unbind();
}
}
// Unbind attribute buffers
for(auto& buffer : geom.buffers) {
UnbindGlElements(prog, buffer.second);
}
// Unbind textures
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
}
}

View File

@@ -0,0 +1,29 @@
/* 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.
*/
#define TINYOBJLOADER_IMPLEMENTATION
#include <tinyobj/tiny_obj_loader.h>

View File

@@ -0,0 +1,39 @@
/* 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 <pangolin/gl/glinclude.h>
namespace pangolin
{
GlEngine& glEngine()
{
static GlEngine engine;
return engine;
}
}

70
thirdparty/Pangolin/src/gl/glchar.cpp vendored Normal file
View File

@@ -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.
*/
#include <pangolin/gl/glchar.h>
namespace pangolin
{
GlChar::GlChar()
: x_step(0.0f)
{
// Uninitialised
}
GlChar::GlChar(int tw, int th, int x, int y, int w, int h, GLfloat advance, GLfloat ox, GLfloat oy)
: x_step(advance)
{
const GLfloat u = (GLfloat)x / (GLfloat)tw;
const GLfloat v = (GLfloat)y / (GLfloat)th;
const GLfloat u2 = (GLfloat)(x + w) / (GLfloat)tw;
const GLfloat v2 = (GLfloat)(y + h) / (GLfloat)th;
// Setup u,v tex coords
vs[0] = XYUV(ox, oy, u,v );
vs[1] = XYUV(ox, oy-h, u,v2 );
vs[2] = XYUV(w+ox, oy-h, u2,v2 );
vs[3] = XYUV(w+ox, oy, u2,v );
y_min = oy-h;
y_max = oy;
}
void GlChar::Draw() const
{
glVertexPointer(2, GL_FLOAT, sizeof(XYUV), &vs[0].x);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(XYUV), &vs[0].tu);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}

51
thirdparty/Pangolin/src/gl/gldraw.cpp vendored Normal file
View File

@@ -0,0 +1,51 @@
/* 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.
*/
#include <pangolin/gl/gldraw.h>
#include <pangolin/utils/timer.h>
namespace pangolin
{
void glRecordGraphic(float x, float y, float radius)
{
const int ticks = static_cast<int>(TimeNow_s());
if( ticks % 2 )
{
// now, render a little red "recording" dot
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glColor3ub( 255, 0, 0 );
glDrawCircle( x, y, radius );
glPopAttrib();
}
}
}

214
thirdparty/Pangolin/src/gl/glfont.cpp vendored Normal file
View File

@@ -0,0 +1,214 @@
/* 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.
*/
#include <pangolin/display/display_internal.h>
#include <pangolin/gl/glfont.h>
#include <pangolin/gl/glstate.h>
#include <pangolin/image/image_io.h>
#include <pangolin/utils/type_convert.h>
#if !defined(HAVE_GLES) || defined(HAVE_GLES_2)
#include <pangolin/gl/glsl.h>
#endif
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_STATIC
#if defined(_GCC_) || defined(_CLANG_)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
# include "stb_truetype.h"
# pragma GCC diagnostic pop
#else
# include "stb_truetype.h"
#endif
#define MAX_TEXT_LENGTH 500
// Embedded fonts:
extern const unsigned char AnonymousPro_ttf[];
namespace pangolin
{
extern __thread PangolinGl* context;
GlFont& GlFont::I()
{
if (!context->font) {
context->font.reset(new GlFont(AnonymousPro_ttf, context->is_high_res ? 30 : 15));
}
return *context->font.get();
}
GlFont::GlFont(const unsigned char* ttf_buffer, float pixel_height, int tex_w, int tex_h)
{
InitialiseFont(ttf_buffer, pixel_height, tex_w, tex_h);
}
GlFont::GlFont(const std::string& filename, float pixel_height, int tex_w, int tex_h)
{
unsigned char* ttf_buffer = new unsigned char[1<<20];
const size_t bytes_read = fread(ttf_buffer, 1, 1<<20, fopen(filename.c_str(), "rb"));
if(bytes_read > 0) {
InitialiseFont(ttf_buffer, pixel_height, tex_w, tex_h);
}else{
throw std::runtime_error("Unable to read font from file.");
}
delete[] ttf_buffer;
}
GlFont::~GlFont()
{
delete[] font_bitmap;
}
void GlFont::InitialiseFont(const unsigned char* ttf_buffer, float pixel_height, int tex_w, int tex_h)
{
font_height_px = pixel_height;
this->tex_w = tex_w;
this->tex_h = tex_h;
font_bitmap = new unsigned char[tex_w*tex_h];
const int offset = 0;
stbtt_fontinfo f;
if (!stbtt_InitFont(&f, ttf_buffer, offset)) {
throw std::runtime_error("Unable to initialise font");
}
float scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
STBTT_memset(font_bitmap, 0, tex_w*tex_h);
int x = 1;
int y = 1;
int bottom_y = 1;
// Generate bitmap and char indices
for (int i=0; i < NUM_CHARS; ++i) {
int advance, lsb, x0,y0,x1,y1,gw,gh;
int g = stbtt_FindGlyphIndex(&f, FIRST_CHAR + i);
stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
gw = x1-x0;
gh = y1-y0;
if (x + gw + 1 >= tex_w)
y = bottom_y, x = 1; // advance to next row
if (y + gh + 1 >= tex_h) // check if it fits vertically AFTER potentially moving to next row
throw std::runtime_error("Unable to initialise font");
STBTT_assert(x+gw < tex_w);
STBTT_assert(y+gh < tex_h);
stbtt_MakeGlyphBitmap(&f, font_bitmap+x+y*tex_w, gw,gh,tex_w, scale,scale, g);
// Adjust offset for edges of pixels
chardata[i] = GlChar(tex_w,tex_h, x, y, gw, gh, scale*advance, x0 -0.5f, -y0 -0.5f);
x = x + gw + 1;
if (y+gh+1 > bottom_y)
bottom_y = y+gh+1;
}
// Generate kern table
for (int i=0; i < NUM_CHARS; ++i) {
for (int j=0; j < NUM_CHARS; ++j) {
kern_table[i*NUM_CHARS+j] = scale * stbtt_GetCodepointKernAdvance(&f,i,j);
}
}
}
void GlFont::InitialiseGlTexture()
{
if(font_bitmap) {
mTex.Reinitialise(tex_w,tex_h, GL_ALPHA, true, 0, GL_ALPHA,GL_UNSIGNED_BYTE, font_bitmap);
// mTex.SetNearestNeighbour();
delete[] font_bitmap;
font_bitmap = 0;
}
}
GlText GlFont::Text( const char* fmt, ... )
{
if(!mTex.IsValid()) InitialiseGlTexture();
GlText ret(mTex);
char text[MAX_TEXT_LENGTH];
va_list ap;
if( fmt != NULL ) {
va_start( ap, fmt );
vsnprintf( text, MAX_TEXT_LENGTH, fmt, ap );
va_end( ap );
const size_t len = strlen(text);
char lc = ' ' - FIRST_CHAR;
for(size_t i=0; i < len; ++i) {
char c = text[i];
if( !(FIRST_CHAR <= c /*&& c <FIRST_CHAR+NUM_CHARS*/) ) {
c = ' ';
}
GlChar& ch = chardata[c-32];
// Kerning
if(i) {
const GLfloat kern = kern_table[ (lc-32)*NUM_CHARS + (c-32) ];
ret.AddSpace(kern);
}
ret.Add(c,ch);
lc = c;
}
}
return ret;
}
GlText GlFont::Text( const std::string& str )
{
if(!mTex.IsValid()) InitialiseGlTexture();
GlText ret(mTex);
char lc = ' ' - FIRST_CHAR;
for(size_t i=0; i < str.length(); ++i) {
char c = str[i];
if( !(FIRST_CHAR <= c /*&& c <FIRST_CHAR+NUM_CHARS*/) ) {
c = ' ';
}
GlChar& ch = chardata[c-32];
// Kerning
if(i) {
const GLfloat kern = kern_table[ (lc-32)*NUM_CHARS + (c-32) ];
ret.AddSpace(kern);
}
ret.Add(c,ch);
lc = c;
}
return ret;
}
}

View File

@@ -0,0 +1,274 @@
/* 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 <pangolin/gl/glpangoglu.h>
#include <pangolin/utils/simple_math.h>
#include <unordered_map>
namespace pangolin {
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetError.xhtml
static const std::unordered_map<GLenum, std::string> gl_error_string = {
{GL_NO_ERROR, "GL_NO_ERROR: No error has been recorded."},
{GL_INVALID_ENUM, "GL_INVALID_ENUM: An unacceptable value is specified for an enumerated argument."},
{GL_INVALID_VALUE, "GL_INVALID_VALUE: A numeric argument is out of range."},
{GL_INVALID_OPERATION, "GL_INVALID_OPERATION: The specified operation is not allowed in the current state."},
{GL_INVALID_FRAMEBUFFER_OPERATION, "GL_INVALID_FRAMEBUFFER_OPERATION: The framebuffer object is not complete."},
{GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY: There is not enough memory left to execute the command."},
{GL_STACK_UNDERFLOW, "GL_STACK_UNDERFLOW: An attempt has been made to perform an operation that would cause an internal stack to underflow."},
{GL_STACK_OVERFLOW, "GL_STACK_OVERFLOW: An attempt has been made to perform an operation that would cause an internal stack to overflow."},
};
const char* glErrorString(GLenum error)
{
return gl_error_string.count(error) ? gl_error_string.at(error).c_str() : nullptr;
}
// Based on glu implementation.
template<typename P>
int InvertMatrix(const P m[16], P invOut[16])
{
P inv[16], det;
int i;
inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
+ m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
- m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
+ m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
- m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
- m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
+ m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
- m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
+ m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
+ m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
- m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
+ m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
- m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
- m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
+ m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
- m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
+ m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
if (det == 0)
return GL_FALSE;
det=1.0f/det;
for (i = 0; i < 16; i++)
invOut[i] = inv[i] * det;
return GL_TRUE;
}
// Based on glu implementation
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)
{
float t1[4] = {objx, objy, objz, 1.0f};
float t2[4];
MatMul<4,4,1,float>(t2, modelMatrix, t1);
MatMul<4,4,1,float>(t1, projMatrix, t2);
if (t1[3] == 0.0) {
return(GL_FALSE);
}
// Normalise
t1[0]/=t1[3];
t1[1]/=t1[3];
t1[2]/=t1[3];
// Map x, y and z to range 0-1
t1[0]=t1[0]*0.5f+0.5f;
t1[1]=t1[1]*0.5f+0.5f;
t1[2]=t1[2]*0.5f+0.5f;
// Map x,y to viewport
t1[0]=t1[0] * viewport[2] + viewport[0];
t1[1]=t1[1] * viewport[3] + viewport[1];
*winx=t1[0];
*winy=t1[1];
*winz=t1[2];
return GL_TRUE;
}
// Based on glu implementation
GLint glUnProject(
float winx, float winy, float winz,
const float mv[16],
const float proj[16],
const GLint viewport[4],
float* objx, float* objy, float* objz)
{
float t1[16];
MatMul<4,4,4,float>(t1, proj, mv);
if (!InvertMatrix<float>(t1, t1)) {
return(GL_FALSE);
}
// Map x and y from window coordinates
float in[4] = {winx, winy, winz, 1.0f};
in[0] = (in[0] - viewport[0]) / viewport[2];
in[1] = (in[1] - viewport[1]) / viewport[3];
// Map to range -1 to 1
in[0] = in[0] * 2 - 1;
in[1] = in[1] * 2 - 1;
in[2] = in[2] * 2 - 1;
float out[4];
MatMul<4,4,1,float>(out, t1, in);
if (out[3] == 0.0) {
return(GL_FALSE);
}
// Normalise
out[0] /= out[3];
out[1] /= out[3];
out[2] /= out[3];
// Copy out
*objx = out[0];
*objy = out[1];
*objz = out[2];
return GL_TRUE;
}
// Based on glu implementation
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)
{
double t1[4] = {objx, objy, objz, 1.0f};
double t2[4];
MatMul<4,4,1,double>(t2, modelMatrix, t1);
MatMul<4,4,1,double>(t1, projMatrix, t2);
if (t1[3] == 0.0) {
return(GL_FALSE);
}
// Normalise
t1[0]/=t1[3];
t1[1]/=t1[3];
t1[2]/=t1[3];
// Map x, y and z to range 0-1
t1[0]=t1[0]*0.5f+0.5f;
t1[1]=t1[1]*0.5f+0.5f;
t1[2]=t1[2]*0.5f+0.5f;
// Map x,y to viewport
t1[0]=t1[0] * viewport[2] + viewport[0];
t1[1]=t1[1] * viewport[3] + viewport[1];
*winx=t1[0];
*winy=t1[1];
*winz=t1[2];
return GL_TRUE;
}
// Based on glu implementation
GLint glUnProject(
double winx, double winy, double winz,
const double mv[16],
const double proj[16],
const GLint viewport[4],
double* objx, double* objy, double* objz)
{
double t1[16];
MatMul<4,4,4,double>(t1, proj, mv);
if (!InvertMatrix<double>(t1, t1)) {
return(GL_FALSE);
}
// Map x and y from window coordinates
double in[4] = {winx, winy, winz, 1.0f};
in[0] = (in[0] - viewport[0]) / viewport[2];
in[1] = (in[1] - viewport[1]) / viewport[3];
// Map to range -1 to 1
in[0] = in[0] * 2 - 1;
in[1] = in[1] * 2 - 1;
in[2] = in[2] * 2 - 1;
double out[4];
MatMul<4,4,1,double>(out, t1, in);
if (out[3] == 0.0) {
return(GL_FALSE);
}
// Normalise
out[0] /= out[3];
out[1] /= out[3];
out[2] /= out[3];
// Copy out
*objx = out[0];
*objy = out[1];
*objz = out[2];
return GL_TRUE;
}
}

202
thirdparty/Pangolin/src/gl/gltext.cpp vendored Normal file
View File

@@ -0,0 +1,202 @@
/* 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.
*/
#include <pangolin/gl/gltext.h>
#include <pangolin/gl/glsl.h>
#ifdef BUILD_PANGOLIN_GUI
#include <pangolin/display/display.h>
#include <pangolin/display/view.h>
#endif
namespace pangolin
{
GlText::GlText()
: tex(NULL), width(0),
ymin(std::numeric_limits<GLfloat>::max()),
ymax(-std::numeric_limits<GLfloat>::max())
{
}
GlText::GlText(const GlText& txt)
: tex(txt.tex), str(txt.str), width(txt.width),
ymin(txt.ymin), ymax(txt.ymax), vs(txt.vs)
{
}
GlText::GlText(const GlTexture& font_tex)
: tex(&font_tex), width(0),
ymin(std::numeric_limits<GLfloat>::max()),
ymax(-std::numeric_limits<GLfloat>::max())
{
}
void GlText::AddSpace(GLfloat s)
{
width += s;
}
void GlText::Add(unsigned char c, const GlChar& glc)
{
GLfloat x = width;
vs.push_back(glc.GetVert(0) + x);
vs.push_back(glc.GetVert(1) + x);
vs.push_back(glc.GetVert(2) + x);
vs.push_back(glc.GetVert(0) + x);
vs.push_back(glc.GetVert(2) + x);
vs.push_back(glc.GetVert(3) + x);
ymin = std::min(ymin, glc.YMin());
ymax = std::max(ymax, glc.YMax());
width = x + glc.StepX();
str.append(1,c);
}
void GlText::Clear()
{
str.clear();
vs.clear();
width = 0;
ymin = +std::numeric_limits<GLfloat>::max();
ymax = -std::numeric_limits<GLfloat>::max();
}
void GlText::DrawGlSl() const
{
#if !defined(HAVE_GLES) || defined(HAVE_GLES_2)
if(vs.size() && tex) {
glEnableVertexAttribArray(pangolin::DEFAULT_LOCATION_POSITION);
glEnableVertexAttribArray(pangolin::DEFAULT_LOCATION_TEXCOORD);
glVertexAttribPointer(pangolin::DEFAULT_LOCATION_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(XYUV), &vs[0].x);
glVertexAttribPointer(pangolin::DEFAULT_LOCATION_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(XYUV), &vs[0].tu);
tex->Bind();
glEnable(GL_TEXTURE_2D);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vs.size() );
glDisable(GL_TEXTURE_2D);
glDisableVertexAttribArray(pangolin::DEFAULT_LOCATION_POSITION);
glDisableVertexAttribArray(pangolin::DEFAULT_LOCATION_TEXCOORD);
}
#endif
}
void GlText::Draw() const
{
if(vs.size() && tex) {
glVertexPointer(2, GL_FLOAT, sizeof(XYUV), &vs[0].x);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(XYUV), &vs[0].tu);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
tex->Bind();
glEnable(GL_TEXTURE_2D);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vs.size() );
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
#ifdef BUILD_PANGOLIN_GUI
void GlText::Draw(GLfloat x, GLfloat y, GLfloat z) const
{
// find object point (x,y,z)' in pixel coords
GLdouble projection[16];
GLdouble modelview[16];
GLint view[4];
GLdouble scrn[3];
#ifdef HAVE_GLES_2
std::copy(glEngine().projection.top().m, glEngine().projection.top().m+16, projection);
std::copy(glEngine().modelview.top().m, 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,
scrn, scrn + 1, scrn + 2);
DisplayBase().Activate();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(-0.5, DisplayBase().v.w-0.5, -0.5, DisplayBase().v.h-0.5, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(std::floor((GLfloat)scrn[0]), std::floor((GLfloat)scrn[1]), (GLfloat)scrn[2]);
Draw();
// Restore viewport
glViewport(view[0],view[1],view[2],view[3]);
// Restore modelview / project matrices
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
// Render at (x,y) in window coordinates.
void GlText::DrawWindow(GLfloat x, GLfloat y, GLfloat z) const
{
// Backup viewport
GLint view[4];
glGetIntegerv(GL_VIEWPORT, view );
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
DisplayBase().ActivatePixelOrthographic();
glTranslatef( std::floor(x), std::floor(y), z);
Draw();
// Restore viewport
glViewport(view[0],view[1],view[2],view[3]);
// Restore modelview / project matrices
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
#endif // BUILD_PANGOLIN_GUI
}

View File

@@ -0,0 +1,38 @@
/* 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.
*/
#include <pangolin/gl/gltexturecache.h>
namespace pangolin
{
TextureCache& TextureCache::I() {
static TextureCache instance;
return instance;
}
}

4882
thirdparty/Pangolin/src/gl/stb_truetype.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,401 @@
/* 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.
*/
#include <pangolin/handler/handler.h>
#include <pangolin/display/display_internal.h>
#include <pangolin/display/view.h>
namespace pangolin
{
// Pointer to context defined in display.cpp
extern __thread PangolinGl* context;
void Handler::Keyboard(View& d, unsigned char key, int x, int y, bool pressed)
{
View* child = d.FindChild(x,y);
if( child)
{
context->activeDisplay = child;
if( child->handler)
child->handler->Keyboard(*child,key,x,y,pressed);
}
}
void Handler::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
{
View* child = d.FindChild(x,y);
if( child )
{
context->activeDisplay = child;
if( child->handler)
child->handler->Mouse(*child,button,x,y,pressed,button_state);
}
}
void Handler::MouseMotion(View& d, int x, int y, int button_state)
{
View* child = d.FindChild(x,y);
if( child )
{
context->activeDisplay = child;
if( child->handler)
child->handler->MouseMotion(*child,x,y,button_state);
}
}
void Handler::PassiveMouseMotion(View& d, int x, int y, int button_state)
{
View* child = d.FindChild(x,y);
if( child )
{
if( child->handler)
child->handler->PassiveMouseMotion(*child,x,y,button_state);
}
}
void Handler::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
View* child = d.FindChild( (int)x, (int)y);
if( child )
{
context->activeDisplay = child;
if( child->handler)
child->handler->Special(*child,inType, x,y, p1, p2, p3, p4, button_state);
}
}
void HandlerScroll::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
{
if( pressed && (button == MouseWheelUp || button == MouseWheelDown) )
{
if( button == MouseWheelUp) d.scroll_offset -= 1;
if( button == MouseWheelDown) d.scroll_offset += 1;
d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.NumVisibleChildren()-1) );
d.ResizeChildren();
}else{
Handler::Mouse(d,button,x,y,pressed,button_state);
}
}
void HandlerScroll::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
if( inType == InputSpecialScroll )
{
d.scroll_offset -= (int)(p2 / fabs(p2));
d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.NumVisibleChildren()-1) );
d.ResizeChildren();
}else{
Handler::Special(d,inType,x,y,p1,p2,p3,p4,button_state);
}
}
Handler3D::Handler3D(OpenGlRenderState& cam_state, AxisDirection enforce_up, float trans_scale, float zoom_fraction)
: cam_state(&cam_state), enforce_up(enforce_up), tf(trans_scale), zf(zoom_fraction), cameraspec(CameraSpecOpenGl), last_z(0.8)
{
SetZero<3,1>(rot_center);
}
void Handler3D::Keyboard(View&, unsigned char /*key*/, int /*x*/, int /*y*/, bool /*pressed*/)
{
// TODO: hooks for reset / changing mode (perspective / ortho etc)
}
bool Handler3D::ValidWinDepth(GLprecision depth)
{
return depth != 1;
}
void Handler3D::PixelUnproject( View& view, GLprecision winx, GLprecision winy, GLprecision winz, GLprecision Pc[3])
{
const GLint viewport[4] = {view.v.l,view.v.b,view.v.w,view.v.h};
const pangolin::OpenGlMatrix proj = cam_state->GetProjectionMatrix();
glUnProject(winx, winy, winz, Identity4d, proj.m, viewport, &Pc[0], &Pc[1], &Pc[2]);
}
void Handler3D::GetPosNormal(pangolin::View& view, int winx, int winy, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision nw[3], GLprecision default_z)
{
// TODO: Get to work on android
const int zl = (hwin*2+1);
const int zsize = zl*zl;
GLfloat zs[zsize];
#ifndef HAVE_GLES
glReadBuffer(GL_FRONT);
glReadPixels(winx-hwin,winy-hwin,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
#else
std::fill(zs,zs+zsize, 1);
#endif
GLfloat mindepth = *(std::min_element(zs,zs+zsize));
if(mindepth == 1) mindepth = (GLfloat)default_z;
p[0] = winx; p[1] = winy; p[2] = mindepth;
PixelUnproject(view, winx, winy, mindepth, Pc);
const pangolin::OpenGlMatrix mv = cam_state->GetModelViewMatrix();
GLprecision T_wc[3*4];
LieSE3from4x4(T_wc, mv.Inverse().m );
LieApplySE3vec(Pw, T_wc, Pc);
// Neighboring points in camera coordinates
GLprecision Pl[3]; GLprecision Pr[3]; GLprecision Pb[3]; GLprecision Pt[3];
PixelUnproject(view, winx-hwin, winy, zs[hwin*zl + 0], Pl );
PixelUnproject(view, winx+hwin, winy, zs[hwin*zl + zl-1], Pr );
PixelUnproject(view, winx, winy-hwin, zs[hwin+1], Pb );
PixelUnproject(view, winx, winy+hwin, zs[zsize-(hwin+1)], Pt );
// n = ((Pr-Pl).cross(Pt-Pb)).normalized();
GLprecision PrmPl[3]; GLprecision PtmPb[3];
MatSub<3,1>(PrmPl,Pr,Pl);
MatSub<3,1>(PtmPb,Pt,Pb);
GLprecision nc[3];
CrossProduct(nc, PrmPl, PtmPb);
Normalise<3>(nc);
// T_wc is col major, so the rotation component is first.
LieApplySO3(nw,T_wc,nc);
}
void Handler3D::Mouse(View& display, MouseButton button, int x, int y, bool pressed, int button_state)
{
// mouse down
last_pos[0] = (float)x;
last_pos[1] = (float)y;
GLprecision T_nc[3*4];
LieSetIdentity(T_nc);
funcKeyState = 0;
if( pressed )
{
GetPosNormal(display,x,y,p,Pw,Pc,n,last_z);
if( ValidWinDepth(p[2]) )
{
last_z = p[2];
std::copy(Pc,Pc+3,rot_center);
}
if( button == MouseWheelUp || button == MouseWheelDown)
{
LieSetIdentity(T_nc);
const GLprecision t[3] = { 0,0,(button==MouseWheelUp?1:-1)*100*tf};
LieSetTranslation<>(T_nc,t);
if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
{
LieSetTranslation<>(T_nc,rot_center);
const GLprecision s = (button==MouseWheelUp?-1.0:1.0) * zf;
MatMul<3,1>(T_nc+(3*3), s);
}
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
}
funcKeyState = button_state;
}
}
void Handler3D::MouseMotion(View& display, int x, int y, int button_state)
{
const GLprecision rf = 0.01;
const float delta[2] = { (float)x - last_pos[0], (float)y - last_pos[1] };
const float mag = delta[0]*delta[0] + delta[1]*delta[1];
if((button_state & KeyModifierCtrl) && (button_state & KeyModifierShift))
{
GLprecision T_nc[3 * 4];
LieSetIdentity(T_nc);
GetPosNormal(display, x, y, p, Pw, Pc, n, last_z);
if(ValidWinDepth(p[2]))
{
last_z = p[2];
std::copy(Pc, Pc + 3, rot_center);
}
funcKeyState = button_state;
}
else
{
funcKeyState = 0;
}
// TODO: convert delta to degrees based of fov
// TODO: make transformation with respect to cam spec
if( mag < 50.0f*50.0f )
{
OpenGlMatrix& mv = cam_state->GetModelViewMatrix();
const GLprecision* up = AxisDirectionVector[enforce_up];
GLprecision T_nc[3*4];
LieSetIdentity(T_nc);
bool rotation_changed = false;
if( button_state == MouseButtonMiddle )
{
// Middle Drag: Rotate around view
// Try to correct for different coordinate conventions.
GLprecision aboutx = -rf * delta[1];
GLprecision abouty = rf * delta[0];
OpenGlMatrix& pm = cam_state->GetProjectionMatrix();
abouty *= -pm.m[2 * 4 + 3];
Rotation<>(T_nc, aboutx, abouty, (GLprecision)0.0);
}else if( button_state == MouseButtonLeft )
{
// Left Drag: in plane translate
if( ValidWinDepth(last_z) )
{
GLprecision np[3];
PixelUnproject(display, x, y, last_z, np);
const GLprecision t[] = { np[0] - rot_center[0], np[1] - rot_center[1], 0};
LieSetTranslation<>(T_nc,t);
std::copy(np,np+3,rot_center);
}else{
const GLprecision t[] = { -10*delta[0]*tf, 10*delta[1]*tf, 0};
LieSetTranslation<>(T_nc,t);
}
}else if( button_state == (MouseButtonLeft | MouseButtonRight) )
{
// Left and Right Drag: in plane rotate about object
// Rotation<>(T_nc,0.0,0.0, delta[0]*0.01);
GLprecision T_2c[3*4];
Rotation<>(T_2c, (GLprecision)0.0, (GLprecision)0.0, delta[0]*rf);
GLprecision mrotc[3];
MatMul<3,1>(mrotc, rot_center, (GLprecision)-1.0);
LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
GLprecision T_n2[3*4];
LieSetIdentity<>(T_n2);
LieSetTranslation<>(T_n2,rot_center);
LieMulSE3(T_nc, T_n2, T_2c );
rotation_changed = true;
}else if( button_state == MouseButtonRight)
{
GLprecision aboutx = -rf * delta[1];
GLprecision abouty = -rf * delta[0];
// Try to correct for different coordinate conventions.
if(cam_state->GetProjectionMatrix().m[2*4+3] <= 0) {
abouty *= -1;
}
if(enforce_up) {
// Special case if view direction is parallel to up vector
const GLprecision updotz = mv.m[2]*up[0] + mv.m[6]*up[1] + mv.m[10]*up[2];
if(updotz > 0.98) aboutx = std::min(aboutx, (GLprecision)0.0);
if(updotz <-0.98) aboutx = std::max(aboutx, (GLprecision)0.0);
// Module rotation around y so we don't spin too fast!
abouty *= (1-0.6*fabs(updotz));
}
// Right Drag: object centric rotation
GLprecision T_2c[3*4];
Rotation<>(T_2c, aboutx, abouty, (GLprecision)0.0);
GLprecision mrotc[3];
MatMul<3,1>(mrotc, rot_center, (GLprecision)-1.0);
LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
GLprecision T_n2[3*4];
LieSetIdentity<>(T_n2);
LieSetTranslation<>(T_n2,rot_center);
LieMulSE3(T_nc, T_n2, T_2c );
rotation_changed = true;
}
LieMul4x4bySE3<>(mv.m,T_nc,mv.m);
if(enforce_up != AxisNone && rotation_changed) {
EnforceUpT_cw(mv.m, up);
}
}
last_pos[0] = (float)x;
last_pos[1] = (float)y;
}
void Handler3D::Special(View& display, InputSpecial inType, float x, float y, float p1, float p2, float /*p3*/, float /*p4*/, int button_state)
{
if( !(inType == InputSpecialScroll || inType == InputSpecialRotate) )
return;
// mouse down
last_pos[0] = x;
last_pos[1] = y;
GLprecision T_nc[3*4];
LieSetIdentity(T_nc);
GetPosNormal(display, (int)x, (int)y, p, Pw, Pc, n, last_z);
if(p[2] < 1.0) {
last_z = p[2];
std::copy(Pc,Pc+3,rot_center);
}
if( inType == InputSpecialScroll ) {
if(button_state & KeyModifierCmd) {
const GLprecision rx = -p2 / 1000;
const GLprecision ry = -p1 / 1000;
Rotation<>(T_nc,rx, ry, (GLprecision)0.0);
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
}else{
const GLprecision scrolly = p2/10;
LieSetIdentity(T_nc);
const GLprecision t[] = { 0,0, -scrolly*100*tf};
LieSetTranslation<>(T_nc,t);
if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
{
LieSetTranslation<>(T_nc,rot_center);
MatMul<3,1>(T_nc+(3*3), -scrolly * zf);
}
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
}
}else if(inType == InputSpecialRotate) {
const GLprecision r = p1 / 20;
GLprecision T_2c[3*4];
Rotation<>(T_2c, (GLprecision)0.0, (GLprecision)0.0, r);
GLprecision mrotc[3];
MatMul<3,1>(mrotc, rot_center, (GLprecision)-1.0);
LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
GLprecision T_n2[3*4];
LieSetIdentity<>(T_n2);
LieSetTranslation<>(T_n2,rot_center);
LieMulSE3(T_nc, T_n2, T_2c );
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
}
}
}

View File

@@ -0,0 +1,45 @@
/* 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.
*/
#include <pangolin/handler/handler_glbuffer.h>
#include <pangolin/display/view.h>
namespace pangolin {
Handler3DFramebuffer::Handler3DFramebuffer(GlFramebuffer& fb, pangolin::OpenGlRenderState& cam_state, pangolin::AxisDirection enforce_up, float trans_scale)
: pangolin::Handler3D(cam_state,enforce_up, trans_scale), fb(fb)
{
}
void Handler3DFramebuffer::GetPosNormal(pangolin::View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision n[3], GLprecision default_z)
{
fb.Bind();
Handler3D::GetPosNormal(view,x,y,p,Pw,Pc,n,default_z);
fb.Unbind();
}
}

View File

@@ -0,0 +1,462 @@
#include <pangolin/handler/handler_image.h>
#include <pangolin/gl/glfont.h>
namespace pangolin
{
ImageViewHandler::ImageViewHandler()
: linked_view_handler(0),
use_nn(false), flipTextureX(false), flipTextureY(false)
{
SetDimensions(1, 1);
}
ImageViewHandler::ImageViewHandler(size_t w, size_t h)
: linked_view_handler(0),
use_nn(false), flipTextureX(false), flipTextureY(false)
{
SetDimensions(w,h);
}
void ImageViewHandler::SetDimensions(size_t w, size_t h)
{
rview_default = pangolin::XYRangef(-0.5f, w-0.5f, -0.5f, h-0.5f),
rview_max = pangolin::XYRangef(-0.5f, w-0.5f, -0.5f, h-0.5f),
rview = rview_default;
target = rview;
}
void ImageViewHandler::UpdateView()
{
// TODO: Base this on current framerate.
const float animate_factor = 1.0f / 5.0f;
if( linked_view_handler ) {
// Synchronise rview and target with linked plotter
rview = linked_view_handler->rview;
target = linked_view_handler->target;
selection = linked_view_handler->selection;
}else{
// Clamp target to image dimensions.
AdjustScale();
AdjustTranslation();
// Animate view window toward target
pangolin::XYRangef d = target - rview;
rview += d * animate_factor;
}
}
void ImageViewHandler::glSetViewOrtho()
{
const pangolin::XYRangef& xy = GetViewToRender();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(xy.x.min, xy.x.max, xy.y.max, xy.y.min, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void ImageViewHandler::glRenderTexture(pangolin::GlTexture& tex)
{
glRenderTexture(tex.tid, tex.width, tex.height);
}
void ImageViewHandler::glRenderTexture(GLuint tex, GLint width, GLint height)
{
if(tex != 0) {
const pangolin::XYRangef& xy = GetViewToRender();
const float w = (float)width;
const float h = (float)height;
// discrete coords, (-0.5, -0.5) - (w-0.5, h-0.5)
const GLfloat l = xy.x.min;
const GLfloat r = xy.x.max;
const GLfloat b = xy.y.max;
const GLfloat t = xy.y.min;
// continuous coords, (0,0) - (1,1)
GLfloat ln = (l + 0.5f) / w;
GLfloat rn = (r + 0.5f) / w;
GLfloat bn = (b + 0.5f) / h;
GLfloat tn = (t + 0.5f) / h;
if(flipTextureX) {
ln = 1-ln;
rn = 1-rn;
}
if(flipTextureY) {
bn = 1-bn;
tn = 1-tn;
}
const GLfloat sq_vert[] = { l,t, r,t, r,b, l,b };
const GLfloat sq_tex[] = { ln,tn, rn,tn, rn,bn, ln,bn };
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, UseNN() ? GL_NEAREST : GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, UseNN() ? GL_NEAREST : GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, sq_tex);
glVertexPointer(2, GL_FLOAT, 0, sq_vert);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
void ImageViewHandler::glRenderOverlay()
{
const pangolin::XYRangef& selxy = GetSelection();
const GLfloat sq_select[] = {
selxy.x.min, selxy.y.min,
selxy.x.max, selxy.y.min,
selxy.x.max, selxy.y.max,
selxy.x.min, selxy.y.max
};
glColor4f(1.0,0.0,0.0,1.0);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, sq_select);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0,1.0,1.0,1.0);
if( std::abs(selxy.Area()) > 0) {
// Render text
pangolin::Viewport v;
glGetIntegerv( GL_VIEWPORT, &v.l );
float xpix, ypix;
ImageToScreen(v, selxy.x.max, selxy.y.max, xpix, ypix);
// Save previous value
GLboolean gl_blend_enabled;
glGetBooleanv(GL_BLEND, &gl_blend_enabled);
// Ensure that blending is enabled for rendering text.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
pangolin::GlFont::I().Text(
"%.2f x %.2f",
selxy.x.Size(), selxy.y.Size()
).DrawWindow(xpix,ypix);
pangolin::GlFont::I().Text(
"(%.1f,%.1f)->(%.1f,%.1f)",
selxy.x.min, selxy.y.min,
selxy.x.max, selxy.y.max
).DrawWindow(xpix, ypix - 1.0f * pangolin::GlFont::I().Height());
// Restore previous value
if(!gl_blend_enabled) glDisable(GL_BLEND);
}
}
void ImageViewHandler::ScreenToImage(Viewport& v, float xpix, float ypix, float& ximg, float& yimg)
{
ximg = rview.x.min + rview.x.Size() * (xpix - v.l) / (float)v.w;
yimg = rview.y.min + rview.y.Size() * ( 1.0f - (ypix - v.b) / (float)v.h);
}
void ImageViewHandler::ImageToScreen(Viewport& v, float ximg, float yimg, float& xpix, float& ypix)
{
xpix = (ximg -rview.x.min) * (float)v.w / rview.x.Size() + v.l;
ypix = v.b - (float)v.h * ((yimg - rview.y.min) / rview.y.Size() - 1.0f);
}
bool ImageViewHandler::UseNN() const
{
return use_nn;
}
bool& ImageViewHandler::UseNN()
{
return use_nn;
}
bool& ImageViewHandler::FlipTextureX()
{
return flipTextureX;
}
bool& ImageViewHandler::FlipTextureY()
{
return flipTextureY;
}
pangolin::XYRangef& ImageViewHandler::GetViewToRender()
{
return rview;
}
float ImageViewHandler::GetViewScale()
{
return rview_max.x.Size() / rview.x.Size();
}
pangolin::XYRangef& ImageViewHandler::GetView()
{
return target;
}
pangolin::XYRangef& ImageViewHandler::GetDefaultView()
{
return rview_default;
}
pangolin::XYRangef& ImageViewHandler::GetSelection()
{
return selection;
}
void ImageViewHandler::GetHover(float& x, float& y)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
x = tv.hover_img[0];
y = tv.hover_img[1];
}
void ImageViewHandler::SetView(const pangolin::XYRangef& range)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
tv.rview = range;
tv.target = range;
}
void ImageViewHandler::SetViewSmooth(const pangolin::XYRangef& range)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
tv.target = range;
}
void ImageViewHandler::ScrollView(float x, float y)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
ScrollViewSmooth(x,y);
tv.rview.x += x;
tv.rview.y += y;
}
void ImageViewHandler::ScrollViewSmooth(float x, float y)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
tv.target.x += x;
tv.target.y += y;
}
void ImageViewHandler::ScaleView(float x, float y, float cx, float cy)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
ScaleViewSmooth(x,y,cx,cy);
tv.rview.x.Scale(x,cx);
tv.rview.y.Scale(y,cy);
}
void ImageViewHandler::ScaleViewSmooth(float x, float y, float cx, float cy)
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
tv.target.x.Scale(x,cx);
tv.target.y.Scale(y,cy);
}
void ImageViewHandler::ResetView()
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
tv.target = tv.rview_default;
}
///////////////////////////////////////////////////////
/// pangolin::Handler
///////////////////////////////////////////////////////
void ImageViewHandler::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
{
XYRangef& sel = linked_view_handler ? linked_view_handler->selection : selection;
const float mvfactor = 1.0f / 10.0f;
const float c[2] = { rview.x.Mid(), rview.y.Mid() };
if(pressed) {
if(key == '\r') {
if( sel.Area() != 0.0f && std::isfinite(sel.Area()) ) {
// Set view to equal selection
SetViewSmooth(sel);
// Reset selection
sel.x.max = sel.x.min;
sel.y.max = sel.y.min;
}
}else if(key == 'n') {
use_nn = !use_nn;
}else if(key == 'l') {
if(to_link) {
linked_view_handler = to_link;
to_link = 0;
}else{
to_link = this;
}
}else if(key == PANGO_SPECIAL + PANGO_KEY_LEFT) {
const float w = target.x.Size();
const float dx = mvfactor*w;
ScrollViewSmooth(-dx, 0);
}else if(key == PANGO_SPECIAL + PANGO_KEY_RIGHT) {
const float w = target.x.Size();
const float dx = mvfactor*w;
ScrollViewSmooth(+dx, 0);
}else if(key == PANGO_SPECIAL + PANGO_KEY_DOWN) {
const float h = target.y.Size();
const float dy = mvfactor*h;
ScrollViewSmooth(0, -dy);
}else if(key == PANGO_SPECIAL + PANGO_KEY_UP) {
const float h = target.y.Size();
const float dy = mvfactor*h;
ScrollViewSmooth(0, +dy);
}else if(key == '=') {
ScaleViewSmooth(0.5, 0.5, c[0], c[1]);
}else if(key == '-') {
ScaleViewSmooth(2.0, 2.0, c[0], c[1]);
}else if(key == '#') {
ResetView();
}else if(key == 1) {
// ctrl-a: select all.
sel = rview;
}else{
pango_print_debug("Unhandled ImageViewHandler::Keyboard. Key: %u\n", (unsigned int)key);
}
}
}
void ImageViewHandler::Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state)
{
XYRangef& sel = linked_view_handler ? linked_view_handler->selection : selection;
ScreenToImage(view.v, (float)x, (float)y, hover_img[0], hover_img[1]);
const float scinc = 1.05f;
const float scdec = 1.0f/scinc;
if(button_state & KeyModifierCtrl) {
const float mvfactor = 1.0f/20.0f;
if(button == MouseWheelUp) {
ScrollViewSmooth(0.0f, +mvfactor*rview.y.Size() );
}else if(button == MouseWheelDown) {
ScrollViewSmooth(0.0f, -mvfactor*rview.y.Size() );
}else if(button == MouseWheelLeft) {
ScrollViewSmooth(+mvfactor*rview.x.Size(), 0.0f );
}else if(button == MouseWheelRight) {
ScrollViewSmooth(-mvfactor*rview.x.Size(), 0.0f );
}
}else{
if(button == MouseButtonLeft) {
// Update selected range
if(pressed) {
sel.x.min = hover_img[0];
sel.y.min = hover_img[1];
}
sel.x.max = hover_img[0];
sel.y.max = hover_img[1];
}else if(button == MouseWheelUp) {
ScaleViewSmooth(scdec, scdec, hover_img[0], hover_img[1]);
}else if(button == MouseWheelDown) {
ScaleViewSmooth(scinc, scinc, hover_img[0], hover_img[1]);
}
}
FixSelection(sel);
last_mouse_pos[0] = x;
last_mouse_pos[1] = y;
if(OnSelectionCallback) {
OnSelectionCallback( OnSelectionEventData(view,*this,pressed) );
}
}
void ImageViewHandler::MouseMotion(View& view, int x, int y, int button_state)
{
XYRangef& sel = linked_view_handler ? linked_view_handler->selection : selection;
const int d[2] = {x-last_mouse_pos[0], y-last_mouse_pos[1]};
// Update hover status (after potential resizing)
ScreenToImage(view.v, (float)x, (float)y, hover_img[0], hover_img[1]);
if( button_state == MouseButtonLeft )
{
// Update selected range
sel.x.max = hover_img[0];
sel.y.max = hover_img[1];
}else if(button_state == MouseButtonRight )
{
Special(view, InputSpecialScroll, (float)x, (float)y, (float)d[0], (float)d[1], 0.0f, 0.0f, button_state);
}
last_mouse_pos[0] = x;
last_mouse_pos[1] = y;
if( button_state == MouseButtonLeft && OnSelectionCallback) {
OnSelectionCallback( OnSelectionEventData(view,*this,true) );
}
}
void ImageViewHandler::PassiveMouseMotion(View&, int /*x*/, int /*y*/, int /*button_state*/)
{
}
void ImageViewHandler::Special(View& view, pangolin::InputSpecial inType, float x, float y, float p1, float p2, float /*p3*/, float /*p4*/, int /*button_state*/)
{
ScreenToImage(view.v, x, y, hover_img[0], hover_img[1]);
if(inType == InputSpecialScroll) {
const float d[2] = {p1,p2};
const float is[2] = {rview.x.Size(),rview.y.Size() };
const float df[2] = {is[0]*d[0]/(float)view.v.w, is[1]*d[1]/(float)view.v.h};
ScrollView(-df[0], df[1]);
} else if(inType == InputSpecialZoom) {
float scale = 1.0f - p1;
ScaleView(scale, scale, hover_img[0], hover_img[1]);
}
// Update hover status (after potential resizing)
ScreenToImage( view.v, x, y, hover_img[0], hover_img[1]);
}
void ImageViewHandler::FixSelection(XYRangef& sel)
{
// Make sure selection matches sign of current viewport
if( (sel.x.min<sel.x.max) != (rview.x.min<rview.x.max) ) {
std::swap(sel.x.min, sel.x.max);
}
if( (sel.y.min<sel.y.max) != (rview.y.min<rview.y.max) ) {
std::swap(sel.y.min, sel.y.max);
}
}
void ImageViewHandler::AdjustScale()
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
if(tv.target.x.AbsSize() > tv.rview_max.x.AbsSize())
tv.target.x.Scale(tv.rview_max.x.AbsSize() / tv.target.x.AbsSize(), tv.target.x.Mid());
if(tv.target.y.AbsSize() > tv.rview_max.y.AbsSize())
tv.target.y.Scale(tv.rview_max.y.AbsSize() / tv.target.y.AbsSize(), tv.target.y.Mid());
}
void ImageViewHandler::AdjustTranslation()
{
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
if( tv.target.x.max > tv.rview_max.x.max) tv.target.x -= tv.target.x.max - tv.rview_max.x.max;
if( tv.target.x.min < tv.rview_max.x.min) tv.target.x -= tv.target.x.min - tv.rview_max.x.min;
if( tv.target.y.max > tv.rview_max.y.max) tv.target.y -= tv.target.y.max - tv.rview_max.y.max;
if( tv.target.y.min < tv.rview_max.y.min) tv.target.y -= tv.target.y.min - tv.rview_max.y.min;
}
float ImageViewHandler::animate_factor = 1.0f / 2.0f;
ImageViewHandler* ImageViewHandler::to_link = 0;
}

View File

@@ -0,0 +1,177 @@
/* 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.
*/
#include <pangolin/image/image_io.h>
#include <fstream>
namespace pangolin {
// PNG
TypedImage LoadPng(std::istream& in);
void SavePng(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, bool top_line_first, int zlib_compression_level );
// JPG
TypedImage LoadJpg(std::istream& in);
void SaveJpg(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, float quality);
// PPM
TypedImage LoadPpm(std::istream& in);
void SavePpm(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, bool top_line_first);
// TGA
TypedImage LoadTga(std::istream& in);
// Pango
TypedImage LoadPango(const std::string& filename);
void SavePango(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first);
// EXR
TypedImage LoadExr(std::istream& source);
void SaveExr(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first);
// ZSTD (https://github.com/facebook/zstd)
TypedImage LoadZstd(std::istream& in);
void SaveZstd(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level);
// https://github.com/lz4/lz4
TypedImage LoadLz4(std::istream& in);
void SaveLz4(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level);
// packed 12 bit image (obtained from unpacked 16bit)
TypedImage LoadPacked12bit(std::istream& in);
void SavePacked12bit(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level);
TypedImage LoadImage(std::istream& in, ImageFileType file_type)
{
switch (file_type) {
case ImageFileTypePng:
return LoadPng(in);
case ImageFileTypeJpg:
return LoadJpg(in);
case ImageFileTypePpm:
return LoadPpm(in);
case ImageFileTypeTga:
return LoadTga(in);
case ImageFileTypeZstd:
return LoadZstd(in);
case ImageFileTypeLz4:
return LoadLz4(in);
case ImageFileTypeP12b:
return LoadPacked12bit(in);
case ImageFileTypeExr:
return LoadExr(in);
default:
throw std::runtime_error("Unable to load image file-type through std::istream");
}
}
TypedImage LoadImage(const std::string& filename, ImageFileType file_type)
{
switch (file_type) {
case ImageFileTypePng:
case ImageFileTypeJpg:
case ImageFileTypePpm:
case ImageFileTypeTga:
case ImageFileTypeZstd:
case ImageFileTypeLz4:
case ImageFileTypeP12b:
case ImageFileTypeExr:
{
std::ifstream ifs(filename, std::ios_base::in|std::ios_base::binary);
return LoadImage(ifs, file_type);
}
case ImageFileTypePango:
return LoadPango(filename);
default:
throw std::runtime_error("Unsupported image file type, '" + filename + "'");
}
}
TypedImage LoadImage(const std::string& filename)
{
ImageFileType file_type = FileType(filename);
return LoadImage( filename, file_type );
}
void SaveImage(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, ImageFileType file_type, bool top_line_first, float quality)
{
switch (file_type) {
case ImageFileTypePng:
// map quality [0..100] to PNG compression levels [0..9]
return SavePng(image, fmt, out, top_line_first, int(quality*0.09));
case ImageFileTypeJpg:
return SaveJpg(image, fmt, out, quality);
case ImageFileTypePpm:
return SavePpm(image,fmt,out,top_line_first);
case ImageFileTypeZstd:
return SaveZstd(image,fmt,out, quality);
case ImageFileTypeLz4:
return SaveLz4(image,fmt,out, quality);
case ImageFileTypeP12b:
return SavePacked12bit(image,fmt,out, quality);
default:
throw std::runtime_error("Unable to save image file-type through std::istream");
}
}
void SaveImage(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, ImageFileType file_type, bool top_line_first, float quality)
{
switch (file_type) {
case ImageFileTypePng:
case ImageFileTypeJpg:
case ImageFileTypePpm:
case ImageFileTypeZstd:
case ImageFileTypeLz4:
case ImageFileTypeP12b:
{
std::ofstream ofs(filename, std::ios_base::binary);
return SaveImage(image, fmt, ofs, file_type, top_line_first, quality);
}
case ImageFileTypeExr:
return SaveExr(image, fmt, filename, top_line_first);
case ImageFileTypePango:
return SavePango(image, fmt, filename, top_line_first);
default:
throw std::runtime_error("Unsupported image file type, '" + filename + "'");
}
}
void SaveImage(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first, float quality)
{
const std::string ext = FileLowercaseExtention(filename);
const ImageFileType file_type = FileTypeExtension(ext);
SaveImage(image, fmt, filename,file_type, top_line_first, quality);
}
void SaveImage(const TypedImage& image, const std::string& filename, bool top_line_first, float quality)
{
SaveImage(image, image.fmt, filename, top_line_first, quality);
}
}

View File

@@ -0,0 +1,188 @@
#include <pangolin/platform.h>
#include <fstream>
#include <pangolin/image/typed_image.h>
#ifdef HAVE_OPENEXR
#include <ImfChannelList.h>
#include <ImfInputFile.h>
#include <ImfOutputFile.h>
#include <ImfIO.h>
#endif // HAVE_OPENEXR
namespace pangolin {
#ifdef HAVE_OPENEXR
Imf::PixelType OpenEXRPixelType(int channel_bits)
{
if( channel_bits == 16 ) {
return Imf::PixelType::HALF;
}else if( channel_bits == 32 ) {
return Imf::PixelType::FLOAT;
}else{
throw std::runtime_error("Unsupported OpenEXR Pixel Type.");
}
}
void SetOpenEXRChannels(Imf::ChannelList& ch, const pangolin::PixelFormat& fmt)
{
const char* CHANNEL_NAMES[] = {"R","G","B","A"};
for(size_t c=0; c < fmt.channels; ++c) {
ch.insert( CHANNEL_NAMES[c], Imf::Channel(OpenEXRPixelType(fmt.channel_bits[c])) );
}
}
class StdIStream: public Imf::IStream
{
public:
StdIStream (std::istream &is):
Imf::IStream ("stream"),
_is (&is)
{
}
virtual bool read (char c[/*n*/], int n)
{
if (!*_is)
throw std::runtime_error("Unexpected end of file.");
_is->read (c, n);
if (_is->gcount() < n)
{
throw std::runtime_error("Early end of file");
return false;
}
return true;
}
virtual Imf::Int64 tellg ()
{
return std::streamoff (_is->tellg());
}
virtual void seekg (Imf::Int64 pos)
{
_is->seekg (pos);
}
virtual void clear ()
{
_is->clear();
}
private:
std::istream * _is;
};
PixelFormat GetPixelFormat(const Imf::Header& header)
{
const Imf::ChannelList &channels = header.channels();
size_t count = 0;
for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i){
const Imf::Channel& channel = i.channel();
if (channel.type != Imf::FLOAT){
throw std::invalid_argument("Currently, only 32-bit float OpenEXR files are supported.");
}
count += 1;
}
switch (count) {
case 1: return PixelFormatFromString("GRAY32F");
case 3: return PixelFormatFromString("RGB96F");
case 4: return PixelFormatFromString("RGBA128F");
default: throw std::invalid_argument("Currently, only 1, 3 or 4-channel OpenEXR files are supported.");
}
}
#endif //HAVE_OPENEXR
TypedImage LoadExr(std::istream& source)
{
#ifdef HAVE_OPENEXR
StdIStream istream(source);
Imf::InputFile file(istream);
PANGO_ENSURE(file.isComplete());
Imath::Box2i dw = file.header().dataWindow();
int width = dw.max.x - dw.min.x + 1;
int height = dw.max.y - dw.min.y + 1;
PixelFormat format = GetPixelFormat(file.header());
TypedImage img(width, height, format);
char *imgBase = (char *) img.ptr - (dw.min.x + dw.min.y * width) * sizeof(float) * format.channels;
Imf::FrameBuffer fb;
const Imf::ChannelList &channels = file.header().channels();
size_t c = 0;
for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i){
fb.insert(i.name(), Imf::Slice(
Imf::FLOAT, imgBase + sizeof(float) * c++,
sizeof(float) * format.channels,
sizeof(float) * format.channels * size_t(width),
1, 1,
0.0));
}
file.setFrameBuffer(fb);
file.readPixels(dw.min.y, dw.max.y);
return img;
#else
PANGOLIN_UNUSED(source);
throw std::runtime_error("Rebuild Pangolin for EXR support.");
#endif //HAVE_OPENEXR
}
void SaveExr(const Image<unsigned char>& image_in, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first)
{
#ifdef HAVE_OPENEXR
ManagedImage<unsigned char> flip_image;
Image<unsigned char> image;
if(top_line_first) {
image = image_in;
}else{
flip_image.Reinitialise(image_in.pitch,image_in.h);
for(size_t y=0; y<image_in.h; ++y) {
std::memcpy(flip_image.RowPtr(y), image_in.RowPtr(y), image_in.pitch);
}
image = flip_image;
}
Imf::Header header (image.w, image.h);
SetOpenEXRChannels(header.channels(), fmt);
Imf::OutputFile file (filename.c_str(), header);
Imf::FrameBuffer frameBuffer;
int ch=0;
size_t ch_bits = 0;
for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it)
{
frameBuffer.insert(
it.name(),
Imf::Slice(
it.channel().type,
(char*)image.ptr + ch_bits/8,
fmt.channel_bits[ch]/8,
image.pitch
)
);
ch_bits += fmt.channel_bits[ch++];
}
file.setFrameBuffer(frameBuffer);
file.writePixels(image.h);
#else
PANGOLIN_UNUSED(image_in);
PANGOLIN_UNUSED(fmt);
PANGOLIN_UNUSED(filename);
PANGOLIN_UNUSED(top_line_first);
throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin.");
#endif // HAVE_OPENEXR
}
}

View File

@@ -0,0 +1,263 @@
#include <algorithm>
#include <fstream>
#include <pangolin/platform.h>
#include <pangolin/image/typed_image.h>
#ifdef HAVE_JPEG
# include <jpeglib.h>
# ifdef _WIN_
// Undef windows Macro polution from jpeglib.h
# undef LoadImage
# endif
#endif // HAVE_JPEG
// Inspired by https://cs.stanford.edu/~acoates/jpegAndIOS.txt
namespace pangolin {
#ifdef HAVE_JPEG
void error_handler(j_common_ptr cinfo) {
char msg[JMSG_LENGTH_MAX];
(*(cinfo->err->format_message)) (cinfo, msg);
throw std::runtime_error(msg);
}
const static size_t PANGO_JPEG_BUF_SIZE = 16384;
struct pango_jpeg_source_mgr {
struct jpeg_source_mgr pub;
std::istream* is;
JOCTET* buffer;
};
static void pango_jpeg_init_source(j_decompress_ptr /*cinfo*/) {
}
static boolean pango_jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
pango_jpeg_source_mgr* src = (pango_jpeg_source_mgr*)cinfo->src;
src->is->read((char*)src->buffer, PANGO_JPEG_BUF_SIZE);
size_t bytes = src->is->gcount();
if (bytes == 0) {
/* Insert a fake EOI marker */
src->buffer[0] = (JOCTET) 0xFF;
src->buffer[1] = (JOCTET) JPEG_EOI;
bytes = 2;
}
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = bytes;
return TRUE;
}
static void pango_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
pango_jpeg_source_mgr* src = (pango_jpeg_source_mgr*)cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long)src->pub.bytes_in_buffer) {
num_bytes -= (long)src->pub.bytes_in_buffer;
pango_jpeg_fill_input_buffer(cinfo);
}
src->pub.next_input_byte += num_bytes;
src->pub.bytes_in_buffer -= num_bytes;
}
}
static void pango_jpeg_term_source(j_decompress_ptr cinfo) {
// must seek backward so that future reads will start at correct place.
pango_jpeg_source_mgr* src = (pango_jpeg_source_mgr*)cinfo->src;
src->is->clear();
src->is->seekg( src->is->tellg() - (std::streampos)src->pub.bytes_in_buffer );
}
static void pango_jpeg_set_source_mgr(j_decompress_ptr cinfo, std::istream& is) {
pango_jpeg_source_mgr* src = nullptr;
if (cinfo->src == 0)
{
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(pango_jpeg_source_mgr));
src = (pango_jpeg_source_mgr*) cinfo->src;
src->buffer = (JOCTET *)(*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_PERMANENT, PANGO_JPEG_BUF_SIZE*sizeof(JOCTET));
}else{
src = (pango_jpeg_source_mgr*) cinfo->src;
}
src->is = &is;
src->pub.init_source = pango_jpeg_init_source;
src->pub.fill_input_buffer = pango_jpeg_fill_input_buffer;
src->pub.skip_input_data = pango_jpeg_skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = pango_jpeg_term_source;
src->pub.bytes_in_buffer = 0;
src->pub.next_input_byte = 0;
}
struct pango_jpeg_destination_mgr {
struct jpeg_destination_mgr pub; /* public fields */
std::ostream* os; /* target stream */
JOCTET * buffer; /* start of buffer */
};
void pango_jpeg_init_destination (j_compress_ptr cinfo) {
pango_jpeg_destination_mgr* dest = (pango_jpeg_destination_mgr*) cinfo->dest;
dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
PANGO_JPEG_BUF_SIZE * sizeof(JOCTET));
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = PANGO_JPEG_BUF_SIZE;
}
boolean pango_jpeg_empty_output_buffer(j_compress_ptr cinfo) {
pango_jpeg_destination_mgr* dest = (pango_jpeg_destination_mgr*)cinfo->dest;
dest->os->write((const char*)dest->buffer, PANGO_JPEG_BUF_SIZE);
if (dest->os->fail()) {
throw std::runtime_error("Couldn't write entire jpeg buffer to stream.");
}
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = PANGO_JPEG_BUF_SIZE;
return TRUE;
}
void pango_jpeg_term_destination (j_compress_ptr cinfo) {
pango_jpeg_destination_mgr* dest = (pango_jpeg_destination_mgr*) cinfo->dest;
size_t datacount = PANGO_JPEG_BUF_SIZE - dest->pub.free_in_buffer;
/* Write any data remaining in the buffer */
if (datacount > 0) {
dest->os->write((const char*)dest->buffer, datacount);
if (dest->os->fail()) {
throw std::runtime_error("Couldn't write remaining jpeg data to stream.");
}
}
dest->os->flush();
}
void pango_jpeg_set_dest_mgr(j_compress_ptr cinfo, std::ostream& os) {
pango_jpeg_destination_mgr* dest;
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(pango_jpeg_destination_mgr));
}
dest = (pango_jpeg_destination_mgr*)cinfo->dest;
dest->pub.init_destination = pango_jpeg_init_destination;
dest->pub.empty_output_buffer = pango_jpeg_empty_output_buffer;
dest->pub.term_destination = pango_jpeg_term_destination;
dest->os = &os;
}
#endif // HAVE_JPEG
TypedImage LoadJpg(std::istream& is) {
#ifdef HAVE_JPEG
TypedImage image;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
// Setup decompression structure
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = error_handler;
jpeg_create_decompress(&cinfo);
pango_jpeg_set_source_mgr(&cinfo, is);
// read info from header.
int r = jpeg_read_header(&cinfo, TRUE);
if (r != JPEG_HEADER_OK) {
throw std::runtime_error("Failed to read JPEG header.");
} else if (cinfo.num_components != 3 && cinfo.num_components != 1) {
throw std::runtime_error("Unsupported number of color components");
} else {
jpeg_start_decompress(&cinfo);
// resize storage if necessary
PixelFormat fmt = PixelFormatFromString(cinfo.output_components == 3 ? "RGB24" : "GRAY8");
image.Reinitialise(cinfo.output_width, cinfo.output_height, fmt);
JSAMPARRAY imageBuffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE,
cinfo.output_width*cinfo.output_components, 1);
for (size_t y = 0; y < cinfo.output_height; y++) {
jpeg_read_scanlines(&cinfo, imageBuffer, 1);
uint8_t* dstRow = (uint8_t*)image.RowPtr(y);
memcpy(dstRow, imageBuffer[0], cinfo.output_width*cinfo.output_components);
}
jpeg_finish_decompress(&cinfo);
}
// clean up.
jpeg_destroy_decompress(&cinfo);
return image;
#else
PANGOLIN_UNUSED(is);
throw std::runtime_error("Rebuild Pangolin for JPEG support.");
#endif // HAVE_JPEG
}
TypedImage LoadJpg(const std::string& filename) {
std::ifstream f(filename);
return LoadJpg(f);
}
void SaveJpg(const Image<unsigned char>& img, const PixelFormat& fmt, std::ostream& os, float quality) {
#ifdef HAVE_JPEG
const int iquality = (int)std::max(std::min(quality, 100.0f),0.0f);
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
if (fmt.channels != 1 && fmt.channels != 3) {
throw std::runtime_error("Unsupported number of image channels.");
}
if (fmt.bpp != 8 && fmt.bpp != 24) {
throw std::runtime_error("Unsupported image depth.");
}
// set up compression structure
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
pango_jpeg_set_dest_mgr(&cinfo, os);
cinfo.image_width = img.w;
cinfo.image_height = img.h;
cinfo.input_components = fmt.channels;
if (fmt.channels == 3) {
cinfo.in_color_space = JCS_RGB;
} else {
cinfo.in_color_space = JCS_GRAYSCALE;
}
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, iquality, (boolean)true);
jpeg_start_compress(&cinfo, (boolean)true);
JSAMPROW row;
while (cinfo.next_scanline < cinfo.image_height) {
row = (JSAMPROW)((char*)img.RowPtr(cinfo.next_scanline));
jpeg_write_scanlines(&cinfo, &row, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
#else
PANGOLIN_UNUSED(img);
PANGOLIN_UNUSED(fmt);
PANGOLIN_UNUSED(os);
PANGOLIN_UNUSED(quality);
throw std::runtime_error("Rebuild Pangolin for JPEG support.");
#endif // HAVE_JPEG
}
void SaveJpg(const Image<unsigned char>& img, const PixelFormat& fmt, const std::string& filename, float quality) {
std::ofstream f(filename);
SaveJpg(img, fmt, f, quality);
}
}

View File

@@ -0,0 +1,86 @@
#include <fstream>
#include <memory>
#include <pangolin/image/typed_image.h>
#ifdef HAVE_LZ4
# include <lz4.h>
#endif
namespace pangolin {
#pragma pack(push, 1)
struct lz4_image_header
{
char magic[3];
char fmt[16];
size_t w, h;
int64_t compressed_size;
};
#pragma pack(pop)
void SaveLz4(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level)
{
#ifdef HAVE_LZ4
const int64_t src_size = image.SizeBytes();
const int64_t max_dst_size = LZ4_compressBound(src_size);
std::unique_ptr<char[]> output_buffer(new char[max_dst_size]);
// Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
// The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
// It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
// An acceleration value of "1" is the same as regular LZ4_compress_default()
// Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
const int64_t compressed_data_size = LZ4_compress_fast((char*)image.ptr, output_buffer.get(), src_size, max_dst_size, compression_level);
if (compressed_data_size < 0)
throw std::runtime_error("A negative result from LZ4_compress_default indicates a failure trying to compress the data.");
if (compressed_data_size == 0)
throw std::runtime_error("A result of 0 for LZ4 means compression worked, but was stopped because the destination buffer couldn't hold all the information.");
lz4_image_header header;
strncpy(header.magic,"LZ4",3);
strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt));
header.w = image.w;
header.h = image.h;
header.compressed_size = compressed_data_size;
out.write((char*)&header, sizeof(header));
out.write(output_buffer.get(), compressed_data_size);
#else
PANGOLIN_UNUSED(image);
PANGOLIN_UNUSED(fmt);
PANGOLIN_UNUSED(out);
PANGOLIN_UNUSED(compression_level);
throw std::runtime_error("Rebuild Pangolin for LZ4 support.");
#endif // HAVE_LZ4
}
TypedImage LoadLz4(std::istream& in)
{
#ifdef HAVE_LZ4
// Read in header, uncompressed
lz4_image_header header;
in.read( (char*)&header, sizeof(header));
TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt));
std::unique_ptr<char[]> input_buffer(new char[header.compressed_size]);
in.read(input_buffer.get(), header.compressed_size);
const int decompressed_size = LZ4_decompress_safe(input_buffer.get(), (char*)img.ptr, header.compressed_size, img.SizeBytes());
if (decompressed_size < 0)
throw std::runtime_error(FormatString("A negative result from LZ4_decompress_safe indicates a failure trying to decompress the data. See exit code (%) for value returned.", decompressed_size));
if (decompressed_size == 0)
throw std::runtime_error("I'm not sure this function can ever return 0. Documentation in lz4.h doesn't indicate so.");
if (decompressed_size != (int)img.SizeBytes())
throw std::runtime_error(FormatString("decompressed size % is not equal to predicted size %", decompressed_size, img.SizeBytes()));
return img;
#else
PANGOLIN_UNUSED(in);
throw std::runtime_error("Rebuild Pangolin for LZ4 support.");
#endif // HAVE_LZ4
}
}

View File

@@ -0,0 +1,85 @@
#include <fstream>
#include <memory>
#include <pangolin/image/typed_image.h>
namespace pangolin {
#pragma pack(push, 1)
struct packed12bit_image_header
{
char magic[4];
char fmt[16];
size_t w, h;
};
#pragma pack(pop)
void SavePacked12bit(const Image<uint8_t>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int /*compression_level*/)
{
if (fmt.bpp != 16) {
throw std::runtime_error("packed12bit currently only supported with 16bit input image");
}
const size_t dest_pitch = (image.w*12)/ 8 + ((image.w*12) % 8 > 0? 1 : 0);
const size_t dest_size = image.h*dest_pitch;
std::unique_ptr<uint8_t[]> output_buffer(new uint8_t[dest_size]);
for(size_t r=0; r<image.h; ++r) {
uint8_t* pout = output_buffer.get() + r*dest_pitch;
uint16_t* pin = (uint16_t*)(image.ptr + r*image.pitch);
const uint16_t* pin_end = (uint16_t*)(image.ptr + (r+1)*image.pitch);
while(pin < pin_end) {
uint32_t val = (*(pin++) & 0x00000FFF);
val |= uint32_t(*(pin++) & 0x00000FFF) << 12;
*(pout++) = uint8_t( val & 0x000000FF);
*(pout++) = uint8_t((val & 0x0000FF00) >> 8);
*(pout++) = uint8_t((val & 0x00FF0000) >> 16);
}
}
packed12bit_image_header header;
strncpy(header.magic,"P12B",4);
strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt));
header.w = image.w;
header.h = image.h;
out.write((char*)&header, sizeof(header));
out.write((char*)output_buffer.get(), dest_size);
}
TypedImage LoadPacked12bit(std::istream& in)
{
// Read in header, uncompressed
packed12bit_image_header header;
in.read((char*)&header, sizeof(header));
TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt));
if (img.fmt.bpp != 16) {
throw std::runtime_error("packed12bit currently only supported with 16bit input image");
}
const size_t input_pitch = (img.w*12)/ 8 + ((img.w*12) % 8 > 0? 1 : 0);
const size_t input_size = img.h*input_pitch;
std::unique_ptr<uint8_t[]> input_buffer(new uint8_t[input_size]);
in.read((char*)input_buffer.get(), input_size);
for(size_t r=0; r<img.h; ++r) {
uint16_t* pout = (uint16_t*)(img.ptr + r*img.pitch);
uint8_t* pin = input_buffer.get() + r*input_pitch;
const uint8_t* pin_end = input_buffer.get() + (r+1)*input_pitch;
while(pin < pin_end) {
uint32_t val = *(pin++);
val |= uint32_t(*(pin++)) << 8;
val |= uint32_t(*(pin++)) << 16;
*(pout++) = uint16_t( val & 0x000FFF);
*(pout++) = uint16_t((val & 0xFFF000) >> 12);
}
}
return img;
}
}

View File

@@ -0,0 +1,62 @@
#include <pangolin/platform.h>
#include <pangolin/image/typed_image.h>
#ifdef BUILD_PANGOLIN_VIDEO
# include <pangolin/video/drivers/pango.h>
# include <pangolin/video/drivers/pango_video_output.h>
#endif
namespace pangolin {
TypedImage LoadPango(const std::string& uri)
{
PANGOLIN_UNUSED(uri);
#ifdef BUILD_PANGOLIN_VIDEO
std::unique_ptr<VideoInterface> video = OpenVideo(uri);
if(!video || video->Streams().size() != 1) {
throw pangolin::VideoException("Wrong number of streams: exactly one expected.");
}
std::unique_ptr<uint8_t[]> buffer( new uint8_t[video->SizeBytes()] );
const StreamInfo& stream_info = video->Streams()[0];
// Grab first image from video
if(!video->GrabNext(buffer.get(), true)) {
throw pangolin::VideoException("Failed to grab image from stream");
}
// Allocate storage for user image to return
TypedImage image(stream_info.Width(), stream_info.Height(), stream_info.PixFormat());
// Copy image data into user buffer.
const Image<unsigned char> img = stream_info.StreamImage(buffer.get());
PANGO_ENSURE(image.pitch <= img.pitch);
for(size_t y=0; y < image.h; ++y) {
std::memcpy(image.RowPtr(y), img.RowPtr(y), image.pitch);
}
return image;
#else
throw std::runtime_error("Video Support not enabled. Please rebuild Pangolin.");
#endif
}
void SavePango(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& uri, bool /*top_line_first*/)
{
PANGOLIN_UNUSED(image);
PANGOLIN_UNUSED(fmt);
PANGOLIN_UNUSED(uri);
#ifdef BUILD_PANGOLIN_VIDEO
std::unique_ptr<VideoOutputInterface> video = OpenVideoOutput(uri);
StreamInfo stream(fmt, image.w, image.h, image.pitch);
video->SetStreams({stream});
video->WriteStreams(image.ptr);
#else
throw std::runtime_error("Video Support not enabled. Please rebuild Pangolin.");
#endif
}
}

View File

@@ -0,0 +1,234 @@
#include <pangolin/platform.h>
#include <fstream>
#include <pangolin/image/image_io.h>
#include <vector>
#ifdef HAVE_PNG
# include <png.h>
#endif // HAVE_PNG
namespace pangolin {
#ifdef HAVE_PNG
PixelFormat PngFormat(png_structp png_ptr, png_infop info_ptr )
{
const png_byte colour = png_get_color_type(png_ptr, info_ptr);
const png_byte depth = png_get_bit_depth(png_ptr, info_ptr);
if( depth == 8 ) {
if( colour == PNG_COLOR_MASK_COLOR ) {
return PixelFormatFromString("RGB24");
} else if( colour == (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) ) {
return PixelFormatFromString("RGBA32");
} else if( colour == PNG_COLOR_MASK_ALPHA ) {
return PixelFormatFromString("Y400A");
} else {
return PixelFormatFromString("GRAY8");
}
}else if( depth == 16 ) {
if( colour == 0 ) {
return PixelFormatFromString("GRAY16LE");
}
}
throw std::runtime_error("Unsupported PNG format");
}
void PNGAPI PngWarningsCallback(png_structp /*png_ptr*/, png_const_charp /*warning_message*/)
{
// Override default behaviour - don't do anything.
}
#define PNGSIGSIZE 8
bool pango_png_validate(std::istream& source)
{
png_byte pngsig[PNGSIGSIZE];
source.read((char*)pngsig, PNGSIGSIZE);
return source.good() && png_sig_cmp(pngsig, 0, PNGSIGSIZE) == 0;
}
void pango_png_stream_read(png_structp pngPtr, png_bytep data, png_size_t length) {
std::istream* s = (std::istream*)png_get_io_ptr(pngPtr);
PANGO_ASSERT(s);
s->read((char*)data, length);
}
void pango_png_stream_write(png_structp pngPtr, png_bytep data, png_size_t length) {
std::ostream* s = (std::ostream*)png_get_io_ptr(pngPtr);
PANGO_ASSERT(s);
s->write((char*)data, length);
}
void pango_png_stream_write_flush(png_structp pngPtr)
{
std::ostream* s = (std::ostream*)png_get_io_ptr(pngPtr);
PANGO_ASSERT(s);
s->flush();
}
#endif // HAVE_PNG
TypedImage LoadPng(std::istream& source)
{
#ifdef HAVE_PNG
//so First, we validate our stream with the validate function I just mentioned
if (!pango_png_validate(source)) {
throw std::runtime_error("Not valid PNG header");
}
//set up initial png structs
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback);
if (!png_ptr) {
throw std::runtime_error( "PNG Init error 1" );
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
throw std::runtime_error( "PNG Init error 2" );
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
throw std::runtime_error( "PNG Init error 3" );
}
png_set_read_fn(png_ptr,(png_voidp)&source, pango_png_stream_read);
png_set_sig_bytes(png_ptr, PNGSIGSIZE);
// Setup transformation options
if( png_get_bit_depth(png_ptr, info_ptr) == 1) {
//Unpack bools to bytes to ease loading.
png_set_packing(png_ptr);
} else if( png_get_bit_depth(png_ptr, info_ptr) < 8) {
//Expand nonbool colour depths up to 8bpp
png_set_expand_gray_1_2_4_to_8(png_ptr);
}
//Get rid of palette, by transforming it to RGB
if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
}
//read the file
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL);
if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) {
throw std::runtime_error( "Interlace not yet supported" );
}
const size_t w = png_get_image_width(png_ptr,info_ptr);
const size_t h = png_get_image_height(png_ptr,info_ptr);
const size_t pitch = png_get_rowbytes(png_ptr, info_ptr);
TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch);
png_bytepp rows = png_get_rows(png_ptr, info_ptr);
for( unsigned int r = 0; r < h; r++) {
memcpy( img.ptr + pitch*r, rows[r], pitch );
}
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return img;
#else
PANGOLIN_UNUSED(source);
throw std::runtime_error("Rebuild Pangolin for PNG support.");
#endif // HAVE_PNG
}
TypedImage LoadPng(const std::string& filename)
{
std::ifstream f(filename);
return LoadPng(f);
}
void SavePng(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& stream, bool top_line_first, int zlib_compression_level)
{
#ifdef HAVE_PNG
// Check image has supported bit depth
for(unsigned int i=1; i < fmt.channels; ++i) {
if( fmt.channel_bits[i] != fmt.channel_bits[0] ) {
throw std::runtime_error("PNG Saving only supported for images where each channel has the same bit depth.");
}
}
png_structp png_ptr;
png_infop info_ptr;
// Initialize write structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
throw std::runtime_error( "PNG Error: Could not allocate write struct." );
}
// Initialize info structure
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
throw std::runtime_error( "PNG Error: Could not allocate info struct." );
}
// Setup Exception handling
if (setjmp(png_jmpbuf(png_ptr))) {
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
throw std::runtime_error( "PNG Error: Error during png creation." );
}
png_set_compression_level(png_ptr, zlib_compression_level);
png_set_write_fn(png_ptr,(png_voidp)&stream, pango_png_stream_write, pango_png_stream_write_flush);
const int bit_depth = fmt.channel_bits[0];
int colour_type;
switch (fmt.channels) {
case 1: colour_type = PNG_COLOR_TYPE_GRAY; break;
case 2: colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
case 3: colour_type = PNG_COLOR_TYPE_RGB; break;
case 4: colour_type = PNG_COLOR_TYPE_RGBA; break;
default:
throw std::runtime_error( "PNG Error: unexpected image channel number");
}
// Write header
png_set_IHDR(
png_ptr, info_ptr, (png_uint_32)image.w, (png_uint_32)image.h, bit_depth, colour_type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
);
// Setup rows to write:
std::vector<png_bytep> rows(image.h);
if(top_line_first) {
for (unsigned int y = 0; y< image.h; y++) {
rows[y] = image.ptr + y*image.pitch;
}
}else{
for (unsigned int y = 0; y< image.h; y++) {
rows[y] = image.ptr + (image.h-1-y)*image.pitch;
}
}
png_set_rows(png_ptr,info_ptr, &rows[0]);
// Write image data: switch to little-endian byte order, to match host.
png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, 0);
// Free resources
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
#else
PANGOLIN_UNUSED(image);
PANGOLIN_UNUSED(fmt);
PANGOLIN_UNUSED(stream);
PANGOLIN_UNUSED(top_line_first);
PANGOLIN_UNUSED(zlib_compression_level);
throw std::runtime_error("Rebuild Pangolin for PNG support.");
#endif // HAVE_PNG
}
}

View File

@@ -0,0 +1,104 @@
#include <fstream>
#include <pangolin/image/typed_image.h>
namespace pangolin {
PixelFormat PpmFormat(const std::string& strType, int num_colours)
{
if(strType == "P5") {
if(num_colours < 256) {
return PixelFormatFromString("GRAY8");
} else {
return PixelFormatFromString("GRAY16LE");
}
}else if(strType == "P6") {
return PixelFormatFromString("RGB24");
}else{
throw std::runtime_error("Unsupported PPM/PGM format");
}
}
void PpmConsumeWhitespaceAndComments(std::istream& in)
{
// TODO: Make a little more general / more efficient
while( in.peek() == ' ' ) in.get();
while( in.peek() == '\n' ) in.get();
while( in.peek() == '#' ) in.ignore(4096, '\n');
}
TypedImage LoadPpm(std::istream& in)
{
// Parse header
std::string ppm_type = "";
int num_colors = 0;
int w = 0;
int h = 0;
in >> ppm_type;
PpmConsumeWhitespaceAndComments(in);
in >> w;
PpmConsumeWhitespaceAndComments(in);
in >> h;
PpmConsumeWhitespaceAndComments(in);
in >> num_colors;
in.ignore(1,'\n');
if(!in.fail() && w > 0 && h > 0) {
TypedImage img(w, h, PpmFormat(ppm_type, num_colors) );
// Read in data
for(size_t r=0; r<img.h; ++r) {
in.read( (char*)img.ptr + r*img.pitch, img.pitch );
}
if(!in.fail()) {
return img;
}
}
throw std::runtime_error("Unable to load PPM file.");
}
void SavePpm(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, bool top_line_first)
{
// Setup header variables
std::string ppm_type = "";
int num_colors = 0;
int w = (int)image.w;
int h = (int)image.h;
if(fmt.format == "GRAY8") {
ppm_type = "P5";
num_colors = 255;
}else if(fmt.format == "GRAY16LE") {
ppm_type = "P5";
num_colors = 65535;
}else if(fmt.format == "RGB24") {
ppm_type = "P6";
num_colors = 255;
}else{
throw std::runtime_error("Unsupported pixel format");
}
// Write header
out << ppm_type;
out << " ";
out << w;
out << " ";
out << h;
out << " ";
out << num_colors;
out << "\n";
// Write out data
if(top_line_first) {
for(size_t r=0; r<image.h; ++r) {
out.write( (char*)image.ptr + r*image.pitch, image.pitch );
}
}else{
for(size_t r=0; r<image.h; ++r) {
out.write( (char*)image.ptr + (image.h-1-r)*image.pitch, image.pitch );
}
}
}
}

View File

@@ -0,0 +1,25 @@
#include <fstream>
#include <pangolin/image/typed_image.h>
namespace pangolin {
TypedImage LoadImage(
const std::string& filename,
const PixelFormat& raw_fmt,
size_t raw_width, size_t raw_height, size_t raw_pitch
) {
TypedImage img(raw_width, raw_height, raw_fmt, raw_pitch);
// Read from file, row at a time.
std::ifstream bFile( filename.c_str(), std::ios::in | std::ios::binary );
for(size_t r=0; r<img.h; ++r) {
bFile.read( (char*)img.ptr + r*img.pitch, img.pitch );
if(bFile.fail()) {
pango_print_warn("Unable to read raw image file to completion.");
break;
}
}
return img;
}
}

View File

@@ -0,0 +1,53 @@
#include <pangolin/platform.h>
#include <pangolin/image/image_io.h>
namespace pangolin {
PixelFormat TgaFormat(int depth, int color_type, int color_map)
{
if(color_map == 0) {
if(color_type == 2) {
// Colour
if(depth == 24) {
return PixelFormatFromString("RGB24");
}else if(depth == 32) {
return PixelFormatFromString("RGBA32");
}
}else if(color_type == 3){
// Greyscale
if(depth == 8) {
return PixelFormatFromString("GRAY8");
}else if(depth == 16) {
return PixelFormatFromString("Y400A");
}
}
}
throw std::runtime_error("Unsupported TGA format");
}
TypedImage LoadTga(std::istream& in)
{
unsigned char type[4];
unsigned char info[6];
in.read((char*)type, 3*sizeof(char));
in.seekg(12);
in.read((char*)info,6*sizeof(char));
const int width = info[0] + (info[1] * 256);
const int height = info[2] + (info[3] * 256);
if(in.good()) {
TypedImage img(width, height, TgaFormat(info[4], type[2], type[1]) );
//read in image data
const size_t data_size = img.h * img.pitch;
in.read((char*)img.ptr, sizeof(char)*data_size);
return img;
}
throw std::runtime_error("Unable to load TGA file");
}
}

View File

@@ -0,0 +1,125 @@
#include <fstream>
#include <memory>
#include <pangolin/image/typed_image.h>
#ifdef HAVE_ZSTD
# include <zstd.h>
#endif
namespace pangolin {
#pragma pack(push, 1)
struct zstd_image_header
{
char magic[4];
char fmt[16];
size_t w, h;
};
#pragma pack(pop)
void SaveZstd(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level)
{
#ifdef HAVE_ZSTD
// Write out header, uncompressed
zstd_image_header header;
strncpy(header.magic,"ZSTD",4);
strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt));
header.w = image.w;
header.h = image.h;
out.write((char*)&header, sizeof(header));
// Write out image data
const size_t output_buffer_size = ZSTD_CStreamOutSize();
std::unique_ptr<char[]> output_buffer(new char[output_buffer_size]);
ZSTD_CStream* const cstream = ZSTD_createCStream();
if (cstream==nullptr) {
throw std::runtime_error("ZSTD_createCStream() error");
}
size_t const initResult = ZSTD_initCStream(cstream, compression_level);
if (ZSTD_isError(initResult)) {
throw std::runtime_error(FormatString("ZSTD_initCStream() error : %", ZSTD_getErrorName(initResult)));
}
const size_t row_size_bytes = (fmt.bpp * image.w)/8;
for(size_t y=0; y < image.h; ++y) {
ZSTD_inBuffer input = { image.RowPtr(y), row_size_bytes, 0 };
while (input.pos < input.size) {
ZSTD_outBuffer output = { output_buffer.get(), output_buffer_size, 0 };
size_t left_to_read = ZSTD_compressStream(cstream, &output , &input);
if (ZSTD_isError(left_to_read)) {
throw std::runtime_error(FormatString("ZSTD_compressStream() error : %", ZSTD_getErrorName(left_to_read)));
}
out.write(output_buffer.get(), output.pos);
}
}
ZSTD_outBuffer output = { output_buffer.get(), output_buffer_size, 0 };
size_t const remainingToFlush = ZSTD_endStream(cstream, &output); /* close frame */
if (remainingToFlush) {
throw std::runtime_error("not fully flushed");
}
out.write(output_buffer.get(), output.pos);
ZSTD_freeCStream(cstream);
#else
PANGOLIN_UNUSED(image);
PANGOLIN_UNUSED(fmt);
PANGOLIN_UNUSED(out);
PANGOLIN_UNUSED(compression_level);
throw std::runtime_error("Rebuild Pangolin for ZSTD support.");
#endif // HAVE_ZSTD
}
TypedImage LoadZstd(std::istream& in)
{
#ifdef HAVE_ZSTD
// Read in header, uncompressed
zstd_image_header header;
in.read( (char*)&header, sizeof(header));
TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt));
const size_t input_buffer_size = ZSTD_DStreamInSize();
std::unique_ptr<char[]> input_buffer(new char[input_buffer_size]);
ZSTD_DStream* dstream = ZSTD_createDStream();
if(!dstream) {
throw std::runtime_error("ZSTD_createDStream() error");
}
size_t read_size_hint = ZSTD_initDStream(dstream);
if (ZSTD_isError(read_size_hint)) {
throw std::runtime_error(FormatString("ZSTD_initDStream() error : % \n", ZSTD_getErrorName(read_size_hint)));
}
// Image represents our fixed buffer.
ZSTD_outBuffer output = { img.ptr, img.SizeBytes(), 0 };
while(read_size_hint)
{
const size_t read = in.readsome(input_buffer.get(), read_size_hint);
ZSTD_inBuffer input = { input_buffer.get(), read, 0 };
while (input.pos < input.size) {
read_size_hint = ZSTD_decompressStream(dstream, &output , &input);
if (ZSTD_isError(read_size_hint)) {
throw std::runtime_error(FormatString("ZSTD_decompressStream() error : %", ZSTD_getErrorName(read_size_hint)));
}
}
}
ZSTD_freeDStream(dstream);
return img;
#else
PANGOLIN_UNUSED(in);
throw std::runtime_error("Rebuild Pangolin for ZSTD support.");
#endif // HAVE_ZSTD
}
}

View File

@@ -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.
*/
#include <pangolin/image/pixel_format.h>
#include <stdexcept>
#include <vector>
namespace pangolin
{
// Not to exceed 8 byte Format code.
const PixelFormat SupportedPixelFormats[] =
{
{"GRAY8", 1, {8}, 8, 8, false},
{"GRAY10", 1, {10}, 10, 10, false},
{"GRAY12", 1, {12}, 12, 12, false},
{"GRAY16LE", 1, {16}, 16, 16, false},
{"GRAY32", 1, {32}, 32, 32, false},
{"Y400A", 2, {8,8}, 16, 8, false},
{"RGB24", 3, {8,8,8}, 24, 8, false},
{"BGR24", 3, {8,8,8}, 24, 8, false},
{"RGB48", 3, {16,16,16}, 48, 16, false},
{"BGR48", 3, {16,16,16}, 48, 16, false},
{"YUYV422", 3, {4,2,2}, 16, 8, false},
{"UYVY422", 3, {4,2,2}, 16, 8, false},
{"RGBA32", 4, {8,8,8,8}, 32, 8, false},
{"BGRA32", 4, {8,8,8,8}, 32, 8, false},
{"RGBA64", 4, {16,16,16,16}, 64, 16, false},
{"BGRA64", 4, {16,16,16,16}, 64, 16, false},
{"GRAY32F", 1, {32}, 32, 32, false},
{"GRAY64F", 1, {64}, 64, 64, false},
{"RGB96F", 3, {32,32,32}, 96, 32, false},
{"RGBA128F", 4, {32,32,32,32}, 128, 32, false},
{"",0,{0,0,0,0},0,0,0}
};
PixelFormat PixelFormatFromString(const std::string& format)
{
for(int i=0; !SupportedPixelFormats[i].format.empty(); ++i)
if(!format.compare(SupportedPixelFormats[i].format))
return SupportedPixelFormats[i];
throw std::runtime_error( std::string("Unknown Format: ") + format);
}
}

View File

@@ -0,0 +1,49 @@
//
// GlTestAppDelegate.m
// gltest
//
// Created by Steven Lovegrove on 30/01/2014.
// Copyright (c) 2014 Steven Lovegrove. All rights reserved.
//
#import <pangolin/ios/PangolinAppDelegate.h>
#import <pangolin/ios/PangolinUIView.h>
@implementation PangolinAppDelegate
@synthesize window=_window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end

View File

@@ -0,0 +1,202 @@
/* 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 <QuartzCore/QuartzCore.h>
#import <pangolin/ios/PangolinUIView.h>
#import <pangolin/ios/PangolinAppDelegate.h>
#include <pangolin/factory/factory_registry.h>
#include <pangolin/pangolin.h>
#include <pangolin/platform.h>
#include <pangolin/gl/glinclude.h>
#include <pangolin/display/display.h>
#include <pangolin/display/display_internal.h>
namespace pangolin
{
extern __thread PangolinGl* context;
}
@implementation PangolinUIView
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (void)setupLayer {
_eaglLayer = (CAEAGLLayer*) self.layer;
_eaglLayer.opaque = YES;
}
- (void)setupContext {
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context) {
NSLog(@"Failed to initialize OpenGLES 2.0 context");
exit(1);
}
if (![EAGLContext setCurrentContext:_context]) {
NSLog(@"Failed to set current OpenGL context");
exit(1);
}
}
- (void)setupRenderBuffer {
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}
- (void)setupDepthBuffer {
glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
const int w = self.frame.size.width * self.contentScaleFactor;
const int h = self.frame.size.height * self.contentScaleFactor;
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h);
}
- (void)setupFrameBuffer {
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
}
- (void)render:(CADisplayLink*)displayLink {
pangolin::glEngine().prog_fixed.Bind();
if(pangolin::context->user_app) {
pangolin::context->user_app->Render();
}
pangolin::RenderViews();
pangolin::PostRender();
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
- (void)setupDisplayLink {
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)setup
{
self.contentScaleFactor = 2;
[self setupLayer];
[self setupContext];
[self setupDepthBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self setupDisplayLink];
pangolin::PangolinCommonInit();
const int w = self.frame.size.width * self.contentScaleFactor;
const int h = self.frame.size.height * self.contentScaleFactor;
pangolin::process::Resize(w,h);
if(pangolin::context->user_app) {
pangolin::context->user_app->Init();
}
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)awakeFromNib
{
[self setup];
}
- (void)dealloc
{
_context = nil;
}
@end
namespace pangolin
{
int LaunchUserApp(UserApp& app)
{
// Create new context
BindToContext("UserApp");
// Reference user application
context->user_app = &app;
// Start IOS Window containing GL Context from which we'll receive events
// These events will be communicated to pangolin::process::... and the UserApp app.
int argc = 1;
char* argv[] = { (char*)"dummy" };
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([PangolinAppDelegate class]));
}
}
// Implement platform agnostic version
void CreateIosWindowAndBind(std::string window_title, int w, int h )
{
throw std::runtime_error("pangolin::CreateWindowAndBind(...) Not supported on this platform");
}
// Implement platform agnostic version
void FinishFrame()
{
throw std::runtime_error("pangolin::FinishFrame() Not supported on this platform");
}
PANGOLIN_REGISTER_FACTORY(IosWindow)
{
struct IosWindowFactory : public FactoryInterface<WindowInterface> {
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
const std::string window_title = uri.Get<std::string>("window_title", "window");
CreateIosWindowAndBind(window_title, 0, 0);
return NULL;
}
};
auto factory = std::make_shared<IosWindowFactory>();
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "ioswindow");
}
}

79
thirdparty/Pangolin/src/log/packet.cpp vendored Normal file
View File

@@ -0,0 +1,79 @@
#include <pangolin/log/packet.h>
namespace pangolin {
Packet::Packet(PacketStream& s, std::unique_lock<std::recursive_mutex>&& lock, std::vector<PacketStreamSource>& srcs)
: _stream(s), lock(std::move(lock))
{
ParsePacketHeader(s, srcs);
}
Packet::Packet(Packet&& o)
: src(o.src), time(o.time), size(o.size), sequence_num(o.sequence_num),
meta(std::move(o.meta)), frame_streampos(o.frame_streampos), _stream(o._stream),
lock(std::move(o.lock)), data_streampos(o.data_streampos), _data_len(o._data_len)
{
o._data_len = 0;
}
Packet::~Packet()
{
ReadRemaining();
}
size_t Packet::BytesRead() const
{
return _stream.tellg() - data_streampos;
}
int Packet::BytesRemaining() const
{
if(_data_len) {
return (int)_data_len - (int)BytesRead();
}else{
return 0;
}
}
void Packet::ParsePacketHeader(PacketStream& s, std::vector<PacketStreamSource>& srcs)
{
size_t json_src = -1;
frame_streampos = s.tellg();
if (s.peekTag() == TAG_SRC_JSON)
{
s.readTag(TAG_SRC_JSON);
json_src = s.readUINT();
picojson::parse(meta, s);
}
s.readTag(TAG_SRC_PACKET);
time = s.readTimestamp();
src = s.readUINT();
PANGO_ENSURE(json_src == size_t(-1) || json_src == src, "Frame preceded by metadata for a mismatched source. Stream may be corrupt.");
PacketStreamSource& src_packet = srcs[src];
size = src_packet.data_size_bytes;
if (!size) {
size = s.readUINT();
}
sequence_num = src_packet.next_packet_id++;
_data_len = size;
data_streampos = s.tellg();
}
void Packet::ReadRemaining()
{
int bytes_left = BytesRemaining();
while(bytes_left > 0 && Stream().good()) {
Stream().skip(bytes_left);
bytes_left = BytesRemaining();
}
}
}

View File

@@ -0,0 +1,146 @@
#include <pangolin/log/packetstream.h>
#include <stdexcept>
namespace pangolin {
size_t PacketStream::readUINT()
{
size_t n = 0;
size_t v = get();
uint32_t shift = 0;
while (good() && (v & 0x80))
{
n |= (v & 0x7F) << shift;
shift += 7;
v = get();
}
if (!good())
return static_cast<size_t>(-1);
return n | (v & 0x7F) << shift;
}
int64_t PacketStream::readTimestamp()
{
int64_t time_us;
read(reinterpret_cast<char*>(&time_us), sizeof(int64_t));
return time_us;
}
pangoTagType PacketStream::readTag()
{
auto r = peekTag();
_tag = 0;
return r;
}
pangoTagType PacketStream::readTag(pangoTagType x)
{
auto r = readTag();
if (r != x)
throw std::runtime_error(("Tag mismatch error: expected tag '" + tagName(r) + "' does not match found tag '" + tagName(x) + "'").c_str());
return r;
}
pangoTagType PacketStream::peekTag()
{
if (!_tag)
{
_tag = 0;
Base::read(reinterpret_cast<char*>(&_tag), TAG_LENGTH);
if (!good())
_tag = TAG_END;
}
return _tag;
}
char PacketStream::get()
{
_tag = 0;
return Base::get();
}
size_t PacketStream::read(char* target, size_t len)
{
_tag = 0;
Base::read(target, len);
return gcount();
}
size_t PacketStream::skip(size_t len)
{
if (seekable()) {
Base::seekg(len, std::ios_base::cur);
} else {
Base::ignore(len);
}
cclear();
return len;
}
std::streampos PacketStream::tellg()
{
if (_tag) {
return Base::tellg() - std::streamoff(TAG_LENGTH);
}else{
return Base::tellg();
}
}
void PacketStream::seekg(std::streampos target)
{
if (seekable()) {
cclear();
Base::seekg(target);
}
}
void PacketStream::seekg(std::streamoff off, std::ios_base::seekdir way)
{
if (seekable()) {
cclear();
Base::seekg(off, way);
}
}
static bool valid(pangoTagType t)
{
switch (t)
{
case TAG_PANGO_SYNC:
case TAG_ADD_SOURCE:
case TAG_SRC_JSON:
case TAG_SRC_PACKET:
case TAG_PANGO_STATS:
case TAG_PANGO_FOOTER:
case TAG_END:
case TAG_PANGO_HDR:
case TAG_PANGO_MAGIC:
return true;
default:
return false;
}
}
pangoTagType PacketStream::syncToTag() //scan through chars one by one until the last three look like a tag
{
peekTag();
char * buffer = reinterpret_cast<char*>(&_tag);
buffer[3] = 0;
do
{
buffer[0] = buffer[1];
buffer[1] = buffer[2];
buffer[2] = get();
}
while (good() && !valid(_tag));
if (!good())
_tag = TAG_END;
return _tag;
}
}

View File

@@ -0,0 +1,425 @@
/* 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.
*/
#include <pangolin/log/packetstream_reader.h>
#include <pangolin/log/packetstream_writer.h>
using std::string;
using std::istream;
using std::ios;
using std::lock_guard;
using std::runtime_error;
using std::ios_base;
using std::streampos;
using std::streamoff;
#include <thread>
#ifndef _WIN_
# include <unistd.h>
#endif
namespace pangolin
{
PacketStreamReader::PacketStreamReader()
: _pipe_fd(-1)
{
}
PacketStreamReader::PacketStreamReader(const std::string& filename)
: _pipe_fd(-1)
{
Open(filename);
}
PacketStreamReader::~PacketStreamReader()
{
Close();
}
void PacketStreamReader::Open(const std::string& filename)
{
std::lock_guard<std::recursive_mutex> lg(_mutex);
Close();
_filename = filename;
_is_pipe = IsPipe(filename);
_stream.open(filename);
if (!_stream.is_open())
throw runtime_error("Cannot open stream.");
for (auto i : PANGO_MAGIC)
{
if (_stream.get() != i)
throw runtime_error("Unrecognised file header.");
if (!_stream.good())
throw runtime_error("Bad stream");
}
ParseHeader();
while (_stream.peekTag() == TAG_ADD_SOURCE) {
ParseNewSource();
}
if(!SetupIndex()) {
FixFileIndex();
}
}
void PacketStreamReader::Close() {
std::lock_guard<std::recursive_mutex> lg(_mutex);
_stream.close();
_sources.clear();
#ifndef _WIN_
if (_pipe_fd != -1) {
close(_pipe_fd);
}
#endif
}
void PacketStreamReader::ParseHeader()
{
_stream.readTag(TAG_PANGO_HDR);
picojson::value json_header;
picojson::parse(json_header, _stream);
// File timestamp
const int64_t start_us = json_header["time_us"].get<int64_t>();
packet_stream_start = SyncTime::TimePoint() + std::chrono::microseconds(start_us);
_stream.get(); // consume newline
}
void PacketStreamReader::ParseNewSource()
{
_stream.readTag(TAG_ADD_SOURCE);
picojson::value json;
picojson::parse(json, _stream);
_stream.get(); // consume newline
const size_t src_id = json[pss_src_id].get<int64_t>();
if(_sources.size() <= src_id) {
_sources.resize(src_id+1);
}
PacketStreamSource& pss = _sources[src_id];
pss.id = src_id;
pss.driver = json[pss_src_driver].get<string>();
pss.uri = json[pss_src_uri].get<string>();
pss.info = json[pss_src_info];
pss.version = json[pss_src_version].get<int64_t>();
pss.data_alignment_bytes = json[pss_src_packet][pss_pkt_alignment_bytes].get<int64_t>();
pss.data_definitions = json[pss_src_packet][pss_pkt_definitions].get<string>();
pss.data_size_bytes = json[pss_src_packet][pss_pkt_size_bytes].get<int64_t>();
}
bool PacketStreamReader::SetupIndex()
{
bool index_good = false;
if (_stream.seekable())
{
// Save current position
std::streampos pos = _stream.tellg();
// Look for footer at end of file (TAG_PANGO_FOOTER + index position).
_stream.seekg(-(static_cast<istream::off_type>(sizeof(uint64_t)) + TAG_LENGTH), ios_base::end);
if (_stream.peekTag() == TAG_PANGO_FOOTER)
{
//parsing the footer returns the index position
_stream.seekg(ParseFooter());
if (_stream.peekTag() == TAG_PANGO_STATS) {
// Read the pre-build index from the file
index_good = ParseIndex();
}
}
// Restore previous location
_stream.clear();
_stream.seekg(pos);
}
return index_good;
}
streampos PacketStreamReader::ParseFooter() //returns position of index.
{
_stream.readTag(TAG_PANGO_FOOTER);
uint64_t index=0;
size_t bytes_read = _stream.read(reinterpret_cast<char*>(&index), sizeof(index));
PANGO_ENSURE(bytes_read == sizeof(index));
return index;
}
bool PacketStreamReader::ParseIndex()
{
_stream.readTag(TAG_PANGO_STATS);
picojson::value json;
picojson::parse(json, _stream);
const bool index_good = json.contains("src_packet_index") && json.contains("src_packet_times");
if (index_good)
{
// This is a two-dimensional serialized array, [source id][sequence number] ---> packet position in stream
const auto& json_index = json["src_packet_index"].get<picojson::array>();
const auto& json_times = json["src_packet_times"].get<picojson::array>();
// We shouldn't have seen more sources than exist in the index
PANGO_ENSURE(_sources.size() <= json_index.size());
PANGO_ENSURE(json_index.size() == json_times.size());
_sources.resize(json_index.size());
// Populate index
for(size_t i=0; i < _sources.size(); ++i) {
PANGO_ENSURE(json_index[i].size() == json_times[i].size());
_sources[i].index.resize(json_index[i].size());
for(size_t f=0; f < json_index[i].size(); ++f) {
_sources[i].index[f].pos = json_index[i][f].get<int64_t>();
_sources[i].index[f].capture_time = json_times[i][f].get<int64_t>();
}
}
}
return index_good;
}
bool PacketStreamReader::GoodToRead()
{
if(!_stream.good()) {
#ifndef _WIN_
if (_is_pipe)
{
if (_pipe_fd == -1) {
_pipe_fd = ReadablePipeFileDescriptor(_filename);
}
if (_pipe_fd != -1) {
// Test whether the pipe has data to be read. If so, open the
// file stream and start reading. After this point, the file
// descriptor is owned by the reader.
if (PipeHasDataToRead(_pipe_fd))
{
close(_pipe_fd);
_pipe_fd = -1;
Open(_filename);
return _stream.good();
}
}
}
#endif
return false;
}
return true;
}
Packet PacketStreamReader::NextFrame()
{
std::unique_lock<std::recursive_mutex> lock(_mutex);
while (GoodToRead())
{
const pangoTagType t = _stream.peekTag();
switch (t)
{
case TAG_PANGO_SYNC:
SkipSync();
break;
case TAG_ADD_SOURCE:
ParseNewSource();
break;
case TAG_SRC_JSON: //frames are sometimes preceded by metadata, but metadata must ALWAYS be followed by a frame from the same source.
case TAG_SRC_PACKET:
return Packet(_stream, std::move(lock), _sources);
case TAG_PANGO_STATS:
ParseIndex();
break;
case TAG_PANGO_FOOTER: //end of frames
case TAG_END:
throw std::runtime_error("PacketStreamReader: end of stream");
case TAG_PANGO_HDR: //shoudln't encounter this
ParseHeader();
break;
case TAG_PANGO_MAGIC: //or this
SkipSync();
break;
default: //or anything else
pango_print_warn("Unexpected packet type: \"%s\". Resyncing()\n", tagName(t).c_str());
ReSync();
break;
}
}
// No frame
throw std::runtime_error("PacketStreamReader: no frame");
}
Packet PacketStreamReader::NextFrame(PacketStreamSourceId src)
{
while (1)
{
// This will throw if nothing is left.
auto fi = NextFrame();
if (fi.src == src) {
return fi;
}
}
}
void PacketStreamReader::RebuildIndex()
{
lock_guard<decltype(_mutex)> lg(_mutex);
if(_stream.seekable()) {
pango_print_warn("Index for '%s' bad / outdated. Rebuilding.\n", _filename.c_str());
// Save current position
std::streampos pos = _stream.tellg();
// Clear existing index
for(PacketStreamSource& s : _sources) {
s.index.clear();
s.next_packet_id = 0;
}
// Read through entire file, updating index
try{
while (1)
{
// This will throw if we've run out of frames
auto fi = NextFrame();
PacketStreamSource& s = _sources[fi.src];
PANGO_ENSURE(s.index.size() == fi.sequence_num);
s.index.push_back({fi.frame_streampos, fi.time});
}
}catch(...){
}
// Reset Packet id's
for(PacketStreamSource& s : _sources) {
s.next_packet_id = 0;
}
// Restore previous location
_stream.clear();
_stream.seekg(pos);
}
}
void PacketStreamReader::AppendIndex()
{
lock_guard<decltype(_mutex)> lg(_mutex);
if(_stream.seekable()) {
// Open file again for append
std::ofstream of(_filename, std::ios::app | std::ios::binary);
if(of.is_open()) {
pango_print_warn("Appending new index to '%s'.\n", _filename.c_str());
uint64_t indexpos = (uint64_t)of.tellp();
writeTag(of, TAG_PANGO_STATS);
SourceStats(_sources).serialize(std::ostream_iterator<char>(of), false);
writeTag(of, TAG_PANGO_FOOTER);
of.write(reinterpret_cast<char*>(&indexpos), sizeof(uint64_t));
}
}
}
void PacketStreamReader::FixFileIndex()
{
if(_stream.seekable())
{
RebuildIndex();
AppendIndex();
}
}
size_t PacketStreamReader::Seek(PacketStreamSourceId src, size_t framenum)
{
lock_guard<decltype(_mutex)> lg(_mutex);
PANGO_ASSERT(_stream.seekable());
PANGO_ASSERT(src < _sources.size());
PacketStreamSource& source = _sources[src];
PANGO_ASSERT(framenum < source.index.size());
if(source.index[framenum].pos > 0) {
_stream.clear();
_stream.seekg(source.index[framenum].pos);
source.next_packet_id = framenum;
}
return source.next_packet_id;
}
// Jumps to the first packet with time >= time
size_t PacketStreamReader::Seek(PacketStreamSourceId src, SyncTime::TimePoint time)
{
PacketStreamSource& source = _sources[src];
PacketStreamSource::PacketInfo v = {
0, std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count()
};
// Find time in indextime
auto lb = std::lower_bound(
source.index.begin(), source.index.end(), v,
[](const PacketStreamSource::PacketInfo& a, const PacketStreamSource::PacketInfo& b){
return a.capture_time < b.capture_time;
}
);
if(lb != source.index.end()) {
const size_t frame_num = lb - source.index.begin();
return Seek(src, frame_num);
}else{
return source.next_packet_id;
}
}
void PacketStreamReader::SkipSync()
{
//Assume we have just read PAN, read GO
if (_stream.get() != 'G' && _stream.get() != 'O')
throw std::runtime_error("Unknown packet type.");
while (_stream.peekTag() != TAG_SRC_PACKET && _stream.peekTag() != TAG_END)
_stream.readTag();
}
}

View File

@@ -0,0 +1,156 @@
/* 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.
*/
#include <pangolin/log/packetstream_writer.h>
#include <pangolin/utils/file_utils.h>
#include <pangolin/utils/timer.h>
using std::ios;
using std::lock_guard;
#define SCOPED_LOCK lock_guard<decltype(_lock)> lg(_lock)
//#define SCOPED_LOCK
namespace pangolin
{
static inline const std::string CurrentTimeStr()
{
time_t time_now = time(0);
struct tm time_struct = *localtime(&time_now);
char buffer[80];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %X", &time_struct);
return buffer;
}
void PacketStreamWriter::WriteHeader()
{
SCOPED_LOCK;
_stream.write(PANGO_MAGIC.c_str(), PANGO_MAGIC.size());
picojson::value pango;
pango["pangolin_version"] = PANGOLIN_VERSION_STRING;
pango["time_us"] = Time_us(TimeNow());
pango["date_created"] = CurrentTimeStr();
pango["endian"] = "little_endian";
writeTag(_stream, TAG_PANGO_HDR);
pango.serialize(std::ostream_iterator<char>(_stream), true);
for (const auto& source : _sources)
Write(source);
}
void PacketStreamWriter::Write(const PacketStreamSource& source)
{
SCOPED_LOCK;
picojson::value serialize;
serialize[pss_src_driver] = source.driver;
serialize[pss_src_id] = source.id;
serialize[pss_src_uri] = source.uri;
serialize[pss_src_info] = source.info;
serialize[pss_src_version] = source.version;
serialize[pss_src_packet][pss_pkt_alignment_bytes] = source.data_alignment_bytes;
serialize[pss_src_packet][pss_pkt_definitions] = source.data_definitions;
serialize[pss_src_packet][pss_pkt_size_bytes] = source.data_size_bytes;
writeTag(_stream, TAG_ADD_SOURCE);
serialize.serialize(std::ostream_iterator<char>(_stream), true);
}
PacketStreamSourceId PacketStreamWriter::AddSource(PacketStreamSource& source)
{
SCOPED_LOCK;
source.id = AddSource(const_cast<const PacketStreamSource&>(source));
return source.id;
}
PacketStreamSourceId PacketStreamWriter::AddSource(const PacketStreamSource& source)
{
SCOPED_LOCK;
PacketStreamSourceId r = _sources.size(); //source id is by vector position, so we must reassign.
_sources.push_back(source);
_sources.back().id = r;
if (_open) //we might be a pipe, in which case we may not be open
Write(_sources.back());
return _sources.back().id;
}
void PacketStreamWriter::WriteMeta(PacketStreamSourceId src, const picojson::value& data)
{
SCOPED_LOCK;
writeTag(_stream, TAG_SRC_JSON);
writeCompressedUnsignedInt(_stream, src);
data.serialize(std::ostream_iterator<char>(_stream), false);
}
void PacketStreamWriter::WriteSourcePacket(PacketStreamSourceId src, const char* source, const int64_t receive_time_us, size_t sourcelen, const picojson::value& meta)
{
SCOPED_LOCK;
_sources[src].index.push_back({_stream.tellp(), receive_time_us});
if (!meta.is<picojson::null>())
WriteMeta(src, meta);
writeTag(_stream, TAG_SRC_PACKET);
writeTimestamp(_stream, receive_time_us);
writeCompressedUnsignedInt(_stream, src);
if (_sources[src].data_size_bytes) {
if (sourcelen != static_cast<size_t>(_sources[src].data_size_bytes))
throw std::runtime_error("oPacketStream::writePacket --> Tried to write a fixed-size packet with bad size.");
} else {
writeCompressedUnsignedInt(_stream, sourcelen);
}
_stream.write(source, sourcelen);
_bytes_written += sourcelen;
}
void PacketStreamWriter::WriteSync()
{
SCOPED_LOCK;
for (unsigned i = 0; i < 10; ++i)
writeTag(_stream, TAG_PANGO_SYNC);
}
void PacketStreamWriter::WriteEnd()
{
SCOPED_LOCK;
if (!_indexable)
return;
auto indexpos = _stream.tellp();
writeTag(_stream, TAG_PANGO_STATS);
SourceStats(_sources).serialize(std::ostream_iterator<char>(_stream), false);
writeTag(_stream, TAG_PANGO_FOOTER);
_stream.write(reinterpret_cast<char*>(&indexpos), sizeof(uint64_t));
}
}

View File

@@ -0,0 +1,26 @@
#include <pangolin/log/playback_session.h>
#include <pangolin/utils/params.h>
namespace pangolin {
std::shared_ptr<PlaybackSession> PlaybackSession::Default()
{
static std::shared_ptr<PlaybackSession> instance = std::make_shared<PlaybackSession>();
return instance;
}
std::shared_ptr<PlaybackSession> PlaybackSession::ChooseFromParams(const Params& params)
{
bool use_ordered_playback = params.Get<bool>("OrderedPlayback", false);
std::shared_ptr<pangolin::PlaybackSession> playback_session;
if(use_ordered_playback)
{
return Default();
}
else
{
return std::make_shared<PlaybackSession>();
}
}
}

287
thirdparty/Pangolin/src/plot/datalog.cpp vendored Normal file
View File

@@ -0,0 +1,287 @@
/* 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 <pangolin/plot/datalog.h>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <stdexcept>
namespace pangolin
{
void DataLogBlock::AddSamples(size_t num_samples, size_t dimensions, const float* data_dim_major )
{
if(nextBlock) {
// If next block exists, add to it instead
nextBlock->AddSamples(num_samples, dimensions, data_dim_major);
}else{
if(dimensions > dim) {
// If dimensions is too high for this block, start a new bigger one
nextBlock = std::unique_ptr<DataLogBlock>(new DataLogBlock(dimensions, max_samples, start_id + samples));
nextBlock->AddSamples(num_samples,dimensions,data_dim_major);
}else{
// Try to copy samples to this block
const size_t samples_to_copy = std::min(num_samples, SampleSpaceLeft());
if(dimensions == dim) {
// Copy entire block all together
std::copy(data_dim_major, data_dim_major + samples_to_copy*dim, sample_buffer.get()+samples*dim);
samples += samples_to_copy;
data_dim_major += samples_to_copy*dim;
}else{
// Copy sample at a time, filling with NaN's where needed.
float* dst = sample_buffer.get();
for(size_t i=0; i< samples_to_copy; ++i) {
std::copy(data_dim_major, data_dim_major + dimensions, dst);
for(size_t ii = dimensions; ii < dim; ++ii) {
dst[ii] = std::numeric_limits<float>::quiet_NaN();
}
dst += dimensions;
data_dim_major += dimensions;
}
samples += samples_to_copy;
}
// // Update Stats
// for(size_t s=0; s < samples_to_copy; ++s) {
// for(size_t d = 0; d < dimensions; ++d) {
// stats[d].Add(data_dim_major[s*dim + d]);
// }
// }
// Copy remaining data to next block (this one is full)
if(samples_to_copy < num_samples) {
nextBlock = std::unique_ptr<DataLogBlock>(new DataLogBlock(dim, max_samples, start_id + Samples()));
nextBlock->AddSamples(num_samples-samples_to_copy, dimensions, data_dim_major);
}
}
}
}
DataLog::DataLog(unsigned int buffer_size)
: block_samples_alloc(buffer_size), block0(nullptr), blockn(nullptr), record_stats(true)
{
}
DataLog::~DataLog()
{
Clear();
}
void DataLog::SetLabels(const std::vector<std::string> & new_labels)
{
std::lock_guard<std::mutex> l(access_mutex);
// Create new labels if needed
for( size_t i= labels.size(); i < new_labels.size(); ++i )
labels.push_back( std::string() );
// Add data to existing plots
for( unsigned int i=0; i<labels.size(); ++i )
labels[i] = new_labels[i];
}
const std::vector<std::string>& DataLog::Labels() const
{
return labels;
}
void DataLog::Log(size_t dimension, const float* vals, unsigned int samples )
{
if(!block0) {
// Create first block
block0 = std::unique_ptr<DataLogBlock>(new DataLogBlock(dimension, block_samples_alloc, 0));
blockn = block0.get();
}
if(record_stats) {
while(stats.size() < dimension) {
stats.push_back( DimensionStats() );
}
for(unsigned int d=0; d<dimension; ++d) {
DimensionStats& ds = stats[d];
for(unsigned int s=0; s<samples; ++s) {
ds.Add(vals[s*dimension+d]);
}
}
}
blockn->AddSamples(samples,dimension,vals);
// Update pointer to most recent block.
while(blockn->NextBlock()) {
blockn = blockn->NextBlock();
}
}
void DataLog::Log(float v)
{
const float vs[] = {v};
Log(1,vs);
}
void DataLog::Log(float v1, float v2)
{
const float vs[] = {v1,v2};
Log(2,vs);
}
void DataLog::Log(float v1, float v2, float v3)
{
const float vs[] = {v1,v2,v3};
Log(3,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4)
{
const float vs[] = {v1,v2,v3,v4};
Log(4,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4, float v5)
{
const float vs[] = {v1,v2,v3,v4,v5};
Log(5,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4, float v5, float v6)
{
const float vs[] = {v1,v2,v3,v4,v5,v6};
Log(6,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7)
{
const float vs[] = {v1,v2,v3,v4,v5,v6,v7};
Log(7,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8)
{
const float vs[] = {v1,v2,v3,v4,v5,v6,v7,v8};
Log(8,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9)
{
const float vs[] = {v1,v2,v3,v4,v5,v6,v7,v8,v9};
Log(9,vs);
}
void DataLog::Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9, float v10)
{
const float vs[] = {v1,v2,v3,v4,v5,v6,v7,v8,v9,v10};
Log(10,vs);
}
void DataLog::Log(const std::vector<float> & vals)
{
Log(vals.size(), &vals[0]);
}
void DataLog::Clear()
{
std::lock_guard<std::mutex> l(access_mutex);
blockn = nullptr;
block0 = nullptr;
stats.clear();
}
void DataLog::Save(std::string filename)
{
std::ofstream csvStream(filename);
if (!Labels().empty()) {
csvStream << Labels()[0];
for (size_t i = 1; i < Labels().size(); ++i) {
csvStream << "," << Labels()[i];
}
csvStream << std::endl;
}
const DataLogBlock * block = FirstBlock();
while (block) {
for (size_t i = 0; i < block->Samples(); ++i) {
csvStream << block->Sample(i)[0];
for (size_t d = 1; d < block->Dimensions(); ++d) {
csvStream << "," << block->Sample(i)[d];
}
csvStream << std::endl;
}
block = block->NextBlock();
}
}
const DataLogBlock* DataLog::FirstBlock() const
{
return block0.get();
}
const DataLogBlock* DataLog::LastBlock() const
{
return blockn;
}
const DimensionStats& DataLog::Stats(size_t dim) const
{
return stats[dim];
}
size_t DataLog::Samples() const
{
if(blockn) {
return blockn->StartId() + blockn->Samples();
}
return 0;
}
const float* DataLog::Sample(int n) const
{
if(block0) {
return block0->Sample(n);
}else{
return 0;
}
}
}

1171
thirdparty/Pangolin/src/plot/plotter.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
/* 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 <Python.h>
#include <pangolin/python/pypangolin_init.h>
#include <pangolin/python/pyinterpreter.h>
#include <pangolin/python/pyuniqueobj.h>
#include <pangolin/python/pypangoio.h>
#include <pangolin/utils/file_utils.h>
namespace pangolin
{
void PyInterpreter::AttachPrefix(void* data, const std::string& name, VarValueGeneric& /*var*/, bool /*brand_new*/ )
{
PyInterpreter* self = (PyInterpreter*)data;
const size_t dot = name.find_first_of('.');
if(dot != std::string::npos) {
const std::string base_prefix = name.substr(0,dot);
if( self->base_prefixes.find(base_prefix) == self->base_prefixes.end() ) {
self->base_prefixes.insert(base_prefix);
std::string cmd =
base_prefix + std::string(" = pypangolin.Var('") +
base_prefix + std::string("')\n");
PyRun_SimpleString(cmd.c_str());
}
}
}
PyInterpreter::PyInterpreter()
: pycompleter(0), pycomplete(0)
{
#if PY_MAJOR_VERSION >= 3
PyImport_AppendInittab("pypangolin", InitPyPangolinModule);
Py_Initialize();
#else
Py_Initialize();
InitPyPangolinModule();
#endif
// Hook stdout, stderr to this interpreter
PyObject* mod_sys = PyImport_ImportModule("sys");
if (mod_sys) {
PyModule_AddObject(mod_sys, "stdout", (PyObject*)new PyPangoIO(
&PyPangoIO::Py_type, line_queue, ConsoleLineTypeStdout
));
PyModule_AddObject(mod_sys, "stderr", (PyObject*)new PyPangoIO(
&PyPangoIO::Py_type, line_queue, ConsoleLineTypeStderr
));
} else {
pango_print_error("Couldn't import module sys.\n");
}
// Attempt to setup readline completion
PyRun_SimpleString(
"import pypangolin\n"
"try:\n"
" import readline\n"
"except ImportError:\n"
" import pyreadline as readline\n"
"\n"
"import rlcompleter\n"
"pypangolin.completer = rlcompleter.Completer()\n"
);
CheckPrintClearError();
// Get reference to rlcompleter.Completer() for tab-completion
PyObject* mod_pangolin = PyImport_ImportModule("pypangolin");
if(mod_pangolin) {
pycompleter = PyObject_GetAttrString(mod_pangolin,"completer");
if(pycompleter) {
pycomplete = PyObject_GetAttrString(pycompleter,"complete");
}
} else {
pango_print_error("PyInterpreter: Unable to load module pangolin.\n");
}
// Hook namespace prefixes into Python
RegisterNewVarCallback(&PyInterpreter::AttachPrefix, (void*)this, "");
ProcessHistoricCallbacks(&PyInterpreter::AttachPrefix, (void*)this, "");
CheckPrintClearError();
}
PyInterpreter::~PyInterpreter()
{
Py_Finalize();
}
std::string PyInterpreter::ToString(PyObject* py)
{
PyUniqueObj pystr = PyObject_Repr(py);
#if PY_MAJOR_VERSION >= 3
return std::string(PyUnicode_AsUTF8(pystr));
#else
return std::string(PyString_AsString(pystr));
#endif
}
void PyInterpreter::CheckPrintClearError()
{
if(PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
}
PyUniqueObj PyInterpreter::EvalExec(const std::string& cmd)
{
PyObject* globals = PyModule_GetDict(PyImport_AddModule("__main__"));
#if PY_MAJOR_VERSION >= 3
PyObject* builtin = PyImport_AddModule("builtins");
#else
PyObject* builtin = PyImport_AddModule("__builtin__");
#endif
if(globals && builtin) {
PyUniqueObj compile = PyObject_GetAttrString(builtin, "compile");
PyUniqueObj eval = PyObject_GetAttrString(builtin, "eval");
if(compile && eval)
{
PyErr_Clear();
PyUniqueObj compile_eval_args = Py_BuildValue("(sss)", cmd.c_str(), "<string>", "eval" );
if(compile_eval_args)
{
PyUniqueObj code = PyObject_Call(compile, compile_eval_args, 0);
if(code) {
PyUniqueObj eval_args = Py_BuildValue("(OOO)", *code, globals, globals );
if(eval_args) {
PyUniqueObj ret = PyObject_Call(eval, eval_args, 0);
CheckPrintClearError();
return ret;
}
}
}
PyErr_Clear();
PyUniqueObj compile_exec_args = Py_BuildValue("(sss)", cmd.c_str(), "<string>", "exec" );
if(compile_exec_args)
{
PyUniqueObj code = PyObject_Call(compile, compile_exec_args, 0);
if(code) {
PyUniqueObj eval_args = Py_BuildValue("(OOO)", *code, globals, globals );
if(eval_args) {
PyUniqueObj ret = PyObject_Call(eval, eval_args, 0);
CheckPrintClearError();
return ret;
}
}
}
}
}
CheckPrintClearError();
return PyUniqueObj();
}
std::vector<std::string> PyInterpreter::Complete(const std::string& cmd, int max_options)
{
std::vector<std::string> ret;
PyErr_Clear();
if(pycomplete) {
for(int i=0; i < max_options; ++i) {
#if PY_MAJOR_VERSION >= 3
PyUniqueObj args = PyTuple_Pack( 2, PyUnicode_FromString(cmd.c_str()), PyLong_FromSize_t(i) );
PyUniqueObj result = PyObject_CallObject(pycomplete, args);
if (result && PyUnicode_Check(result)) {
std::string res_str(PyUnicode_AsUTF8(result));
#else
PyUniqueObj args = PyTuple_Pack(2, PyString_FromString(cmd.c_str()), PyInt_FromSize_t(i));
PyUniqueObj result = PyObject_CallObject(pycomplete, args);
if (result && PyString_Check(result)) {
std::string res_str(PyString_AsString(result));
#endif
if( res_str.find("__")==std::string::npos ||
cmd.find("__")!=std::string::npos ||
(cmd.size() > 0 && cmd[cmd.size()-1] == '_')
) {
ret.push_back( res_str );
}
}else{
break;
}
}
}
return ret;
}
void PyInterpreter::PushCommand(const std::string& cmd)
{
PyUniqueObj obj = EvalExec(cmd);
if(obj && obj != Py_None) {
const std::string output = ToString(obj);
line_queue.push(
ConsoleLine(output, ConsoleLineTypeOutput)
);
}
}
bool PyInterpreter::PullLine(ConsoleLine& line)
{
if(line_queue.size()) {
line = line_queue.front();
line_queue.pop();
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,48 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "attach.hpp"
#include <pangolin/gl/glinclude.h>
#include <pangolin/display/attach.h>
namespace py_pangolin {
void bind_attach(pybind11::module &m){
pybind11::enum_<pangolin::Unit>(m, "Unit")
.value("Fraction", pangolin::Unit::Fraction)
.value("Pixel", pangolin::Unit::Pixel)
.value("ReversePixel", pangolin::Unit::ReversePixel)
.export_values();
pybind11::class_<pangolin::Attach>(m, "Attach")
.def(pybind11::init<>())
.def(pybind11::init<pangolin::Unit, GLfloat>())
.def(pybind11::init<GLfloat>())
.def_static("Pix", &pangolin::Attach::Pix)
.def_static("ReversePix", &pangolin::Attach::ReversePix)
.def_static("Frac", &pangolin::Attach::Frac);
}
}

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_attach(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,48 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "colour.hpp"
#include <pangolin/gl/colour.h>
namespace py_pangolin {
void bind_colour(pybind11::module& m){
pybind11::class_<pangolin::Colour> (m, "Colour")
.def(pybind11::init<>())
.def(pybind11::init<const float, const float, const float, const float>(), pybind11::arg("red"), pybind11::arg("green"), pybind11::arg("blue"), pybind11::arg("alpha")=1.0f)
// .def(pybind11::init<float[4]>())
.def("Get", &pangolin::Colour::Get)
.def_static("White", &pangolin::Colour::White)
.def_static("Black", &pangolin::Colour::Black)
.def_static("Red", &pangolin::Colour::Red)
.def_static("Green", &pangolin::Colour::Green)
.def_static("Blue", &pangolin::Colour::Blue)
.def_static("Hsv", &pangolin::Colour::Hsv)
.def("WithAlpha", &pangolin::Colour::WithAlpha);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_colour(pybind11::module& m);
} // py_pangolin

View File

@@ -0,0 +1,86 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "datalog.hpp"
#include <pybind11/stl.h>
#include <pangolin/plot/datalog.h>
namespace py_pangolin {
void bind_datalog(pybind11::module& m){
pybind11::class_<pangolin::DimensionStats >(m, "DimensionStats")
.def(pybind11::init<>())
.def("Reset", &pangolin::DimensionStats::Reset)
.def("Add", &pangolin::DimensionStats::Add)
.def_readwrite("isMonotonic", &pangolin::DimensionStats::isMonotonic)
.def_readwrite("sum", &pangolin::DimensionStats::sum)
.def_readwrite("sum_sq", &pangolin::DimensionStats::sum_sq)
.def_readwrite("min", &pangolin::DimensionStats::min)
.def_readwrite("max", &pangolin::DimensionStats::max);
pybind11::class_<pangolin::DataLogBlock>(m, "DataLogBlock")
.def(pybind11::init<size_t,size_t,size_t>())
.def("Samples", &pangolin::DataLogBlock::Samples)
.def("MaxSamples", &pangolin::DataLogBlock::MaxSamples)
.def("SampleSpaceLeft", &pangolin::DataLogBlock::SampleSpaceLeft)
.def("IsFull", &pangolin::DataLogBlock::IsFull)
.def("AddSamples", &pangolin::DataLogBlock::AddSamples)
.def("ClearLinked", &pangolin::DataLogBlock::ClearLinked)
.def("NextBlock", &pangolin::DataLogBlock::NextBlock)
.def("StartId", &pangolin::DataLogBlock::StartId)
.def("DimData", &pangolin::DataLogBlock::DimData)
.def("Dimensions", &pangolin::DataLogBlock::Dimensions)
.def("Sample", &pangolin::DataLogBlock::Sample)
.def("StartId", &pangolin::DataLogBlock::StartId);
pybind11::class_<pangolin::DataLog>(m, "DataLog")
.def(pybind11::init<unsigned int>(), pybind11::arg("block_samples_alloc")=10000)
.def("SetLabels", &pangolin::DataLog::SetLabels)
.def("Labels", &pangolin::DataLog::Labels)
.def("Log", (void (pangolin::DataLog::*)(size_t, const float*, unsigned int))&pangolin::DataLog::Log, pybind11::arg("dimension"), pybind11::arg("vals"), pybind11::arg("samples")=1)
.def("Log", (void (pangolin::DataLog::*)(float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float, float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float, float, float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(float, float, float, float, float, float, float, float, float, float))&pangolin::DataLog::Log)
.def("Log", (void (pangolin::DataLog::*)(const std::vector<float>&))&pangolin::DataLog::Log)
.def("Clear", &pangolin::DataLog::Clear)
.def("Save", &pangolin::DataLog::Save)
.def("FirstBlock", &pangolin::DataLog::FirstBlock)
.def("LastBlock", &pangolin::DataLog::LastBlock)
.def("Samples", &pangolin::DataLog::Samples)
.def("Sample", &pangolin::DataLog::Sample)
.def("Stats", &pangolin::DataLog::Stats);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_datalog(pybind11::module& m);
} // py_pangolin

View File

@@ -0,0 +1,81 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "display.hpp"
#include <pangolin/display/display.h>
#include <pangolin/display/view.h>
#include <pybind11/functional.h>
namespace py_pangolin {
void bind_display(pybind11::module &m) {
m.def("CreateWindowAndBind",
&pangolin::CreateWindowAndBind,
pybind11::return_value_policy::reference,
pybind11::arg("window_title"),
pybind11::arg("w") = 640,
pybind11::arg("h") = 480,
pybind11::arg("params") = pangolin::Params());
m.def("DestroyWindow",
&pangolin::DestroyWindow,
pybind11::arg("window_title"));
m.def("CreateDisplay",
&pangolin::CreateDisplay,
pybind11::return_value_policy::reference);
m.def("ShouldQuit",
&pangolin::ShouldQuit);
m.def("FinishFrame",
&pangolin::FinishFrame);
m.def("ToggleFullscreen",
&pangolin::ToggleFullscreen);
m.def("ToggleConsole",
&pangolin::ToggleConsole);
m.def("RegisterKeyPressCallback",
[](int v, const std::function<void()>& f){
pangolin::RegisterKeyPressCallback(v, f);
}
);
m.def("DisplayBase",
&pangolin::DisplayBase,
pybind11::return_value_policy::reference);
m.def("Display",
&pangolin::Display,
pybind11::return_value_policy::reference,
pybind11::arg("name"));
}
} // Py_pangolin

View File

@@ -0,0 +1,36 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_display(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,102 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "gl.hpp"
#include <pangolin/gl/gl.h>
#include <pybind11/numpy.h>
namespace py_pangolin {
bool is_packed(const pybind11::buffer_info & info) {
int next_expected_stride = info.itemsize;
for (int i = info.ndim-1; i >= 0; --i) {
if (!(info.strides[i] == next_expected_stride)) {
return false;
}
next_expected_stride *= info.shape[i];
}
return true;
}
void bind_gl(pybind11::module &m) {
pybind11::class_<pangolin::GlTexture>(m, "GlTexture")
.def(pybind11::init<>())
.def(pybind11::init<GLint, GLint, GLint, bool, int, GLenum, GLenum>(), pybind11::arg("width"), pybind11::arg("height"), pybind11::arg("internal_format") = GL_RGBA8, pybind11::arg("sampling_linear") = true, pybind11::arg("border") = 0, pybind11::arg("glformat") = GL_RGBA, pybind11::arg("gltype") = GL_UNSIGNED_BYTE)
.def("Upload", [](pangolin::GlTexture & texture, pybind11::buffer b, GLenum data_format, GLenum type){
pybind11::buffer_info info = b.request();
texture.Upload(info.ptr, data_format, type);
})
.def("Download", [](pangolin::GlTexture & texture, pybind11::buffer b, GLenum data_layout, GLenum data_type) {
pybind11::buffer_info info = b.request();
if (!is_packed(info)) {
throw std::runtime_error("cannot Download into non-packed buffer");
}
texture.Download(info.ptr, data_layout, data_type);
})
.def("Save", &pangolin::GlTexture::Save, pybind11::arg("filename"), pybind11::arg("top_line_first")=true)
.def("RenderToViewport", (void (pangolin::GlTexture::*)() const)&pangolin::GlTexture::RenderToViewport)
.def("RenderToViewportFlipY", &pangolin::GlTexture::RenderToViewportFlipY)
.def("SetNearestNeighbour", &pangolin::GlTexture::SetNearestNeighbour);
pybind11::class_<pangolin::GlRenderBuffer>(m, "GlRenderBuffer")
.def(pybind11::init<GLint, GLint, GLint>(), pybind11::arg("width")=0, pybind11::arg("height")=0, pybind11::arg("internal_format") = GL_DEPTH_COMPONENT24)
.def("Reinitialise", &pangolin::GlRenderBuffer::Reinitialise);
pybind11::class_<pangolin::GlFramebuffer>(m, "GlFramebuffer")
.def(pybind11::init<pangolin::GlTexture &, pangolin::GlRenderBuffer &>())
.def("Bind", &pangolin::GlFramebuffer::Bind)
.def("Unbind", &pangolin::GlFramebuffer::Unbind);
pybind11::enum_<pangolin::GlBufferType>(m, "GlBufferType")
.value("GlUndefined", pangolin::GlBufferType::GlUndefined)
.value("GlArrayBuffer", pangolin::GlBufferType::GlArrayBuffer)
.value("GlElementArrayBuffer", pangolin::GlBufferType::GlElementArrayBuffer)
#ifndef HAVE_GLES
.value("GlPixelPackBuffer", pangolin::GlBufferType::GlPixelPackBuffer)
.value("GlPixelUnpackBuffer", pangolin::GlBufferType::GlPixelUnpackBuffer)
.value("GlShaderStorageBuffer", pangolin::GlBufferType::GlShaderStorageBuffer)
#endif
.export_values();
pybind11::class_<pangolin::GlBufferData>(m, "GlBufferData")
.def(pybind11::init<>())
.def("Reinitialise", [](pangolin::GlBufferData & gl_buffer, pangolin::GlBufferType buffer_type, GLuint size_bytes, GLenum gl_use) {
gl_buffer.Reinitialise(buffer_type, size_bytes, gl_use);
})
.def("Bind", &pangolin::GlBufferData::Bind)
.def("Unbind", &pangolin::GlBufferData::Unbind)
.def("Upload", [](pangolin::GlBufferData & gl_buffer, pybind11::buffer b, GLsizeiptr size_bytes, GLintptr offset) {
pybind11::buffer_info info = b.request();
gl_buffer.Upload(info.ptr, size_bytes, offset);
}, pybind11::arg("data"), pybind11::arg("size_bytes"), pybind11::arg("offset")=0)
.def_readwrite("size_bytes", &pangolin::GlBufferData::size_bytes);
}
} // namespace py_pangolin

View File

@@ -0,0 +1,36 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_gl(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,71 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "gl_draw.hpp"
#include <pangolin/gl/gldraw.h>
#include <pybind11/eigen.h>
namespace py_pangolin {
void bind_gl_draw(pybind11::module &m){
m.def("glDrawAxis",
(void (*)(float))&pangolin::glDrawAxis);
m.def("glDrawColouredCube",
&pangolin::glDrawColouredCube,
pybind11::arg("axis_min") = -0.5f,
pybind11::arg("axis_max") = +0.5f);
m.def("glDraw_x0",
&pangolin::glDraw_x0);
m.def("glDraw_y0",
&pangolin::glDraw_y0);
m.def("glDraw_z0",
&pangolin::glDraw_z0);
m.def("glDrawFrustum", (void (*)(GLfloat, GLfloat, GLfloat, GLfloat, int, int, GLfloat)) &pangolin::glDrawFrustum);
m.def("glDrawFrustum", (void (*)(const Eigen::Matrix3f &, int, int, GLfloat)) &pangolin::glDrawFrustum<float>);
m.def("glDrawFrustum", (void (*)(const Eigen::Matrix3d &, int, int, GLfloat)) &pangolin::glDrawFrustum<double>);
m.def("glDrawFrustum", (void (*)(const Eigen::Matrix3f &, int, int, const Eigen::Matrix4f &, float)) &pangolin::glDrawFrustum<float>);
m.def("glDrawFrustum", (void (*)(const Eigen::Matrix3d &, int, int, const Eigen::Matrix4d &, double)) &pangolin::glDrawFrustum<double>);
m.def("glDrawAxis", (void (*)(float)) &pangolin::glDrawAxis);
m.def("glDrawAxis", (void (*)(const Eigen::Matrix4f &, float)) &pangolin::glDrawAxis<Eigen::Matrix4f, float>);
m.def("glDrawAxis", (void (*)(const Eigen::Matrix4d &, float)) &pangolin::glDrawAxis<Eigen::Matrix4d, float>);
m.def("glSetFrameOfReference", (void (*)(const Eigen::Matrix4f &)) &pangolin::glSetFrameOfReference);
m.def("glSetFrameOfReference", (void (*)(const Eigen::Matrix4d &)) &pangolin::glSetFrameOfReference);
m.def("glUnsetFrameOfReference", &pangolin::glUnsetFrameOfReference);
m.def("glDrawAlignedBox", (void (*)(const Eigen::AlignedBox2f &, GLenum)) &pangolin::glDrawAlignedBox<float>, pybind11::arg("box"), pybind11::arg("mode") = GL_TRIANGLE_FAN);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_gl_draw(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,72 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "glsl.hpp"
#include <pangolin/gl/glsl.h>
#include <pybind11/eigen.h>
#include <pybind11/stl.h>
namespace py_pangolin {
void bind_glsl(pybind11::module &m) {
pybind11::enum_<pangolin::GlSlShaderType>(m, "GlSlShaderType")
.value("GlSlAnnotatedShader", pangolin::GlSlShaderType::GlSlAnnotatedShader)
.value("GlSlFragmentShader", pangolin::GlSlShaderType::GlSlFragmentShader)
.value("GlSlVertexShader", pangolin::GlSlShaderType::GlSlVertexShader)
.value("GlSlGeometryShader", pangolin::GlSlShaderType::GlSlGeometryShader)
.value("GlSlComputeShader", pangolin::GlSlShaderType::GlSlComputeShader)
.export_values();
pybind11::class_<pangolin::GlSlProgram>(m, "GlSlProgram")
.def(pybind11::init<>())
.def("AddShader", &pangolin::GlSlProgram::AddShader, pybind11::arg("shader_type"), pybind11::arg("filename"), pybind11::arg("program_defines")=std::map<std::string,std::string>(), pybind11::arg("search_path")=std::vector<std::string>())
.def("AddShaderFromFile", &pangolin::GlSlProgram::AddShaderFromFile)
.def("Link", &pangolin::GlSlProgram::Link)
.def("GetAttributeHandle", &pangolin::GlSlProgram::GetAttributeHandle)
.def("GetUniformHandle", &pangolin::GlSlProgram::GetUniformHandle)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, int))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, int, int))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, int, int, int))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, int, int, int, int))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, float))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, float, float))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, float, float, float))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, float, float, float, float))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, const pangolin::OpenGlMatrix &))&pangolin::GlSlProgram::SetUniform)
#ifdef HAVE_EIGEN
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, const Eigen::Matrix3f &))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, const Eigen::Matrix4f &))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, const Eigen::Matrix3d &))&pangolin::GlSlProgram::SetUniform)
.def("SetUniform", (void (pangolin::GlSlProgram::*)(const std::string &, const Eigen::Matrix4d &))&pangolin::GlSlProgram::SetUniform)
#endif
.def("Bind", &pangolin::GlSlProgram::Bind)
.def("Unbind", &pangolin::GlSlProgram::Unbind);
}
}

View File

@@ -0,0 +1,36 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_glsl(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,58 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "handler.hpp"
#include <pangolin/handler/handler.h>
#include <pangolin/display/opengl_render_state.h>
#include <pangolin/plot/plotter.h>
namespace py_pangolin {
void bind_handler(pybind11::module &m) {
pybind11::class_<pangolin::Handler, PyHandler> handler(m, "Handler");
handler
.def(pybind11::init<>())
.def("Keyboard", &pangolin::Handler::Keyboard)
.def("Mouse", &pangolin::Handler::Mouse)
.def("MouseMotion", &pangolin::Handler::MouseMotion)
.def("PassiveMouseMotion", &pangolin::Handler::PassiveMouseMotion)
.def("Special", &pangolin::Handler::Special);
pybind11::class_<pangolin::Handler3D>(m, "Handler3D", handler)
.def(pybind11::init<pangolin::OpenGlRenderState&, pangolin::AxisDirection, float, float>(), pybind11::arg("state"), pybind11::arg("enforce_up") = pangolin::AxisNone, pybind11::arg("trans_scale")=0.01f, pybind11::arg("zoom_factor")=PANGO_DFLT_HANDLER3D_ZF)
.def("ValidWinDepth", &pangolin::Handler3D::ValidWinDepth)
.def("PixelUnproject", &pangolin::Handler3D::PixelUnproject)
.def("GetPosNormal", &pangolin::Handler3D::GetPosNormal)
.def("Keyboard", &pangolin::Handler3D::Keyboard)
.def("Mouse", &pangolin::Handler3D::Mouse)
.def("MouseMotion", &pangolin::Handler3D::MouseMotion)
.def("Special", &pangolin::Handler3D::Special);
}
} // py_pangolin

View File

@@ -0,0 +1,62 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
#include <pangolin/handler/handler.h>
#include <pangolin/display/view.h>
namespace py_pangolin {
class PyHandler : public pangolin::Handler {
public:
using pangolin::Handler::Handler;
void Keyboard(pangolin::View& v, unsigned char key, int x, int y, bool pressed) override {
PYBIND11_OVERLOAD(void, pangolin::Handler, Keyboard, v, key, x, y, pressed);
}
void Mouse(pangolin::View& v, pangolin::MouseButton button, int x, int y, bool pressed, int button_state) override {
PYBIND11_OVERLOAD(void, pangolin::Handler, Mouse, v, button, x, y, pressed, button_state);
}
void MouseMotion(pangolin::View& v, int x, int y, int button_state) override {
PYBIND11_OVERLOAD(void, pangolin::Handler, MouseMotion, v, x, y, button_state);
}
void PassiveMouseMotion(pangolin::View& v, int x, int y, int button_state) override {
PYBIND11_OVERLOAD(void, pangolin::Handler, PassiveMouseMotion, v, x, y, button_state);
}
void Special(pangolin::View& v, pangolin::InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state) override{
PYBIND11_OVERLOAD(void, pangolin::Handler, Special, v, inType, x, y, p1, p2, p3, p4, button_state);
}
};
void bind_handler(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,34 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "image.hpp"
#include <pangolin/image/image.h>
namespace py_pangolin {
} // py_pangolin

View File

@@ -0,0 +1,67 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
#include <pangolin/image/image.h>
namespace py_pangolin {
template<typename T>
void bind_image(pybind11::module& m, const std::string& pyname){
pybind11::class_<pangolin::Image<T> >(m, pyname.c_str())
.def(pybind11::init<>())
.def(pybind11::init<T*, size_t, size_t, size_t>())
.def("SizeBytes", &pangolin::Image<T>::SizeBytes)
.def("Area", &pangolin::Image<T>::Area)
.def("IsValid", &pangolin::Image<T>::IsValid)
.def("IsContiguous", &pangolin::Image<T>::IsContiguous)
.def("begin", (unsigned char* (pangolin::Image<T>::*)())&pangolin::Image<T>::begin)
.def("end", (unsigned char* (pangolin::Image<T>::*)())&pangolin::Image<T>::end)
.def("begin", (const unsigned char* (pangolin::Image<T>::*)() const )&pangolin::Image<T>::begin)
.def("end", (const unsigned char* (pangolin::Image<T>::*)() const )&pangolin::Image<T>::end)
.def("size", &pangolin::Image<T>::size)
.def("Fill", &pangolin::Image<T>::Fill)
.def("Replace", &pangolin::Image<T>::Replace)
.def("Memset", &pangolin::Image<T>::Memset)
.def("CopyFrom", &pangolin::Image<T>::CopyFrom)
.def("MinMax", &pangolin::Image<T>::MinMax)
// .def("Sum", [](pangolin::Image<T>& v){ return v.Sum();})
// .def("Mean", [](pangolin::Image<T>& v){ return v.Mean();})
.def("RowPtr", (T* (pangolin::Image<T>::*)(size_t))&pangolin::Image<T>::RowPtr)
.def("RowPtr", (const T* (pangolin::Image<T>::*)(size_t) const )&pangolin::Image<T>::RowPtr)
.def("InImage", &pangolin::Image<T>::InImage)
.def("InBounds", (bool (pangolin::Image<T>::*)(int, int) const)&pangolin::Image<T>::InBounds)
.def("InBounds", (bool (pangolin::Image<T>::*)(float, float, float) const)&pangolin::Image<T>::InBounds)
// .def("SubImage", (pangolin::Image<T> (pangolin::Image<T>::*)(size_t, size_t, size_t, size_t))&pangolin::Image<T>::SubImage)
// .def("Row", &pangolin::Image<T>::Row)
// .def("Col", &pangolin::Image<T>::Col)
.def("InImage", &pangolin::Image<T>::InImage);
}
} // py_pangolin

View File

@@ -0,0 +1,50 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 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 "image_view.hpp"
#include <pangolin/display/image_view.h>
#include <pybind11/numpy.h>
namespace py_pangolin {
void bind_image_view(pybind11::module &m) {
using namespace pangolin;
pybind11::class_<ImageView, View>(m, "ImageView")
.def(pybind11::init<>())
.def("SetImage", [](ImageView& view, pybind11::array_t<float>& img) -> ImageView&{
if(img.ndim() == 2) {
Image<uint8_t> wrapper((uint8_t*)img.mutable_data(0,0), img.shape(1), img.shape(0), img.shape(1) * sizeof(float));
return view.SetImage(wrapper, GlPixFormat(PixelFormatFromString("GRAY32F")) );
}else if(img.ndim() == 3 && img.shape()[2] == 3) {
Image<uint8_t> wrapper((uint8_t*)img.mutable_data(0,0), img.shape(1), img.shape(0), 3 * img.shape(1) * sizeof(float));
return view.SetImage(wrapper, GlPixFormat(PixelFormatFromString("RGB96F")) );
}else{
throw std::runtime_error("Unsupported format for now.");
}
});
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 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 <pybind11/pybind11.h>
namespace py_pangolin{
void bind_image_view(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,116 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "opengl_render_state.hpp"
#include <pangolin/display/opengl_render_state.h>
#include <pybind11/eigen.h>
#include <pybind11/operators.h>
#include <pybind11/numpy.h>
namespace py_pangolin {
void bind_opengl_render_state(pybind11::module &m){
pybind11::enum_<pangolin::AxisDirection>(m, "AxisDirection")
.value("AxisNone", pangolin::AxisDirection::AxisNone)
.value("AxisNegX", pangolin::AxisDirection::AxisNegX)
.value("AxisNegY", pangolin::AxisDirection::AxisNegY)
.value("AxisNegZ", pangolin::AxisDirection::AxisNegZ)
.value("AxisX", pangolin::AxisDirection::AxisX)
.value("AxisY", pangolin::AxisDirection::AxisY)
.value("AxisZ", pangolin::AxisDirection::AxisZ)
.export_values();
pybind11::enum_<pangolin::OpenGlStack>(m, "OpenGlStack")
.value("GlModelViewStack", pangolin::OpenGlStack::GlModelViewStack)
.value("GlProjectionStack", pangolin::OpenGlStack::GlProjectionStack)
.value("GlTextureStack", pangolin::OpenGlStack::GlTextureStack)
.export_values();
pybind11::class_<pangolin::OpenGlMatrix>(m, "OpenGlMatrix")
.def("Translate", &pangolin::OpenGlMatrix::Translate)
.def("Scale", &pangolin::OpenGlMatrix::Scale)
.def("RotateX", &pangolin::OpenGlMatrix::RotateX)
.def("RotateY", &pangolin::OpenGlMatrix::RotateY)
.def("RotateZ", &pangolin::OpenGlMatrix::RotateZ)
.def(pybind11::init<>())
.def(pybind11::init<const Eigen::Matrix<float, 4, 4> >())
.def(pybind11::init<const Eigen::Matrix<double, 4, 4> >())
.def("Load", &pangolin::OpenGlMatrix::Load)
.def("Multiply", &pangolin::OpenGlMatrix::Multiply)
.def("SetIdentity", &pangolin::OpenGlMatrix::SetIdentity)
.def("Transpose", &pangolin::OpenGlMatrix::Transpose)
.def("Inverse", &pangolin::OpenGlMatrix::Inverse)
.def("Matrix", [](pangolin::OpenGlMatrix& mat){
using T = pangolin::GLprecision;
return pybind11::array_t<T>( {4, 4 }, {1*sizeof(T), 4*sizeof(T)}, mat.m );
})
.def(pybind11::self * pybind11::self);
pybind11::class_<pangolin::OpenGlMatrixSpec, pangolin::OpenGlMatrix>(m, "OpenGlMatrixSpec")
.def(pybind11::init<>());
m.def("ProjectionMatrixRUB_BottomLeft", &pangolin::ProjectionMatrixRUB_BottomLeft);
m.def("ProjectionMatrixRUB_TopLeft", &pangolin::ProjectionMatrixRUB_TopLeft);
m.def("ProjectionMatrixRDF_BottomLeft", &pangolin::ProjectionMatrixRDF_BottomLeft);
m.def("ProjectionMatrixRDF_TopLeft", &pangolin::ProjectionMatrixRDF_TopLeft);
m.def("ProjectionMatrix", &pangolin::ProjectionMatrix);
m.def("ProjectionMatrixOrthographic", &pangolin::ProjectionMatrixOrthographic);
m.def("ModelViewLookAtRUB", &pangolin::ModelViewLookAtRUB);
m.def("ModelViewLookAtRDF", &pangolin::ModelViewLookAtRDF);
m.def("ModelViewLookAt", (pangolin::OpenGlMatrix (*)(pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::AxisDirection))&pangolin::ModelViewLookAt);
m.def("ModelViewLookAt", (pangolin::OpenGlMatrix (*)(pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision))&pangolin::ModelViewLookAt);
m.def("IdentityMatrix", (pangolin::OpenGlMatrix (*)())&pangolin::IdentityMatrix);
m.def("IdentityMatrix", (pangolin::OpenGlMatrixSpec (*)(pangolin::OpenGlStack))&pangolin::IdentityMatrix);
m.def("negIdentityMatrix", &pangolin::negIdentityMatrix);
pybind11::class_<pangolin::OpenGlRenderState>(m, "OpenGlRenderState")
.def(pybind11::init<const pangolin::OpenGlMatrix&>())
.def(pybind11::init<const pangolin::OpenGlMatrix&, const pangolin::OpenGlMatrix&>())
.def(pybind11::init<>())
.def("ApplyIdentity", &pangolin::OpenGlRenderState::ApplyIdentity)
.def("Apply", &pangolin::OpenGlRenderState::Apply)
.def("SetProjectionMatrix", &pangolin::OpenGlRenderState::SetProjectionMatrix)
.def("SetModelViewMatrix", &pangolin::OpenGlRenderState::SetModelViewMatrix)
.def("GetProjectionMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)())&pangolin::OpenGlRenderState::GetProjectionMatrix)
.def("GetProjectionMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)() const)&pangolin::OpenGlRenderState::GetProjectionMatrix)
.def("GetModelViewMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)())&pangolin::OpenGlRenderState::GetModelViewMatrix)
.def("GetModelViewMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)() const)&pangolin::OpenGlRenderState::GetModelViewMatrix)
.def("GetProjectionModelViewMatrix", &pangolin::OpenGlRenderState::GetProjectionModelViewMatrix)
.def("GetProjectiveTextureMatrix", &pangolin::OpenGlRenderState::GetProjectiveTextureMatrix)
.def("EnableProjectiveTexturing", &pangolin::OpenGlRenderState::EnableProjectiveTexturing)
.def("DisableProjectiveTexturing", &pangolin::OpenGlRenderState::DisableProjectiveTexturing)
.def("Follow", &pangolin::OpenGlRenderState::Follow, pybind11::arg("T_wc"), pybind11::arg("follow")=true)
.def("Unfollow", &pangolin::OpenGlRenderState::Unfollow)
.def("GetProjectionMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)(unsigned int))&pangolin::OpenGlRenderState::GetProjectionMatrix)
.def("GetProjectionMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(unsigned int) const)&pangolin::OpenGlRenderState::GetProjectionMatrix)
.def("GetViewOffset", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)(unsigned int))&pangolin::OpenGlRenderState::GetViewOffset)
.def("GetViewOffset", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(unsigned int) const)&pangolin::OpenGlRenderState::GetViewOffset)
.def("GetModelViewMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(int) const)&pangolin::OpenGlRenderState::GetModelViewMatrix)
.def("ApplyNView", &pangolin::OpenGlRenderState::ApplyNView);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_opengl_render_state(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,43 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "params.hpp"
#include <pangolin/utils/params.h>
namespace py_pangolin {
void bind_params(pybind11::module &m) {
pybind11::class_<pangolin::Params>(m, "Params")
.def(pybind11::init<>())
.def("Contains", &pangolin::Params::Contains)
.def("Set", &pangolin::Params::Set<int>)
.def("Get", &pangolin::Params::Get<int>)
.def("Set", &pangolin::Params::Set<std::string>)
.def("Get", &pangolin::Params::Get<std::string>);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_params(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,43 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "pixel_format.hpp"
#include <pangolin/image/pixel_format.h>
namespace py_pangolin {
void bind_pixel_format(pybind11::module& m){
pybind11::class_<pangolin::PixelFormat>(m, "PixelFormat")
.def_readwrite("format", &pangolin::PixelFormat::format)
.def_readwrite("channels", &pangolin::PixelFormat::channels)
// .def_readwrite("channel_bits", &pangolin::PixelFormat::channel_bits) //channel_bits[4]
.def_readwrite("bpp", &pangolin::PixelFormat::bpp)
.def_readwrite("planar", &pangolin::PixelFormat::planar);
m.def("PixelFormatFromString", &pangolin::PixelFormatFromString);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_pixel_format(pybind11::module& m);
} // py_pangolin

View File

@@ -0,0 +1,131 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov, 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 "view.hpp"
#include "plotter.hpp"
#include "handler.hpp"
#include <pangolin/plot/plotter.h>
namespace py_pangolin {
//extern pybind11::class_<pangolin::Handler, PyHandler> handler;
void bind_plotter(pybind11::module& m){
// pybind11::class_<pangolin::Handler, PyHandler> handler1(m, "Handler1");
// handler1
// .def(pybind11::init<>())
// .def("Keyboard", &pangolin::Handler::Keyboard)
// .def("Mouse", &pangolin::Handler::Mouse)
// .def("MouseMotion", &pangolin::Handler::MouseMotion)
// .def("PassiveMouseMotion", &pangolin::Handler::PassiveMouseMotion)
// .def("Special", &pangolin::Handler::Special);
pybind11::enum_<pangolin::DrawingMode>(m, "DrawingMode")
.value("DrawingModePoints", pangolin::DrawingMode::DrawingModePoints)
.value("DrawingModeDashed", pangolin::DrawingMode::DrawingModeDashed)
.value("DrawingModeLine", pangolin::DrawingMode::DrawingModeLine)
.value("DrawingModeNone", pangolin::DrawingMode::DrawingModeNone)
.export_values();
pybind11::class_<pangolin::Marker> marker(m, "Marker");
pybind11::enum_<pangolin::Marker::Direction>(marker, "Direction")
.value("Horizontal", pangolin::Marker::Direction::Horizontal)
.value("Vertical", pangolin::Marker::Direction::Vertical)
.export_values();
pybind11::enum_<pangolin::Marker::Equality>(marker, "Equality")
.value("LessThan", pangolin::Marker::Equality::LessThan)
.value("Equal", pangolin::Marker::Equality::Equal)
.value("GreaterThan", pangolin::Marker::Equality::GreaterThan)
.export_values();
marker.def(pybind11::init<pangolin::Marker::Direction, float, pangolin::Marker::Equality, pangolin::Colour>(), pybind11::arg("d"), pybind11::arg("value"), pybind11::arg("leg") = pangolin::Marker::Equality::Equal, pybind11::arg("c")=pangolin::Colour())
.def(pybind11::init<const pangolin::XYRangef&, const pangolin::Colour&>(), pybind11::arg("range"), pybind11::arg("c")=pangolin::Colour())
.def_readwrite("range", &pangolin::Marker::range)
.def_readwrite("colour", &pangolin::Marker::colour);
pybind11::class_<pangolin::Plotter,pangolin::View>(m, "Plotter")
.def(pybind11::init<pangolin::DataLog*, float, float, float, float, float, float, pangolin::Plotter*, pangolin::Plotter*>(),
pybind11::arg("default_log"),
pybind11::arg("left")=0,
pybind11::arg("right")=600,
pybind11::arg("bottom")=-1,
pybind11::arg("top")=1,
pybind11::arg("tickx")=30,
pybind11::arg("ticky")=0.5,
pybind11::arg("linked_plotter_x")=NULL,
pybind11::arg("linked_plotter_y")=NULL)
.def(pybind11::init([](pangolin::DataLog* log, float left, float right, float bottom, float top, float tickx, float ticky){return new pangolin::Plotter(log, left, right, bottom, top,tickx, ticky);}),
pybind11::arg("default_log"),
pybind11::arg("left")=0,
pybind11::arg("right")=600,
pybind11::arg("bottom")=-1,
pybind11::arg("top")=1,
pybind11::arg("// TODO: ickx")=30,
pybind11::arg("ticky")=0.5)
.def("Render", &pangolin::Plotter::Render)
.def("GetSelection", &pangolin::Plotter::GetSelection)
.def("GetDefaultView", &pangolin::Plotter::GetDefaultView)
.def("SetDefaultView", &pangolin::Plotter::SetDefaultView)
.def("GetView", &pangolin::Plotter::GetView)
.def("SetView", &pangolin::Plotter::SetView)
.def("SetViewSmooth", &pangolin::Plotter::SetViewSmooth)
.def("ScrollView", &pangolin::Plotter::ScrollView)
.def("ScrollViewSmooth", &pangolin::Plotter::ScrollViewSmooth)
.def("ScaleView", &pangolin::Plotter::ScaleView)
.def("ScaleViewSmooth", &pangolin::Plotter::ScaleViewSmooth)
.def("SetTicks", &pangolin::Plotter::SetTicks)
.def("Track", &pangolin::Plotter::Track, pybind11::arg("x")="$i", pybind11::arg("y")="")
.def("ToggleTracking", &pangolin::Plotter::ToggleTracking)
.def("Trigger", &pangolin::Plotter::Trigger, pybind11::arg("x")="$0", pybind11::arg("edge")=-1, pybind11::arg("value")=0.0f)
.def("ToggleTrigger", &pangolin::Plotter::ToggleTrigger)
.def("SetBackgroundColour", &pangolin::Plotter::SetBackgroundColour)
.def("SetAxisColour", &pangolin::Plotter::SetAxisColour)
.def("SetTickColour", &pangolin::Plotter::SetTickColour)
.def("Keyboard", &pangolin::Plotter::Keyboard)
.def("Mouse", &pangolin::Plotter::Mouse)
.def("MouseMotion", &pangolin::Plotter::MouseMotion)
.def("PassiveMouseMotion", &pangolin::Plotter::PassiveMouseMotion)
.def("Special", &pangolin::Plotter::Special)
.def("ClearSeries", &pangolin::Plotter::ClearSeries)
.def("AddSeries", &pangolin::Plotter::AddSeries)
.def("PlotTitleFromExpr", &pangolin::Plotter::PlotTitleFromExpr)
.def("ClearMarkers", &pangolin::Plotter::ClearMarkers)
.def("AddMarker", (pangolin::Marker& (pangolin::Plotter::*)(pangolin::Marker::Direction, float, pangolin::Marker::Equality, pangolin::Colour))&pangolin::Plotter::AddMarker, pybind11::arg("d"), pybind11::arg("value"), pybind11::arg("leg") = pangolin::Marker::Equality::Equal, pybind11::arg("c")=pangolin::Colour())
.def("AddMarker", (pangolin::Marker& (pangolin::Plotter::*)(const pangolin::Marker&))&pangolin::Plotter::AddMarker)
// .def("ClearImplicitPlots", &pangolin::Plotter::ClearImplicitPlots);
// .def("AddImplicitPlot", &pangolin::Plotter::AddImplicitPlot);
.def("SetBounds", (pangolin::View& (pangolin::Plotter::*)(pangolin::Attach, pangolin::Attach, pangolin::Attach, pangolin::Attach))&pangolin::Plotter::SetBounds)
.def("SetBounds", (pangolin::View& (pangolin::Plotter::*)(pangolin::Attach, pangolin::Attach, pangolin::Attach, pangolin::Attach, bool))&pangolin::Plotter::SetBounds)
.def("SetBounds", (pangolin::View& (pangolin::Plotter::*)(pangolin::Attach, pangolin::Attach, pangolin::Attach, pangolin::Attach, double))&pangolin::Plotter::SetBounds);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_plotter(pybind11::module& m);
} // py_pangolin

View File

@@ -0,0 +1,83 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 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 <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/embed.h>
#include "attach.hpp"
#include "colour.hpp"
#include "datalog.hpp"
#include "display.hpp"
#include "gl.hpp"
#include "glsl.hpp"
#include "gl_draw.hpp"
#include "handler.hpp"
#include "image.hpp"
#include "opengl_render_state.hpp"
#include "params.hpp"
#include "pixel_format.hpp"
#include "plotter.hpp"
#include "var.hpp"
#include "video.hpp"
#include "view.hpp"
#include "viewport.hpp"
#include "widget.hpp"
#include "window.hpp"
#include "image_view.hpp"
namespace pypangolin {
inline void PopulateModule(pybind11::module& m)
{
m.doc() = "pypangolin python wrapper for Pangolin rapid prototyping graphics and video library.";
py_pangolin::bind_var(m);
py_pangolin::bind_params(m);
py_pangolin::bind_viewport(m);
py_pangolin::bind_view(m);
py_pangolin::bind_window(m);
py_pangolin::bind_display(m);
py_pangolin::bind_opengl_render_state(m);
py_pangolin::bind_attach(m);
py_pangolin::bind_colour(m);
py_pangolin::bind_datalog(m);
py_pangolin::bind_plotter(m);
py_pangolin::bind_handler(m);
py_pangolin::bind_gl(m);
py_pangolin::bind_glsl(m);
py_pangolin::bind_gl_draw(m);
py_pangolin::bind_widget(m);
py_pangolin::bind_pixel_format(m);
py_pangolin::bind_image<unsigned char>(m, "Image");
py_pangolin::bind_video(m);
py_pangolin::bind_image_view(m);
}
}

View File

@@ -0,0 +1,157 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "var.hpp"
#include <functional>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
namespace py_pangolin {
var_t::var_t(const std::string& ns_){
if(ns_==""){
throw std::invalid_argument("not support empty argument");
}
ns=ns_+".";
}
var_t::~var_t() noexcept{}
var_t::var_t(const var_t &/*other*/){}
var_t::var_t(var_t &&/*other*/) noexcept{}
var_t& var_t::operator=(const var_t &/*other*/){
return *this;
}
var_t& var_t::operator=(var_t &&/*other*/) noexcept{
return *this;
}
pybind11::object var_t::get_attr(const std::string &name){
pangolin::VarState::VarStoreContainer::iterator i = pangolin::VarState::I().vars.find(ns+name);
if (i != pangolin::VarState::I().vars.end()) {
pangolin::VarValueGeneric* var = i->second;
if (!strcmp(var->TypeId(), typeid(bool).name())) {
const bool val = pangolin::Var<bool>(*var).Get();
return pybind11::bool_(val);
} else if (!strcmp(var->TypeId(), typeid(short).name()) ||
!strcmp(var->TypeId(), typeid(int).name()) ||
!strcmp(var->TypeId(), typeid(long).name())) {
const long val = pangolin::Var<long>(*var).Get();
return pybind11::int_(val);
} else if (!strcmp(var->TypeId(), typeid(double).name()) ||
!strcmp(var->TypeId(), typeid(float).name())) {
const double val = pangolin::Var<double>(*var).Get();
return pybind11::float_(val);
} else {
const std::string val = var->str->Get();
return pybind11::str(val);
}
}
return pybind11::none();
}
template <typename T>
void var_t::set_attr_(const std::string& name, T val, const PyVarMeta & meta){
pangolin::VarState::VarStoreContainer::iterator i = pangolin::VarState::I().vars.find(ns+name);
if (i != pangolin::VarState::I().vars.end()) {
pangolin::VarValueGeneric* var = i->second;
pangolin::Var<T> v(*var);
v = val;
} else {
int flags = pangolin::META_FLAG_NONE;
if (meta.toggle) flags |= pangolin::META_FLAG_TOGGLE;
if (meta.read_only) flags |= pangolin::META_FLAG_READONLY;
pangolin::Var<T> pango_var(ns+name, val, flags);
pango_var.Meta().gui_changed = true;
pango_var.Meta().range[0] = meta.low;
pango_var.Meta().range[1] = meta.high;
pango_var.Meta().logscale = meta.logscale;
pangolin::FlagVarChanged();
}
}
std::vector<std::string>& var_t::get_members(){
const int nss = ns.size();
members.clear();
for (const std::string& s : pangolin::VarState::I().var_adds) {
if (!s.compare(0, nss, ns)) {
size_t dot = s.find_first_of('.', nss);
members.push_back((dot != std::string::npos) ? s.substr(nss, dot - nss) : s.substr(nss));
}
}
return members;
}
template <typename ... Ts>
struct VarBinder {
static inline void Bind(pybind11::class_<var_t> & varClass) {}
};
template <typename Head, typename ... Tail>
struct VarBinder<Head, Tail...> {
static inline void Bind(pybind11::class_<var_t> & varClass) {
varClass.def("__setattr__", [](var_t& v, const std::string& name, Head val) {
v.set_attr_<Head>(name, val);
}).def("__setattr__", [](var_t& v, const std::string& name, const std::tuple<Head, PyVarMeta> & valMeta) {
v.set_attr_<Head>(name, std::get<0>(valMeta), std::get<1>(valMeta));
});
VarBinder<Tail...>::Bind(varClass);
}
};
void bind_var(pybind11::module& m){
pybind11::class_<PyVarMeta>(m, "VarMeta")
.def(pybind11::init<double, double, bool, bool, bool>(),
pybind11::arg("low") = 0.0,
pybind11::arg("high") = 1.0,
pybind11::arg("logscale") = false,
pybind11::arg("toggle") = false,
pybind11::arg("read_only") = false);
pybind11::class_<py_pangolin::var_t> varClass(m, "Var");
varClass.def(pybind11::init<const std::string &>())
.def("__members__", &py_pangolin::var_t::get_members)
.def("__getattr__", &py_pangolin::var_t::get_attr);
VarBinder<bool, int, double, std::string, std::function<void(void)> >::Bind(varClass);
}
} // py_pangolin

View File

@@ -0,0 +1,67 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
#include <pangolin/var/var.h>
#include <Python.h>
namespace py_pangolin {
struct PyVarMeta {
double low;
double high;
bool logscale;
bool toggle;
bool read_only;
};
void bind_var(pybind11::module& m);
class var_t
{
public:
var_t(const std::string& ns);
virtual ~var_t() noexcept;
pybind11::object get_attr(const std::string &name);
template <typename T>
void set_attr_(const std::string& name, T val, const PyVarMeta & meta = {});
std::vector<std::string>& get_members();
protected:
var_t(const var_t &other);
var_t(var_t &&other) noexcept;
var_t& operator=(const var_t &other);
var_t& operator=(var_t &&other) noexcept;
private:
std::vector<std::string> members;
std::string ns;
};
} // py_pangolin

View File

@@ -0,0 +1,645 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "video.hpp"
#include <pangolin/video/video_interface.h>
#include <pangolin/video/video_input.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
namespace py_pangolin {
class PyVideoInterface: public pangolin::VideoInterface{
public:
using pangolin::VideoInterface::VideoInterface;
size_t SizeBytes() const override {
PYBIND11_OVERLOAD_PURE(
size_t,
pangolin::VideoInterface,
SizeBytes);
}
const std::vector<pangolin::StreamInfo>& Streams() const override {
PYBIND11_OVERLOAD_PURE(
const std::vector<pangolin::StreamInfo>&,
pangolin::VideoInterface,
Streams);
}
void Start() override {
PYBIND11_OVERLOAD_PURE(
void,
pangolin::VideoInterface,
Start);
}
void Stop() override {
PYBIND11_OVERLOAD_PURE(
void,
pangolin::VideoInterface,
Stop);
}
bool GrabNext(unsigned char* image, bool wait = true) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoInterface,
GrabNext,
image,
wait);
}
bool GrabNewest(unsigned char* image, bool wait = true) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoInterface,
GrabNewest,
image,
wait);
}
};
class PyGenicamVideoInterface: public pangolin::GenicamVideoInterface{
public:
using pangolin::GenicamVideoInterface::GenicamVideoInterface;
bool GetParameter(const std::string& name, std::string& result) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::GenicamVideoInterface,
GetParameter,
name,
result);
}
bool SetParameter(const std::string& name, const std::string& value) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::GenicamVideoInterface,
SetParameter,
name,
value);
}
size_t CameraCount() const override
{
PYBIND11_OVERLOAD_PURE(
size_t,
pangolin::GenicamVideoInterface,
CameraCount);
}
};
class PyBufferAwareVideoInterface: public pangolin::BufferAwareVideoInterface{
public:
using pangolin::BufferAwareVideoInterface::BufferAwareVideoInterface;
uint32_t AvailableFrames() const override {
PYBIND11_OVERLOAD_PURE(
uint32_t,
pangolin::BufferAwareVideoInterface,
AvailableFrames);
}
bool DropNFrames(uint32_t n) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::BufferAwareVideoInterface,
DropNFrames,
n);
}
};
class PyVideoPropertiesInterface: public pangolin::VideoPropertiesInterface{
public:
using pangolin::VideoPropertiesInterface::VideoPropertiesInterface;
const picojson::value& DeviceProperties() const override {
PYBIND11_OVERLOAD_PURE(
const picojson::value&,
pangolin::VideoPropertiesInterface,
DeviceProperties);
}
const picojson::value& FrameProperties() const override {
PYBIND11_OVERLOAD_PURE(
const picojson::value&,
pangolin::VideoPropertiesInterface,
FrameProperties);
}
};
class PyVideoFilterInterface: public pangolin::VideoFilterInterface{
public:
using pangolin::VideoFilterInterface::VideoFilterInterface;
// template <typename T>
// std::vector<T*> FindMatchingStreams() override {
// PYBIND11_OVERLOAD(
// std::vector<T*>,
// pangolin::VideoFilterInterface,
// FindMatchingStreams);
// }
std::vector<pangolin::VideoInterface*>& InputStreams() override {
PYBIND11_OVERLOAD_PURE(
std::vector<pangolin::VideoInterface*>&,
pangolin::VideoFilterInterface,
InputStreams);
}
};
class PyVideoUvcInterface: public pangolin::VideoUvcInterface{
public:
using pangolin::VideoUvcInterface::VideoUvcInterface;
int IoCtrl(uint8_t unit, uint8_t ctrl, unsigned char* data, int len, pangolin::UvcRequestCode req_code) override {
PYBIND11_OVERLOAD_PURE(
int,
pangolin::VideoUvcInterface,
IoCtrl,
unit,
ctrl,
data,
len,
req_code);
}
bool GetExposure(int& exp_us) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoUvcInterface,
GetExposure,
exp_us);
}
bool SetExposure(int exp_us) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoUvcInterface,
SetExposure,
exp_us);
}
bool GetGain(float& gain) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoUvcInterface,
GetGain,
gain);
}
bool SetGain(float gain) override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoUvcInterface,
SetGain,
gain);
}
};
class PyVideoPlaybackInterface: public pangolin::VideoPlaybackInterface{
public:
using pangolin::VideoPlaybackInterface::VideoPlaybackInterface;
size_t GetCurrentFrameId() const override {
PYBIND11_OVERLOAD_PURE(
size_t,
pangolin::VideoPlaybackInterface,
GetCurrentFrameId);
}
size_t GetTotalFrames() const override {
PYBIND11_OVERLOAD_PURE(
size_t,
pangolin::VideoPlaybackInterface,
GetTotalFrames);
}
size_t Seek(size_t frameid) override {
PYBIND11_OVERLOAD_PURE(
size_t,
pangolin::VideoPlaybackInterface,
Seek,
frameid);
}
};
class PyVideoOutputInterface: public pangolin::VideoOutputInterface{
public:
using pangolin::VideoOutputInterface::VideoOutputInterface;
const std::vector<pangolin::StreamInfo>& Streams() const override {
PYBIND11_OVERLOAD_PURE(
const std::vector<pangolin::StreamInfo>&,
pangolin::VideoOutputInterface,
Streams);
}
void SetStreams(const std::vector<pangolin::StreamInfo>& streams, const std::string& uri, const picojson::value& properties) override {
PYBIND11_OVERLOAD_PURE(
void,
pangolin::VideoOutputInterface,
SetStreams,
streams,
uri,
properties);
}
int WriteStreams(const unsigned char* data, const picojson::value& frame_properties) override {
PYBIND11_OVERLOAD_PURE(
int,
pangolin::VideoOutputInterface,
WriteStreams,
data,
frame_properties);
}
bool IsPipe() const override {
PYBIND11_OVERLOAD_PURE(
bool,
pangolin::VideoOutputInterface,
IsPipe);
}
};
pybind11::list VideoInputGrab(pangolin::VideoInput& vi, bool wait, bool newest){
unsigned char *buffer = new unsigned char[vi.SizeBytes()];
std::vector<pangolin::Image<unsigned char>> imgs;
pybind11::list imgsList;
if(vi.Grab(buffer,imgs,wait,newest)) {
for(size_t s=0; s < vi.Streams().size(); ++s) {
// Let's just return the first stream for the moment
const pangolin::StreamInfo& si = vi.Streams()[s];
const pangolin::Image<uint8_t> img = si.StreamImage(buffer);
const int c = si.PixFormat().channels;
const std::string fmt = si.PixFormat().format;
const int Bpp = si.PixFormat().bpp / (8);
const int Bpc = Bpp / c;
const int bpc = si.PixFormat().bpp / c;
PANGO_ASSERT(bpc == 8 || bpc == 16 || bpc == 32, "only support 8, 16, 32 bits channel");
pangolin::Image<uint8_t> dstImage(
new unsigned char[img.h * img.w * Bpp],
img.w, img.h, img.w*Bpp
);
pangolin::PitchedCopy((char*)dstImage.ptr, dstImage.pitch, (char*)img.ptr, img.pitch, img.w * Bpp, img.h);
// Create a Python object that will free the allocated memory
pybind11::capsule free_when_done(dstImage.ptr,[](void* f) {
unsigned char* buffer = (unsigned char*)f;
delete[] buffer;
});
if (bpc == 8) {
imgsList.append(
pybind11::array_t<uint8_t>(
{(int)dstImage.h, (int)dstImage.w, c },
{(int)dstImage.pitch, Bpp, Bpc},
(uint8_t*)dstImage.ptr,
free_when_done)
);
}
else if (bpc == 16){
imgsList.append(
pybind11::array_t<uint16_t>(
{(int)dstImage.h, (int)dstImage.w, c },
{(int)dstImage.pitch, Bpp, Bpc},
(uint16_t*)dstImage.ptr,
free_when_done)
);
}
else if (bpc == 32){
if (fmt == "GRAY32")
{
imgsList.append(
pybind11::array_t<uint32_t>(
{(int)dstImage.h, (int)dstImage.w, c },
{(int)dstImage.pitch, Bpp, Bpc},
(uint32_t*)dstImage.ptr,
free_when_done)
);
}
else if (fmt == "GRAY32F" ||
fmt == "RGB96F" ||
fmt == "RGBA128F")
{
imgsList.append(
pybind11::array_t<float>(
{(int)dstImage.h, (int)dstImage.w, c },
{(int)dstImage.pitch, Bpp, Bpc},
(float*)dstImage.ptr,
free_when_done)
);
}
else{
PANGO_ASSERT(false, "unsupported 32 bpc format");
}
}
else{
PANGO_ASSERT(false, "incompatible bpc");
}
}
}
delete[] buffer;
return imgsList;
}
picojson::value PicojsonFromPyObject(pybind11::object& obj)
{
// convert frame_properties to std::string via json.dumps(...)
pybind11::module pymodjson = pybind11::module::import("json");
auto pydumps = pymodjson.attr("dumps");
const std::string json = pydumps(obj).cast<pybind11::str>();
std::stringstream ss(json);
picojson::value pjson;
picojson::parse(pjson, ss);
return pjson;
}
void bind_video(pybind11::module& m){
pybind11::class_<pangolin::VideoInterface, PyVideoInterface > video_interface(m, "VideoInterface");
video_interface
.def(pybind11::init<>())
.def("SizeBytes", &pangolin::VideoInterface::SizeBytes)
.def("Streams", &pangolin::VideoInterface::Streams)
.def("Start", &pangolin::VideoInterface::Start)
.def("Stop", &pangolin::VideoInterface::Stop)
.def("GrabNext", &pangolin::VideoInterface::GrabNext)
.def("GrabNewest", &pangolin::VideoInterface::GrabNewest);
pybind11::class_<pangolin::GenicamVideoInterface, PyGenicamVideoInterface > genicam_video_interface(m, "GenicamVideoInterface");
genicam_video_interface
.def(pybind11::init<>())
.def("GetParameter", &pangolin::GenicamVideoInterface::GetParameter)
.def("SetParameter", &pangolin::GenicamVideoInterface::SetParameter);
pybind11::class_<pangolin::BufferAwareVideoInterface, PyBufferAwareVideoInterface > buffer_aware_video_interface(m, "BufferAwareVideoInterface");
buffer_aware_video_interface
.def(pybind11::init<>())
.def("AvailableFrames", &pangolin::BufferAwareVideoInterface::AvailableFrames)
.def("DropNFrames", &pangolin::BufferAwareVideoInterface::DropNFrames);
pybind11::class_<pangolin::VideoPropertiesInterface, PyVideoPropertiesInterface > video_properties_interface(m, "VideoPropertiesInterface");
video_properties_interface
.def(pybind11::init<>())
.def("DeviceProperties", &pangolin::VideoPropertiesInterface::DeviceProperties)
.def("FrameProperties", &pangolin::VideoPropertiesInterface::FrameProperties);
pybind11::class_<pangolin::VideoFilterInterface, PyVideoFilterInterface > video_filter_interface(m, "VideoFilterInterface");
video_filter_interface
.def(pybind11::init<>())
// .def("FindMatchingStreams", &pangolin::VideoFilterInterface::FindMatchingStreams)
.def("InputStreams", &pangolin::VideoFilterInterface::InputStreams);
pybind11::class_<pangolin::VideoUvcInterface, PyVideoUvcInterface > video_uvc_interface(m, "VideoUvcInterface");
video_uvc_interface
.def(pybind11::init<>())
.def("IoCtrl", &pangolin::VideoUvcInterface::IoCtrl)
.def("GetExposure", &pangolin::VideoUvcInterface::GetExposure)
.def("SetExposure", &pangolin::VideoUvcInterface::SetExposure)
.def("GetGain", &pangolin::VideoUvcInterface::GetGain)
.def("SetGain", &pangolin::VideoUvcInterface::SetGain);
pybind11::class_<pangolin::VideoPlaybackInterface, PyVideoPlaybackInterface > video_playback_interface(m, "VideoPlaybackInterface");
video_playback_interface
.def(pybind11::init<>())
.def("GetCurrentFrameId", &pangolin::VideoPlaybackInterface::GetCurrentFrameId)
.def("GetTotalFrames", &pangolin::VideoPlaybackInterface::GetTotalFrames)
.def("Seek", &pangolin::VideoPlaybackInterface::Seek);
pybind11::class_<pangolin::VideoOutputInterface, PyVideoOutputInterface > video_output_interface(m, "VideoOutputInterface");
video_output_interface
.def(pybind11::init<>())
.def("Streams", &pangolin::VideoOutputInterface::Streams)
.def("SetStreams", &pangolin::VideoOutputInterface::SetStreams)
.def("WriteStreams", &pangolin::VideoOutputInterface::WriteStreams)
.def("IsPipe", &pangolin::VideoOutputInterface::IsPipe);
pybind11::enum_<pangolin::UvcRequestCode>(m, "UvcRequestCode")
.value("UVC_RC_UNDEFINED", pangolin::UvcRequestCode::UVC_RC_UNDEFINED)
.value("UVC_SET_CUR", pangolin::UvcRequestCode::UVC_SET_CUR)
.value("UVC_GET_CUR", pangolin::UvcRequestCode::UVC_GET_CUR)
.value("UVC_GET_MIN", pangolin::UvcRequestCode::UVC_GET_MIN)
.value("UVC_GET_MAX", pangolin::UvcRequestCode::UVC_GET_MAX)
.value("UVC_GET_RES", pangolin::UvcRequestCode::UVC_GET_RES)
.value("UVC_GET_LEN", pangolin::UvcRequestCode::UVC_GET_LEN)
.value("UVC_GET_INFO", pangolin::UvcRequestCode::UVC_GET_INFO)
.value("UVC_GET_DEF", pangolin::UvcRequestCode::UVC_GET_DEF)
.export_values();
/// This iterator enable pythonic video iterations a la `for frame in video_input: ...`
struct VideoInputIterator {
VideoInputIterator(pangolin::VideoInput& vi, pybind11::object ref) : vi(vi), ref(ref) { }
pybind11::list next() {
pybind11::list result = VideoInputGrab(vi, true, false);
if(result.size()==0)
throw pybind11::stop_iteration();
return result;
}
pangolin::VideoInput& vi;
pybind11::object ref; // keep a reference
};
pybind11::class_<VideoInputIterator>(m, "Iterator")
.def("__iter__", [](VideoInputIterator &it) -> VideoInputIterator& { return it; })
.def("__next__", &VideoInputIterator::next);
pybind11::class_<pangolin::VideoInput>(m, "VideoInput", video_interface)
.def(pybind11::init<>())
.def(pybind11::init<const std::string&, const std::string&>(), pybind11::arg("input_uri"), pybind11::arg("output_uri")="pango:[buffer_size_mb=100]//video_log.pango")
.def("SizeBytes", &pangolin::VideoInput::SizeBytes)
.def("Streams", &pangolin::VideoInput::Streams)
.def("Start", &pangolin::VideoInput::Start)
.def("Stop", &pangolin::VideoInput::Stop)
.def("InputStreams", &pangolin::VideoInput::InputStreams)
.def("Open", &pangolin::VideoInput::Open, pybind11::arg("input_uri"), pybind11::arg("output_uri")="pango:[buffer_size_mb=100]//video_log.pango")
.def("Close", &pangolin::VideoInput::Close)
.def("Grab", VideoInputGrab, pybind11::arg("wait")=true, pybind11::arg("newest")=false )
.def("GetStreamsBitDepth", [](pangolin::VideoInput& vi){
std::vector<int> bitDepthList;
for(size_t s=0; s < vi.Streams().size(); ++s) {
bitDepthList.push_back(vi.Streams()[s].PixFormat().channel_bit_depth);
}
return bitDepthList;
})
.def("GetNumStreams", [](pangolin::VideoInput& vi){
return (int) vi.Streams().size();
})
.def("GetCurrentFrameId", [](pangolin::VideoInput& vi){
return (int) vi.Cast<pangolin::VideoPlaybackInterface>()->GetCurrentFrameId();
})
.def("GetTotalFrames", [](pangolin::VideoInput& vi){
return (int) vi.Cast<pangolin::VideoPlaybackInterface>()->GetTotalFrames();
})
.def("Seek", [](pangolin::VideoInput& vi, size_t frameid){
vi.Cast<pangolin::VideoPlaybackInterface>()->Seek(frameid);
return;
})
.def("DeviceProperties", [](pangolin::VideoInput& vi) -> pybind11::object {
// Use std::string as an intermediate representation
const std::string props = vi.template Cast<pangolin::VideoPropertiesInterface>()->DeviceProperties().serialize();
pybind11::module pymodjson = pybind11::module::import("json");
auto pyloads = pymodjson.attr("loads");
auto json = pyloads(pybind11::str(props));
return json;
})
.def("FrameProperties", [](pangolin::VideoInput& vi) -> pybind11::object {
// Use std::string as an intermediate representation
const std::string props = vi.template Cast<pangolin::VideoPropertiesInterface>()->FrameProperties().serialize();
pybind11::module pymodjson = pybind11::module::import("json");
auto pyloads = pymodjson.attr("loads");
auto json = pyloads(pybind11::str(props));
return json;
})
.def("Width", &pangolin::VideoInput::Width)
.def("Height", &pangolin::VideoInput::Height)
.def("PixFormat", &pangolin::VideoInput::PixFormat)
.def("VideoUri", &pangolin::VideoInput::VideoUri)
.def("Reset", &pangolin::VideoInput::Reset)
.def("LogFilename", (const std::string& (pangolin::VideoInput::*)() const)&pangolin::VideoInput::LogFilename)
.def("LogFilename", (std::string& (pangolin::VideoInput::*)())&pangolin::VideoInput::LogFilename)
.def("Record", &pangolin::VideoInput::Record)
.def("RecordOneFrame", &pangolin::VideoInput::RecordOneFrame)
.def("SetTimelapse", &pangolin::VideoInput::SetTimelapse)
.def("IsRecording", &pangolin::VideoInput::IsRecording)
.def("__iter__", [](pybind11::object s) { return VideoInputIterator(s.cast<pangolin::VideoInput&>(), s);});
pybind11::class_<pangolin::VideoOutput>(m, "VideoOutput", video_output_interface)
.def(pybind11::init<>())
.def(pybind11::init<const std::string&>())
.def("IsOpen", &pangolin::VideoOutput::IsOpen)
.def("Open", &pangolin::VideoOutput::Open)
.def("Close", &pangolin::VideoOutput::Close)
.def("Streams", &pangolin::VideoOutput::Streams)
.def("WriteStreams", [](pangolin::VideoOutput& vo, pybind11::list images, const std::vector<int> &streamsBitDepth, pybind11::object frame_properties, pybind11::object device_properties, const std::string& descriptive_uri){
if(vo.SizeBytes()==0) {
PANGO_ASSERT(streamsBitDepth.size() == images.size() || streamsBitDepth.size() == 0);
// Setup stream info
for(size_t i = 0; i < images.size(); ++i){
// num bits per channel
auto arr = pybind11::array::ensure(images[i]);
// num channels
PANGO_ASSERT(arr.ndim() == 2 || arr.ndim() == 3, "Method only accepts ndarrays of 2 or 3 dimensions.");
const size_t channels = (arr.ndim() == 3) ? arr.shape(2) : 1;
std::string fmtStr;
if(pybind11::isinstance<pybind11::array_t<std::uint8_t>>(arr)){
if(channels == 1) fmtStr = "GRAY8";
else if(channels == 3) fmtStr = "RGB24";
else if(channels == 4) fmtStr = "RGBA32";
else PANGO_ASSERT(false, "Only 1, 3 and 4 channel uint8_t formats are supported.");
} else if (pybind11::isinstance<pybind11::array_t<std::uint16_t>>(arr)){
if(channels == 1) fmtStr = "GRAY16LE";
else if(channels == 3) fmtStr = "RGB48";
else if(channels == 4) fmtStr = "RGBA64";
else PANGO_ASSERT(false, "Only 1, 3 and 4 channel uint16_t formats are supported.");
} else if (pybind11::isinstance<pybind11::array_t<std::float_t>>(arr)){
if(channels == 1) fmtStr = "GRAY32F";
else if(channels == 3) fmtStr = "RGB96F";
else if(channels == 4) fmtStr = "RGBA128F";
else PANGO_ASSERT(false, "Only 1, 3 and 4 channel float_t formats are supported.");
} else if (pybind11::isinstance<pybind11::array_t<std::double_t>>(arr)){
if(channels == 1) fmtStr = "GRAY64F";
else PANGO_ASSERT(false, "Only 1 channel double_t format is supported.");
} else {
PANGO_ASSERT(false, "numpy dtype must be either uint8_t, uint16_t, float_t or double_t");
}
pangolin::PixelFormat pf = pangolin::PixelFormatFromString(fmtStr);
if(streamsBitDepth.size())
pf.channel_bit_depth = (unsigned int) streamsBitDepth[i];
vo.AddStream(pf, arr.shape(1), arr.shape(0));
}
picojson::value json_device_properties;
if(device_properties) {
json_device_properties = PicojsonFromPyObject(device_properties);
}
vo.SetStreams(descriptive_uri, json_device_properties);
}
picojson::value json_frame_properties;
if(frame_properties) {
json_frame_properties = PicojsonFromPyObject(frame_properties);
}
std::unique_ptr<uint8_t[]> buffer(new uint8_t[vo.SizeBytes()]);
std::vector<pangolin::Image<unsigned char>> bimgs = vo.GetOutputImages(buffer.get());
PANGO_ASSERT(bimgs.size() == images.size(), "length of input streams not consistent");
for(size_t i=0; i < images.size(); ++i) {
const pangolin::StreamInfo& so = vo.Streams()[i];
const unsigned int bpc = so.PixFormat().channel_bit_depth;
const unsigned int Bpp = so.PixFormat().bpp / (8);
if (bpc == 8){
pybind11::array_t<uint8_t> arr = images[i].cast<pybind11::array_t<unsigned char, pybind11::array::c_style | pybind11::array::forcecast>>();
pangolin::Image<uint8_t> srcImg(arr.mutable_data(0,0), bimgs[i].w, bimgs[i].h, bimgs[i].w * Bpp);
pangolin::PitchedCopy((char*)bimgs[i].ptr, bimgs[i].pitch, (char*)srcImg.ptr,
srcImg.pitch, srcImg.pitch, srcImg.h);
}else if (bpc == 12 || bpc == 16){
pybind11::array_t<uint16_t> arr = images[i].cast<pybind11::array_t<uint16_t, pybind11::array::c_style | pybind11::array::forcecast>>();
pangolin::Image<uint16_t> srcImg(arr.mutable_data(0,0), bimgs[i].w, bimgs[i].h, bimgs[i].w * Bpp);
pangolin::PitchedCopy((char*)bimgs[i].ptr, bimgs[i].pitch, (char*)srcImg.ptr,
srcImg.pitch, srcImg.pitch, srcImg.h);
}else if (bpc == 32){
pybind11::array_t<float_t> arr = images[i].cast<pybind11::array_t<float_t, pybind11::array::c_style | pybind11::array::forcecast>>();
pangolin::Image<float_t> srcImg(arr.mutable_data(0,0), bimgs[i].w, bimgs[i].h, bimgs[i].w * Bpp);
pangolin::PitchedCopy((char*)bimgs[i].ptr, bimgs[i].pitch, (char*)srcImg.ptr,
srcImg.pitch, srcImg.pitch, srcImg.h);
}else if (bpc == 64){
pybind11::array_t<double_t> arr = images[i].cast<pybind11::array_t<double_t, pybind11::array::c_style | pybind11::array::forcecast>>();
pangolin::Image<double_t> srcImg(arr.mutable_data(0,0), bimgs[i].w, bimgs[i].h, bimgs[i].w * Bpp);
pangolin::PitchedCopy((char*)bimgs[i].ptr, bimgs[i].pitch, (char*)srcImg.ptr,
srcImg.pitch, srcImg.pitch, srcImg.h);
}else{
PANGO_ASSERT(false, "format must have 8, 12, 16, 32 or 64 bit depth");
}
}
vo.WriteStreams(buffer.get(), json_frame_properties);
}, pybind11::arg("images"), pybind11::arg("streamsBitDepth") = std::vector<int>(), pybind11::arg("frame_properties") = pybind11::none(), pybind11::arg("device_properties") = pybind11::none(), pybind11::arg("descriptive_uri") = "python://")
.def("IsPipe", &pangolin::VideoOutput::IsPipe)
.def("AddStream", (void (pangolin::VideoOutput::*)(const pangolin::PixelFormat&, size_t,size_t,size_t))&pangolin::VideoOutput::AddStream)
.def("AddStream", (void (pangolin::VideoOutput::*)(const pangolin::PixelFormat&, size_t,size_t))&pangolin::VideoOutput::AddStream)
.def("SizeBytes", &pangolin::VideoOutput::SizeBytes)
.def("GetOutputImages", (std::vector<pangolin::Image<unsigned char>> (pangolin::VideoOutput::*)(unsigned char*) const)&pangolin::VideoOutput::GetOutputImages)
.def("GetOutputImages", (std::vector<pangolin::Image<unsigned char>> (pangolin::VideoOutput::*)(std::vector<unsigned char>&) const)&pangolin::VideoOutput::GetOutputImages);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_video(pybind11::module& m);
} // py_pangolin

View File

@@ -0,0 +1,86 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "view.hpp"
#include <pangolin/display/view.h>
#include <pangolin/display/opengl_render_state.h>
#include <pangolin/handler/handler.h>
namespace py_pangolin {
void bind_view(pybind11::module &m) {
pybind11::class_<pangolin::View>(m, "View")
.def(pybind11::init<double>(), pybind11::arg("aspect") = 0.0)
.def("Activate", (void(pangolin::View::*)() const)&pangolin::View::Activate)
.def("Activate", (void(pangolin::View::*)(const pangolin::OpenGlRenderState&) const)&pangolin::View::Activate)
.def("ActivateAndScissor", (void(pangolin::View::*)() const)&pangolin::View::ActivateAndScissor)
.def("ActivateScissorAndClear", (void(pangolin::View::*)() const)&pangolin::View::ActivateScissorAndClear)
.def("ActivateAndScissor", (void(pangolin::View::*)(const pangolin::OpenGlRenderState&) const)&pangolin::View::ActivateAndScissor)
.def("ActivateScissorAndClear", (void(pangolin::View::*)(const pangolin::OpenGlRenderState&) const)&pangolin::View::ActivateScissorAndClear)
.def("ActivatePixelOrthographic", &pangolin::View::ActivatePixelOrthographic)
.def("ActivateIdentity", &pangolin::View::ActivateIdentity)
.def("GetClosestDepth", &pangolin::View::GetClosestDepth)
.def("GetCamCoordinates", &pangolin::View::GetCamCoordinates)
.def("GetObjectCoordinates", &pangolin::View::GetObjectCoordinates)
.def("Resize", &pangolin::View::Resize)
.def("ResizeChildren", &pangolin::View::ResizeChildren)
.def("Render", &pangolin::View::Render)
.def("RenderChildren", &pangolin::View::RenderChildren)
.def("SetFocus", &pangolin::View::SetFocus)
.def("HasFocus", &pangolin::View::HasFocus)
.def("SetBounds", (pangolin::View& (pangolin::View::*)(pangolin::Attach, pangolin::Attach, pangolin::Attach, pangolin::Attach))&pangolin::View::SetBounds)
.def("SetBounds", (pangolin::View& (pangolin::View::*)(pangolin::Attach, pangolin::Attach, pangolin::Attach, pangolin::Attach, bool))&pangolin::View::SetBounds)
.def("SetBounds", (pangolin::View& (pangolin::View::*)(pangolin::Attach, pangolin::Attach, pangolin::Attach, pangolin::Attach, double))&pangolin::View::SetBounds)
.def("SetHandler", [](pangolin::View& v, pangolin::Handler& h) -> pangolin::View& {return v.SetHandler(&h);}, pybind11::return_value_policy::reference)
.def("SetDrawFunction", &pangolin::View::SetDrawFunction)
.def("SetAspect", &pangolin::View::SetAspect)
.def("SetLock", &pangolin::View::SetLock)
.def("SetLayout", &pangolin::View::SetLayout)
.def("AddDisplay", &pangolin::View::AddDisplay)
.def("Show", &pangolin::View::Show, pybind11::arg("show") = true)
.def("ToggleShow", &pangolin::View::ToggleShow)
.def("IsShown", &pangolin::View::IsShown)
.def("GetBounds", &pangolin::View::GetBounds)
.def("SaveOnRender", &pangolin::View::SaveOnRender)
.def("RecordOnRender", &pangolin::View::RecordOnRender)
.def("SaveRenderNow", &pangolin::View::SaveRenderNow)
.def("NumChildren", &pangolin::View::NumChildren)
.def("GetChild", [] (pangolin::View &v, size_t i) -> pangolin::View& { return v[i];}, pybind11::return_value_policy::reference)
.def("VisibleChild", &pangolin::View::VisibleChild)
.def("FindChild", &pangolin::View::FindChild)
.def("NumVisibleChildren", &pangolin::View::NumVisibleChildren);
pybind11::enum_<pangolin::Layout>(m, "Layout")
.value("Overlay", pangolin::LayoutOverlay)
.value("Vertical", pangolin::LayoutVertical)
.value("Horizontal", pangolin::LayoutHorizontal)
.value("Equal", pangolin::LayoutEqual)
.value("EqualVertical", pangolin::LayoutEqualVertical)
.value("EqualHorizontal", pangolin::LayoutEqualHorizontal);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_view(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,56 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "viewport.hpp"
#include <pangolin/display/viewport.h>
namespace py_pangolin {
void bind_viewport(pybind11::module &m) {
pybind11::class_<pangolin::Viewport>(m, "Viewport")
.def(pybind11::init<>())
.def(pybind11::init<int, int, int, int>())
.def("Activate", &pangolin::Viewport::Activate)
.def("ActivateIdentity", &pangolin::Viewport::ActivateIdentity)
.def("ActivatePixelOrthographic", &pangolin::Viewport::ActivatePixelOrthographic)
.def("Scissor", &pangolin::Viewport::Scissor)
.def("ActivateAndScissor", &pangolin::Viewport::ActivateAndScissor)
.def("Contains", &pangolin::Viewport::Contains)
.def("Inset", (pangolin::Viewport (pangolin::Viewport::*)(int)const)&pangolin::Viewport::Inset)
.def("Inset", (pangolin::Viewport (pangolin::Viewport::*)(int, int)const)&pangolin::Viewport::Inset)
.def("Insetsect", &pangolin::Viewport::Intersect)
.def("DisableScissor", &pangolin::Viewport::DisableScissor)
.def("r", &pangolin::Viewport::r)
.def("t", &pangolin::Viewport::t)
.def("aspect", &pangolin::Viewport::aspect)
.def_readwrite("l", &pangolin::Viewport::l)
.def_readwrite("b", &pangolin::Viewport::b)
.def_readwrite("w", &pangolin::Viewport::w)
.def_readwrite("h", &pangolin::Viewport::h);
}
} // py_pangolin

View File

@@ -0,0 +1,38 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin{
void bind_viewport(pybind11::module &m);
} // py_pangolin

View File

@@ -0,0 +1,36 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 "widget.hpp"
#include <pangolin/display/widgets/widgets.h>
namespace py_pangolin {
void bind_widget(pybind11::module &m){
m.def("CreatePanel", &pangolin::CreatePanel, pybind11::return_value_policy::reference);
}
} // py_pangolin

View File

@@ -0,0 +1,37 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) Andrey Mnatsakanov
*
* 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 <pybind11/pybind11.h>
namespace py_pangolin {
void bind_widget(pybind11::module &m);
} // py_pangolin

Some files were not shown because too many files have changed in this diff Show More