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 <iostream>
51 #include <boost/thread.hpp>
52 #include <ros/console.h>
53 
54 using namespace std;
55 
56 mesh_filter::GLRenderer::GLRenderer(unsigned width, unsigned height, float near, float far)
57  : width_(width)
58  , height_(height)
59  , fbo_id_(0)
60  , rbo_id_(0)
61  , rgb_id_(0)
62  , depth_id_(0)
63  , program_(0)
64  , near_(near)
65  , far_(far)
66  , fx_(width >> 1) // 90 degree wide angle
67  , fy_(fx_)
68  , cx_(width >> 1)
69  , cy_(height >> 1)
70 {
73 }
74 
76 {
77  if (program_)
78  glDeleteProgram(program_);
79 
82 }
83 
84 void mesh_filter::GLRenderer::setBufferSize(unsigned width, unsigned height)
85 {
86  if (width_ != width || height_ != height)
87  {
88  width_ = width;
89  height_ = height;
92  }
93 }
94 
95 void mesh_filter::GLRenderer::setClippingRange(float near, float far)
96 {
97  if (near_ <= 0)
98  throw runtime_error("near clipping plane distance needs to be larger than 0");
99  if (far_ <= near_)
100  throw runtime_error("far clipping plane needs to be larger than near clipping plane distance");
101  near_ = near;
102  far_ = far;
103 }
104 
105 void mesh_filter::GLRenderer::setCameraParameters(float fx, float fy, float cx, float cy)
106 {
107  fx_ = fx;
108  fy_ = fy;
109  cx_ = cx;
110  cy_ = cy;
111 }
112 
114 {
115  float left = near_ * -cx_ / fx_;
116  float right = near_ * (width_ - cx_) / fx_;
117  float top = near_ * cy_ / fy_;
118  float bottom = near_ * (cy_ - height_) / fy_;
119 
120  glMatrixMode(GL_PROJECTION);
121  glLoadIdentity();
122  glFrustum(left, right, bottom, top, near_, far_);
123 
124  glMatrixMode(GL_MODELVIEW);
125  glLoadIdentity();
126  gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
127 }
128 
130 {
131  glGenTextures(1, &rgb_id_);
132  glBindTexture(GL_TEXTURE_2D, rgb_id_);
133  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
134  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
135  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
136  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
137  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
138  glBindTexture(GL_TEXTURE_2D, 0);
139 
140  glGenTextures(1, &depth_id_);
141  glBindTexture(GL_TEXTURE_2D, depth_id_);
142  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
143  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
144  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
145  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
146  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147  glBindTexture(GL_TEXTURE_2D, 0);
148 
149  glGenFramebuffers(1, &fbo_id_);
150  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
151  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);
152 
153  glGenRenderbuffers(1, &rbo_id_);
154  glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
155  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
156  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
157  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
158  glBindRenderbuffer(GL_RENDERBUFFER, 0);
159 
160  GLenum DrawBuffers[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
161  glDrawBuffers(2, DrawBuffers);
162 
163  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
164 
165  if (status != GL_FRAMEBUFFER_COMPLETE) // If the frame buffer does not report back as complete
166  throw runtime_error("Couldn't create frame buffer");
167 
168  glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer
169 }
170 
172 {
173  if (rbo_id_)
174  glDeleteRenderbuffers(1, &rbo_id_);
175  if (fbo_id_)
176  glDeleteFramebuffers(1, &fbo_id_);
177  if (depth_id_)
178  glDeleteTextures(1, &depth_id_);
179  if (rgb_id_)
180  glDeleteTextures(1, &rgb_id_);
181 
182  rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
183 }
184 
186 {
187  glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);
188  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
189  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
190  glViewport(0, 0, width_, height_);
191  glUseProgram(program_);
193 }
194 
195 void mesh_filter::GLRenderer::callList(GLuint list) const
196 {
197  begin();
198  glCallList(list);
199  end();
200 }
201 
203 {
204  glFlush();
205  glPopAttrib();
206  glBindFramebuffer(GL_FRAMEBUFFER, 0);
207 }
208 
209 void mesh_filter::GLRenderer::getColorBuffer(unsigned char* buffer) const
210 {
211  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
212  glBindTexture(GL_TEXTURE_2D, rgb_id_);
213  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
214  glBindFramebuffer(GL_FRAMEBUFFER, 0);
215 }
216 
218 {
219  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
220  glBindTexture(GL_TEXTURE_2D, depth_id_);
221  glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
222  glBindFramebuffer(GL_FRAMEBUFFER, 0);
223 }
224 
225 GLuint mesh_filter::GLRenderer::setShadersFromFile(const string& vertex_filename, const string& fragment_filename)
226 {
227  if (program_)
228  glDeleteProgram(program_);
229 
230  string vertex_source, fragment_source;
231  readShaderCodeFromFile(vertex_filename, vertex_source);
232  readShaderCodeFromFile(fragment_filename, fragment_source);
233 
234  program_ = loadShaders(vertex_source, fragment_source);
235  return program_;
236 }
237 
238 GLuint mesh_filter::GLRenderer::setShadersFromString(const string& vertex_source, const string& fragment_source)
239 {
240  program_ = loadShaders(vertex_source, fragment_source);
241  return program_;
242 }
243 
245 {
246  return program_;
247 }
248 
250 {
251  return near_;
252 }
253 
255 {
256  return far_;
257 }
258 
259 GLuint mesh_filter::GLRenderer::createShader(GLuint shaderType, const string& ShaderCode) const
260 {
261  GLuint ShaderID = glCreateShader(shaderType);
262 
263  // Compile Shader
264  char const* SourcePointer = ShaderCode.c_str();
265  glShaderSource(ShaderID, 1, &SourcePointer, NULL);
266  glCompileShader(ShaderID);
267 
268  // Check Shader
269  GLint Result = GL_FALSE;
270  glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &Result);
271  if (Result != GL_TRUE)
272  {
273  int InfoLogLength;
274  glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
275  if (InfoLogLength > 0)
276  {
277  vector<char> ShaderErrorMessage(InfoLogLength + 1);
278  glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, &ShaderErrorMessage[0]);
279  stringstream errorStream;
280  errorStream << "Could not compile shader: " << (const char*)&ShaderErrorMessage[0];
281 
282  glDeleteShader(ShaderID);
283  throw runtime_error(errorStream.str());
284  }
285  }
286  return ShaderID;
287 }
288 
289 void mesh_filter::GLRenderer::readShaderCodeFromFile(const string& filename, string& shader) const
290 {
291  if (filename.empty())
292  shader = "";
293  else
294  {
295  string ShaderCode;
296  fstream ShaderFile(filename.c_str(), ios::in);
297  if (ShaderFile.is_open())
298  {
299  stringstream buffer;
300  buffer << ShaderFile.rdbuf();
301  shader = buffer.str();
302  }
303  else
304  {
305  stringstream errorStream;
306  errorStream << "Could not open shader code in file \"" << filename << "\"";
307  throw runtime_error(errorStream.str());
308  }
309  }
310 }
311 
312 GLuint mesh_filter::GLRenderer::loadShaders(const string& vertex_source, const string& fragment_source) const
313 {
314  if (vertex_source.empty() && fragment_source.empty())
315  return 0;
316 
317  GLuint ProgramID = glCreateProgram();
318  GLuint VertexShaderID = 0;
319  GLuint FragmentShaderID = 0;
320 
321  if (!vertex_source.empty())
322  {
323  GLuint VertexShaderID = createShader(GL_VERTEX_SHADER, vertex_source);
324  glAttachShader(ProgramID, VertexShaderID);
325  }
326 
327  if (!fragment_source.empty())
328  {
329  GLuint FragmentShaderID = createShader(GL_FRAGMENT_SHADER, fragment_source);
330  glAttachShader(ProgramID, FragmentShaderID);
331  }
332 
333  glLinkProgram(ProgramID);
334 
335  // Check the program
336  GLint Result = GL_FALSE;
337  GLint InfoLogLength;
338  glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
339  glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
340  if (InfoLogLength > 0)
341  {
342  vector<char> ProgramErrorMessage(InfoLogLength + 1);
343  glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
344  std::size_t l = strnlen(&ProgramErrorMessage[0], ProgramErrorMessage.size());
345  if (l > 0)
346  ROS_ERROR("%s\n", &ProgramErrorMessage[0]);
347  }
348 
349  if (VertexShaderID)
350  glDeleteShader(VertexShaderID);
351 
352  if (FragmentShaderID)
353  glDeleteShader(FragmentShaderID);
354 
355  return ProgramID;
356 }
357 
358 map<boost::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::context_;
361 
362 namespace
363 {
364 void nullDisplayFunction(){};
365 }
366 
368 {
369  boost::mutex::scoped_lock _(context_lock_);
370  if (!glutInitialized_)
371  {
372  char buffer[1];
373  char* args = buffer;
374  int n = 1;
375 
376  glutInit(&n, &args);
377  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
378  glutInitialized_ = true;
379  }
380 
381  // check if our thread is initialized
382  boost::thread::id threadID = boost::this_thread::get_id();
383  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
384 
385  if (contextIt == context_.end())
386  {
387  context_[threadID] = std::pair<unsigned, GLuint>(1, 0);
388  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
389 
390  glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
391  glutInitWindowSize(1, 1);
392  GLuint window_id = glutCreateWindow("mesh_filter");
393  glutDisplayFunc(nullDisplayFunction);
394 
395  GLenum err = glewInit();
396  if (GLEW_OK != err)
397  {
398  stringstream errorStream;
399  errorStream << "Unable to initialize GLEW: " << glewGetErrorString(err);
400 
401  throw(runtime_error(errorStream.str()));
402  }
403  glutIconifyWindow();
404  glutHideWindow();
405 
406  for (int i = 0; i < 10; ++i)
407  glutMainLoopEvent();
408 
409  context_[threadID] = std::pair<unsigned, GLuint>(1, window_id);
410  }
411  else
412  ++(contextIt->second.first);
413 }
414 
416 {
417  boost::mutex::scoped_lock _(context_lock_);
418  boost::thread::id threadID = boost::this_thread::get_id();
419  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
420  if (contextIt == context_.end())
421  {
422  stringstream errorMsg;
423  errorMsg << "No OpenGL context exists for Thread " << threadID;
424  throw runtime_error(errorMsg.str());
425  }
426 
427  if (--(contextIt->second.first) == 0)
428  {
429  glutDestroyWindow(contextIt->second.second);
430  context_.erase(contextIt);
431  }
432 }
433 
435 {
436  return rgb_id_;
437 }
438 
440 {
441  return depth_id_;
442 }
443 
444 const unsigned mesh_filter::GLRenderer::getWidth() const
445 {
446  return width_;
447 }
448 
450 {
451  return height_;
452 }
void getDepthBuffer(float *buffer) const
retrieves the depth buffer from OpenGL
const GLuint & getProgramID() const
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.
GLuint rgb_id_
handle to color buffer
Definition: gl_renderer.h:271
float far_
distance of far clipping plane in meters
Definition: gl_renderer.h:283
float fy_
focal length in y-direction of camera in pixels
Definition: gl_renderer.h:289
static bool glutInitialized_
Definition: gl_renderer.h:303
GLuint rbo_id_
handle to render buffer object
Definition: gl_renderer.h:268
void callList(GLuint list) const
executes a OpenGL list
unsigned height_
height of frame buffer objects in pixels
Definition: gl_renderer.h:262
const float & getFarClippingDistance() const
returns the distance of the far 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.
void deleteFrameBuffers()
deletes the frame buffer objects
const unsigned getWidth() const
returns the width of the frame buffer objectsin pixels
const float & getNearClippingDistance() const
returns the distance of the near clipping plane in meters
GLuint fbo_id_
handle to frame buffer object
Definition: gl_renderer.h:265
void initFrameBuffers()
initializes the frame buffer objects
float cx_
x-coordinate of principal point of camera in pixels
Definition: gl_renderer.h:292
GLuint depth_id_
handle to depth buffer
Definition: gl_renderer.h:274
static void deleteGLContext()
deletes OpenGL context for the current thread
float near_
distance of near clipping plane in meters
Definition: gl_renderer.h:280
GLuint getColorTexture() const
returns the handle of the color buffer as an OpenGL texture object
void end() const
finalizes the frame buffers after rendering and/or manipulating
~GLRenderer()
destructor, destroys frame buffer objects and OpenGL context
Definition: gl_renderer.cpp:75
GLuint createShader(GLuint shaderID, const std::string &source) const
create a OpenGL shader object from the shader source code
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.
static void createGLContext()
create the OpenGL context if required. Only on context is created for each thread ...
void setCameraParameters() const
sets the OpenGL camera parameters
void readShaderCodeFromFile(const std::string &filename, std::string &source) const
reads shader source code from file to a string
void begin() const
initializes the frame buffers for rendering and or manipulating
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:56
static boost::mutex context_lock_
Definition: gl_renderer.h:301
static std::map< boost::thread::id, std::pair< unsigned, GLuint > > context_
map from thread id to OpenGL context
Definition: gl_renderer.h:298
const unsigned getHeight() const
returns the height of the frame buffer objects in pixels
float cy_
y-coordinate of principal point of camera in pixels
Definition: gl_renderer.h:295
GLuint getDepthTexture() const
returns the handle of the depth buffer as an OpenGL texture object
GLuint program_
handle to program that is currently used
Definition: gl_renderer.h:277
void setBufferSize(unsigned width, unsigned height)
set the size of fram buffers
Definition: gl_renderer.cpp:84
float fx_
focal length in x-direction of camera in pixels
Definition: gl_renderer.h:286
void setClippingRange(float near, float far)
sets the near and far clipping plane distances in meters
Definition: gl_renderer.cpp:95
unsigned width_
width of frame buffer objects in pixels
Definition: gl_renderer.h:259
#define ROS_ERROR(...)
void getColorBuffer(unsigned char *buffer) const
retrieves the color buffer from OpenGL


perception
Author(s): Ioan Sucan , Jon Binney , Suat Gedikli
autogenerated on Wed Jul 18 2018 02:48:55