Reputation: 13
I'm currently working on something in C++ using SDL2 that requires being able to draw a lot of individual pixels with specific color values to the screen every update. I'm using SDL_RenderDrawPoint just to make sure my program works but I'm sure the performance on that is terrible. From a cursory search it seems like using a texture that is the size of my window would be fastest by using SDL_UpdateTexture and updating it with a vector of pixels with my desired pixel values with a default of {0,0,0,0} RGBA value for any pixel not changed.
However every attempt I've had at writing it fails and I'm not sure where my misunderstandings lie. This is my current code that attempts to draw a specific RGBA color value to a specific x,y coordinate in my texture. I assume the part of the buffer I'm accessing using my x,y values is incorrect but I'm unsure how to make it correct if so.
Any help is appreciated including suggestions on how to efficiently do this without a texture if there's a better way.
SDL_Texture* windowTexture = SDL_CreateTexture(render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, screenWidth, screenHeight);
unsigned int* lockedPixels = nullptr;
std::vector<int> pixels(screenHeight*screenWidth*4, 0);
int pitch = 0;
int start = (y * screenWidth + x) * 4;
pixels[start + 0] = B;
pixels[start + 1] = G;
pixels[start + 2] = R;
pixels[start + 3] = A;
SDL_UpdateTexture(windowTexture, nullptr, pixels.data(), screenWidth * 4);
Upvotes: 0
Views: 1515
Reputation: 1
For convenience, use SDL_MapRGB or SDL_MapRGBA to calculate the value for you, using any format.
SDL_PixelFormat* format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
...
Uint32 color = SDL_MapRGBA(format, R, G, B, A);
...
SDL_FreeFormat(format);
Upvotes: 0
Reputation: 3812
The pixel format RGBA8888
means that each pixel is a 32 bit element with each channel (i.e. red, green, blue or alpha) taking up 8 bits, in that order.
You may want to declare pixels
as containing the type "32 bit unsigned integer". An unsigned int
is typically 32 bits, but it may also be larger.
std::vector<Uint32> pixels(screenHeight*screenWidth, 0); // Note: no *4
The individual R, G, B, A values (which should each be 8 bit unsigned integers) can be combined into one pixel by using shifts and bit-wise ORs:
int start = y * screenWidth + x; // Note: no *4
pixels[start] = (R << 24U) | (G << 16U) | (B << 8U) | A;
Lastly, you may want to not hardcode the last parameter of SDL_UpdateTexture
(i.e. pitch). Instead, use screenWidth * sizeof(Uint32)
.
The implementation above is basically a direct implementation of "RGBA8888" and allows you to access individual pixels. Alternatively, you could also declare an array of four times the size containing 8 bit unsigned integers. Then, the first four indices would correspond to the R, G, B, A values of the first pixel, the next four indices would correspond to the R, G, B, A values of the second pixel, etc. Which one is faster would depend on the exact system and use-case (whether the most common operations are on pixels or individual channels).
PS. Instead of Uint32
you could also use C++'s own std::uint32_t
from the cstdlib
header.
Upvotes: 2