Rotating SDL_Surfaces

Since SDL doesn't have it's own function for rotating images and I'm tired of storing multiple angles of the same sprite in a file, I created my own function for doing so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//XY Class
class XY
{
public:
    XY(){}
    XY(float x, float y);

    float X;
    float Y;

    float Magnitude();
    void Display();

    XY operator+( XY other );
    XY operator-( XY other );
    XY operator+=( XY other );
    XY operator-=( XY other );

    XY operator*( float scalar );
    XY operator/( float scalar );
    XY operator*=( float scalar );
    XY operator/=( float scalar );

    XY operator-();
    bool operator==( XY other );
};

XY::XY(float x,float y)
{
    X = x;
    Y = y;
}

float XY::Magnitude()
{
    return sqrt( pow(X,2) + pow(Y,2) );
}

void XY::Display()
{
    cout<<'('<<X<<','<<Y<<')'<<endl;
}

XY XY::operator*( float scalar )
{
    return XY( X*scalar, Y*scalar );
}

XY XY::operator*=( float scalar )
{
    X *= scalar;
    Y *= scalar;
}

XY XY::operator+( XY other )
{
    return XY( X + other.X, Y + other.Y );
}

XY XY::operator+=( XY other )
{
    X += other.X;
    Y += other.Y;
}

XY XY::operator-( XY other )
{
    return XY( X - other.X, Y - other.Y );
}

XY XY::operator-=( XY other )
{
    X -= other.X;
    Y -= other.Y;
}

XY XY::operator/( float scalar )
{
    return XY( X/scalar, Y/scalar );
}

XY XY::operator/=( float scalar )
{
    X /= scalar;
    Y /= scalar;
}

XY XY::operator-()
{
    return XY( -X, -Y );
}

bool XY::operator==( XY other )
{
    return ( X == other.X && Y == other.Y );
}
//Functions
XY Rotate( float degrees ,XY Vector, XY Origin )
{ //I use -degrees so it rotates counter clock wise
    XY Difference = Vector - Origin;
    return XY( cos(-degrees * PI/180 ) * Difference.X - sin( -degrees * PI/180 ) * Difference.Y,
               sin(-degrees * PI/180 ) * Difference.X + cos( -degrees * PI/180 ) * Difference.Y )
               + Origin;
}

void Set_Pixel( SDL_Surface* Surface, int x, int y, Uint32 Pixel )
{
    Uint32* Pixels = (Uint32*)Surface->pixels;
    Pixels[ x + Surface->w*y ] = Pixel;
}

Uint32 Get_Pixel( SDL_Surface* Surface, int x, int y )
{
    Uint32* Pixels = (Uint32*)Surface->pixels;
    return Pixels[ x + Surface->w*y ];
}

SDL_Surface* Spin( SDL_Surface* Surface, float degrees, SDL_Surface* Buffer)
{ //Surface must be a square and Buffer has to be wider and longer
    if ( Buffer == NULL or
         Buffer->w < Surface->w or
         Buffer->h < Surface->h or
         Surface->w != Surface->h
         )
        exit(0xBAD);

    int Width = Surface->w, Height = Surface->h;
    SDL_Surface* Return = Buffer;

    for ( int x = 0; x < Return->w; x++ )
        for ( int y = 0; y < Return->h; y++ )
            Set_Pixel( Return, x, y, SDL_MapRGB( Return->format, 0, 255, 255 ) );

    for ( int x = 0, x2 = 0; x < Width; x++ )
        for ( int y = 0, y2 = 0; y < Height; y++ )
        {
            x2 = Rotate( degrees, XY(x,y), XY( Width/2, Height/2 ) ).X;
            y2 = Rotate( degrees, XY(x,y), XY( Width/2, Height/2 ) ).Y;
            if ( x2 + Return->w*y2 < 0 )
                continue;
            Set_Pixel( Return, x2, y2, Get_Pixel( Surface, x, y ) );
        }

    return Return;
}


The problem is while Spin does spin the surface correctly, some pixels are rotated to the same new position so gaps appear in the returned surface. I need a way of filling in the gaps so the returned image looks better. A link to a program I made that uses this function is below so you can see the problem that I'm talking about.

http://www.mediafire.com/?cvk78bawxp9gdyw

Anyone have any ideas on what I could do?

Edit:
I currently use SDL 1.2. Could my problem be fixed if I used 2.0? For example, does SDL 2.0 have a built in function for rotating surfaces?
Last edited on
The SDL_gfx library has surface rotation/zoom in it.

Having a library of surfaces that are pre-rotated is preferred -- always offload as much processing as possible to somewhere other than your main event loop.

In terms of your code, you are thinking about it backwards. Scan rasters across the final surface, and sample the source image pixels, interpolating colors as appropriate.

1
2
3
4
5
6
7
for (yf in dest->h)
for (xf in dest->w)
  {
  xs, ys = Rotate( -degrees, XY( xf, yf ), XY( ... ) );

  Set_Pixel( dest, xf, yf, Get_Pixel( source, xs, ys ) );
  }

The above code just grabs the most convenient pixel, meaning that the resulting image will have obvious artifacts in it.

If you wish to actually sample the source image instead of just getting the closest pixel, make sure that xs and ys are float and then get the four closest pixel colors. Weight them by how close they are to the point, then combine them using a simple linear average. (Remember to handle each color component separately.)

Hope this helps.
Thanks for the help. I modified my Spin function a little using your advice ( I didn't follow your advice exactly for sake of simplicity since the surface I'm rotating is all one color ), but I'm going to check out SDL_gfx for future programs instead of using my function.
Personally I wouldn't spend too much time looking into SDL_gfx and try to switch over to opengl to do scaling/rotating etc. It will perform much faster and I'm sure it will help in the future.

(I am guessing you have thought of this already as well).
Topic archived. No new replies allowed.