Loop Setting Pixels

Hi,

So, I’m rather annoyed at my realtime radiosity renderer, so I’m taking a
break and writing a ray-tracer (in C++ for practice). This function will be
the core of the ray-tracer:

void trace() {
Uint8 r,g,b;
SDL_Rect rect;
rect.w = 1;
rect.h = 1;
for (int y=0;y<image_size[1];y++) {
for (int x=0;x<image_size[0];x++) {
rect.x = x;
rect.y = y;
r = g = b = 255;
Uint32 color = SDL_MapRGB(screen->format,r,g,b);
SDL_FillRect(screen,&rect,color);
}
SDL_UpdateRect(screen,0,0,0,0);
}
}

For technical reasons, x=0, y=0 needs to correspond to the bottom left of
the screen. I thus tried changing “rect.y = y;” to “rect.y =
image_size[1]-y;”. The screen remains black. I’m not sure why this should
be; I’ve done similar things before and they always worked. Shouldn’t it
set the rows effectively in reverse order? What’s going on?

Thanks,
Ian

I believe you should be using image_size[1] - y -1. Consider that y
never reaches image_size[1], therefore the 0 pixel line will be black.
I suspect that SDL_FillRect is clipping your rectangle by setting w or
h to 0, due to the above off-by-one which writes out of the screen
boundary.

Finally, you probably should be use SDL_LockSurface(), followed by
direct manipulation of the surface->pixels array, followed by
SDL_UnlockSurface() for this. Lots of 1x1 FillRect calls are bound to
add up.On 22 July 2010 22:31, Ian Mallett wrote:

Hi,

So, I’m rather annoyed at my realtime radiosity renderer, so I’m taking a
break and writing a ray-tracer (in C++ for practice).? This function will be
the core of the ray-tracer:

Since you are ray-tracing probably purely CPU-memory, for best
performance one should keep pixel accesses in memory as well. I would
render all pixels into a local buffer first, then create a surface from
it in a single call using SDL_CreateRGBSurfaceFrom using the current
display format and then blit that one to the screen in one shot. Here is
some info:
http://sdl.beuc.net/sdl.wiki/SDL_CreateRGBSurfaceFrom
–AndreasOn 7/22/10 2:31 PM, Ian Mallett wrote:

Hi,

So, I’m rather annoyed at my realtime radiosity renderer, so I’m
taking a break and writing a ray-tracer (in C++ for practice). This
function will be the core of the ray-tracer:

void trace() {
Uint8 r,g,b;
SDL_Rect rect;
rect.w = 1;
rect.h = 1;
for (int y=0;y<image_size[1];y++) {
for (int x=0;x<image_size[0];x++) {
rect.x = x;
rect.y = y;
r = g = b = 255;
Uint32 color = SDL_MapRGB(screen->format,r,g,b);
SDL_FillRect(screen,&rect,color);
}
SDL_UpdateRect(screen,0,0,0,0);
}
}

For technical reasons, x=0, y=0 needs to correspond to the bottom left
of the screen. I thus tried changing “rect.y = y;” to “rect.y =
image_size[1]-y;”. The screen remains black. I’m not sure why this
should be; I’ve done similar things before and they always worked.
Shouldn’t it set the rows effectively in reverse order? What’s going on?

Thanks,
Ian


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I believe you should be using image_size[1] - y -1. Consider that y
never reaches image_size[1], therefore the 0 pixel line will be black.
I suspect that SDL_FillRect is clipping your rectangle by setting w or
h to 0, due to the above off-by-one which writes out of the screen
boundary.

Thanks, this fixes it. Still, this seems very counter-intuitive behavior to
me. I see why it needs an extra -1, but not why it should cause the whole
screen to go black if it can’t write one pixel.

Finally, you probably should be use SDL_LockSurface(), followed by
direct manipulation of the surface->pixels array, followed by
SDL_UnlockSurface() for this. Lots of 1x1 FillRect calls are bound to
add up.

It fills the whole screen in about a quarter second, but yes, that’s true;
I’ll add that.On Thu, Jul 22, 2010 at 2:56 PM, Brian Barrett <brian.ripoff at gmail.com>wrote:
On Thu, Jul 22, 2010 at 6:21 PM, Andreas Schiffler wrote:

Since you are ray-tracing probably purely CPU-memory, for best performance
one should keep pixel accesses in memory as well. I would render all pixels
into a local buffer first, then create a surface from it in a single call
using SDL_CreateRGBSurfaceFrom using the current display format and then
blit that one to the screen in one shot. Here is some info:
http://sdl.beuc.net/sdl.wiki/SDL_CreateRGBSurfaceFrom
–Andreas

True, but for this ray-tracer, I want to see intermediate results; in this
case, one row at a time. Again, I’m not too concerned about the time it
takes to draw the screen.

Thanks everyone,
Ian

Hi.

This is the clipping behaviour. You might notice that SDL_FillRect
takes a non-const pointer to a SDL_Rect. This is because it writes to
it. Imagine you told SDL to fill an area twice the size of the screen.
First SDL clips the rectangle to the area of the screen. Then it
(conceptually) loops over this area filling it with the colour. If you
set rect.w and rect.h to 1 inside the inner loop you would not see
this behaviour. It doesn’t cause the entire screen to go black because
one pixel is out of bounds, what happens is that out of bounds pixel
causes your rectangle to shrink to an area of zero, and your
subsequent attempts to fill this rectangle don’t appear to do
anything, so it would be more correct to say that the screen remains
black, not that the screen goes black.

HTH,
– BrianOn 23 July 2010 02:38, Ian Mallett wrote:

Thanks, this fixes it.? Still, this seems very counter-intuitive behavior to
me.? I see why it needs an extra -1, but not why it should cause the whole
screen to go black if it can’t write one pixel.

Hi.

Consider then selectively updating the current scanline then using the
appropriate arguments to SDL_UpdateRect, it should be faster.
Otherwise you could be copying the entire screen surface, even though
only a small part has changed.

HTH,
– Brian.On 23 July 2010 02:38, Ian Mallett wrote:

True, but for this ray-tracer, I want to see intermediate results; in this
case, one row at a time.? Again, I’m not too concerned about the time it
takes to draw the screen.