0

my problem is that while loading any type of image with the library STB image I get the next error: BAD PNG SIG, even if It's not even a PNG, all the code worked before I tried making an OBJECT class as I'm learning OpenGL, now the results that I get are the next:

enter image description here

First I get no apparent errors so far apart to the fact that I should be seeing two textures and not only the crate one,

and the other thing that happens if i run the program but with a different texture is that i get a debugBreak:
enter image description here

The codes for the different parts of the texture Generation/Loading are the next:

Texture creating/adding:

TEXTURE tex1("res/textures/container.jpg", FILTER_LINEAR, GL_RGB, GL_TEXTURE_2D);

TEXTURE tex2("res/textures/dog.jpg", FILTER_NEAREST, GL_RGBA, GL_TEXTURE_2D);

box1.AddTextures(tex1);

box1.AddTextures(tex2);

This is the texture class:

class TEXTURE{

private:

    unsigned int m_TextureID;
    std::string m_filepath;
    int m_width, m_height, m_BPP;
    unsigned int m_TextureType;

public:

    TEXTURE(std::string filepath, FILTERING_OPTIONS opt, unsigned int RGB_CHANNEL, unsigned int TEXTURE_TYPE, bool FLIP_IMAGE = 0, bool MIPMAP = 1);
    ~TEXTURE();


    void Bind(unsigned int slot = 0);

    void Unbind();


    inline int GetWidth() const { return m_width; }
    inline int GetHeight() const { return m_height; }

};

And its constructor is the next:

TEXTURE::TEXTURE(std::string filepath, FILTERING_OPTIONS opt, unsigned int RGB_CHANNEL, unsigned int TEXTURE_TYPE, bool FLIP_IMAGE, bool MIPMAP) : m_filepath(filepath), m_TextureType(TEXTURE_TYPE){

    //stbi_set_flip_vertically_on_load(FLIP_IMAGE);
    stbi_set_flip_vertically_on_load(1);
    glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT));
    glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT));

    float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
    glCall(glTexParameterfv(TEXTURE_TYPE, GL_TEXTURE_BORDER_COLOR, borderColor));


    if (MIPMAP) {

        switch (opt)
        {
        
        case FILTER_NEAREST:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
            break;
        
        case FILTER_LINEAR:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;
        
        case BOTH:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;
        
        default:

            std::cerr << "[Error]: Wrong option parameter" << std::endl;

            return;
            break;
        }

    }
    else {

        switch (opt)
        {

        case FILTER_NEAREST:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
            break;

        case FILTER_LINEAR:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;

        case BOTH:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;

        default:

            std::cerr << "[Error]: Wrong option parameter" << std::endl;

            return;
            break;
        }

    }

    
    unsigned char* data = stbi_load(filepath.c_str(), &m_width, &m_height, &m_BPP, 0);

    glCall(glGenTextures(1, &m_TextureID));

    glCall(glBindTexture(m_TextureType, m_TextureID));

    std::cerr << stbi_failure_reason() << std::endl;

    if (data)
    {
        glCall(glTexImage2D(TEXTURE_TYPE, 0, GL_RGB, m_width, m_height, 0, RGB_CHANNEL, GL_UNSIGNED_BYTE, data));
        glCall(if (MIPMAP) glGenerateMipmap(TEXTURE_TYPE));
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    };
    stbi_image_free(data);



}

This is the texture bind function:

void TEXTURE::Bind(unsigned int slot){

    glCall(glActiveTexture(GL_TEXTURE0 + slot));
    glCall(glBindTexture(m_TextureType, m_TextureID));


}

And the loading is beeing made by the OBJECT class:

This adds the texture to a vector:

void OBJECT::AddTextures(TEXTURE texture){
    textures.push_back(texture);

}

and this loads the OBJECT(and the textures):

void OBJECT::Show(bool INDEXED, callbackFunction preRenderFunction){

    vb.Bind();
    va.Bind();
    shader.Bind();
    shader.Use();

    for (unsigned int i = 0; i < textures.size(); i++) {

        textures[i].Bind(i);

    }

    preRenderFunction(this);

    if (INDEXED) {
        ib.Bind();
        glCall(glDrawElements(GL_TRIANGLES, ib.GetLength() , GL_UNSIGNED_INT, 0));
        
    }else glDrawArrays(GL_TRIANGLES, 0, vb.GetLength());

}

This is the shader bind and use functions

void SHADER::Bind(){
    glCall(glUseProgram(m_ShaderProgramID));

}

void SHADER::Use(){

    glCall(glUseProgram(m_ShaderProgramID));

}

This is the vertex shader:

#version 330 core
layout (location = 0) in vec3 aPos; // the position variable has attribute position 0
layout (location = 1) in vec2 aTexCoord;

out vec3 vertexColor; // specify a color output to the fragment shader
out vec2 TexCoord;


uniform mat4 transform;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 MVP;

void main()
{
    gl_Position = projection * view * model * transform * vec4(aPos, 1.0); // see how we directly give a vec3 to vec4's constructor
    //gl_Position = MVP* vec4(aPos, 1.0);
    //gl_Position = projection * view * model * vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

This is the fragment shader:

#version 330 core
out vec4 FragColor;
  
in vec3 vertexColor; // the input variable from the vertex shader (same name and same type)  
in vec2 TexCoord;

uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float blend;

void main()
{
    //FragColor = texture(texture2, vec2(TexCoord.x, TexCoord.y * -1 ));
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, vec2(TexCoord.x, TexCoord.y * -1 )) / 10, blend);
}

That all the code i think its relevant, also, here is the file tree of my project(i'm using Visual Studio btw):

C:.
├───res
│   ├───shaders
│   └───textures
├───src
│   ├───include
│   └───vendor
│       ├───glm
│       │   ├───detail
│       │   ├───ext
│       │   ├───gtc
│       │   ├───gtx
│       │   └───simd
│       ├───imgui
│       └───stb_image
└───x64
    ├───Debug
    │   └───OpenGL-PLSDFMTT.tlog
    └───Release
        └───OpenGL-PLSDFMTT.tlog

I tried using the debugger of VS for watching what was happening, in the case that it didn't crash the data pointer to the image data was empty (the data was empty), and when it had data it crashed, I tried reviewing my logic, but it all seemed to be ok, that's all I tried (all this in a lapse of 4 hours).

11
  • Only call stbi_failure_reason() when something actually fails. The message you're seeing doesn't mean anything if the load succeeded. Commented Sep 13, 2023 at 2:58
  • Could you show the code of TEXTURE::Bind()? I guess you bind the textures to different texture image units? Commented Sep 13, 2023 at 5:52
  • And shader.Bind() uses the specific texture image units to set the sampler uniforms? Best to also show the shader code. Commented Sep 13, 2023 at 6:03
  • I've added what you asked for @ErdalKüçük Commented Sep 13, 2023 at 22:40
  • Where is the texture bind source? Commented Sep 14, 2023 at 0:06

1 Answer 1

2

Before you include the stbi_image header file in one C or C++ source file to create the implementation, do

#define STB_IMAGE_IMPLEMENTATION

alternatively, add

#define STBI_FAILURE_USERMSG //generate user friendly error messages

afterwards

#include "stb_image.h"

Once the stbi_image implementation has been included, to load an image, do

unsigned char *pixels = stbi_load(filename, &width, &height, &channels, 0);

but before doing anything else, one should do the mandatory error checking

if (!pixels) {
    std::cout
    << "unable to load image: "
    << stbi_failure_reason() 
    << "\n";
    //throw;
}

From now on, one can safely assume that the image has been loaded and the values in the fields pixels, width, height and channels are safe to use.

Additional checks, e.g. if the dimensions are power of two (important for pixel unpack alignment), the number of channels (pixel format), and so on, are required for a successful (desired) result.


To set the pixel unpack alignment before uploading the pixel data, do

glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //default is 4

Furthermore

TEXTURE tex2("res/textures/dog.jpg", FILTER_NEAREST, GL_RGBA, GL_TEXTURE_2D);

what if the image file does not have an alpha channel (what happens to be the case with jpeg encoded images), then the call to glTexImage2D will fail, because you're passing an invalid format argument (which does not match the pixel data). Therefore, check how many channels your image has and depending on that, use the proper format argument.

#1 -> GL_RED
#2 -> GL_RG
#3 -> GL_RGB
#4 -> GL_RGBA

It is possible to force stbi to add additional channels, for that you'll have to set the last parameter of stbi_load to the desired number of channels, 0 means to take the number of channels stored in the image file.

Instead of loading the whole image, one can do

stbi_info(filename, &width, &height, &channels);

which loads only the header of the image file (most image formats do contain a header with all the relevant information).


Once the data has been successfully loaded and uploaded to the GPU, its time to bind the textures to specific texture image units.

The shader has also to be notified, via setting the according uniform variables, e.g.

//bind tex to unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, tex);

//set the value of the uniform located at sampler_loc to the
//unit where the texture is bound to, here 0
glProgramUniform1i(prog, sampler_loc, 0);
Sign up to request clarification or add additional context in comments.

8 Comments

Hi, when I added #define STBI_FAILURE_USERMSG and the error handling you gave me, now stbi does not give me errors, but the image still not loading, when I pass the debugger when loading the image that shows up the data pointer has a super long string, but with the image that doesn't load it has no data other than the pointer itself, the pointer is 0 by the way, additional the second sampler that should have the image that is not loading has the image of the first sampler
Just as a reminder, if stbi_load returns a null pointer (nullptr), then the loading of the image failed. The reason can be queried via stbi_failure_reason(). The macro STBI_FAILURE_USERMSG (if defined) gives more user friendly error messages. If the image could be loaded (returned pointer is not null) then (and only then) continue to upload the image data to the GPU. By doing that, some rules have to be considered (described in my answer above).
Once that is done, then you have to bind the textures to specific texture image units, via glActiveTexture(GLenum) and glBindTexture(GLuint)) or in one step via glBindTextureUnit(GLuint, GLuint) (highly recommended to read the specs).
After that, set the sampler variables of the shader with the values of the specific units (in short, the sampler var in the shader, is the value - index - of the texture image unit). If your shader displays the wrong texture, then either you've bound the wrong texture to the wrong unit, or passed the wrong unit (via glProgramUniform) to the shader. That is why i asked you to submit your texture bind function.
Now it returns a pointer to nothing, the "text view" shows 0 characters
|

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.