Sprite Origin positions

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.

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 - cxcosp - cysinp + 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 :> 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
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

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

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), wcx, hcy)

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

Le 19/09/2014 11:48, MrTAToad a ?crit :> I presume SDL2 does scaling first (or rather it acts on a defined

size) and then rotation.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

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

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), wcx, hcy)

I forgot to add that the “center” to use in RenderCopyEx is now
(scalexcx, scaleycy)> and THEN, apply SDL_RenderCopyEx

It should do exactly what you want

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

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


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

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:

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
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

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

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

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:

srcRect = (x,y,w,h), center=(cx,cy) ===> dstRect =
(x+cx*(1-scalex), y+cy*(1-scaley), wscalex, hscaley)

I forgot to add that the “center” to use in RenderCopyEx is now
(scalexcx, scaleycy)

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

now it works (I have tested it) !

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

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” <mrtatoad at mrtatoad.plus.com (mrtatoad at mrtatoad.plus.com)> wrote:

  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 = ((pxcosp + pysinp) * scaleX)+sx;
?? ??? ??ry = ((pycosp - pxsinp) * 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
SDL at lists.libsdl.org (SDL at lists.libsdl.org)
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org (http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org)

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);
           }

Sanette wrote:

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

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

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:

srcRect = (x,y,w,h), center=(cx,cy)?? ===> dstRect = (x+cx*(1-scalex), y+cy*(1-scaley), wscalex, hscaley)

I forgot to add that the “center” to use in RenderCopyEx is now (scalexcx, scaleycy)

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

now it works (I have tested it) !

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 :

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…

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);
    }