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 = 0;
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  // Do nothing until we are assigned an image.
175  if (m_textureImage.isEmpty()) return;
176 
177  try
178  {
179  if (m_texture_is_loaded)
180  {
181  glBindTexture(GL_TEXTURE_2D, m_glTextureName);
183  return;
184  }
185 
186  // Reserve the new one --------------------------
187  ASSERT_(m_textureImage.getPixelDepth() == mrpt::img::PixelDepth::D8U);
188 
189  // allocate texture names:
190  m_glTextureName = getNewTextureNumber();
191 
192  // select our current texture
193  glBindTexture(GL_TEXTURE_2D, m_glTextureName);
195 
196  // when texture area is small, linear interpolation. Default is
197  // GL_LINEAR_MIPMAP_NEAREST but we
198  // are not building mipmaps.
199  // See also:
200  // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=133116&page=1
203 
204  // when texture area is large, NEAREST: this is mainly thinking of
205  // rendering
206  // occupancy grid maps, such as we want those "big pixels" to be
207  // clearly visible ;-)
210 
211  // if wrap is true, the texture wraps over at the edges (repeat)
212  // ... false, the texture ends at the edges (clamp)
215 
218 
219  // Assure that the images do not overpass the maximum dimensions allowed
220  // by OpenGL:
221  // ------------------------------------------------------------------------------------
222  GLint texSize;
224  while (m_textureImage.getHeight() > (unsigned int)texSize ||
225  m_textureImage.getWidth() > (unsigned int)texSize)
226  {
227  m_textureImage =
228  m_textureImage.scaleHalf(mrpt::img::IMG_INTERP_LINEAR);
229  m_textureImageAlpha =
230  m_textureImageAlpha.scaleHalf(mrpt::img::IMG_INTERP_LINEAR);
231  }
232 
233  const int width = m_textureImage.getWidth();
234  const int height = m_textureImage.getHeight();
235 
236 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
237  {
238  const std::string sSec = mrpt::format(
239  "opengl_texture: load %ix%i %s %stransp", width, height,
240  m_textureImage.isColor() ? "RGB" : "BW",
241  m_enableTransparency ? "" : "no ");
242  tim.enter(sSec.c_str());
243  }
244 #endif
245 
246  r_width = width; // round2up( width );
247  r_height = height; // round2up( height );
248 
249  // Padding pixels:
250  m_pad_x_right = (r_width - width);
251  m_pad_y_bottom = (r_height - height);
252 
253  if (m_enableTransparency)
254  {
255  ASSERT_(!m_textureImageAlpha.isColor());
256  ASSERT_(
257  m_textureImageAlpha.getWidth() == m_textureImage.getWidth());
258  ASSERT_(
259  m_textureImageAlpha.getHeight() == m_textureImage.getHeight());
260  }
261 
262  if (m_textureImage.isColor())
263  {
264  // Color texture:
265  if (m_enableTransparency)
266  {
267 // Color texture WITH trans.
268 // --------------------------------------
269 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
270  const std::string sSec = mrpt::format(
271  "opengl_texture_alloc %ix%i (color,trans)", width, height);
272  tim.enter(sSec.c_str());
273 #endif
274 
275  dataAligned = reserveDataBuffer(height * width * 4 + 512, data);
276 
277 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
278  tim.leave(sSec.c_str());
279 #endif
280 
281  for (int y = 0; y < height; y++)
282  {
283  unsigned char* ptrSrcCol = m_textureImage(0, y, 0);
284  unsigned char* ptrSrcAlfa = m_textureImageAlpha(0, y);
285  unsigned char* ptr = dataAligned + y * width * 4;
286 
287  for (int x = 0; x < width; x++)
288  {
289  *ptr++ = *ptrSrcCol++;
290  *ptr++ = *ptrSrcCol++;
291  *ptr++ = *ptrSrcCol++;
292  *ptr++ = *ptrSrcAlfa++;
293  }
294  }
295 
296  // Prepare image data types:
297  const GLenum img_type = GL_UNSIGNED_BYTE;
298  // Reverse RGB <-> BGR order?
299  const bool is_RGB_order =
300  (m_textureImage.getChannelsOrder() == std::string("RGB"));
301  const GLenum img_format = (is_RGB_order ? GL_RGBA : GL_BGRA);
302 
303  // Send image data to OpenGL:
306  glTexImage2D(
307  GL_TEXTURE_2D, 0 /*level*/, 4 /* RGB components */, width,
308  height, 0 /*border*/, img_format, img_type, dataAligned);
310  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
311 
312  // No need to hide a fill border:
313  m_pad_x_right = 0;
314  m_pad_y_bottom = 0;
315 
316  } // End of color texture WITH trans.
317  else
318  {
319  // Color texture WITHOUT trans.
320  // --------------------------------------
321  // Prepare image data types:
322  const GLenum img_type = GL_UNSIGNED_BYTE;
323  const int nBytesPerPixel = m_textureImage.isColor() ? 3 : 1;
324  // Reverse RGB <-> BGR order?
325  const bool is_RGB_order =
326  (m_textureImage.getChannelsOrder() == std::string("RGB"));
327  const GLenum img_format = nBytesPerPixel == 3
328  ? (is_RGB_order ? GL_RGB : GL_BGR)
329  : GL_LUMINANCE;
330 
331  // Send image data to OpenGL:
335  m_textureImage.getRowStride() / nBytesPerPixel);
336  glTexImage2D(
337  GL_TEXTURE_2D, 0 /*level*/, 3 /* RGB components */, width,
338  height, 0 /*border*/, img_format, img_type,
339  m_textureImage.ptrLine<uint8_t>(0));
340  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
341 
342  // No need to hide a fill border:
343  m_pad_x_right = 0;
344  m_pad_y_bottom = 0;
345 
346  } // End of color texture WITHOUT trans.
347  }
348  else
349  {
350  // Gray-scale texture:
351  if (m_enableTransparency)
352  {
353 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
354  const std::string sSec = mrpt::format(
355  "opengl_texture_alloc %ix%i (gray,transp)", width, height);
356  tim.enter(sSec.c_str());
357 #endif
358 
359  dataAligned =
360  reserveDataBuffer(height * width * 2 + 1024, data);
361 
362 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
363  tim.leave(sSec.c_str());
364 #endif
365 
366  for (int y = 0; y < height; y++)
367  {
368  unsigned char* ptrSrcCol = m_textureImage(0, y);
369  unsigned char* ptrSrcAlfa = m_textureImageAlpha(0, y);
370  unsigned char* ptr = dataAligned + y * width * 2;
371  for (int x = 0; x < width; x++)
372  {
373  *ptr++ = *ptrSrcCol++;
374  *ptr++ = *ptrSrcAlfa++;
375  }
376  }
377 
378  // Prepare image data types:
379  const GLenum img_type = GL_UNSIGNED_BYTE;
380  const GLenum img_format = GL_LUMINANCE_ALPHA;
381 
382  // Send image data to OpenGL:
385  glTexImage2D(
386  GL_TEXTURE_2D, 0 /*level*/, 2 /* RGB components */, width,
387  height, 0 /*border*/, img_format, img_type, dataAligned);
389  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
390 
391  // No need to hide a fill border:
392  m_pad_x_right = 0;
393  m_pad_y_bottom = 0;
394 
395  } // End of gray-scale texture WITH trans.
396  else
397  {
398  // Prepare image data types:
399  const GLenum img_type = GL_UNSIGNED_BYTE;
400  const GLenum img_format = GL_LUMINANCE;
401 
402  // Send image data to OpenGL:
405  GL_UNPACK_ROW_LENGTH, m_textureImage.getRowStride());
406  glTexImage2D(
407  GL_TEXTURE_2D, 0 /*level*/, 1 /* RGB components */, width,
408  height, 0 /*border*/, img_format, img_type,
409  m_textureImage(0, 0));
411  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
412 
413  // No need to hide a fill border:
414  m_pad_x_right = 0;
415  m_pad_y_bottom = 0;
416 
417  } // End of gray-scale texture WITHOUT trans.
418  }
419 
420  m_texture_is_loaded = true;
421 
422 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
423  {
424  const std::string sSec = mrpt::format(
425  "opengl_texture: load %ix%i %s %stransp", width, height,
426  m_textureImage.isColor() ? "RGB" : "BW",
427  m_enableTransparency ? "" : "no ");
428  tim.leave(sSec.c_str());
429  }
430 #endif
431 
432 #ifdef TEXTUREOBJ_USE_MEMPOOL
433  // Before freeing the buffer in "data", donate my memory to the pool:
434  if (!data.empty())
435  {
437  if (pool)
438  {
439  CTexturedObject_MemPoolParams mem_params;
440  mem_params.len = data.size();
441 
442  auto* mem_block = new CTexturedObject_MemPoolData();
443  data.swap(mem_block->data);
444 
445  pool->dump_to_pool(mem_params, mem_block);
446  }
447  }
448 #endif
449  }
450  catch (exception& e)
451  {
453  format("m_glTextureName=%i\n%s", m_glTextureName, e.what()));
454  }
455  catch (...)
456  {
457  THROW_EXCEPTION("Runtime error!");
458  }
459 #endif
460 }
461 
462 /*---------------------------------------------------------------
463  ~CTexturedObject
464  ---------------------------------------------------------------*/
465 CTexturedObject::~CTexturedObject() { unloadTexture(); }
466 /*---------------------------------------------------------------
467  unloadTexture
468  ---------------------------------------------------------------*/
470 {
471  if (m_texture_is_loaded)
472  {
473  m_texture_is_loaded = false;
474  releaseTextureName(m_glTextureName);
475  m_glTextureName = 0;
476  }
477 }
478 
481 {
482  uint8_t ver = 0;
483 
484  out << ver;
485  out << m_enableTransparency;
486  out << m_textureImage;
487  if (m_enableTransparency) out << m_textureImageAlpha;
488 }
489 
491 {
492 #if MRPT_HAS_OPENGL_GLUT
493  render_pre();
494  if (glGetError() != GL_NO_ERROR)
495  std::cerr << "render_pre: Error" << std::endl;
496  render_texturedobj();
497  if (glGetError() != GL_NO_ERROR)
498  std::cerr << "render_texturedobj: Error" << std::endl;
499  render_post();
500  if (glGetError() != GL_NO_ERROR)
501  std::cerr << "render_post: Error" << std::endl;
502 #endif
503 }
504 
506 {
507 #if MRPT_HAS_OPENGL_GLUT
508  MRPT_START
511 
512  if (m_enableTransparency || m_color.A != 255)
513  {
517  }
518  else
519  {
522  }
523 
524  // This will load and/or select our texture, only if "m_texture_is_loaded"
525  // is false
526  loadTextureInOpenGL();
527  MRPT_END
528 #endif
529 }
530 
532 {
533 #if MRPT_HAS_OPENGL_GLUT
534  MRPT_START
535 
536  if (m_enableTransparency || m_color.A != 255)
537  {
540 
542 
545  }
546 
549 
550  MRPT_END
551 #endif
552 }
553 
556 {
557  uint8_t version;
558  in >> version;
559 
561 
562  switch (version)
563  {
564  case 0:
565  {
566  in >> m_enableTransparency;
567  in >> m_textureImage;
568  if (m_enableTransparency)
569  {
570  in >> m_textureImageAlpha;
571  assignImage(m_textureImage, m_textureImageAlpha);
572  }
573  else
574  {
575  assignImage(m_textureImage);
576  }
577  }
578  break;
579  default:
581  };
583 }
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
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
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)
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...
void enter(const std::string_view &func_name) noexcept
Start of a named section.
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:54
#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
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
double leave(const std::string_view &func_name) noexcept
End of a named section.
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
#define GL_TEXTURE_2D
Definition: glew.h:7505
#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: abb8b1a1e Fri Oct 18 14:19:12 2019 +0200 at vie oct 18 14:20:13 CEST 2019