0
\$\begingroup\$

I've been trying for hours now to figure out why this piece of code is giving me seg fault, but can't figure out why.

 void pixel::Texture::LoadTexture(const char* filepath)
 {
    SDL_Surface* image = IMG_Load(filepath);
    SDL_Surface* formattedImage = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_ARGB8888, 0);

    textureBuffer = new Uint32[formattedImage->pitch * formattedImage->h];

    width = formattedImage->w;
    height = formattedImage->h;
    pitch = formattedImage->pitch;

    SDL_LockSurface(formattedImage);

    Uint32* pixels = (Uint32*)formattedImage->pixels;

    int bpp = formattedImage->format->BytesPerPixel;
    
    for(int y = 0; y < height; y++)
        for(int x = 0; x < width; x++)
            textureBuffer[(formattedImage->pitch * y) + (x * bpp)] = pixels[(formattedImage->pitch * y) + (x * bpp)];

    SDL_UnlockSurface(formattedImage);

    SDL_FreeSurface(image);
    SDL_FreeSurface(formattedImage);
 }

Essentially, what I'm doing is I have an array of unsigned 32 bit integers called the texture buffer. All I do is load an image into a surface then convert it's pixel format to ARGB then start reading each pixel and storing it inside my texture buffer array but for some reason the pixels array gets an out of bounds error at some point in runtime and I can't figure out exactly why.

\$\endgroup\$
1
\$\begingroup\$

This code gives the byte offset to the pixel at coordinates x, y:

(formattedImage->pitch * y) + (x * bpp)

But you're providing it as the index into an array to which you've assigned the type Uint32*:

Uint32* pixels = (Uint32*)formattedImage->pixels;

This is like measuring a distance in kilometers, then using it to give someone driving directions in miles. A trusting person (or CPU) following your directions will end up overshooting the destination by a long way!

A Uint32 is 4 bytes, so each time you step your byte offset forward by 1 pixel by incrementing x by 1, your index into the pixel data leaps forward 4 * 4 = 16 bytes:

pixels[(formattedImage->pitch * y) + (x * bpp)];

So you burn through your data 4x faster than you meant to, and by the time your code thinks it's read just a quarter of the data, it's already at the end of the collection. You continue reading 3x the total data size past there until you trigger the fault.

It looks to me like your code is better set up for iterating with an index measured as a pixel count, rather than as a byte offset, which we can do with a couple small tweaks:

textureBuffer = new Uint32[width * height];

for(int y = 0; y < height; y++)
    for(int x = 0; x < width; x++)
        textureBuffer[width * y + x] = pixels[width * y + x];

Note that we no longer multiply by pitch or bpp here.

There's probably a more modern C++ way to iterate over this collection as a range, or just do a memcopy, but I'm afraid I'm not fluent enough in the language to advise on the particulars there.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.