gl_renderer.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Suat Gedikli */
36 
37 #include <GL/glew.h>
38 #ifdef __APPLE__
39 #include <OpenGL/glu.h>
40 #else
41 #include <GL/glu.h>
42 #endif
43 #include <GL/glut.h>
44 #include <GL/freeglut.h>
46 #include <sstream>
47 #include <fstream>
48 #include <stdexcept>
49 #include <vector>
50 #include <ros/console.h>
51 
52 using namespace std;
53 
54 mesh_filter::GLRenderer::GLRenderer(unsigned width, unsigned height, float near, float far)
55  : width_(width)
56  , height_(height)
57  , fbo_id_(0)
58  , rbo_id_(0)
59  , rgb_id_(0)
60  , depth_id_(0)
61  , program_(0)
62  , near_(near)
63  , far_(far)
64  , fx_(width >> 1) // 90 degree wide angle
65  , fy_(fx_)
66  , cx_(width >> 1)
67  , cy_(height >> 1)
68 {
71 }
72 
74 {
75  glDeleteProgram(program_);
76  deleteFrameBuffers();
77  deleteGLContext();
78 }
79 
80 void mesh_filter::GLRenderer::setBufferSize(unsigned width, unsigned height)
81 {
82  if (width_ != width || height_ != height)
83  {
84  width_ = width;
85  height_ = height;
86  deleteFrameBuffers();
87  initFrameBuffers();
88  }
89 }
90 
91 void mesh_filter::GLRenderer::setClippingRange(float near, float far)
92 {
93  if (near_ <= 0)
94  throw runtime_error("near clipping plane distance needs to be larger than 0");
95  if (far_ <= near_)
96  throw runtime_error("far clipping plane needs to be larger than near clipping plane distance");
97  near_ = near;
98  far_ = far;
99 }
100 
101 void mesh_filter::GLRenderer::setCameraParameters(float fx, float fy, float cx, float cy)
102 {
103  fx_ = fx;
104  fy_ = fy;
105  cx_ = cx;
106  cy_ = cy;
107 }
108 
110 {
111  float left = near_ * -cx_ / fx_;
112  float right = near_ * (width_ - cx_) / fx_;
113  float top = near_ * cy_ / fy_;
114  float bottom = near_ * (cy_ - height_) / fy_;
115 
116  glMatrixMode(GL_PROJECTION);
117  glLoadIdentity();
118  glFrustum(left, right, bottom, top, near_, far_);
119 
120  glMatrixMode(GL_MODELVIEW);
121  glLoadIdentity();
122  gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
123 }
124 
126 {
127  glGenTextures(1, &rgb_id_);
128  glBindTexture(GL_TEXTURE_2D, rgb_id_);
129  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
130  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
131  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
132  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
133  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
134  glBindTexture(GL_TEXTURE_2D, 0);
135 
136  glGenTextures(1, &depth_id_);
137  glBindTexture(GL_TEXTURE_2D, depth_id_);
138  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
139  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
140  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
141  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
142  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
143  glBindTexture(GL_TEXTURE_2D, 0);
144 
145  glGenFramebuffers(1, &fbo_id_);
146  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
147  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);
148 
149  glGenRenderbuffers(1, &rbo_id_);
150  glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
151  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
152  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
153  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
154  glBindRenderbuffer(GL_RENDERBUFFER, 0);
155 
156  GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
157  glDrawBuffers(2, draw_buffers);
158 
159  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
160 
161  if (status != GL_FRAMEBUFFER_COMPLETE) // If the frame buffer does not report back as complete
162  throw runtime_error("Couldn't create frame buffer");
163 
164  glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer
165 }
166 
168 {
169  if (rbo_id_)
170  glDeleteRenderbuffers(1, &rbo_id_);
171  if (fbo_id_)
172  glDeleteFramebuffers(1, &fbo_id_);
173  if (depth_id_)
174  glDeleteTextures(1, &depth_id_);
175  if (rgb_id_)
176  glDeleteTextures(1, &rgb_id_);
177 
178  rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
179 }
180 
182 {
183  glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT | GL_PIXEL_MODE_BIT);
184  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
185  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
186  glViewport(0, 0, width_, height_);
187  glUseProgram(program_);
188  setCameraParameters();
189 }
190 
191 void mesh_filter::GLRenderer::callList(GLuint list) const
192 {
193  begin();
194  glCallList(list);
195  end();
196 }
197 
199 {
200  glFlush();
201  glPopAttrib();
202  glBindFramebuffer(GL_FRAMEBUFFER, 0);
203 }
204 
205 void mesh_filter::GLRenderer::getColorBuffer(unsigned char* buffer) const
206 {
207  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
208  glBindTexture(GL_TEXTURE_2D, rgb_id_);
209  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
210  glBindFramebuffer(GL_FRAMEBUFFER, 0);
211 }
212 
214 {
215  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
216  glBindTexture(GL_TEXTURE_2D, depth_id_);
217  glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
218  glBindFramebuffer(GL_FRAMEBUFFER, 0);
219 }
220 
221 GLuint mesh_filter::GLRenderer::setShadersFromFile(const string& vertex_filename, const string& fragment_filename)
222 {
223  if (program_)
224  glDeleteProgram(program_);
225 
226  string vertex_source, fragment_source;
227  readShaderCodeFromFile(vertex_filename, vertex_source);
228  readShaderCodeFromFile(fragment_filename, fragment_source);
229 
230  program_ = loadShaders(vertex_source, fragment_source);
231  return program_;
232 }
233 
234 GLuint mesh_filter::GLRenderer::setShadersFromString(const string& vertex_source, const string& fragment_source)
235 {
236  program_ = loadShaders(vertex_source, fragment_source);
237  return program_;
238 }
239 
241 {
242  return program_;
243 }
244 
246 {
247  return near_;
248 }
249 
251 {
252  return far_;
253 }
254 
255 GLuint mesh_filter::GLRenderer::createShader(GLuint shaderType, const string& ShaderCode) const
256 {
257  GLuint shader_id = glCreateShader(shaderType);
258 
259  // Compile Shader
260  char const* source_pointer = ShaderCode.c_str();
261  glShaderSource(shader_id, 1, &source_pointer, nullptr);
262  glCompileShader(shader_id);
263 
264  // Check Shader
265  GLint result = GL_FALSE;
266  glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result);
267  if (result != GL_TRUE)
268  {
269  int info_log_length;
270  glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
271  if (info_log_length > 0)
272  {
273  vector<char> shader_error_message(info_log_length + 1);
274  glGetShaderInfoLog(shader_id, info_log_length, nullptr, &shader_error_message[0]);
275  stringstream error_stream;
276  error_stream << "Could not compile shader: " << (const char*)&shader_error_message[0];
277 
278  glDeleteShader(shader_id);
279  throw runtime_error(error_stream.str());
280  }
281  }
282  return shader_id;
283 }
284 
285 void mesh_filter::GLRenderer::readShaderCodeFromFile(const string& filename, string& shader) const
286 {
287  if (filename.empty())
288  shader = "";
289  else
290  {
291  string shader_code;
292  fstream shader_file(filename.c_str(), ios::in);
293  if (shader_file.is_open())
294  {
295  stringstream buffer;
296  buffer << shader_file.rdbuf();
297  shader = buffer.str();
298  }
299  else
300  {
301  stringstream error_stream;
302  error_stream << "Could not open shader code in file \"" << filename << "\"";
303  throw runtime_error(error_stream.str());
304  }
305  }
306 }
307 
308 GLuint mesh_filter::GLRenderer::loadShaders(const string& vertex_source, const string& fragment_source) const
309 {
310  if (vertex_source.empty() && fragment_source.empty())
311  return 0;
312 
313  GLuint program_id = glCreateProgram();
314  GLuint vertex_shader_id = 0;
315  GLuint fragment_shader_id = 0;
316 
317  if (!vertex_source.empty())
318  {
319  GLuint vertex_shader_id = createShader(GL_VERTEX_SHADER, vertex_source);
320  glAttachShader(program_id, vertex_shader_id);
321  }
322 
323  if (!fragment_source.empty())
324  {
325  GLuint fragment_shader_id = createShader(GL_FRAGMENT_SHADER, fragment_source);
326  glAttachShader(program_id, fragment_shader_id);
327  }
328 
329  glLinkProgram(program_id);
330 
331  // Check the program
332  GLint result = GL_FALSE;
333  GLint info_log_length;
334  glGetProgramiv(program_id, GL_LINK_STATUS, &result);
335  glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
336  if (info_log_length > 0)
337  {
338  vector<char> program_error_message(info_log_length + 1);
339  glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error_message[0]);
340  std::size_t l = strnlen(&program_error_message[0], program_error_message.size());
341  if (l > 0)
342  ROS_ERROR("%s\n", &program_error_message[0]);
343  }
344 
345  if (vertex_shader_id)
346  glDeleteShader(vertex_shader_id);
347 
348  if (fragment_shader_id)
349  glDeleteShader(fragment_shader_id);
350 
351  return program_id;
352 }
353 
354 map<std::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::context_;
357 
358 namespace
359 {
360 void nullDisplayFunction(){};
361 }
362 
364 {
365  std::unique_lock<std::mutex> _(context_lock_);
366  if (!glutInitialized_)
367  {
368  char buffer[1];
369  char* args = buffer;
370  int n = 1;
371 
372  glutInit(&n, &args);
373  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
374  glutInitialized_ = true;
375  }
376 
377  // check if our thread is initialized
378  std::thread::id thread_id = std::this_thread::get_id();
379  map<std::thread::id, pair<unsigned, GLuint> >::iterator context_it = context_.find(thread_id);
380 
381  if (context_it == context_.end())
382  {
383  context_[thread_id] = std::pair<unsigned, GLuint>(1, 0);
384 
385  glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
386  glutInitWindowSize(1, 1);
387  GLuint window_id = glutCreateWindow("mesh_filter");
388  glutDisplayFunc(nullDisplayFunction);
389 
390  GLenum err = glewInit();
391  if (GLEW_OK != err)
392  {
393  stringstream error_stream;
394  error_stream << "Unable to initialize GLEW: " << glewGetErrorString(err);
395 
396  throw(runtime_error(error_stream.str()));
397  }
398  glutIconifyWindow();
399  glutHideWindow();
400 
401  for (int i = 0; i < 10; ++i)
402  glutMainLoopEvent();
403 
404  context_[thread_id] = std::pair<unsigned, GLuint>(1, window_id);
405  }
406  else
407  ++(context_it->second.first);
408 }
409 
411 {
412  std::unique_lock<std::mutex> _(context_lock_);
413  std::thread::id thread_id = std::this_thread::get_id();
414  map<std::thread::id, pair<unsigned, GLuint> >::iterator context_it = context_.find(thread_id);
415  if (context_it == context_.end())
416  {
417  stringstream error_msg;
418  error_msg << "No OpenGL context exists for Thread " << thread_id;
419  throw runtime_error(error_msg.str());
420  }
421 
422  if (--(context_it->second.first) == 0)
423  {
424  glutDestroyWindow(context_it->second.second);
425  context_.erase(context_it);
426  }
427 }
428 
430 {
431  return rgb_id_;
432 }
433 
435 {
436  return depth_id_;
437 }
438 
440 {
441  return width_;
442 }
443 
445 {
446  return height_;
447 }
mesh_filter::GLRenderer::createGLContext
static void createGLContext()
create the OpenGL context if required. Only on context is created for each thread
Definition: gl_renderer.cpp:363
mesh_filter::GLRenderer::getColorBuffer
void getColorBuffer(unsigned char *buffer) const
retrieves the color buffer from OpenGL
Definition: gl_renderer.cpp:205
mesh_filter::GLRenderer::initFrameBuffers
void initFrameBuffers()
initializes the frame buffer objects
Definition: gl_renderer.cpp:125
mesh_filter::GLRenderer::setClippingRange
void setClippingRange(float near, float far)
sets the near and far clipping plane distances in meters
Definition: gl_renderer.cpp:91
mesh_filter::GLRenderer::glutInitialized_
static bool glutInitialized_
Definition: gl_renderer.h:336
mesh_filter::GLRenderer::getDepthBuffer
void getDepthBuffer(float *buffer) const
retrieves the depth buffer from OpenGL
Definition: gl_renderer.cpp:213
mesh_filter::GLRenderer::callList
void callList(GLuint list) const
executes a OpenGL list
Definition: gl_renderer.cpp:191
mesh_filter::GLRenderer::getColorTexture
GLuint getColorTexture() const
returns the handle of the color buffer as an OpenGL texture object
Definition: gl_renderer.cpp:429
mesh_filter::GLRenderer::end
void end() const
finalizes the frame buffers after rendering and/or manipulating
Definition: gl_renderer.cpp:198
mesh_filter::GLRenderer::setShadersFromString
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.
Definition: gl_renderer.cpp:234
mesh_filter::GLRenderer::getDepthTexture
GLuint getDepthTexture() const
returns the handle of the depth buffer as an OpenGL texture object
Definition: gl_renderer.cpp:434
mesh_filter::GLRenderer::getNearClippingDistance
const float & getNearClippingDistance() const
returns the distance of the near clipping plane in meters
Definition: gl_renderer.cpp:245
mesh_filter::GLRenderer::setShadersFromFile
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.
Definition: gl_renderer.cpp:221
mesh_filter::GLRenderer::setBufferSize
void setBufferSize(unsigned width, unsigned height)
set the size of fram buffers
Definition: gl_renderer.cpp:80
console.h
mesh_filter::GLRenderer::deleteGLContext
static void deleteGLContext()
deletes OpenGL context for the current thread
Definition: gl_renderer.cpp:410
mesh_filter::GLRenderer::createShader
GLuint createShader(GLuint shaderID, const std::string &source) const
create a OpenGL shader object from the shader source code
Definition: gl_renderer.cpp:255
mesh_filter::GLRenderer::begin
void begin() const
initializes the frame buffers for rendering and or manipulating
Definition: gl_renderer.cpp:181
mesh_filter::GLRenderer::~GLRenderer
~GLRenderer()
destructor, destroys frame buffer objects and OpenGL context
Definition: gl_renderer.cpp:73
ROS_ERROR
#define ROS_ERROR(...)
mesh_filter::GLRenderer::readShaderCodeFromFile
void readShaderCodeFromFile(const std::string &filename, std::string &source) const
reads shader source code from file to a string
Definition: gl_renderer.cpp:285
mesh_filter::GLRenderer::GLRenderer
GLRenderer(unsigned width, unsigned height, float near=0.1, float far=10.0)
constructs the frame buffer object in a new OpenGL context.
Definition: gl_renderer.cpp:54
gl_renderer.h
mesh_filter::GLRenderer::deleteFrameBuffers
void deleteFrameBuffers()
deletes the frame buffer objects
Definition: gl_renderer.cpp:167
std
mesh_filter::GLRenderer::setCameraParameters
void setCameraParameters() const
sets the OpenGL camera parameters
Definition: gl_renderer.cpp:109
mesh_filter::GLRenderer::getWidth
unsigned getWidth() const
returns the width of the frame buffer objectsin pixels
Definition: gl_renderer.cpp:439
mesh_filter::GLRenderer::context_
static std::map< std::thread::id, std::pair< unsigned, GLuint > > context_
map from thread id to OpenGL context
Definition: gl_renderer.h:331
args
mesh_filter::GLRenderer::getFarClippingDistance
const float & getFarClippingDistance() const
returns the distance of the far clipping plane in meters
Definition: gl_renderer.cpp:250
mesh_filter::GLRenderer::loadShaders
GLuint loadShaders(const std::string &vertex_source, const std::string &fragment_source) const
Compiles, Links and adds the GLSL shaders from strings containing the source codes.
Definition: gl_renderer.cpp:308
mesh_filter::GLRenderer::getProgramID
const GLuint & getProgramID() const
Definition: gl_renderer.cpp:240
mesh_filter::GLRenderer::getHeight
unsigned getHeight() const
returns the height of the frame buffer objects in pixels
Definition: gl_renderer.cpp:444
mesh_filter::GLRenderer::context_lock_
static std::mutex context_lock_
Definition: gl_renderer.h:334


perception
Author(s): Ioan Sucan , Jon Binney , Suat Gedikli
autogenerated on Fri Jun 21 2024 02:26:30