The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
Sprite Origin positions
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
Does anyone have a way of positioning a sprite based on a defined origin for the graphic, so that if the origin is set to the middle (for example), x and y coordinates would position the sprite so that the centre of the sprite would be at the coordinates.

The main problem is that whilst SDL can rotate an object around defined coordinates, positioning is still based on the top-left coordinate, causing the usual way of calculating the position :

Code:
cosp = COS(angle);
      sinp = SIN(angle);
      sx = sourceRect.w / 2.0;
      sy = sourceRect.h / 2.0;

      px = point.x - sx;
      py = point.y - sy;

      rx = ((px*cosp + py*sinp) * scaleX)+sx;
      ry = ((py*cosp - px*sinp) * scaleY)+sy;
      
      destRect.x = (int) (x - rx);
      destRect.y = (int) (y - ry);


to fail to give the correct positions - calculating the correct origin position needs to take into account the sprites angle and scale.
Sprite Origin positions
Sanette
Guest

a nice geometry exercice. Here is what I found (only rotation, without scaling)

assume that the top left corner of your initial rect is (x0,y0).
I call (x0+cx,y0+cy) the position of the center of rotation.
Here is the formula for the top-left position of the rect containing the rotated sprite:

x1 = x0 + cx - cx*cosp - cy*sinp + min(cosp,0)*w + min(sinp,0)*h
y1 = y0 + cy + cx*sinp - cy*cosp + min(cosp,0)*h - max(sinp,0)*w

note that the angle is computed counterclock-wise (standard math convention)
cosp=cos(angle)
sinp=sin(angle)


For the scaling, I cannot answer right now, because I need to know if you apply the scaling before rotation or after rotation
(if scalex <> scaley, this makes a difference)

S.

Le 19/09/2014 01:09, MrTAToad a écrit :

Quote:
Does anyone have a way of positioning a sprite based on a defined origin for the graphic, so that if the origin is set to the middle (for example), x and y coordinates would position the sprite so that the centre of the sprite would be at the coordinates.

The main problem is that whilst SDL can rotate an object around defined coordinates, positioning is still based on the top-left coordinate, causing the usual way of calculating the position :








Code: cosp = COS(angle);
      sinp = SIN(angle);
      sx = sourceRect.w / 2.0;
      sy = sourceRect.h / 2.0;

      px = point.x - sx;
      py = point.y - sy;

      rx = ((px*cosp + py*sinp) * scaleX)+sx;
      ry = ((py*cosp - px*sinp) * scaleY)+sy;
      
      destRect.x = (int) (x - rx);
      destRect.y = (int) (y - ry);


to fail to give the correct positions - calculating the correct origin position needs to take into account the sprites angle and scale.


Quote:
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
I presume SDL2 does scaling first (or rather it acts on a defined size) and then rotation.
Sprite Origin positions
Sanette
Guest

I made some quick tests and it seems that SDL_RenderCopyEx does all the calculations for you:

if you rotate a texture around some point p, then the rotated image is displayed the way you want, that is, the point p has not moved.

But, if you also scale the image by providing a dstRect, then SDL_RenderCopyEx does not scale p for you; it first scales the texture, and then rotates around the point given by the original coordinates of p.

Therefore, the only thing you have to do, is simply to scale p before rotating. Of course, since you want that the image to be stretched around p you need to make the following transforms:
srcRect = (x,y,w,h), center=(cx,cy)   ===> dstRect = (x+cx*(1-scalex), y+cy*(1-scaley), w*cx, h*cy)

and THEN, apply SDL_RenderCopyEx
It should do exactly what you want


Le 19/09/2014 11:48, MrTAToad a écrit :

Quote:
I presume SDL2 does scaling first (or rather it acts on a defined size) and then rotation.


Quote:
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Sprite Origin positions
Sanette
Guest

Le 19/09/2014 17:33, Sanette a écrit :

Quote:
I made some quick tests and it seems that SDL_RenderCopyEx does all the calculations for you:

if you rotate a texture around some point p, then the rotated image is displayed the way you want, that is, the point p has not moved.

But, if you also scale the image by providing a dstRect, then SDL_RenderCopyEx does not scale p for you; it first scales the texture, and then rotates around the point given by the original coordinates of p.

Therefore, the only thing you have to do, is simply to scale p before rotating. Of course, since you want that the image to be stretched around p you need to make the following transforms:
srcRect = (x,y,w,h), center=(cx,cy)   ===> dstRect = (x+cx*(1-scalex), y+cy*(1-scaley), w*cx, h*cy)


I forgot to add that the "center" to use in RenderCopyEx is now (scalex*cx, scaley*cy)

Quote:
and THEN, apply SDL_RenderCopyEx
It should do exactly what you want


Le 19/09/2014 11:48, MrTAToad a écrit :

Quote:
I presume SDL2 does scaling first (or rather it acts on a defined size) and then rotation.


Quote:
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org



Quote:
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Sprite Origin positions
arosian


Joined: 22 Oct 2013
Posts: 13
Hi,
Look in to using SDL_RenderCopyEx. One of the parameters is described as such:
" a pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done aroud dstrect.w/2, dstrect.h/2)" On Sep 18, 2014 7:09 PM, "MrTAToad" wrote:
Quote:
Does anyone have a way of positioning a sprite based on a defined origin for the graphic, so that if the origin is set to the middle (for example), x and y coordinates would position the sprite so that the centre of the sprite would be at the coordinates.

The main problem is that whilst SDL can rotate an object around defined coordinates, positioning is still based on the top-left coordinate, causing the usual way of calculating the position :



Code:


cosp = COS(angle);
      sinp = SIN(angle);
      sx = sourceRect.w / 2.0;
      sy = sourceRect.h / 2.0;

      px = point.x - sx;
      py = point.y - sy;

      rx = ((px*cosp + py*sinp) * scaleX)+sx;
      ry = ((py*cosp - px*sinp) * scaleY)+sy;
      
      destRect.x = (int) (x - rx);
      destRect.y = (int) (y - ry);




to fail to give the correct positions - calculating the correct origin position needs to take into account the sprites angle and scale.


_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Sprite Origin positions
Sanette
Guest

Le 19/09/2014 17:38, Sanette a écrit :

Quote:
Le 19/09/2014 17:33, Sanette a écrit :

Quote:
I made some quick tests and it seems that SDL_RenderCopyEx does all the calculations for you:

if you rotate a texture around some point p, then the rotated image is displayed the way you want, that is, the point p has not moved.

But, if you also scale the image by providing a dstRect, then SDL_RenderCopyEx does not scale p for you; it first scales the texture, and then rotates around the point given by the original coordinates of p.

Therefore, the only thing you have to do, is simply to scale p before rotating. Of course, since you want that the image to be stretched around p you need to make the following transforms:

arg, another typo:
Quote:
Quote:
srcRect = (x,y,w,h), center=(cx,cy)   ===> dstRect = (x+cx*(1-scalex), y+cy*(1-scaley), w*scalex, h*scaley)


I forgot to add that the "center" to use in RenderCopyEx is now (scalex*cx, scaley*cy)

Quote:
and THEN, apply SDL_RenderCopyEx
It should do exactly what you want



now it works (I have tested it) !
Sprite Origin positions
Jonny D


Joined: 12 Sep 2009
Posts: 932
Just to put it out there...  SDL_gpu blits images at their center points by default, so positioning with scaling and rotation works without any extra effort.  When a pivot point is used (GPU_BlitTransformX()), then the image is rendered relative to that point (i.e. you can use 0,0 as the hotspot, which is what SDL does normally).


Jonny D
Re: Sprite Origin positions
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
Dont forget that is the point for which rotation is performed around, not the origin for plotting the sprite.

arosian wrote:
Hi,
Look in to using SDL_RenderCopyEx. One of the parameters is described as such:
" a pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done aroud dstrect.w/2, dstrect.h/2)" On Sep 18, 2014 7:09 PM, "MrTAToad" wrote:
Quote:
Does anyone have a way of positioning a sprite based on a defined origin for the graphic, so that if the origin is set to the middle (for example), x and y coordinates would position the sprite so that the centre of the sprite would be at the coordinates.

The main problem is that whilst SDL can rotate an object around defined coordinates, positioning is still based on the top-left coordinate, causing the usual way of calculating the position :



Code:


cosp = COS(angle);
      sinp = SIN(angle);
      sx = sourceRect.w / 2.0;
      sy = sourceRect.h / 2.0;

      px = point.x - sx;
      py = point.y - sy;

      rx = ((px*cosp + py*sinp) * scaleX)+sx;
      ry = ((py*cosp - px*sinp) * scaleY)+sy;
      
      destRect.x = (int) (x - rx);
      destRect.y = (int) (y - ry);




to fail to give the correct positions - calculating the correct origin position needs to take into account the sprites angle and scale.


_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Re: Sprite Origin positions
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
Having a slight problem with it at the moment. The following is rotating and scaling around an origin (100,100). Unfortunately the coordinates aren't resulting in the centre of the sprite being there :

Code:
       switch (GETXHANDLE()) {
         case    TOPLEFT:   centre.x = 0;              break;
         case    MIDDLE:   centre.x = sourceRect.w / 2;   break;
         case    BOTTOMRIGHT:   centre.x = sourceRect.w - 1;   break;
            };

        switch (GETYHANDLE()) {
         case    TOPLEFT:   centre.y = 0;              break;
         case    MIDDLE:   centre.y = sourceRect.h / 2;   break;
         case    BOTTOMRIGHT:   centre.y = sourceRect.h - 1;    break;
            };

      destRect.x = (int)(x + centre.x*(1 - scaleX));
      destRect.y = (int)(y + centre.y*(1 - scaleY));
      destRect.w = (int)(sourceRect.w*scaleX);
      destRect.h = (int)(sourceRect.h*scaleY);

      point.x = (int)(centre.x*scaleX);
      point.y = (int)(centre.y*scaleY);

                if (SDL_RenderCopyEx(m_mainRenderer,
                        sprite->texture,&sourceRect,&destRect,angle,&point,SDL_FLIP_NONE)<0)
               {
         throw(CMP_SDL_ERROR);
               }


[img]https://onedrive.live.com/redir?resid=DD5B5E7788984419!6230&authkey=!AKX9BHox8k0YKoA&v=3&ithint=photo%2cpng[/img]

Sanette wrote:
Le 19/09/2014 17:38, Sanette a écrit :

Quote:
Le 19/09/2014 17:33, Sanette a écrit :

Quote:
I made some quick tests and it seems that SDL_RenderCopyEx does all the calculations for you:

if you rotate a texture around some point p, then the rotated image is displayed the way you want, that is, the point p has not moved.

But, if you also scale the image by providing a dstRect, then SDL_RenderCopyEx does not scale p for you; it first scales the texture, and then rotates around the point given by the original coordinates of p.

Therefore, the only thing you have to do, is simply to scale p before rotating. Of course, since you want that the image to be stretched around p you need to make the following transforms:

arg, another typo:
Quote:
Quote:
srcRect = (x,y,w,h), center=(cx,cy)   ===> dstRect = (x+cx*(1-scalex), y+cy*(1-scaley), w*scalex, h*scaley)


I forgot to add that the "center" to use in RenderCopyEx is now (scalex*cx, scaley*cy)

Quote:
and THEN, apply SDL_RenderCopyEx
It should do exactly what you want



now it works (I have tested it) !
[img][/img]
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
I think I may have solved it with a quick change of the calculations to :

Code:
centre.x *= scaleX;
      centre.y *= scaleY;
      //centre.x = centre.y = 0;

      destRect.x = (int)(x - centre.x);
      destRect.y = (int)(y - centre.y);
      destRect.w = (int)(sourceRect.w*scaleX);
      destRect.h = (int)(sourceRect.h*scaleY);

      point.x = (int) centre.x;
      point.y = (int) centre.y;


Which produces a correct position of :

[img]https://onedrive.live.com/redir?resid=DD5B5E7788984419!6231&authkey=!AOKt2b7arja3N4o&v=3&ithint=photo%2cpng[/img]

I just need to check now to make sure that positions are correct when the origin is the top-left and bottom-right of a sprite now, but initial tests look fine...
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
My change did work fine with all 9 possible origin positions.

My rendering code is now thus :

Code:
       // Calculate final size
        switch (mode) {
            case    RESIZE      :   // Resize to a given size - calculate the scaling value
                           scaleX = scaleX / sourceRect.w;
                           scaleY = scaleY / sourceRect.h;
                                    break;

            case    SCALE       :   // Scale to indiviual values
                                    // Do nothing
                                    break;

         default            :   // Standard scaling
                           scaleX = 1.0;
                           scaleY = 1.0;
                           break;
            };

      if (scaleX == 0.0 || scaleY == 0.0) return true;

        switch (GETXHANDLE()) {
         case    TOPLEFT      :   pointX = 0;              break;
         case    MIDDLE      :   pointX = sourceRect.w / 2;   break;
         case    BOTTOMRIGHT   :   pointX = sourceRect.w - 1;   break;
            };

        switch (GETYHANDLE()) {
         case    TOPLEFT      :   pointY = 0;              break;
         case    MIDDLE      :   pointY = sourceRect.h / 2;   break;
         case    BOTTOMRIGHT   :   pointY = sourceRect.h - 1;    break;
            };

      pointX *= scaleX;
      pointY *= scaleY;
      //centre.x = centre.y = 0;

      destRect.x = (int)(x - pointX);
      destRect.y = (int)(y - pointY);
      destRect.w = (int)(sourceRect.w*scaleX);
      destRect.h = (int)(sourceRect.h*scaleY);

      point.x = (int)pointX;
      point.y = (int)pointY;

      SDL_SetTextureAlphaMod(sprite->texture,blendModes[TEXTURE-TEXTURE].amount);
        SDL_SetTextureBlendMode(sprite->texture,blendModes[TEXTURE-TEXTURE].mode);
      SDL_SetTextureColorMod(sprite->texture, blendModes[TEXTURE - TEXTURE].r,
                        blendModes[TEXTURE - TEXTURE].g,
                        blendModes[TEXTURE - TEXTURE].b);

        if (SDL_RenderCopyEx(m_mainRenderer,
                        sprite->texture,&sourceRect,&destRect,angle,&point,SDL_FLIP_NONE)<0)
        {
         throw(CMP_SDL_ERROR);
        }