0

I am using OpenGL 2.1 in my academic work to create a 3D scene. I have a 24-bit BMP file, a texture for a cube side, that is loaded manually into the memory.

Straight to the problem: displayed texture has some excess pixels at the lower left corner. BMP file, of course, doesn't have these pixels, it has a full black border. Here's the result:

Arrows point to extra pixels

Seems like the data loaded from file is OK - pixels in a row after excess once are the same as in file, checked with another varicolored BMP. Here's the function I use to create texture from BMP:

GLuint CreateTextureFromBMP (const char path [])
{
    unsigned char header [54];
    unsigned int  data_position, width, height, image_size;
    unsigned char * data;

    FILE * file = fopen (path, "rb");
    fread (header, sizeof (char), 54, file);

    data_position = *(int *)&(header [0x0A]);
    image_size    = *(int *)&(header [0x22]);
    width         = *(int *)&(header [0x12]);
    height        = *(int *)&(header [0x16]);

    if (image_size == 0)
        image_size = width * height * 3;
    if (data_position == 0)
        data_position = 54;

    data = (unsigned char *) malloc (sizeof (unsigned char) * image_size);
    fread (data, sizeof (char), image_size, file);
    free (data);
    fclose (file);

    GLuint texture_id;
    glGenTextures (1, &texture_id);
    glBindTexture (GL_TEXTURE_2D, texture_id);

    glTexImage2D (GL_TEXTURE_2D, 0, 3, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    return texture_id;
}

I tried using different parameters in glTexImage2D and glTexParameteri functions, but still it change nothing. Here's the render scene function:

void RenderScene (int arg)
{
    static GLuint texture_id = CreateTextureFromBMP ("cube_blue.bmp");

    glEnable (GL_TEXTURE_2D);
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
    glEnableClientState (GL_VERTEX_ARRAY);
    glActiveTexture (GL_TEXTURE0);

    GLfloat vertices  [] = { ... };
    GLfloat texcoords [] = { ... };
    GLubyte indices   [] = { ... };

    glVertexPointer   (3, GL_FLOAT, 0, vertices);
    glTexCoordPointer (2, GL_FLOAT, 0, texcoords);

    glPushMatrix ();
        glBindTexture   (GL_TEXTURE_2D, texture_id);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glColor3f (1.0f, 1.0f, 1.0f);
        glDrawElements (GL_QUADS, 24, GL_UNSIGNED_BYTE, indices);
    glPopMatrix ();

    glDisable (GL_TEXTURE_2D);
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
    glDisableClientState (GL_VERTEX_ARRAY);
}

Any ideas where to look for the mistake?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
CoSalamander
  • 121
  • 7
  • 1
    try use `glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);` Also did you [reformat the BMP pixel data to remove align bytes](https://stackoverflow.com/a/55277088/2521214) ? btw is this for [Rubi'k cube app](https://stackoverflow.com/a/39024016/2521214) perhaps? – Spektre Mar 28 '22 at 07:07
  • 2
    Are you sure the header in your file is 54 bytes? – user253751 Mar 28 '22 at 10:10
  • @Spektre `glTexParameteri` doesn't solve it. No, I did not reformat the BMP that way, do I need to do it? If so, I'll read about it more. And yes, this is for Rubik's cube. – CoSalamander Mar 28 '22 at 17:34
  • You can view the bytes in a file with a tool called a hex editor. If you're using Windows I recommend one called HxD. You can also make your program print out the bytes which should help you determine the problem – user253751 Mar 28 '22 at 17:43
  • @user253751 I've viewed my BMP-file via hex editor. The header and info-header fields are 14 and 40 bytes respectively, [so now I am sure that the header is 54 bytes] followed by 102 bytes (34 24-bit pixels) of black pixel data. Because in BMP-files scan lines are stored from bottom to top, I found out that these are the pixels that are covered by excess once at the picture in my question. – CoSalamander Mar 28 '22 at 18:30
  • @user253751 After the header, it has 3072 bytes of data, 3072 = 32 * 32 * 3, where 32 - side of a picture, 3 - bytes per pixel. Last 102 bytes are 34 black pixels too. – CoSalamander Mar 28 '22 at 18:45
  • 1
    bmps have weird align algorithm they usually do not store the scanlines tightly packed instead there is align gap between them which is calculated from header how is described in the first link of mine. However if the case the texture would be skewed in GL which does not look like it ... unless you have misinterpreted the texture width by +1 and by lucky chance the align size is exactly 3 bytes making the problems on 2 edges of texture (right edge error might not be visible because you got black pixels there but bottom edge might overrun your memory allocated for it hence few bad pixels ...) – Spektre Mar 28 '22 at 19:39
  • You should post the bmp in its format so we can see what actually you are dealing with ... there is a lot of abreviations in BMP ... – Spektre Mar 28 '22 at 19:41
  • @Spektre [Here's](https://drive.google.com/file/d/16jyvTf2gc1k66AzHvdGLQmG4LE9eSTr7/view?usp=sharing) the BMP-file I am using – CoSalamander Mar 29 '22 at 08:09
  • 1
    @CoSalamander this one has 0 align bytes so its not the case and the problem lies elswhere ... btw. why are you using `malloc` instead of `new` in C++ (I had problems that `malloc` was corrupting C++ engine before but that was decades ago)? also why not have white texture instead of blue and just modulate the color latter ? so you got single texture for all sides ... – Spektre Mar 29 '22 at 08:16
  • 1
    @CoSalamander btw are you sure that your `fread` reads the file in binary mode ? if not it might represent bytes below 32 as escape commands causing weird stuff like this ... even terminate file reading prematurily (had problems with ancient compiler once that even binary mode was not binary and textures where corrupted during load but that was in MS-DOS had to use assembly and DOS interrupt for file access instead) ... also I see `glPushMatrix` but not `glMatrixMode` before it ... – Spektre Mar 29 '22 at 08:28
  • 1
    @CoSalamander try to hex print your entire file to console and check with hex editor if it matches (try to mimic the same layout as your hex viewer for easier comparison) if not you know file access is a problem and look for a way how to configure it for binary access or use winapi instead ... you can also read and save as new file and compare files by DOS command or in TotalComadder with compare by content tool in its file menu – Spektre Mar 29 '22 at 08:34
  • @Spektre Well, the answer wasn't even about BMP format, see below, I've made a rude mistake. By the way, I checked manually that my BMP-file is the same as the one in online hex editor. Also, I am using malloc because it gives me better visualization of how I'm working with memory, but I consider what you said about all these functions and BMP formats itself, thanks. – CoSalamander Mar 29 '22 at 10:38

1 Answers1

2

I can see an error in your code which could cause the problem you're seeing.

data = (unsigned char *) malloc (sizeof (unsigned char) * image_size);
fread (data, sizeof (char), image_size, file);
free (data);

You are allocating a buffer, reading into it, then immediately freeing it. This means that any code between free() and glTexImage2D() is free to overwrite this buffer in the heap.

Try moving the call to free() until after the call to glTexImage2D() and see what happens.