Newbie trying to understand the logic of this code:

I’m fairly new at programming with C++ and I’ve just started working
with SDL. I’m going through the SDL API Reference Guide and I’m
trying to get a handle on some of the code presented in the examples.
In example for “Drawing directly to the display” there is a line that
I’m having difficulty understanding:

bits = ((Uint8 )screen->pixels)+Yscreen->pitch+X*bpp;

I’ve listed the complete example below for clarification. From what I
can interpret ‘bits’ is a pointer to an 8 bit integer and this
statement is assigning a value to it. If I understand correctly
((Uint8 )screen->pixels) is the screen pixels casts as a pointer to
Uint8. The part that says Y
screen->pitch+Xbpp is what’s confusing
me. Why are we multiplying Y by screen->pitch and X
bpp and then
adding them together? what’s the point of this?

I apologize if I sound like an idiot… I’m trying to understand the
logic and not just memorize the code… thanks for your patience.

Rene

------ example code ------

/* Code to set a yellow pixel at the center of the screen */

Sint32   X, Y;
Uint32   pixel;
Uint8   *bits, bpp;

/* Map the color yellow to this display (R=0xFF, G=0xFF, B=0x00)
   Note:  If the display is palettized, you must set the palette first.
*/
pixel = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0x00);

/* Calculate the framebuffer offset of the center of the screen */
if ( SDL_MUSTLOCK(screen) ) {
    if ( SDL_LockSurface(screen) < 0 )
        return;
}
bpp = screen->format->BytesPerPixel;
X = screen->w/2;
Y = screen->h/2;
bits = ((Uint8 *)screen->pixels)+Y*screen->pitch+X*bpp;

/* Set the pixel */
switch(bpp) {
    case 1:
        *((Uint8 *)(bits)) = (Uint8)pixel;
        break;
    case 2:
        *((Uint16 *)(bits)) = (Uint16)pixel;
        break;
    case 3: { /* Format/endian independent */
        Uint8 r, g, b;

        r = (pixel>>screen->format->Rshift)&0xFF;
        g = (pixel>>screen->format->Gshift)&0xFF;
        b = (pixel>>screen->format->Bshift)&0xFF;
        *((bits)+screen->format->Rshift/8) = r;
        *((bits)+screen->format->Gshift/8) = g;
        *((bits)+screen->format->Bshift/8) = b;
        }
        break;
    case 4:
        *((Uint32 *)(bits)) = (Uint32)pixel;
        break;
}

/* Update the display */
if ( SDL_MUSTLOCK(screen) ) {
    SDL_UnlockSurface(screen);
}
SDL_UpdateRect(screen, X, Y, 1, 1);

return;--

Rene

bits = ((Uint8 )screen->pixels)+Yscreen->pitch+X*bpp;

(Uint8 *)screen->pixels:

by casting to a Uint8*, we are telling the compiler to treat our “pixels” as
an array of 1 byte units.

Y*screen->pitch :

we need to offset to line “Y” of the pixels.
pitch is the length of each horizontal line in each surface.
so by telling it to go from screen->pixels + screen->pitch
we retrive the address of the first line.

screen->pixels + screen->pitch * Y means the “Yth” line.

X * bpp:

this will offset into that line of pixels, X times the number of bytes in a
pixel.
if bpp > 1, each pixel occuys more than one byte in RAM, so we have to skip
over them
thats why we multiply.

at the end our “bits” pointer points to the address of the pixel we want to
modify.

next up it will be cast to a Uint16* or a Uint32* so that its pointing to a
pixel thats 8,16, 24 or 32 bits long.

then we can write a colour to that address.

i hope that helps

Hey no worries! Everyone was a newbie at one point :P------------------
screen->pitch

ok check this out, pretend for a moment that you had a screen that was 10x5
pixels in resolution (just for the sake of example)

0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

The coordinates of the 1 in X,Y is (3,1) right? well in memory, the screen
is basicly just one long array so even though the screen looks 2D it’s
really 1D like this:

0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

So how do you convert from 2d coordinates to 1d?

you multiply the Y coordinate by how long a row is and add the X coordinate.

So, to get our (3,1) 2d coordinate in the 1d coordinate:

1 * 10 + 3

1 is the Y coordinate, 10 is how long a row is and 3 is the X coordinate.

We end up with 13 as the answer, which if you count on the 1D version of the
screen above, the 1 is the 13th spot so it shows that our equation works.

screen->pitch is the variable that keeps track of how long a row is (in
bytes, not pixels - very important distinction when you are in a mode where
1 pixel is more than 1 byte) so that explains this part of the equation:
Y*screen->pitch


BPP

BPP stands for “bytes per pixel”. In the above example, i noted how it was
important that the screen pitch was in bytes, not pixels. If BPP is 1, (ie
1 byte per pixel - ie 8 bit color), then pitch is the same as the number of
pixels (exceptions listed later).

but if you are in 16 bit color, each pixel is 2 bytes. Looking at our old
equation of : Y*rowlength+X, and our screen being 10x5, let’s assume we are
in 16 bit graphics mode trying to get the pixel at (3,1).

In this case, screen->pitch will be 20 instead of 10 since BPP is 2 (2 bytes
per pixel = 16 bit color).

our equation would look like this: 1*20 +3 which would give us 23. if you
count in the 1d array, assuming each number is 2 bytes, you get to the
number 11 instead of 13 (23/2 = 11 in integer land)!

So, to correct this, our equation should be… Yrowlength+XBPP.
Recalculating we get 120+32 which gives us 26. If you count through the
1d array, each number being 2 bytes, you get to 13 like you should! (26/2 =
13, another easy way to check that this is right).


screen->pitch again

so why multiply by screen->pitch? what if you knew you were in 800x600
screen resolution, why wouldnt you just multiply by 800?

well, for some reason im not really sure about, sometimes there is "padding"
on the end of each row of pixels (perhaps to make the screen row boundaries
line up better for optomized drawing? not sure). So, even though you have
800 pixels at 16 bit color, your screen->pitch might not be 1600, it could
be 1800 (with 200 bytes of padding) or 2048 (with 448 bytes of padding).

What a pain in the ass right? actualy it’s not that bad, just always
remember to multiply by screen->pitch and it will take care of this for you
automaticly (:

Hope this helps!
Alan

----- Original Message -----
From: renx99@gmail.com (Rene Lopez)
To:
Sent: Friday, October 28, 2005 10:01 AM
Subject: [SDL] newbie trying to understand the logic of this code:

I’m fairly new at programming with C++ and I’ve just started working
with SDL. I’m going through the SDL API Reference Guide and I’m
trying to get a handle on some of the code presented in the examples.
In example for “Drawing directly to the display” there is a line that
I’m having difficulty understanding:

bits = ((Uint8 )screen->pixels)+Yscreen->pitch+X*bpp;

I’ve listed the complete example below for clarification. From what I
can interpret ‘bits’ is a pointer to an 8 bit integer and this
statement is assigning a value to it. If I understand correctly
((Uint8 )screen->pixels) is the screen pixels casts as a pointer to
Uint8. The part that says Y
screen->pitch+Xbpp is what’s confusing
me. Why are we multiplying Y by screen->pitch and X
bpp and then
adding them together? what’s the point of this?

I apologize if I sound like an idiot… I’m trying to understand the
logic and not just memorize the code… thanks for your patience.

Rene

------ example code ------

/* Code to set a yellow pixel at the center of the screen */

Sint32   X, Y;
Uint32   pixel;
Uint8   *bits, bpp;

/* Map the color yellow to this display (R=0xFF, G=0xFF, B=0x00)
   Note:  If the display is palettized, you must set the palette first.
*/
pixel = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0x00);

/* Calculate the framebuffer offset of the center of the screen */
if ( SDL_MUSTLOCK(screen) ) {
    if ( SDL_LockSurface(screen) < 0 )
        return;
}
bpp = screen->format->BytesPerPixel;
X = screen->w/2;
Y = screen->h/2;
bits = ((Uint8 *)screen->pixels)+Y*screen->pitch+X*bpp;

/* Set the pixel */
switch(bpp) {
    case 1:
        *((Uint8 *)(bits)) = (Uint8)pixel;
        break;
    case 2:
        *((Uint16 *)(bits)) = (Uint16)pixel;
        break;
    case 3: { /* Format/endian independent */
        Uint8 r, g, b;

        r = (pixel>>screen->format->Rshift)&0xFF;
        g = (pixel>>screen->format->Gshift)&0xFF;
        b = (pixel>>screen->format->Bshift)&0xFF;
        *((bits)+screen->format->Rshift/8) = r;
        *((bits)+screen->format->Gshift/8) = g;
        *((bits)+screen->format->Bshift/8) = b;
        }
        break;
    case 4:
        *((Uint32 *)(bits)) = (Uint32)pixel;
        break;
}

/* Update the display */
if ( SDL_MUSTLOCK(screen) ) {
    SDL_UnlockSurface(screen);
}
SDL_UpdateRect(screen, X, Y, 1, 1);

return;

Rene


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

Thanks Alan!!

This explains it perfectly for me. Just what I needed. I was blind
but now i see!!! It’s a miracle!

ReneOn 10/28/05, Alan Wolfe wrote:

Hey no worries! Everyone was a newbie at one point :stuck_out_tongue:


screen->pitch

ok check this out, pretend for a moment that you had a screen that was 10x5
pixels in resolution (just for the sake of example)

0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

The coordinates of the 1 in X,Y is (3,1) right? well in memory, the screen
is basicly just one long array so even though the screen looks 2D it’s
really 1D like this:

0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

So how do you convert from 2d coordinates to 1d?

you multiply the Y coordinate by how long a row is and add the X coordinate.

So, to get our (3,1) 2d coordinate in the 1d coordinate:

1 * 10 + 3

1 is the Y coordinate, 10 is how long a row is and 3 is the X coordinate.

We end up with 13 as the answer, which if you count on the 1D version of the
screen above, the 1 is the 13th spot so it shows that our equation works.

screen->pitch is the variable that keeps track of how long a row is (in
bytes, not pixels - very important distinction when you are in a mode where
1 pixel is more than 1 byte) so that explains this part of the equation:
Y*screen->pitch


BPP

BPP stands for “bytes per pixel”. In the above example, i noted how it was
important that the screen pitch was in bytes, not pixels. If BPP is 1, (ie
1 byte per pixel - ie 8 bit color), then pitch is the same as the number of
pixels (exceptions listed later).

but if you are in 16 bit color, each pixel is 2 bytes. Looking at our old
equation of : Y*rowlength+X, and our screen being 10x5, let’s assume we are
in 16 bit graphics mode trying to get the pixel at (3,1).

In this case, screen->pitch will be 20 instead of 10 since BPP is 2 (2 bytes
per pixel = 16 bit color).

our equation would look like this: 1*20 +3 which would give us 23. if you
count in the 1d array, assuming each number is 2 bytes, you get to the
number 11 instead of 13 (23/2 = 11 in integer land)!

So, to correct this, our equation should be… Yrowlength+XBPP.
Recalculating we get 120+32 which gives us 26. If you count through the
1d array, each number being 2 bytes, you get to 13 like you should! (26/2 =
13, another easy way to check that this is right).


screen->pitch again

so why multiply by screen->pitch? what if you knew you were in 800x600
screen resolution, why wouldnt you just multiply by 800?

well, for some reason im not really sure about, sometimes there is "padding"
on the end of each row of pixels (perhaps to make the screen row boundaries
line up better for optomized drawing? not sure). So, even though you have
800 pixels at 16 bit color, your screen->pitch might not be 1600, it could
be 1800 (with 200 bytes of padding) or 2048 (with 448 bytes of padding).

What a pain in the ass right? actualy it’s not that bad, just always
remember to multiply by screen->pitch and it will take care of this for you
automaticly (:

Hope this helps!
Alan

----- Original Message -----
From: “Rene Lopez”
To:
Sent: Friday, October 28, 2005 10:01 AM
Subject: [SDL] newbie trying to understand the logic of this code:

I’m fairly new at programming with C++ and I’ve just started working
with SDL. I’m going through the SDL API Reference Guide and I’m
trying to get a handle on some of the code presented in the examples.
In example for “Drawing directly to the display” there is a line that
I’m having difficulty understanding:

bits = ((Uint8 )screen->pixels)+Yscreen->pitch+X*bpp;

I’ve listed the complete example below for clarification. From what I
can interpret ‘bits’ is a pointer to an 8 bit integer and this
statement is assigning a value to it. If I understand correctly
((Uint8 )screen->pixels) is the screen pixels casts as a pointer to
Uint8. The part that says Y
screen->pitch+Xbpp is what’s confusing
me. Why are we multiplying Y by screen->pitch and X
bpp and then
adding them together? what’s the point of this?

I apologize if I sound like an idiot… I’m trying to understand the
logic and not just memorize the code… thanks for your patience.

Rene

------ example code ------

/* Code to set a yellow pixel at the center of the screen */

Sint32   X, Y;
Uint32   pixel;
Uint8   *bits, bpp;

/* Map the color yellow to this display (R=0xFF, G=0xFF, B=0x00)
   Note:  If the display is palettized, you must set the palette first.
*/
pixel = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0x00);

/* Calculate the framebuffer offset of the center of the screen */
if ( SDL_MUSTLOCK(screen) ) {
    if ( SDL_LockSurface(screen) < 0 )
        return;
}
bpp = screen->format->BytesPerPixel;
X = screen->w/2;
Y = screen->h/2;
bits = ((Uint8 *)screen->pixels)+Y*screen->pitch+X*bpp;

/* Set the pixel */
switch(bpp) {
    case 1:
        *((Uint8 *)(bits)) = (Uint8)pixel;
        break;
    case 2:
        *((Uint16 *)(bits)) = (Uint16)pixel;
        break;
    case 3: { /* Format/endian independent */
        Uint8 r, g, b;

        r = (pixel>>screen->format->Rshift)&0xFF;
        g = (pixel>>screen->format->Gshift)&0xFF;
        b = (pixel>>screen->format->Bshift)&0xFF;
        *((bits)+screen->format->Rshift/8) = r;
        *((bits)+screen->format->Gshift/8) = g;
        *((bits)+screen->format->Bshift/8) = b;
        }
        break;
    case 4:
        *((Uint32 *)(bits)) = (Uint32)pixel;
        break;
}

/* Update the display */
if ( SDL_MUSTLOCK(screen) ) {
    SDL_UnlockSurface(screen);
}
SDL_UpdateRect(screen, X, Y, 1, 1);

return;

Rene


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

Rene