hedgewars/uRender.pas
changeset 12119 3374e0f67f39
parent 11824 3f1f8f79fcdb
child 12189 31184d9b9bfc
--- 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