I have a slight problem: I can't modify the pixels of an SDL screen.
我有一个小问题:我不能修改SDL屏幕的像素。
Specifically, the following code doesn't work.
具体地说,下面的代码不起作用。
Uint32 * pixels = (Uint32 *) screen -> pixels;
screen -> pixels = pixels;
This compiles, but it doesn't show anything. What am I missing?
这个编译,但它没有显示任何东西。我缺少什么?
5 个解决方案
#1
19
I had the following functions lying around for setting pixels in an SDL_Surface. There are two versions each for 32-bit, 24-bit, 16-bit and 8-bit surfaces. If you just want to set a single pixel, you would use the normal versions. But if you want to set a bunch of pixels, first you lock the surface, then you use the nolock version(named so because it does not lock the surface), then you unlock. This way you aren't repeatedly locking and unlocking the surface, which is supposed to be an expensive operation, though I don't think I ever actually tested it.
我在SDL_Surface中设置了以下函数。32位、24位、16位和8位曲面各有两个版本。如果您只想设置一个像素,您将使用普通版本。但是如果你想设置一堆像素,首先锁定表面,然后使用nolock版本(因为它没有锁定表面),然后解锁。这样,您就不会反复锁定和解锁表面,这应该是一个昂贵的操作,尽管我认为我从未真正测试过它。
void PutPixel32_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint32));
*((Uint32*)pixel) = color;
}
void PutPixel24_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint8) * 3);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
pixel[0] = (color >> 24) & 0xFF;
pixel[1] = (color >> 16) & 0xFF;
pixel[2] = (color >> 8) & 0xFF;
#else
pixel[0] = color & 0xFF;
pixel[1] = (color >> 8) & 0xFF;
pixel[2] = (color >> 16) & 0xFF;
#endif
}
void PutPixel16_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint16));
*((Uint16*)pixel) = color & 0xFFFF;
}
void PutPixel8_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint8));
*pixel = color & 0xFF;
}
void PutPixel32(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel32_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
void PutPixel24(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel24_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
}
void PutPixel16(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel16_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
void PutPixel8(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel8_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
#2
2
Manipulating the contents of screen->pixels
will modify pixels, with a couple of caveats.
操作屏幕->像素的内容将修改像素,有几个注意事项。
First, as you've shown in the code snippet, note that screen->pixels
is a pointer to the pixel data of the surface. The pixel data itself is accessed as a linear array from that pointer based on the width of the surface (surface->pitch
) and the size of the pixel in bytes. The pixel size (aka depth) is set during initialisation, using SDL_SetVideoMode()
and can be found in screen->format->BytesPerPixel
.
首先,如您在代码片段中所示,请注意screen->像素是指向表面像素数据的指针。根据表面的宽度(表面->间距)和像素的大小(以字节为单位),从指针中以线性数组的形式访问像素数据本身。在初始化过程中,使用SDL_SetVideoMode()设置像素大小(即深度),可以在screen->格式->BytesPerPixel中找到。
Locking of the surface before making changes may be necessary.
可能需要在进行更改之前锁定表面。
In addition, depending on the options that were passed to SDL_SetVideoMode()
you may also need to call SDL_Flip()
to display the changes that you've made.
此外,根据传递给SDL_SetVideoMode()的选项,还可能需要调用SDL_Flip()来显示所做的更改。
A working example of pixel manipulation can be found here.
可以在这里找到一个像素操作的工作示例。
As has been pointed out in the comments, the code listed in the question is not actually going to do anything visible as no changes are being made to the pixel data.
正如在评论中指出的,问题中列出的代码实际上不会做任何可见的事情,因为像素数据没有任何变化。
#3
1
Adding an SDL2 variant manipulating pixels not on a surface but in a renderer (and which does not crash if you try to manipulate pixels outside of your screen, unlike previous answers)
添加SDL2变体,它不是在表面上操作像素,而是在渲染器中操作像素(与之前的答案不同,如果您试图在屏幕外操作像素,那么它不会崩溃)
void putPixelRGB(SDL_Renderer* renderer, int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
SDL_SetRenderDrawColor(renderer, (Uint8)r, (Uint8)g, (Uint8)b, 255);
SDL_RenderDrawPoint(renderer, x, y);
}
#4
-1
why change a pixel?
为什么改变像素?
make a new surface & a Rect
做一个新的表面&一个矩形
// CODE ------------>
/ /代码- - - - - - - - - - - - >
SDL_Surface *screen, *PIXEL = NULL;
SDL_Rect PIXELRect;
PIXELRect.h=5;
PIXELRect.w=5;
PIXELRect.x=100;
PIXELRect.y=100;
screen = SDL_SetVideoMode(640, 468, 32, SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_ANYFORMAT);
while(running){
SDL_FillRect(screen, &PIXELRect, (#color));
}
#5
-2
You must not modify the contents of the SDL_Surface structure. If you want to copy the pixels you should malloc() some memory and then memcpy() the pixels.
不能修改SDL_Surface结构的内容。如果您想复制像素,您应该malloc()一些内存,然后memcpy()这些像素。
#1
19
I had the following functions lying around for setting pixels in an SDL_Surface. There are two versions each for 32-bit, 24-bit, 16-bit and 8-bit surfaces. If you just want to set a single pixel, you would use the normal versions. But if you want to set a bunch of pixels, first you lock the surface, then you use the nolock version(named so because it does not lock the surface), then you unlock. This way you aren't repeatedly locking and unlocking the surface, which is supposed to be an expensive operation, though I don't think I ever actually tested it.
我在SDL_Surface中设置了以下函数。32位、24位、16位和8位曲面各有两个版本。如果您只想设置一个像素,您将使用普通版本。但是如果你想设置一堆像素,首先锁定表面,然后使用nolock版本(因为它没有锁定表面),然后解锁。这样,您就不会反复锁定和解锁表面,这应该是一个昂贵的操作,尽管我认为我从未真正测试过它。
void PutPixel32_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint32));
*((Uint32*)pixel) = color;
}
void PutPixel24_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint8) * 3);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
pixel[0] = (color >> 24) & 0xFF;
pixel[1] = (color >> 16) & 0xFF;
pixel[2] = (color >> 8) & 0xFF;
#else
pixel[0] = color & 0xFF;
pixel[1] = (color >> 8) & 0xFF;
pixel[2] = (color >> 16) & 0xFF;
#endif
}
void PutPixel16_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint16));
*((Uint16*)pixel) = color & 0xFFFF;
}
void PutPixel8_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint8));
*pixel = color & 0xFF;
}
void PutPixel32(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel32_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
void PutPixel24(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel24_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
}
void PutPixel16(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel16_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
void PutPixel8(SDL_Surface * surface, int x, int y, Uint32 color)
{
if( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
PutPixel8_nolock(surface, x, y, color);
if( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
#2
2
Manipulating the contents of screen->pixels
will modify pixels, with a couple of caveats.
操作屏幕->像素的内容将修改像素,有几个注意事项。
First, as you've shown in the code snippet, note that screen->pixels
is a pointer to the pixel data of the surface. The pixel data itself is accessed as a linear array from that pointer based on the width of the surface (surface->pitch
) and the size of the pixel in bytes. The pixel size (aka depth) is set during initialisation, using SDL_SetVideoMode()
and can be found in screen->format->BytesPerPixel
.
首先,如您在代码片段中所示,请注意screen->像素是指向表面像素数据的指针。根据表面的宽度(表面->间距)和像素的大小(以字节为单位),从指针中以线性数组的形式访问像素数据本身。在初始化过程中,使用SDL_SetVideoMode()设置像素大小(即深度),可以在screen->格式->BytesPerPixel中找到。
Locking of the surface before making changes may be necessary.
可能需要在进行更改之前锁定表面。
In addition, depending on the options that were passed to SDL_SetVideoMode()
you may also need to call SDL_Flip()
to display the changes that you've made.
此外,根据传递给SDL_SetVideoMode()的选项,还可能需要调用SDL_Flip()来显示所做的更改。
A working example of pixel manipulation can be found here.
可以在这里找到一个像素操作的工作示例。
As has been pointed out in the comments, the code listed in the question is not actually going to do anything visible as no changes are being made to the pixel data.
正如在评论中指出的,问题中列出的代码实际上不会做任何可见的事情,因为像素数据没有任何变化。
#3
1
Adding an SDL2 variant manipulating pixels not on a surface but in a renderer (and which does not crash if you try to manipulate pixels outside of your screen, unlike previous answers)
添加SDL2变体,它不是在表面上操作像素,而是在渲染器中操作像素(与之前的答案不同,如果您试图在屏幕外操作像素,那么它不会崩溃)
void putPixelRGB(SDL_Renderer* renderer, int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
SDL_SetRenderDrawColor(renderer, (Uint8)r, (Uint8)g, (Uint8)b, 255);
SDL_RenderDrawPoint(renderer, x, y);
}
#4
-1
why change a pixel?
为什么改变像素?
make a new surface & a Rect
做一个新的表面&一个矩形
// CODE ------------>
/ /代码- - - - - - - - - - - - >
SDL_Surface *screen, *PIXEL = NULL;
SDL_Rect PIXELRect;
PIXELRect.h=5;
PIXELRect.w=5;
PIXELRect.x=100;
PIXELRect.y=100;
screen = SDL_SetVideoMode(640, 468, 32, SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_ANYFORMAT);
while(running){
SDL_FillRect(screen, &PIXELRect, (#color));
}
#5
-2
You must not modify the contents of the SDL_Surface structure. If you want to copy the pixels you should malloc() some memory and then memcpy() the pixels.
不能修改SDL_Surface结构的内容。如果您想复制像素,您应该malloc()一些内存,然后memcpy()这些像素。