SLProject  4.3.020
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SENSGLTextureReader.cpp
Go to the documentation of this file.
1 #include "SENSGLTextureReader.h"
2 
3 #include <SENS.h>
4 #include <Utils.h>
5 
6 //include opengl plattform dependent
7 #if defined(SENS_OS_MACIOS)
8 # include <OpenGLES/ES3/gl.h>
9 # include <OpenGLES/ES3/glext.h>
10 #elif defined(SENS_OS_MACOS)
11 # include <GL/gl3w.h>
12 #elif defined(SENS_OS_ANDROID)
13 //https://stackoverflow.com/questions/31003863/gles-3-0-including-gl2ext-h
14 # include <GLES3/gl3.h>
15 # include <GLES2/gl2ext.h>
16 # ifndef GL_CLAMP_TO_BORDER //see #define GL_CLAMP_TO_BORDER_OES 0x812D in gl2ext.h
17 # define GL_CLAMP_TO_BORDER GL_CLAMP_TO_BORDER_OES
18 # endif
19 #elif defined(SENS_OS_WINDOWS)
20 # include <GL/gl3w.h>
21 #elif defined(SENS_OS_LINUX)
22 # include <GL/gl3w.h>
23 #else
24 # error "SL has not been ported to this OS"
25 #endif
26 
27 #ifndef GET_GL_ERROR
28 # if defined(DEBUG) || defined(_DEBUG)
29 # define GET_GL_ERROR SENSGLTextureReader::getGLError((const char*)__FILE__, __LINE__, false)
30 # else
31 # define GET_GL_ERROR
32 # endif
33 #endif
34 
35 //-----------------------------------------------------------------------------
36 std::vector<std::string> SENSGLTextureReader::_errors;
37 
38 //-----------------------------------------------------------------------------
39 //! Returns the OpenGL Shading Language version number as a string.
40 /*! The string returned by glGetString can contain additional vendor
41  information such as the build number and the brand name.
42  For the shading language string "Nvidia GLSL 4.5" the function returns "450"
43  */
44 std::string glSLVersionNO()
45 {
46  std::string versionStr = std::string((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
47  size_t dotPos = versionStr.find('.');
48  char NO[4];
49  NO[0] = versionStr[dotPos - 1];
50  NO[1] = versionStr[dotPos + 1];
51  NO[2] = '0';
52  NO[3] = 0;
53  return std::string(NO);
54 }
55 
56 //-----------------------------------------------------------------------------
57 GLuint buildShaderFromSource(std::string source, GLenum shaderType, bool isGlExternalTexture)
58 {
59  // Compile Shader code
60  GLuint shaderHandle = glCreateShader(shaderType);
61  std::string version;
62 
63  std::string versionGLSL = glSLVersionNO();
64  std::string glVersion = std::string((const char*)glGetString(GL_VERSION));
65  bool glIsES3 = (glVersion.find("OpenGL ES 3") != string::npos);
66  std::string srcVersion = "#version " + versionGLSL;
67  if (glIsES3)
68  srcVersion += " es";
69  srcVersion += "\n";
70 
71  std::string completeSrc = srcVersion + source;
72 
73  if (isGlExternalTexture)
74  {
75  Utils::replaceString(completeSrc, "#include extension", "#extension GL_OES_EGL_image_external_essl3 : enable");
76  Utils::replaceString(completeSrc, "#include sampler", "uniform samplerExternalOES");
77  }
78  else
79  {
80  Utils::replaceString(completeSrc, "#include extension", "");
81  Utils::replaceString(completeSrc, "#include sampler", "uniform sampler2D");
82  }
83 
84  const char* src = completeSrc.c_str();
85 
86  glShaderSource(shaderHandle, 1, &src, nullptr);
87  glCompileShader(shaderHandle);
88 
89  // Check compile success
90  GLint compileSuccess;
91  glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
92 
93  if (!compileSuccess)
94  {
95  GLint logSize = 0;
96  glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, &logSize);
97 
98  GLchar* log = new GLchar[logSize];
99 
100  glGetShaderInfoLog(shaderHandle, logSize, nullptr, log);
101 
102  Utils::log("Application", "Cannot compile shader %s", log);
103  Utils::log("Application", "%s", src);
104  exit(1);
105  }
106  return shaderHandle;
107 }
108 
109 SENSGLTextureReader::SENSGLTextureReader(unsigned int textureId, bool isGlTextureExternal, int targetWidth, int targetHeight)
110  : _extTextureId(textureId),
111  _isGlTextureExternal(isGlTextureExternal),
112  _targetWidth(targetWidth),
113  _targetHeight(targetHeight)
114 {
115  initGl();
116 }
117 
119 {
120  glDeleteTextures(1, &_targetTex);
121  glDeleteFramebuffers(1, &_fbo);
122  glDeleteVertexArrays(1, &_VAO);
123  glDeleteBuffers(1, &_VBO);
124  glDeleteBuffers(1, &_EBO);
125  glDeleteProgram(_prog);
126 }
127 
129 {
130  //-----------------------------------------------------------------------------
131  //store old gl state
132  GLint lastFBO = -1;
133  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lastFBO);
134  GLint lastTex = -1;
135  glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTex);
136 
137  //-----------------------------------------------------------------------------
138  //setup shader program
139  static std::string vertexShSrc =
140  "#ifdef GL_ES\n"
141  " precision highp float;\n"
142  "#endif\n"
143  "\n"
144  "layout (location = 0) in vec2 aPos;\n"
145  "layout (location = 1) in vec2 aTexCoords;\n"
146  "\n"
147  "out vec2 TexCoords;\n"
148  "\n"
149  "void main()\n"
150  "{\n"
151  " gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n"
152  " TexCoords = aTexCoords;\n"
153  "}\n";
154 
155  static std::string fragShSrc =
156  "#include extension\n"
157  "#ifdef GL_ES\n"
158  " precision highp float;\n"
159  "#endif\n"
160  "\n"
161  "out vec4 FragColor;\n"
162  "\n"
163  "in vec2 TexCoords;\n"
164  "\n"
165  "#include sampler texture0;\n"
166  "\n"
167  "void main()\n"
168  "{\n"
169  " //ATTENTION: order is changed to bgr\n"
170  " FragColor = texture(texture0, vec2(TexCoords.x, TexCoords.y)).bgra;\n"
171  "}\n";
172 
173  GLuint vertexSh = buildShaderFromSource(vertexShSrc, GL_VERTEX_SHADER, _isGlTextureExternal);
174  GLuint fragSh = buildShaderFromSource(fragShSrc, GL_FRAGMENT_SHADER, _isGlTextureExternal);
175  _prog = glCreateProgram();
176  glAttachShader(_prog, vertexSh);
177  glAttachShader(_prog, fragSh);
178  glLinkProgram(_prog);
179  glDeleteShader(vertexSh);
180  glDeleteShader(fragSh);
181  GET_GL_ERROR;
182 
183  // clang-format off
184  //-----------------------------------------------------------------------------
185  //setup vertex array
186  float vertices[] = {
187  // positions // texture coords
188  1.0f, 1.0f, 1.0f, 1.0f, // top right
189  1.0f, -1.0f, 1.0f, 0.0f, // bottom right
190  -1.0f, -1.0f, 0.0f, 0.0f, // bottom left
191  -1.0f, 1.0f, 0.0f, 1.0f // top left
192  };
193  //ATTENTION: BE SURE ORDER INDICATES A FRONT FACING NORMAL
194  unsigned int indices[] = {
195  0, 3, 1, // first triangle
196  1, 3, 2 // second triangle
197  };
198  // clang-format on
199 
200  glGenVertexArrays(1, &_VAO);
201  glGenBuffers(1, &_VBO);
202  glGenBuffers(1, &_EBO);
203 
204  glBindVertexArray(_VAO);
205 
206  glBindBuffer(GL_ARRAY_BUFFER, _VBO);
207  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
208 
209  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);
210  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
211 
212  // position attribute
213  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
214  glEnableVertexAttribArray(0);
215  // texture coord attribute
216  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
217  glEnableVertexAttribArray(1);
218 
219  glBindBuffer(GL_ARRAY_BUFFER, 0);
220  glBindVertexArray(0);
221 
222  glGenFramebuffers(1, &_fbo);
223  glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
224  GET_GL_ERROR;
225 
226  //-----------------------------------------------------------------------------
227  //setup target texture
228  glGenTextures(1, &_targetTex);
229  glBindTexture(GL_TEXTURE_2D, _targetTex);
230  //TODO: GL_RGB??
231  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _targetWidth, _targetHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
232 
233  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
234  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
235 
236  //bind fbo to target texture
237  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _targetTex, 0);
238  GET_GL_ERROR;
239 
240  //test fbo status
241  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
242  if (status != GL_FRAMEBUFFER_COMPLETE)
243  Utils::log("SENSGLTextureReader", "failed to make complete framebuffer object %x", status);
244  GET_GL_ERROR;
245  //-----------------------------------------------------------------------------
246  //restore old gl state
247  glBindFramebuffer(GL_FRAMEBUFFER, lastFBO);
248  glBindTexture(GL_TEXTURE_2D, lastTex);
249 }
250 
252 {
253  //-----------------------------------------------------------------------------
254  //store old gl state
255  GLint lastFBO = -1;
256  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lastFBO);
257  GLint lastTex = -1;
258  glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTex);
259  //depth test
260  GLboolean lastDepthTestV;
261  glGetBooleanv(GL_DEPTH_TEST, &lastDepthTestV);
262  //stencil test
263  GLboolean lastStencilTestV;
264  glGetBooleanv(GL_STENCIL_TEST, &lastStencilTestV);
265  //viewport
266  GLint lastViewport[4];
267  glGetIntegerv(GL_VIEWPORT, lastViewport);
268 
269  //-----------------------------------------------------------------------------
270  glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
271  glViewport(0, 0, _targetWidth, _targetHeight);
272 
273  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
274  glClear(GL_COLOR_BUFFER_BIT);
275  if (lastDepthTestV)
276  glDisable(GL_DEPTH_TEST);
277  if (lastStencilTestV)
278  glDisable(GL_STENCIL_TEST);
279 
280  glBindTexture(GL_TEXTURE_2D, _extTextureId);
281 
282  glUseProgram(_prog);
283  glBindVertexArray(_VAO);
284  glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
285 
286  //read pixels from framebuffer
287  cv::Mat image = cv::Mat(_targetHeight, _targetWidth, CV_8UC4);
288  glReadPixels(0, 0, _targetWidth, _targetHeight, GL_RGBA, GL_UNSIGNED_BYTE, image.data);
289 
290  //-------------------------------------------------------------------
291  //restore old gl state
292  glUseProgram(0);
293  glBindFramebuffer(GL_FRAMEBUFFER, lastFBO);
294  glBindTexture(GL_TEXTURE_2D, lastTex);
295  glViewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3]);
296  if (lastDepthTestV)
297  glEnable(GL_DEPTH_TEST);
298  if (lastStencilTestV)
299  glEnable(GL_STENCIL_TEST);
300  GET_GL_ERROR;
301 
302  if (image.data)
303  return image;
304  else
305  return cv::Mat();
306 }
307 
308 //-----------------------------------------------------------------------------
309 void SENSGLTextureReader::getGLError(const char* file,
310  int line,
311  bool quit)
312 {
313  GLenum err;
314  if ((err = glGetError()) != GL_NO_ERROR)
315  {
316  std::string errStr;
317  switch (err)
318  {
319  case GL_INVALID_ENUM:
320  errStr = "GL_INVALID_ENUM";
321  break;
322  case GL_INVALID_VALUE:
323  errStr = "GL_INVALID_VALUE";
324  break;
325  case GL_INVALID_OPERATION:
326  errStr = "GL_INVALID_OPERATION";
327  break;
328  case GL_INVALID_FRAMEBUFFER_OPERATION:
329  errStr = "GL_INVALID_FRAMEBUFFER_OPERATION";
330  break;
331  case GL_OUT_OF_MEMORY:
332  errStr = "GL_OUT_OF_MEMORY";
333  break;
334  default:
335  errStr = "Unknown error";
336  }
337 
338  // Build error string as a concatenation of file, line & error
339  char sLine[32];
340  snprintf(sLine, sizeof(sLine), "%d", line);
341 
342  std::string newErr(file);
343  newErr += ": line:";
344  newErr += sLine;
345  newErr += ": ";
346  newErr += errStr;
347 
348  // Check if error exists already
349  bool errExists = std::find(_errors.begin(),
350  _errors.end(),
351  newErr) != _errors.end();
352  // Only print
353  if (!errExists)
354  {
355  _errors.push_back(newErr);
356  Utils::log("SENSGLTextureReader", "OpenGL Error in %s, line %d: %s\n", file, line, errStr.c_str());
357  }
358 
359  if (quit)
360  exit(1);
361  }
362 }
GLuint buildShaderFromSource(std::string source, GLenum shaderType, bool isGlExternalTexture)
#define GET_GL_ERROR
std::string glSLVersionNO()
Returns the OpenGL Shading Language version number as a string.
static void getGLError(const char *file, int line, bool quit)
Checks if an OpenGL error occurred.
SENSGLTextureReader(unsigned int textureId, bool isGlTextureExternal, int targetWidth, int targetHeight)
ATTENTION: make sure this constructor is called from gl thread.
static std::vector< std::string > _errors
vector for errors collected in getGLError
unsigned int _extTextureId
id of externally generated texture
void replaceString(string &source, const string &from, const string &to)
Replaces in the source string the from string by the to string.
Definition: Utils.cpp:170
void log(const char *tag, const char *format,...)
logs a formatted string platform independently
Definition: Utils.cpp:1100