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.

P#54942 2018-08-10 21:40 ( Edited 2018-08-11 01:40)

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 :)

P#54945 2018-08-11 03:25 ( Edited 2018-08-11 07:39)

@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

P#54950 2018-08-11 11:07 ( Edited 2018-08-11 16:12)

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!

P#54960 2018-08-11 13:49 ( Edited 2018-08-11 19:27)

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?

P#54973 2018-08-11 17:30 ( Edited 2018-08-11 21:30)

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)

P#54977 2018-08-11 17:59 ( Edited 2018-08-11 21:59)

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.

P#54980 2018-08-11 20:00 ( Edited 2018-08-12 00:01)

@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

P#55010 2018-08-12 15:34 ( Edited 2018-08-12 22:21)

@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?

P#55091 2018-08-13 18:02 ( Edited 2018-08-13 22:02)

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)

P#55119 2018-08-14 04:05 ( Edited 2018-08-14 08:07)

@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?

P#55146 2018-08-14 15:30 ( Edited 2018-08-14 19:30)

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).

P#55148 2018-08-14 15:43 ( Edited 2018-08-14 19:43)

@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

P#55154 2018-08-14 16:23 ( Edited 2018-08-14 20:36)

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...

P#55163 2018-08-14 17:58 ( Edited 2018-08-14 21:58)

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?

P#55164 2018-08-14 18:36 ( Edited 2018-08-14 23:31)

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

 local mask=shl(0xfff8,(w-1))
P#65760 2019-07-11 06:30

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.

P#65761 2019-07-11 08:35

oh thanks

P#65768 2019-07-11 18:07

@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
P#65780 2019-07-11 22:17

what is a ‘rotation offset’??

P#65787 2019-07-12 05:34

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

P#65800 2019-07-13 02:48

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

  • rotation around center
  • translation to rotated position
P#65809 2019-07-13 07:18

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-28 21:12:26 | 0.055s | Q:54