コートスニペット: SDL_gfxで回転

SDL_Surfaceを任意の座標を中心に回転する関数を書いたのでメモ。

ただし毎回rotozoomで回転させるようなことは計算量の関係で避けた方がいい。座標の計算を参考にする程度で。

#include <SDL.h>
#include <SDL_rotozoom.h>
#include <SDL_gfxPrimitives.h>

void draw(SDL_Surface *src,
	  int cx, int cy,
	  int  x, int  y,
	  SDL_Surface *dst,
	  double angle,
	  double zoom_x, double zoom_y)
{
  double 	 th, s_th, c_th;
  SDL_Surface 	*s1;
  SDL_Rect 	 drect;
  Sint16	 w, h;

  if ( angle == 0 && zoom_x == 1 && zoom_y == 1)
    {
      s1 = src;
      drect.x = x - cx;
      drect.y = y - cy;
    }
  else if ( angle == 0 )
    {
      s1 = zoomSurface (src, zoom_x, zoom_y, 0);
      drect.x = x - zoom_x * cx;
      drect.y = y - zoom_y * cy;
    }
  else
    {
      w = src->w * zoom_x;
      h = src->h * zoom_y;

      if (angle>0)
	{
	  while (angle>360.0)
	    angle -= 360.0;
	}
      else
	{
	  while (0 > angle)
	    angle += 360.0;
	}

      th   = angle * 2.0 * M_PI / 360.0;
      s_th = sin(th);
      c_th = cos(th);

      // [MEMO] ほんとはx,y方向の倍率を引数で指定したいんだけど
      //        rotozoomSurfaceXYがちゃんと動かない
      //s1 = rotozoomSurfaceXY (src, angle, zoom_x, zoom_y, 0);
      s1   = rotozoomSurfaceXY (src, angle, zoom_x, zoom_x, 0);

      drect.x = x - ( c_th * zoom_x * cx + s_th * zoom_y *cy);
      drect.y = y - (-s_th * zoom_x * cx + c_th * zoom_y *cy);

      if (th < M_PI/2.0)
	{
	  //drect.x -= 0;
	  drect.y -= w * s_th;
	}
      else if (th < M_PI)
	{
	  drect.x -= -w * c_th;
	  drect.y -=  s1->h;
	  //drect.y -=  w * s_th - h * c_th;
	}
      else if (th < 3 * M_PI / 2)
	{
	  //drect.x -= s1->w ;
	  drect.x -= -w * c_th - h * s_th;
	  drect.y -=           - h * c_th;
	}
      else
	{
	  drect.x -= -h * s_th;
	  //drect.y -= 0;
	}
    }

  SDL_BlitSurface(s1, NULL, dst, &drect);

  if (s1 != src)
    SDL_FreeSurface(s1);
}

int main(int argc, char* argv[])
{
  int		 x, y;
  int		 cx, cy;
  int 		 frame;
  SDL_Surface 	*scr;
  SDL_Surface 	*s;
  double 	 angle, zoom;

  SDL_Init(SDL_INIT_EVERYTHING);

  scr	= SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE|SDL_DOUBLEBUF);

  s	= SDL_LoadBMP("icon.bmp");

  x	= 320;
  y	= 240;
  cx	= s->w / 2;
  cy	= s->h / 2;
  angle = -180;
  zoom	= 1.5;

  frame	= 0;

  while(frame++ < 360)
    {
      angle += 5;

      SDL_FillRect(scr, NULL, SDL_MapRGB(scr->format,0,0,0) );

      draw(s, cx, cy,  x, y, scr, angle, zoom, zoom);

      lineRGBA(scr, 
	       320-2, 240,
	       320+2, 240,
	       0x00, 0xff, 0x00, 0xff);

      lineRGBA(scr, 
	       320, 240-2,
	       320, 240+2,
	       0x00, 0xff, 0x00, 0xff);

      SDL_UpdateRect(scr, 0, 0, scr->w, scr->h);
    }

  SDL_Quit();
  return 0;
}