MRPT  1.9.9
CTexturedObject.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "opengl-precomp.h" // Precompiled header
11 
15 #include "opengl_internals.h"
16 #include <memory> // std::align
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.copyFastFrom(img);
107  m_textureImageAlpha.copyFastFrom(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.copyFastFrom(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 
185  // allocate texture names:
186  m_glTextureName = getNewTextureNumber();
187 
188  // select our current texture
189  glBindTexture(GL_TEXTURE_2D, m_glTextureName);
191 
192  // when texture area is small, linear interpolation. Default is
193  // GL_LINEAR_MIPMAP_NEAREST but we
194  // are not building mipmaps.
195  // See also:
196  // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=133116&page=1
199 
200  // when texture area is large, NEAREST: this is mainly thinking of
201  // rendering
202  // occupancy grid maps, such as we want those "big pixels" to be
203  // clearly visible ;-)
206 
207  // if wrap is true, the texture wraps over at the edges (repeat)
208  // ... false, the texture ends at the edges (clamp)
211 
214 
215  // Assure that the images do not overpass the maximum dimensions allowed
216  // by OpenGL:
217  // ------------------------------------------------------------------------------------
218  GLint texSize;
220  while (m_textureImage.getHeight() > (unsigned int)texSize ||
221  m_textureImage.getWidth() > (unsigned int)texSize)
222  {
223  m_textureImage = m_textureImage.scaleHalf();
224  m_textureImageAlpha = m_textureImageAlpha.scaleHalf();
225  }
226 
227  const int width = m_textureImage.getWidth();
228  const int height = m_textureImage.getHeight();
229 
230 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
231  {
232  const std::string sSec = mrpt::format(
233  "opengl_texture: load %ix%i %s %stransp", width, height,
234  m_textureImage.isColor() ? "RGB" : "BW",
235  m_enableTransparency ? "" : "no ");
236  tim.enter(sSec.c_str());
237  }
238 #endif
239 
240  r_width = width; // round2up( width );
241  r_height = height; // round2up( height );
242 
243  // Padding pixels:
244  m_pad_x_right = (r_width - width);
245  m_pad_y_bottom = (r_height - height);
246 
247  if (m_enableTransparency)
248  {
249  ASSERT_(!m_textureImageAlpha.isColor());
250  ASSERT_(
251  m_textureImageAlpha.getWidth() == m_textureImage.getWidth());
252  ASSERT_(
253  m_textureImageAlpha.getHeight() == m_textureImage.getHeight());
254  }
255 
256  if (m_textureImage.isColor())
257  {
258  // Color texture:
259  if (m_enableTransparency)
260  {
261 // Color texture WITH trans.
262 // --------------------------------------
263 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
264  const std::string sSec = mrpt::format(
265  "opengl_texture_alloc %ix%i (color,trans)", width, height);
266  tim.enter(sSec.c_str());
267 #endif
268 
269  dataAligned = reserveDataBuffer(height * width * 4 + 512, data);
270 
271 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
272  tim.leave(sSec.c_str());
273 #endif
274 
275  for (int y = 0; y < height; y++)
276  {
277  unsigned char* ptrSrcCol = m_textureImage(0, y, 0);
278  unsigned char* ptrSrcAlfa = m_textureImageAlpha(0, y);
279  unsigned char* ptr = dataAligned + y * width * 4;
280 
281  for (int x = 0; x < width; x++)
282  {
283  *ptr++ = *ptrSrcCol++;
284  *ptr++ = *ptrSrcCol++;
285  *ptr++ = *ptrSrcCol++;
286  *ptr++ = *ptrSrcAlfa++;
287  }
288  }
289 
290  // Prepare image data types:
291  const GLenum img_type = GL_UNSIGNED_BYTE;
292  const bool is_RGB_order = (!::strcmp(
293  m_textureImage.getChannelsOrder(),
294  "RGB")); // Reverse RGB <-> BGR order?
295  const GLenum img_format = (is_RGB_order ? GL_RGBA : GL_BGRA);
296 
297  // Send image data to OpenGL:
300  glTexImage2D(
301  GL_TEXTURE_2D, 0 /*level*/, 4 /* RGB components */, width,
302  height, 0 /*border*/, img_format, img_type, dataAligned);
304  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
305 
306  // No need to hide a fill border:
307  m_pad_x_right = 0;
308  m_pad_y_bottom = 0;
309 
310  } // End of color texture WITH trans.
311  else
312  {
313  // Color texture WITHOUT trans.
314  // --------------------------------------
315  // Prepare image data types:
316  const GLenum img_type = GL_UNSIGNED_BYTE;
317  const int nBytesPerPixel = m_textureImage.isColor() ? 3 : 1;
318  const bool is_RGB_order = (!::strcmp(
319  m_textureImage.getChannelsOrder(),
320  "RGB")); // Reverse RGB <-> BGR order?
321  const GLenum img_format = nBytesPerPixel == 3
322  ? (is_RGB_order ? GL_RGB : GL_BGR)
323  : GL_LUMINANCE;
324 
325  // Send image data to OpenGL:
329  m_textureImage.getRowStride() / nBytesPerPixel);
330  glTexImage2D(
331  GL_TEXTURE_2D, 0 /*level*/, 3 /* RGB components */, width,
332  height, 0 /*border*/, img_format, img_type,
333  m_textureImage.get_unsafe(0, 0));
334  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
335 
336  // No need to hide a fill border:
337  m_pad_x_right = 0;
338  m_pad_y_bottom = 0;
339 
340  } // End of color texture WITHOUT trans.
341  }
342  else
343  {
344  // Gray-scale texture:
345  if (m_enableTransparency)
346  {
347 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
348  const std::string sSec = mrpt::format(
349  "opengl_texture_alloc %ix%i (gray,transp)", width, height);
350  tim.enter(sSec.c_str());
351 #endif
352 
353  dataAligned =
354  reserveDataBuffer(height * width * 2 + 1024, data);
355 
356 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
357  tim.leave(sSec.c_str());
358 #endif
359 
360  for (int y = 0; y < height; y++)
361  {
362  unsigned char* ptrSrcCol = m_textureImage(0, y);
363  unsigned char* ptrSrcAlfa = m_textureImageAlpha(0, y);
364  unsigned char* ptr = dataAligned + y * width * 2;
365  for (int x = 0; x < width; x++)
366  {
367  *ptr++ = *ptrSrcCol++;
368  *ptr++ = *ptrSrcAlfa++;
369  }
370  }
371 
372  // Prepare image data types:
373  const GLenum img_type = GL_UNSIGNED_BYTE;
374  const GLenum img_format = GL_LUMINANCE_ALPHA;
375 
376  // Send image data to OpenGL:
379  glTexImage2D(
380  GL_TEXTURE_2D, 0 /*level*/, 2 /* RGB components */, width,
381  height, 0 /*border*/, img_format, img_type, dataAligned);
383  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
384 
385  // No need to hide a fill border:
386  m_pad_x_right = 0;
387  m_pad_y_bottom = 0;
388 
389  } // End of gray-scale texture WITH trans.
390  else
391  {
392  // Prepare image data types:
393  const GLenum img_type = GL_UNSIGNED_BYTE;
394  const GLenum img_format = GL_LUMINANCE;
395 
396  // Send image data to OpenGL:
399  GL_UNPACK_ROW_LENGTH, m_textureImage.getRowStride());
400  glTexImage2D(
401  GL_TEXTURE_2D, 0 /*level*/, 1 /* RGB components */, width,
402  height, 0 /*border*/, img_format, img_type,
403  m_textureImage(0, 0));
405  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Reset
406 
407  // No need to hide a fill border:
408  m_pad_x_right = 0;
409  m_pad_y_bottom = 0;
410 
411  } // End of gray-scale texture WITHOUT trans.
412  }
413 
414  m_texture_is_loaded = true;
415 
416 #ifdef TEXTUREOBJ_PROFILE_MEM_ALLOC
417  {
418  const std::string sSec = mrpt::format(
419  "opengl_texture: load %ix%i %s %stransp", width, height,
420  m_textureImage.isColor() ? "RGB" : "BW",
421  m_enableTransparency ? "" : "no ");
422  tim.leave(sSec.c_str());
423  }
424 #endif
425 
426 #ifdef TEXTUREOBJ_USE_MEMPOOL
427  // Before freeing the buffer in "data", donate my memory to the pool:
428  if (!data.empty())
429  {
431  if (pool)
432  {
433  CTexturedObject_MemPoolParams mem_params;
434  mem_params.len = data.size();
435 
436  CTexturedObject_MemPoolData* mem_block =
438  data.swap(mem_block->data);
439 
440  pool->dump_to_pool(mem_params, mem_block);
441  }
442  }
443 #endif
444  }
445  catch (exception& e)
446  {
448  format("m_glTextureName=%i\n%s", m_glTextureName, e.what()));
449  }
450  catch (...)
451  {
452  THROW_EXCEPTION("Runtime error!");
453  }
454 #endif
455 }
456 
457 /*---------------------------------------------------------------
458  ~CTexturedObject
459  ---------------------------------------------------------------*/
460 CTexturedObject::~CTexturedObject() { unloadTexture(); }
461 /*---------------------------------------------------------------
462  unloadTexture
463  ---------------------------------------------------------------*/
465 {
466  if (m_texture_is_loaded)
467  {
468  m_texture_is_loaded = false;
469  releaseTextureName(m_glTextureName);
470  m_glTextureName = 0;
471  }
472 }
473 
476 {
477  uint8_t ver = 0;
478 
479  out << ver;
480  out << m_enableTransparency;
481  out << m_textureImage;
482  if (m_enableTransparency) out << m_textureImageAlpha;
483 }
484 
486 {
487 #if MRPT_HAS_OPENGL_GLUT
488  render_pre();
489  if (glGetError() != GL_NO_ERROR)
490  std::cerr << "render_pre: Error" << std::endl;
491  render_texturedobj();
492  if (glGetError() != GL_NO_ERROR)
493  std::cerr << "render_texturedobj: Error" << std::endl;
494  render_post();
495  if (glGetError() != GL_NO_ERROR)
496  std::cerr << "render_post: Error" << std::endl;
497 #endif
498 }
499 
501 {
502 #if MRPT_HAS_OPENGL_GLUT
503  MRPT_START
506 
507  if (m_enableTransparency || m_color.A != 255)
508  {
512  }
513  else
514  {
517  }
518 
519  // This will load and/or select our texture, only if "m_texture_is_loaded"
520  // is false
521  loadTextureInOpenGL();
522  MRPT_END
523 #endif
524 }
525 
527 {
528 #if MRPT_HAS_OPENGL_GLUT
529  MRPT_START
530 
531  if (m_enableTransparency || m_color.A != 255)
532  {
535 
537 
540  }
541 
544 
545  MRPT_END
546 #endif
547 }
548 
551 {
552  uint8_t version;
553  in >> version;
554 
556 
557  switch (version)
558  {
559  case 0:
560  {
561  in >> m_enableTransparency;
562  in >> m_textureImage;
563  if (m_enableTransparency)
564  {
565  in >> m_textureImageAlpha;
566  assignImage(m_textureImage, m_textureImageAlpha);
567  }
568  else
569  {
570  assignImage(m_textureImage);
571  }
572  }
573  break;
574  default:
576  };
578 }
virtual void render_post() const
#define GL_BGR
Definition: glew.h:1239
#define MRPT_START
Definition: exceptions.h:262
#define GL_TEXTURE_WRAP_T
Definition: glew.h:668
#define GL_RGBA
Definition: glew.h:624
A base class for all OpenGL objects with loadable textures.
virtual 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:41
#define GL_ZERO
Definition: glew.h:282
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:8246
EIGEN_STRONG_INLINE void notifyChange() const
Must be called to notify that the object has changed (so, the display list must be updated) ...
STL namespace.
#define GL_UNSIGNED_BYTE
Definition: glew.h:302
#define GL_LINEAR
Definition: glew.h:660
#define GL_ONE_MINUS_SRC_ALPHA
Definition: glew.h:287
#define GL_DEPTH_TEST
Definition: glew.h:401
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:4712
GLenum GLsizei width
Definition: glext.h:3531
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:41
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:90
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:113
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:283
GLint GLvoid * img
Definition: glext.h:3763
#define GL_RGB
Definition: glew.h:623
double leave(const char *func_name)
End of a named section.
#define GL_BLEND
Definition: glew.h:432
virtual void render_pre() const
#define GL_REPEAT
Definition: glew.h:670
GLsizei const GLchar ** string
Definition: glext.h:4101
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:206
#define GL_NEAREST
Definition: glew.h:659
#define GL_SRC_ALPHA
Definition: glew.h:286
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
#define GL_NO_ERROR
Definition: glew.h:326
#define GL_UNPACK_ROW_LENGTH
Definition: glew.h:481
#define GL_TEXTURE_MIN_FILTER
Definition: glew.h:666
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:52
#define GL_UNPACK_ALIGNMENT
Definition: glew.h:484
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:665
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:143
GLAPI void GLAPIENTRY glGetIntegerv(GLenum pname, GLint *params)
#define MRPT_END
Definition: exceptions.h:266
GLAPI GLenum GLAPIENTRY glGetError(void)
GLuint in
Definition: glext.h:7274
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
GLenum GLint GLint y
Definition: glext.h:3538
void readFromStreamTexturedObject(mrpt::serialization::CArchive &in)
int GLint
Definition: glew.h:209
#define GL_MAX_TEXTURE_SIZE
Definition: glew.h:510
GLenum GLint x
Definition: glext.h:3538
#define GL_LUMINANCE_ALPHA
Definition: glew.h:626
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:3554
GLAPI void GLAPIENTRY glDisable(GLenum cap)
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
GLAPI void GLAPIENTRY glPixelStorei(GLenum pname, GLint param)
void writeToStreamTexturedObject(mrpt::serialization::CArchive &out) const
#define GL_TEXTURE_WRAP_S
Definition: glew.h:667
#define GL_TEXTURE_2D
Definition: glew.h:7238
#define GL_LUMINANCE
Definition: glew.h:625
GLAPI void GLAPIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
void enter(const char *func_name)
Start of a named section.
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:130
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: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020