The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
Strange SDL_UpdateTexture() behaviour
guido.gonzato


Joined: 06 Nov 2015
Posts: 6
Hello everybody,

I've come across a strange problem using SDL_UpdateTexture(), which seems to work only on entire textures instead of an SDL_Rect.
The following code draws pixels, and only works correctly when I pass NULL to SDL_UpdateTexture(). I want it to work on the SDL_Rect I specify:

Code:

#include <SDL2/SDL.h>

int main (int argc, char ** argv)
{
  int leftMouseButtonDown = 0;
  int quit = 0;
  SDL_Event event;
  int pitch = 640 * sizeof(Uint32);
 
  int mouseX, mouseY;
  SDL_Rect rect;

  SDL_Init(SDL_INIT_VIDEO);

  SDL_Window *window =
    SDL_CreateWindow("SDL2 Pixel Drawing",
                     SDL_WINDOWPOS_UNDEFINED,
                     SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
  SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
  SDL_Texture *texture =
    SDL_CreateTexture (renderer, SDL_PIXELFORMAT_ARGB8888,
                       SDL_TEXTUREACCESS_STATIC, 640, 480);
  Uint32 pixels[640 * 480];
 
  // make the window white
  memset (pixels, 255, 640 * 480 * sizeof(Uint32));
  SDL_UpdateTexture(texture, NULL, pixels, pitch);
  SDL_RenderCopy(renderer, texture, NULL, NULL);

  while (!quit) {
   
    SDL_WaitEvent(&event);

    switch (event.type)
    {
    case SDL_MOUSEBUTTONUP:
      if (event.button.button == SDL_BUTTON_LEFT)
        leftMouseButtonDown = 0;
      break;
    case SDL_MOUSEBUTTONDOWN:
      if (event.button.button == SDL_BUTTON_LEFT)
        leftMouseButtonDown = 1;
    case SDL_MOUSEMOTION:
      if (leftMouseButtonDown) {
        mouseX = event.motion.x;
        mouseY = event.motion.y;
        pixels[mouseY * 640 + mouseX] = 0xffff0000; // red
      }
      break;
    case SDL_QUIT:
      quit = 1;
      break;
    }
   
    // let's update the pixel "rectangle" only
    rect.x = mouseX;
    rect.y = mouseY;
    rect.w = rect.h = 1;
   
    // NOT WORKING:
    // SDL_UpdateTexture (texture, &rect, pixels, pitch);
   
    // WORKING - update the whole texture
    SDL_UpdateTexture(texture, NULL, pixels, pitch);
   
    // ALSO WORKING (kind of):
    // rect.x = 0;
    // rect.y = 0;
    // rect.w = mouseX;
    // rect.h = mouseY;
    // SDL_UpdateTexture (texture, &rect, pixels, pitch);
   
    // copy the rectangle only - this time it works
    SDL_RenderCopy(renderer, texture, &rect, &rect);
    SDL_RenderPresent(renderer);
  }

  SDL_DestroyTexture(texture);
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();

  return 0;
}


Am I doing something wrong? I thought that SDL_UpdateTexture() would work on textures like old SDL_UpdateRect() did on surfaces - and it worked fine.
I would like to speed up SDL_UpdateTexture() for SDL_bgi, a BGI_compatible graphics library I wrote.
I'm using stock SDL2 2.0.2 on Linux Mint.

Thanks,
Guido
brada


Joined: 16 Aug 2012
Posts: 38
I believe its not working because when you are updating a rect, the pixels pointer needs to be set to the first pixel of the rect. it looks like you are passing a pointer to all the pixels in the image so SDL is going to treat that as if it were the pixels for the rect only so you are going to end up with whatever was in the top left rect of the entire buffer.

Try adding an offset to the pointer something like (you probably want to think though this longer than i did)
Code:
pixels + (pitch * rect.y) + rect.x


It could be that im completely wrong also Smile
guido.gonzato


Joined: 06 Nov 2015
Posts: 6
brada wrote:
I believe its not working because when you are updating a rect, the pixels pointer needs to be set to the first pixel of the rect. it looks like you are passing a pointer to all the pixels in the image so SDL is going to treat that as if it were the pixels for the rect only so you are going to end up with whatever was in the top left rect of the entire buffer.

Try adding an offset to the pointer something like (you probably want to think though this longer than i did)
Code:
pixels + (pitch * rect.y) + rect.x


It could be that im completely wrong also Smile


unfortunately, it didn't work; the program segfaults.
guido.gonzato


Joined: 06 Nov 2015
Posts: 6
This is increasingly looking like a bug in SDL_UpdateTexture().

I happened to make it work in a very strange way. Let's modify the code as follows:

Code:

   // NOT WORKING:
   SDL_UpdateTexture (texture, &rect, pixels, pitch);
   
   // WORKING - update the whole texture
   //  SDL_UpdateTexture(texture, NULL, pixels, pitch);


That is, let's uncomment out the "not working" code and comment out the "working" line.

Compile the program then click around; no pixels will be displayed. But if you keep clicking and manage to hit the (0, 0) pixel, voila! From now on, pixels will be correctly refreshed.

I'm really puzzled. Hints/ideas?

Thanks,
Guido
brada


Joined: 16 Aug 2012
Posts: 38
This sounds like exactly what I already tried explaining to you. I never promised my code would work (in fact i made a disclaimer to the contrary); I was merely attempting to demonstrate that you need to pass an offset from your pixels array that corresponds to the rect you are trying to update, otherwise you are copying the pixels from the top left of your buffer (it is top left in SDL right?) which are not the pixels you actually change. This is why passing NULL works, because then its updating a rect equal to your entire image which means the top left pixel of the rect to update is in fact the pixels pointer you are passing; unlike when you are trying to update the subrect.

I dont know how to explain it more clearly; I'm sorry.

guido.gonzato wrote:
This is increasingly looking like a bug in SDL_UpdateTexture().

I happened to make it work in a very strange way. Let's modify the code as follows:

Code:

   // NOT WORKING:
   SDL_UpdateTexture (texture, &rect, pixels, pitch);
   
   // WORKING - update the whole texture
   //  SDL_UpdateTexture(texture, NULL, pixels, pitch);


That is, let's uncomment out the "not working" code and comment out the "working" line.

Compile the program then click around; no pixels will be displayed. But if you keep clicking and manage to hit the (0, 0) pixel, voila! From now on, pixels will be correctly refreshed.

I'm really puzzled. Hints/ideas?

Thanks,
Guido