-1

I'm having issues loading a texture onto my triangle strips. I'm following Anton Gerdelan's tutorial, and after failing with my main program, I went back to the basics and just tried to make a plain square and put his texture on it (the skull and crossbones).

I completely copy and pasted code from his "Hello Triangle" page, which worked, but once trying to fit in code from his texture tutorial above (and changing the triangle to a square), all I'm getting is a big white square with no texture.

I've checked the status of my shaders with glGetShaderiv() and they returned positive, I checked the image I loaded to see if the pixel data was sensible, so I believe my error is in declaring my VBOs, or the order/parameters in which I'm using them.

Here's the complete code which I copied, which compiles fine in Visual Studio 2013, except the output isn't what is expected.

I am using the static libraries of GLEW and GLFW, along with the STBI Image header

#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GL/glfw3.h> // GLFW helper library
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>

const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"layout (location=1) in vec2 vt; // per-vertex texture co-ords"
"out vec2 texture_coordinates; "
"void main () {"
"  gl_Position = vec4 (vp, 1.0);"
"  texture_coordinates = vt; "
"}";

const char* fragment_shader =
"#version 400\n"
"in vec2 texture_coordinates;"
"uniform sampler2D basic_texture;"
"out vec4 frag_colour;"
"void main () {"
"vec4 texel = texture(basic_texture, texture_coordinates);"
"frag_colour = texel; "
"}";

float points[] = {
    -0.5f, -0.5f, 0.0f,
    -0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    0.5f, 0.5f, 0.0f

};

float texcoords[] = {
    0.0f, 1.0f,
    0.0f, 0.0f,
    1.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0
};

GLFWwindow* window;
unsigned int vt_vbo;
unsigned int tex = 0;
GLuint vao = 0;
GLuint vbo = 0;
GLuint shader_programme;

void initializeGL(){
    // start GL context and O/S window using the GLFW helper library
    if (!glfwInit()) {
        printf("ERROR: could not start GLFW3\n");
        return;
    }

    window = glfwCreateWindow(640, 480, "Texture Test", NULL, NULL);
    if (!window) {
        printf("ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return;
    }
    glfwMakeContextCurrent(window);

    // start GLEW extension handler
    glewExperimental = GL_TRUE;
    glewInit();

    // get version info
    const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
    const GLubyte* version = glGetString(GL_VERSION); // version as a string
    printf("Renderer: %s\n", renderer);
    printf("OpenGL version supported %s\n", version);

    // tell GL to only draw onto a pixel if the shape is closer to the viewer
    glEnable(GL_DEPTH_TEST); // enable depth-testing
    glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
}

void startShaders(){

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vertex_shader, NULL);
    glCompileShader(vs);
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fragment_shader, NULL);
    glCompileShader(fs);

    shader_programme = glCreateProgram();
    glAttachShader(shader_programme, fs);
    glAttachShader(shader_programme, vs);
    glLinkProgram(shader_programme);
    GLint vsstat;
    glGetShaderiv(vs, GL_COMPILE_STATUS, &vsstat);
    GLint fsstat;
    glGetShaderiv(fs, GL_COMPILE_STATUS, &fsstat);
    printf("%i\n%i\n", vsstat, fsstat);
}

void loadImage(){
    int x, y, n;
    int force_channels = 4;
    unsigned char* image_data = stbi_load("skulluvmap.png", &x, &y, &n, force_channels);
    if (!image_data) {
        printf("ERROR: could not load %s\n", "skulluvmap.png");
    }

    int width_in_bytes = x * 4;
    unsigned char *top = NULL;
    unsigned char *bottom = NULL;
    unsigned char temp = 0;
    int half_height = y / 2;


    for (int row = 0; row < half_height; row++) {
        top = image_data + row * width_in_bytes;
        bottom = image_data + (y - row - 1) * width_in_bytes;
        for (int col = 0; col < width_in_bytes; col++) {
            temp = *top;
            *top = *bottom;
            *bottom = temp;
            top++;
            bottom++;
        }
    }
    printf("first 4 bytes are: %i %i %i %i\n",
        image_data[0], image_data[1], image_data[2], image_data[3]
        );
    glGenTextures(1, &tex);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
    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_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

void generateBuffers(){
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), points, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(0); // don't forget this!

    glGenBuffers(1, &vt_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), texcoords, GL_STATIC_DRAW);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(1); // don't forget this!
}

void mainLoop(){
    while (!glfwWindowShouldClose(window)) {
        // wipe the drawing surface clear
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
        int tex_loc = glGetUniformLocation(shader_programme, "basic_texture");
        glUseProgram(shader_programme);
        glUniform1i(tex_loc, 0); // use active texture 0
        // draw points 0-4 from the currently bound VAO with current in-use shader
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        // update other events like input handling 
        glfwPollEvents();
        // put the stuff we've been drawing onto the display
        glfwSwapBuffers(window);
    }
}

int main() {

    initializeGL();
    startShaders();
    loadImage();
    generateBuffers();
    mainLoop();

    // close GL context and any other GLFW resources
    glfwTerminate();
    return 0;
}
klh
  • 605
  • 7
  • 23
Shotoku
  • 13
  • 4
  • Can you try adding a `layout (location=0)` before `in vec3 vp;` in the vertex shader? You're not forcing the position attribute to be at location 0 otherwise. – Reto Koradi Jun 11 '14 at 04:38

1 Answers1

1

You're misusing your second buffer which is supposed to be the buffer with texcoords. So what you really want to achieve is having a pair of texture coordinates for every vertex. It means that you texcoords array should in fact store 4 pairs because you have 4 triples in the points array. So that's the first fix. You probably want it to look like:

float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 1.0,
};

Then in the generateBuffers, your vt_vbo is wrong. The data should be passed this way:

glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), texcoords, GL_STATIC_DRAW);

because you only want to pass 8 values there. 2 texcoords for each vertex.

Edit:

This however, doesn't fully explain why your texture doesn't appear at all. I primarily thought that there might be a problem with your texcoords pointer but it doesn't seem to be the case.

Jon Cage
  • 36,366
  • 38
  • 137
  • 215
Elvithari
  • 834
  • 1
  • 8
  • 13
  • This code uses generic vertex attributes. `glVertexAttribPointer(1, ..)` sets the texture coordinates. `glTexCoordPointer()` is for fixed function vertex attributes, and it would be wrong to use it here. – Reto Koradi Jun 10 '14 at 14:38
  • @Reto Koradi: Good point, my bad. But anyways, is it safe to assume that the texture location is 1? Shouldn't something like "glGetAttribLocation(MyShader, "InTexCoord0");" be used to retrieve that location? – Elvithari Jun 10 '14 at 15:10
  • Location is specified in vertex shader's `layout`. It is 1 as long as application haven't redefined it manually. – keltar Jun 10 '14 at 15:31
  • Right. On the other hand, adding a `layout(location=0)` directive for the position would be a good idea. – Reto Koradi Jun 10 '14 at 15:53