├── imgui_ros_msgs ├── include │ └── foo ├── srv │ ├── AddProjector.srv │ ├── AddShape.srv │ ├── AddTf.srv │ ├── AddCamera.srv │ ├── AddShaders.srv │ ├── AddTexture.srv │ ├── AddCubeCamera.srv │ └── AddWindow.srv ├── msg │ ├── Vertex.msg │ ├── TfWidget.msg │ ├── Projector.msg │ ├── Camera.msg │ ├── Widget.msg │ └── TexturedShape.msg ├── package.xml └── CMakeLists.txt ├── imgui_ros ├── data │ ├── black.png │ ├── square.png │ ├── white.png │ └── gradient.png ├── scripts │ ├── old │ │ ├── imgui_ros │ │ │ ├── __init__.py │ │ │ └── demo_imgui_ros.py │ │ ├── demo.sh │ │ ├── usb_cam_viewer.py │ │ └── graph.py │ ├── test_rosout.py │ ├── node_graph.py │ ├── console.py │ ├── add_shaders_utility.py │ ├── demo_viz3d.py │ ├── to_mesh.py │ └── demo2.py ├── include │ └── imgui_ros │ │ ├── utility.h │ │ ├── point_cloud.h │ │ ├── graph.h │ │ ├── image_transfer.h │ │ ├── viz2d.h │ │ ├── param.h │ │ ├── bag_console.h │ │ ├── dynamic_reconfigure.h │ │ ├── tf.h │ │ ├── cube_camera.h │ │ ├── shaders.h │ │ ├── projector.h │ │ ├── sub.h │ │ ├── surface.h │ │ ├── imgui_ros.h │ │ ├── window.h │ │ ├── image.h │ │ ├── camera.h │ │ └── node.h ├── config │ ├── depth_vertex.glsl │ ├── depth_fragment.glsl │ ├── cube_camera_fragment.glsl │ ├── cube_camera_vertex.glsl │ └── vertex.glsl ├── launch │ ├── console.launch │ ├── dragndrop.launch │ ├── viz3d.launch │ ├── old │ │ ├── demo_launch.py │ │ ├── graph_launch.py │ │ ├── shaders_launch.py │ │ └── usb_cam_launch.py │ ├── cyberscape.launch │ └── cam.launch ├── src │ ├── utility.cpp │ ├── nodes │ │ ├── imgui_ros_node.cpp │ │ ├── executor_imgui_ros_node.cpp │ │ └── usb_cam_viewer.cpp │ ├── sub.cpp │ ├── point_cloud.cpp │ ├── pub.cpp │ ├── test │ │ └── generate_pointcloud2.cpp │ ├── window.cpp │ ├── param_to_topic.cpp │ ├── surface.cpp │ └── shaders.cpp ├── package.xml └── CMakeLists.txt ├── README.md ├── LICENSE └── .github └── workflows ├── codeql-analysis.yml ├── ubuntu_18_04.yml └── ubuntu_20_04.yml /imgui_ros_msgs/include/foo: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imgui_ros/data/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucasw/imgui_ros/HEAD/imgui_ros/data/black.png -------------------------------------------------------------------------------- /imgui_ros/data/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucasw/imgui_ros/HEAD/imgui_ros/data/square.png -------------------------------------------------------------------------------- /imgui_ros/data/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucasw/imgui_ros/HEAD/imgui_ros/data/white.png -------------------------------------------------------------------------------- /imgui_ros/data/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucasw/imgui_ros/HEAD/imgui_ros/data/gradient.png -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddProjector.srv: -------------------------------------------------------------------------------- 1 | imgui_ros_msgs/Projector projector 2 | --- 3 | string message # "" 4 | bool success # False 5 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddShape.srv: -------------------------------------------------------------------------------- 1 | imgui_ros_msgs/TexturedShape[] shapes 2 | --- 3 | string message # "" 4 | bool success # False 5 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddTf.srv: -------------------------------------------------------------------------------- 1 | # the name needs to be unique, it will overwrite same named textures otherwise. 2 | imgui_ros_msgs/TfWidget tf 3 | --- 4 | string message # "" 5 | bool success # False 6 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddCamera.srv: -------------------------------------------------------------------------------- 1 | # the name needs to be unique, it will overwrite same named textures otherwise. 2 | imgui_ros_msgs/Camera camera 3 | --- 4 | string message # "" 5 | bool success # False 6 | -------------------------------------------------------------------------------- /imgui_ros_msgs/msg/Vertex.msg: -------------------------------------------------------------------------------- 1 | geometry_msgs/Point vertex 2 | geometry_msgs/Vector3 normal 3 | std_msgs/ColorRGBA color 4 | # TODO(lucasw) could make 2d vector for this, but maybe have 3d textures at some point? 5 | geometry_msgs/Vector3 uv 6 | -------------------------------------------------------------------------------- /imgui_ros/scripts/old/imgui_ros/__init__.py: -------------------------------------------------------------------------------- 1 | from .add_shaders import AddShadersNode, add_default_shaders 2 | from .demo_imgui_ros import DemoImguiRos 3 | from .demo_gui import DemoGui 4 | from .cameras import Cameras 5 | from .pub_shape import PubShape 6 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/utility.h: -------------------------------------------------------------------------------- 1 | #ifndef IMGUI_ROS_UTILITY_H 2 | #define IMGUI_ROS_UTILITY_H 3 | 4 | #include 5 | 6 | namespace imgui_ros 7 | { 8 | bool inputText(const std::string name, std::string& text); 9 | } // namespace imgui_ros 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddShaders.srv: -------------------------------------------------------------------------------- 1 | # the name needs to be unique, it will overwrite same named textures otherwise. 2 | string name 3 | string vertex 4 | string geometry 5 | string fragment 6 | bool remove # false 7 | --- 8 | string message # "" 9 | bool success # False 10 | -------------------------------------------------------------------------------- /imgui_ros_msgs/msg/TfWidget.msg: -------------------------------------------------------------------------------- 1 | string name # "" 2 | string window # "" 3 | string tab_name # "" 4 | bool remove # False 5 | # default values for all sliders, min and max are relative to these numbers 6 | geometry_msgs/TransformStamped transform_stamped 7 | float64 min # -1.0 8 | float64 max # 1.0 9 | -------------------------------------------------------------------------------- /imgui_ros/config/depth_vertex.glsl: -------------------------------------------------------------------------------- 1 | uniform mat4 model_matrix; 2 | uniform mat4 view_matrix; 3 | uniform mat4 projection_matrix; 4 | in vec3 Position; 5 | 6 | void main() 7 | { 8 | mat4 mvp = projection_matrix * view_matrix * model_matrix; 9 | gl_Position = mvp * vec4(Position.xyz, 1.0); 10 | } 11 | -------------------------------------------------------------------------------- /imgui_ros/launch/console.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddTexture.srv: -------------------------------------------------------------------------------- 1 | uint8 CLAMP_TO_EDGE=0 2 | uint8 MIRRORED_REPEAT=1 3 | uint8 REPEAT=2 4 | # the name needs to be unique, it will overwrite same named textures otherwise. 5 | string name 6 | # TODO(lucasw) make Texture msg 7 | sensor_msgs/Image image 8 | uint8 wrap_s # 0 9 | uint8 wrap_t # 0 10 | bool remove # false 11 | --- 12 | string message # "" 13 | bool success # False 14 | -------------------------------------------------------------------------------- /imgui_ros/launch/dragndrop.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /imgui_ros/config/depth_fragment.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D Texture; 2 | uniform sampler2D projector_shadow_map; 3 | out vec4 Out_Color; 4 | 5 | void main() 6 | { 7 | // TODO(lucasw) in nvidia need to access these texture otherwise too much optimization 8 | // happens and the depth fragment doesn't work? 9 | // Somewhere there are probably bound textures being used here meant for the default 10 | // shader. 11 | Out_Color = texture(Texture, vec2(0,0)) + texture(projector_shadow_map, vec2(0,0)); 12 | } 13 | -------------------------------------------------------------------------------- /imgui_ros/scripts/test_rosout.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | 4 | import rospy 5 | 6 | 7 | class TestRosout: 8 | def __init__(self): 9 | i = 0 10 | while not rospy.is_shutdown(): 11 | rospy.loginfo("test {}".format(i)) 12 | if i % 10 == 0: 13 | rospy.loginfo("foo {}".format(i)) 14 | rospy.sleep(0.05) 15 | i += 1 16 | 17 | if __name__ == '__main__': 18 | rospy.init_node('test_rosout') 19 | test_rosout = TestRosout() 20 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddCubeCamera.srv: -------------------------------------------------------------------------------- 1 | # the name needs to be unique, it will overwrite same named textures otherwise. 2 | imgui_ros_msgs/Camera camera 3 | # this should be about a quarter of the camera width and height if the 4 | # lens produces a panoramic image, otherwise it should be higher in proportion 5 | # and approach the camera width as the fov approaches one cube face (though 6 | # if that is the case a regular camera ought to be used). 7 | uint32 face_width # 512 8 | --- 9 | string message # "" 10 | bool success # False 11 | -------------------------------------------------------------------------------- /imgui_ros_msgs/msg/Projector.msg: -------------------------------------------------------------------------------- 1 | bool remove # False 2 | # camera width and height aren't used, the texture in texture_name defines that 3 | imgui_ros_msgs/Camera camera 4 | # stop projecting beyond this range - TODO(lucasw) redundant with Camera far? 5 | float32 max_range 6 | float32 constant_attenuation 7 | float32 linear_attenuation 8 | float32 quadratic_attenuation 9 | # TODO(lucasw) these would be interesting to implement 10 | # Combine the focal_distance with aov 11 | # to make image blur scale with distance 12 | # float focal_distance 13 | # float aperture ? 14 | -------------------------------------------------------------------------------- /imgui_ros/scripts/old/demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # https://unix.stackexchange.com/questions/55558/how-can-i-kill-and-wait-for-background-processes-to-finish-in-a-shell-script-whe 3 | trap 'killall' INT 4 | 5 | killall() { 6 | trap '' INT TERM # ignore INT and TERM while shutting down 7 | echo "**** Shutting down... ****" # added double quotes 8 | kill -TERM 0 # fixed order, send TERM not INT 9 | wait 10 | echo DONE 11 | } 12 | 13 | ros2 run internal_pub_sub node_loader & 14 | ros2 run imgui_ros demo_imgui_ros.py -n & 15 | 16 | cat # wait forever 17 | 18 | -------------------------------------------------------------------------------- /imgui_ros/src/utility.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace imgui_ros 5 | { 6 | 7 | bool inputText(const std::string name, std::string& text) 8 | { 9 | const size_t sz = 64; 10 | char buf[sz]; 11 | 12 | const size_t sz2 = (text.size() > (sz - 1)) ? (sz - 1) : text.size(); 13 | strncpy(buf, text.c_str(), sz2); 14 | buf[sz2] = '\0'; 15 | const bool changed = ImGui::InputText(name.c_str(), buf, sz, 16 | ImGuiInputTextFlags_EnterReturnsTrue); 17 | if (changed) { 18 | text = buf; 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | } // namespace imgui_ros 25 | -------------------------------------------------------------------------------- /imgui_ros/config/cube_camera_fragment.glsl: -------------------------------------------------------------------------------- 1 | // OpenGL makes the first vec4 `out` the fragment color by default 2 | // but should be explicit. 3 | // 130 4 | uniform samplerCube cube_map; 5 | 6 | // TODO(lucasw) 7 | // uniform sampler2D lens_normal_texture; 8 | // in vec2 fragment_uv; 9 | 10 | // TODO(lucasw) chromatic aberration? 11 | 12 | // TODO(lucasw) could use color to have the edges get dim 13 | // in vec4 fragment_color; 14 | smooth in vec3 fragment_normal; 15 | 16 | out vec4 fragment_color; 17 | 18 | void main() 19 | { 20 | // simple geometric normals to cube map lookup 21 | fragment_color.rgb = texture(cube_map, -fragment_normal).rgb; 22 | } 23 | -------------------------------------------------------------------------------- /imgui_ros/config/cube_camera_vertex.glsl: -------------------------------------------------------------------------------- 1 | uniform mat4 model_matrix; 2 | uniform mat4 view_matrix; 3 | uniform mat4 projection_matrix; 4 | 5 | in vec3 Position; 6 | in vec3 Normal; 7 | // in vec2 UV; 8 | // in vec4 Color; 9 | 10 | // out vec2 FraUV; 11 | 12 | smooth out vec3 fragment_normal; 13 | // out vec4 fragment_color; 14 | 15 | void main() 16 | { 17 | // FraUV = UV; 18 | // fragment_color = Color; 19 | // put normal into world frame 20 | fragment_normal = (model_matrix * vec4(Normal, 1.0)).xyz - 21 | (model_matrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 22 | 23 | mat4 mvp = projection_matrix * view_matrix * model_matrix; 24 | gl_Position = mvp * vec4(Position.xyz, 1.0); 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imgui_ros 2 | 3 | View ros images and interact with node topics, services, 4 | and parameters using imgui (https://github.com/ocornut/imgui). 5 | 6 | ## Instructions 7 | 8 | 9 | ``` 10 | sudo apt install libglm-dev libsdl2-dev ros-melodic-pcl-ros libyaml-cpp-dev 11 | pip3 install transforms3d 12 | ``` 13 | 14 | Run a demo: 15 | 16 | ``` 17 | cd ~/catkin_ws/src 18 | git clone https://github.com/lucasw/imgui_ros.git 19 | git clone https://github.com/lucasw/image_manip.git # required for the demo 20 | cd imgui_ros/imgui_ros 21 | git clone https://github.com/ocornut/imgui.git 22 | cd ~/catkin_ws/src 23 | catkin build imgui_ros image_manip 24 | source install/setup.bash 25 | roslaunch imgui_ros dragndrop.launch 26 | ``` 27 | -------------------------------------------------------------------------------- /imgui_ros_msgs/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | imgui_ros_msgs 4 | 0.0.0 5 | imgui user interface msgs for ros 6 | Lucas Walter 7 | BSD-3 8 | 9 | catkin 10 | 11 | message_generation 12 | sensor_msgs 13 | shape_msgs 14 | std_msgs 15 | tf2_geometry_msgs 16 | tf2_msgs 17 | message_generation 18 | sensor_msgs 19 | shape_msgs 20 | std_msgs 21 | tf2_geometry_msgs 22 | tf2_msgs 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /imgui_ros_msgs/msg/Camera.msg: -------------------------------------------------------------------------------- 1 | # this frame id in header is in gl frame, used internally for tf lookups 2 | std_msgs/Header header 3 | # the optical frame reported on published messages 4 | string header_frame_id 5 | # unique name, will replace any Camera received 6 | string name 7 | # needs to be unique out of all textures for cameras or shapes 8 | string texture_name 9 | bool add # True 10 | # publish onto ros2 dds 11 | bool ros_pub # False 12 | int32 width # 128 13 | int32 height # 128 14 | float32 aov_y # 90.0 15 | float32 aov_x # 0.0 # aov_x is width / height * aov_y if <= 0.0 16 | float32 near # 0.1 17 | float32 far # 100.0 18 | # publish the rendered image out on that topic. 19 | string topic # '' 20 | # TODO(lucasw) reduce update rate down from full frame rate 21 | # int32 update_skip 22 | # TODO(lucasw) focal distance and aperture to model depth of field 23 | # TODO(lucasw) later allow actual framerate, for now have to specify 24 | # number to skip before next render. 25 | uint8 skip # 0 26 | -------------------------------------------------------------------------------- /imgui_ros/launch/viz3d.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /imgui_ros_msgs/msg/Widget.msg: -------------------------------------------------------------------------------- 1 | uint8 PUB=1 2 | uint8 SUB=2 3 | uint8 PLOT=3 4 | uint8 PARAM=4 5 | uint8 GRAPH=5 6 | uint8 DYNREC=6 7 | # pub sub types 8 | uint8 BOOL=0 9 | uint8 FLOAT32=1 10 | uint8 FLOAT64=2 11 | uint8 INT8=3 12 | uint8 INT16=4 13 | uint8 INT32=5 14 | uint8 INT64=6 15 | uint8 UINT8=7 16 | uint8 UINT16=8 17 | uint8 UINT32=9 18 | uint8 UINT64=10 19 | uint8 STRING=11 20 | uint8 MENU=12 21 | uint8 TF=13 22 | uint8 VIZ2D=14 23 | uint8 VIZ3D=15 24 | uint8 POINTCLOUD=16 25 | uint8 IMAGE=17 26 | uint8 ROSOUT=18 27 | # uint8 TODO(lucasw) 28 | string name # "" 29 | # TODO(lucasw) maybe window_name belongs here too? 30 | # Or get tab name out of here and push up to AddWindow 31 | # currently Widget is within AddWindow, but could refactor that. 32 | string tab_name # "" 33 | string topic # "" 34 | uint8 type # 1 # PUB 35 | uint8 sub_type # 1 # FLOAT32 36 | bool remove # False 37 | float64 value # 0.0 38 | float64 min # 0.0 39 | float64 max # 1.0 40 | bool enable_info # True # draw extra misc info, controls 41 | string[] items 42 | -------------------------------------------------------------------------------- /imgui_ros/launch/old/demo_launch.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Lucas Walter 2 | 3 | import launch 4 | import launch_ros.actions 5 | import os 6 | import yaml 7 | 8 | from ament_index_python.packages import get_package_share_directory 9 | 10 | def generate_launch_description(): 11 | 12 | launches = [] 13 | 14 | # TODO(lucasw) all the nodes come out named node_loader when using this launch file, 15 | # otherwise they are named as desired. 16 | node = launch_ros.actions.Node( 17 | package='internal_pub_sub', 18 | node_executable='node_loader', 19 | output='screen', 20 | node_name='node_loader', 21 | ) 22 | launches.append(node) 23 | 24 | node = launch_ros.actions.Node( 25 | package='imgui_ros', 26 | node_executable='demo_imgui_ros.py', 27 | node_name='demo_imgui_ros', 28 | output='screen', 29 | arguments=['-n'], 30 | ) 31 | launches.append(node) 32 | 33 | return launch.LaunchDescription(launches) 34 | -------------------------------------------------------------------------------- /imgui_ros/scripts/node_graph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2019 Lucas Walter 3 | # November 2019 4 | # Get a list of all nodes, and what topics they publish and subscribe too. 5 | # Advance work for generating a node graph. 6 | 7 | import rosgraph 8 | import rosnode 9 | import rospy 10 | 11 | 12 | if __name__ == '__main__': 13 | rospy.init_node('node_graph') 14 | node_names = rosnode.get_node_names() 15 | 16 | master = rosgraph.Master(rospy.get_name()) 17 | print(master) 18 | try: 19 | state = master.getSystemState() 20 | pub_topics = master.getPublishedTopics('/') 21 | except socket.error: 22 | raise ROSNodeIOException("Unable to communicate with master!") 23 | 24 | for node_name in node_names: 25 | pubs = [t for t, l in state[0] if node_name in l] 26 | subs = [t for t, l in state[1] if node_name in l] 27 | srvs = [t for t, l in state[2] if node_name in l] 28 | 29 | rospy.loginfo(node_name) 30 | print(' pubs: {}'.format(pubs)) 31 | print(' subs: {}'.format(subs)) 32 | -------------------------------------------------------------------------------- /imgui_ros_msgs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(imgui_ros_msgs) 3 | 4 | find_package(catkin REQUIRED COMPONENTS 5 | geometry_msgs 6 | message_generation 7 | sensor_msgs 8 | shape_msgs 9 | std_msgs 10 | tf2_geometry_msgs 11 | tf2_msgs 12 | tf2_ros 13 | visualization_msgs 14 | ) 15 | 16 | add_message_files( 17 | FILES 18 | Camera.msg 19 | Projector.msg 20 | Vertex.msg 21 | Widget.msg 22 | TexturedShape.msg 23 | TfWidget.msg 24 | ) 25 | 26 | add_service_files( 27 | FILES 28 | AddCamera.srv 29 | AddCubeCamera.srv 30 | AddProjector.srv 31 | AddTf.srv 32 | AddTexture.srv 33 | AddWindow.srv 34 | AddShape.srv 35 | AddShaders.srv 36 | ) 37 | 38 | generate_messages( 39 | DEPENDENCIES geometry_msgs sensor_msgs shape_msgs std_msgs 40 | ) 41 | 42 | catkin_package( 43 | # LIBRARIES ${PROJECT_NAME} 44 | CATKIN_DEPENDS message_generation sensor_msgs std_msgs 45 | ) 46 | 47 | # TODO(lucasw) I think this was trying to install an include directory that is empty but 48 | # is populated later? 49 | # install(DIRECTORY include/${PROJECT_NAME}/ 50 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 51 | # PATTERN ".svn" EXCLUDE) 52 | -------------------------------------------------------------------------------- /imgui_ros_msgs/srv/AddWindow.srv: -------------------------------------------------------------------------------- 1 | string name 2 | bool remove # false 3 | imgui_ros_msgs/Widget[] widgets 4 | # TODO(lucasw) any number of other window properties 5 | # these are saved in the imgui.ini file 6 | # whether to use the settings before, or continue to use 7 | # what has already been set. 8 | bool init # False 9 | bool fractional # False # interpret the position and size as 0.0 - 1.0 fractional values 10 | geometry_msgs/Point position 11 | geometry_msgs/Point size 12 | # 0 - 1.0 to scroll from min to max 13 | # doesn't work if it takes some time for all window contents to determin y size 14 | float32 scroll_x # not currently supported 15 | float32 scroll_y 16 | bool collapsed # False 17 | # TODO(lucasw) pass in flags as int just as ImGui expects- but 18 | # is it hard to give python access to what the flags are? 19 | bool no_move # False # don't allow dragging on the window to move it (TODO ConfigWindowsMoveFromTitleBarOnly) 20 | bool no_title_bar # False 21 | bool no_resize # False 22 | bool no_scrollbar # False 23 | bool no_collapse # False 24 | bool no_decoration # False # combines title, resize, scrollbar, collapse 25 | --- 26 | string message # "" 27 | bool success # False 28 | -------------------------------------------------------------------------------- /imgui_ros/launch/cyberscape.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /imgui_ros_msgs/msg/TexturedShape.msg: -------------------------------------------------------------------------------- 1 | std_msgs/Header header 2 | # unique name, will replace any textured shape already received 3 | string name 4 | bool add # True 5 | # whether to draw this shape 6 | bool enable # True 7 | # where the shape is relative to the header frame_id 8 | # TODO(lucasw) or make this a TransformStamped, and have the position computed 9 | # relative to the header frame id at the time in the TransformStamped, 10 | # but then at later timesteps it remains fixed relative to the header frame_id? 11 | # No should just have the caller figure that out. 12 | # TODO(lucasw) this belongs in a ShapeInstance.msg, this msg should be 13 | # just for the geometry to be stored but doesn't actually create an instance to be rendered. 14 | imgui_ros_msgs/Vertex[] vertices 15 | # List of triangles; the index values refer to positions in vertices[]. 16 | shape_msgs/MeshTriangle[] triangles 17 | # the name of the texture, which needs to be stored in the receiver unless 18 | # it is a topic or supplied below. 19 | # If blank use solid colors. 20 | string texture # "" 21 | # this texture corresponds to the shininess of the specular reflection 22 | # at the same uv coordinates of the texture above. 23 | string shininess_texture # "" 24 | string emission_texture # "" 25 | # get the texture from an image topic specified in texture 26 | bool is_topic # false 27 | # specify which set of already loaded shaders to use- 28 | # This should map to consistent pair of vertex and fragment shaders 29 | # (though could maybe specify those independently here) 30 | # If blank use default shader 31 | string shader # "" 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Lucas Walter 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /imgui_ros/scripts/console.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2018 Lucas Walter 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # TODO(lucasW) this doesn't exist in python yet? 17 | # import tf2_ros 18 | import rospy 19 | 20 | from imgui_ros_msgs.msg import Widget 21 | from imgui_ros_msgs.srv import AddWindow, AddWindowRequest 22 | 23 | 24 | class Console: 25 | def __init__(self): 26 | rospy.wait_for_service('add_window') 27 | self.cli = rospy.ServiceProxy('add_window', AddWindow) 28 | 29 | self.add_console() 30 | 31 | def add_console(self): 32 | # TF control widgets 33 | req = AddWindowRequest() 34 | req.name = "console" 35 | tab_name = "console2" 36 | 37 | widget = Widget() 38 | widget.name = "console3" 39 | widget.tab_name = tab_name 40 | widget.type = Widget.SUB 41 | widget.sub_type = Widget.ROSOUT 42 | widget.topic = "/rosout_agg" 43 | req.widgets.append(widget) 44 | 45 | # All the above take up about 10% cpu 46 | self.cli(req) 47 | 48 | if __name__ == '__main__': 49 | rospy.init_node('setup_console') 50 | console = Console() 51 | -------------------------------------------------------------------------------- /imgui_ros/launch/old/graph_launch.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Lucas Walter 2 | 3 | import launch 4 | import launch_ros.actions 5 | import os 6 | import yaml 7 | 8 | from ament_index_python.packages import get_package_share_directory 9 | 10 | def generate_launch_description(): 11 | # image_manip_dir = get_package_share_directory('image_manip') 12 | # print('image_manip dir ' + image_manip_dir) 13 | 14 | launches = [] 15 | 16 | node_name = 'imgui_ros' 17 | params = dict( 18 | name = 'imgui_ros demo', 19 | width = 1000, 20 | height = 800, 21 | ) 22 | node = launch_ros.actions.Node( 23 | package='imgui_ros', node_executable='imgui_ros_node', output='screen', 24 | node_name=node_name, 25 | # arguments=[image_manip_dir + "/data/mosaic.jpg"]) 26 | # arguments=['__params:=' + param_file], 27 | parameters=[params], 28 | remappings=[]) 29 | launches.append(node) 30 | 31 | node = launch_ros.actions.Node( 32 | package='imgui_ros', node_executable='graph.py', output='screen') 33 | launches.append(node) 34 | 35 | if False: 36 | node = launch.actions.IncludeLaunchDescription( 37 | launch.launch_description_sources.PythonLaunchDescriptionSource( 38 | get_package_share_directory('imgui_ros') + '/launch/shaders_launch.py')) 39 | launches.append(node) 40 | 41 | node = launch_ros.actions.Node( 42 | package='imgui_ros', node_executable='pub_shape.py', output='screen', 43 | ) 44 | launches.append(node) 45 | node = launch_ros.actions.Node( 46 | package='imgui_ros', node_executable='cameras.py', output='screen', 47 | ) 48 | launches.append(node) 49 | 50 | return launch.LaunchDescription(launches) 51 | -------------------------------------------------------------------------------- /imgui_ros/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | imgui_ros 4 | 0.0.0 5 | imgui user interface for ros 6 | Lucas Walter 7 | BSD-3 8 | 9 | catkin 10 | 11 | cv_bridge 12 | dynamic_reconfigure 13 | imgui_ros_msgs 14 | nodelet 15 | pcl_conversions 16 | roscpp 17 | 18 | sensor_msgs 19 | shape_msgs 20 | std_msgs 21 | tf2_geometry_msgs 22 | tf2_msgs 23 | usb_cam 24 | visualization_msgs 25 | 26 | cv_bridge 27 | dynamic_reconfigure 28 | imgui_ros_msgs 29 | nodelet 30 | pcl_conversions 31 | roscpp 32 | 33 | rospy 34 | sensor_msgs 35 | shape_msgs 36 | std_msgs 37 | tf2_geometry_msgs 38 | tf2_msgs 39 | visualization_msgs 40 | usb_cam 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /imgui_ros/src/nodes/imgui_ros_node.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | int main(int argc, char * argv[]) 37 | { 38 | setvbuf(stdout, NULL, _IONBF, BUFSIZ); 39 | ros::init(argc, argv); 40 | const bool ros_pub_enable = false; 41 | auto core = std::make_shared(ros_pub_enable); 42 | auto imgui_ros = std::make_shared(); 43 | imgui_ros->init("imgui_ros"); 44 | imgui_ros->postInit(core); 45 | ros::spin(imgui_ros); 46 | ros::shutdown(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /imgui_ros/config/vertex.glsl: -------------------------------------------------------------------------------- 1 | const int MAX_PROJECTORS = 6; 2 | 3 | uniform mat4 model_matrix; 4 | uniform mat4 view_matrix; 5 | uniform mat4 projection_matrix; 6 | // the transpose of the projector view matrix times an xyz position relative 7 | // to the projector should yield world coordinates 8 | uniform mat4 projector_view_matrix[MAX_PROJECTORS]; 9 | uniform mat4 projector_view_matrix_inverse[MAX_PROJECTORS]; 10 | uniform mat4 projector_projection_matrix[MAX_PROJECTORS]; 11 | 12 | in vec3 Position; 13 | in vec3 Normal; 14 | in vec2 UV; 15 | in vec4 Color; 16 | in float shininess; 17 | 18 | out vec2 FraUV; 19 | 20 | smooth out vec3 FraNormal; 21 | smooth out vec3 fragment_pos; 22 | 23 | out vec4 FraColor; 24 | out vec4 ProjectedTexturePosition[MAX_PROJECTORS]; 25 | // The coordinate frame of this direction needs to be the same as the output normal 26 | out vec3 projector_pos[MAX_PROJECTORS]; 27 | out vec3 projector_dir[MAX_PROJECTORS]; 28 | 29 | void main() 30 | { 31 | FraUV = UV; 32 | FraColor = Color; 33 | // put normal into world frame 34 | FraNormal = (model_matrix * vec4(Normal, 1.0)).xyz - 35 | (model_matrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 36 | fragment_pos = (model_matrix * vec4(Position.xyz, 1.0)).xyz; 37 | 38 | mat4 mvp = projection_matrix * view_matrix * model_matrix; 39 | gl_Position = mvp * vec4(Position.xyz, 1.0); 40 | 41 | for (int i = 0; i < MAX_PROJECTORS; ++i) { 42 | // for (int i = 0; i < 1; ++i) { 43 | // TODO(lucasw) this is per-model so perhaps would be better in cpu 44 | mat4 projector_mvp = projector_projection_matrix[i] * projector_view_matrix[i] * model_matrix; 45 | // the vertex does get used here, so this needs to be in this shader 46 | ProjectedTexturePosition[i] = projector_mvp * vec4(Position.xyz, 1.0); 47 | 48 | // TODO(lucasw) this could be done outside of the vertex shader entirely, 49 | // it is redundant to calculate it over and over per vertex. 50 | // put projector into world frame 51 | vec4 origin = vec4(0.0, 0.0, 0.0, 1.0); 52 | vec4 z_axis = vec4(0.0, 0.0, 1.0, 1.0); 53 | 54 | // TODO(lucasw) instead pass in position and direction as calculated on cpu? 55 | // The inverse isn't used for anything else 56 | projector_pos[i] = (projector_view_matrix_inverse[i] * origin).xyz; 57 | projector_dir[i] = (projector_view_matrix_inverse[i] * z_axis).xyz - projector_pos[i]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /imgui_ros/launch/old/shaders_launch.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Lucas Walter 2 | 3 | import launch 4 | import launch_ros.actions 5 | import os 6 | import yaml 7 | 8 | from ament_index_python.packages import get_package_share_directory 9 | 10 | 11 | def generate_launch_description(): 12 | prefix = '/tmp/ros2/imgui_ros_demo/' 13 | if not os.path.exists(prefix): 14 | os.makedirs(prefix) 15 | 16 | namespace = launch.substitutions.LaunchConfiguration('namespace', default='') 17 | 18 | shader_dir = get_package_share_directory('imgui_ros') + '/../../lib/imgui_ros/' 19 | vertex_filename = shader_dir + 'vertex.glsl' 20 | fragment_filename = shader_dir + 'fragment.glsl' 21 | add_default_shaders = launch_ros.actions.Node( 22 | package='imgui_ros', node_executable='add_shaders.py', 23 | node_name='add_default_shaders', 24 | node_namespace=[namespace], 25 | output='screen', 26 | arguments=['-n', 'default', '-v', vertex_filename, '-f', fragment_filename], 27 | ) 28 | vertex_filename = shader_dir + 'depth_vertex.glsl' 29 | fragment_filename = shader_dir + 'depth_fragment.glsl' 30 | add_depth_shaders = launch_ros.actions.Node( 31 | package='imgui_ros', node_executable='add_shaders.py', 32 | node_name='add_depth_shaders', 33 | node_namespace=[namespace], 34 | output='screen', 35 | arguments=['-n', 'depth', '-v', vertex_filename, '-f', fragment_filename], 36 | ) 37 | vertex_filename = shader_dir + 'cube_camera_vertex.glsl' 38 | fragment_filename = shader_dir + 'cube_camera_fragment.glsl' 39 | add_cube_camera_shaders = launch_ros.actions.Node( 40 | package='imgui_ros', node_executable='add_shaders.py', 41 | node_name='add_cube_camera_shaders', 42 | node_namespace=[namespace], 43 | output='screen', 44 | arguments=['-n', 'cube_map', '-v', vertex_filename, '-f', fragment_filename], 45 | ) 46 | 47 | return launch.LaunchDescription([ 48 | launch.actions.DeclareLaunchArgument( 49 | 'namespace', 50 | default_value='', # TODO(lwalter) redundant with default above? 51 | description='namespace to run in'), 52 | add_default_shaders, 53 | add_depth_shaders, 54 | add_cube_camera_shaders, 55 | ]) 56 | -------------------------------------------------------------------------------- /imgui_ros/src/nodes/executor_imgui_ros_node.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | int main(int argc, char * argv[]) 38 | { 39 | setvbuf(stdout, NULL, _IONBF, BUFSIZ); 40 | ros::init(argc, argv); 41 | auto core = std::make_shared(); 42 | auto imgui_ros = std::make_shared(); 43 | imgui_ros->init("imgui_ros"); 44 | imgui_ros->postInit(core); 45 | ros::executors::SingleThreadedExecutor executor; 46 | executor.add_node(imgui_ros); 47 | executor.spin(); 48 | // ros::spin(imgui_ros); 49 | ros::shutdown(); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /imgui_ros/launch/cam.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | - 'image_transport/compressed' 46 | - 'image_transport/compressedDepth' 47 | - 'image_transport/theora' 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [melodic] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [melodic] 9 | schedule: 10 | - cron: '0 17 * * 4' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | # Override automatic language detection by changing the below list 21 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 22 | # TODO(lucasw) Disabling cpp for now, would need to install ros and bring 23 | # in all the ros dependencies for cpp build and then be analyzed. 24 | # That is already done in the other action, don't want to duplicate it. 25 | # language: ['cpp', 'python'] 26 | language: ['python'] 27 | # Learn more... 28 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 29 | 30 | steps: 31 | - name: Checkout repository 32 | uses: actions/checkout@v2 33 | with: 34 | # We must fetch at least the immediate parents so that if this is 35 | # a pull request then we can checkout the head. 36 | fetch-depth: 2 37 | 38 | # If this run was triggered by a pull request event, then checkout 39 | # the head of the pull request instead of the merge commit. 40 | - run: git checkout HEAD^2 41 | if: ${{ github.event_name == 'pull_request' }} 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | 49 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 50 | # If this step fails, then you should remove it and run the build manually (see below) 51 | - name: Autobuild 52 | uses: github/codeql-action/autobuild@v1 53 | 54 | # ℹ️ Command-line programs to run using the OS shell. 55 | # 📚 https://git.io/JvXDl 56 | 57 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 58 | # and modify them (or add more) to build your code if your project 59 | # uses a compiled language 60 | 61 | #- run: | 62 | # make bootstrap 63 | # make release 64 | 65 | - name: Perform CodeQL Analysis 66 | uses: github/codeql-action/analyze@v1 67 | -------------------------------------------------------------------------------- /imgui_ros/src/sub.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | using std::placeholders::_1; 34 | 35 | namespace imgui_ros 36 | { 37 | Sub::Sub(const std::string name, const std::string topic, // const unsigned type, 38 | ros::NodeHandle& nh) : 39 | Widget(name, topic) { 40 | (void)nh; 41 | } 42 | 43 | BoolSub::BoolSub(const std::string name, const std::string topic, // const unsigned type, 44 | const bool value, 45 | ros::NodeHandle& nh) : 46 | Sub(name, topic, nh) { 47 | (void)value; 48 | // msg_.reset(new std_msgs::Bool); 49 | sub_ = nh.subscribe(topic, 3, &BoolSub::callback, this); 50 | } 51 | 52 | void BoolSub::callback(const std_msgs::Bool::ConstPtr msg) 53 | { 54 | std::lock_guard lock(mutex_); 55 | msg_ = msg; 56 | } 57 | 58 | void BoolSub::draw() { 59 | std::lock_guard lock(mutex_); 60 | std::stringstream ss; 61 | ss << name_ << ": "; 62 | if (msg_) { 63 | ss << (msg_->data ? "True" : "False"); 64 | } 65 | ImGui::Text("%s", ss.str().c_str()); 66 | } 67 | } // namespace imgui_ros 68 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/point_cloud.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_POINT_CLOUD_H 32 | #define IMGUI_ROS_POINT_CLOUD_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | 48 | namespace imgui_ros 49 | { 50 | struct PointCloud : public Sub 51 | { 52 | PointCloud(const std::string name, const std::string topic, 53 | std::shared_ptr tf_buffer, 54 | ros::NodeHandle& node); 55 | ~PointCloud() {} 56 | 57 | virtual void draw(); 58 | void render(); 59 | std::shared_ptr shape_; 60 | protected: 61 | pcl::PointCloud cloud_; 62 | sensor_msgs::PointCloud2::ConstPtr msg_; 63 | void pointCloud2Callback(const sensor_msgs::PointCloud2::ConstPtr msg); 64 | ros::Subscriber sub_; 65 | }; 66 | 67 | } // namespace imgui_ros 68 | #endif // IMGUI_ROS_POINT_CLOUD_H 69 | -------------------------------------------------------------------------------- /imgui_ros/scripts/old/usb_cam_viewer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2018 Lucas Walter 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # TODO(lucasW) this doesn't exist in python yet? 17 | # import tf2_ros 18 | import math 19 | import rclpy 20 | 21 | from geometry_msgs.msg import Point, TransformStamped 22 | from imgui_ros.msg import TexturedShape, TfWidget, Widget 23 | from imgui_ros.srv import AddTf, AddWindow 24 | from rclpy.node import Node 25 | from shape_msgs.msg import MeshTriangle, Mesh 26 | from transforms3d import _gohlketransforms as tg 27 | from visualization_msgs.msg import Marker 28 | 29 | 30 | class Demo(Node): 31 | 32 | def __init__(self): 33 | super().__init__('usb_cam_viewer') 34 | self.cli = self.create_client(AddWindow, 'add_window') 35 | while not self.cli.wait_for_service(timeout_sec=3.0): 36 | self.get_logger().info('add_window service not available, waiting again...') 37 | 38 | # TODO(lucasw) can't this be a callback instead? 39 | def wait_for_response(self): 40 | while rclpy.ok(): 41 | rclpy.spin_once(self) 42 | if self.future.done(): 43 | if self.future.result() is not None: 44 | response = self.future.result() 45 | self.get_logger().info( 46 | 'Result %s' % (str(response))) 47 | else: 48 | self.get_logger().info( 49 | 'Service call failed %r' % (self.future.exception(),)) 50 | break 51 | 52 | def init(self): 53 | self.add_images() 54 | 55 | def add_images(self): 56 | req = AddWindow.Request() 57 | req.name = 'usb cam viewer' 58 | tab_name = 'images' 59 | widget = Widget() 60 | widget.name = "roto image" 61 | widget.tab_name = tab_name 62 | widget.topic = '/image_raw' 63 | widget.type = Widget.IMAGE 64 | req.widgets.append(widget) 65 | self.future = self.cli.call_async(req) 66 | self.wait_for_response() 67 | 68 | def main(args=None): 69 | rclpy.init(args=args) 70 | 71 | try: 72 | demo = Demo() 73 | demo.init() 74 | rclpy.spin(demo) 75 | finally: 76 | demo.destroy_node() 77 | rclpy.shutdown() 78 | 79 | if __name__ == '__main__': 80 | main() 81 | -------------------------------------------------------------------------------- /imgui_ros/scripts/old/graph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2018 Lucas Walter 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # TODO(lucasW) this doesn't exist in python yet? 17 | # import tf2_ros 18 | import math 19 | import rclpy 20 | 21 | from geometry_msgs.msg import Point, TransformStamped 22 | from imgui_ros.msg import TexturedShape, TfWidget, Widget 23 | from imgui_ros.srv import AddTf, AddWindow 24 | from rclpy.node import Node 25 | from shape_msgs.msg import MeshTriangle, Mesh 26 | from transforms3d import _gohlketransforms as tg 27 | from visualization_msgs.msg import Marker 28 | 29 | 30 | class Demo(Node): 31 | def __init__(self): 32 | super().__init__('demo') 33 | self.cli = self.create_client(AddWindow, 'add_window') 34 | while not self.cli.wait_for_service(timeout_sec=3.0): 35 | self.get_logger().info('service not available, waiting again...') 36 | self.tf_cli = self.create_client(AddTf, 'add_tf') 37 | while not self.tf_cli.wait_for_service(timeout_sec=3.0): 38 | self.get_logger().info('service not available, waiting again...') 39 | 40 | # TODO(lucasw) can't this be a callback instead? 41 | def wait_for_response(self): 42 | while rclpy.ok(): 43 | rclpy.spin_once(self) 44 | if self.future.done(): 45 | if self.future.result() is not None: 46 | response = self.future.result() 47 | self.get_logger().info( 48 | 'Result %s' % (str(response))) 49 | else: 50 | self.get_logger().info( 51 | 'Service call failed %r' % (self.future.exception(),)) 52 | break 53 | 54 | def run(self): 55 | req = AddWindow.Request() 56 | req.name = "graph" 57 | widget = Widget() 58 | widget.name = 'graph' 59 | widget.tab_name = 'graph' 60 | widget.type = Widget.GRAPH 61 | req.widgets.append(widget) 62 | self.future = self.cli.call_async(req) 63 | self.wait_for_response() 64 | 65 | def main(args=None): 66 | rclpy.init(args=args) 67 | 68 | try: 69 | demo = Demo() 70 | demo.run() 71 | rclpy.spin(demo) 72 | finally: 73 | demo.destroy_node() 74 | rclpy.shutdown() 75 | 76 | 77 | if __name__ == '__main__': 78 | main() 79 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_GRAPH_H 32 | #define IMGUI_ROS_GRAPH_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace imgui_ros 41 | { 42 | // TODO(lucasw) 43 | // namespace imgui_ros 44 | // TODO(lucasw) template ? 45 | // Or just make a subclass for each because the imgui draw code will be different 46 | // for each? 47 | struct Graph : public Widget { 48 | Graph(const std::string name, 49 | ros::NodeHandle& nh); 50 | // ~Graph(); 51 | virtual void draw(); 52 | virtual void update(const ros::Time& stamp); 53 | 54 | protected: 55 | // unsigned type_ = imgui_ros::AddWindow::Request::FLOAT32; 56 | ros::NodeHandle nh_; 57 | 58 | bool opened_; 59 | 60 | std::shared_ptr con_src_; 61 | std::shared_ptr con_dst_; 62 | 63 | std::map > nodes_; 64 | std::map > links_; 65 | bool linkNodes( 66 | const std::string& output_node_name, const std::string& output_node_con_name, 67 | const std::string& input_node_name, const std::string& input_node_con_name); 68 | ros::Time start_, stamp_; 69 | 70 | void init(); 71 | bool inited_ = false; 72 | 73 | ImVec2 scrolling_ = ImVec2(0.0f, 0.0f); 74 | bool show_grid_ = true; 75 | std::shared_ptr node_selected_; 76 | }; 77 | 78 | } // namespace imgui_ros 79 | #endif // IMGUI_ROS_GRAPH_H 80 | -------------------------------------------------------------------------------- /imgui_ros/scripts/add_shaders_utility.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2018 Lucas Walter 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import cv2 17 | import math 18 | import time 19 | import rospkg 20 | import rospy 21 | import sys 22 | 23 | from geometry_msgs.msg import Point, TransformStamped, Vector3 24 | from imgui_ros_msgs.msg import TexturedShape, Widget 25 | from imgui_ros_msgs.srv import AddShaders, AddShadersRequest 26 | from shape_msgs.msg import MeshTriangle, Mesh 27 | from std_msgs.msg import ColorRGBA 28 | from visualization_msgs.msg import Marker 29 | 30 | 31 | class AddShadersUtility(): 32 | def __init__(self): 33 | rospy.wait_for_service('add_shaders') 34 | self.shaders_cli = rospy.ServiceProxy('add_shaders', AddShaders) 35 | 36 | def add(self, name, vertex_filename, fragment_filename): 37 | req = AddShadersRequest() 38 | req.name = name 39 | req.vertex = '' 40 | if vertex_filename != '': 41 | with open(vertex_filename) as vertex_file: 42 | req.vertex = vertex_file.read() 43 | if req.vertex == '': 44 | rospy.logerr("couldn't load vertex shader from: '{}'".format(vertex_filename)) 45 | return False 46 | # print(req.vertex) 47 | # print('####################################################') 48 | req.fragment = '' 49 | if fragment_filename != '': 50 | with open(fragment_filename) as fragment_file: 51 | req.fragment = fragment_file.read() 52 | if req.vertex == '': 53 | rospy.logerr("couldn't load fragment shader from '{}'".format(fragment_filename)) 54 | return False 55 | # print(req.fragment) 56 | resp = self.shaders_cli(req) 57 | rospy.loginfo(resp) 58 | 59 | def add_default_shaders(): 60 | # TODO(lucasw) put the shaders into a config/data dir 61 | rospack = rospkg.RosPack() 62 | shader_dir = rospack.get_path('imgui_ros') + '/config/' 63 | rospy.loginfo("loading shaders '{}'".format(shader_dir)) 64 | if True: 65 | add_shaders = AddShadersUtility() 66 | add_shaders.add('default', 67 | shader_dir + 'vertex.glsl', 68 | shader_dir + 'fragment.glsl') 69 | add_shaders.add('depth', 70 | shader_dir + 'depth_vertex.glsl', 71 | shader_dir + 'depth_fragment.glsl') 72 | add_shaders.add('cube_map', 73 | shader_dir + 'cube_camera_vertex.glsl', 74 | shader_dir + 'cube_camera_fragment.glsl') 75 | 76 | if __name__ == '__main__': 77 | rospy.init_node("add_shaders") 78 | add_default_shaders() 79 | -------------------------------------------------------------------------------- /imgui_ros/launch/old/usb_cam_launch.py: -------------------------------------------------------------------------------- 1 | # Copyright Lucas Walter 2019 2 | # Requires internal_pub_sub branch of usb_cam https://github.com/lucasw/usb_cam/tree/internal_pub_sub 3 | # git clone -b internal_pub_sub https://github.com/lucasw/usb_cam 4 | 5 | import argparse 6 | import launch 7 | import launch_ros.actions 8 | import os 9 | import sys 10 | import time 11 | import yaml 12 | 13 | from ament_index_python.packages import get_package_share_directory 14 | from launch.substitutions import ThisLaunchFileDir 15 | 16 | 17 | def write_params(prefix, ns, node_name, params): 18 | name = prefix + ns + node_name + '_params.yaml' 19 | path = os.path.dirname(name) 20 | if not os.path.exists(path): 21 | os.makedirs(path) 22 | with open(name, 'w') as outfile: 23 | print('opened ' + name + ' for yaml parameter writing') 24 | data = {} 25 | data[ns] = {} 26 | for node_name in params.keys(): 27 | data[ns][node_name] = {} 28 | data[ns][node_name]['ros__parameters'] = params[node_name] 29 | yaml.dump(data, outfile, default_flow_style=False) 30 | return name 31 | print('error opening file for parameter writing: ' + name) 32 | return None 33 | 34 | def generate_launch_description(): 35 | parser = argparse.ArgumentParser(description='usb_cam_viewer') 36 | # parser.add_argument('-cmp', '--composed', dest='composed', 37 | # help='launch composed nodes', action='store_true') 38 | args, unknown = parser.parse_known_args(sys.argv[4:]) 39 | 40 | # can't set to '' 41 | namespace = '/' # '/tmp' 42 | 43 | device = '/dev/video0' 44 | usb_params = dict( 45 | video_device = device, 46 | # io_method 47 | # pixel_format 48 | image_width = 640, 49 | image_height = 480, 50 | # camera_name = 'usb_camera', 51 | ) 52 | imgui_params = dict( 53 | name = device, 54 | width = 800, 55 | height = 600, 56 | ) 57 | 58 | launches = [] 59 | if True: 60 | prefix = "/tmp/ros2/" + str(int(time.time())) + "/" 61 | print('writing launch parameter files to ' + prefix) 62 | 63 | params = {} 64 | params['usb_cam'] = usb_params 65 | params['imgui_ros'] = imgui_params 66 | 67 | # if the node_name is left blank, and all the default node names 68 | # match the names in params above, then the parameters will 69 | # get loaded 70 | composed_exec_name = 'usb_cam_viewer' 71 | param_file = write_params(prefix, namespace, composed_exec_name, params) 72 | params_arg = '__params:=' + param_file 73 | 74 | node = launch_ros.actions.Node( 75 | package='imgui_ros', 76 | node_executable=composed_exec_name, 77 | arguments=[params_arg], 78 | node_namespace=[namespace], 79 | remappings=[ 80 | ], 81 | output='screen') 82 | launches.append(node) 83 | 84 | node = launch_ros.actions.Node( 85 | package='imgui_ros', 86 | node_executable='usb_cam_viewer.py', 87 | node_namespace=[namespace], 88 | remappings=[ 89 | ], 90 | output='screen') 91 | launches.append(node) 92 | 93 | return launch.LaunchDescription(launches) 94 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/image_transfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_IMAGE_TRANSFER_H 32 | #define IMGUI_ROS_IMAGE_TRANSFER_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | namespace imgui_ros 44 | { 45 | // TODO(lucasw) get rid of this and restore pub/sub to where needed 46 | class ImageTransfer 47 | { 48 | public: 49 | ImageTransfer(); 50 | ~ImageTransfer(); 51 | virtual void postInit(); 52 | 53 | ros::Timer update_timer_; 54 | 55 | bool getSub(const std::string& topic, sensor_msgs::ImagePtr& image); 56 | 57 | bool publish(const std::string& topic, sensor_msgs::ImagePtr& image); 58 | 59 | void setRosPub(const std::string& topic); // , const bool ros_pub); 60 | // TODO(lucasw) need way to remove publisher or subscriber 61 | 62 | // TODO(lucasw) virtual void draw() 63 | 64 | void update(const ros::TimerEvent& event); 65 | 66 | void draw(ros::Time cur); 67 | 68 | private: 69 | ros::NodeHandle nh_; 70 | 71 | bool initted_ = false; 72 | std::map sub_mutexes_; 73 | void imageCallback(const sensor_msgs::Image::ConstPtr msg, const std::string topic); 74 | 75 | bool show_unused_ = false; 76 | 77 | std::map from_sub_; 78 | std::map subs_; 79 | 80 | std::mutex pub_mutex_; 81 | std::deque> to_pub_; 82 | std::map pubs_; 83 | }; 84 | } // namespace imgui_ros 85 | #endif // IMGUI_ROS_IMAGE_TRANSFER_H 86 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/viz2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * November 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_VIZ2D_H 32 | #define IMGUI_ROS_VIZ2D_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | namespace imgui_ros 47 | { 48 | // TODO(lucasw) 49 | // namespace imgui_ros 50 | struct Viz2D : public Sub { 51 | Viz2D(const std::string name, 52 | const std::string topic, 53 | const std::string frame_id, 54 | const std::vector& frames, 55 | const double pixels_per_meter, 56 | std::shared_ptr tf_buffer, 57 | ros::NodeHandle& nh); 58 | 59 | ~Viz2D() {} 60 | 61 | virtual void draw(); 62 | protected: 63 | std::string frame_id_; 64 | std::vector frames_; 65 | std::shared_ptr tf_buffer_; 66 | ros::Subscription::SharedPtr marker_sub_; 67 | // TODO(lucasw) make this a service later 68 | std::map > markers_; 69 | void markerCallback(const visualization_msgs::Marker::SharedPtr msg); 70 | 71 | bool dragging_scale_ = false; 72 | double pixels_per_meter_ = 10.0; 73 | double pixels_per_meter_live_; 74 | ImVec2 offset_; 75 | bool dragging_view_ = false; 76 | ImVec2 drag_point_; 77 | 78 | void drawTf(ImDrawList* draw_list, ImVec2 origin, ImVec2 center, const float sc); 79 | void drawMarkers(ImDrawList* draw_list, ImVec2 origin, ImVec2 center, const float sc); 80 | }; 81 | 82 | } // namespace imgui_ros 83 | #endif // IMGUI_ROS_VIZ2D_H 84 | -------------------------------------------------------------------------------- /imgui_ros/src/nodes/usb_cam_viewer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | void run_usb_cam(std::shared_ptr core) 40 | { 41 | // ros::executors::MultiThreadedExecutor executor; 42 | ros::executors::SingleThreadedExecutor executor; 43 | auto usb_cam = std::make_shared(); 44 | usb_cam->init("usb_cam"); 45 | usb_cam->postInit(core); 46 | executor.add_node(usb_cam); 47 | executor.spin(); 48 | } 49 | 50 | int main(int argc, char * argv[]) 51 | { 52 | setvbuf(stdout, NULL, _IONBF, BUFSIZ); 53 | ros::init(argc, argv); 54 | 55 | const bool ros_pub_enable = false; 56 | auto core = std::make_shared(ros_pub_enable); 57 | 58 | ros::executors::SingleThreadedExecutor single_executor; 59 | // imgui_ros has to be single threaded for now to avoid context switches with opengl 60 | auto imgui_ros = std::make_shared(); 61 | imgui_ros->init("imgui_ros"); 62 | imgui_ros->postInit(core); 63 | single_executor.add_node(imgui_ros); 64 | 65 | #if 0 66 | ros::WallRate rate(50); 67 | // This doesn't work even though the execution time out to be in a different thread than 68 | // this one- need to spawn to different threads to spin each executor in. 69 | ros::Clock::SharedPtr clock = std::make_shared(RCL_ROS_TIME); 70 | while (ros::ok()) { 71 | single_executor.spin_some(); 72 | multi_executor.spin_some(); 73 | rate.sleep(); 74 | } 75 | #else 76 | std::thread cam_thread(std::bind(run_usb_cam, core)); 77 | single_executor.spin(); 78 | cam_thread.join(); 79 | #endif 80 | 81 | ros::shutdown(); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /imgui_ros/scripts/demo_viz3d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2018 Lucas Walter 3 | # BSD3 license 4 | import math 5 | import rospy 6 | 7 | from geometry_msgs.msg import TransformStamped 8 | from imgui_ros_msgs.msg import TexturedShape, TfWidget, Vertex, Widget 9 | from imgui_ros_msgs.srv import AddCamera, AddCubeCamera, AddProjector, AddShaders 10 | from imgui_ros_msgs.srv import AddShape, AddTexture, AddTf, AddTfRequest, AddWindow, AddWindowRequest 11 | from shape_msgs.msg import MeshTriangle, Mesh 12 | from transforms3d import _gohlketransforms as tg 13 | 14 | 15 | class DemoViz3DGui: 16 | def __init__(self): 17 | pass 18 | 19 | def run(self, namespace=''): 20 | rospy.wait_for_service(namespace + '/add_window') 21 | self.window_cli = rospy.ServiceProxy(namespace + '/add_window', AddWindow) 22 | rospy.wait_for_service(namespace + '/add_tf') 23 | self.tf_cli = rospy.ServiceProxy(namespace + '/add_tf', AddTf) 24 | 25 | self.add_tf() 26 | 27 | def add_tf(self): 28 | # TODO(lucasw) what if this window doesn't exist yet? 29 | req = AddWindowRequest() 30 | req.name = "misc controls" 31 | tab_name = 'tf' 32 | 33 | tf_widget = TfWidget() 34 | tf_widget.name = "cube camera tf" 35 | tf_widget.window = req.name 36 | tf_widget.tab_name = tab_name 37 | tf_widget.min = -2.0 38 | tf_widget.max = 2.0 39 | ts = TransformStamped() 40 | ts.header.frame_id = "viz3d_main_window_camera" 41 | ts.child_frame_id = "cube_camera" 42 | ts.transform.translation.x = 0.0 43 | ts.transform.translation.y = 0.0 44 | ts.transform.translation.z = 0.0 45 | roll = 0.0 46 | pitch = 0.0 47 | yaw = 0.0 48 | rot = tg.quaternion_from_euler(roll, pitch, yaw, 'sxyz') 49 | ts.transform.rotation.w = rot[0] 50 | ts.transform.rotation.x = rot[1] 51 | ts.transform.rotation.y = rot[2] 52 | ts.transform.rotation.z = rot[3] 53 | tf_widget.transform_stamped = ts 54 | tf_req = AddTfRequest() 55 | tf_req.tf = tf_widget 56 | 57 | try: 58 | resp = self.tf_cli(tf_req) 59 | rospy.loginfo(resp) 60 | except rospy.service.ServiceException as e: 61 | rospy.logerr(e) 62 | 63 | tf_widget = TfWidget() 64 | tf_widget.name = "cube camera lens pub" 65 | tf_widget.tab_name = tab_name 66 | tf_widget.window = req.name 67 | tf_widget.min = -2.0 68 | tf_widget.max = 2.0 69 | ts = TransformStamped() 70 | ts.header.frame_id = "cube_camera" 71 | ts.child_frame_id = "cube_camera_lens" 72 | ts.transform.translation.x = 0.0 73 | ts.transform.translation.y = 0.0 74 | ts.transform.translation.z = 0.0 75 | roll = 0.0 76 | pitch = 0.0 77 | yaw = 0.0 78 | rot = tg.quaternion_from_euler(roll, pitch, yaw, 'sxyz') 79 | ts.transform.rotation.w = rot[0] 80 | ts.transform.rotation.x = rot[1] 81 | ts.transform.rotation.y = rot[2] 82 | ts.transform.rotation.z = rot[3] 83 | tf_widget.transform_stamped = ts 84 | tf_req = AddTfRequest() 85 | tf_req.tf = tf_widget 86 | 87 | try: 88 | resp = self.tf_cli(tf_req) 89 | rospy.loginfo(resp) 90 | except rospy.service.ServiceException as e: 91 | rospy.logerr(e) 92 | 93 | def main(args=None): 94 | rospy.init_node("imgui_ros_demo_viz3d") 95 | 96 | try: 97 | demo = DemoViz3DGui() 98 | demo.run() 99 | finally: 100 | pass 101 | 102 | if __name__ == '__main__': 103 | main() 104 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/param.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_PARAM_H 32 | #define IMGUI_ROS_PARAM_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #if 0 41 | #include 42 | #include 43 | #include 44 | #endif 45 | #include 46 | #include 47 | 48 | namespace imgui_ros 49 | { 50 | // TODO(lucasw) 51 | // namespace imgui_ros 52 | struct Param : public Widget { 53 | Param(const std::string name, 54 | const std::string node_name, 55 | const std::string parameter_name, 56 | // TODO(lucasw) this should be the Widget msg sub type, or the ParameterType? 57 | // Using ParameterType for now 58 | uint8_t type, 59 | double min, 60 | double max, 61 | ros::NodeHandle& nh); 62 | ~Param(); 63 | 64 | virtual void draw(); 65 | 66 | bool update_ = false; 67 | std::string node_name_; 68 | std::string parameter_name_; 69 | // rcl_interfaces::ParameterValue value_; 70 | // ros::ParameterValue value_; 71 | protected: 72 | // uint8_t type_; 73 | double min_ = 0.0; 74 | double max_ = 1.0; 75 | 76 | std::weak_ptr node_; 77 | 78 | #if 0 79 | void responseReceivedCallback( 80 | const std::shared_future> future); 81 | 82 | // TODO(lucasw) need to push this up into containing viz3d class, 83 | // it will have a list of namespaces that it has parameter events for and will 84 | // receive the event and distribute the values to the proper param 85 | void onParameterEvent(const rcl_interfaces::ParameterEvent::SharedPtr event); 86 | bool updateValue(const rcl_interfaces::ParameterValue& new_value); 87 | 88 | ros::AsyncParametersClient::SharedPtr parameters_client_; 89 | ros::Subscription::SharedPtr param_sub_; 90 | #endif 91 | }; 92 | 93 | } // namespace imgui_ros 94 | #endif // IMGUI_ROS_PARAM_H 95 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/bag_console.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_BAG_CONSOLE_H 32 | #define IMGUI_ROS_BAG_CONSOLE_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | namespace imgui_ros 45 | { 46 | // template 47 | struct BagConsole : public Sub { 48 | BagConsole(const std::string name, const std::string topic, 49 | ros::NodeHandle& nh) : Sub(name, topic, nh) 50 | { 51 | sub_ = nh.subscribe(topic, 10, &BagConsole::callback, this); 52 | } 53 | ~BagConsole() {} 54 | virtual void draw(); 55 | protected: 56 | // TODO(lucasw) this should be derived from the current widget height 57 | const size_t view_num = 32; 58 | size_t position_ = 0; 59 | size_t max_num_ = 255; 60 | size_t count_ = 0; 61 | bool pause_ = false; 62 | 63 | struct Column { 64 | Column(const std::string& name, const bool enable, const float width) : 65 | name_(name), 66 | enable_(enable), 67 | width_(width) 68 | { 69 | } 70 | 71 | void draw(const rosgraph_msgs::Log::ConstPtr& msg, 72 | size_t& selected, size_t& i) const; 73 | const std::string name_; 74 | bool enable_ = true; 75 | float width_ = 0.1; 76 | bool hhmmss_ = false; 77 | }; 78 | // TODO(lucasw) want to support dragging to re-order 79 | std::vector columns_ { 80 | Column("time", true, 0.11), 81 | Column("msg", true, 0.5), 82 | Column("name", true, 0.11), 83 | Column("file", true, 0.11), 84 | Column("function", true, 0.12), 85 | Column("line", true, 0.05) 86 | }; 87 | 88 | // typename T::ConstPtr msg_; 89 | std::deque msgs_; 90 | // typename 91 | ros::Subscriber sub_; 92 | size_t selected_ = 0; 93 | // virtual void callback(const typename T::ConstPtr msg) 94 | void callback(const typename rosgraph_msgs::LogConstPtr msg); 95 | }; 96 | 97 | } // namespace imgui_ros 98 | #endif // IMGUI_ROS_BAG_CONSOLE_H 99 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/dynamic_reconfigure.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGGUI_ROS_DYNAMIC_RECONFIGURE_H 32 | #define IMGGUI_ROS_DYNAMIC_RECONFIGURE_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | namespace imgui_ros 45 | { 46 | struct DynamicReconfigure : public Widget { 47 | DynamicReconfigure(const std::string name, const std::string topic, 48 | ros::NodeHandle& nh); 49 | ~DynamicReconfigure() {} 50 | void descriptionCallback(const dynamic_reconfigure::ConfigDescriptionConstPtr& msg); 51 | void updatesCallback(const dynamic_reconfigure::ConfigConstPtr& msg); 52 | virtual void draw() override; 53 | private: 54 | ros::Subscriber descriptions_sub_; 55 | dynamic_reconfigure::ConfigDescription config_description_; 56 | ros::Subscriber updates_sub_; 57 | dynamic_reconfigure::ConfigConstPtr config_; 58 | 59 | std::map bools_; 60 | std::map ints_; 61 | std::map strs_; 62 | std::map doubles_; 63 | 64 | ros::ServiceClient client_; 65 | 66 | struct DrEnum 67 | { 68 | std::string name_; 69 | std::string value_; 70 | std::string type_; 71 | std::string description_; 72 | }; 73 | std::map > dr_enums_; 74 | std::map dr_enums_combo_text_; 75 | 76 | // preserve the order in the vectors, will be the same order as in the cfg, 77 | // but the order of the groups will be alphabetical 78 | std::map > groups_of_parameters_; 79 | std::map parameters_to_groups_; 80 | 81 | bool do_reconfigure_ = false; 82 | ros::Timer timer_; 83 | void updateParameters(const ros::TimerEvent& e); 84 | }; // DynamicReconfigure 85 | } // namespae imgui_ros 86 | #endif // IMGGUI_ROS_DYNAMIC_RECONFIGURE_H 87 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/tf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * November 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_TF_H 32 | #define IMGUI_ROS_TF_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | // #include 46 | #include 47 | 48 | namespace imgui_ros 49 | { 50 | // TODO(lucasw) 51 | // namespace imgui_ros 52 | struct TfEcho : public Sub { 53 | TfEcho(const std::string name, 54 | const std::string parent, const std::string child, 55 | std::shared_ptr tf_buffer, 56 | ros::NodeHandle& nh); 57 | 58 | ~TfEcho() {} 59 | 60 | virtual void draw(); 61 | protected: 62 | std::string parent_; 63 | std::string child_; 64 | std::shared_ptr tf_buffer_; 65 | }; 66 | 67 | struct TfBroadcaster : public Pub { 68 | TfBroadcaster(const std::string name, 69 | const std::string parent, const std::string child, 70 | const double min, const double max, 71 | std::shared_ptr tf_buffer, 72 | ros::NodeHandle& nh); 73 | 74 | TfBroadcaster( 75 | const imgui_ros_msgs::TfWidget& tf, 76 | std::shared_ptr tf_buffer, 77 | ros::NodeHandle& nh); 78 | 79 | ~TfBroadcaster() {} 80 | 81 | virtual void addTF(tf2_msgs::TFMessage& tfm, const ros::Time& stamp) 82 | { 83 | if ((ts_.header.frame_id != "") && (ts_.child_frame_id != "")) { 84 | ts_.header.stamp = stamp; 85 | tfm.transforms.push_back(ts_); 86 | } 87 | } 88 | #if 0 89 | virtual void update(const ros::Time& stamp); 90 | #endif 91 | virtual void draw(); 92 | protected: 93 | double min_; 94 | double max_; 95 | geometry_msgs::TransformStamped ts_; 96 | geometry_msgs::TransformStamped default_ts_; 97 | // TODO(lucasw) may weak_ptr would work 98 | // std::shared_ptr tf_broadcaster_; 99 | // ros::Publisher tf_pub_; 100 | std::shared_ptr tf_buffer_; 101 | }; 102 | 103 | } // namespace imgui_ros 104 | #endif // IMGUI_ROS_TF_H 105 | -------------------------------------------------------------------------------- /imgui_ros/scripts/to_mesh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sudo apt install python-pyassimp 3 | 4 | import cv2 5 | import cv_bridge 6 | import pyassimp 7 | import rospy 8 | 9 | from imgui_ros_msgs.msg import TexturedShape, Vertex 10 | from imgui_ros_msgs.srv import AddShape, AddShapeRequest, AddTexture, AddTextureRequest 11 | from shape_msgs.msg import MeshTriangle 12 | 13 | 14 | class ToMesh: 15 | def __init__(self): 16 | filename = rospy.get_param("~filename", None) 17 | name = rospy.get_param("~name", "mesh") 18 | frame = rospy.get_param("~frame", "map") 19 | texture_file = rospy.get_param("~texture", None) 20 | texture_name = rospy.get_param("~texture_name", "tex1") 21 | 22 | self.bridge = cv_bridge.CvBridge() 23 | 24 | rospy.wait_for_service('add_texture') 25 | self.texture_cli = rospy.ServiceProxy('add_texture', AddTexture) 26 | self.add_texture(texture_name, texture_file) 27 | 28 | scene = pyassimp.load(name) 29 | if len(scene.meshes) < 1: 30 | rospy.logerr("no meshes in {}".format(name)) 31 | 32 | texture_req = AddTextureRequest() 33 | 34 | req = AddShapeRequest() 35 | # TODO(lucasw) need to be able to have multiple frames for same shape 36 | # then re-render instances at all of those frames. 37 | for ind, mesh in enumerate(scene.meshes): 38 | shape = TexturedShape() 39 | shape.header.frame_id = frame 40 | shape.add = True 41 | shape.enable = True 42 | # TODO(lucasw) does the assimp mesh have a name? 43 | shape.name = name + str(ind) 44 | # TODO(lucasw) what does this mean? Is it for the textures? 45 | shape.is_topic = False 46 | shape.texture = texture_name 47 | print(mesh) 48 | print(dir(mesh)) 49 | print(dir(mesh.material.contents)) 50 | print(dir(mesh.material.properties)) 51 | print(len(mesh.texturecoords[0])) 52 | # print(mesh.texturecoords) 53 | print(len(mesh.vertices)) 54 | print(len(mesh.normals)) 55 | print(len(mesh.colors)) 56 | print(len(mesh.faces)) 57 | for ind, vertex in enumerate(mesh.vertices): 58 | vtx = Vertex() 59 | vtx.vertex.x = vertex[0] 60 | vtx.vertex.y = vertex[1] 61 | vtx.vertex.z = vertex[2] 62 | vtx.normal.x = mesh.normals[ind][0] 63 | vtx.normal.y = mesh.normals[ind][1] 64 | vtx.normal.z = mesh.normals[ind][2] 65 | vtx.color.r = 1.0 66 | vtx.color.g = 1.0 67 | vtx.color.b = 1.0 68 | vtx.color.a = 1.0 69 | vtx.uv.x = mesh.texturecoords[0][ind][0] 70 | vtx.uv.y = mesh.texturecoords[0][ind][1] 71 | shape.vertices.append(vtx) 72 | for ind, face in enumerate(mesh.faces): 73 | tri = MeshTriangle() 74 | # print('{} {}'.format(ind, face)) 75 | for i in range(3): 76 | # print(type(face[i])) 77 | tri.vertex_indices[i] = int(face[i]) 78 | shape.triangles.append(tri) 79 | req.shapes.append(shape) 80 | 81 | rospy.wait_for_service('add_shape') 82 | self.cli = rospy.ServiceProxy('add_shape', AddShape) 83 | rv = self.cli(req) 84 | rospy.loginfo(rv) 85 | 86 | def add_texture(self, name, image_name): 87 | image = cv2.imread(image_name, 1) 88 | if image is None: 89 | rospy.logerr("Couldn't read image '{}'".format(image_name)) 90 | return 91 | image = self.bridge.cv2_to_imgmsg(image, encoding="bgr8") 92 | req = AddTextureRequest() 93 | req.name = name 94 | req.image = image 95 | req.wrap_s = AddTextureRequest.REPEAT 96 | req.wrap_t = AddTextureRequest.REPEAT 97 | 98 | rv = self.texture_cli(req) 99 | rospy.loginfo(rv) 100 | 101 | if __name__ == '__main__': 102 | rospy.init_node('to_mesh') 103 | to_mesh = ToMesh() 104 | -------------------------------------------------------------------------------- /imgui_ros/src/point_cloud.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | // #include "imgui.h" 32 | // #include "imgui_impl_opengl3.h" 33 | // #include "imgui_impl_sdl.h" 34 | // #include 35 | #include 36 | #include 37 | // #include 38 | #include 39 | 40 | namespace imgui_ros 41 | { 42 | PointCloud::PointCloud(const std::string name, const std::string topic, 43 | std::shared_ptr tf_buffer, 44 | ros::NodeHandle& nh 45 | ) : 46 | Sub(name, topic, nh) 47 | { 48 | shape_ = std::make_shared(name + "_shape", 49 | "", "default", "default", tf_buffer); 50 | shape_->draw_mode_ = 2; // GL_POINTS; 51 | // this may not exist as an available texture- 52 | // need an AddPointCloud service that specifies this instead of using Widget 53 | shape_->emission_texture_ = "white"; 54 | 55 | sub_ = nh.subscribe(topic, 3, &PointCloud::pointCloud2Callback, this); 56 | } 57 | 58 | void PointCloud::pointCloud2Callback(const sensor_msgs::PointCloud2::ConstPtr msg) 59 | { 60 | msg_ = msg; 61 | // std::cout << "new point cloud " << msg_->data.size() << "\n"; 62 | // this requires pcl::console::print to be linked in, the code is identical 63 | // to below anyhow. 64 | pcl::fromROSMsg(*msg, cloud_); 65 | 66 | shape_->frame_id_ = msg->header.frame_id; 67 | shape_->vertices_.resize(cloud_.points.size()); 68 | shape_->indices_.resize(cloud_.points.size()); 69 | for (size_t i = 0; i < cloud_.points.size(); ++i) { 70 | auto& cpt = cloud_.points[i]; 71 | DrawVert pt; 72 | pt.pos.x = cpt.x; 73 | pt.pos.y = cpt.y; 74 | pt.pos.z = cpt.z; 75 | 76 | uint32_t rgb = *reinterpret_cast(&cpt.rgb); 77 | uint8_t r = (rgb >> 16) & 0x0000ff; 78 | uint8_t g = (rgb >> 8) & 0x0000ff; 79 | uint8_t b = (rgb) & 0x0000ff; 80 | pt.col.x = static_cast(r) / 255.0; 81 | pt.col.y = static_cast(g) / 255.0; 82 | pt.col.z = static_cast(b) / 255.0; 83 | pt.col.w = 1.0; // alpha 84 | shape_->vertices_[i] = pt; 85 | shape_->indices_[i] = i; 86 | } 87 | shape_->init(); 88 | } 89 | 90 | void PointCloud::draw() 91 | { 92 | #if 1 93 | int num_points = cloud_.points.size(); 94 | ImGui::Text("point cloud points %d", num_points); 95 | #else 96 | if (msg_) { 97 | ImGui::Text("point cloud data size %d", static_cast(msg_->data.size())); 98 | } 99 | #endif 100 | } 101 | 102 | void PointCloud::render() 103 | { 104 | } 105 | } // namespace imgui_ros 106 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu_18_04.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 18.04 ROS Melodic 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-18.04 8 | env: 9 | ROS_CI_DESKTOP: "`lsb_release -cs`" # e.g. [trusty|xenial|...] 10 | CI_SOURCE_PATH: $(pwd) 11 | ROSINSTALL_FILE: $CI_SOURCE_PATH/dependencies.rosinstall 12 | CATKIN_OPTIONS: $CI_SOURCE_PATH/catkin.options 13 | ROS_PARALLEL_JOBS: '-j8 -l6' 14 | # Set the python path manually to include /usr/-/python2.7/dist-packages 15 | # as this is where apt-get installs python packages. 16 | PYTHONPATH: $PYTHONPATH:/usr/lib/python2.7/dist-packages:/usr/local/lib/python2.7/dist-packages 17 | ROS_DISTRO: melodic 18 | 19 | steps: 20 | - uses: actions/checkout@v1 21 | - name: Install ROS 22 | run: | 23 | sudo sh -c "echo \"deb http://packages.ros.org/ros/ubuntu $ROS_CI_DESKTOP main\" > /etc/apt/sources.list.d/ros-latest.list" 24 | sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 25 | sudo apt-get update -qq 26 | sudo apt-get install dpkg 27 | sudo apt-get install -y libeigen3-dev 28 | sudo apt-get install -y libglm-dev 29 | sudo apt-get install -y python-catkin-tools python-catkin-pkg 30 | sudo apt-get install -y python-rosdep python-wstool 31 | sudo apt-get install -y libboost-dev 32 | sudo apt-get install -y libpcl-dev 33 | sudo apt-get install -y libsdl2-dev 34 | sudo apt-get install -y libyaml-cpp-dev 35 | sudo apt-get install -y ros-cmake-modules 36 | # sudo apt-get install -y ros-$ROS_DISTRO-camera-info-manager 37 | sudo apt-get install -y ros-$ROS_DISTRO-cv-bridge 38 | sudo apt-get install -y ros-$ROS_DISTRO-dynamic-reconfigure 39 | sudo apt-get install -y ros-$ROS_DISTRO-ddynamic-reconfigure 40 | sudo apt-get install -y ros-$ROS_DISTRO-image-transport 41 | sudo apt-get install -y ros-$ROS_DISTRO-nodelet-core 42 | sudo apt-get install -y ros-$ROS_DISTRO-pcl-conversions 43 | sudo apt-get install -y ros-$ROS_DISTRO-pcl-ros 44 | sudo apt-get install -y ros-$ROS_DISTRO-roscpp 45 | sudo apt-get install -y ros-$ROS_DISTRO-roslint 46 | sudo apt-get install -y ros-$ROS_DISTRO-rospy 47 | sudo apt-get install -y ros-$ROS_DISTRO-rostest 48 | sudo apt-get install -y ros-$ROS_DISTRO-shape-msgs 49 | sudo apt-get install -y ros-$ROS_DISTRO-sensor-msgs 50 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-geometry-msgs 51 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-msgs 52 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-py 53 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-ros 54 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-sensor-msgs 55 | sudo apt-get install -y ros-$ROS_DISTRO-visualization-msgs 56 | source /opt/ros/$ROS_DISTRO/setup.bash 57 | # Prepare rosdep to install dependencies. 58 | sudo rosdep init 59 | rosdep update --include-eol-distros # Support EOL distros. 60 | 61 | - name: build 62 | run: | 63 | source /opt/ros/$ROS_DISTRO/setup.bash 64 | mkdir -p ~/catkin_ws/src 65 | cd ~/catkin_ws 66 | catkin init 67 | cd ~/catkin_ws/src 68 | ln -s ~/work/imgui_ros/imgui_ros # $CI_SOURCE_PATH 69 | cd imgui_ros/imgui_ros 70 | git clone https://github.com/ocornut/imgui.git 71 | cd imgui 72 | git reset --hard 3f26a07ee1813cecaa87253436149e28fc11dc4e 73 | # echo "::warning $CI_SOURCE_PATH" 74 | # echo "::warning `ls -l`" 75 | cd .. 76 | catkin config -b ~/work/build -d ~/work/devel -i ~/work/install --install 77 | catkin build --no-status 78 | - name: lint 79 | run: | 80 | cd ~/catkin_ws 81 | echo "not using roslint for now, a lot of work is required to make it pass" 82 | # catkin build imgui_ros --no-deps --catkin-make-args roslint 83 | 84 | # Initializes the CodeQL tools for scanning. 85 | - name: Initialize CodeQL 86 | uses: github/codeql-action/init@v1 87 | with: 88 | languages: cpp 89 | - name: Perform CodeQL Analysis 90 | uses: github/codeql-action/analyze@v1 91 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/cube_camera.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_CUBE_CAMERA_H 32 | #define IMGUI_ROS_CUBE_CAMERA_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | // #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #pragma GCC diagnostic push 48 | #pragma GCC diagnostic ignored "-Wpedantic" 49 | // About OpenGL function loaders: modern OpenGL doesn't have a standard header 50 | // file and requires individual function pointers to be loaded manually. Helper 51 | // libraries are often used for this purpose! Here we are supporting a few 52 | // common ones: gl3w, glew, glad. You may use another loader/header of your 53 | // choice (glext, glLoadGen, etc.), or chose to manually implement your own. 54 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 55 | #include // Initialize with gl3wInit() 56 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 57 | #include // Initialize with glewInit() 58 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 59 | #include // Initialize with gladLoadGL() 60 | #else 61 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 62 | #endif 63 | #pragma GCC diagnostic pop 64 | 65 | namespace imgui_ros 66 | { 67 | struct CubeFace 68 | { 69 | CubeFace() 70 | { 71 | transform_.setIdentity(); 72 | } 73 | 74 | ~CubeFace() 75 | { 76 | glDeleteRenderbuffers(1, &depth_buffer_); 77 | glDeleteFramebuffers(1, &frame_buffer_); 78 | } 79 | 80 | GLenum dir_; 81 | std::shared_ptr image_; 82 | GLuint depth_buffer_; 83 | GLuint frame_buffer_; 84 | 85 | tf2::Transform transform_; 86 | }; 87 | 88 | struct CubeCamera : public Camera { 89 | CubeCamera(const std::string& name, 90 | const std::string& frame_id, 91 | const std::string& header_frame_id, 92 | const float aox_y, const float aov_x, 93 | ros::NodeHandle* nh); 94 | ~CubeCamera(); 95 | void init( 96 | const size_t width, const size_t height, 97 | const size_t face_width, 98 | const std::string& texture_name, const std::string& topic, 99 | const bool ros_pub, 100 | ros::NodeHandle* nh, 101 | std::shared_ptr image_transfer); 102 | virtual void draw(); 103 | // void render(); 104 | 105 | const std::string lens_name_ = "cube_camera_lens"; 106 | GLuint cube_texture_id_ = 0; 107 | std::array, 6> faces_; 108 | }; 109 | 110 | } // namespace imgui_ros 111 | #endif // IMGUI_ROS_CUBE_CAMERA_H 112 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/shaders.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_SHADERS_H 32 | #define IMGUI_ROS_SHADERS_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | // #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #pragma GCC diagnostic push 55 | #pragma GCC diagnostic ignored "-Wpedantic" 56 | // About OpenGL function loaders: modern OpenGL doesn't have a standard header 57 | // file and requires individual function pointers to be loaded manually. Helper 58 | // libraries are often used for this purpose! Here we are supporting a few 59 | // common ones: gl3w, glew, glad. You may use another loader/header of your 60 | // choice (glext, glLoadGen, etc.), or chose to manually implement your own. 61 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 62 | #include // Initialize with gl3wInit() 63 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 64 | #include // Initialize with glewInit() 65 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 66 | #include // Initialize with gladLoadGL() 67 | #else 68 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 69 | #endif 70 | #pragma GCC diagnostic pop 71 | 72 | namespace imgui_ros 73 | { 74 | struct ShaderSet { 75 | ShaderSet(const std::string& name, const std::string& vertex_code, 76 | const std::string& geometry_code, const std::string& fragment_code) : 77 | name_(name), 78 | vertex_code_(vertex_code), 79 | geometry_code_(geometry_code), 80 | fragment_code_(fragment_code) 81 | { 82 | } 83 | 84 | ~ShaderSet(); 85 | void remove(); 86 | 87 | bool init(const std::string& glsl_version, std::string& message); 88 | 89 | void draw(); 90 | 91 | const std::string name_; 92 | 93 | std::string vertex_code_; 94 | GLuint vert_handle_ = 0; 95 | 96 | std::string geometry_code_; 97 | GLuint geometry_handle_ = 0; 98 | 99 | std::string fragment_code_; 100 | GLuint frag_handle_ = 0; 101 | 102 | GLuint shader_handle_ = 0; 103 | 104 | // TODO(lucasw) use a std::map for all of these? 105 | std::map attrib_locations_; 106 | std::map uniform_locations_; 107 | }; 108 | 109 | } // namespace imgui_ros 110 | #endif // IMGUI_ROS_SHADERS_H 111 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu_20_04.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 20.04 ROS Noetic 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-20.04 8 | env: 9 | ROS_CI_DESKTOP: "`lsb_release -cs`" # e.g. [trusty|xenial|...] 10 | CI_SOURCE_PATH: $(pwd) 11 | ROSINSTALL_FILE: $CI_SOURCE_PATH/dependencies.rosinstall 12 | CATKIN_OPTIONS: $CI_SOURCE_PATH/catkin.options 13 | ROS_PARALLEL_JOBS: '-j8 -l6' 14 | # Set the python path manually to include /usr/-/python2.7/dist-packages 15 | # as this is where apt-get installs python packages. 16 | PYTHONPATH: $PYTHONPATH:/usr/lib/python2.7/dist-packages:/usr/local/lib/python2.7/dist-packages 17 | ROS_DISTRO: noetic 18 | steps: 19 | - uses: actions/checkout@v1 20 | - name: Install ROS 21 | run: | 22 | sudo sh -c "echo \"deb http://packages.ros.org/ros/ubuntu $ROS_CI_DESKTOP main\" > /etc/apt/sources.list.d/ros-latest.list" 23 | # sudo sh -c "echo \"deb http://packages.ros.org/ros-testing/ubuntu $ROS_CI_DESKTOP main\" > /etc/apt/sources.list.d/ros-testing-latest.list" 24 | sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 25 | sudo apt-get update -qq 26 | sudo apt-get install dpkg 27 | sudo apt-get install -y libeigen3-dev 28 | sudo apt-get install -y libglm-dev 29 | # https://answers.ros.org/question/353113/catkin-build-in-ubuntu-2004-noetic/ 30 | # sudo apt-get install -y python-catkin-tools python-catkin-pkg 31 | # pip3 install --user git+https://github.com/catkin/catkin_tools.git 32 | sudo apt-get install -y python3-catkin-pkg 33 | sudo apt-get install -y python3-catkin-tools 34 | sudo apt-get install -y python3-osrf-pycommon 35 | sudo apt-get install -y python3-rosdep 36 | sudo apt-get install -y python3-wstool 37 | sudo apt-get install -y libboost-dev 38 | sudo apt-get install -y libpcl-dev 39 | sudo apt-get install -y libsdl2-dev 40 | sudo apt-get install -y libyaml-cpp-dev 41 | sudo apt-get install -y ros-cmake-modules 42 | # sudo apt-get install -y ros-$ROS_DISTRO-camera-info-manager 43 | sudo apt-get install -y ros-$ROS_DISTRO-cv-bridge 44 | sudo apt-get install -y ros-$ROS_DISTRO-dynamic-reconfigure 45 | sudo apt-get install -y ros-$ROS_DISTRO-ddynamic-reconfigure 46 | sudo apt-get install -y ros-$ROS_DISTRO-image-transport 47 | sudo apt-get install -y ros-$ROS_DISTRO-nodelet-core 48 | sudo apt-get install -y ros-$ROS_DISTRO-pcl-conversions 49 | sudo apt-get install -y ros-$ROS_DISTRO-pcl-ros 50 | sudo apt-get install -y ros-$ROS_DISTRO-roscpp 51 | sudo apt-get install -y ros-$ROS_DISTRO-roslint 52 | sudo apt-get install -y ros-$ROS_DISTRO-rospy 53 | sudo apt-get install -y ros-$ROS_DISTRO-rostest 54 | sudo apt-get install -y ros-$ROS_DISTRO-shape-msgs 55 | sudo apt-get install -y ros-$ROS_DISTRO-sensor-msgs 56 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-geometry-msgs 57 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-msgs 58 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-py 59 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-ros 60 | sudo apt-get install -y ros-$ROS_DISTRO-tf2-sensor-msgs 61 | sudo apt-get install -y ros-$ROS_DISTRO-visualization-msgs 62 | source /opt/ros/$ROS_DISTRO/setup.bash 63 | # Prepare rosdep to install dependencies. 64 | sudo rosdep init 65 | rosdep update --include-eol-distros # Support EOL distros. 66 | 67 | - name: build 68 | run: | 69 | source /opt/ros/$ROS_DISTRO/setup.bash 70 | mkdir -p ~/catkin_ws/src 71 | cd ~/catkin_ws 72 | catkin build 73 | source devel/setup.bash 74 | cd ~/catkin_ws/src 75 | ln -s ~/work/imgui_ros/imgui_ros # $CI_SOURCE_PATH 76 | cd imgui_ros/imgui_ros 77 | git clone https://github.com/ocornut/imgui.git 78 | cd imgui 79 | git reset --hard 3f26a07ee1813cecaa87253436149e28fc11dc4e 80 | # echo "::warning $CI_SOURCE_PATH" 81 | # echo "::warning `ls -l`" 82 | cd .. 83 | catkin build 84 | - name: lint 85 | run: | 86 | cd ~/catkin_ws 87 | echo "not using roslint for now, a lot of work is required to make it pass" 88 | # catkin build imgui_ros --no-deps --catkin-make-args roslint 89 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/projector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_PROJECTOR_H 32 | #define IMGUI_ROS_PROJECTOR_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | // #include 39 | // #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #pragma GCC diagnostic push 47 | #pragma GCC diagnostic ignored "-Wpedantic" 48 | // About OpenGL function loaders: modern OpenGL doesn't have a standard header 49 | // file and requires individual function pointers to be loaded manually. Helper 50 | // libraries are often used for this purpose! Here we are supporting a few 51 | // common ones: gl3w, glew, glad. You may use another loader/header of your 52 | // choice (glext, glLoadGen, etc.), or chose to manually implement your own. 53 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 54 | #include // Initialize with gl3wInit() 55 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 56 | #include // Initialize with glewInit() 57 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 58 | #include // Initialize with gladLoadGL() 59 | #else 60 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 61 | #endif 62 | #pragma GCC diagnostic pop 63 | 64 | namespace imgui_ros 65 | { 66 | struct Projector { 67 | // TODO(lucas) just pass in the Projector.msg 68 | Projector(const std::string name, 69 | const std::string texture_name, 70 | const std::string frame_id, 71 | const double aov_y, 72 | const double aov_x, 73 | const double max_range, 74 | const double constant_attenuation, 75 | const double linear_attenuation, 76 | const double quadratic_attenuation); 77 | // ros::NodeHandle* nh); 78 | ~Projector(); 79 | 80 | std::string print(); 81 | void draw(const std::vector& texture_names, 82 | const std::string& texture_items); 83 | // void render(); 84 | 85 | std::string name_; 86 | std::string texture_name_; 87 | std::string frame_id_; 88 | tf2::Stamped stamped_transform_; 89 | 90 | // TODO(lucasw) later need to use this and resolution to make a CameraInfo 91 | double aov_y_; 92 | double aov_x_ = 0.0; 93 | 94 | double near_ = 1.0; 95 | // TODO(lucasw) can far and max range be the same? 96 | double far_ = 20.0; 97 | // set to > 0.0 to be used 98 | double max_range_ = 0.0; 99 | double constant_attenuation_ = 0.0; 100 | double linear_attenuation_ = 0.0; 101 | double quadratic_attenuation_ = 0.0; 102 | 103 | // TODO(lucasw) put in own class later 104 | bool enable_ = true; 105 | 106 | int shadow_width_ = 512; 107 | int shadow_height_ = 512; 108 | GLuint shadow_framebuffer_ = 0; 109 | GLuint shadow_depth_texture_ = 0; 110 | 111 | // is a NodeHandle needed? 112 | // std::weak_ptr node_; 113 | }; 114 | 115 | } // namespace imgui_ros 116 | #endif // IMGUI_ROS_PROJECTOR_H 117 | -------------------------------------------------------------------------------- /imgui_ros/scripts/demo2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2018 Lucas Walter 3 | # BSD3 license 4 | import math 5 | import rospy 6 | 7 | from imgui_ros_msgs.msg import Widget 8 | from imgui_ros_msgs.srv import * 9 | # from time import sleep 10 | 11 | 12 | class DemoGui: 13 | def __init__(self): 14 | pass 15 | 16 | def run(self, namespace=''): 17 | rospy.wait_for_service(namespace + '/add_window') 18 | self.cli = rospy.ServiceProxy(namespace + '/add_window', AddWindow) 19 | 20 | self.add_misc() 21 | self.add_dr() 22 | 23 | def add_dr(self): 24 | req = AddWindowRequest() 25 | req.name = 'misc controls' 26 | req.init = True 27 | req.fractional = False 28 | if req.fractional: 29 | # TODO(lucasw) fractional doesn't allow dragging of window around 30 | req.position.x = 0.0 31 | req.position.y = 0.0 32 | req.size.x = 0.5 33 | req.size.y = 0.5 34 | else: 35 | req.position.x = 200.0 36 | req.position.y = 0.0 37 | req.size.x = 300.0 38 | req.size.y = 400.0 39 | 40 | tab_name = 'dr' 41 | 42 | if True: 43 | widget = Widget() 44 | widget.name = "dr_manual" 45 | widget.tab_name = tab_name 46 | widget.topic = '/example_server_manual_py' 47 | widget.type = Widget.DYNREC 48 | # widget.sub_type = Widget.IMAGE 49 | req.widgets.append(widget) 50 | 51 | if True: 52 | widget = Widget() 53 | widget.name = "dr" 54 | widget.tab_name = tab_name 55 | widget.topic = '/example_server_node' 56 | widget.type = Widget.DYNREC 57 | req.widgets.append(widget) 58 | 59 | if True: 60 | widget = Widget() 61 | widget.name = "dr2" 62 | widget.tab_name = tab_name 63 | widget.topic = '/example_server_node2' 64 | widget.type = Widget.DYNREC 65 | req.widgets.append(widget) 66 | 67 | try: 68 | resp = self.cli(req) 69 | rospy.loginfo(resp) 70 | except rospy.service.ServiceException as e: 71 | rospy.logerr(e) 72 | 73 | 74 | def add_misc(self): 75 | req = AddWindowRequest() 76 | req.name = 'misc controls' 77 | req.init = True 78 | req.fractional = False 79 | if req.fractional: 80 | # TODO(lucasw) fractional doesn't allow dragging of window around 81 | req.position.x = 0.0 82 | req.position.y = 0.0 83 | req.size.x = 0.5 84 | req.size.y = 0.5 85 | else: 86 | req.position.x = 100.0 87 | req.position.y = 0.0 88 | req.size.x = 300.0 89 | req.size.y = 400.0 90 | tab_name = 'misc' 91 | 92 | if True: 93 | widget = Widget() 94 | widget.name = "image pub" 95 | widget.tab_name = tab_name 96 | widget.topic = "test_image1/image_raw" 97 | widget.type = Widget.PUB 98 | widget.sub_type = Widget.IMAGE 99 | req.widgets.append(widget) 100 | 101 | if True: 102 | widget = Widget() 103 | widget.name = "image sub" 104 | widget.tab_name = tab_name 105 | widget.topic = "test_image2/image_raw" 106 | widget.type = Widget.SUB 107 | widget.sub_type = Widget.IMAGE 108 | req.widgets.append(widget) 109 | 110 | # string pub sub test 111 | string_topic = "string" 112 | widget = Widget() 113 | widget.name = "string pub" 114 | widget.tab_name = tab_name 115 | widget.topic = string_topic 116 | widget.type = Widget.PUB 117 | widget.sub_type = Widget.STRING 118 | # has to be float even though type above is int 119 | req.widgets.append(widget) 120 | 121 | widget = Widget() 122 | widget.name = "string menu pub" 123 | widget.tab_name = tab_name 124 | widget.topic = string_topic 125 | widget.type = Widget.PUB 126 | widget.sub_type = Widget.STRING 127 | widget.items = ['item1 foo', 'item2 bar', 'item final'] 128 | # has to be float even though type above is int 129 | widget.value = 0.0 130 | req.widgets.append(widget) 131 | 132 | widget = Widget() 133 | widget.name = "string sub" 134 | widget.tab_name = tab_name 135 | widget.topic = string_topic 136 | widget.type = Widget.SUB 137 | widget.sub_type = Widget.STRING 138 | req.widgets.append(widget) 139 | 140 | try: 141 | resp = self.cli(req) 142 | rospy.loginfo(resp) 143 | except rospy.service.ServiceException as e: 144 | rospy.logerr(e) 145 | 146 | def main(args=None): 147 | rospy.init_node("imgui_ros_demo2") 148 | 149 | try: 150 | demo = DemoGui() 151 | demo.run() 152 | finally: 153 | pass 154 | 155 | if __name__ == '__main__': 156 | main() 157 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/sub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_SUB_H 32 | #define IMGUI_ROS_SUB_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | namespace imgui_ros 44 | { 45 | // TODO(lucasw) 46 | // namespace imgui_ros 47 | struct Sub : public Widget { 48 | Sub(const std::string name, const std::string topic, // const unsigned type, 49 | ros::NodeHandle& nh); 50 | // ~Sub(); 51 | virtual void draw() = 0; 52 | protected: 53 | }; 54 | 55 | template 56 | struct GenericSub : public Sub { 57 | GenericSub(const std::string name, const std::string topic, 58 | ros::NodeHandle& nh) : Sub(name, topic, nh) 59 | { 60 | sub_ = nh.subscribe(topic, &GenericSub::callback, this); 61 | } 62 | ~GenericSub() {} 63 | virtual void draw() 64 | { 65 | // TODO(lucasw) typeToString() 66 | // const std::string text = topic_; 67 | // ImGui::Text("%.*s", static_cast(text.size()), text.data()); 68 | std::lock_guard lock(mutex_); 69 | std::stringstream ss; 70 | // TODO(lucasw) Text box with label on side? 71 | // or just use other number widget but disable interaction? 72 | // ImGui::Value()? 73 | ss << name_ << ": "; 74 | if (msg_) { 75 | // only types with data members that can be used with streams will build 76 | ss << msg_->data; 77 | } 78 | std::string text = ss.str(); 79 | ImGui::Text("%s", ss.str().c_str()); 80 | } 81 | protected: 82 | typename T::ConstPtr msg_; 83 | // typename 84 | ros::Subscriber sub_; 85 | virtual void callback(const typename T::ConstPtr msg) 86 | { 87 | std::lock_guard lock(mutex_); 88 | msg_ = msg; 89 | } 90 | }; 91 | 92 | template 93 | struct PlotSub : public GenericSub { 94 | // TODO(lucasw) how to get the type of T->data? 95 | // typedef decltype(T::*data) data_type; 96 | PlotSub(const std::string name, const std::string topic, 97 | float value, 98 | ros::NodeHandle& nh) : 99 | GenericSub(name, topic, nh) 100 | { 101 | data_.push_back(value); 102 | data_.push_back(value); 103 | } 104 | 105 | ~PlotSub() {} 106 | virtual void draw() 107 | { 108 | // GenericSub::draw(); 109 | // Can't just refer to inherited mutex_ 110 | std::lock_guard lock(GenericSub::mutex_); 111 | if (data_.size() > 0) { 112 | ImGui::PlotLines(GenericSub::name_.c_str(), &data_[0], data_.size()); 113 | } 114 | } 115 | protected: 116 | size_t max_points_ = 100; 117 | std::vector data_; 118 | // float min_; 119 | // float max_; 120 | virtual void callback(const typename T::ConstPtr msg) 121 | { 122 | GenericSub::callback(msg); 123 | std::lock_guard lock(GenericSub::mutex_); 124 | data_.push_back(msg->data); 125 | if (data_.size() > max_points_) { 126 | data_.erase(data_.begin(), data_.begin() + 1); 127 | } 128 | } 129 | }; // PlotSub 130 | 131 | struct BoolSub : public Sub { 132 | BoolSub(const std::string name, const std::string topic, // const unsigned type, 133 | const bool value, 134 | ros::NodeHandle& nh); 135 | ~BoolSub() {} 136 | virtual void draw(); 137 | protected: 138 | std_msgs::Bool::ConstPtr msg_; 139 | ros::Subscriber sub_; 140 | void callback(const std_msgs::Bool::ConstPtr msg); 141 | }; 142 | 143 | } // namespace imgui_ros 144 | #endif // IMGUI_ROS_SUB_H 145 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/surface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_SURFACE_H 32 | #define IMGUI_ROS_SURFACE_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | // #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #pragma GCC diagnostic push 47 | #pragma GCC diagnostic ignored "-Wpedantic" 48 | // About OpenGL function loaders: modern OpenGL doesn't have a standard header 49 | // file and requires individual function pointers to be loaded manually. Helper 50 | // libraries are often used for this purpose! Here we are supporting a few 51 | // common ones: gl3w, glew, glad. You may use another loader/header of your 52 | // choice (glext, glLoadGen, etc.), or chose to manually implement your own. 53 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 54 | #include // Initialize with gl3wInit() 55 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 56 | #include // Initialize with glewInit() 57 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 58 | #include // Initialize with gladLoadGL() 59 | #else 60 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 61 | #endif 62 | #pragma GCC diagnostic pop 63 | 64 | struct DrawVert { 65 | glm::vec3 pos; 66 | glm::vec3 nrm; 67 | glm::vec2 uv; 68 | glm::vec4 col; 69 | }; 70 | 71 | namespace imgui_ros 72 | { 73 | struct Shape { 74 | Shape(const std::string& name, const std::string& frame_id, 75 | const std::string& texture_name, 76 | const std::string& shininess_texture_name_, 77 | std::shared_ptr tf_buffer); 78 | ~Shape(); 79 | 80 | // transfer to gpu 81 | void init(); 82 | 83 | // TODO(lucasw) passing in a lot of texture information 84 | // so that the texture can be changed through combo box, 85 | // it would be nice to make this streamlined. 86 | void draw(const std::vector& texture_names, 87 | const std::string& texture_items); 88 | 89 | std::string print() { 90 | std::stringstream ss; 91 | ss << "shape " << name_ << " " << texture_ << " " 92 | << vertices_.Size << " " << indices_.Size << "\n"; 93 | #if 0 94 | for (int i = 0; (i < 10) && (i < vertices_.Size); ++i) 95 | std::cout << i << " " 96 | << " " << vertices_[i].pos.x 97 | << " " << vertices_[i].pos.y 98 | << " " << vertices_[i].pos.z << ", "; 99 | std::cout << "\n"; 100 | for (int i = 0; (i < 12) && (i < indices_.Size); ++i) 101 | std::cout << " " << indices_[i]; 102 | std::cout << "\n"; 103 | #endif 104 | return ss.str(); 105 | } 106 | 107 | std::string name_ = "unset"; 108 | std::string frame_id_ = "map"; 109 | ImVector vertices_; 110 | ImVector indices_; 111 | std::string texture_ = "default"; 112 | std::string shininess_texture_ = "default"; 113 | std::string emission_texture_ = "default"; 114 | 115 | // ROS 116 | std::shared_ptr tf_buffer_; 117 | 118 | // GL_LINE_LOOP doesn't handle points meant for GL_TRIANGLES well. 119 | static constexpr std::array draw_modes_ = {GL_TRIANGLES, GL_LINE_LOOP, GL_POINTS}; 120 | int draw_mode_ = 0; 121 | 122 | // OpenGL 123 | GLuint vao_handle_ = 0; 124 | GLuint vbo_handle_ = 0; 125 | GLuint elements_handle_ = 0; 126 | 127 | bool enable_ = true; 128 | }; 129 | 130 | } // namespace imgui_ros 131 | #endif // IMGUI_ROS_SURFACE_H 132 | -------------------------------------------------------------------------------- /imgui_ros/src/pub.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | namespace imgui_ros 35 | { 36 | Pub::Pub(const std::string name, const std::string topic, // const unsigned type, 37 | ros::NodeHandle& nh) : 38 | Widget(name, topic) { 39 | (void)nh; 40 | } 41 | 42 | // Pub::~Pub() { 43 | // } 44 | 45 | BoolPub::BoolPub(const std::string name, const std::string topic, // const unsigned type, 46 | const bool value, 47 | ros::NodeHandle& nh) : 48 | Pub(name, topic, nh), value_(value) { 49 | msg_.data = false; 50 | pub_ = nh.advertise(topic, 2); 51 | } 52 | 53 | void BoolPub::draw() { 54 | // TODO(lucasw) typeToString() 55 | // const std::string text = topic_; 56 | // ImGui::Text("%.*s", static_cast(text.size()), text.data()); 57 | { 58 | std::lock_guard lock(mutex_); 59 | 60 | { 61 | bool new_value = value_; 62 | const bool changed = ImGui::Checkbox(name_.c_str(), &new_value); 63 | if (changed) { 64 | // TODO(lucasw) optionall keep this checked, or uncheck immediately 65 | // value_ = new_value; 66 | msg_.data = new_value; 67 | pub_.publish(msg_); 68 | } 69 | } 70 | } 71 | } 72 | 73 | StringPub::StringPub(const std::string name, const std::string topic, 74 | const std::vector& items, 75 | ros::NodeHandle& nh) : 76 | Pub(name, topic, nh), items_(items) { 77 | if (items.size() > 0) { 78 | msg_.data = items[0]; 79 | } 80 | for (auto item : items) { 81 | items_null_ += item + '\0'; 82 | } 83 | // TODO(lucasw) bring back type for all the int types 84 | pub_ = nh.advertise(topic, 3); 85 | } 86 | 87 | void StringPub::draw() { 88 | // TODO(lucasw) typeToString() 89 | std::stringstream ss; 90 | ss << name_ << " - " << topic_; 91 | std::lock_guard lock(mutex_); 92 | 93 | // if there are multiple items then the user can select from them, 94 | // but can't type a new one in (it would be nice if they could) 95 | if (items_.size() > 1) { 96 | int new_value = value_; 97 | const bool changed = ImGui::Combo(name_.c_str(), &new_value, items_null_.c_str()); 98 | if (changed) { 99 | value_ = new_value; 100 | msg_.data = items_[value_]; 101 | pub_.publish(msg_); 102 | } 103 | } else { 104 | const size_t sz = 64; 105 | char buf[sz]; 106 | const size_t sz2 = (msg_.data.size() > (sz - 1)) ? (sz - 1) : msg_.data.size(); 107 | strncpy(buf, msg_.data.c_str(), sz2); 108 | buf[sz2 + 1] = '\0'; 109 | const bool changed = ImGui::InputText(name_.c_str(), buf, sz, 110 | ImGuiInputTextFlags_EnterReturnsTrue); 111 | if (changed) { 112 | msg_.data = buf; 113 | pub_.publish(msg_); 114 | } 115 | } 116 | } 117 | 118 | MenuPub::MenuPub(const std::string name, const std::string topic, // const unsigned type, 119 | const int value, const std::vector& items, 120 | ros::NodeHandle& nh) : 121 | Pub(name, topic, nh), value_(value), items_(items) { 122 | for (auto item : items) { 123 | items_null_ += item + '\0'; 124 | } 125 | // TODO(lucasw) bring back type for all the int types 126 | pub_ = nh.advertise(topic, 3); 127 | } 128 | 129 | void MenuPub::draw() { 130 | // TODO(lucasw) typeToString() 131 | std::stringstream ss; 132 | ss << name_ << " - " << topic_; 133 | std::lock_guard lock(mutex_); 134 | 135 | int new_value = value_; 136 | const bool changed = ImGui::Combo(name_.c_str(), &new_value, items_null_.c_str()); 137 | if (changed) { 138 | value_ = new_value; 139 | msg_.data = value_; 140 | pub_.publish(msg_); 141 | } 142 | } 143 | } // namespace imgui_ros 144 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/imgui_ros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_IMGUI_ROS_H 32 | #define IMGUI_ROS_IMGUI_ROS_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #if 0 42 | #include 43 | #include 44 | #include 45 | #endif 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | namespace imgui_ros { 57 | 58 | class ImguiRos { 59 | public: 60 | ImguiRos(); 61 | ~ImguiRos(); 62 | void postInit(); 63 | 64 | private: 65 | ros::NodeHandle nh_; 66 | #if 0 67 | void runNodeSingleThreaded(ros::NodeHandle& nh); 68 | #endif 69 | ros::ServiceServer add_tf_; 70 | bool addTf(imgui_ros_msgs::AddTf::Request& req, 71 | imgui_ros_msgs::AddTf::Response& res); 72 | bool addWindow(imgui_ros_msgs::AddWindow::Request& req, 73 | imgui_ros_msgs::AddWindow::Response& res); 74 | bool addWidget(const imgui_ros_msgs::Widget& widget, 75 | std::string& message, std::shared_ptr& imgui_widget); 76 | // TODO(lucasw) still need to update even if ros time is paused 77 | ros::Timer update_timer_; 78 | void newFrame(); 79 | void update(const ros::TimerEvent& ev); 80 | 81 | // Need to init the opengl context in same thread as the update 82 | // is run in, not necessarily the same thread onInit runs in 83 | void glInit(); 84 | std::mutex mutex_; 85 | bool init_ = false; 86 | // TODO(lucasw) std::shared_ptr 87 | SDL_Window *sdl_window_; 88 | SDL_GLContext gl_context; 89 | // ImVec4 clear_color_ = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 90 | 91 | std::map > windows_; 92 | ros::ServiceServer add_window_; 93 | 94 | #if 0 95 | ros::Clock::SharedPtr clock_; 96 | // std::shared_ptr tf_node_; 97 | #endif 98 | std::shared_ptr tf_listener_; 99 | std::shared_ptr tf_buffer_; 100 | // TODO(lucasw) maybe a non shared pointer works better 101 | // tf2_ros::Buffer buffer_; 102 | 103 | ros::Publisher tf_pub_; 104 | std::string name_ = "imgui_ros"; 105 | int width_ = 1280; 106 | int height_ = 720; 107 | int old_width_ = 0; 108 | int old_height_ = 0; 109 | int old_x_ = 0; 110 | int old_y_ = 0; 111 | 112 | bool fullscreen_ = false; 113 | 114 | ros::Time start_stamp_ = ros::Time::now(); 115 | bool stats_window_init_ = true; 116 | void drawStats(ros::Time stamp); 117 | 118 | std::shared_ptr imgui_impl_opengl3_; 119 | std::shared_ptr viz3d; 120 | 121 | #if 0 122 | std::map parameters_clients_; 123 | // node_name, widget_name 124 | std::map > > param_widgets_; 125 | 126 | // thread dedicate to large ros messages 127 | std::thread ros_io_thread_; 128 | 129 | // this will get parameter events for all nodes in same namespace (or just root namespace? 130 | // namespacing seems broken in ros2 currently) 131 | // void onParameterEvent(const rcl_interfaces::ParameterEvent::SharedPtr event); 132 | #endif 133 | std::shared_ptr image_transfer_; 134 | // check to make sure opengl context accesses never happen in different thread 135 | std::thread::id thread_id_; 136 | }; 137 | 138 | } // namespace imgui_ros 139 | 140 | #endif // IMGUI_ROS_IMGUI_ROS_H 141 | -------------------------------------------------------------------------------- /imgui_ros/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(imgui_ros) 3 | 4 | # Default to C99 5 | if(NOT CMAKE_C_STANDARD) 6 | set(CMAKE_C_STANDARD 99) 7 | endif() 8 | 9 | # Default to C++17 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 17) 12 | endif() 13 | 14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 15 | add_compile_options(-Wall -Wextra -Wpedantic) 16 | endif() 17 | 18 | find_package(OpenCV REQUIRED) 19 | find_package(SDL2 REQUIRED) 20 | find_package(Boost COMPONENTS system REQUIRED) 21 | find_package(PCL COMPONENTS common REQUIRED) 22 | find_package(glm REQUIRED) 23 | find_package(yaml-cpp REQUIRED) 24 | 25 | find_package(catkin REQUIRED COMPONENTS 26 | cv_bridge 27 | dynamic_reconfigure 28 | geometry_msgs 29 | imgui_ros_msgs 30 | pcl_conversions 31 | roscpp 32 | # roslint 33 | sensor_msgs 34 | shape_msgs 35 | std_msgs 36 | tf2 37 | tf2_geometry_msgs 38 | tf2_msgs 39 | tf2_ros 40 | visualization_msgs 41 | ) 42 | 43 | set( 44 | ROSLINT_CPP_OPTS 45 | "--extensions=cpp,h,hpp" "--filter=-whitespace/braces,-runtime/references" 46 | ) 47 | # roslint_cpp( 48 | # # src/bag_console.cpp 49 | # src/camera.cpp 50 | # src/cube_camera.cpp 51 | # src/dynamic_reconfigure.cpp 52 | # src/graph.cpp 53 | # src/image.cpp 54 | # src/image_transfer.cpp 55 | # # src/imgui_impl_opengl3.cpp 56 | # src/imgui_ros.cpp 57 | # src/node.cpp 58 | # src/param.cpp 59 | # src/param_to_topic.cpp 60 | # src/point_cloud.cpp 61 | # src/projector.cpp 62 | # src/pub.cpp 63 | # src/shaders.cpp 64 | # src/sub.cpp 65 | # src/surface.cpp 66 | # src/tf.cpp 67 | # src/utility.cpp 68 | # src/viz2d.cpp 69 | # src/viz3d.cpp 70 | # src/window.cpp 71 | # ) 72 | # roslint_python() 73 | 74 | catkin_package( 75 | INCLUDE_DIRS include 76 | LIBRARIES ${PROJECT_NAME} 77 | CATKIN_DEPENDS nodelet roscpp sensor_msgs std_msgs # imgui_ros_msgs 78 | ) 79 | 80 | # TODO(lucasw) currently have to symlink imgui in, 81 | # later could make it a subrepo, or git clone it right here 82 | # from cmake. 83 | include_directories( 84 | include 85 | imgui 86 | imgui/examples 87 | imgui/examples/libs/gl3w 88 | ${catkin_INCLUDE_DIRS} 89 | ${OpenCV_INCLUDE_DIRECTORIES} 90 | ${SDL2_INCLUDE_DIRS} 91 | ) 92 | 93 | add_library(imgui SHARED 94 | src/imgui_impl_opengl3.cpp 95 | imgui/imgui.cpp 96 | imgui/imgui_demo.cpp 97 | imgui/imgui_draw.cpp 98 | imgui/imgui_widgets.cpp 99 | imgui/examples/imgui_impl_sdl.cpp 100 | # imgui/examples/imgui_impl_opengl3.cpp 101 | imgui/examples/libs/gl3w/GL/gl3w.c 102 | ) 103 | set_source_files_properties(imgui/examples/libs/gl3w/GL/gl3w.c PROPERTIES COMPILE_FLAGS -Wno-pedantic) 104 | 105 | add_library(imguiros SHARED 106 | src/bag_console.cpp 107 | src/camera.cpp 108 | src/cube_camera.cpp 109 | src/point_cloud.cpp 110 | src/projector.cpp 111 | src/pub.cpp 112 | src/shaders.cpp 113 | src/sub.cpp 114 | src/surface.cpp 115 | src/tf.cpp 116 | src/utility.cpp 117 | src/viz3d.cpp 118 | 119 | src/dynamic_reconfigure.cpp 120 | src/graph.cpp 121 | src/image.cpp 122 | src/image_transfer.cpp 123 | src/imgui_ros.cpp 124 | src/node.cpp 125 | src/window.cpp 126 | ) 127 | 128 | if(false) 129 | add_library(imguiros SHARED 130 | src/param.cpp 131 | # TODO(lucasw) maybe there should be a separate test library? 132 | src/test/generate_pointcloud2.cpp 133 | src/viz2d.cpp 134 | # src/imgui_impl_opengl3.cpp 135 | ) 136 | endif(false) 137 | 138 | target_link_libraries(imguiros imgui 139 | ${Boost_SYSTEM_LIBRARY} # pcl_conversions requires this 140 | ${OpenCV_LIBRARIES} 141 | ${PCL_LIBRARIES} 142 | ${SDL2_LIBRARIES} 143 | ${catkin_LIBRARIES} 144 | GL 145 | dl 146 | yaml-cpp 147 | ) 148 | 149 | install(TARGETS imguiros 150 | ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 151 | LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 152 | RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 153 | ) 154 | 155 | add_executable(imgui_ros_node src/imgui_ros.cpp) 156 | target_link_libraries(imgui_ros_node imguiros imgui) 157 | # install(TARGETS imgui_ros_node DESTINATION lib/${PROJECT_NAME}) 158 | 159 | # only optionally build usb_cam node, need right version of usb_cam 160 | # https://github.com/lucasw/usb_cam/tree/internal_pub_sub 161 | # find_package(usb_cam) 162 | # if (usb_cam_FOUND_AMENT_PACKAGE) 163 | # add_executable(usb_cam_viewer src/nodes/usb_cam_viewer.cpp) 164 | # target_link_libraries(usb_cam_viewer imguiros) 165 | # ament_target_dependencies(usb_cam_viewer rclcpp imguiros usb_cam) 166 | # install(TARGETS usb_cam_viewer DESTINATION lib/${PROJECT_NAME}) 167 | # endif() 168 | 169 | install(DIRECTORY config DESTINATION share/${PROJECT_NAME}) 170 | 171 | install(DIRECTORY data DESTINATION share/${PROJECT_NAME}) 172 | 173 | install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}) 174 | 175 | install(PROGRAMS 176 | # TODO(lucasw) is this redundant with install package above, or necessary to run this from ros2 run? 177 | # imgui_ros/add_shaders.py 178 | # imgui_ros/cameras.py 179 | # imgui_ros/demo_imgui_ros.py 180 | # imgui_ros/demo_gui.py 181 | # imgui_ros/pub_shape.py 182 | scripts/demo2.py 183 | # scripts/graph.py 184 | # scripts/usb_cam_viewer.py 185 | DESTINATION lib/${PROJECT_NAME}) 186 | 187 | install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION include/${PROJECT_NAME}) 188 | install(DIRECTORY imgui/examples/libs/gl3w/GL/ DESTINATION include/GL) 189 | install(FILES 190 | imgui/imconfig.h 191 | imgui/imgui.h 192 | # imgui/imgui_internal.h 193 | imgui/imstb_rectpack.h 194 | imgui/imstb_textedit.h 195 | imgui/imstb_truetype.h 196 | DESTINATION include 197 | ) 198 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/window.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_WINDOW_H 32 | #define IMGUI_ROS_WINDOW_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | namespace imgui_ros 43 | { 44 | struct Widget 45 | { 46 | Widget(const std::string name, const std::string topic, const std::string topic_prefix = "") : 47 | name_(name), topic_(topic), topic_prefix_(topic_prefix) 48 | { 49 | } 50 | virtual ~Widget() {} 51 | virtual void update(const ros::Time& stamp, const std::string dropped_file="") 52 | {(void)stamp; (void)dropped_file;} 53 | virtual void draw() = 0; 54 | std::string name_ = ""; 55 | 56 | virtual void addTF(tf2_msgs::TFMessage& tfm, const ros::Time& now) 57 | { 58 | (void)tfm; 59 | (void)now; 60 | } 61 | bool enable_info_ = true; 62 | protected: 63 | bool is_focused_ = false; 64 | bool dirty_ = true; 65 | std::string topic_ = ""; 66 | std::string topic_prefix_ = ""; 67 | std::mutex mutex_; 68 | ros::Duration update_duration_ = ros::Duration(0); 69 | }; 70 | 71 | struct Window { 72 | Window(const std::string name) : 73 | name_(name) {} 74 | virtual ~Window(); 75 | // TODO(lucasw) can draw and upate be pure virtual, if not here then 76 | // one class up? 77 | virtual void draw(const int outer_window_width, 78 | const int outer_window_height); 79 | void add(std::shared_ptr widget, const std::string& tab_name); 80 | void remove(const std::string& name, const std::string& tab_name); 81 | virtual void addTF(tf2_msgs::TFMessage& tfm, const ros::Time& now) { 82 | // for (auto& name : tab_order_) { 83 | for (auto tab_pair : tab_groups_) { 84 | tab_pair.second->addTF(tfm, now); 85 | } 86 | } 87 | 88 | virtual void update(const ros::Time& stamp, const std::string dropped_file=""); 89 | 90 | // over ride the current settings with these 91 | void setSettings(const ImVec2 pos, const ImVec2 size, 92 | const bool fractional, 93 | const float scroll_y, 94 | const bool collapsed, 95 | const ImGuiWindowFlags window_flags = ImGuiWindowFlags_None) 96 | { 97 | pos_ = pos; 98 | size_ = size; 99 | fractional_ = fractional; 100 | scroll_y_ = scroll_y; 101 | collapsed_ = collapsed; 102 | window_flags_ = window_flags; 103 | init_ = true; 104 | } 105 | protected: 106 | // TODO(lucasw) this sorts into alphabetical order, but want to preserve insertion order 107 | struct TabGroup { 108 | TabGroup(const std::string& name) : name_(name) 109 | { 110 | } 111 | std::string name_ = ""; 112 | std::map > widgets_; 113 | std::vector widget_order_; 114 | 115 | virtual void update(const ros::Time& stamp, const std::string dropped_file) 116 | { 117 | for (auto& name : widget_order_) { 118 | if (widgets_[name]) { 119 | widgets_[name]->update(stamp, dropped_file); 120 | } 121 | } 122 | } 123 | virtual void draw(); 124 | void add(std::shared_ptr widget); 125 | void remove(const std::string& name); 126 | 127 | void addTF(tf2_msgs::TFMessage& tfm, const ros::Time& now) { 128 | for (auto& name : widget_order_) { 129 | if (widgets_[name]) { 130 | widgets_[name]->addTF(tfm, now); 131 | } 132 | } 133 | } // addTF 134 | }; // TabGroup 135 | 136 | std::map > tab_groups_; 137 | 138 | // initial settings 139 | ImVec2 pos_; 140 | ImVec2 size_; 141 | bool fractional_ = false; 142 | float scroll_y_ = 0.0; 143 | bool collapsed_ = false; 144 | bool init_ = false; 145 | 146 | ImGuiWindowFlags window_flags_ = ImGuiWindowFlags_None; 147 | 148 | ros::Time stamp_; 149 | bool dirty_ = true; 150 | std::string name_ = ""; 151 | std::mutex mutex_; 152 | }; 153 | 154 | } // namespace imgui_ros 155 | #endif // IMGUI_ROS_WINDOW_H 156 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_IMAGE_H 32 | #define IMGUI_ROS_IMAGE_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | // #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | namespace imgui_ros 46 | { 47 | struct GlImage : public Widget { 48 | GlImage(const std::string name, const std::string topic); 49 | ~GlImage(); 50 | virtual bool updateTexture() = 0; 51 | virtual void draw() = 0; 52 | 53 | // TODO(lucasw) or NULL or -1? 54 | GLuint texture_id_ = 0; 55 | // protected: 56 | size_t width_ = 0; 57 | size_t height_ = 0; 58 | }; 59 | 60 | // TODO(lucasw) RosImage is capable of subscribing a ros image and displaying 61 | // it, or being used to publish an internally generated image, or publishing 62 | // an image loaded from disk - maybe should subclass or delineate these 63 | // modes better. 64 | 65 | // TODO(lucasw) move ros specific code out, have not ros code in common 66 | // location that ros1 and ros2 versions can use. 67 | // TODO(lucasw) should every window be a node? Or less overhead to 68 | // have a single node in the imgui parent? 69 | struct RosImage : public GlImage { 70 | // TODO(lucasw) image_transfer is required, can't be nullptr 71 | RosImage(const std::string name, 72 | std::shared_ptr image_transfer, 73 | const std::string topic = "", 74 | const bool sub_not_pub = false, 75 | const bool ros_pub = false); 76 | RosImage(const std::string& name, 77 | std::shared_ptr image_transfer, 78 | sensor_msgs::ImagePtr image); 79 | 80 | virtual void update(const ros::Time& stamp, const std::string dropped_file="") override; 81 | // void imageCallback(const sensor_msgs::ImagePtr msg); 82 | 83 | // TODO(lucasw) factor this into a generic opengl function to put in parent class 84 | // if the image changes need to call this 85 | virtual bool updateTexture(); 86 | 87 | // TODO(lucasw) factor out common code 88 | virtual void draw(); 89 | 90 | virtual void publish(const ros::Time& stamp); 91 | 92 | sensor_msgs::ImagePtr image_msg_; 93 | 94 | int wrap_s_ind_ = 0; 95 | int wrap_t_ind_ = 0; 96 | int min_filter_ind_ = 5; 97 | int mag_filter_ind_ = 1; 98 | bool draw_texture_controls_ = false; 99 | bool enable_draw_image_ = false; 100 | bool enable_cpu_to_gpu_ = true; 101 | std::string header_frame_id_ = ""; 102 | // is there a fresh image to publish? 103 | bool pub_dirty_ = true; 104 | // may want to keep the image just within imgui, don't send it anywhere 105 | bool enable_publish_ = true; 106 | private: 107 | const bool sub_not_pub_ = false; 108 | std::shared_ptr image_transfer_; 109 | 110 | // temp until image_transfer supports subs 111 | // ros::Subscription::SharedPtr sub_; 112 | 113 | std::vector min_filter_modes_; 114 | std::vector mag_filter_modes_; 115 | std::vector wrap_modes_; 116 | 117 | std::string loaded_file_ = ""; 118 | 119 | // TODO(lucasw) Duration(0, 0) may have resulted in crashes? 120 | ros::Duration image_gap_ = ros::Duration(0); 121 | ros::Duration image_age_ = ros::Duration(0); 122 | bool enable_one_to_one_ = false; 123 | }; // RosImage 124 | 125 | struct CvImage : public GlImage { 126 | CvImage(const std::string name); 127 | // TODO(lucasw) instead of cv::Mat use a sensor_msgs Image pointer, 128 | // an convert straight from that format rather than converting to cv. 129 | // Or just have two implementations of Image here, the cv::Mat 130 | // would be good to keep as an example. 131 | cv::Mat image_; 132 | 133 | // if the image changes need to call this 134 | virtual bool updateTexture(); 135 | virtual void draw(); 136 | }; 137 | } // namespace imgui_ros 138 | #endif // IMGUI_ROS_IMAGE_H 139 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/camera.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_CAMERA_H 32 | #define IMGUI_ROS_CAMERA_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | // #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #pragma GCC diagnostic push 48 | #pragma GCC diagnostic ignored "-Wpedantic" 49 | // About OpenGL function loaders: modern OpenGL doesn't have a standard header 50 | // file and requires individual function pointers to be loaded manually. Helper 51 | // libraries are often used for this purpose! Here we are supporting a few 52 | // common ones: gl3w, glew, glad. You may use another loader/header of your 53 | // choice (glext, glLoadGen, etc.), or chose to manually implement your own. 54 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 55 | #include // Initialize with gl3wInit() 56 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 57 | #include // Initialize with glewInit() 58 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 59 | #include // Initialize with gladLoadGL() 60 | #else 61 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 62 | #endif 63 | #pragma GCC diagnostic pop 64 | 65 | namespace imgui_ros 66 | { 67 | struct Camera { 68 | Camera(const std::string name, 69 | const std::string frame_id, 70 | const std::string header_frame_id, 71 | const double aov_y, 72 | const double aov_x, 73 | ros::NodeHandle* nh); 74 | ~Camera(); 75 | 76 | void init(const size_t width, const size_t height, 77 | const std::string& texture_name, const std::string& topic, 78 | const bool ros_pub, 79 | ros::NodeHandle* nh, 80 | std::shared_ptr image_transfer); 81 | virtual void draw(); 82 | // void render(); 83 | 84 | std::string name_; 85 | // the frame used in the simulation- needs to be in opengl frame 86 | // z back, x right, y up 87 | std::string frame_id_; 88 | // the frame reported on published messages, should be in optical frame 89 | // z forward, x right, y down 90 | std::string header_frame_id_; 91 | tf2::Stamped stamped_transform_; 92 | std::shared_ptr image_; 93 | 94 | ros::Publisher camera_info_pub_; 95 | void publishCameraInfo(const ros::Time& stamp); 96 | 97 | ImVec4 clear_color_ = ImVec4(0.5, 0.5, 0.5, 1.0); 98 | 99 | // TODO(lucasw) later need to use this and resolution to make a CameraInfo 100 | double aov_y_ = 90.0; 101 | double aov_x_ = 0.0; 102 | 103 | double near_ = 0.01; 104 | double far_ = 100.0; 105 | 106 | bool isReadyToRender(); 107 | // <= 0.0 means render as fast as main loop, otherwise 108 | // try to get close to the desired framerate by skipping some frames 109 | float frame_rate = 0.0; 110 | // the easiest frame rates to do will be those that involving skipping n 111 | // frames for every rendered, or rendering n frames for every skipped, 112 | // so for 30Hz update rate this means: 113 | // skip_max output frame rate (30 / (skip_max) 114 | // 1 30 115 | // 2 15 116 | // 3 10 117 | // 4 7.5 118 | // 5 6 119 | // 6 5 120 | // 7 4.28 121 | // 8 3.75 122 | // ... 123 | // pub_max output frame rate 30 * pub_max / (pub_max + 1) 124 | // 1 15 125 | // 2 20 126 | // 3 22.5 127 | // 4 24.0 128 | // 5 25 129 | // 6 25.7 130 | // 7 26.25 131 | // 8 26.7 132 | // ... 133 | // 19 28.5 134 | // ... 135 | // TODO make a map of pairs of pub/skip maxes 136 | size_t pub_count_ = 0; 137 | size_t pub_max_ = 0; 138 | size_t skip_count_ = 0; 139 | size_t skip_max_ = 0; 140 | void setFrameRate(const float target_frame_rate, const float update_rate); 141 | 142 | // TODO(lucasw) put in own class later 143 | bool enable_ = true; 144 | GLuint frame_buffer_; 145 | GLuint depth_buffer_; 146 | // TODO(lucasw) not sure about this 147 | GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; 148 | }; 149 | 150 | } // namespace imgui_ros 151 | #endif // IMGUI_ROS_CAMERA_H 152 | -------------------------------------------------------------------------------- /imgui_ros/src/test/generate_pointcloud2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Lucas Walter 3 | * October 2019 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | // this brings in a boost system dependency, 33 | // will get undefined reference to `boost::system::generic_category() 34 | #include 35 | #include 36 | #include 37 | #include 38 | using namespace std::chrono_literals; 39 | 40 | 41 | namespace imgui_ros 42 | { 43 | 44 | class GeneratePointCloud2 : public ros::Node 45 | { 46 | public: 47 | GeneratePointCloud2() 48 | { 49 | } 50 | 51 | void init( 52 | const std::string & node_name, 53 | const std::string & namespace_, 54 | ros::Context::SharedPtr context, 55 | const std::vector & arguments, 56 | const std::vector & initial_parameters, 57 | bool use_global_arguments, 58 | bool use_intra_process_comms, 59 | bool start_parameter_services) 60 | { 61 | // If this is forgotten the node loader will crash 62 | ros::Node::init( 63 | node_name, 64 | namespace_, 65 | context, 66 | arguments, 67 | initial_parameters, 68 | use_global_arguments, 69 | use_intra_process_comms, 70 | start_parameter_services); 71 | 72 | get_parameter_or("num_lat", num_lat_, num_lat_); 73 | set_parameter_if_not_set("num_lat", num_lat_); 74 | get_parameter_or("num_long", num_long_, num_long_); 75 | set_parameter_if_not_set("num_long", num_long_); 76 | 77 | get_parameter_or("frame_id", frame_id_, frame_id_); 78 | set_parameter_if_not_set("frame_id", frame_id_); 79 | 80 | generatePointCloud2(); 81 | 82 | pub_ = create_publisher("point_cloud"); 83 | timer_ = this->create_wall_timer(1000ms, 84 | std::bind(&GeneratePointCloud2::update, this)); 85 | } 86 | 87 | ~GeneratePointCloud2() 88 | { 89 | } 90 | private: 91 | void generatePointCloud2() 92 | { 93 | // TODO(lucasw) generate a cube or sphere instead, more interesting than 2di 94 | const float radius = 1.0; 95 | for (int i = 0; i < num_lat_; ++i) { 96 | const float fr_lat = static_cast(i) / static_cast(num_lat_); 97 | const float phi = (fr_lat - 0.5) * M_PI; 98 | for (int j = 0; j < num_long_; ++j) { 99 | const float fr_long = static_cast(j) / static_cast(num_long_); 100 | const float theta = fr_long * M_PI * 2.0; 101 | 102 | // TODO(lucasw) normals 103 | pcl::PointXYZRGB pt; 104 | pt = pcl::PointXYZRGB(50 + fr_lat * 205, 255 - fr_long * 100, 255); 105 | pt.x = radius * cos(phi) * cos(theta); 106 | pt.y = radius * cos(phi) * sin(theta); 107 | pt.z = radius * sin(phi); 108 | 109 | #if 1 110 | const uint8_t& pixel_r = 255 * fr_lat; 111 | const uint8_t& pixel_g = 255 * (1.0 - fr_long); 112 | const uint8_t& pixel_b = 255; 113 | // Define point color 114 | uint32_t rgb = (static_cast(pixel_r) << 16 115 | | static_cast(pixel_g) << 8 116 | | static_cast(pixel_b)); 117 | pt.rgb = *reinterpret_cast(&rgb); 118 | #endif 119 | cloud_.points.push_back(pt); 120 | } 121 | } 122 | 123 | pc2_msg_ = std::make_shared(); 124 | pcl::toROSMsg(cloud_, *pc2_msg_); 125 | 126 | // TEMP test 127 | #if 1 128 | { 129 | pcl::PointCloud cloud2; 130 | pcl::fromROSMsg(*pc2_msg_, cloud2); 131 | std::cout << cloud2.points.size() << "\n"; 132 | } 133 | #endif 134 | 135 | pc2_msg_->header.frame_id = frame_id_; 136 | } 137 | 138 | void update() 139 | { 140 | if (!pc2_msg_) { 141 | return; 142 | } 143 | 144 | // TODO(lucasw) regenerate if num_points has changed 145 | 146 | pc2_msg_->header.stamp = now(); 147 | 148 | pub_->publish(pc2_msg_); 149 | } 150 | 151 | int num_lat_ = 36; 152 | int num_long_ = 36; 153 | std::string frame_id_ = "map"; 154 | 155 | pcl::PointCloud cloud_; 156 | sensor_msgs::PointCloud2::SharedPtr pc2_msg_; 157 | 158 | ros::Publisher::SharedPtr pub_; 159 | ros::TimerBase::SharedPtr timer_; 160 | }; 161 | 162 | } // namespace imgui_ros 163 | 164 | #include 165 | 166 | CLASS_LOADER_REGISTER_CLASS(imgui_ros::GeneratePointCloud2, ros::Node) 167 | -------------------------------------------------------------------------------- /imgui_ros/include/imgui_ros/node.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Lucas Walter 3 | * June 2017 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef IMGUI_ROS_NODE_H 32 | #define IMGUI_ROS_NODE_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | // Adapting from https://gist.github.com/ocornut/7e9b3ec566a333d725d4 by ocornut 41 | // NB: You can use math functions/operators on ImVec2 if you #define IMGUI_DEFINE_MATH_OPERATORS and #include "imgui_internal.h" 42 | // Here we only declare simple +/- operators so others don't leak into the demo code. 43 | static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } 44 | static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } 45 | 46 | namespace imgui_ros 47 | { 48 | struct Link; 49 | struct Node; 50 | 51 | // either input or output 52 | struct Connector : std::enable_shared_from_this 53 | { 54 | Connector(const bool input_not_output) : input_not_output_(input_not_output) 55 | { 56 | color_ = ImVec4(0.5, 0.5, 0.5, 0.6); 57 | } 58 | 59 | std::string name_; 60 | float value_; 61 | bool selected_ = false; 62 | const float RADIUS = 8.0f; 63 | ImVec4 color_; 64 | ImVec2 pos_; 65 | ImVec2 size_; 66 | 67 | bool input_not_output_ = true; 68 | 69 | void update(); 70 | void draw(ImDrawList* draw_list, const ImVec2& offset, 71 | std::shared_ptr& src, std::shared_ptr& dst); 72 | ImVec2 getPos(); 73 | ImVec2 getEndPos(); 74 | 75 | std::shared_ptr parent_; 76 | std::shared_ptr link_; 77 | }; 78 | 79 | struct Node : std::enable_shared_from_this 80 | { 81 | std::string name_; 82 | ImVec2 pos_, size_; 83 | ImVec4 color_; 84 | bool selected_ = false; 85 | const ImVec2 NODE_WINDOW_PADDING = ImVec2(8.0f, 8.0f); 86 | 87 | Node(const std::string& name, const ImVec2& pos, 88 | const ImVec4& color) : 89 | name_(name) 90 | { 91 | pos_ = pos; 92 | color_ = color; 93 | } 94 | 95 | ImVec2 getPos() { return pos_; } 96 | 97 | void resetConnections(); 98 | virtual void init() { resetConnections();} 99 | virtual void update(const double& seconds) { seconds_ = seconds;} 100 | 101 | virtual void draw2(ImDrawList* draw_list); 102 | virtual void draw(ImDrawList* draw_list, const ImVec2& offset, 103 | std::shared_ptr& node_hovered_in_list, 104 | std::shared_ptr& node_hovered_in_scene, 105 | bool& open_context_menu, 106 | std::shared_ptr& con_src, std::shared_ptr& con_dst); 107 | 108 | double seconds_; 109 | 110 | std::map > inputs_; 111 | std::map > outputs_; 112 | }; 113 | 114 | struct Link 115 | { 116 | Link(const std::string& name) : name_(name) 117 | { 118 | } 119 | 120 | virtual void update(); 121 | virtual void draw(ImDrawList* draw_list, const ImVec2& offset); 122 | 123 | std::string name_; 124 | // TODO(lucasw) weak_ptr instead? 125 | std::shared_ptr input_; 126 | std::map > outputs_; 127 | }; 128 | 129 | /////////////////////////////////////////////////////////////////////// 130 | struct SignalGenerator : public Node 131 | { 132 | SignalGenerator(const std::string& name, const ImVec2& pos); 133 | virtual void init(); 134 | virtual void update(const double& seconds); 135 | virtual void draw2(ImDrawList* draw_list); 136 | 137 | // TODO(lucasw) Turn these into inputs later 138 | float amplitude_ = 1.0; 139 | float frequency_ = 1.0; 140 | }; 141 | 142 | struct SignalCombine : public Node 143 | { 144 | SignalCombine(const std::string& name, const ImVec2& pos); 145 | virtual void init(); 146 | virtual void update(const double& seconds); 147 | virtual void draw2(ImDrawList* draw_list); 148 | }; 149 | 150 | struct FloatPublisher : public Node 151 | { 152 | FloatPublisher(const std::string& name, const ImVec2& pos, const std::string& topic); 153 | virtual void init(); 154 | virtual void update(const double& seconds); 155 | virtual void draw2(ImDrawList* draw_list); 156 | 157 | std::string topic_; 158 | ros::Publisher pub_; 159 | }; 160 | 161 | } // namespace imgui_ros 162 | #endif // IMGUI_ROS_NODE_H 163 | -------------------------------------------------------------------------------- /imgui_ros/scripts/old/imgui_ros/demo_imgui_ros.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2019 Lucas Walter 3 | # February 2019 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # * Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # * Neither the name of the Willow Garage, Inc. nor the names of its 15 | # contributors may be used to endorse or promote products derived from 16 | # this software without specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | # POSSIBILITY OF SUCH DAMAGE. 29 | 30 | import argparse 31 | import imgui_ros 32 | import internal_pub_sub 33 | import rclpy 34 | import sys 35 | import time 36 | 37 | from ament_index_python.packages import get_package_share_directory 38 | from internal_pub_sub.msg import NodeSettings, Remapping 39 | from internal_pub_sub.srv import AddNode 40 | from rcl_interfaces.msg import Parameter, ParameterType 41 | from rclpy.node import Node 42 | 43 | 44 | class DemoImguiRos(Node): 45 | def __init__(self): 46 | super().__init__('demo_add_node') 47 | self.node_cli = self.create_client(AddNode, 'add_node') 48 | while not self.node_cli.wait_for_service(timeout_sec=3.0): 49 | self.get_logger().info(self.get_namespace() + '/add_node service not available') 50 | time.sleep(1.0) 51 | 52 | def wait_for_response(self): 53 | while rclpy.ok(): 54 | rclpy.spin_once(self) 55 | if self.future.done(): 56 | if self.future.result() is not None: 57 | response = self.future.result() 58 | self.get_logger().info( 59 | 'Result %s' % (str(response))) 60 | else: 61 | self.get_logger().info( 62 | 'Service call failed %r' % (self.future.exception(),)) 63 | break 64 | 65 | def run(self, namespace='', load_imgui_node=True): 66 | add_node = AddNode.Request() 67 | if load_imgui_node: 68 | node_settings = NodeSettings() 69 | node_settings.package_name = 'imgui_ros' 70 | node_settings.plugin_name = 'ImguiRos' 71 | node_settings.node_name = 'imgui_ros' 72 | node_settings.node_namespace = namespace 73 | node_settings.internal_pub_sub = True 74 | 75 | # TODO(lucasw) need to be able to specify parameters with fewer lines 76 | # parameters 77 | node_settings.parameters.append(internal_pub_sub.string_param('name', 'imgui_ros_demo')) 78 | node_settings.parameters.append(internal_pub_sub.integer_param('width', 1440)) 79 | node_settings.parameters.append(internal_pub_sub.integer_param('height', 800)) 80 | node_settings.parameters.append(internal_pub_sub.double_param('red', 0.5)) 81 | node_settings.parameters.append(internal_pub_sub.double_param('green', 0.5)) 82 | node_settings.parameters.append(internal_pub_sub.double_param('blue', 0.52)) 83 | 84 | if False: 85 | node_settings.remappings.append(internal_pub_sub.make_remapping('image', 'different_image')) 86 | 87 | add_node.node_settings.append(node_settings) 88 | 89 | # generate test pointcloud2 90 | if True: 91 | # this is taking up 100% cpu 92 | node_settings = NodeSettings() 93 | node_settings.package_name = 'imgui_ros' 94 | node_settings.plugin_name = 'GeneratePointCloud2' 95 | node_settings.node_name = 'generate_pointcloud2' 96 | node_settings.node_namespace = namespace 97 | node_settings.internal_pub_sub = False 98 | add_node.node_settings.append(node_settings) 99 | 100 | self.future = self.node_cli.call_async(add_node) 101 | self.wait_for_response() 102 | 103 | imgui_ros.add_default_shaders(namespace) 104 | 105 | try: 106 | print("add shapes and textures") 107 | node = imgui_ros.PubShape() 108 | node.run(namespace) 109 | finally: 110 | node.destroy_node() 111 | 112 | try: 113 | print("add cameras") 114 | node = imgui_ros.Cameras() 115 | node.run(namespace) 116 | finally: 117 | node.destroy_node() 118 | 119 | try: 120 | print("add gui controls") 121 | node = imgui_ros.DemoGui() 122 | node.run(namespace) 123 | finally: 124 | node.destroy_node() 125 | 126 | def main(args=None): 127 | rclpy.init(args=args) 128 | 129 | parser = argparse.ArgumentParser(description='load_sim_line_nodes') 130 | parser.add_argument('-n', '--load-imgui-node', dest='load_imgui_node', # type=bool, 131 | help='enable node loading', action='store_true') # , default=True) 132 | args, unknown = parser.parse_known_args(sys.argv) 133 | 134 | try: 135 | demo = DemoImguiRos() 136 | demo.run('', args.load_imgui_node) 137 | finally: 138 | demo.destroy_node() 139 | 140 | rclpy.shutdown() 141 | 142 | if __name__ == '__main__': 143 | main() 144 | -------------------------------------------------------------------------------- /imgui_ros/src/window.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | // #include "imgui.h" 32 | // #include "imgui_impl_opengl3.h" 33 | // #include "imgui_impl_sdl.h" 34 | // #include 35 | #include 36 | #include 37 | // #include 38 | 39 | namespace imgui_ros 40 | { 41 | Window::~Window() 42 | { 43 | ROS_INFO_STREAM("freeing window " << this); 44 | } 45 | 46 | void Window::update(const ros::Time& stamp, const std::string dropped_file) 47 | { 48 | stamp_ = stamp; 49 | 50 | for (auto tab_pair : tab_groups_) { 51 | tab_pair.second->update(stamp, dropped_file); 52 | } 53 | } 54 | 55 | void Window::draw( 56 | const int outer_window_width, 57 | const int outer_window_height) 58 | { 59 | if (fractional_) { 60 | // TODO(lucasw) need to handle dragging 61 | ROS_DEBUG_STREAM(pos_.x << " * " << outer_window_width); 62 | ImGui::SetNextWindowPos(ImVec2(pos_.x * outer_window_width, pos_.y * outer_window_height)); 63 | ImGui::SetNextWindowSize(ImVec2(size_.x * outer_window_width, size_.y * outer_window_height)); 64 | } 65 | if (init_) { 66 | if (!fractional_) { 67 | ImGui::SetNextWindowPos(pos_); 68 | ImGui::SetNextWindowSize(size_); 69 | } 70 | ImGui::SetNextWindowCollapsed(collapsed_); 71 | } 72 | 73 | ImGui::Begin(name_.c_str(), NULL, window_flags_); 74 | // std::stringstream ss; 75 | // ss << tab_groups_.size() << " "; 76 | 77 | // ImGui::Text("%lu", tab_groups_.size()); 78 | 79 | ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; 80 | if (tab_groups_.size() > 1) { 81 | if (ImGui::BeginTabBar(name_.c_str(), tab_bar_flags)) { 82 | for (auto& tab_pair : tab_groups_) { 83 | const auto& tab_name = tab_pair.first; 84 | const auto& tab_group = tab_pair.second; 85 | // ImGui::Text("%s", tab_name.c_str()); 86 | // std::cout << "'" << name_ << "' " << tab_name << "\n"; 87 | // ss << tab_name << " "; 88 | if (tab_group) { 89 | if (ImGui::BeginTabItem(tab_name.c_str())) { 90 | tab_group->draw(); 91 | ImGui::EndTabItem(); 92 | } 93 | } 94 | } 95 | } 96 | ImGui::EndTabBar(); 97 | } else if (tab_groups_.size() == 1) { 98 | for (auto& tab_pair : tab_groups_) { 99 | // const auto& tab_name = tab_pair.first; 100 | // ImGui::Text("%s", tab_name.c_str()); 101 | const auto& tab_group = tab_pair.second; 102 | tab_group->draw(); 103 | } 104 | } 105 | // ImGui::Text("%s", ss.str().c_str()); 106 | 107 | // won't know scroll max y until after drawing window? 108 | if (init_) { 109 | const float scroll_y_adj = scroll_y_ * ImGui::GetScrollMaxY(); 110 | ImGui::SetScrollY(scroll_y_adj); 111 | init_ = false; 112 | } 113 | // ImGui::Text("%0.2f %0.2f %0.2f", ImGui::GetScrollY(), 114 | // ImGui::GetScrollMaxY(), scroll_y_); 115 | ImGui::End(); 116 | } 117 | 118 | void Window::TabGroup::draw() { 119 | for (auto& name : widget_order_) { 120 | // ImGui::Text("%s", name.c_str()); 121 | if (widgets_[name]) { 122 | // TODO(lucasw) make collapsing header optional 123 | // if (ImGui::CollapsingHeader((name + "##header").c_str())) { 124 | // { 125 | widgets_[name]->draw(); 126 | // } 127 | } 128 | } 129 | } 130 | 131 | void Window::add(std::shared_ptr widget, const std::string& tab_name) { 132 | if (tab_groups_.count(tab_name) < 1) { 133 | std::cout << "'" << name_ << "' new tab group '" << tab_name << "' " 134 | << tab_groups_.size() << " " << this << "\n"; 135 | tab_groups_[tab_name] = std::make_shared(tab_name); 136 | } 137 | tab_groups_[tab_name]->add(widget); 138 | } 139 | 140 | void Window::remove(const std::string& name, const std::string& tab_name) { 141 | if (tab_groups_.count(tab_name) > 0) { 142 | std::cout << "'" << name_ << "' removing tab group '" << tab_name << "' widget '" 143 | << name << "'\n"; 144 | tab_groups_[tab_name]->remove(name); 145 | } 146 | // TODO(lucasw) if no widgets in current tab name, remove it 147 | } 148 | 149 | // TODO(lucasw) add ability to insert earlier into list, or if already exists 150 | // then keep current position, currently only adds to end 151 | void Window::TabGroup::add(std::shared_ptr widget) { 152 | const std::string name = widget->name_; 153 | remove(name); 154 | widgets_[name] = widget; 155 | widget_order_.push_back(name); 156 | } 157 | 158 | void Window::TabGroup::remove(const std::string& name) { 159 | if (widgets_.count(name) > 0) { 160 | widget_order_.erase(std::remove(widget_order_.begin(), 161 | widget_order_.end(), name), 162 | widget_order_.end()); 163 | } 164 | widgets_.erase(name); 165 | } 166 | } // namespace imgui_ros 167 | -------------------------------------------------------------------------------- /imgui_ros/src/param_to_topic.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "ros/ros.h" 21 | #include "rcutils/cmdline_parser.h" 22 | 23 | #include "std_msgs/float32.hpp" 24 | 25 | using namespace std::chrono_literals; 26 | 27 | void print_usage() 28 | { 29 | printf("Usage for talker app:\n"); 30 | printf("talker [-t topic_name] [-h]\n"); 31 | printf("options:\n"); 32 | printf("-h : Print this help function.\n"); 33 | printf("-t topic_name : Specify the topic on which to publish. Defaults to chatter.\n"); 34 | } 35 | 36 | // Create a ParamToTopic class that subclasses the generic ros::Node base class. 37 | // The main function below will instantiate the class as a ROS node. 38 | class ParamToTopic : public ros::Node 39 | { 40 | public: 41 | explicit ParamToTopic() 42 | : Node("param_to_topic") 43 | { 44 | } 45 | 46 | // can't init in constructor because shared_from_this will throw bad_weak_ptr 47 | void init() 48 | { 49 | msg_ = std::make_shared(); 50 | const std::string topic_name = "test"; 51 | 52 | // Typically a parameter client is created for a remote node by passing the name of the remote 53 | // node in the constructor; in this example we create a parameter client for this node itself. 54 | parameters_client_ = std::make_shared(this); 55 | 56 | auto on_parameter_event_callback = 57 | [this](const rcl_interfaces::ParameterEvent::SharedPtr event) -> void 58 | { 59 | // TODO(wjwwood): The message should have an operator<<, which would replace all of this. 60 | std::stringstream ss; 61 | ss << "\nParameter event:\n new parameters:"; 62 | for (auto & new_parameter : event->new_parameters) { 63 | ss << "\n " << new_parameter.name; 64 | } 65 | ss << "\n changed parameters:"; 66 | for (auto & changed_parameter : event->changed_parameters) { 67 | ss << "\n " << changed_parameter.name; 68 | if (changed_parameter.name == "foo") { 69 | float val; 70 | get_parameter_or("foo", val, 0.0f); 71 | msg_->data = val; 72 | ss << " " << val << " "; 73 | } 74 | } 75 | ss << "\n deleted parameters:"; 76 | for (auto & deleted_parameter : event->deleted_parameters) { 77 | ss << "\n " << deleted_parameter.name; 78 | } 79 | ss << "\n"; 80 | ROS_INFO_STREAM(ss.str().c_str()); 81 | }; 82 | 83 | // Setup callback for changes to parameters. 84 | parameter_event_sub_ = parameters_client_->on_parameter_event(on_parameter_event_callback); 85 | 86 | // Node already has std::enable_shared_from_this 87 | parameters_client_ = std::make_shared(shared_from_this()); 88 | while (!parameters_client_->wait_for_service(1s)) { 89 | if (!ros::ok()) { 90 | ROS_ERROR_STREAM("Interrupted while waiting for the service. Exiting."); 91 | return; 92 | } 93 | ROS_INFO_STREAM("service not available, waiting again..."); 94 | } 95 | 96 | // TODO(lucasw) there ought to be a set_parameter for setting just one parameter 97 | #if 0 98 | auto results = parameters_client_->set_parameters({ros::Parameter("foo", 2.0)}); 99 | for (auto result : results) { 100 | if (!result.successful) { 101 | ROS_ERROR_STREAM("Failed to set parameter: %s", result.reason.c_str()); 102 | } 103 | } 104 | #endif 105 | 106 | // Create a function for when messages are to be sent. 107 | auto publish_message = 108 | [this]() -> void 109 | { 110 | #if 0 111 | for (auto & parameter : parameters_client_->get_parameters({"foo"})) { 112 | msg_->data = parameter.as_double(); 113 | } 114 | #endif 115 | // + std::to_string(count_++); 116 | // ROS_INFO_STREAM("Publishing: '%s'", msg_->data.c_str()); 117 | 118 | // Put the message into a queue to be processed by the middleware. 119 | // This call is non-blocking. 120 | pub_->publish(msg_); 121 | }; 122 | 123 | // Create a publisher with a custom Quality of Service profile. 124 | rmw_qos_profile_t custom_qos_profile = rmw_qos_profile_default; 125 | custom_qos_profile.depth = 7; 126 | pub_ = this->create_publisher(topic_name, custom_qos_profile); 127 | // Use a timer to schedule periodic message publishing. 128 | timer_ = this->create_wall_timer(1s, publish_message); 129 | } 130 | 131 | private: 132 | std::shared_ptr parameters_client_; 133 | ros::Subscription::SharedPtr parameter_event_sub_; 134 | std::shared_ptr msg_; 135 | ros::Publisher::SharedPtr pub_; 136 | ros::TimerBase::SharedPtr timer_; 137 | }; 138 | 139 | int main(int argc, char * argv[]) 140 | { 141 | // Force flush of the stdout buffer. 142 | // This ensures a correct sync of all prints 143 | // even when executed simultaneously within the launch file. 144 | setvbuf(stdout, NULL, _IONBF, BUFSIZ); 145 | 146 | if (rcutils_cli_option_exist(argv, argv + argc, "-h")) { 147 | print_usage(); 148 | return 0; 149 | } 150 | 151 | // Initialize any global resources needed by the middleware and the client library. 152 | // You must call this before using any other part of the ROS system. 153 | // This should be called once per process. 154 | ros::init(argc, argv); 155 | 156 | // Create a node. 157 | auto node = std::make_shared(); 158 | node->init(); 159 | 160 | // spin will block until work comes in, execute work as it becomes available, and keep blocking. 161 | // It will only be interrupted by Ctrl-C. 162 | ros::spin(node); 163 | 164 | ros::shutdown(); 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /imgui_ros/src/surface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | // #include "imgui_impl_sdl.h" 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | using std::placeholders::_1; 45 | using std::placeholders::_2; 46 | 47 | 48 | namespace imgui_ros 49 | { 50 | constexpr std::array Shape::draw_modes_; 51 | // A 3D shape with textures 52 | // For more textures a more complex object would need to be a composite 53 | // of multiple Shapes. 54 | Shape::Shape(const std::string& name, const std::string& frame_id, 55 | const std::string& texture_name, 56 | const std::string& shininess_texture_name, 57 | std::shared_ptr tf_buffer) : 58 | name_(name), 59 | frame_id_(frame_id), 60 | texture_(texture_name), 61 | shininess_texture_(shininess_texture_name), 62 | tf_buffer_(tf_buffer) 63 | { 64 | glGenVertexArrays(1, &vao_handle_); 65 | glBindVertexArray(vao_handle_); 66 | 67 | glGenBuffers(1, &vbo_handle_); 68 | glBindBuffer(GL_ARRAY_BUFFER, vbo_handle_); 69 | glGenBuffers(1, &elements_handle_); 70 | 71 | // TBD 72 | glBindBuffer(GL_ARRAY_BUFFER, 0); 73 | glBindVertexArray(0); 74 | } 75 | 76 | Shape::~Shape() 77 | { 78 | glDeleteBuffers(1, &elements_handle_); 79 | glDeleteBuffers(1, &vbo_handle_); 80 | glDeleteVertexArrays(1, &vao_handle_); 81 | } 82 | 83 | void Shape::init() 84 | { 85 | glBindBuffer(GL_ARRAY_BUFFER, vbo_handle_); 86 | // copy vertex data to gpu 87 | glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)vertices_.Size * sizeof(DrawVert), 88 | (const GLvoid*)vertices_.Data, GL_STREAM_DRAW); 89 | 90 | checkGLError(__FILE__, __LINE__); 91 | if (false) { 92 | std::cout << "'" << name_ << "' init vao " << vao_handle_ << ", " 93 | << "vbo " << vbo_handle_ << ", elements " << elements_handle_ << ", " 94 | << "vertices size " << vertices_.Size << ", " 95 | << "indices size " << indices_.Size << "\n"; 96 | } 97 | 98 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elements_handle_); 99 | // copy index data to the gpu 100 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)indices_.Size * sizeof(ImDrawIdx), 101 | (const GLvoid*)indices_.Data, GL_STREAM_DRAW); 102 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 103 | 104 | #if 0 105 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 106 | glBindBuffer(GL_ARRAY_BUFFER, 0); 107 | glBindVertexArray(0); 108 | #endif 109 | checkGLError(__FILE__, __LINE__); 110 | } 111 | 112 | void Shape::draw(const std::vector& texture_names_, 113 | const std::string& texture_items) 114 | { 115 | ImGui::PushID(name_.c_str()); 116 | std::string name = name_ + " shape"; 117 | ImGui::Checkbox(name_.c_str(), &enable_); 118 | 119 | // TODO(lucasw) this is a pain 120 | int texture_ind = 0; 121 | int shininess_texture_ind = 0; 122 | int emission_texture_ind = 0; 123 | for (int i = 0; i < static_cast(texture_names_.size()); ++i) { 124 | if (texture_names_[i] == texture_) { 125 | texture_ind = i; 126 | } 127 | if (texture_names_[i] == shininess_texture_) { 128 | shininess_texture_ind = i; 129 | } 130 | if (texture_names_[i] == emission_texture_) { 131 | emission_texture_ind = i; 132 | } 133 | } 134 | 135 | bool changed; 136 | changed = ImGui::Combo("texture", &texture_ind, 137 | texture_items.c_str()); 138 | if (changed) { 139 | texture_ = texture_names_[texture_ind]; 140 | } 141 | 142 | changed = ImGui::Combo("shininess texture", 143 | &shininess_texture_ind, texture_items.c_str()); 144 | if (changed) { 145 | shininess_texture_ = texture_names_[shininess_texture_ind]; 146 | } 147 | 148 | changed = ImGui::Combo("emission texture", 149 | &emission_texture_ind, texture_items.c_str()); 150 | if (changed) { 151 | emission_texture_ = texture_names_[emission_texture_ind]; 152 | } 153 | 154 | const std::string items = std::string("triangles") + '\0' + 155 | std::string("lines") + '\0' + std::string("points") + '\0'; 156 | ImGui::Combo("draw mode", &draw_mode_, items.c_str()); 157 | 158 | // TODO(lucasw) put the frame in a combo box that allows it to be changed 159 | // to any other existing frame (or typed in?) 160 | // use tf buffer getFrames() 161 | imgui_ros::inputText("frame", frame_id_); 162 | std::stringstream ss; 163 | ss << " `- vertices: " << vertices_.size() << ", indices " << indices_.size() << "\n"; 164 | ss << " `- vao: " << vao_handle_ << ", vbo " << vbo_handle_ 165 | << ", elements " << elements_handle_ << "\n"; 166 | // ss << msg_; 167 | // TODO(lucasw) add interactive way to browse vertices and indices 168 | // maybe highlight each graphically as it is selected 169 | ImGui::Text("%s", ss.str().c_str()); 170 | ImGui::PopID(); 171 | } 172 | } // namespace imgui_ros 173 | -------------------------------------------------------------------------------- /imgui_ros/src/shaders.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Lucas Walter 3 | * October 2018 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of the Willow Garage, Inc. nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | // #include "imgui_impl_sdl.h" 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | using std::placeholders::_1; 44 | using std::placeholders::_2; 45 | 46 | namespace imgui_ros 47 | { 48 | ShaderSet::~ShaderSet() 49 | { 50 | remove(); 51 | } 52 | 53 | void ShaderSet::remove() 54 | { 55 | std::cout << "Deleting shader set " << name_ << " " 56 | << vert_handle_ << " " << frag_handle_ << " " << shader_handle_ << "\n"; 57 | glDeleteShader(vert_handle_); 58 | glDeleteShader(frag_handle_); 59 | glDeleteProgram(shader_handle_); 60 | } 61 | 62 | bool ShaderSet::init(const std::string& glsl_version, std::string& message) 63 | { 64 | message += "shader init: '" + name_ + "'\n"; 65 | if ((vert_handle_ != 0) || (frag_handle_ != 0) || (shader_handle_ != 0)) { 66 | std::stringstream ss; 67 | ss << "already initialized, deleting old versions " 68 | << vert_handle_ << " " << frag_handle_ << " " << shader_handle_ << "\n"; 69 | message += ss.str(); 70 | remove(); 71 | } 72 | // Create shaders 73 | const GLchar* vertex_shader_with_version[2] = {glsl_version.c_str(), 74 | vertex_code_.c_str()}; 75 | vert_handle_ = glCreateShader(GL_VERTEX_SHADER); 76 | if (!vert_handle_) 77 | { 78 | message = "vertex shader failed to create " + glGetError(); 79 | return false; 80 | } 81 | else 82 | { 83 | glShaderSource(vert_handle_, 2, vertex_shader_with_version, NULL); 84 | glCompileShader(vert_handle_); 85 | if (!CheckShader(vert_handle_, "vertex shader", message)) { 86 | // std::cout << vertex_code_ << std::endl; 87 | return false; 88 | } 89 | } 90 | 91 | const GLchar* fragment_shader_with_version[2] = {glsl_version.c_str(), fragment_code_.c_str() }; 92 | frag_handle_ = glCreateShader(GL_FRAGMENT_SHADER); 93 | if (!frag_handle_) 94 | { 95 | message = "fragment shader failed to create " + glGetError(); 96 | return false; 97 | } 98 | else 99 | { 100 | glShaderSource(frag_handle_, 2, fragment_shader_with_version, NULL); 101 | glCompileShader(frag_handle_); 102 | if (!CheckShader(frag_handle_, "fragment shader", message)) { 103 | // std::cout << fragment_code_ << std::endl; 104 | return false; 105 | } 106 | } 107 | 108 | shader_handle_ = glCreateProgram(); 109 | glAttachShader(shader_handle_, vert_handle_); 110 | glAttachShader(shader_handle_, frag_handle_); 111 | glLinkProgram(shader_handle_); 112 | if (!CheckProgram(shader_handle_, "shader program", message)) { 113 | return false; 114 | } 115 | 116 | GLint size; 117 | GLenum type; 118 | const GLsizei buf_size = 64; 119 | GLchar name_char[buf_size]; 120 | GLsizei length; 121 | 122 | GLint num_attribs = 0; 123 | glGetProgramiv(shader_handle_, GL_ACTIVE_ATTRIBUTES, &num_attribs); 124 | if (false) 125 | std::cout << "shader '" << name_ << "' has " << num_attribs << " attribs\n"; 126 | 127 | for (int i = 0; i < num_attribs; ++i) { 128 | glGetActiveAttrib(shader_handle_, (GLuint)i, buf_size, &length, &size, &type, name_char); 129 | std::string name(name_char); 130 | attrib_locations_[name] = glGetAttribLocation(shader_handle_, name.c_str()); 131 | if (false) 132 | std::cout << " '" << name << "' attrib location: " << attrib_locations_[name] 133 | << ", size " << size << ", type " << type << "\n"; 134 | } 135 | 136 | GLint num_uniforms = 0; 137 | glGetProgramiv(shader_handle_, GL_ACTIVE_UNIFORMS, &num_uniforms); 138 | if (false) 139 | std::cout << "shader '" << name_ << "' has " << num_uniforms << " uniforms\n"; 140 | 141 | for (int i = 0; i < num_uniforms; ++i) { 142 | glGetActiveUniform(shader_handle_, (GLuint)i, buf_size, &length, &size, &type, name_char); 143 | std::string name(name_char); 144 | 145 | // removing [0] makes the uniforms work properly 146 | std::string remove_str = "[0]"; 147 | size_t num = remove_str.size(); 148 | if (name.size() >= num) { 149 | if (name.substr(name.size() - num) == "[0]") { 150 | name = name.substr(0, name.size() - num); 151 | } 152 | } 153 | 154 | uniform_locations_[name] = glGetUniformLocation(shader_handle_, name.c_str()); 155 | // TODO(lucasw) ambient is -1, but still seems to work 156 | if (false) 157 | std::cout << " '" << name << "' uniform location: " << uniform_locations_[name] 158 | << ", size " << size << ", type " << type << "\n"; 159 | } 160 | 161 | std::string msg; 162 | if (checkGLError2(msg)) { 163 | return false; 164 | } 165 | 166 | return true; 167 | } 168 | 169 | void ShaderSet::draw() 170 | { 171 | std::stringstream ss; 172 | ss << "shader: " << name_ << " " << shader_handle_ << ", vert " << vert_handle_ 173 | << ", geometry " << geometry_handle_ << ", frag " << frag_handle_; 174 | ss << "\n"; 175 | 176 | for (auto name_pair : attrib_locations_) { 177 | std::string name = name_pair.first; 178 | ss << name << ": " << attrib_locations_[name] << ", "; 179 | } 180 | 181 | if (false) { 182 | ss << "\n--------------------------"; 183 | ss << vertex_code_ << "\n"; 184 | ss << "--------------------------"; 185 | ss << geometry_code_ << "\n"; 186 | ss << "--------------------------"; 187 | ss << fragment_code_ << "\n"; 188 | ss << "--------------------------"; 189 | } 190 | 191 | ImGui::Text("%s", ss.str().c_str()); 192 | } 193 | } // namespace imgui_ros 194 | --------------------------------------------------------------------------------