Friday, February 11, 2011

Streaming textures with SDL 1.3

I was recently asked how to use streaming textures with SDL 1.3, and while it's very simple, I didn't actually find any documentation on how to do it, so here it is!

First, why would you use a streaming texture?

Static textures are designed for sprites and backgrounds and other images that don't change much.  You update them with pixels using SDL_UpdateTexture().

Streaming textures are designed for things that update frequently, every few seconds, or every frame.  You can also update them with SDL_UpdateTexture(), but for optimal performance you lock them, write the pixels, and then unlock them.

Conceptually they're very simple to use:
  1. Call SDL_CreateTexture() with the SDL_TEXTUREACCESS_STREAMING access type
  2. Call SDL_LockTexture() to get raw access to the pixels
  3. Do any pixel manipulation you want
  4. Call SDL_UnlockTexture()
  5. Use the texture in rendering normally.
You can specify any RGB/RGBA or YUV format you want and SDL or the hardware drivers will do the conversion for you on the back end if it's not supported. To get the best speed you'll probably want to create the texture in the first format listed in the renderer info, although at the time of this writing SDL_PIXELFORMAT_ARGB8888 is the optimal format for all renderers. 

You might also want to create a surface from the texture pixels if you're doing old style blitting using other SDL surfaces.  You can do this by creating a surface with no pixel data and then filling the pixel and pitch info in later:

texture = SDL_CreateTexture(renderer,
                            SDL_PIXELFORMAT_ARGB8888,
                            SDL_TEXTUREACCESS_STREAMING,
                            width, height);

surface = SDL_CreateRGBSurfaceFrom(NULL,
                                   width, height,
                                   32, 0,
                                   0x00FF0000,
                                   0x0000FF00,
                                   0x000000FF,
                                   0xFF000000);

...
SDL_LockTexture(texture, NULL,
                &surface->pixels,
                &surface->pitch);
... draw to surface
SDL_UnlockTexture(texture)


I put together a very simple example based on the running moose by Mike Gorchak:
http://hg.libsdl.org/SDL/file/default/test/teststreaming.c


Enjoy!

8 comments:

  1. Was hoping it was like megatextures (from the ID tech 5 engine), now I'm dissapoint.

    Still useful, though.

    ReplyDelete
  2. I too was searching for how streaming textures with SDL 1.3 can be done and your post saved me lots of time and efforts.It worked perfectly after some small changes according to my requirements which were quite easy to do.Keep sharing useful information

    ReplyDelete
  3. Thanks a lot for this. Most of the stuff in the test director still seems to be 1.2-based, but in the Moose example I see a bit more how the new stuff is used.

    I find SDL 1.3 is a pretty fun and rewarding way to get back into Linux C programming, something which it has been a couple of years since I mucked about with.

    ReplyDelete
  4. I'm glad you're enjoying it! :)

    ReplyDelete
  5. Dear slouken, where can I download SDL 2.0 libs? I just want to start to use the new paradigm, introduced in 2.0 (working with textures, multiple monitors and so on).

    ReplyDelete
  6. Thank you!! That SDL_PIXELFORMAT_ARGB8888 was the magic bullet, I've been using SDL_PIXELFORMAT_RGBA8888 and that slows down screen redraws!

    ReplyDelete
  7. Hey man very nice article do you think you could help me finish my program? It is based on yours and all I have to do to finish it is to connect my array of pixels to the texture (line 26) http://ideone.com/Zspe8u
    I believe the issue is that I don't know how to use the SDL_Color pointer. As you'll see I declare it but don't use it, because your example code was a tadbit too advanced for me to understand:
    (THIS IS FROM YOUR EXAMPLE CODE, the part where you populate the array? it is very dense, I'm having trouble breaking through it)
    src = MooseFrames[frame];
    for (row = 0; row < MOOSEPIC_H; ++row) {
    dst = (Uint32*)((Uint8*)pixels + row * pitch);
    for (col = 0; col < MOOSEPIC_W; ++col) {
    color = &MooseColors[*src++];
    *dst++ = (0xFF000000|(color->r<<16)|(color->g<<8)|color->b);
    }
    }

    ReplyDelete