39#include <OpenGL/glu.h>
44#include <GL/freeglut.h>
52#include <rclcpp/logger.hpp>
53#include <rclcpp/logging.hpp>
78 glDeleteProgram(program_);
85 if (width_ != width || height_ != height)
97 throw runtime_error(
"near clipping plane distance needs to be larger than 0");
99 throw runtime_error(
"far clipping plane needs to be larger than near clipping plane distance");
112void mesh_filter::GLRenderer::setCameraParameters()
const
114 double left = near_ * -cx_ / fx_;
115 double right = near_ * (width_ - cx_) / fx_;
116 double top = near_ * cy_ / fy_;
117 double bottom = near_ * (cy_ - height_) / fy_;
119 glMatrixMode(GL_PROJECTION);
121 glFrustum(left, right, bottom, top, near_, far_);
123 glMatrixMode(GL_MODELVIEW);
125 gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
128void mesh_filter::GLRenderer::initFrameBuffers()
130 glGenTextures(1, &rgb_id_);
131 glBindTexture(GL_TEXTURE_2D, rgb_id_);
132 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
133 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
134 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
137 glBindTexture(GL_TEXTURE_2D, 0);
139 glGenTextures(1, &depth_id_);
140 glBindTexture(GL_TEXTURE_2D, depth_id_);
141 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
nullptr);
142 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
143 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
145 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
146 glBindTexture(GL_TEXTURE_2D, 0);
148 glGenFramebuffers(1, &fbo_id_);
149 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
150 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);
152 glGenRenderbuffers(1, &rbo_id_);
153 glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
154 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
155 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
156 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
157 glBindRenderbuffer(GL_RENDERBUFFER, 0);
159 GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
160 glDrawBuffers(2, draw_buffers);
162 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
164 if (status != GL_FRAMEBUFFER_COMPLETE)
165 throw runtime_error(
"Couldn't create frame buffer");
167 glBindFramebuffer(GL_FRAMEBUFFER, 0);
170void mesh_filter::GLRenderer::deleteFrameBuffers()
173 glDeleteRenderbuffers(1, &rbo_id_);
175 glDeleteFramebuffers(1, &fbo_id_);
177 glDeleteTextures(1, &depth_id_);
179 glDeleteTextures(1, &rgb_id_);
181 rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
186 glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT | GL_PIXEL_MODE_BIT);
187 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
188 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
189 glViewport(0, 0, width_, height_);
190 glUseProgram(program_);
191 setCameraParameters();
205 glBindFramebuffer(GL_FRAMEBUFFER, 0);
210 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
211 glBindTexture(GL_TEXTURE_2D, rgb_id_);
212 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
213 glBindFramebuffer(GL_FRAMEBUFFER, 0);
218 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
219 glBindTexture(GL_TEXTURE_2D, depth_id_);
220 glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
221 glBindFramebuffer(GL_FRAMEBUFFER, 0);
227 glDeleteProgram(program_);
229 string vertex_source, fragment_source;
230 readShaderCodeFromFile(vertex_filename, vertex_source);
231 readShaderCodeFromFile(fragment_filename, fragment_source);
233 program_ = loadShaders(vertex_source, fragment_source);
239 program_ = loadShaders(vertex_source, fragment_source);
258GLuint mesh_filter::GLRenderer::createShader(GLuint shaderType,
const string& ShaderCode)
const
260 GLuint shader_id = glCreateShader(shaderType);
263 const char* source_pointer = ShaderCode.c_str();
264 glShaderSource(shader_id, 1, &source_pointer,
nullptr);
265 glCompileShader(shader_id);
268 GLint result = GL_FALSE;
269 glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result);
270 if (result != GL_TRUE)
273 glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
274 if (info_log_length > 0)
276 vector<char> shader_error_message(info_log_length + 1);
277 glGetShaderInfoLog(shader_id, info_log_length,
nullptr, &shader_error_message[0]);
278 stringstream error_stream;
279 error_stream <<
"Could not compile shader: " <<
const_cast<const char*
>(&shader_error_message[0]);
281 glDeleteShader(shader_id);
282 throw runtime_error(error_stream.str());
288void mesh_filter::GLRenderer::readShaderCodeFromFile(
const string& filename,
string& shader)
const
290 if (filename.empty())
297 fstream shader_file(filename.c_str(), ios::in);
298 if (shader_file.is_open())
301 buffer << shader_file.rdbuf();
302 shader = buffer.str();
306 stringstream error_stream;
307 error_stream <<
"Could not open shader code in file \"" << filename <<
'\"';
308 throw runtime_error(error_stream.str());
313GLuint mesh_filter::GLRenderer::loadShaders(
const string& vertex_source,
const string& fragment_source)
const
315 if (vertex_source.empty() && fragment_source.empty())
318 GLuint program_id = glCreateProgram();
319 GLuint vertex_shader_id = 0;
320 GLuint fragment_shader_id = 0;
322 if (!vertex_source.empty())
324 GLuint vertex_shader_id = createShader(GL_VERTEX_SHADER, vertex_source);
325 glAttachShader(program_id, vertex_shader_id);
328 if (!fragment_source.empty())
330 GLuint fragment_shader_id = createShader(GL_FRAGMENT_SHADER, fragment_source);
331 glAttachShader(program_id, fragment_shader_id);
334 glLinkProgram(program_id);
337 GLint result = GL_FALSE;
338 GLint info_log_length;
339 glGetProgramiv(program_id, GL_LINK_STATUS, &result);
340 glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
341 if (info_log_length > 0)
343 vector<char> program_error_message(info_log_length + 1);
344 glGetProgramInfoLog(program_id, info_log_length,
nullptr, &program_error_message[0]);
345 std::size_t l = strnlen(&program_error_message[0], program_error_message.size());
347 RCLCPP_ERROR(
moveit::getLogger(
"moveit.ros.gl_renderer"),
"%s\n", &program_error_message[0]);
350 if (vertex_shader_id)
351 glDeleteShader(vertex_shader_id);
353 if (fragment_shader_id)
354 glDeleteShader(fragment_shader_id);
359map<std::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::s_context;
360std::mutex mesh_filter::GLRenderer::s_context_lock;
361bool mesh_filter::GLRenderer::s_glut_initialized =
false;
365void nullDisplayFunction()
370void mesh_filter::GLRenderer::createGLContext()
372 std::unique_lock<std::mutex> _(s_context_lock);
373 if (!s_glut_initialized)
380 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
381 s_glut_initialized =
true;
385 std::thread::id thread_id = std::this_thread::get_id();
386 map<std::thread::id, pair<unsigned, GLuint> >::iterator context_it = s_context.find(thread_id);
388 if (context_it == s_context.end())
390 s_context.insert({ thread_id, std::pair<unsigned, GLuint>(1, 0) });
392 glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
393 glutInitWindowSize(1, 1);
394 GLuint window_id = glutCreateWindow(
"mesh_filter");
395 glutDisplayFunc(nullDisplayFunction);
397 GLenum err = glewInit();
400 stringstream error_stream;
401 error_stream <<
"Unable to initialize GLEW: " << glewGetErrorString(err);
403 throw(runtime_error(error_stream.str()));
408 for (
int i = 0; i < 10; ++i)
411 s_context.at(thread_id) = std::pair<unsigned, GLuint>(1, window_id);
414 ++(context_it->second.first);
417void mesh_filter::GLRenderer::deleteGLContext()
419 std::unique_lock<std::mutex> _(s_context_lock);
420 std::thread::id thread_id = std::this_thread::get_id();
421 map<std::thread::id, pair<unsigned, GLuint> >::iterator context_it = s_context.find(thread_id);
422 if (context_it == s_context.end())
424 stringstream error_msg;
425 error_msg <<
"No OpenGL context exists for Thread " << thread_id;
426 throw runtime_error(error_msg.str());
429 if (--(context_it->second.first) == 0)
431 glutDestroyWindow(context_it->second.second);
432 s_context.erase(context_it);
const double & getFarClippingDistance() const
returns the distance of the far clipping plane in meters
void getDepthBuffer(float *buffer) const
retrieves the depth buffer from OpenGL
void setBufferSize(unsigned width, unsigned height)
set the size of frame buffers
void callList(GLuint list) const
executes a OpenGL list
GLuint getColorTexture() const
returns the handle of the color buffer as an OpenGL texture object
GLuint getDepthTexture() const
returns the handle of the depth buffer as an OpenGL texture object
unsigned getWidth() const
returns the width of the frame buffer objectsin pixels
void end() const
finalizes the frame buffers after rendering and/or manipulating
void begin() const
initializes the frame buffers for rendering and or manipulating
GLuint setShadersFromFile(const std::string &vertex_filename, const std::string &fragment_filename)
loads, compiles, links and adds GLSL shaders from files to the current OpenGL context.
void setClippingRange(double near, double far)
sets the near and far clipping plane distances in meters
void getColorBuffer(unsigned char *buffer) const
retrieves the color buffer from OpenGL
unsigned getHeight() const
returns the height of the frame buffer objects in pixels
GLRenderer(unsigned width, unsigned height, double near=0.1, double far=10.0)
constructs the frame buffer object in a new OpenGL context.
const double & getNearClippingDistance() const
returns the distance of the near clipping plane in meters
GLuint setShadersFromString(const std::string &vertex_shader, const std::string &fragment_shader)
loads, compiles, links and adds GLSL shaders from string to the current OpenGL context.
~GLRenderer()
destructor, destroys frame buffer objects and OpenGL context
void setCameraParameters(double fx, double fy, double cx, double cy)
set the camera parameters
const GLuint & getProgramID() const
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.