The textureViewer example

textureViewer

Loads image files and textures map polygons with it.

Pedagogical example that shows how to apply a texture on a 3D object. Inpired from the Qt texture example.

The Qt QImage class and its convertToGLFormat() function are used to load any image format. The image is resized so that its dimensions are powers of two if needed. Feel free to cut and paste.

textureViewer.h


#include <QGLViewer/qglviewer.h>

class Viewer : public QGLViewer
{
protected :
  virtual void init();
  virtual void draw();
  virtual void keyPressEvent(QKeyEvent *e);
  virtual QString helpString() const;

  void loadImage();

private :
  float ratio, u_max, v_max;
};

textureViewer.cpp


#include "textureViewer.h"

#include <qimage.h>
#include <qfiledialog.h>

using namespace qglviewer;
using namespace std;

void Viewer::init()
{
  restoreFromFile();

  // Enable GL textures
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  glEnable( GL_TEXTURE_2D );

  // Nice texture coordinate interpolation
  glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

  u_max = 1.0;
  v_max = 1.0;
  ratio = 1.0;

  loadImage();
  help();
}


void Viewer::draw()
{
  // Display the quad
  glNormal3f(0.0, 0.0, 1.0);
  glBegin(GL_QUADS);
  glTexCoord2f(0.0,   1.0-v_max);	glVertex2f(-u_max*ratio,-v_max);
  glTexCoord2f(0.0,   1.0);		glVertex2f(-u_max*ratio, v_max);
  glTexCoord2f(u_max, 1.0);		glVertex2f( u_max*ratio, v_max);
  glTexCoord2f(u_max, 1.0-v_max);	glVertex2f( u_max*ratio,-v_max);
  glEnd();
}


void Viewer::loadImage()
{
  QString name = QFileDialog::getOpenFileName(".", "Images (*.png *.xpm *.jpg)", this, "Choose", "Select an image");

  // In case of Cancel
  if (name.isEmpty())
    return;

  QImage img(name);

  if (img.isNull())
    {
      cerr << "Unable to load " << name << ", unsupported file format" << endl;
      return;
    }

  cout << "Loading " << name << ", " << img.width() << "x" << img.height() << " pixels" << endl;

  // 1E-3 needed. Just try with width=128 and see !
  int newWidth  = 1<<(int)(1+log(img.width() -1+1E-3) / log(2.0));
  int newHeight = 1<<(int)(1+log(img.height()-1+1E-3) / log(2.0));

  u_max = img.width()  / (float)newWidth;
  v_max = img.height() / (float)newHeight;

  if ((img.width()!=newWidth) || (img.height()!=newHeight))
    {
      cout << "Image size set to " << newWidth << "x" << newHeight << " pixels" << endl;
      img = img.copy(0, 0, newWidth, newHeight);
    }

  ratio = newWidth / (float)newHeight;

  QImage glImg = QGLWidget::convertToGLFormat(img);  // flipped 32bit RGBA

  // Bind the img texture...
  glTexImage2D(GL_TEXTURE_2D, 0, 4, glImg.width(), glImg.height(), 0,
	       GL_RGBA, GL_UNSIGNED_BYTE, glImg.bits());
}


void Viewer::keyPressEvent(QKeyEvent *e)
{
  switch (e->key())
    {
    case Qt::Key_L : loadImage(); break;
    default:         QGLViewer::keyPressEvent(e);
    }
}

QString Viewer::helpString() const
{
  QString text("<h2>T e x t u r e V i e w e r</h2>");
  text += "This pedagogical example illustrates how to texture map a polygon.<br>";
  text += "The Qt <i>QImage</i> class and its <i>convertToGLFormat()</i> function are used ";
  text += "to load an image in any format. The image is resized so that its dimensions ";
  text += "are powers of two if needed. Feel free to cut and paste.<br>";
  text += "Press <b>L</b>(oad) to load a new image.";
  return text;
}

main.cpp


#include "textureViewer.h"
#include <qapplication.h>

int main(int argc, char** argv)
{
  // Read command lines arguments.
  QApplication application(argc,argv);

  // Instantiate the viewer, show it on screen.
  Viewer viewer;
  viewer.show();

  // Set the viewer as the application main widget.
  application.setMainWidget(&viewer);

  // Run main loop.
  return application.exec();
}

Go back to the examples main page

Valid XHTML 1.0! Valid CSS! Last modified on Thursday, February 5, 2004.