2

I'm trying to port a C# application to Java, and I'm currently translating OpenGL code. In the C# app was used OpenTK, in the Java one I chose JOGL. When I try to create textures, the program throws an exception. Here is the code which is causing troubles:

            BMD0.Model.ModelData.Material.MatDef mat = (BMD0.Model.ModelData.Material.MatDef) model.model.mdlData[0].material.material[i];
            ImageData tmp_tex = Nsbtx.getTexture(tex, mat.texID, mat.palID).getImageData();
            gl.glBindTexture(GL2.GL_TEXTURE_2D, texturesID.get(i));
            ByteBuffer tmp_tex_data = ByteBuffer.allocate(tmp_tex.data.length);
            tmp_tex_data.put(tmp_tex.data);
            tmp_tex_data.flip();
            gl.glTexImage2D(texturesID.get(i), 0, GL2.GL_RGB, tmp_tex.width, tmp_tex.height, 0, GL2.GL_RGB, GL2.GL_UNSIGNED_BYTE, tmp_tex_data);
            texturesGL.put(i, texturesID.get(i));

The exception is this:

java.lang.IndexOutOfBoundsException: Required 192 remaining bytes in buffer, only had 32

I'm using SWT's ImageData to load an image I have in the RAM (it's not an external file) and it's only 32 byte long! Why is JOGL expecting so much bytes?!

This is one of my first program with OpenGL, so I'm not that expert...

EDIT: This is the corresponding C# code:

        int id = GL.GenTexture();
        GL.BindTexture(TextureTarget.Texture2D, id);

        Bitmap bmp = BTX0.GetTexture(pluginHost, tex, num_tex, num_pal);
        System.Drawing.Imaging.BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);

        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
            OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmp_data.Scan0);

        bmp.UnlockBits(bmp_data);

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Repeat);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Repeat);
        return id;
8
  • What are tex_width and tex_height? 32 bytes is not much data for an image... It would be enough for something like 2x4 pixels. Commented Aug 29, 2015 at 17:17
  • They are respectively texture width and texture height. Yes the image should be 4x4 pixel Commented Aug 29, 2015 at 18:00
  • 1
    2x4 pixels wouldn't work correctly here though, a row width of 2 would cause alignment issues with 8-bit RGB image data. 2 pixels * 3-bytes each means that the second, third and forth rows would begin on 3-byte boundaries instead of 4-byte. The 2nd and 4th rows would be misaligned. That said, 4x4 pixels at 3-bytes each is 48-bytes not 32. Commented Aug 29, 2015 at 18:15
  • 1
    8*8*3 = 192, that explains why the buffer is expected to be 192-bytes in length. You are going to have to unpallettize that image because glTexImage2D (...) does not work that way, it wants RGB triplets (1-byte per component, 3 components). For what you are discussing to work, it seems you have 4-bit palette entries. So some sort of 16 color image. Commented Aug 29, 2015 at 23:52
  • 1
    Andon is very close to the explanation, such tests are done internally by JOGL before passing the data to OpenGL, it's better than a crash. By the way, rather use Buffers.newDirectByteBuffer() instead of passing an indirect NIO buffer to JOGL. Commented Aug 30, 2015 at 9:40

1 Answer 1

2

Ok, I've solved by un-indexing everything and making RGBA (there was also alpha values) values.

            BMD0.Model.ModelData.Material.MatDef mat = (BMD0.Model.ModelData.Material.MatDef) model.model.mdlData[0].material.material[i];
            ImageData tmp_tex = Nsbtx.getTexture(tex, mat.texID, mat.palID).getImageData();
            gl.glBindTexture(GL2.GL_TEXTURE_2D, texturesID.get(i));
            ByteBuffer tmp_tex_data = ByteBuffer.allocate(tmp_tex.height * tmp_tex.width * 4);
            PaletteData pal = tmp_tex.palette;
            for (int h = 0; h < tmp_tex.height; h++) {
                for (int w = 0; w < tmp_tex.width; w++) {
                    tmp_tex_data.put((byte) pal.getRGB(tmp_tex.getPixel(w, h)).red);
                    tmp_tex_data.put((byte) pal.getRGB(tmp_tex.getPixel(w, h)).green);
                    tmp_tex_data.put((byte) pal.getRGB(tmp_tex.getPixel(w, h)).blue);
                    tmp_tex_data.put((byte) tmp_tex.getAlpha(w, h));
                }
            }
            tmp_tex_data.flip();
            gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGBA, tmp_tex.width, tmp_tex.height, 0, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, tmp_tex_data);
            texturesGL.put(i, texturesID.get(i));
Sign up to request clarification or add additional context in comments.

3 Comments

Anyway, you should use GLBuffers as gouessej suggested you
Ok so I'll try them ;)
When you feel ready and confident, you could also "upgrade" to samplers, come on jogl forum/irc if you need help on how to do it ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.