Logo Search packages:      
Sourcecode: whitedune version File versions  Download package

NodeImageTexture.cpp

/*
 * NodeImageTexture.cpp
 *
 * Copyright (C) 1999 Stephen F. White
 * 
 * Modified by Aaron Cram - Now uses DevIL to load textures
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include "stdafx.h"

#include "swt.h"
#include "DuneApp.h"
#include "resource.h"

#include "NodeImageTexture.h"
#include "Scene.h"
#include "Proto.h"
#include "FieldValue.h"
#include "MFString.h"
#include "SFBool.h"
#include "SFInt32.h"
#include "Field.h"
#include "URL.h"
#ifdef HAVE_LIBDEVIL
# include <IL/ilu.h>
#else
# include "Image.h"
#endif
#include "Util.h"

enum {
    IMG_STATUS_UNLOADED,
    IMG_STATUS_LOADED,
    IMG_STATUS_ERROR
};

ProtoImageTexture::ProtoImageTexture(Scene *scene)
  : Proto(scene, "ImageTexture")
{
    url.set(
          addExposedField(MFSTRING, "url", new MFString(), FF_URL, NULL));
    repeatS.set(
          addField(SFBOOL, "repeatS", new SFBool(true)));
    repeatT.set(
          addField(SFBOOL, "repeatT", new SFBool(true)));
#ifdef HAVE_TEXTUREIMAGE_MODE
    mode.set(
          addField(SFINT32, "mode", new SFInt32(0), new SFInt32(0), 
                 new SFInt32(3)));
#endif
}

Node *
ProtoImageTexture::create(Scene *scene)
{ 
    return new NodeImageTexture(scene, this); 
}

NodeImageTexture::NodeImageTexture(Scene *scene, Proto *def)
  : Node(scene, def)
{
    _image = NULL;
    _textureWidth = 0;
    _textureHeight = 0;
    _imageStatus = IMG_STATUS_UNLOADED;
    _textureName = 0;
    _components = 0;
    _glColorMode = GL_RGB;          // default: no transparency

    _scaleRequired = false;

#ifdef HAVE_LIBDEVIL
    static bool il_needs_init = true;
    if (il_needs_init) {
        ilInit();
        iluInit();
        il_needs_init = false;
        ilEnable(IL_ORIGIN_SET);
        ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
    }

    ilGenImages(1, &_imageName);
    ilBindImage(_imageName);
#endif
}

NodeImageTexture::NodeImageTexture(const NodeImageTexture &node)
  : Node(node)
{
    _image = NULL;
    _textureName = 0;             // must load its own texture though
    _textureWidth = node._textureWidth;
    _textureHeight = node._textureHeight;
    _components=node._components;
    _glColorMode = node._glColorMode ;
    _imageStatus = node._imageStatus;
    _scaleRequired = node._scaleRequired;

#ifdef HAVE_LIBDEVIL
    ilGenImages(1, &_imageName);
    ilBindImage(_imageName);

    // copy image data, if needed
    if (node._imageStatus == IMG_STATUS_LOADED) {
        if (ilCopyImage(node._imageName)) {
            _image = ilGetData();
            if (_image) {
                _imageStatus = IMG_STATUS_LOADED;
            } else {
                _imageStatus = IMG_STATUS_ERROR;
                reportLoadError(NULL, NULL);
            }
        } else {
            _imageStatus = IMG_STATUS_ERROR;
            reportLoadError(NULL, NULL);
        }
    }
#else
    int size = _textureWidth * _textureHeight * _components;
    // copy image data, if any
    if (node._image) {
      _image = new unsigned char[size];
      memcpy(_image, node._image, size);
    }
#endif
}

NodeImageTexture::~NodeImageTexture()
{
    if (_textureName != 0) glDeleteTextures(1, &_textureName);
#ifdef HAVE_LIBDEVIL
    ilDeleteImages(1, &_imageName);
#else
    delete [] _image;
#endif
}

void
NodeImageTexture::setField(int field, FieldValue *value)
{
    if (field == url_Index()) {
      _imageStatus = IMG_STATUS_UNLOADED;
    }
    Node::setField(field, value);
}

void
NodeImageTexture::load()
{
    MFString         *urls = url();
    int               width, height;
    unsigned char  *data = NULL;
    bool errorflag=true;
    char *lastCheckedPath = NULL;

    for (int i = 0; i < urls->getSize(); i++) {
      MyString        path;
      URL       url(_scene->getURL(), urls->getValue(i));
      if (urls->getValue(i).length() == 0) continue;
      _scene->Download(url, &path);

#ifdef HAVE_LIBDEVIL
        errorflag=true;
      if (ilLoadImage((char *)(const char *)path)) {
            width = ilGetInteger(IL_IMAGE_WIDTH);
            height = ilGetInteger(IL_IMAGE_HEIGHT);
            _components = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
            if (_components == 1) {
                _glColorMode=GL_LUMINANCE;
                ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE);
            } else if (_components == 2) {
                _glColorMode=GL_LUMINANCE_ALPHA;
                ilConvertImage(IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE);
            } else if (_components == 3) {
                _glColorMode=GL_RGB;
                ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
            } else if (_components == 4) {
                _glColorMode=GL_RGBA;
                ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
            } else {
                reportLoadError((char *)(const char *)path, 
                                "Invalid image type: wrong number of components");
            _imageStatus = IMG_STATUS_ERROR;
            return;
          }
            errorflag=false;
            break;
        } else
            lastCheckedPath = strdup(path);

#else
      Image     image;
      if (image.Open(path)) {
          width = image.GetWidth();
          height = image.GetHeight();
          _components = image.GetComponents();
            if (_components==4)
               _glColorMode=GL_RGBA;
            else if (_components==3)
               _glColorMode = GL_RGB;
            else if (_components==2)
               _glColorMode = GL_LUMINANCE_ALPHA;
            else
               _glColorMode = GL_LUMINANCE;
          data = new unsigned char [width * height * _components];
          image.Read(data);
          break;
      }
#endif        
    }

#ifdef HAVE_LIBDEVIL
    if (errorflag) {
        _imageStatus = IMG_STATUS_ERROR;
        reportLoadError(lastCheckedPath, NULL);
        return;
    }
#else    
    if (data == NULL) { 
        _imageStatus = IMG_STATUS_ERROR;
        return;
    }
#endif        
        
    _textureWidth = 1;
    _textureHeight = 1;

    while (_textureWidth < width)
       _textureWidth <<= 1;

    while (_textureHeight < height)
       _textureHeight <<= 1;

#ifdef HAVE_LIBDEVIL
    if (width == _textureWidth && height == _textureHeight) {
        _scaleRequired = false;
    } else {
        _scaleRequired = true;
        iluImageParameter(ILU_FILTER, ILU_BILINEAR);
      if (!iluScale(_textureWidth, _textureHeight, _components)) {
            _imageStatus = IMG_STATUS_ERROR;
            reportLoadError(NULL, NULL);
            return;
        }
    }

    _image = ilGetData();
    if (_image) {
        _imageStatus = IMG_STATUS_LOADED;
    } else {
        _imageStatus = IMG_STATUS_ERROR;
        reportLoadError(NULL, NULL);
        return;
    }
#else
    delete [] _image;

    if (width == _textureWidth && height == _textureHeight) {
        _scaleRequired = false;
        _image = data;
    } else {
        _scaleRequired = true;
        _image = new unsigned char[_textureWidth * _textureHeight * 
                                     _components];
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
        gluScaleImage(_glColorMode, width, height, GL_UNSIGNED_BYTE, data,
                 _textureWidth, _textureHeight, GL_UNSIGNED_BYTE, _image);
      delete [] data;
    }
    _imageStatus = IMG_STATUS_LOADED;
#endif
    if (TheApp->isAnaglyphStereo()) {
        // change colors into grayscale values
        if ((_components == 3) || (_components == 4)) {
            int size = _textureWidth * _textureHeight * _components;
            for (int i = 0; i < size; i += _components) {
                int gray = (_image[i + 0] + _image[i + 1] + _image[i + 2]) / 3;
                _image[i + 0] = gray;
                _image[i + 1] = gray;
                _image[i + 2] = gray;
            }
        }
    }
}

#ifdef HAVE_LIBDEVIL
// If a NULL pointer is passed in, this function will report any errors
// that have happened inside the DevIL image library.  Otherwise, it will
// report whatever string is passed in.
void
NodeImageTexture::reportLoadError(char* filename, const char *error_msg)
{
    // If the user hits the cancel button, all subsequent errors will be ignored.
    // This way, if the VRML file contains 100 broken images, the user won't have
    // to hit the OK button 100 times.
    // FIXME:  This won't be reset until the program is restarted...
    static int mbReturn = 0;
    if (mbReturn == IDCANCEL) return;

    char errorstring[256];
    swLoadString(IDS_IMAGE_TEXTURE_ERROR, errorstring, 255);
    char buf[4096];
    if (error_msg) {                
         if (filename)
             mysnprintf(buf, 4095, "%s: %s\n", filename, error_msg);
         else
             mysnprintf(buf, 4095, "%s\n", error_msg);
    } else {
        ILenum Error;
        while ((Error = ilGetError()) != IL_NO_ERROR) {
            if (filename)
                 mysnprintf(buf, 4095, "%s: ilError #%d: %s\n", filename, Error, iluErrorString(Error));
            else
                 mysnprintf(buf, 4095, "ilError #%d: %s\n", Error, iluErrorString(Error));
            mbReturn = swMessageBox(TheApp->mainWnd(), buf, 
                                    errorstring, SW_MB_OKCANCEL, SW_MB_ERROR);
        }
    }
}
#endif

void
NodeImageTexture::bind()
{
    if (_imageStatus == IMG_STATUS_UNLOADED) {
      load();
      if (_textureName != 0) glDeleteTextures(1, &_textureName);
      _textureName = 0;
    }
    if (_imageStatus == IMG_STATUS_LOADED) {
      if (_textureName == 0) {
          glGenTextures(1, &_textureName);
          glBindTexture(GL_TEXTURE_2D, _textureName);
          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
          glTexImage2D(GL_TEXTURE_2D, 0, _components, 
                         _textureWidth, _textureHeight, 0,
                   _glColorMode, GL_UNSIGNED_BYTE, _image);
            GLenum error=glGetError();
            if (error!=0)
               {
               /* what's wrong here with "invalid value" ? */
               fprintf(stderr,"GL Error: %s\n",gluErrorString(error));
               }

      } else {
          glBindTexture(GL_TEXTURE_2D, _textureName);
      }
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
                  repeatS()->getValue() ? GL_REPEAT : GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
                  repeatT()->getValue() ? GL_REPEAT : GL_CLAMP);
      glEnable(GL_TEXTURE_2D);
#ifdef HAVE_TEXTUREIMAGE_MODE
      switch (mode()->getValue()) {
        case 1:
          glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
          glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
          glEnable(GL_TEXTURE_GEN_S);
          glEnable(GL_TEXTURE_GEN_T);
          break;
        case 2:
          glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
          glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
          glEnable(GL_TEXTURE_GEN_S);
          glEnable(GL_TEXTURE_GEN_T);
          break;
        case 3:
          glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
          glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
          glEnable(GL_TEXTURE_GEN_S);
          glEnable(GL_TEXTURE_GEN_T);
          break;
      }
#endif
    }
}

void
NodeImageTexture::unbind()
{
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
}

int
NodeImageTexture::isLoaded()
{
    return _imageStatus == IMG_STATUS_LOADED;
}

Generated by  Doxygen 1.6.0   Back to index