Log In  


does anybody have a good rspr(n, x, y, w, h, r, ox, oy, flipx, flipy) function to draw rotated sprites?
I need this to make my 4 player spaceship battle game.




See the ‘Gyrus’ demo cart in this thread:
https://www.lexaloffle.com/bbs/?tid=3593

You’ll find a rspr function that is fast and pixel perfect :)


@dddaaannn
the first one u linked doesn't seem to be in a function and I can't read it well enough to put it in one to try it out

the second one you linked doesn't fit what I need and when I tried to fix it it doesn't draw right

@freds72 u mean this one?

Cart #54948 | 2018-08-11 | Code ▽ | Embed ▽ | No License

Cart #54949 | 2018-08-11 | Code ▽ | Embed ▽ | No License

this uses weird arguments as it doesn't let me specify a height

function rspr(sx,sy,x,y,a,w)
	local ca,sa=cos(a),sin(a)
	local srcx,srcy,addr,pixel_pair
	local ddx0,ddy0=ca,sa
	local mask=shl(0xfff8,(w-1))
	w*=4
	ca*=w-0.5
	sa*=w-0.5
	local dx0,dy0=sa-ca+w,-ca-sa+w
	w=2*w-1
	for ix=0,w do
		srcx,srcy=dx0,dy0
		for iy=0,w do
			if band(bor(srcx,srcy),mask)==0 then
				local c=sget(sx+srcx,sy+srcy)
				sset(x+ix,y+iy,c)
			else
				sset(x+ix,y+iy,rspr_clear_col)
			end
			srcx-=ddy0
			srcy+=ddx0
		end
		dx0+=ddx0
		dy0+=ddy0
	end
end

also if you mean the first one then it doesn't work properly for example putting in 32 for argument s should be tile 0,2 but its not.

EDIT: something like sprr(s,x,y,w,h,r) should work


You can’t put height because I only ever needed to rotate square sprites!
Adding a height should be easy.

Note that this version actually writes to the sprite sheet, replace sset by pset to draw on screen.

As for:
« 
EDIT: something like sprr(s,x,y,w,h,r) should work
« 
Sorry, that’s Pico-8, either you roll put tour own sprr function or work with what other did.
Don’t expect someone else to do your own code!


ok sorry so I took a try at it from the top of my head and got this...

function sprr(s,x,y,w,h,r)
  local xr=sin(r/360)
  local yr=cos(r/360)
  local sx=flr(s%16) * 8
  local sy=flr(s/16) * 8
  for yy=sy,sy+h*8-1 do 
  for xx=sx,sx+w*8-1 do
   local dc=sget(xx,yy)
   -- this should get the rotated loop position
  	local dx=x+(xx-sx) * xr 
  	local dy=y+(yy-sy) * yr

  	pset(x+xx,y+yy, dc)
  end 
  end
end

however dx and dy is not correct do you know what could be wrong?


To have a clean rotated sprie with no holes, you must go through the target region (eg square ir rectangle) and get the rotated pixel that should be at position. Suggest to read the Dr Dobbs article I took the code from (linked in the post I mention)


I thought thats what I am doing.
I am offsetting the current pixel position by a angle and length.

I did take a look at that dr dobbs page you posted in the other topic though, I really didn't understand it.


@freds72 can you tell me what I am doing wrong with dx and dy?

so here is another attempt to create it..

function sprr(s,x,y,w,h,r)
  local rx=cos(r/360)
  local ry=sin(r/360)
  local sx=flr(s%16) * 8
  local sy=flr(s/16) * 8
  local ex=sy+h*8-1
  local ey=sx+w*8-1
  local rr=ry*ry+rx*rx

  for yy=sy,ey do 
  for xx=sx,ex do
   local dx=( ry*yy+rx*xx)/rr+w
   local dy=(-ry*xx+rx*yy)/rr+h
   local dc=sget(dx,dy)
  	pset(x+xx,y+yy, dc)
  end 
  end
end

based it on this.. https://www.lexaloffle.com/bbs/?tid=2189


@freds72 so this time I tried my best to follow the dr dobbs tutorial and reference it to yours and I got this..

function sprr(s,x,y,w,h,r)

	local sx=flr(s % 16) * 8
	local sy=flr(s / 16) * 8
	local sw=w*8
	local sh=h*8
	local dx=x
	local dy=y
	local dw=w*8
	local dh=h*8

 local colx = sin(r/360)
 local coly = cos(r/360)
 local rowx = coly;
 local rowy =-colx;

 local srtu = sx - (dx * coly + dy * colx);
 local srtv = sy - (dx * rowy + dy * rowx);
 local rowu = srtu;
 local rowv = srtv;

 for y=0, dh do
 	local u = rowu
 	local v = rowv
 for x=0, dw do
 	local su = ((u < 0.0 and -u or u) + sw) % sw
 	local sv = ((v < 0.0 and -v or v) + sh) % sh

 	pset(dx+x, dy+y, pget(su, sv))

 	u += rowx
 	v += rowy
 end
 	rowu += rowx
 	rowv += rowy
 end
end

can you please take a look at it and tell me whats wrong?


Looks like a plain typo:
pset(..,..,pget(..))
should read:
pset(..,..,sget(..))
(that is read from spritesheet, write on screen)

edit: you are not iterating over the right direction:
u+=rowx
v+=rowy
must be:
u+=colx
v+=coly

Otherwise, looks ok (it’s fine to start with a very verbose version and optimize after)


@freds72 thankyou for the reply.

is there any optimizations I could make besides ingnoring color 0?

also I see your version has a mask so it doesn't draw outside of the source tiles, but I had a hard time understanding it can you explain how to do that in mine?


The fully optimized version is mine ;)
You’re version as a lot of useless variables and intermediate variables that you can rid of.

The mask indicates if the value is above the width/height of the sprite (expressed as a power of 2).


@freds72 I was messing around and I came up with a compact version.
the only problem is that it seems to rotate the src pixels and slows down at certain angles

function sprrt1(s,x,y,w,h,r)

	local spx=flr(s%16)*8
	local spy=flr(s/16)*8

	w*=8
	h*=8
 r=r/360

	for iy=0,h do
	for ix=0,w do

	local sx=spx+ cos(-r)*ix+sin(-r)*iy
	local sy=spy+-sin(-r)*ix+cos(-r)*iy
	local sc=sget(sx,sy)
	//local bnd=sx<spx or sy<spy or sx>spx+w or sy>spy+h

	//if sc>0 and not bnd then 

	pset(x+ix,y+iy,sc)

	end
	end
end

https://gph.is/2OCbFTu

edit: i wanted it to rotate around center


Sorry @Shadowblitz but I gave the source code for a fast and correct sprite rotating function.
I am not going to redo the same work again for your version.

Hint: do not calculate 4 sin/cos for every single pixel...


can you at least fix your version then so it takes in a height parameter?
this is basically your code but with h implemented and mask taken out because I don't know how to do the mask with h included.
it also has a bug where it rotating the src rectangle.

function sprr(s,x,y,w,h,r)

	local rx=cos(r/360)
	local rx=cos(r/360)
	local ry=sin(r/360)
	local sx=flr(s % 16) * 8
	local sy=flr(s / 16) * 8
	local ddx0=rx
	local ddy0=ry  

	w*=4
	h*=4
	rx*=w-0.5
	ry*=h-0.5

	local dx0= ry-rx+w
	local dy0=-rx-ry+h

	w=2*w-1
	h=2*h-1

 for iy=0,h do
 	local srcx = dx0
 	local srcy = dy0
 for ix=0,w do
 	local c=sget(sx+srcx,sy+srcy)
 	pset(x+ix,y+iy,c)
 	srcx -= ddy0
 	srcy += ddx0
 end
 	dx0 += ddx0
 	dy0 += ddy0
 end
end

if your not going to help people adapt your code for something that should have been implemented to begin with, then why did you even post a link to your code in the first place?


@freds72
so what do I do with this function to add a height paramater?

 local mask=shl(0xfff8,(w-1))

you cannot unless you have 2 masks (which defeats the point).
So just check if source pixel is outside boundaries (0,0,w,h) and you should be good.


oh thanks


@freds72

how would I add a rotation offset to the function?

function rspr(n,x,y,w,h,a,ax,ay)
	print(a,64,64,7)
	ax=ax or 0
	ay=ay or 0
	a = flr(a/22.5)*22.5
	local sx,sy=flr(n%16)*8,flr(n/16)*8 
	local ca,sa=cos(a/360),sin(a/360)
	local srcx,srcy,addr,pixel_pair
	local ddx0,ddy0=ca,sa
	local mask=shl(0xfff8,(w-1))
	w*=4
	h*=4
	ca*=w-0.5
	sa*=h-0.5
	local dx0,dy0=sa-ca+w,-ca-sa+h
	w=2*w-1
	h=2*h-1
	for ix=0,w do
		srcx,srcy=dx0,dy0
		for iy=0,h do
			if contains(srcx,srcy,0,0,w,h) then
				local c=sget(sx+srcx,sy+srcy)
				pset(x+ix,y+iy,c)
			else
				pset(x+ix,y+iy,rspr_clear_col)
			end
			srcx-=ddy0
			srcy+=ddx0
	 end
	 dx0+=ddx0
	 dy0+=ddy0
	end
end

what is a ‘rotation offset’??


it's a rotation x and y offset from the center


This is done outside of the function - you need to decompose as:

  • rotation around center
  • translation to rotated position


[Please log in to post a comment]