超标肝功能检验报告单:SDL Scale Surface | SDLTutorials.com

来源:百度文库 编辑:九乡新闻网 时间:2024/05/05 12:38:49
  • Home
  • Forums
  • RSS
  • Register
  • Log in

SDLTutorials.com

SDL Tutorials – Game Tutorials – Programming Tutorials

SDL Scale Surface

July 15th, 2008 by Tim Jones Leave a reply ?

The following user tutorial was created by Mod J., for thepurpose of expanding upon the SDLTutorials.com series, and expoundingupon the use of SDL. This tutorial, though not purposely a part of theSDLTutorials.com or created for the series, may be a branch or additionto the series. Please read notes by the author for any additional codeand/or framework used by the author. If you wish to submit your owntutorial to this site, please visit the “User Tutorials” page.

Today we’re going to learn something about extending the capabilitiesof SDL_Surfaces. If we take a look at OpenGL, what happens when we loada Surface and we render it specifying a width and height bigger thanthe Surface’s original width and height? It gets automatically scaled(unless you specify you want to be repeated). In SDL there is noautomatic way of scaling surfaces, so we’re going to make a (relativelysimple) routine that does the trick.

First, the prototype of the function:

SDL_Surface* SDL_ScaleSurface(SDL_Surface* Surface, Uint16 Width, Uint16 Height);
 

What are these parameters? Well:
Surface: The original surface the caller of the function wants to be scaled.
Width: The width the caller wants the scaled surface to be (we use Uint16 because this is SDL’s standard for width).
Height: The height the caller wants the scaled surface to be (we use Uint16 because this is SDL’s standard for height).

Got that? If you didn’t, try reading it over again; if you did, then let’s move on.

First, we have to check if the Surface’s width and height are valid; this is simple to accomplish:

SDL_Surface* SDL_ScaleSurface(SDL_Surface* Surface, Uint16 Width, Uint16 Height)
{
    if(!Surface || !Width || !Height)
        return 0;
}
 

We don’t want a null pointer specified, since it will make BAD thingshappen when we try to read data from the surface. Secondly, a surfacewith 0 width or 0 height wouldn’t be a good idea, so let’s just return anull pointer when either of these things happen.

Now we need to create a surface that suits our needs; we’ll do this using the SDL_CreateRGBSurface function:

SDL_Surface* SDL_ScaleSurface(SDL_Surface* Surface, Uint16 Width, Uint16 Height)
{
    SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel,
        Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);
}
 

Here we’re declaring and defining the return surface. We want itsspecifications to be the same as the surface we got from the caller, sowe do so, and then the width and the height should be the same as theones the caller specified. Looks pretty simple to me .

Now comes the math part. We need to calculate the scaling (orstretching) factor to be applied when we copy the surface’s pixels. It’snot as hard as it seems, we just divide the width the caller wants bythe width of the surface, what have we calculated then? If you calculatethe scaling factor for the widths, you’ll get the number of pixels youneed for each individual source pixel, in other words, each pixel youread from the source surface has to be drawn SCALING_FACTOR_X times overthe width in order to stretch it (the same goes for the height).

Calculations:

SDL_Surface* SDL_ScaleSurface(SDL_Surface* Surface, Uint16 Width, Uint16 Height)
{
    double  _stretch_factor_x = (static_cast(Width)  / static_cast(Surface->w)),
        _stretch_factor_y = (static_cast(Height) / static_cast(Surface->h));
}
 

Casting might be bad to some of you, but it’s necessary here since weneed the scaling factors as a double. This probably could have beendone better, like checking for w = 0 and h = 0, but this is just asimple tutorial . We’re just doing here what I explained before.

Now we need to do the actual drawing. This might look overwhelming,but it’s not as hard as it seems. We’re just going to make 2 for-loopsto run across all the pixels on the source surface, and then 2 moreloops for drawing STRETCHING_FACTOR pixels for each pixel that gets readfrom the source surface.

Here we go!

SDL_Surface* SDL_ScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{
    for(Sint32 y = 0; y < Surface->h; y++) //Run across all Y pixels.
        for(Sint32 x = 0; x < Surface->w; x++) //Run across all X pixels.
            for(Sint32 o_y = 0; o_y < _stretch_factor_y; ++o_y) //Draw _stretch_factor_y pixels for each Y pixel.
                for(Sint32 o_x = 0; o_x < _stretch_factor_x; ++o_x) //Draw _stretch_factor_x pixels for each X pixel.
                    DrawPixel(_ret, static_cast(_stretch_factor_x * x) + o_x,
                        static_cast(_stretch_factor_y * y) + o_y, ReadPixel(Surface, x, y));
}
 

I’m not going to specify the DrawPixel and ReadPixel functions here, as they can be gotten from the SDL documentation wiki (http://www.libsdl.org/cgi/docwiki.cgi/Pixel_Access), though my prototype might be a little different, they work like this:

void DrawPixel(SDL_Surface* Target, Sint16 X, Sint16 Y, Uint16 Color); //Draws the specified color at the specified X and Y on the target surface.
Uint32 ReadPixel(SDL_Surface* Source, Sint16 X, Sint16 Y); //Returns the color of the specified surface on the specified X and Y coordinates.
 

The principle is pretty easy:

for(each_source_pixel) -> draw(scaling_factor_amount_of_pixels_on_the_return_value)
 

The DrawPixel call might look weird to you, but actually what happensinside is this: Draw a pixel on(the return value, stretching_factor_x *source_x because the destination moves each time and then blit theamount of pixels we need, same for y, what color do we need? The colorthat’s on the source surface at the x and y position, because we need toblit it scaling_factor amount of times).

Why the strange X and Y coordinates? Well, imagine we need to make the width twice as bug, look at this crappy drawing:

Source surface:---------------------------------------------|x,y       |0,0       |1,0       |2,0       |---------------------------------------------Destination:---------------------------------------------|x,y       |0,0 & 1,0 |2,0 & 3,0 |4,0 & 5,0 |---------------------------------------------

See? When at pixel (0,0) we need to draw a pixel at (0,0) and (1,0)because we need 2 pixels on the destination for each 1 pixel on thesource (following the X-axis because it’s the width), the same goes forthe Y. We’re actually just skipping what we’ve already drawn,_stretch_factor_x * x is actually ‘Move to the corresponding pixel onthe destination. It makes the (2,0) on the drawing say that it shouldbegin its drawing at (4,0) on the destination, then it loops o_x untillit’s smaller than 2, drawing first at (4,0) and then when o_x incrementsat (5,0). It’s THAT easy.

Finally we return the desired surface:

SDL_Surface *SDL_ScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{
    return _ret;
}
 

Here an overview of the full function:

SDL_Surface *ScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{
    if(!Surface || !Width || !Height)
        return 0;
   
    SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel,
        Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);

 

    double  _stretch_factor_x = (static_cast(Width)  / static_cast(Surface->w)),
        _stretch_factor_y = (static_cast(Height) / static_cast(Surface->h));

    for(Sint32 y = 0; y < Surface->h; y++)
        for(Sint32 x = 0; x < Surface->w; x++)
            for(Sint32 o_y = 0; o_y < _stretch_factor_y; ++o_y)
                for(Sint32 o_x = 0; o_x < _stretch_factor_x; ++o_x)
                    DrawPixel(_ret, static_cast(_stretch_factor_x * x) + o_x,
                        static_cast(_stretch_factor_y * y) + o_y, ReadPixel(Surface, x, y));

    return _ret;
}
 

I hope you learned something with this tutorial, maybe I’ll writemore tutorials in the future (perhaps something on texture repeating? ).

See ya!
Creature

Share and Enjoy:
Did you like this tutorial/blog post? Feel free to donate to keep more comin', and have more contests.

Posted in SDL Tutorials

You can follow any responses to this entry through the RSS 2.0 Feed.You can skip to the end and leave a response. Pinging is currently not allowed.

Advertisement

9 comments

Add your comment
  1. Sotiris June 10, 2010 at 9:59 am

    Could someone please post all the source code?

    Reply
  2. Johnny(TM) July 25, 2009 at 4:32 am

    This code works well, but if I try to scale a surface that has a 256 color palette, it returns a black surface. Why does it happen, and how can I fix it? My ReadPixel and DrawPixel function is a copy from the link in the tutorial.

    Reply
  3. Philip May 28, 2009 at 10:25 am

    Instead of x_scale*y_scale calls to DrawPixel for each source pixel, why not a single call to SDL_FillRect?

    Reply
  4. Creature August 26, 2008 at 1:43 pm

    Yeah, I know it isn’t the fastest thing around and there probably could be some optimizations like declaring x, y, o_y and o_x before the first for-loop so they don’t have to get created over and over again. The second argument of DrawPixel could also be calculated in the third for-loop instead of the fourth, now it has to be calculated over and over again as well. But anyway, it was just for learning practices .

    Reply
  5. Tim Jones August 20, 2008 at 7:37 am

    Andre,

    I haven’t had a chance to test it out, but I thought it was a good start to show people a method of how to scale a surface. Anyway, if you really wanted rotation/scaling I would take the leap to OpenGL. Otherwise, you’re going to take huge performance hits no matter what library you use (and I would choose SPriG over SDL_gfx).

    Reply
  6. Andre Botelho August 14, 2008 at 9:11 am

    I’ve tryed this code but it is a lot slow, othes SDL libs like Sprig or SDL_gfx are better choices but this here is good to learn how it works.
    Good work.

    Reply
  7. Creature July 15, 2008 at 1:52 pm

    I’d rather prefer Creature, but Mod J is fine too .

    Reply
  8. Tim Jones July 15, 2008 at 1:08 pm

    I could have sworn I put the other guys name in, fixed now.

    Reply
  9. Arseniy Banayev July 15, 2008 at 11:47 am

    Did I really write that?

    Reply

Leave a Reply

    • Root Beer Tapper Contest
      (Ends July 1, 2011)
    • C++ Tutorials
      1. C++ Tutorial Basics
      2. C++ Variables
      3. C++ Conditions
      4. C++ Strings
    • SDL Tutorials
      1. SDL Tutorial Basics
      2. SDL Coordinates and Blitting
      3. SDL Events
      4. SDL Tutorial Tic-Tac-Toe
      5. SDL Animation
      6. SDL Entities
      7. SDL Maps
      8. SDL Collision
      9. SDL Collision Events
      10. SDL Space Shooter (Part 1)
      11. SDL Space Shooter (Part 2)
      12. SDL Space Shooter (Part 3)
      13. SDL Space Shooter (Part 4)
    • SDL 1.3 Tutorials
      1. SDL 1.2 v. SDL 1.3
      2. Compile SDL 1.3 on Windows
      3. Compile SDL 1.3 on Mac OS X
      4. Compile SDL 1.3 on Linux
    • SDL + OpenGL Tutorials
      1. SDL + OpenGL Tutorial Basics
    • SDL Side Tutorials
      1. SDL Image
      2. SDL SoundBank
      3. SDL App States
    • SDL User Tutorials
      1. SDL Net Part 1
      2. SDL Net Part 2
      3. SDL Per Pixel Collision
      4. SDL Scale Surface
      5. SDL Sokoban
    • Blue Dino Code Tutorials
      1. Jonny D's C++ Tutorial
      2. MixBox Quick Guide
      3. A Guide to Graphics with Sprig
      4. Graphics from Scratch, Using SDL
      5. The Ins and Outs (and Overlays) of Alpha-blending
      6. Huh? My Pong clone uses 100% CPU and is still slow?
    • Recent Forum Posts
      • managing states...
      • Is this forum/website dead?...
      • Repeating background image...
      • {gamedesigncenter.org}...
      • SPriG - SDL Primitive Generator...
      • SDL_Net...
      • redrawing surfaces questions...
      • Key States problem...
      • SDL Collision Turtorial "CMap::GetT...
      • Indrajit Games...
    • Categories
      • Blue Dino Code (4)
      • C++ Tips (6)
      • C++ tutorials (8)
      • Charity (1)
      • Contests (13)
      • Kizare (2)
      • Music (1)
      • Podcasts (1)
      • Projects (1)
      • Resources (1)
      • SDL + OpenGL Tutorials (1)
      • SDL Featured Libraries (1)
      • SDL Tips (3)
      • SDL Tutorials (30)
      • Uncategorized (34)

      Back to Top

      2011 SDLTutorials.com · Proudly powered by WordPress&Green Park 2by Cordobo.

      Valid XHTML 1.0 Transitional | Valid CSS 3