Zaide Chris
Zaide Chris

Reputation: 361

GL_TEXTURE_2D_ARRAY in lwjgl not working

I'm having issues useing GL_TEXTURE_2D_ARRAY in lwjgl to replace a GL_TEXTURE_2D. All textures just show up as a plain white.What am I missing?

And does any one know of a simple example program that uses GL_TEXTURE_2D_ARRAY in lwjgl or at least an example program another C-based programming language that has beginning to end compile instructions?

What I want:

Image showing textures

What I get:

Image showing nontextured white cube

I've striped much of my project's logic out in attempt to minimize the code.

Test.java:

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.util.glu.GLU;

public class Test {
    private Texture3D texture;
    private VertexBuffer mainCube;

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

    public void run() throws Exception {
        this.setup();
        while (!Display.isCloseRequested()) {
            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
            this.render();
            Display.sync(60);
            Display.update();
        }
        this.destroy();
    }

    private void setup() throws Exception {
        Display.setTitle("Game");
        Display.setDisplayMode(new DisplayMode(600, 400));
        Display.create();
        Test.checkForGLError("setupDisplay");
        this.texture = new Texture3D("res/images/textures.png");
        this.texture.buildBuffer();
        this.texture.bufferData();
        Test.checkForGLError("setupTexture");
        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL11.GL_CULL_FACE);
        GL11.glCullFace(GL11.GL_BACK);
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GLU.gluPerspective(90.0f, 1.5f, 0.1f, 1000.0F);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glTranslatef(0, 0, -4);
        GL11.glEnable(GL12.GL_TEXTURE_3D);
        Test.checkForGLError("setupCamera");
        this.mainCube = new VertexBuffer();
        int vi0, vi1, vi2, vi3;
        // Top
        vi0 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, 1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 0f, 0f));
        vi1 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, 1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 1f, 0f));
        vi2 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, 1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 1f, 0f));
        vi3 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, 1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 0f, 0f));
        this.mainCube.addIndices(vi0, vi1, vi2);
        this.mainCube.addIndices(vi2, vi3, vi0);
        // Bottom
        vi0 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, -1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 0f, 1f));
        vi1 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, -1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 1f, 1f));
        vi2 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, -1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 1f, 1f));
        vi3 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, -1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 0f, 1f));
        this.mainCube.addIndices(vi0, vi1, vi2);
        this.mainCube.addIndices(vi2, vi3, vi0);
        // North
        vi0 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, 1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 0f, 2f));
        vi1 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, -1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 1f, 2f));
        vi2 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, -1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 1f, 2f));
        vi3 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, 1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 0f, 2f));
        this.mainCube.addIndices(vi0, vi1, vi2);
        this.mainCube.addIndices(vi2, vi3, vi0);
        // South
        vi0 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, 1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 0f, 3f));
        vi1 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, -1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 1f, 3f));
        vi2 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, -1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 1f, 3f));
        vi3 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, 1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 0f, 3f));
        this.mainCube.addIndices(vi0, vi1, vi2);
        this.mainCube.addIndices(vi2, vi3, vi0);
        // East
        vi0 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, 1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 0f, 4f));
        vi1 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, -1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 1f, 4f));
        vi2 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, -1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 1f, 4f));
        vi3 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(1f, 1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 0f, 4f));
        this.mainCube.addIndices(vi0, vi1, vi2);
        this.mainCube.addIndices(vi2, vi3, vi0);
        // West
        vi0 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, 1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 0f, 5f));
        vi1 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, -1f, -1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(0f, 1f, 5f));
        vi2 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, -1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 1f, 5f));
        vi3 = this.mainCube.addVertex(new VertexBuffer.Vertex().setVertexCoords(-1f, 1f, 1f, 1f).setColors(1f, 1f, 1f, 1f).setTextureCoords(1f, 0f, 5f));
        this.mainCube.addIndices(vi0, vi1, vi2);
        this.mainCube.addIndices(vi2, vi3, vi0);
        this.mainCube.buildBuffers();
        this.mainCube.bufferData();

        GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
        GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
        GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
        Test.checkForGLError("setupMainCube");
    }

    private void render() {
        GL11.glPushMatrix();
        {
            long currnet_timestamp = System.currentTimeMillis();
            GL11.glRotated((currnet_timestamp / 30.0) % 360.0, 1.0, 0.0, 0.0);
            GL11.glRotated((currnet_timestamp / 20.0) % 360.0, 0.0, 1.0, 0.0);
            GL11.glRotated((currnet_timestamp / 10.0) % 360.0, 0.0, 0.0, 1.0);
            this.texture.bind();
            {
                this.mainCube.render();
            }
            this.texture.unbind();
        }
        GL11.glPopMatrix();
        Test.checkForGLError("render");
    }

    private void destroy() {
        this.texture.destroyBuffer();
        this.mainCube.destroyBuffers();
        Display.destroy();
    }

    public static void checkForGLError(String string) {
        int errorFlag = GL11.glGetError();
        if (errorFlag != GL11.GL_NO_ERROR) {
            System.out.println(string + ": " + GLU.gluErrorString(errorFlag));
        }
    }
}

Texture3D.java:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import javax.imageio.ImageIO;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL30;

public class Texture3D {
    private static final int BYTES_PER_PIXEL = 4;

    public static BufferedImage loadImage(String loc) {
        try {
            File file = new File(loc);
            return ImageIO.read(file);
        } catch (IOException e) {
            // Error Handling Here
        }
        return null;
    }

    private int textureId;
    private int height = 1;
    private int width = 1;
    private int depth = 6;
    private int[] pixels;

    public Texture3D(String loc) {
        this.loadTexture(Texture3D.loadImage(loc));

    }

    void loadTexture(BufferedImage image) {
        this.width = image.getWidth();
        this.height = image.getHeight() / this.depth;
        this.pixels = new int[this.width * this.height * 6];
        image.getRGB(0, 0, this.width, this.height, this.pixels, 0, this.width);
    }

    public ByteBuffer buildPixelBuffer() {
        ByteBuffer pixelBuffer = BufferUtils.createByteBuffer(this.width * this.height * this.depth * Texture3D.BYTES_PER_PIXEL);
        for (int y = 0; y < (this.height * 6); y++) {
            for (int x = 0; x < this.width; x++) {
                int pixel = this.pixels[(y * this.width) + x];
                pixelBuffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
                pixelBuffer.put((byte) ((pixel >> 8) & 0xFF)); // Green
                // component
                pixelBuffer.put((byte) (pixel & 0xFF)); // Blue component
                pixelBuffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha
                // component
            }
        }
        pixelBuffer.flip();
        return pixelBuffer;
    }

    public void buildBuffer() {
        this.textureId = GL11.glGenTextures();
    }

    public void bufferData() {
        GL11.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, this.textureId);
        GL12.glTexImage3D(GL30.GL_TEXTURE_2D_ARRAY, 0, GL11.GL_RGBA8, this.width, this.height, this.depth, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, this.buildPixelBuffer());
        GL11.glTexParameteri(GL30.GL_TEXTURE_2D_ARRAY, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
        GL11.glTexParameteri(GL30.GL_TEXTURE_2D_ARRAY, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
        GL11.glTexParameteri(GL30.GL_TEXTURE_2D_ARRAY, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL30.GL_TEXTURE_2D_ARRAY, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
        GL11.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, 0);
    }

    public void bind() {
        GL11.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, this.textureId);
    }

    public void unbind() {
        GL11.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, 0);
    }

    public void destroyBuffer() {
        GL11.glDeleteTextures(this.textureId);
    }

}

VertexBuffer.java:

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.LinkedList;
import java.util.List;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;

public class VertexBuffer {
    public static class Vertex {
        public float[] pos;
        public float[] color;
        public float[] tex;

        Vertex setVertexCoords(float x, float y, float z, float w) {
            this.pos = new float[] { x, y, z, w };
            return this;
        }

        Vertex setColors(float r, float g, float b, float a) {
            this.color = new float[] { r, g, b, a };
            return this;
        }

        Vertex setTextureCoords(float s, float t, float r) {
            this.tex = new float[] { s, t, r };
            return this;
        }
    }

    public static final int stride = 11 * 4;
    public static final int vertexOffset = 0 * 4;
    public static final int colorOffset = 4 * 4;
    public static final int texCoordOffset = 8 * 4;
    List<Vertex> rawVertexs = new LinkedList<Vertex>();
    List<short[]> rawIndicesSets = new LinkedList<short[]>();
    private int vertexBufferHandle;
    private int indexBufferHandle;
    private int indexBufferLength;
    private boolean dirty = false;
    private boolean hasBuffers = false;

    public int addVertex(Vertex vertex) {
        this.rawVertexs.add(vertex);
        this.dirty = true;
        return this.rawVertexs.size() - 1;
    }

    public void addIndices(int index0, int index1, int index2) {
        this.rawIndicesSets.add(new short[] { (short) index0, (short) index1, (short) index2 });
        this.dirty = true;
    }

    public FloatBuffer getVertexBuffer() {
        FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(this.rawVertexs.size() * 11);
        for (Vertex vertex : this.rawVertexs) {
            verticesBuffer.put(vertex.pos);
            verticesBuffer.put(vertex.color);
            verticesBuffer.put(vertex.tex);
        }
        verticesBuffer.flip();
        return verticesBuffer;
    }

    public ShortBuffer getIndicesBuffer() {
        ShortBuffer indicesBuffer = BufferUtils.createShortBuffer(this.rawIndicesSets.size() * 3);
        for (short[] rawVertexIndexSet : this.rawIndicesSets) {
            indicesBuffer.put(rawVertexIndexSet);
        }
        indicesBuffer.flip();
        return indicesBuffer;
    }

    public int getIndicesCount() {
        return this.rawIndicesSets.size() * 3;
    }

    public void buildBuffers() {
        if (this.hasBuffers) {
            return;
        }
        this.vertexBufferHandle = GL15.glGenBuffers();
        this.indexBufferHandle = GL15.glGenBuffers();
    }

    public void bufferData() {
        if (!this.hasBuffers) {
            this.buildBuffers();
        }
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vertexBufferHandle);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, this.getVertexBuffer(), GL15.GL_STATIC_DRAW);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.indexBufferHandle);
        GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, this.getIndicesBuffer(), GL15.GL_STATIC_DRAW);
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
        this.indexBufferLength = this.getIndicesCount();
        this.dirty = false;
    }

    public void render() {
        if (this.dirty) {
            this.bufferData();
        }
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vertexBufferHandle);
        {
            GL11.glVertexPointer(4, GL11.GL_FLOAT, VertexBuffer.stride, VertexBuffer.vertexOffset);
            GL11.glColorPointer(4, GL11.GL_FLOAT, VertexBuffer.stride, VertexBuffer.colorOffset);
            GL11.glTexCoordPointer(2, GL11.GL_FLOAT, VertexBuffer.stride, VertexBuffer.texCoordOffset);
            GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.indexBufferHandle);
            {
                GL11.glDrawElements(GL11.GL_TRIANGLES, this.indexBufferLength, GL11.GL_UNSIGNED_SHORT, 0);
            }
            GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
        }
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    }

    void destroyBuffers() {
        if (!this.hasBuffers) {
            return;
        }
        GL15.glDeleteBuffers(this.vertexBufferHandle);
        GL15.glDeleteBuffers(this.indexBufferHandle);
    }
}

texture.png:

texture for covering cube

Upvotes: 3

Views: 455

Answers (1)

derhass
derhass

Reputation: 45362

It appears as if you are trying to use array textures with the fixed function pipeline. This is just not possible in the GL. You must use shaders if you want to access array textures. The GL11.glEnable(GL12.GL_TEXTURE_3D); is enabling a 3D texture, which you haven't bound, and GL_TEXTURE_2D_ARRAY is not a 3D texture, it is just reusing the TexImage3D() functions because of the similiarities of the input data layout.

If you really want to use the fixed function pipeline, you might be able to use a real 3D texture instead - and have to live with the drawbacks (filtering and mipmapping between layers, lower limit on texture dimensions and so on).

My advice would be to drop the deprecated fixed function pipeline and switch to shaders, though.

Upvotes: 1

Related Questions