MRPT  1.9.9
CTexturedObject.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "opengl-precomp.h" // Precompiled header
11 
15 #include <memory> // std::align
16 #include "opengl_internals.h"
17 
18 using namespace mrpt;
19 using namespace mrpt::opengl;
20 using namespace mrpt::poses;
21 using namespace mrpt::math;
22 using namespace std;
23 using mrpt::img::CImage;
24 
27 
28 // Whether to profile memory allocations:
29 //#define TEXTUREOBJ_PROFILE_MEM_ALLOC
30 
31 // Whether to use a memory pool for the texture buffer:
32 #define TEXTUREOBJ_USE_MEMPOOL
33 
34 // Data types for memory pooling CTexturedObject:
35 #ifdef TEXTUREOBJ_USE_MEMPOOL
36 
38 
39 struct CTexturedObject_MemPoolParams
40 {
41  /** size of the vector<unsigned char> */
42  size_t len;
43 
44  inline bool isSuitable(const CTexturedObject_MemPoolParams& req) const
45  {
46  return len == req.len;
47  }
48 };
50 {
51  vector<unsigned char> data;
52 };
53 
55  CTexturedObject_MemPoolParams, CTexturedObject_MemPoolData>;
56 #endif
57 
58 void CTexturedObject::assignImage(const CImage& img, const CImage& imgAlpha)
59 {
61 
63 
64  unloadTexture();
65 
66  // Make a copy:
67  m_textureImage = img;
68  m_textureImageAlpha = imgAlpha;
69 
70  m_enableTransparency = true;
71 
72  MRPT_END
73 }
74 
75 /*---------------------------------------------------------------
76  assignImage
77  ---------------------------------------------------------------*/
79 {
81 
83 
84  unloadTexture();
85 
86  // Make a copy:
87  m_textureImage = img;
88 
89  m_enableTransparency = false;
90 
91  MRPT_END
92 }
93 
94 /*---------------------------------------------------------------
95  assignImage
96  ---------------------------------------------------------------*/
98 {
100 
102 
103  unloadTexture();
104 
105  // Make a copy:
106  m_textureImage = std::move(img);
107  m_textureImageAlpha = std::move(imgAlpha);
108 
109  m_enableTransparency = true;
110 
111  MRPT_END
112 }
113 
114 /*---------------------------------------------------------------
115  assignImage
116  ---------------------------------------------------------------*/
118 {
119  MRPT_START
120 
122 
123  unloadTexture();
124 
125  // Make a copy:
126  m_textureImage = std::move(img);
127 
128  m_enableTransparency = false;
129 
130  MRPT_END
131 }
132 
133 // Auxiliary function for loadTextureInOpenGL(): reserve memory and return
134 // 16byte aligned starting point within it:
135 unsigned char* reserveDataBuffer(const size_t len, vector<unsigned char>& data)
136 {
137 #ifdef TEXTUREOBJ_USE_MEMPOOL
139  if (pool)
140  {
141  CTexturedObject_MemPoolParams mem_params;
142  mem_params.len = len;
143 
144  CTexturedObject_MemPoolData* mem_block =
145  pool->request_memory(mem_params);
146  if (mem_block)
147  {
148  // Recover the memory block via a swap:
149  data.swap(mem_block->data);
150  delete mem_block;
151  }
152  }
153 #endif
154  data.resize(len);
155  void* ptr = &data[0];
156  size_t space = len;
157  return reinterpret_cast<unsigned char*>(
158  std::align(16, 1 /*dummy size*/, ptr, space));
159 }
160 
161 /*---------------------------------------------------------------
162  loadTextureInOpenGL
163  ---------------------------------------------------------------*/
165 {
166 #if MRPT_HAS_OPENGL_GLUT
167  unsigned char* dataAligned = nullptr;
168  vector<unsigned char> data;
169 
170 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
171  static mrpt::system::CTimeLogger tim;
172 #endif
173 
174  try
175  {
176  if (m_texture_is_loaded)
177  {
178  glBindTexture(GL_TEXTURE_2D, m_glTextureName);
180  return;
181  }
182 
183  // Reserve the new one --------------------------
184  ASSERT_(m_textureImage.getPixelDepth() == mrpt::img::PixelDepth::D8U);
185 
186  // allocate texture names:
187  m_glTextureName = getNewTextureNumber();
188 
189  // select our current texture
190  glBindTexture(GL_TEXTURE_2D, m_glTextureName);
192 
193  // when texture area is small, linear interpolation. Default is
194  // GL_LINEAR_MIPMAP_NEAREST but we
195  // are not building mipmaps.
196  // See also:
197  // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=133116&page=1
200 
201  // when texture area is large, NEAREST: this is mainly thinking of
202  // rendering
203  // occupancy grid maps, such as we want those "big pixels" to be
204  // clearly visible ;-)
207 
208  // if wrap is true, the texture wraps over at the edges (repeat)
209  // ... false, the texture ends at the edges (clamp)
212 
215 
216  // Assure that the images do not overpass the maximum dimensions allowed
217  // by OpenGL:
218  // ------------------------------------------------------------------------------------
219  GLint texSize;
221  while (m_textureImage.getHeight() > (unsigned int)texSize ||
222  m_textureImage.getWidth() > (unsigned int)texSize)
223  {
224  m_textureImage =
225  m_textureImage.scaleHalf(mrpt::img::IMG_INTERP_LINEAR);
226  m_textureImageAlpha =
227  m_textureImageAlpha.scaleHalf(mrpt::img::IMG_INTERP_LINEAR);
228  }
229 
230  const int width = m_textureImage.getWidth();
231  const int height = m_textureImage.getHeight();
232 
233 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
234  {
235  const std::string sSec = mrpt::format(
236  "opengl_texture: load %ix%i %s %stransp", width, height,
237  m_textureImage.isColor() ? "RGB" : "BW",
238  m_enableTransparency ? "" : "no ");
239  tim.enter(sSec.c_str());
240  }
241 #endif
242 
243  r_width = width; // round2up( width );
244  r_height = height; // round2up( height );
245 
246  // Padding pixels:
247  m_pad_x_right = (r_width - width);
248  m_pad_y_bottom = (r_height - height);
249 
250  if (m_enableTransparency)
251  {
252  ASSERT_(!m_textureImageAlpha.isColor());
253  ASSERT_(
254  m_textureImageAlpha.getWidth() == m_textureImage.getWidth());
255  ASSERT_(
256  m_textureImageAlpha.getHeight() == m_textureImage.getHeight());
257  }
258 
259  if (m_textureImage.isColor())
260  {
261  // Color texture:
262  if (m_enableTransparency)
263  {
264 // Color texture WITH trans.
265 // --------------------------------------
266 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
267  const std::string sSec = mrpt::format(
268  "opengl_texture_alloc %ix%i (color,trans)", width, height);
269  tim.enter(sSec.c_str());
270 #endif
271 
272  dataAligned = reserveDataBuffer(height * width * 4 + 512, data);
273 
274 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
275  tim.leave(sSec.c_str());
276 #endif
277 
278  for (int y = 0; y < height; y++)
279  {
280  unsigned char* ptrSrcCol = m_textureImage(0, y, 0);
281  unsigned char* ptrSrcAlfa = m_textureImageAlpha(0, y);
282  unsigned char* ptr = dataAligned + y * width * 4;
283 
284  for (int x = 0; x < width; x++)
285  {
286  *ptr++ = *ptrSrcCol++;
287  *ptr++ = *ptrSrcCol++;
288  *ptr++ = *ptrSrcCol++;
289  *ptr++ = *ptrSrcAlfa++;
290  }
291  }
292 
293  // Prepare image data types:
294  const GLenum img_type = GL_UNSIGNED_BYTE;
295  // Reverse RGB <-> BGR order?
296  const bool is_RGB_order =
297  (m_textureImage.getChannelsOrder() == std::string("RGB"));
298  const GLenum img_format = (is_RGB_order ? GL_RGBA : GL_BGRA);
299 
300  // Send image data to OpenGL:
303  glTexImage2D(
304  GL_TEXTURE_2D, 0 /*level*/, 4 /* RGB components */, width,
305  height, 0 /*border*/, img_format, img_type, dataAligned);
307  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
308 
309  // No need to hide a fill border:
310  m_pad_x_right = 0;
311  m_pad_y_bottom = 0;
312 
313  } // End of color texture WITH trans.
314  else
315  {
316  // Color texture WITHOUT trans.
317  // --------------------------------------
318  // Prepare image data types:
319  const GLenum img_type = GL_UNSIGNED_BYTE;
320  const int nBytesPerPixel = m_textureImage.isColor() ? 3 : 1;
321  // Reverse RGB <-> BGR order?
322  const bool is_RGB_order =
323  (m_textureImage.getChannelsOrder() == std::string("RGB"));
324  const GLenum img_format = nBytesPerPixel == 3
325  ? (is_RGB_order ? GL_RGB : GL_BGR)
326  : GL_LUMINANCE;
327 
328  // Send image data to OpenGL:
332  m_textureImage.getRowStride() / nBytesPerPixel);
333  glTexImage2D(
334  GL_TEXTURE_2D, 0 /*level*/, 3 /* RGB components */, width,
335  height, 0 /*border*/, img_format, img_type,
336  m_textureImage.ptrLine<uint8_t>(0));
337  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
338 
339  // No need to hide a fill border:
340  m_pad_x_right = 0;
341  m_pad_y_bottom = 0;
342 
343  } // End of color texture WITHOUT trans.
344  }
345  else
346  {
347  // Gray-scale texture:
348  if (m_enableTransparency)
349  {
350 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
351  const std::string sSec = mrpt::format(
352  "opengl_texture_alloc %ix%i (gray,transp)", width, height);
353  tim.enter(sSec.c_str());
354 #endif
355 
356  dataAligned =
357  reserveDataBuffer(height * width * 2 + 1024, data);
358 
359 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
360  tim.leave(sSec.c_str());
361 #endif
362 
363  for (int y = 0; y < height; y++)
364  {
365  unsigned char* ptrSrcCol = m_textureImage(0, y);
366  unsigned char* ptrSrcAlfa = m_textureImageAlpha(0, y);
367  unsigned char* ptr = dataAligned + y * width * 2;
368  for (int x = 0; x < width; x++)
369  {
370  *ptr++ = *ptrSrcCol++;
371  *ptr++ = *ptrSrcAlfa++;
372  }
373  }
374 
375  // Prepare image data types:
376  const GLenum img_type = GL_UNSIGNED_BYTE;
377  const GLenum img_format = GL_LUMINANCE_ALPHA;
378 
379  // Send image data to OpenGL:
382  glTexImage2D(
383  GL_TEXTURE_2D, 0 /*level*/, 2 /* RGB components */, width,
384  height, 0 /*border*/, img_format, img_type, dataAligned);
386  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
387 
388  // No need to hide a fill border:
389  m_pad_x_right = 0;
390  m_pad_y_bottom = 0;
391 
392  } // End of gray-scale texture WITH trans.
393  else
394  {
395  // Prepare image data types:
396  const GLenum img_type = GL_UNSIGNED_BYTE;
397  const GLenum img_format = GL_LUMINANCE;
398 
399  // Send image data to OpenGL:
402  GL_UNPACK_ROW_LENGTH, m_textureImage.getRowStride());
403  glTexImage2D(
404  GL_TEXTURE_2D, 0 /*level*/, 1 /* RGB components */, width,
405  height, 0 /*border*/, img_format, img_type,
406  m_textureImage(0, 0));
408  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
409 
410  // No need to hide a fill border:
411  m_pad_x_right = 0;
412  m_pad_y_bottom = 0;
413 
414  } // End of gray-scale texture WITHOUT trans.
415  }
416 
417  m_texture_is_loaded = true;
418 
419 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
420  {
421  const std::string sSec = mrpt::format(
422  "opengl_texture: load %ix%i %s %stransp", width, height,
423  m_textureImage.isColor() ? "RGB" : "BW",
424  m_enableTransparency ? "" : "no ");
425  tim.leave(sSec.c_str());
426  }
427 #endif
428 
429 #ifdef TEXTUREOBJ_USE_MEMPOOL
430  // Before freeing the buffer in "data", donate my memory to the pool:
431  if (!data.empty())
432  {
434  if (pool)
435  {
436  CTexturedObject_MemPoolParams mem_params;
437  mem_params.len = data.size();
438 
439  auto* mem_block = new CTexturedObject_MemPoolData();
440  data.swap(mem_block->data);
441 
442  pool->dump_to_pool(mem_params, mem_block);
443  }
444  }
445 #endif
446  }
447  catch (exception& e)
448  {
450  format("m_glTextureName=%i\n%s", m_glTextureName, e.what()));
451  }
452  catch (...)
453  {
454  THROW_EXCEPTION("Runtime error!");
455  }
456 #endif
457 }
458 
459 /*---------------------------------------------------------------
460  ~CTexturedObject
461  ---------------------------------------------------------------*/
462 CTexturedObject::~CTexturedObject() { unloadTexture(); }
463 /*---------------------------------------------------------------
464  unloadTexture
465  ---------------------------------------------------------------*/
467 {
468  if (m_texture_is_loaded)
469  {
470  m_texture_is_loaded = false;
471  releaseTextureName(m_glTextureName);
472  m_glTextureName = 0;
473  }
474 }
475 
478 {
479  uint8_t ver = 0;
480 
481  out << ver;
482  out << m_enableTransparency;
483  out << m_textureImage;
484  if (m_enableTransparency) out << m_textureImageAlpha;
485 }
486 
488 {
489 #if MRPT_HAS_OPENGL_GLUT
490  render_pre();
491  if (glGetError() != GL_NO_ERROR)
492  std::cerr << "render_pre: Error" << std::endl;
493  render_texturedobj();
494  if (glGetError() != GL_NO_ERROR)
495  std::cerr << "render_texturedobj: Error" << std::endl;
496  render_post();
497  if (glGetError() != GL_NO_ERROR)
498  std::cerr << "render_post: Error" << std::endl;
499 #endif
500 }
501 
503 {
504 #if MRPT_HAS_OPENGL_GLUT
505  MRPT_START
508 
509  if (m_enableTransparency || m_color.A != 255)
510  {
514  }
515  else
516  {
519  }
520 
521  // This will load and/or select our texture, only if "m_texture_is_loaded"
522  // is false
523  loadTextureInOpenGL();
524  MRPT_END
525 #endif
526 }
527 
529 {
530 #if MRPT_HAS_OPENGL_GLUT
531  MRPT_START
532 
533  if (m_enableTransparency || m_color.A != 255)
534  {
537 
539 
542  }
543 
546 
547  MRPT_END
548 #endif
549 }
550 
553 {
554  uint8_t version;
555  in >> version;
556 
558 
559  switch (version)
560  {
561  case 0:
562  {
563  in >> m_enableTransparency;
564  in >> m_textureImage;
565  if (m_enableTransparency)
566  {
567  in >> m_textureImageAlpha;
568  assignImage(m_textureImage, m_textureImageAlpha);
569  }
570  else
571  {
572  assignImage(m_textureImage);
573  }
574  }
575  break;
576  default:
578  };
580 }
virtual void render_post() const
#define GL_BGR
Definition: glew.h:1262
void notifyChange() const
Must be called to notify that the object has changed (so, the display list must be updated) ...
#define MRPT_START
Definition: exceptions.h:241
#define GL_TEXTURE_WRAP_T
Definition: glew.h:669
#define GL_RGBA
Definition: glew.h:625
A base class for all OpenGL objects with loadable textures.
void render_dl() const override
Derived classes must implement this method to the render the object.
GLAPI void GLAPIENTRY glEnable(GLenum cap)
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
#define GL_ZERO
Definition: glew.h:283
void dump_to_pool(const DATA_PARAMS &params, POOLABLE_DATA *block)
Saves the passed data block (characterized by params) to the pool.
#define GL_BGRA
Definition: glew.h:8559
STL namespace.
#define GL_UNSIGNED_BYTE
Definition: glew.h:303
#define GL_LINEAR
Definition: glew.h:661
#define GL_ONE_MINUS_SRC_ALPHA
Definition: glew.h:288
#define GL_DEPTH_TEST
Definition: glew.h:402
POOLABLE_DATA * request_memory(const DATA_PARAMS &params)
Request a block of data which fulfils the size requirements stated in params.
GLenum GLsizei len
Definition: glext.h:4756
GLenum GLsizei width
Definition: glext.h:3535
void assignImage_fast(mrpt::img::CImage &img, mrpt::img::CImage &imgAlpha)
Similar to assignImage, but the passed images will be returned as empty: it avoids making a copy of t...
GLAPI void GLAPIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
unsigned char uint8_t
Definition: rptypes.h:44
A renderizable object suitable for rendering with OpenGL&#39;s display lists.
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:97
GLAPI void GLAPIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param)
A generic system for versatile memory pooling.
GLAPI void GLAPIENTRY glBindTexture(GLenum target, GLuint texture)
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
vector< unsigned char > data
mrpt::img::CImage CImage
Definition: utils/CImage.h:5
This base provides a set of functions for maths stuff.
IMPLEMENTS_VIRTUAL_SERIALIZABLE(CTexturedObject, CRenderizableDisplayList, mrpt::opengl) struct CTexturedObject_MemPoolParams
#define GL_ONE
Definition: glew.h:284
GLint GLvoid * img
Definition: glext.h:3769
#define GL_RGB
Definition: glew.h:624
#define GL_BLEND
Definition: glew.h:433
virtual void render_pre() const
#define GL_REPEAT
Definition: glew.h:671
GLsizei const GLchar ** string
Definition: glext.h:4116
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
unsigned char * reserveDataBuffer(const size_t len, vector< unsigned char > &data)
unsigned int GLenum
Definition: glew.h:207
#define GL_NEAREST
Definition: glew.h:660
#define GL_SRC_ALPHA
Definition: glew.h:287
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
#define GL_NO_ERROR
Definition: glew.h:327
#define GL_UNPACK_ROW_LENGTH
Definition: glew.h:482
#define GL_TEXTURE_MIN_FILTER
Definition: glew.h:667
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:53
#define GL_UNPACK_ALIGNMENT
Definition: glew.h:485
A versatile "profiler" that logs the time spent within each pair of calls to enter(X)-leave(X), among other stats.
#define GL_TEXTURE_MAG_FILTER
Definition: glew.h:666
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:16
void checkOpenGLError()
Checks glGetError and throws an exception if an error situation is found.
Definition: gl_utils.cpp:155
GLAPI void GLAPIENTRY glGetIntegerv(GLenum pname, GLint *params)
#define MRPT_END
Definition: exceptions.h:245
GLAPI GLenum GLAPIENTRY glGetError(void)
GLuint in
Definition: glext.h:7391
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
GLenum GLint GLint y
Definition: glext.h:3542
void readFromStreamTexturedObject(mrpt::serialization::CArchive &in)
int GLint
Definition: glew.h:210
#define GL_MAX_TEXTURE_SIZE
Definition: glew.h:511
GLenum GLint x
Definition: glext.h:3542
#define GL_LUMINANCE_ALPHA
Definition: glew.h:627
void loadTextureInOpenGL() const
VERY IMPORTANT: If you use a multi-thread application, you MUST call this from the same thread that w...
void assignImage(const mrpt::img::CImage &img, const mrpt::img::CImage &imgAlpha)
Assigns a texture and a transparency image, and enables transparency (If the images are not 2^N x 2^M...
GLenum GLsizei GLsizei height
Definition: glext.h:3558
GLAPI void GLAPIENTRY glDisable(GLenum cap)
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3550
GLAPI void GLAPIENTRY glPixelStorei(GLenum pname, GLint param)
void writeToStreamTexturedObject(mrpt::serialization::CArchive &out) const
#define GL_TEXTURE_WRAP_S
Definition: glew.h:668
void enter(const std::string_view &func_name)
Start of a named section.
#define GL_TEXTURE_2D
Definition: glew.h:7505
double leave(const std::string_view &func_name)
End of a named section.
#define GL_LUMINANCE
Definition: glew.h:626
GLAPI void GLAPIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:147
static CGenericMemoryPool< DATA_PARAMS, POOLABLE_DATA > * getInstance(const size_t max_pool_entries=5)
Construct-on-first-use (~singleton) pattern: Return the unique instance of this class for a given tem...



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019