Developer Documentation
TextureNode.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 
46 
47 //=============================================================================
48 //
49 // CLASS TextureNode - IMPLEMENTATION
50 //
51 //=============================================================================
52 
53 
54 //== INCLUDES =================================================================
55 
56 
57 #include "TextureNode.hh"
58 #include <QGLWidget>
59 
60 //== NAMESPACES ===============================================================
61 
62 
63 namespace ACG {
64 namespace SceneGraph {
65 
66 
67 //== IMPLEMENTATION ==========================================================
68 
69 
71  const std::string& _name,
72  bool _texture_repeat,
73  GLint _texture_filter )
74  : BaseNode( _parent, _name ),
75  textures_(),
76  alpha_( 0 ),
77  texture_repeat_( _texture_repeat ),
78  tex_mode_( GL_MODULATE ),
79  texture_filter_( _texture_filter ),
80  mipmapping_globally_active_(true),
81  last_mipmapping_status_(true),
82  mipmapping_(true),
83  activeTexture_(-1),
84  open_volume_mesh_texture_draw_modes_(DrawModes::getDrawMode("Faces (textured)") | DrawModes::getDrawMode("Faces (textured and shaded)") )
85 {
86 // open_volume_mesh_texture_draw_modes_ = DrawModes::getDrawMode("Faces (textured)");
87 // open_volume_mesh_texture_draw_modes_ |= DrawModes::getDrawMode("Faces (textured and shaded)");
88 }
89 
90 
91 //----------------------------------------------------------------------------
92 
93 
95 {
96  for (std::vector<TextureInfo>::iterator texturesIt = textures_.begin(); texturesIt != textures_.end(); ++texturesIt) {
97  delete texturesIt->tex;
98  }
99  textures_.clear();
100 }
101 
102 
103 
104 //----------------------------------------------------------------------------
105 
106 
107 bool
108 TextureNode::read(const char* _filename)
109 {
110  // load to image
111  QImage image;
112  if ( !image.load( _filename ) )
113  {
114  std::cerr << "Cannot load texture " << _filename << "\n";
115  return false;
116  }
117 
118  set_texture( image );
119 
120  return true;
121 }
122 
123 
124 //----------------------------------------------------------------------------
125 
126 
127 void
129 {
130  // GL settings
131  glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
132  glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
133  glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
134  glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
135  glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
136  glPixelStorei( GL_PACK_SKIP_ROWS, 0 );
137  glPixelStorei( GL_PACK_SKIP_PIXELS, 0 );
138  glPixelStorei( GL_PACK_ALIGNMENT, 1 );
139 }
140 
141 void
143 {
144  if ( texture_repeat_ ) {
145  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
146  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
147  } else {
148  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
149  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
150 
151  // Set BorderColor for Clamping
152  const float borderColor[4] = {1.0, 1.0, 1.0, 1.0};
153  glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
154  }
155 
156  if((mipmapping_globally_active_ && mipmapping_ && textures_[_id].mipmapAvailable) &&
157  (texture_filter_ == GL_LINEAR_MIPMAP_NEAREST ||
158  texture_filter_ == GL_LINEAR_MIPMAP_LINEAR ||
159  texture_filter_ == GL_NEAREST_MIPMAP_LINEAR ||
160  texture_filter_ == GL_NEAREST_MIPMAP_NEAREST)) {
161 
162  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
163  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_filter_ );
164  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
165 
166  } else if(texture_filter_ == GL_LINEAR) {
167 
168  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
169  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
170 
171  } else {
172  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
173  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
174  }
175 
176 }
177 
178 //----------------------------------------------------------------------------
179 
181 
182  if(!mipmapping_) {
183  mipmapping_ = true;
184  updateMipmaps(mipmapping_globally_active_);
185  }
186 }
187 
188 //----------------------------------------------------------------------------
189 
191 
192  if(mipmapping_) {
193  mipmapping_ = false;
194  updateMipmaps(mipmapping_);
195  }
196 }
197 
198 //----------------------------------------------------------------------------
199 
200 void TextureNode::setTextureDataGL ( GLuint _textureId,
201  GLenum _target,
202  GLint _width ,
203  GLint _height,
204  GLenum _format ,
205  GLenum _type,
206  const void * _data) {
207 
208  applyGLSettings();
209 
210  Texture2D* tex = textures_[_textureId].tex;
211 
212  tex->bind();
213 
214  if ( mipmapping_ )
215  textures_[_textureId].mipmapAvailable = true;
216  else
217  textures_[_textureId].mipmapAvailable = false;
218 
219  applyTextureParameters(_textureId);
220 
221  bool mipmaps = mipmapping_globally_active_ && mipmapping_;
222  // Load the image
223  if ( mipmaps )
224  tex->autogenerateMipMaps();
225 
226  tex->setData( 0, // level
227  GL_RGBA, // internal format
228  _width, // width (2^n)
229  _height, // height (2^m)
230  _format, // format
231  _type, // type
232  _data, // pointer to pixels
233  mipmaps); // mipmaps or not
234 
235  // Unbind until we use it
236  ACG::GLState::bindTexture(GL_TEXTURE_2D,0);
237 }
238 
239 
240 //----------------------------------------------------------------------------
241 
244 void TextureNode::updateMipmaps(bool _mipmap) {
245 
246  // Make sure we have at least on element in the textures list
247  checkEmpty();
248 
249  for(unsigned int i = 1; i < textures_.size(); ++i) {
250 
251  Texture2D* tex = textures_[i].tex;
252 
253  // Bind texture
254  tex->bind();
255 
256  // size in bytes of level 0 texture
257  size_t bufferSize = textures_[i].tex->getWidth() * textures_[i].tex->getHeight()*4;
258 
259  if(_mipmap && bufferSize) {
260 
261  // Get pixel data out of texture memory
262  GLubyte* buffer = new GLubyte[bufferSize];
263 // glGetTexImage(textures_[i].target, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
264  tex->getData(0, buffer);
265 
266  // Build mipmap
267  tex->autogenerateMipMaps();
268  tex->setData(0, tex->getInternalFormat(), tex->getWidth(), tex->getHeight(),
269  tex->getFormat(), tex->getType(), buffer);
270 
271  delete [] buffer;
272  }
273 
274  // Set mipmap available flag
275  textures_[i].mipmapAvailable = _mipmap;
276 
277  // Update parameters such that changes apply during runtime
279  }
280 }
281 
282 //----------------------------------------------------------------------------
283 
284 
285 void
286 TextureNode::set_texture(const unsigned char * _image, int _width, int _height)
287 {
288  checkEmpty();
289 
290  // enough texture mem?
291  if ( !Texture2D::checkTextureMem(GL_RGBA, _width, _height, GL_RGBA) ) {
292  std::cerr << "Can't load texture";
293  return;
294  }
295 
296  setTextureDataGL(activeTexture_,GL_TEXTURE_2D,_width,_height,GL_RGBA,GL_UNSIGNED_BYTE,_image);
297 
298 }
299 
300 
301 //----------------------------------------------------------------------------
302 
303 
304 void
305 TextureNode::set_texture(const QImage& _image)
306 {
307  checkEmpty();
308 
309  // adjust texture size: 2^k * 2^l
310  int tex_w, w( _image.width() );
311  int tex_h, h( _image.height() );
312 
313  for (tex_w=1; tex_w < w; tex_w <<= 1) {};
314  for (tex_h=1; tex_h < h; tex_h <<= 1) {};
315  if (5 * tex_w > 7 *w) // tex_w longer than sqrt(2)*w means too much waste of storage space (7/5 = sqrt(2)-1%)
316  tex_w >>= 1;
317  if (5 * tex_h > 7 *h) // tex_h longer than sqrt(2)*h means too much waste of storage space (7/5 = sqrt(2)-1%)
318  tex_h >>= 1;
319 
320  // is size of input image a power of 2?
321  bool isNPOT = ( tex_w != w ) || ( tex_h != h );
322 
323  // image has to be converted to GL_RGBA8 to avoid crash
324  QImage textureGL;
325 
326  // eventually scale to pot image if no hw support / core in GL 2.0
327  if (!openGLVersion(2,0) && isNPOT)
328  {
329  // because texture will only be accessed proportionally by texture coordinates, aspect ratio is of no concern
330  textureGL = QGLWidget::convertToGLFormat ( _image.scaled( tex_w, tex_h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
331  }
332  else
333  {
334  // use npot texture
335  tex_w = w;
336  tex_h = h;
337  textureGL = QGLWidget::convertToGLFormat ( _image );
338  }
339 
340  // enough texture mem?
341  if ( !Texture2D::checkTextureMem(GL_RGBA, tex_w, tex_h, GL_RGBA) ) {
342  std::cerr << "Can't load texture TextureNode::set_texture" << std::endl;
343  return;
344  }
345 
346  // Set the image
347  setTextureDataGL(activeTexture_ ,GL_TEXTURE_2D,tex_w,tex_h,GL_RGBA,GL_UNSIGNED_BYTE,textureGL.bits());
348 }
349 
350 //----------------------------------------------------------------------------
351 
352 
353 void
354 TextureNode::set_texture(const float * _image, int _width, int _height )
355 {
356  checkEmpty();
357 
358  // enough texture mem?
359  if ( !Texture2D::checkTextureMem(GL_RGBA, _width, _height, GL_RGBA) ) {
360  std::cerr << "Can't load texture TextureNode::set_texture" << std::endl;
361  return;
362  }
363 
364  // Set the image
365  setTextureDataGL(activeTexture_,GL_TEXTURE_2D,_width,_height,GL_RGBA,GL_FLOAT,_image);
366 }
367 
368 //----------------------------------------------------------------------------
369 
371 
372  // No texture generated yet!
373  if ( textures_.empty() ) {
374  textures_.resize(1);
375  activeTexture_ = 0;
376 // textures_[activeTexture_].id = 0;
377  Texture2D* t = new Texture2D();
378  t->gen();
379  textures_[activeTexture_].tex = t;
380  }
381 
382 }
383 
384 //----------------------------------------------------------------------------
385 
386 int TextureNode::available( GLuint _id ) {
387  // If the texture is found in the array return its id otherwise -1
388  for ( uint i = 0 ; i < textures_.size(); ++i )
389  if ( textures_[i].tex->id() == _id )
390  return i;
391 
392  return -1;
393 }
394 
395 //----------------------------------------------------------------------------
396 
397 bool TextureNode::read(const char* _filename, GLuint _id ) {
398  if ( available(_id) != -1 ) {
399  activeTexture_ = available(_id);
400  return read(_filename);
401  } else
402  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
403 
404  return false;
405 
406 }
407 
408 
409 //----------------------------------------------------------------------------
410 
411 
412 
413 void TextureNode::set_texture(const QImage& _image, GLuint _id) {
414 
415  checkEmpty();
416 
417  if ( available(_id) != -1 ) {
418  activeTexture_ = available(_id);
419  set_texture(_image);
420  } else
421  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
422 
423 }
424 
425 
426 //----------------------------------------------------------------------------
427 
428 
429 
430 void TextureNode::set_texture(const float * _image, int _width, int _height, GLuint _id) {
431 
432  checkEmpty();
433 
434  if ( available(_id) != -1 ) {
435  activeTexture_ = available(_id);
436  set_texture(_image,_width,_height);
437  } else
438  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
439 }
440 
441 
442 
443 //----------------------------------------------------------------------------
444 
445 
446 void TextureNode::set_texture(const unsigned char * _image, int _width, int _height, GLuint _id) {
447 
448  checkEmpty();
449 
450  if ( available(_id) != -1 ) {
451  activeTexture_ = available(_id);
452  set_texture(_image,_width,_height);
453 
454  } else
455  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
456 
457 }
458 
459 
460 //----------------------------------------------------------------------------
461 
462 
463 // add QImage _image as additional texture, using face_texture_index
464 GLuint
465 TextureNode::add_texture(const QImage& _image)
466 {
467  checkEmpty();
468 
469  textures_.resize(textures_.size()+1); // can't push_back, because glGenTextures needs a pointer
470 
471  // Generate new texture
472  textures_.back().tex = new Texture2D();
473 
474  activeTexture_ = int(textures_.size() - 1);
475 
476  // Set the image
477  set_texture(_image);
478 
479  // return the id of the new texture
480  return textures_.back().tex->id();
481 }
482 
483 
484 //----------------------------------------------------------------------------
485 
486 
487 void TextureNode::enter(GLState& _state , const DrawModes::DrawMode& _drawmode)
488 {
489  if ( _drawmode & ( DrawModes::SOLID_TEXTURED |
497  {
498  if(_state.compatibilityProfile())
499  ACG::GLState::enable( GL_TEXTURE_2D );
500 
501  mipmapping_globally_active_ = _state.mipmapping_allowed();
502 
503  // Check if mipmapping status has changed
504  if(_state.mipmapping_allowed() != last_mipmapping_status_) {
505 
506  // Update mipmaps
507  updateMipmaps(mipmapping_globally_active_ && mipmapping_);
508 
509  // Keep track of changes
510  last_mipmapping_status_ = _state.mipmapping_allowed();
511 
512  }
513 
514  if ( !textures_.empty() ) {
515  textures_[activeTexture_].tex->bind();
516  }
517 
518  if(_state.compatibilityProfile())
519  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_ );
520 
521 // if (_drawmode & DrawModes::SOLID_FACES_COLORED_2DTEXTURED_FACE_SMOOTH_SHADED)
522 // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
523  }
524 }
525 
526 
527 //----------------------------------------------------------------------------
528 
529 
530 void TextureNode::leave(GLState& _state , const DrawModes::DrawMode& _drawmode)
531 {
532  if ( _drawmode & ( DrawModes::SOLID_TEXTURED |
539  {
540  ACG::GLState::bindTexture( GL_TEXTURE_2D, 0 );
541  if(_state.compatibilityProfile())
542  ACG::GLState::disable( GL_TEXTURE_2D );
543  }
544 }
545 
546 void TextureNode::enterPick(GLState& /*_state*/ , PickTarget /*_target*/, const DrawModes::DrawMode& /*_drawMode*/ ) {
547 
548 }
549 
550 void TextureNode::leavePick(GLState& /*_state*/, PickTarget /*_target*/, const DrawModes::DrawMode& /*_drawMode*/ ) {
551 }
552 
553 //----------------------------------------------------------------------------
554 
555 
557 {
558  if (0 <= activeTexture_ && activeTexture_ < int(textures_.size()))
559  return textures_[activeTexture_].tex->id();
560 
561  return 0;
562 }
563 
564 //----------------------------------------------------------------------------
565 
567 {
568  int search = available(_id);
569 
570  //==========================================================================
571  // If zero is given, unbind all textures
572  //==========================================================================
573  if ( _id == 0 ) {
574  search = 0;
575  }
576 
577  //==========================================================================
578  // Index has not been found ... No corresponding Texture in this node
579  //==========================================================================
580  if ( search == -1 ) {
581  std::cerr << "Texture to activate not found!" << std::endl;
582  return false;
583  }
584 
585  activeTexture_ = search;
586 
587  return true;
588 }
589 
590 //=============================================================================
591 } // namespace SceneGraph
592 } // namespace ACG
593 //=============================================================================
DrawMode SOLID_2DTEXTURED_FACE
draw per halfedge textured faces
Definition: DrawModes.cc:96
bool read(const char *_filename)
Uses a QImage to load the texture from the given file.
Definition: TextureNode.cc:108
DrawMode SOLID_ENV_MAPPED
draw environment mapped
Definition: DrawModes.cc:87
Namespace providing different geometric functions concerning angles.
TextureNode(BaseNode *_parent=0, const std::string &_name="<TextureNode>", bool _texture_repeat=true, GLint _texture_filter=GL_LINEAR)
Default constructor. Applies all properties.
Definition: TextureNode.cc:70
DrawModes::DrawMode open_volume_mesh_texture_draw_modes_
OpenVolumeMesh DrawModes using textures.
Definition: TextureNode.hh:352
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
DrawMode SOLID_FACES_COLORED_2DTEXTURED_FACE_SMOOTH_SHADED
draw per halfedge texture faces modulated with face colors with smooth shading
Definition: DrawModes.cc:104
DrawMode SOLID_2DTEXTURED_FACE_SHADED
draw per halfedge textured faces
Definition: DrawModes.cc:97
void checkEmpty()
Check if a texture is already generated by this Node.
Definition: TextureNode.cc:370
int available(GLuint _id)
check this node for a texture
Definition: TextureNode.cc:386
PickTarget
What target to use for picking.
Definition: PickTarget.hh:73
void enable_mipmapping()
Enable mipmapping.
Definition: TextureNode.cc:180
int activeTexture_
currently active texture
Definition: TextureNode.hh:346
void leave(GLState &_state, const DrawModes::DrawMode &_drawmode) override
Unbind Texture.
Definition: TextureNode.cc:530
DrawMode SOLID_TEXTURED
draw textured faces
Definition: DrawModes.cc:88
void updateMipmaps(bool _mipmap)
Build mip maps of textures that don&#39;t have one yet.
Definition: TextureNode.cc:244
void leavePick(GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode) override
Do nothing in picking.
Definition: TextureNode.cc:550
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129
void enterPick(GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode) override
Do nothing in picking.
Definition: TextureNode.cc:546
void applyTextureParameters(int _id)
Definition: TextureNode.cc:142
bool activateTexture(GLuint _id)
Set active Texture.
Definition: TextureNode.cc:566
void set_texture(const QImage &_image)
Uses a QImage to set the texture.
Definition: TextureNode.cc:305
virtual ~TextureNode()
Destructor.
Definition: TextureNode.cc:94
void enter(GLState &_state, const DrawModes::DrawMode &_drawmode) override
set default texture and states for the nodes children
Definition: TextureNode.cc:487
GLuint activeTexture()
Get active Texture.
Definition: TextureNode.cc:556
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
void disable_mipmapping()
Disable mipmapping.
Definition: TextureNode.cc:190
DrawMode SOLID_TEXTURED_SHADED
draw smooth shaded textured faces
Definition: DrawModes.cc:89
bool mipmapping_allowed() const
Get current global mipmapping state.
Definition: GLState.hh:1071
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
GLuint add_texture(const QImage &_image)
Add a texture to this node.
Definition: TextureNode.cc:465