00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <GL/glew.h>
00038 #ifdef __APPLE__
00039 #include <OpenGL/glu.h>
00040 #else
00041 #include <GL/glu.h>
00042 #endif
00043 #include <GL/glut.h>
00044 #include <GL/freeglut.h>
00045 #include <moveit/mesh_filter/gl_renderer.h>
00046 #include <sstream>
00047 #include <fstream>
00048 #include <stdexcept>
00049 #include <vector>
00050 #include <iostream>
00051 #include <boost/thread.hpp>
00052 #include <ros/console.h>
00053
00054 using namespace std;
00055
00056 mesh_filter::GLRenderer::GLRenderer(unsigned width, unsigned height, float near, float far)
00057 : width_(width)
00058 , height_(height)
00059 , fbo_id_(0)
00060 , rbo_id_(0)
00061 , rgb_id_(0)
00062 , depth_id_(0)
00063 , program_(0)
00064 , near_(near)
00065 , far_(far)
00066 , fx_(width >> 1)
00067 , fy_(fx_)
00068 , cx_(width >> 1)
00069 , cy_(height >> 1)
00070 {
00071 createGLContext();
00072 initFrameBuffers();
00073 }
00074
00075 mesh_filter::GLRenderer::~GLRenderer()
00076 {
00077 if (program_)
00078 glDeleteProgram(program_);
00079
00080 deleteFrameBuffers();
00081 deleteGLContext();
00082 }
00083
00084 void mesh_filter::GLRenderer::setBufferSize(unsigned width, unsigned height)
00085 {
00086 if (width_ != width || height_ != height)
00087 {
00088 width_ = width;
00089 height_ = height;
00090 deleteFrameBuffers();
00091 initFrameBuffers();
00092 }
00093 }
00094
00095 void mesh_filter::GLRenderer::setClippingRange(float near, float far)
00096 {
00097 if (near_ <= 0)
00098 throw runtime_error("near clipping plane distance needs to be larger than 0");
00099 if (far_ <= near_)
00100 throw runtime_error("far clipping plane needs to be larger than near clipping plane distance");
00101 near_ = near;
00102 far_ = far;
00103 }
00104
00105 void mesh_filter::GLRenderer::setCameraParameters(float fx, float fy, float cx, float cy)
00106 {
00107 fx_ = fx;
00108 fy_ = fy;
00109 cx_ = cx;
00110 cy_ = cy;
00111 }
00112
00113 void mesh_filter::GLRenderer::setCameraParameters() const
00114 {
00115 float left = near_ * -cx_ / fx_;
00116 float right = near_ * (width_ - cx_) / fx_;
00117 float top = near_ * cy_ / fy_;
00118 float bottom = near_ * (cy_ - height_) / fy_;
00119
00120 glMatrixMode(GL_PROJECTION);
00121 glLoadIdentity();
00122 glFrustum(left, right, bottom, top, near_, far_);
00123
00124 glMatrixMode(GL_MODELVIEW);
00125 glLoadIdentity();
00126 gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
00127 }
00128
00129 void mesh_filter::GLRenderer::initFrameBuffers()
00130 {
00131 glGenTextures(1, &rgb_id_);
00132 glBindTexture(GL_TEXTURE_2D, rgb_id_);
00133 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
00134 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00135 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00138 glBindTexture(GL_TEXTURE_2D, 0);
00139
00140 glGenTextures(1, &depth_id_);
00141 glBindTexture(GL_TEXTURE_2D, depth_id_);
00142 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
00143 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00144 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00145 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00146 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00147 glBindTexture(GL_TEXTURE_2D, 0);
00148
00149 glGenFramebuffers(1, &fbo_id_);
00150 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
00151 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);
00152
00153 glGenRenderbuffers(1, &rbo_id_);
00154 glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
00155 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
00156 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
00157 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
00158 glBindRenderbuffer(GL_RENDERBUFFER, 0);
00159
00160 GLenum DrawBuffers[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
00161 glDrawBuffers(2, DrawBuffers);
00162
00163 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
00164
00165 if (status != GL_FRAMEBUFFER_COMPLETE)
00166 throw runtime_error("Couldn't create frame buffer");
00167
00168 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00169 }
00170
00171 void mesh_filter::GLRenderer::deleteFrameBuffers()
00172 {
00173 if (rbo_id_)
00174 glDeleteRenderbuffers(1, &rbo_id_);
00175 if (fbo_id_)
00176 glDeleteFramebuffers(1, &fbo_id_);
00177 if (depth_id_)
00178 glDeleteTextures(1, &depth_id_);
00179 if (rgb_id_)
00180 glDeleteTextures(1, &rgb_id_);
00181
00182 rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
00183 }
00184
00185 void mesh_filter::GLRenderer::begin() const
00186 {
00187 glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);
00188 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
00189 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00190 glViewport(0, 0, width_, height_);
00191 glUseProgram(program_);
00192 setCameraParameters();
00193 }
00194
00195 void mesh_filter::GLRenderer::callList(GLuint list) const
00196 {
00197 begin();
00198 glCallList(list);
00199 end();
00200 }
00201
00202 void mesh_filter::GLRenderer::end() const
00203 {
00204 glFlush();
00205 glPopAttrib();
00206 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00207 }
00208
00209 void mesh_filter::GLRenderer::getColorBuffer(unsigned char* buffer) const
00210 {
00211 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
00212 glBindTexture(GL_TEXTURE_2D, rgb_id_);
00213 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
00214 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00215 }
00216
00217 void mesh_filter::GLRenderer::getDepthBuffer(float* buffer) const
00218 {
00219 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
00220 glBindTexture(GL_TEXTURE_2D, depth_id_);
00221 glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
00222 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00223 }
00224
00225 GLuint mesh_filter::GLRenderer::setShadersFromFile(const string& vertex_filename, const string& fragment_filename)
00226 {
00227 if (program_)
00228 glDeleteProgram(program_);
00229
00230 string vertex_source, fragment_source;
00231 readShaderCodeFromFile(vertex_filename, vertex_source);
00232 readShaderCodeFromFile(fragment_filename, fragment_source);
00233
00234 program_ = loadShaders(vertex_source, fragment_source);
00235 return program_;
00236 }
00237
00238 GLuint mesh_filter::GLRenderer::setShadersFromString(const string& vertex_source, const string& fragment_source)
00239 {
00240 program_ = loadShaders(vertex_source, fragment_source);
00241 return program_;
00242 }
00243
00244 const GLuint& mesh_filter::GLRenderer::getProgramID() const
00245 {
00246 return program_;
00247 }
00248
00249 const float& mesh_filter::GLRenderer::getNearClippingDistance() const
00250 {
00251 return near_;
00252 }
00253
00254 const float& mesh_filter::GLRenderer::getFarClippingDistance() const
00255 {
00256 return far_;
00257 }
00258
00259 GLuint mesh_filter::GLRenderer::createShader(GLuint shaderType, const string& ShaderCode) const
00260 {
00261 GLuint ShaderID = glCreateShader(shaderType);
00262
00263
00264 char const* SourcePointer = ShaderCode.c_str();
00265 glShaderSource(ShaderID, 1, &SourcePointer, NULL);
00266 glCompileShader(ShaderID);
00267
00268
00269 GLint Result = GL_FALSE;
00270 glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &Result);
00271 if (Result != GL_TRUE)
00272 {
00273 int InfoLogLength;
00274 glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
00275 if (InfoLogLength > 0)
00276 {
00277 vector<char> ShaderErrorMessage(InfoLogLength + 1);
00278 glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, &ShaderErrorMessage[0]);
00279 stringstream errorStream;
00280 errorStream << "Could not compile shader: " << (const char*)&ShaderErrorMessage[0];
00281
00282 glDeleteShader(ShaderID);
00283 throw runtime_error(errorStream.str());
00284 }
00285 }
00286 return ShaderID;
00287 }
00288
00289 void mesh_filter::GLRenderer::readShaderCodeFromFile(const string& filename, string& shader) const
00290 {
00291 if (filename.empty())
00292 shader = "";
00293 else
00294 {
00295 string ShaderCode;
00296 fstream ShaderFile(filename.c_str(), ios::in);
00297 if (ShaderFile.is_open())
00298 {
00299 stringstream buffer;
00300 buffer << ShaderFile.rdbuf();
00301 shader = buffer.str();
00302 }
00303 else
00304 {
00305 stringstream errorStream;
00306 errorStream << "Could not open shader code in file \"" << filename << "\"";
00307 throw runtime_error(errorStream.str());
00308 }
00309 }
00310 }
00311
00312 GLuint mesh_filter::GLRenderer::loadShaders(const string& vertex_source, const string& fragment_source) const
00313 {
00314 if (vertex_source.empty() && fragment_source.empty())
00315 return 0;
00316
00317 GLuint ProgramID = glCreateProgram();
00318 GLuint VertexShaderID = 0;
00319 GLuint FragmentShaderID = 0;
00320
00321 if (!vertex_source.empty())
00322 {
00323 GLuint VertexShaderID = createShader(GL_VERTEX_SHADER, vertex_source);
00324 glAttachShader(ProgramID, VertexShaderID);
00325 }
00326
00327 if (!fragment_source.empty())
00328 {
00329 GLuint FragmentShaderID = createShader(GL_FRAGMENT_SHADER, fragment_source);
00330 glAttachShader(ProgramID, FragmentShaderID);
00331 }
00332
00333 glLinkProgram(ProgramID);
00334
00335
00336 GLint Result = GL_FALSE;
00337 GLint InfoLogLength;
00338 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
00339 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
00340 if (InfoLogLength > 0)
00341 {
00342 vector<char> ProgramErrorMessage(InfoLogLength + 1);
00343 glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
00344 std::size_t l = strnlen(&ProgramErrorMessage[0], ProgramErrorMessage.size());
00345 if (l > 0)
00346 ROS_ERROR("%s\n", &ProgramErrorMessage[0]);
00347 }
00348
00349 if (VertexShaderID)
00350 glDeleteShader(VertexShaderID);
00351
00352 if (FragmentShaderID)
00353 glDeleteShader(FragmentShaderID);
00354
00355 return ProgramID;
00356 }
00357
00358 map<boost::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::context_;
00359 boost::mutex mesh_filter::GLRenderer::context_lock_;
00360 bool mesh_filter::GLRenderer::glutInitialized_ = false;
00361
00362 namespace
00363 {
00364 void nullDisplayFunction(){};
00365 }
00366
00367 void mesh_filter::GLRenderer::createGLContext()
00368 {
00369 boost::mutex::scoped_lock _(context_lock_);
00370 if (!glutInitialized_)
00371 {
00372 char buffer[1];
00373 char* args = buffer;
00374 int n = 1;
00375
00376 glutInit(&n, &args);
00377 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
00378 glutInitialized_ = true;
00379 }
00380
00381
00382 boost::thread::id threadID = boost::this_thread::get_id();
00383 map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
00384
00385 if (contextIt == context_.end())
00386 {
00387 context_[threadID] = std::pair<unsigned, GLuint>(1, 0);
00388 map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
00389
00390 glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
00391 glutInitWindowSize(1, 1);
00392 GLuint window_id = glutCreateWindow("mesh_filter");
00393 glutDisplayFunc(nullDisplayFunction);
00394
00395 GLenum err = glewInit();
00396 if (GLEW_OK != err)
00397 {
00398 stringstream errorStream;
00399 errorStream << "Unable to initialize GLEW: " << glewGetErrorString(err);
00400
00401 throw(runtime_error(errorStream.str()));
00402 }
00403 glutIconifyWindow();
00404 glutHideWindow();
00405
00406 for (int i = 0; i < 10; ++i)
00407 glutMainLoopEvent();
00408
00409 context_[threadID] = std::pair<unsigned, GLuint>(1, window_id);
00410 }
00411 else
00412 ++(contextIt->second.first);
00413 }
00414
00415 void mesh_filter::GLRenderer::deleteGLContext()
00416 {
00417 boost::mutex::scoped_lock _(context_lock_);
00418 boost::thread::id threadID = boost::this_thread::get_id();
00419 map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
00420 if (contextIt == context_.end())
00421 {
00422 stringstream errorMsg;
00423 errorMsg << "No OpenGL context exists for Thread " << threadID;
00424 throw runtime_error(errorMsg.str());
00425 }
00426
00427 if (--(contextIt->second.first) == 0)
00428 {
00429 glutDestroyWindow(contextIt->second.second);
00430 context_.erase(contextIt);
00431 }
00432 }
00433
00434 GLuint mesh_filter::GLRenderer::getColorTexture() const
00435 {
00436 return rgb_id_;
00437 }
00438
00439 GLuint mesh_filter::GLRenderer::getDepthTexture() const
00440 {
00441 return depth_id_;
00442 }
00443
00444 const unsigned mesh_filter::GLRenderer::getWidth() const
00445 {
00446 return width_;
00447 }
00448
00449 const unsigned mesh_filter::GLRenderer::getHeight() const
00450 {
00451 return height_;
00452 }