Texture won't render on simple quad


#1

Moved to a different thread as this is actually a different issue. The code provided is mine. This work is licensed under MIT.

main_class class:

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL42.*;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.glfw.GLFW.*;

import org.lwjgl.opengl.GL;
import org.lwjgl.glfw.GLFWImage;

/*
 * Created by Cinder SD on 2/19/2017.
 */
public class main_class implements Runnable {
    private final resource_parser_01 resource_04 = resource_parser_01.loads_images("res\\roguelike_cave_pack\\icon_04.png");
    private final resource_parser_01 resource_06 = resource_parser_01.loads_images("res\\roguelike_cave_pack\\icon_06.png");
    private int texture_ID;

    public boolean running = true;
    private long window;

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

    private void start() {
        Thread thread_00 = new Thread(this, "Dungeons Heart");
        thread_00.start(); running = true;
    }

    private void init() {
        if (!glfwInit()) System.out.println("Could not initialise opengl4.5. [FWERROR]");

        glfwWindowHint(GLFW_RESIZABLE, 0);
        glfwWindowHint(GLFW_DECORATED, 0);

        int wind_width = 1200;
        int wind_height = 800;
        window = glfwCreateWindow(wind_width, wind_height, "Dungeons Heart", NULL, NULL);
        if (window == NULL) System.out.println("Could not create our window. [FWERROR]");

        glfwSetWindowPos(window, 100, 100);
        glfwShowWindow(window);
        glfwMakeContextCurrent(window);

        GLFWImage image = GLFWImage.malloc(); GLFWImage.Buffer imagebf = GLFWImage.malloc(2);
        image.set(resource_04.get_width(), resource_04.get_heigh(), resource_04.get_image());
        imagebf.put(0, image);
        image.set(resource_06.get_width(), resource_06.get_heigh(), resource_06.get_image());
        imagebf.put(1, image);
        glfwSetWindowIcon(window, imagebf);

        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if (action == GLFW_RELEASE)
                return;
            switch (key) {
                case GLFW_KEY_ESCAPE:
                    glfwSetWindowShouldClose(window, true);  running = false;
                    break;
            }
        });
        glfwSetMouseButtonCallback(window,(window, button, action, mods) -> {
            if (action == GLFW_RELEASE)
                return;
            switch (button) {
                case GLFW_MOUSE_BUTTON_1:
                    System.out.println("MOUSE_1");
                    break;
                case GLFW_MOUSE_BUTTON_2:
                    System.out.println("MOUSE_2");
                    break;
                case GLFW_MOUSE_BUTTON_3:
                    System.out.println("MOUSE_3");
                    break;
            }
        });
        maze_generator.create_maze();

        GL.createCapabilities();
        glEnable(GL_DEPTH_TEST);
        glMatrixMode(GL_PROJECTION); glLoadIdentity();
        glOrtho(0, wind_width, wind_height, 0, 1, -1);

        texture_ID = resource_parser_02.parse_texture(1, 1);
    }

    private void loop() {
        while (!glfwWindowShouldClose(window)) {
            update();
            render();
        }
    }

    private void update() {
        glfwPollEvents();
    }

    private void render() {

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindTexture(GL_TEXTURE_2D, texture_ID);
        glEnable(GL_TEXTURE_2D);
        glBegin(GL_QUADS);
        glTexCoord2f(0, 1); glVertex2f(16, 48);
        glTexCoord2f(1, 1); glVertex2f(48, 48);
        glTexCoord2f(1, 0); glVertex2f(48, 16);
        glTexCoord2f(0, 0); glVertex2f(16, 16);
        glEnd();

        glfwSwapBuffers(window);
    }

    public void run() {
        try {
            init();
            loop();
        } finally { destroy(); }
    }

    private void destroy() {
        glfwDestroyWindow(window);
        glfwTerminate();
    }
}

resource_parser_01 class:

import static org.lwjgl.stb.STBImage.stbi_load;

import org.lwjgl.system.MemoryStack;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

/*
 * Created by Cinder SD on 2/27/2017.
 */
public class resource_parser_01 {
    public ByteBuffer get_image() {
        return this.image;
    }

    public int get_width() {
        return this.width;
    }

    public int get_heigh() {
        return this.heigh;
    }

    private ByteBuffer image;
    private int width, heigh;

    resource_parser_01(int width, int heigh, ByteBuffer image) {
        this.image = image;
        this.heigh = heigh;
        this.width = width;
    }
    public static resource_parser_01 loads_images(String path) {
        ByteBuffer image;
        int width, heigh;
        try (MemoryStack stack = MemoryStack.stackPush()){
            IntBuffer comp = stack.mallocInt(1);
            IntBuffer w = stack.mallocInt(1);
            IntBuffer h = stack.mallocInt(1);

            image = stbi_load(path, w, h, comp, 4);
            if (image == null) System.out.println("Could not load image resources. [STERROR]");

            width = w.get();
            heigh = h.get();
        }
        return new resource_parser_01(width, heigh, image);
    }
}

resource_parser_02 class:

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL42.*;

import java.nio.ByteBuffer;

/*
 * Created by Cinder SD on 2/28/2017.
 */
public class resource_parser_02 {
    private static resource_parser_01 tex_resources_01 = resource_parser_01.loads_images("res\\sprite1.png");

    public static int parse_texture(int row, int col) {

        ByteBuffer sprite_sheet = tex_resources_01.get_image();
        int texture_ID = glGenTextures();
        int width = tex_resources_01.get_width();
        int heigh = tex_resources_01.get_heigh();

        int xoffset = (col != 1 && col != 29) ? (col - 1) * 32 + 2 : (col - 1) * 32;
        int yoffset = (row != 1 && col != 18) ? (row - 1) * 32 + 2 : (row - 1) * 32;

        glBindTexture(GL_TEXTURE_2D, texture_ID);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexStorage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, width, heigh);
        glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, 32, 32, GL_RGBA, GL_UNSIGNED_BYTE, sprite_sheet);

        System.out.println("" + texture_ID); return texture_ID;
    }
}

Any insight is much appreciated, thank you for your time!


#2

Problem identified!

In resource_parser_02 replaced:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, width, heigh);

with

glTexStorage2D(GL_TEXTURE_2D, 1, GL_SRGB8_ALPHA8, width, heigh);

However, the glTexSubImage2D does not appear to work with width and height in pixels. The documentation does specify the datatype to be GLsizei (A non-negative binary integer, for sizes). As a result my texture is not cut properly. Not very useful.


#3

Glad you found the error. I missed that you’d put 0 for the number of levels in your earlier post and have been away from the computer since then.

glTexSubImage2D does work with pixel sizes for xoffset, yoffset, width and height.

What is your input texture like, what are you seeing as output, and what is wrong?


#4

Source image is a 984x610 divided in 29x18 sprites (32x32 sprite size) with 2 pixels space in-between them.

I’m trying to take the first sprite and use it as texture. I’m either seeing a pixel or two when i use 32 as width and height. And a jammed image when I increase that to 160.


#5

OK.

The first approach I’d try is simply to use the whole texture and then display only one of the sprites in the rendering. You may have issues with the fact that your image is a non-power of two size, I would recommend always using power of two size images if possible.

So use:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, heigh, GL_RGBA, GL_UNSIGNED_BYTE, sprite_sheet);

And in your render adjust the texture coordinates:

glTexCoord2f(0, 1.0f/18.0f); glVertex2f(16, 48);
glTexCoord2f(1.0f/29.0f, 1.0f/18.0f); glVertex2f(48, 48);
glTexCoord2f(1.0f/29.0f, 0); glVertex2f(48, 16);
glTexCoord2f(0, 0); glVertex2f(16, 16);

You may need to adjust these coordinates slightly, and you may find your image is upside down compared to what you expect.


#6

Thanks, for some reason glTexSubImage2d doesn’t behave as advertised in documentation. Using:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, widthh, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, sprite_sheets);

and calculating the sprites as you recommended works for me. The only issue I’m having now is transparency. My sprites are RGBA with transparent background, however my quad isn’t transparent. If I paint it black, my texture dissapears aswell. If it remains white, the texture is there.


#7

To get transparency working you will need blending. Try something like the following:

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);