Sub-pixel movement and Anti-Aliased rotation

From Directorforum Collaboration Wiki

Jump to: navigation, search

Moving sprites can be really ugly. Rotating sprites can be really ugly. Nice rotation and movement comes at a CPU cost. For some applications the speed of this code might be good enough, for others it will be too slow. 128x128 image takes 1 ms to be rotated and scaled down to 32x32. {on my computer} It does look nicer than doing the same with a sprite.


---------------------------------------------------------------------
--  Code by Arnold Wuis, 29-jan-2010, Director forum, Collab Wiki  --
---------------------------------------------------------------------
 
 
 
Global BigBuffer
on FinalSubPixel(HoekRAD, location, SourceImage, HalfBufferDim)
  -- The Code assumes a 4 times bigger source image than destination image
 
 
 
  aQuad=RotateRect(SourceImage.Rect, HoekRAD) --rotates the source image; returns a Quad with center at (0,0)
 
  -- Gets the Rect enveloping the Quad {center at (0,0)}
  QuadRect=getQuadRect(aQuad)
 
  -- Source Mod, Makes the Source image bigger if it is not a factor 4 ( 4x4 pixels are mapped back to 1x1 pixel )
  ModX= QuadRect.width mod 4 > 1 
  ModY= QuadRect.height mod 4 > 1
 
  -- Dest Mod , Source image can also have 2 pixels outlined resulting in a destination image that has 2 half pixels on each side. 
  -- This is prevented by adding 2 half pixels in the destination (or better 2 pixel outline in Source image)
  DestModX=2*((QuadRect.width/4) mod 2)
  DestModY=2*((QuadRect.height/4) mod 2)
 
 
  -- Total Inflate, because the Quad and Rect have their center at 0,0 inflate will keep it that way
  -- combination of space needed for sub-pixel placement, the Source Modulo and the destination modulo
  QuadRect=QuadRect.Inflate(2+ModX+DestModX, 2+ModY,DestModY)
 
  -- Sub pixel offset -2...2, -2..2 ;
  aOffset=[integer(    (   Location[1]  -integer(location[1])  )*4), integer(    (  Location[2]  -integer(location[2])    )*4)]  
  -- (every 4x4 pixel is a real pixel so by moving inside this you can get sub pixels)
  aOffset=aOffset+[HalfBufferDim, HalfBufferDim] --half of big buffer size will put the Quad in the center
 
  -- copy the rotated image tot the buffer with the center of the image at the center of the buffer
  BigBuffer.copyPixels(SourceImage, aQuad+[aOffset, aOffset, aOffset, aOffset] , SourceImage.Rect )
 
  -- copy the size of the used buffer to the stage with a scale of 1/4
  (the stage).image.copyPixels(BigBuffer, (QuadRect/4).offset(location[1], location[2]) , QuadRect.offset(HalfBufferDim, HalfBufferDim))
  -- clean the buffer to be used again with the next image
  BigBuffer.fill(QuadRect.offset(HalfBufferDim, HalfBufferDim) , rgb(255,255,255) )
 
end
 
 
 
on RotateRect(aRect, AngleRAD) 
  -- center for Rect and for Quad result
  NewCenter=vector(aRect.Width/2, aRect.Height/2, 0)
  -- Vector(0,0,0)-NewCenter (leftTop van Rect=0,0)
  LeftTop=-NewCenter
  -- RightTop
  RightTop=Vector(aRect[3],0,0)-NewCenter
 
  --rotationMatrix 
 
  cosAngle=cos(angleRAD)
  sinAngle=sin(AngleRAD)
 
  aQuad=[]
  -- newleftTop
  aQuad.add(point(LeftTop[1]*cosAngle-LeftTop[2]*sinAngle, LeftTop[1]*SinAngle+leftTop[2]*cosAngle))
  -- newRightTop
  aQuad.add(point(RightTop[1]*cosAngle-RightTop[2]*sinAngle, RightTop[1]*SinAngle+RightTop[2]*cosAngle))
  aQuad.add(-aQuad[1]) --RightBottom
  aQuad.add(-aQuad[2]) --LeftBottum
 
  -- Quad with center at (0,0)
  return aQuad 
 
 
end
 
 
on GetQuadRect(aQuad)
 
  -- returns the outline Rect of a Quad
 
  MinimaleXwaarde=Min([ aQuad[1][1], aQuad[2][1], aQuad[3][1], aQuad[4][1] ])
  MinimaleYwaarde=Min([ aQuad[1][2], aQuad[2][2], aQuad[3][2], aQuad[4][2] ])
 
  MaximaleXwaarde=Max([ aQuad[1][1], aQuad[2][1], aQuad[3][1], aQuad[4][1] ])
  MaximaleYwaarde=Max([ aQuad[1][2], aQuad[2][2], aQuad[3][2], aQuad[4][2] ])
 
 
  return rect(minimaleXwaarde, MinimaleYwaarde, MaximaleXWaarde, maximaleYwaarde)
end
Personal tools