OpenGLException while loading textures

Started by ryiden, March 24, 2007, 18:09:58

Previous topic - Next topic

ryiden

I have a problem with texture loading. I have a code example which works on my notebook very fine, but on my desktop computer an OpenGLException will be thrown:
org.lwjgl.opengl.OpenGLException: Invalid value (1281)
	at org.lwjgl.opengl.Util.checkGLError(Util.java:56)
	at org.lwjgl.opengl.Display.swapBuffers(Display.java:555)
	at org.lwjgl.opengl.Display.update(Display.java:571)
	at TexturedHouse.run(TexturedHouse.java:44)
	at TexturedHouse.main(TexturedHouse.java:23)

ryiden

After some code changes the example is working now, but the textured model is looking very bad:
import java.awt.Graphics;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Hashtable;
import javax.imageio.ImageIO;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.glu.GLU;

public class TexturedHouse
{
  private static boolean exit;

  public static void main(String[] args)
  {
    new TexturedHouse().run();
  }

  public void run()
  {
    if (Display.isCreated() == false)
    {
      try
      {
        Display.setTitle("Textured House");
        Display.setDisplayMode(new DisplayMode(640, 480));
        Display.setVSyncEnabled(true);
        Display.create();
        init();
        synchronized (this)
        {
          exit = false;
        }
        while (exit == false)
        {
          // call update
          Display.update();
          // check for exit
          if (Display.isCloseRequested())
          {
            synchronized (this)
            {
              exit = true;
            }
          }
          // the display is active
          else if (Display.isActive())
          {
            update();
            Display.sync(60);
          }
          // the display is inactive
          else
          {
            try
            {
              Thread.sleep(100);
            }
            catch (InterruptedException ie)
            {
              ie.printStackTrace();
            }
            update();
          }
        }
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }
      finally
      {
        Display.destroy();
      }
    }
  }

  public void init()
  {
    try
    {
      // load the image
      File file = new File("woodtexture.png");
      BufferedImage loadedImage = ImageIO.read(file);
      // obtain the texture size
      int textureWidth = 2;
      while (textureWidth < loadedImage.getWidth())
      {
        textureWidth *= 2;
      }
      int textureHeight = 2;
      while (textureHeight < loadedImage.getHeight())
      {
        textureHeight *= 2;
      }
      // create the texture image
      ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
      ComponentColorModel colorModel;
      WritableRaster raster;
      Hashtable<Object, Object> properties = new Hashtable<Object, Object>();
      BufferedImage textureImage;
      if (loadedImage.getColorModel().hasAlpha())
      {
        colorModel = new ComponentColorModel(colorSpace, new int[] { 8, 8, 8, 8 }, true, false,
                                             Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
        raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, textureWidth,
                                                textureHeight, 4, null);
        textureImage = new BufferedImage(colorModel, raster, false, properties);
      }
      else
      {
        colorModel = new ComponentColorModel(colorSpace, new int[] { 8, 8, 8, 0 }, false, false,
                                             Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, textureWidth,
                                                textureHeight, 3, null);
        textureImage = new BufferedImage(colorModel, raster, false, properties);
      }
      Graphics graphics = textureImage.getGraphics();
      graphics.fillRect(0, 0, textureWidth, textureHeight);
      graphics.drawImage(loadedImage, 0, 0, null);
      // create the texture buffer
      byte[] textureData = ((DataBufferByte) textureImage.getRaster().getDataBuffer()).getData();
      ByteBuffer textureBuffer = ByteBuffer.allocateDirect(textureData.length);
      textureBuffer.order(ByteOrder.nativeOrder());
      textureBuffer.put(textureData, 0, textureData.length);
      textureBuffer.flip();
      // init OpenGL
      GL11.glClearColor(0.3f, 0.5f, 0.8f, 1.0f);
      GL11.glClearDepth(1f);
      GL11.glDepthFunc(GL11.GL_LEQUAL);
      GL11.glEnable(GL11.GL_DEPTH_TEST);
      GL11.glEnable(GL11.GL_TEXTURE_2D);
      GL11.glBindTexture(GL11.GL_TEXTURE_2D, 1);
      GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
      GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
      GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
      GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
      GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
      GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_DECAL);
      GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, textureWidth, textureHeight, 0,
                        GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, textureBuffer);
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }

  public void update()
  {
    // clear the screen
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT
                 | GL11.GL_DEPTH_BUFFER_BIT);
    // the projection
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GLU.gluPerspective(15, 640f / 480f, 1, 1500);
    // the model
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glLoadIdentity();
    GL11.glTranslatef(0, 0, -1000f);
    GL11.glRotatef(75, 1f, 1f, 1f);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 1);
    // // house wall back
    GL11.glBegin(GL11.GL_POLYGON);
    GL11.glVertex3f(0, 50, -70);
    GL11.glTexCoord2f(0f, 0f);
    GL11.glVertex3f(-50, 10, -70);
    GL11.glTexCoord2f(2f, 0f);
    GL11.glVertex3f(-50, -60, -70);
    GL11.glTexCoord2f(2f, 1f);
    GL11.glVertex3f(50, -60, -70);
    GL11.glTexCoord2f(0f, 1f);
    GL11.glVertex3f(50, 10, -70);
    GL11.glEnd();
    GL11.glBegin(GL11.GL_QUADS);
    // // house wall left
    GL11.glTexCoord2f(0f, 0f);
    GL11.glVertex3f(-50, 10, -70);
    GL11.glTexCoord2f(2f, 0f);
    GL11.glVertex3f(-50, 10, 70);
    GL11.glTexCoord2f(2f, 1f);
    GL11.glVertex3f(-50, -60, 70);
    GL11.glTexCoord2f(0f, 1f);
    GL11.glVertex3f(-50, -60, -70);
    // // house wall right
    GL11.glTexCoord2f(0f, 0f);
    GL11.glVertex3f(50, 10, -70);
    GL11.glTexCoord2f(2f, 0f);
    GL11.glVertex3f(50, 10, 70);
    GL11.glTexCoord2f(2f, 1f);
    GL11.glVertex3f(50, -60, 70);
    GL11.glTexCoord2f(0f, 1f);
    GL11.glVertex3f(50, -60, -70);
    // // grounding
    GL11.glVertex3f(-50, -60, -70);
    GL11.glVertex3f(50, -60, -70);
    GL11.glVertex3f(50, -60, 70);
    GL11.glVertex3f(-50, -60, 70);
    // // house top left
    GL11.glTexCoord2f(0f, 0f);
    GL11.glVertex3f(-50, 10, -70);
    GL11.glTexCoord2f(1f, 0f);
    GL11.glVertex3f(0, 50, -70);
    GL11.glTexCoord2f(1f, 1f);
    GL11.glVertex3f(0, 50, 70);
    GL11.glTexCoord2f(0f, 1f);
    GL11.glVertex3f(-50, 10, 70);
    // // house top right
    GL11.glTexCoord2f(0f, 0f);
    GL11.glVertex3f(50, 10, -70);
    GL11.glTexCoord2f(1f, 0f);
    GL11.glVertex3f(0, 50, -70);
    GL11.glTexCoord2f(1f, 1f);
    GL11.glVertex3f(0, 50, 70);
    GL11.glTexCoord2f(0f, 1f);
    GL11.glVertex3f(50, 10, 70);
    GL11.glEnd();
    // // house top front
    GL11.glBegin(GL11.GL_TRIANGLES);
    GL11.glTexCoord2f(0f, 0f);
    GL11.glVertex3f(-50, 10, 70);
    GL11.glTexCoord2f(1f, 0f);
    GL11.glVertex3f(0, 50, 70);
    GL11.glTexCoord2f(1f, 1f);
    GL11.glVertex3f(50, 10, 70);
    GL11.glEnd();
  }
}

I changed the following lines from
// obtain the texture size
int textureWidth = loadedImage.getWidth();
int textureHeight = loadedImage.getHeight();

to
// obtain the texture size
int width = 2;
while (width < loadedImage.getWidth())
{
  width *= 2;
}
int height = 2;
while (height < loadedImage.getHeight())
{
  height *= 2;
}

I think the dimensions of the texture are oversized now, but if I use the exact dimensions for the texture, an OpenGLException will be thrown.
Is anybody here who can help me?

ryiden

Ok, solved, just resize the image to the power of 2:
      // obtain the texture size
      int textureWidth = 2;
      while (textureWidth < loadedImage.getWidth())
      {
        textureWidth *= 2;
      }
      int textureHeight = 2;
      while (textureHeight < loadedImage.getHeight())
      {
        textureHeight *= 2;
      }
      // scale the image if the dimensions does not match
      if (textureWidth != loadedImage.getWidth() || textureHeight != loadedImage.getHeight())
      {
        Image scaledImage = loadedImage.getScaledInstance(textureWidth, textureHeight, Image.SCALE_DEFAULT);
        loadedImage = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), BufferedImage.TYPE_3BYTE_BGR);
        Graphics2D graphics = loadedImage.createGraphics();
        graphics.drawImage(scaledImage, 0, 0, null);
        graphics.dispose();
      }

The image resizing should be applied to the TextureLoader of SpaceInvaders, because this class has the same problem.

Fool Running

This is a general working of OpenGL (it only accepts textures with a power-of-two size). Probably why it wasn't explicitly done.
If you need non-power-of-two textures, then there is an extension to allow it.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D