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 <ACG/Utils/ImageConversion.hh>
59
60//== NAMESPACES ===============================================================
61
62
63namespace ACG {
64namespace 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
107bool
108TextureNode::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
127void
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
141void
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
200void TextureNode::setTextureDataGL ( GLuint _textureId,
201 GLenum _target,
202 GLint _width ,
203 GLint _height,
204 GLenum _format ,
205 GLenum _type,
206 const void * _data) {
207
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
244void 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
285void
286TextureNode::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
304void
305TextureNode::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 = ACG::Util::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 = ACG::Util::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
353void
354TextureNode::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
386int 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
397bool TextureNode::read(const char* _filename, GLuint _id ) {
398 if ( available(_id) != -1 ) {
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
413void TextureNode::set_texture(const QImage& _image, GLuint _id) {
414
415 checkEmpty();
416
417 if ( available(_id) != -1 ) {
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
430void TextureNode::set_texture(const float * _image, int _width, int _height, GLuint _id) {
431
432 checkEmpty();
433
434 if ( available(_id) != -1 ) {
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
446void TextureNode::set_texture(const unsigned char * _image, int _width, int _height, GLuint _id) {
447
448 checkEmpty();
449
450 if ( available(_id) != -1 ) {
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
464GLuint
465TextureNode::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
487void 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
530void 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
546void TextureNode::enterPick(GLState& /*_state*/ , PickTarget /*_target*/, const DrawModes::DrawMode& /*_drawMode*/ ) {
547
548}
549
550void 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//=============================================================================
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1911
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
bool mipmapping_allowed() const
Get current global mipmapping state.
Definition: GLState.hh:1096
void checkEmpty()
Check if a texture is already generated by this Node.
Definition: TextureNode.cc:370
void enter(GLState &_state, const DrawModes::DrawMode &_drawmode) override
set default texture and states for the nodes children
Definition: TextureNode.cc:487
int activeTexture_
currently active texture
Definition: TextureNode.hh:346
void leave(GLState &_state, const DrawModes::DrawMode &_drawmode) override
Unbind Texture.
Definition: TextureNode.cc:530
bool read(const char *_filename)
Uses a QImage to load the texture from the given file.
Definition: TextureNode.cc:108
DrawModes::DrawMode open_volume_mesh_texture_draw_modes_
OpenVolumeMesh DrawModes using textures.
Definition: TextureNode.hh:352
int available(GLuint _id)
check this node for a texture
Definition: TextureNode.cc:386
void applyTextureParameters(int _id)
Definition: TextureNode.cc:142
void updateMipmaps(bool _mipmap)
Build mip maps of textures that don't have one yet.
Definition: TextureNode.cc:244
void disable_mipmapping()
Disable mipmapping.
Definition: TextureNode.cc:190
virtual ~TextureNode()
Destructor.
Definition: TextureNode.cc:94
GLuint add_texture(const QImage &_image)
Add a texture to this node.
Definition: TextureNode.cc:465
GLuint activeTexture()
Get active Texture.
Definition: TextureNode.cc:556
void set_texture(const QImage &_image)
Uses a QImage to set the texture.
Definition: TextureNode.cc:305
void enterPick(GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode) override
Do nothing in picking.
Definition: TextureNode.cc:546
void enable_mipmapping()
Enable mipmapping.
Definition: TextureNode.cc:180
bool activateTexture(GLuint _id)
Set active Texture.
Definition: TextureNode.cc:566
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
void leavePick(GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode) override
Do nothing in picking.
Definition: TextureNode.cc:550
DrawMode SOLID_ENV_MAPPED
draw environment mapped
Definition: DrawModes.cc:87
DrawMode SOLID_TEXTURED_SHADED
draw smooth shaded textured faces
Definition: DrawModes.cc:89
DrawMode SOLID_2DTEXTURED_FACE
draw per halfedge textured faces
Definition: DrawModes.cc:96
DrawMode SOLID_2DTEXTURED_FACE_SHADED
draw per halfedge textured faces
Definition: DrawModes.cc:97
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_TEXTURED
draw textured faces
Definition: DrawModes.cc:88
PickTarget
What target to use for picking.
Definition: PickTarget.hh:74
Namespace providing different geometric functions concerning angles.
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129