[Ohrrpgce] Slice rotation and zoom

Ralph Versteegen teeemcee at gmail.com
Fri Mar 1 19:23:52 PST 2019


On Sun, 24 Feb 2019 at 08:31, James Paige <Bob at hamsterrepublic.com> wrote:
>
> That is all very interesting!
>
> > Right now, rotating around a custom offset and specialising
> > SliceX/YAnchor() to compensate for that offset + rotation angle seems
> > preferable. Funny, I almost got rid of those functions a couple weeks
> > ago because they seemed unneeded.
>
> I think I agree with your conclusions here, although some of this is over my head, and I don't understand all the issues 100%

I would have checked in my addition of rotation and zoom to sprite
slices already, but I think I have a dozen different features and
bugfixes all mixed together in my working copy right now and it's
taking me a while to untangle them!

If the only option was to rotate a sprite by multiples of 90 degrees
and/or to stretch/shrink it, it seems pretty obvious that rotating by
90 degrees should swap the width & height, before stretching/shrinking
is applied based on on the overridden slice width/height. But allowing
arbitrary rotations, it seems that we have to (act as if we) do the
stretching first, then rotate (though practically they are done at the
same time), because stretching/shrinking a rotated sprite causes skew,
which is also useful but not what you want 95% of the time. (So I'm
glad we didn't implement 90 degree slice rotations yet!)

Anyway, back to the question of the size of a rotated sprite.
If we change only SliceX/YAnchor, then the position of rotated sprites
will be correct, but using Slice.Size as the "screen size" will be
wrong.
Just like Slice.Pos and Slice.ScreenPos are separate, we could in
principle add Slice.ScreenSize (possibly as a property rather than a
member) which returns the "resulting" size for things like slice
collisions.

When I spoke of "bounding boxes" I was thinking of the axis-aligned
box around the rotated sprite, which goes through its 4 rotated
corners.
But that box can be much larger than the sprite itself, so it's
dubious whether it would be better than using the unrotated
Slice.Size, though it varies by the purpose.

To help decide what size would be appropriate to use, I did a survey
for code which uses slice size and excluding stuff specific to other
slice types and stuff which looks like it won't break, and found (I'm
likely to have missed something):
-child positioning (alignment)
-children which 'Fill Parent'
-child clipping
-slice clamping (both the new slice clamping setting and ClampSlice)
-EdgeYSortChildSlices (via SliceX/YAnchor)
-Cover Children
-sliceedit ants
-Scroll slices and ScrollToChild
-Layout slices
-SliceCollide, SliceCollidePoint, FindSliceCollision,
FindSliceAtPoint, SliceContains, SliceClamp
-"move slice with wallchecking"
-Scripts which want to know a slice's top-left corner: "slice screen
x/y" return the position of a slice's anchor point, not its top-left
corner, making it the only code I saw that cares about where the
anchor point is rather than the top-left. To get the top-left of a
slice, you either need to check the slice's anchor settings and
convert from anchor position to top-left yourself, or otherwise add
"slice edge x/y(sl, edge:top/left)" to its parent's screen position.
But doing the calculation manually will give the wrong result for
rotated slices because of the special case anchoring, and using "slice
edge x/y" don't work (you could say "broken") for Panel, Grid and
Layout parents. So that's unfortunate. I guess we should add some new
commands, or maybe an arg to "slice screen x/y"

So all of the above would be using the wrong size for rotated sprites.
None of these look terribly bad, but many look inconvenient.

-for collision checking, using the bounding box is probably a bit
better than not changing the size at all, if you want to swing a sword
in an arc and simply use "find colliding slice". There are also other
choices aside from the bounding box, but they're pretty arbitrary - I
don't see any clear choice for which rectangle to use, they all look
highly suboptimal. But that's not really anything new: an axis-aligned
rectangular hitbox be might be bad for any sprite "far from
rectangular". Maybe some day we'll have different hitbox shape options
for the purposes of slice collision: axis-aligned bounding box,
rotated rectangle (same as axis-aligned rectangle except for Lines and
rotated Sprites), circular, maybe union of circles/rects. But not
ellipses **

-for clamping (and also scrolling, Scroll and Layout), using the
bounding box for the size ensures that the sprite doesn't go outside
the clamp area at all. But it also causes the center of the sprite to
move about as it's rotated if it's on the boundary, which is probably
even uglier than escaping the clamp area. Also, note that the

-for positioning/clipping/filling/covering of child slices, if the
coordinates of the child slice aren't rotated to match their parent,
then I don't see much preference to do things one way or another - it
doesn't seem useful. But it would be good to be consistent with other
usage of slice size

(Also, Layout slices ignore child anchor points, meaning that sprites
attached to a layout slice will always rotate around their centers.
Maybe I should change that.)

Also, in addition to all of that slice stuff, I also need to make some
changes in rotozoom.c. There are bugs in the original code (eg
combining a rotation with different x and y zoom doesn't work) and I
want to make it draw straight to the destination rather than creating
a temporary surface. Then as a bonus we can finally get rid of the
temp surfaces used by DrawSpriteSlice for horizontally and vertically
flipped sprites!


** Checking for collision between two circles is trivial, checking for
collision between a circle or an ellipse and an axis-aligned
rectangle/line is easy, checking for collision between a arbitrary
ellipse/circle and arbitrary rectangle is also fairly straightforward,
checking for collision between an ellipse and a circle is the seventh
ellipse of mathematician hell: http://yehar.com/blog/?p=2926
Even that approximate solution is huuuuuuuuuuge (though I'm sure there
are simpler ones)






>
> ---
> James Paige
>
>
> On Fri, Feb 22, 2019 at 5:51 PM Ralph Versteegen <teeemcee at gmail.com> wrote:
>>
>> I've added a rotozoomer and slice rotate/zoom options, though there
>> are various things that need to be addressed before I expose it to
>> users. And those are mostly to do with slice positioning. This email
>> is about that, and not anything interesting.
>>
>> It's natural that changing the size of a sprite slice should stretch
>> its sprite to match its width and height, just like lines, rects and
>> ellipses.
>> The hidden "scaled" sprite slice setting (a bool), only available in
>> 32-bit color mode, already acts like this. (I'll be getting rid of
>> this now-redundant setting).
>> Sprite slices could still have zoom/zoom x/zoom y properties, but they
>> could just provide an alternative way to set the size of the slice.
>> (But sub-pixel zoom is a nice thing to have, so I'll probably still
>> store the zoom separately. I need to modify the rotozoomer to support
>> this.)
>> We will need a backcompat bit to enable zooming, because you can
>> already change the width and height of a sprite by setting it to fill,
>> but it does nothing. (Even though "set slice width/height" is
>> disallowed, Fill Parent is a loophole)
>>
>> That's all fine, but rotation is a problem. As they rotate, the size
>> of the axis-aligned bounding box changes. But if you want to set both
>> the sprite size and rotation, the slice width and height should be the
>> non-rotated size, not the bounding box size.
>>
>> But if bounding box is used for positioning/alignment, it would mean
>> their position can't be calculated like other slices.
>> And how should child slices of the sprite be positioned, how should
>> the Fill Parent setting for both the sprite and its children work,
>> "Cover Children", "slice at pixel", and whatever else I've forgotten?
>>
>> In a perfect world, perhaps all children of a rotated sprites would be
>> rotated too, like an OpenGL transformation matrix stack... but we
>> wouldn't really expect child slices of a stretched sprite to be
>> stretched in the same way. I think that if we ever implemented
>> whole-slice-tree zooming/rotating, they should actually be completely
>> separate slice properties, not sprite properties. Still, even if the
>> child slices aren't rotated, maybe the alignment points on the rotated
>> parent should be rotated too, for convenience when positioning? Oh,
>> but then child X and Y offsets would also have to be rotated for
>> consistency. How about we assume that in future we would add separate
>> settings to rotate and stretch a slice tree, so anything we add now
>> should be orthogonal to that instead of overlapping: we shouldn't add
>> transformation of child positions now, because there's a better way to
>> do it later.
>>
>> Still, that leaves the problem that the bounding box size is not equal
>> to the "specified size" set in the slice editor/by scripts.
>> If rotated sprites always rotated around their center and we treated
>> the bounding box size as being equal to the specified size, even
>> though the drawn sprite might extend far outside it, then all the
>> problems can go away. "slice at pixel" could always be given special
>> cases for rotated sprites, ellipses, and lines anyway.
>>
>> But you should be able to customise the point around which a sprite is
>> rotated, otherwise correctly positioning a sprite rotated around a
>> corner (eg a swung weapon) would require complicated calculations by
>> the user.
>> At a minimum sprites should rotate around their anchor point, but even
>> that's not flexible enough - for a weapon swung in an arc the point
>> should actually be outside the sprite. You could add blank space to
>> the sprite, though.
>> Again, if the bounding box size and position didn't change at all
>> there would be no problem, except the sprite is likely to be
>> completely outside its bounding box! That seems a tad ridiculous. If
>> the box size didn't change but the position did that seems reasonable
>> enough, and only the calculation of the anchor point would need to be
>> specialised. Allowing the size to change requires replacing most
>> occurrences of sl->Width and sl->Height in the code!
>>
>> Another example: a ball rolling along the top of a surface. You might
>> want its anchor point to be the bottom of the slice, but to rotate
>> around the center.
>>
>> Right now, rotating around a custom offset and specialising
>> SliceX/YAnchor() to compensate for that offset + rotation angle seems
>> preferable. Funny, I almost got rid of those functions a couple weeks
>> ago because they seemed unneeded.
>> _______________________________________________
>> Ohrrpgce mailing list
>> ohrrpgce at lists.motherhamster.org
>> http://lists.motherhamster.org/listinfo.cgi/ohrrpgce-motherhamster.org
>
> _______________________________________________
> Ohrrpgce mailing list
> ohrrpgce at lists.motherhamster.org
> http://lists.motherhamster.org/listinfo.cgi/ohrrpgce-motherhamster.org


More information about the Ohrrpgce mailing list