--- a/hedgewars/uRender.pas Sun Jan 15 12:49:26 2017 -0500
+++ b/hedgewars/uRender.pas Sun Jan 15 12:50:27 2017 -0500
@@ -34,6 +34,7 @@
procedure DrawSpriteClipped (Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
procedure DrawSpriteRotated (Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
procedure DrawSpriteRotatedF (Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
+procedure DrawSpritePivotedF(Sprite: TSprite; X, Y, Frame, Dir, PivotX, PivotY: LongInt; Angle: real);
procedure DrawTexture (X, Y: LongInt; Texture: PTexture); inline;
procedure DrawTexture (X, Y: LongInt; Texture: PTexture; Scale: GLfloat);
@@ -73,6 +74,7 @@
procedure FinishRender();
function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
+function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; inline;
// 0 => not offscreen, <0 => left/top of screen >0 => right/below of screen
function isDxAreaOffscreen(X, Width: LongInt): LongInt; inline;
@@ -147,6 +149,20 @@
isAreaOffscreen:= (isDxAreaOffscreen(X, Width) <> 0) or (isDyAreaOffscreen(Y, Height) <> 0);
end;
+function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; inline;
+var dRightX, dBottomY, dLeftX, dTopY: LongInt;
+begin
+ dRightX:= (X - ViewRightX);
+ dBottomY:= (Y - ViewBottomY);
+ dLeftX:= (ViewLeftX - X);
+ dTopY:= (ViewTopY - Y);
+ isCircleOffscreen:=
+ ((dRightX > 0) and (sqr(dRightX) > RadiusSquared)) or
+ ((dBottomY > 0) and (sqr(dBottomY) > RadiusSquared)) or
+ ((dLeftX > 0) and (sqr(dLeftX) > RadiusSquared)) or
+ ((dTopY > 0) and (sqr(dTopY) > RadiusSquared))
+end;
+
function isDxAreaOffscreen(X, Width: LongInt): LongInt; inline;
begin
if X > ViewRightX then exit(1);
@@ -1131,11 +1147,8 @@
if Angle <> 0 then
begin
- // sized doubled because the sprite might occupy up to 1.4 * of it's
- // original size in each dimension, because it is rotated
- if isDxAreaOffscreen(X - SpritesData[Sprite].Width, 2 * SpritesData[Sprite].Width) <> 0 then
- exit;
- if isDYAreaOffscreen(Y - SpritesData[Sprite].Height, 2 * SpritesData[Sprite].Height) <> 0 then
+ // Check the bounding circle
+ if isCircleOffscreen(X, Y, sqr(SpritesData[Sprite].Width) + sqr(SpritesData[Sprite].Height)) then
exit;
end
else
@@ -1164,6 +1177,43 @@
end;
+procedure DrawSpritePivotedF(Sprite: TSprite; X, Y, Frame, Dir, PivotX, PivotY: LongInt; Angle: real);
+begin
+if Angle <> 0 then
+ begin
+ // Check the bounding circle
+ // Assuming the pivot point is inside the sprite's rectangle, the farthest possible point is 3/2 of its diagonal away from the center
+ if isCircleOffscreen(X, Y, 9 * (sqr(SpritesData[Sprite].Width) + sqr(SpritesData[Sprite].Height)) div 4) then
+ exit;
+ end
+else
+ begin
+ if isDxAreaOffscreen(X - SpritesData[Sprite].Width div 2, SpritesData[Sprite].Width) <> 0 then
+ exit;
+ if isDYAreaOffscreen(Y - SpritesData[Sprite].Height div 2 , SpritesData[Sprite].Height) <> 0 then
+ exit;
+ end;
+
+openglPushMatrix;
+openglTranslatef(X, Y, 0);
+
+// mirror
+if Dir < 0 then
+ openglScalef(-1.0, 1.0, 1.0);
+
+// apply rotation around the pivot after (conditional) mirroring
+if Angle <> 0 then
+ begin
+ openglTranslatef(PivotX, PivotY, 0);
+ openglRotatef(Angle, 0, 0, 1);
+ openglTranslatef(-PivotX, -PivotY, 0);
+ end;
+
+DrawSprite(Sprite, -SpritesData[Sprite].Width div 2, -SpritesData[Sprite].Height div 2, Frame);
+
+openglPopMatrix;
+end;
+
procedure DrawTextureRotated(Texture: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
begin