Jump to content
  • Advertisement
Sign in to follow this  
c4c0d3m0n

SDL_BYTEORDER - major confusion

This topic is 3820 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

SDL_Surface*
CGraphics::
printString( std::string sz, const CFont* fnt, int x, int y,
             const SDL_Color& color, int flags )
{
    SDL_Rect offset;
    offset.x = x;
    offset.y = y;
    offset.w = 0;
    offset.h = 0;

    std::vector<std::string> vlines;


    // Split up the text in lines
    int n = 0;
    while ( n != -1 ) {

        n = sz.find( '\n', 0 );

        std::string szsub = sz.substr( 0, n );
        if ( n != -1 )
          sz = sz.substr( n+1 );

        vlines.push_back( szsub );

        int tmpwidth = fnt->calcWidth( szsub );
        if ( tmpwidth > offset.w )
          offset.w = tmpwidth;

        offset.h += fnt->height();
    }


    SDL_Surface* temp = NULL;
    SDL_Surface* text = NULL;

    temp = SDL_CreateRGBSurface( SDL_SWSURFACE|SDL_SRCALPHA,
                                 offset.w, fnt->height(),
                                 screen->format->BitsPerPixel,
                                 screen->format->Rmask,
                                 screen->format->Gmask,
                                 screen->format->Bmask,
                                 0 );

    text = SDL_CreateRGBSurface( SDL_SWSURFACE|SDL_SRCALPHA,
                                 offset.w, offset.h,
                                 screen->format->BitsPerPixel,
                                 screen->format->Rmask,
                                 screen->format->Gmask,
                                 screen->format->Bmask,
                                 amask );

    SDL_Rect rect;
    rect.x = rect.y = 0;
    rect.w = offset.w;
    rect.h = offset.h;

    Uint32 background = SDL_MapRGB( text->format, 0x00, 0xFF, 0xFF );

    SDL_FillRect( text, &rect, background );

    rect.h = fnt->height();


    // Populate surfaces
    for ( int line = 0; line < vlines.size(); ++line ) {

        SDL_FillRect( temp, &rect, background );

        int xpos = 0;

        // Print characters on temp surface
        for ( int i = 0; i < vlines[line].length(); ++i ) {
            fnt->print( vlines[line], temp, xpos, 0 );
            xpos += fnt->calcWidth( vlines[line] );
        }


        if ( flags & GFX_TXT_ALIGN_CENTER )
          rect.x = (offset.w - fnt->calcWidth( vlines[line] )) / 2;

        else if ( flags & GFX_TXT_ALIGN_RIGHT )
          rect.x = offset.w - fnt->calcWidth( vlines[line] );

        else
          rect.x = 0;

        rect.y = line * fnt->height();

        // Blit temp surface on text surface
        SDL_BlitSurface( temp, NULL, text, &rect );
    }

    SDL_FreeSurface( temp );


    // Modify text surface
    SDL_SetColorKey( text, SDL_SRCCOLORKEY, background );

    Uint32 pixel = SDL_MapRGB( text->format, color.r, color.g, color.b );


    if( SDL_MUSTLOCK( text ) )
      SDL_LockSurface( text );


    if ( flags & GFX_TXT_SMOOTH ) {

        for ( int i = 0; i < text->w; ++i ) {
            for ( int j = 0; j < text->h; ++j ) {

                int alpha = 255 - (int)getPixel32( i, j, text );

                pixel = SDL_MapRGBA( text->format, color.r, color.g,
                                     color.b, alpha );

                putPixel32( i, j, text, pixel );
            }
        }

    }

    else {

        for ( int i = 0; i < text->w; ++i ) {
            for ( int j = 0; j < text->h; ++j ) {

                Uint32 reading = getPixel32( i, j, text );

                if ( reading < 128 )
                  putPixel32( i, j, text, pixel );

                else
                  putPixel32( i, j, text, background );
            }
        }

    }


    if( SDL_MUSTLOCK( text ) )
      SDL_UnlockSurface( text );


    // Finish
    if ( flags & GFX_TXT_RETURN_SURFACE )
      return text;

    else
      this->blitSurface( text, x, y, flags );

    SDL_FreeSurface( text );

    return 0;
}

The problem lies within this piece of code:
    text = SDL_CreateRGBSurface( SDL_SWSURFACE|SDL_SRCALPHA,
                                 offset.w, offset.h,
                                 screen->format->BitsPerPixel,
                                 screen->format->Rmask,
                                 screen->format->Gmask,
                                 screen->format->Bmask,
                                 amask ); // <-- Problem!
The variables amask (and rmask, gmask, bmask) are member variables of the class, I set them in the constructor as such (ripped directly from the SDL documentation):
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
#else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
#endif
The problem is, that for some reason, my entire screen is discoloured (even though none of the code messes with my screen->format->*mask). Also, the masking for my printString() function doesn't work, the surface ends up being one block of one colour. However, if I don't use any variables for the masks, and just hardcode 0xff000000 as the amask for the text surface, everything works just dandy. This is weird, seeing the variable amask should also be that value. I don't understand what this whole masking thing is about anyway, and Google hasn't been of much help either. What is this SDL_BYTEORDER thingamagic? Also, why would I want to create variables that are set at compiler time, instead of just hardcoding the correct value in my function? What is the "correct" way to do things here? Thanks for any help

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by c4c0d3m0n
    text = SDL_CreateRGBSurface( SDL_SWSURFACE|SDL_SRCALPHA,
offset.w, offset.h,
screen->format->BitsPerPixel,
screen->format->Rmask,
screen->format->Gmask,
screen->format->Bmask,
amask ); // <-- Problem!



The variables amask (and rmask, gmask, bmask) are member variables of the class, I set them in the constructor as such (ripped directly from the SDL documentation):


Then why aren't you using them for the call? :)

Quote:
I don't understand what this whole masking thing is about anyway


"masking" means taking a binary number and clearing all the bits that don't fit within the 'mask', with bitwise AND.

The idea is, the bitmap represents the image with a 4-byte value for each pixel, and each byte of the 4-byte value represents a different component of the colour - red, green, blue and alpha. The mask is used in combination with a shift to extract each individual byte, where needed. When you make the SDL call, you need to tell it what masks to use, because...

Quote:
What is this SDL_BYTEORDER thingamagic?


...of endianness. Basically, there isn't a totally universal standard as to which byte represents red, which is green, etc. Or rather, we always represent red in the "most significant" byte, but that byte might be either first or last in order as you scan through increasing memory addresses.

The SDL_BYTEORDER, SDL_BIG_ENDIAN and SDL_LITTLE_ENDIAN values are pre-set depending on what hardware you're on (using a simple test: a pointer is made to an int with a known value, cast to a pointer-to-character, and then the value in that character is checked, to see if it's the most-significant or least-significant byte of the known value).

Quote:
Also, why would I want to create variables that are set at compiler time, instead of just hardcoding the correct value in my function? What is the "correct" way to do things here?


As you have it, just actually using the values that you set in the proper places. The reason you set the values this way is so that, when you later compile the code on another computer, that compiler can set the values in a different way - the way that is correct for that hardware.

Share this post


Link to post
Share on other sites
The reason I'm not using screen->format->amask for the call is because the screen's amask is 0. I need a proper amask for the text surface though, because it will smoothen out the text.

Now, I changed my code, I got rid of the variables rmask, gmask and bmask. I just have the variable amask that is still initialized the same way. What I get now is very funny. The program I wrote that uses this class is just a test app printing Hello World in white text on a black screen. What happens though, is that everytime I start the program, the backgroundcolor is not black, but rather some random color. It changes everytime I start the program again. What is going on here? Why does the alpha mask of the text layer (which is only as big as the text itself) change the entire screen colour???

Also, it's important to note that this weird discoloration only happens when I use the variable and set it through the precompiler commands. If I just hardcode in the correct value in SDL_CreateRGBSurface, nothing is wrong, and everything works fine.


A side question: Wouldn't it also be possible to use SDL_BYTEORDER at runtime, so I wouldn't have to recompile on a machine with different endianness?

Share this post


Link to post
Share on other sites
Update:

I don't know what went wrong, but a make clean && make all fixed the problem of the random background colour. Now, the variable amask works like I want (with precompiler endianness). I still want to know whether there isn't a way to determine the endianness at runtime, so people don't have to recompile the code when they want to run my program.

Share this post


Link to post
Share on other sites
Quote:

The SDL_BYTEORDER, SDL_BIG_ENDIAN and SDL_LITTLE_ENDIAN values are pre-set depending on what hardware you're on (using a simple test: a pointer is made to an int with a known value, cast to a pointer-to-character, and then the value in that character is checked, to see if it's the most-significant or least-significant byte of the known value).

Unless SDL has changed its method since I last looked then it does not do a runtime setting as you describe yet uses the preprocessor and checks the predefined macros to figure if little or big endian is defined otherwise it works on the platform macros.

Quote:

I still want to know whether there isn't a way to determine the endianness at runtime
Hmmm did you read Zahlman's post?


edit:
Hmm well it seems the configure script may use the runtime check itself if on a unix environment, otherwise it falls back to the method I previously mentioned.

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
The reason I'm not using screen->format->amask for the call is because the screen's amask is 0. I need a proper amask for the text surface though, because it will smoothen out the text.


Nonononononono. I meant, why aren't you using the Graphics' rmask, gmask and bmask?

Share this post


Link to post
Share on other sites
Quote:
Original post by CmpDev
Quote:

The SDL_BYTEORDER, SDL_BIG_ENDIAN and SDL_LITTLE_ENDIAN values are pre-set depending on what hardware you're on (using a simple test: a pointer is made to an int with a known value, cast to a pointer-to-character, and then the value in that character is checked, to see if it's the most-significant or least-significant byte of the known value).

Unless SDL has changed its method since I last looked then it does not do a runtime setting


I wasn't describing a runtime setting. ;) You can write code that does that with *initializations* of global variables, and then the compiler optimizes it all away at compile time:


int endian_test = 2 << 24 | 1;
char SDL_BYTEORDER = *(reinterpret_cast<char*>(&endian_test)); /* either 1 or 2 */


Something like that, anyway.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!