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  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 
51 
52 
53 //=============================================================================
54 //
55 // CLASS TextureNode - IMPLEMENTATION
56 //
57 //=============================================================================
58 
59 
60 //== INCLUDES =================================================================
61 
62 
63 #include "TextureNode.hh"
64 #include <QGLWidget>
65 
66 //== NAMESPACES ===============================================================
67 
68 
69 namespace ACG {
70 namespace SceneGraph {
71 
72 
73 //== IMPLEMENTATION ==========================================================
74 
75 
77  const std::string& _name,
78  bool _texture_repeat,
79  GLint _texture_filter )
80  : BaseNode( _parent, _name ),
81  textures_(),
82  alpha_( 0 ),
83  texture_repeat_( _texture_repeat ),
84  tex_mode_( GL_MODULATE ),
85  texture_filter_( _texture_filter ),
86  mipmapping_globally_active_(true),
87  last_mipmapping_status_(true),
88  mipmapping_(true),
89  activeTexture_(-1),
90  open_volume_mesh_texture_draw_modes_(DrawModes::getDrawMode("Faces (textured)") | DrawModes::getDrawMode("Faces (textured and shaded)") )
91 {
92 // open_volume_mesh_texture_draw_modes_ = DrawModes::getDrawMode("Faces (textured)");
93 // open_volume_mesh_texture_draw_modes_ |= DrawModes::getDrawMode("Faces (textured and shaded)");
94 }
95 
96 
97 //----------------------------------------------------------------------------
98 
99 
101 {
102  for (std::vector<TextureInfo>::iterator texturesIt = textures_.begin(); texturesIt != textures_.end(); ++texturesIt) {
103  delete texturesIt->tex;
104  }
105  textures_.clear();
106 }
107 
108 
109 
110 //----------------------------------------------------------------------------
111 
112 
113 bool
114 TextureNode::read(const char* _filename)
115 {
116  // load to image
117  QImage image;
118  if ( !image.load( _filename ) )
119  {
120  std::cerr << "Cannot load texture " << _filename << "\n";
121  return false;
122  }
123 
124  set_texture( image );
125 
126  return true;
127 }
128 
129 
130 //----------------------------------------------------------------------------
131 
132 
133 void
135 {
136  // GL settings
137  glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
138  glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
139  glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
140  glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
141  glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
142  glPixelStorei( GL_PACK_SKIP_ROWS, 0 );
143  glPixelStorei( GL_PACK_SKIP_PIXELS, 0 );
144  glPixelStorei( GL_PACK_ALIGNMENT, 1 );
145 }
146 
147 void
149 {
150  if ( texture_repeat_ ) {
151  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
152  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
153  } else {
154  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
155  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
156 
157  // Set BorderColor for Clamping
158  const float borderColor[4] = {1.0, 1.0, 1.0, 1.0};
159  glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
160  }
161 
162  if((mipmapping_globally_active_ && mipmapping_ && textures_[_id].mipmapAvailable) &&
163  (texture_filter_ == GL_LINEAR_MIPMAP_NEAREST ||
164  texture_filter_ == GL_LINEAR_MIPMAP_LINEAR ||
165  texture_filter_ == GL_NEAREST_MIPMAP_LINEAR ||
166  texture_filter_ == GL_NEAREST_MIPMAP_NEAREST)) {
167 
168  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
169  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_filter_ );
170  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
171 
172  } else if(texture_filter_ == GL_LINEAR) {
173 
174  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
175  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
176 
177  } else {
178  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
179  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
180  }
181 
182 }
183 
184 //----------------------------------------------------------------------------
185 
187 
188  if(!mipmapping_) {
189  mipmapping_ = true;
190  updateMipmaps(mipmapping_globally_active_);
191  }
192 }
193 
194 //----------------------------------------------------------------------------
195 
197 
198  if(mipmapping_) {
199  mipmapping_ = false;
200  updateMipmaps(mipmapping_);
201  }
202 }
203 
204 //----------------------------------------------------------------------------
205 
206 void TextureNode::setTextureDataGL ( GLuint _textureId,
207  GLenum _target,
208  GLint _width ,
209  GLint _height,
210  GLenum _format ,
211  GLenum _type,
212  const void * _data) {
213 
214  applyGLSettings();
215 
216  Texture2D* tex = textures_[_textureId].tex;
217 
218  tex->bind();
219 
220  if ( mipmapping_ )
221  textures_[_textureId].mipmapAvailable = true;
222  else
223  textures_[_textureId].mipmapAvailable = false;
224 
225  applyTextureParameters(_textureId);
226 
227  // Load the image
228  if ( mipmapping_globally_active_ && mipmapping_ )
229  tex->autogenerateMipMaps();
230 
231  tex->setData( 0, // level
232  GL_RGBA, // internal format
233  _width, // width (2^n)
234  _height, // height (2^m)
235  _format, // format
236  _type, // type
237  _data ); // pointer to pixels
238 
239  // Unbind until we use it
240  ACG::GLState::bindTexture(GL_TEXTURE_2D,0);
241 }
242 
243 
244 //----------------------------------------------------------------------------
245 
248 void TextureNode::updateMipmaps(bool _mipmap) {
249 
250  // Make sure we have at least on element in the textures list
251  checkEmpty();
252 
253  for(unsigned int i = 1; i < textures_.size(); ++i) {
254 
255  Texture2D* tex = textures_[i].tex;
256 
257  // Bind texture
258  tex->bind();
259 
260  // size in bytes of level 0 texture
261  size_t bufferSize = textures_[i].tex->getWidth() * textures_[i].tex->getHeight()*4;
262 
263  if(_mipmap && bufferSize) {
264 
265  // Get pixel data out of texture memory
266  GLubyte* buffer = new GLubyte[bufferSize];
267 // glGetTexImage(textures_[i].target, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
268  tex->getData(0, buffer);
269 
270  // Build mipmap
271  tex->autogenerateMipMaps();
272  tex->setData(0, tex->getInternalFormat(), tex->getWidth(), tex->getHeight(),
273  tex->getFormat(), tex->getType(), buffer);
274 
275  delete [] buffer;
276  }
277 
278  // Set mipmap available flag
279  textures_[i].mipmapAvailable = _mipmap;
280 
281  // Update parameters such that changes apply during runtime
283  }
284 }
285 
286 //----------------------------------------------------------------------------
287 
288 
289 void
290 TextureNode::set_texture(const unsigned char * _image, int _width, int _height)
291 {
292  checkEmpty();
293 
294  // enough texture mem?
295  if ( !Texture2D::checkTextureMem(GL_RGBA, _width, _height, GL_RGBA) ) {
296  std::cerr << "Can't load texture";
297  return;
298  }
299 
300  setTextureDataGL(activeTexture_,GL_TEXTURE_2D,_width,_height,GL_RGBA,GL_UNSIGNED_BYTE,_image);
301 
302 }
303 
304 
305 //----------------------------------------------------------------------------
306 
307 
308 void
309 TextureNode::set_texture(const QImage& _image)
310 {
311  checkEmpty();
312 
313  // adjust texture size: 2^k * 2^l
314  int tex_w, w( _image.width() );
315  int tex_h, h( _image.height() );
316 
317  for (tex_w=1; tex_w < w; tex_w <<= 1) {};
318  for (tex_h=1; tex_h < h; tex_h <<= 1) {};
319  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%)
320  tex_w >>= 1;
321  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%)
322  tex_h >>= 1;
323 
324  // is size of input image a power of 2?
325  bool isNPOT = ( tex_w != w ) || ( tex_h != h );
326 
327  // image has to be converted to GL_RGBA8 to avoid crash
328  QImage textureGL;
329 
330  // eventually scale to pot image if no hw support / core in GL 2.0
331  if (!openGLVersion(2,0) && isNPOT)
332  {
333  // because texture will only be accessed proportionally by texture coordinates, aspect ratio is of no concern
334  textureGL = QGLWidget::convertToGLFormat ( _image.scaled( tex_w, tex_h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
335  }
336  else
337  {
338  // use npot texture
339  tex_w = w;
340  tex_h = h;
341  textureGL = QGLWidget::convertToGLFormat ( _image );
342  }
343 
344  // enough texture mem?
345  if ( !Texture2D::checkTextureMem(GL_RGBA, tex_w, tex_h, GL_RGBA) ) {
346  std::cerr << "Can't load texture TextureNode::set_texture" << std::endl;
347  return;
348  }
349 
350  // Set the image
351  setTextureDataGL(activeTexture_ ,GL_TEXTURE_2D,tex_w,tex_h,GL_RGBA,GL_UNSIGNED_BYTE,textureGL.bits());
352 }
353 
354 //----------------------------------------------------------------------------
355 
356 
357 void
358 TextureNode::set_texture(const float * _image, int _width, int _height )
359 {
360  checkEmpty();
361 
362  // enough texture mem?
363  if ( !Texture2D::checkTextureMem(GL_RGBA, _width, _height, GL_RGBA) ) {
364  std::cerr << "Can't load texture TextureNode::set_texture" << std::endl;
365  return;
366  }
367 
368  // Set the image
369  setTextureDataGL(activeTexture_,GL_TEXTURE_2D,_width,_height,GL_RGBA,GL_FLOAT,_image);
370 }
371 
372 //----------------------------------------------------------------------------
373 
375 
376  // No texture generated yet!
377  if ( textures_.empty() ) {
378  textures_.resize(1);
379  activeTexture_ = 0;
380 // textures_[activeTexture_].id = 0;
381  Texture2D* t = new Texture2D();
382  t->gen();
383  textures_[activeTexture_].tex = t;
384  }
385 
386 }
387 
388 //----------------------------------------------------------------------------
389 
390 int TextureNode::available( GLuint _id ) {
391  // If the texture is found in the array return its id otherwise -1
392  for ( uint i = 0 ; i < textures_.size(); ++i )
393  if ( textures_[i].tex->id() == _id )
394  return i;
395 
396  return -1;
397 }
398 
399 //----------------------------------------------------------------------------
400 
401 bool TextureNode::read(const char* _filename, GLuint _id ) {
402  if ( available(_id) != -1 ) {
403  activeTexture_ = available(_id);
404  return read(_filename);
405  } else
406  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
407 
408  return false;
409 
410 }
411 
412 
413 //----------------------------------------------------------------------------
414 
415 
416 
417 void TextureNode::set_texture(const QImage& _image, GLuint _id) {
418 
419  checkEmpty();
420 
421  if ( available(_id) != -1 ) {
422  activeTexture_ = available(_id);
423  set_texture(_image);
424  } else
425  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
426 
427 }
428 
429 
430 //----------------------------------------------------------------------------
431 
432 
433 
434 void TextureNode::set_texture(const float * _image, int _width, int _height, GLuint _id) {
435 
436  checkEmpty();
437 
438  if ( available(_id) != -1 ) {
439  activeTexture_ = available(_id);
440  set_texture(_image,_width,_height);
441  } else
442  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
443 }
444 
445 
446 
447 //----------------------------------------------------------------------------
448 
449 
450 void TextureNode::set_texture(const unsigned char * _image, int _width, int _height, GLuint _id) {
451 
452  checkEmpty();
453 
454  if ( available(_id) != -1 ) {
455  activeTexture_ = available(_id);
456  set_texture(_image,_width,_height);
457 
458  } else
459  std::cerr << "Texture with id " << _id << " not handled by this Node!!!" << std::endl;
460 
461 }
462 
463 
464 //----------------------------------------------------------------------------
465 
466 
467 // add QImage _image as additional texture, using face_texture_index
468 GLuint
469 TextureNode::add_texture(const QImage& _image)
470 {
471  checkEmpty();
472 
473  textures_.resize(textures_.size()+1); // can't push_back, because glGenTextures needs a pointer
474 
475  // Generate new texture
476  textures_.back().tex = new Texture2D();
477 
478  activeTexture_ = int(textures_.size() - 1);
479 
480  // Set the image
481  set_texture(_image);
482 
483  // return the id of the new texture
484  return textures_.back().tex->id();
485 }
486 
487 
488 //----------------------------------------------------------------------------
489 
490 
491 void TextureNode::enter(GLState& _state , const DrawModes::DrawMode& _drawmode)
492 {
493  if ( _drawmode & ( DrawModes::SOLID_TEXTURED |
501  {
502  ACG::GLState::enable( GL_TEXTURE_2D );
503 
504  mipmapping_globally_active_ = _state.mipmapping_allowed();
505 
506  // Check if mipmapping status has changed
507  if(_state.mipmapping_allowed() != last_mipmapping_status_) {
508 
509  // Update mipmaps
510  updateMipmaps(mipmapping_globally_active_ && mipmapping_);
511 
512  // Keep track of changes
513  last_mipmapping_status_ = _state.mipmapping_allowed();
514 
515  }
516 
517  if ( !textures_.empty() ) {
518  textures_[activeTexture_].tex->bind();
519  }
520  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_ );
521 
522 // if (_drawmode & DrawModes::SOLID_FACES_COLORED_2DTEXTURED_FACE_SMOOTH_SHADED)
523 // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
524  }
525 }
526 
527 
528 //----------------------------------------------------------------------------
529 
530 
531 void TextureNode::leave(GLState& /* _state */ , const DrawModes::DrawMode& _drawmode)
532 {
533  if ( _drawmode & ( DrawModes::SOLID_TEXTURED |
540  {
541  ACG::GLState::bindTexture( GL_TEXTURE_2D, 0 );
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 //=============================================================================
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:76
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
void leave(GLState &_state, const DrawModes::DrawMode &_drawmode)
Unbind Texture.
Definition: TextureNode.cc:531
void disable_mipmapping()
Disable mipmapping.
Definition: TextureNode.cc:196
bool read(const char *_filename)
Uses a QImage to load the texture from the given file.
Definition: TextureNode.cc:114
void checkEmpty()
Check if a texture is already generated by this Node.
Definition: TextureNode.cc:374
DrawMode SOLID_2DTEXTURED_FACE
draw per halfedge textured faces
Definition: DrawModes.cc:102
DrawMode SOLID_2DTEXTURED_FACE_SHADED
draw per halfedge textured faces
Definition: DrawModes.cc:103
void enterPick(GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode)
Do nothing in picking.
Definition: TextureNode.cc:546
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
void applyTextureParameters(int _id)
Definition: TextureNode.cc:148
bool openGLVersion(const int _major, const int _minor)
Definition: gl.cc:95
DrawMode SOLID_FACES_COLORED_2DTEXTURED_FACE_SMOOTH_SHADED
draw per halfedge texture faces modulated with face colors with smooth shading
Definition: DrawModes.cc:110
bool activateTexture(GLuint _id)
Set active Texture.
Definition: TextureNode.cc:566
static void enable(GLenum _cap)
replaces glEnable, but supports locking
DrawMode SOLID_TEXTURED
draw textured faces
Definition: DrawModes.cc:94
DrawModes::DrawMode open_volume_mesh_texture_draw_modes_
OpenVolumeMesh DrawModes using textures.
Definition: TextureNode.hh:358
static void disable(GLenum _cap)
replaces glDisable, but supports locking
GLuint activeTexture()
Get active Texture.
Definition: TextureNode.cc:556
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
void set_texture(const QImage &_image)
Uses a QImage to set the texture.
Definition: TextureNode.cc:309
void updateMipmaps(bool _mipmap)
Build mip maps of textures that don&#39;t have one yet.
Definition: TextureNode.cc:248
DrawMode SOLID_ENV_MAPPED
draw environment mapped
Definition: DrawModes.cc:93
GLuint add_texture(const QImage &_image)
Add a texture to this node.
Definition: TextureNode.cc:469
virtual ~TextureNode()
Destructor.
Definition: TextureNode.cc:100
void enable_mipmapping()
Enable mipmapping.
Definition: TextureNode.cc:186
DrawMode SOLID_TEXTURED_SHADED
draw smooth shaded textured faces
Definition: DrawModes.cc:95
int activeTexture_
currently active texture
Definition: TextureNode.hh:352
void enter(GLState &_state, const DrawModes::DrawMode &_drawmode)
set default texture and states for the nodes children
Definition: TextureNode.cc:491
int available(GLuint _id)
check this node for a texture
Definition: TextureNode.cc:390
bool mipmapping_allowed() const
Get current global mipmapping state.
Definition: GLState.hh:1074
void leavePick(GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode)
Do nothing in picking.
Definition: TextureNode.cc:550