improve rope rendering
authoralfadur
Thu, 23 May 2019 20:37:41 +0300
changeset 15040 a315927a44b2
parent 15039 981f16edea02
child 15041 7328f16bd299
improve rope rendering
hedgewars/uGearsRender.pas
hedgewars/uRender.pas
--- a/hedgewars/uGearsRender.pas	Thu May 23 13:41:14 2019 +0200
+++ b/hedgewars/uGearsRender.pas	Thu May 23 20:37:41 2019 +0300
@@ -95,102 +95,64 @@
 end;
 
 
-function DrawRopeLine(X1, Y1, X2, Y2, roplen: LongInt; LayerIndex: Longword): LongInt;
-var  eX, eY, dX, dY: LongInt;
-    i, sX, sY, x, y, d: LongInt;
-    b: boolean;
-    angle: real;
+procedure DrawRopeLine(X1, Y1, X2, Y2: Real; LayerIndex: Longword; var linesLength, ropeLength: Real);
+var dX, dY, angle, length: Real;
+    FrameIndex: LongWord;
 begin
     if (X1 = X2) and (Y1 = Y2) then
-        begin
-        //OutError('WARNING: zero length rope line!', false);
-        DrawRopeLine:= 0;
-        exit
-        end;
-    eX:= 0;
-    eY:= 0;
+        exit;
+
     dX:= X2 - X1;
     dY:= Y2 - Y1;
+    length:= sqrt(sqr(dX) + sqr(dY));
     angle:= arctan2(dY, dX) * 180 / PI - 90;
 
-    if (dX > 0) then
-        sX:= 1
-    else
-        if (dX < 0) then
-            begin
-            sX:= -1;
-            dX:= -dX
-            end
-        else sX:= dX;
-
-    if (dY > 0) then
-        sY:= 1
-    else
-        if (dY < 0) then
-            begin
-            sY:= -1;
-            dY:= -dY
-            end
-        else
-            sY:= dY;
-
-    if (dX > dY) then
-        d:= dX
-    else
-        d:= dY;
+    dX:= dX / length;
+    dY:= dY / length;
 
-    x:= X1;
-    y:= Y1;
-
-    for i:= 0 to d do
-        begin
-        inc(eX, dX);
-        inc(eY, dY);
-        b:= false;
-        if (eX > d) then
-            begin
-            dec(eX, d);
-            inc(x, sX);
-            b:= true
-            end;
-        if (eY > d) then
-            begin
-            dec(eY, d);
-            inc(y, sY);
-            b:= true
-            end;
-        if b then
-            begin
-            inc(roplen);
-            if (roplen mod (cRopeNodeStep * cRopeLayers)) = (cRopeNodeStep * LayerIndex) then
-                DrawSpriteRotatedF(sprRopeNode, x, y, roplen div cRopeNodeStep, 1, angle);
-            end
+    while (ropeLength - linesLength) <= length do
+    begin
+        FrameIndex:= round(ropeLength / cRopeNodeStep);
+        if (FrameIndex mod cRopeLayers) = LayerIndex then
+            DrawSpriteRotatedFReal(sprRopeNode,
+                X1 + (ropeLength - linesLength) * dX,
+                Y1 + (ropeLength - linesLength) * dY,
+                FrameIndex, 1, angle);
+        ropeLength:= ropeLength + cRopeNodeStep;
     end;
-    DrawRopeLine:= roplen;
+    linesLength:= linesLength + length
 end;
 
 procedure DrawRopeLayer(Gear: PGear; LayerIndex: LongWord);
-var roplen, i: LongInt;
+var i: LongInt;
+    linesLength, ropeLength: Real;
 begin
-    roplen:= 0;
+    linesLength:= 0;
+    ropeLength:= cRopeNodeStep;
     if RopePoints.Count > 0 then
     begin
         i:= 0;
         while i < Pred(RopePoints.Count) do
         begin
-            roplen:= DrawRopeLine(hwRound(RopePoints.ar[i].X) + WorldDx, hwRound(RopePoints.ar[i].Y) + WorldDy,
-                                  hwRound(RopePoints.ar[Succ(i)].X) + WorldDx, hwRound(RopePoints.ar[Succ(i)].Y) + WorldDy, roplen, LayerIndex);
+            DrawRopeLine(hwFloat2Float(RopePoints.ar[i].X) + WorldDx, hwFloat2Float(RopePoints.ar[i].Y) + WorldDy,
+                         hwFloat2Float(RopePoints.ar[Succ(i)].X) + WorldDx, hwFloat2Float(RopePoints.ar[Succ(i)].Y) + WorldDy,
+                         LayerIndex, linesLength, ropeLength);
             inc(i)
         end;
-        roplen:= DrawRopeLine(hwRound(RopePoints.ar[i].X) + WorldDx, hwRound(RopePoints.ar[i].Y) + WorldDy,
-                              hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, roplen, LayerIndex);
-        roplen:= DrawRopeLine(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy,
-                              hwRound(Gear^.Hedgehog^.Gear^.X) + WorldDx, hwRound(Gear^.Hedgehog^.Gear^.Y) + WorldDy, roplen, LayerIndex);
+
+        DrawRopeLine(hwFloat2Float(RopePoints.ar[i].X) + WorldDx, hwFloat2Float(RopePoints.ar[i].Y) + WorldDy,
+                     hwFloat2Float(Gear^.X) + WorldDx, hwFloat2Float(Gear^.Y) + WorldDy,
+                     LayerIndex, linesLength, ropeLength);
+
+        DrawRopeLine(hwFloat2Float(Gear^.X) + WorldDx, hwFloat2Float(Gear^.Y) + WorldDy,
+                     hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + WorldDx, hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) + WorldDy,
+                     LayerIndex, linesLength, ropeLength);
     end
     else
         if Gear^.Elasticity.QWordValue > 0 then
-            roplen:= DrawRopeLine(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy,
-                                  hwRound(Gear^.Hedgehog^.Gear^.X) + WorldDx, hwRound(Gear^.Hedgehog^.Gear^.Y) + WorldDy, roplen, LayerIndex);
+            DrawRopeLine(hwFloat2Float(Gear^.X) + WorldDx, hwFloat2Float(Gear^.Y) + WorldDy,
+                         hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + WorldDx, hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) + WorldDy,
+                         LayerIndex, linesLength, ropeLength);
 end;
 
 procedure DrawRope(Gear: PGear);
--- a/hedgewars/uRender.pas	Thu May 23 13:41:14 2019 +0200
+++ b/hedgewars/uRender.pas	Thu May 23 20:37:41 2019 +0300
@@ -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 DrawSpriteRotatedFReal(Sprite: TSprite; X, Y: Real; 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;
@@ -1152,7 +1153,7 @@
 
 if Angle <> 0  then
     begin
-    // Check the bounding circle 
+    // Check the bounding circle
     if isCircleOffscreen(X, Y, (sqr(SpritesData[Sprite].Width) + sqr(SpritesData[Sprite].Height)) div 4) then
         exit;
     end
@@ -1186,6 +1187,45 @@
 
 end;
 
+procedure DrawSpriteRotatedFReal(Sprite: TSprite; X, Y: Real; Frame, Dir: LongInt; Angle: real);
+begin
+
+    if Angle <> 0  then
+    begin
+        // Check the bounding circle
+        if isCircleOffscreen(round(X), round(Y), (sqr(SpritesData[Sprite].Width) + sqr(SpritesData[Sprite].Height)) div 4) then
+            exit;
+    end
+    else
+    begin
+        if isDxAreaOffscreen(round(X) - SpritesData[Sprite].Width div 2, SpritesData[Sprite].Width) <> 0 then
+            exit;
+        if isDYAreaOffscreen(round(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 angle after (conditional) mirroring
+    if Angle <> 0  then
+        openglRotatef(Angle, 0, 0, 1);
+
+    UpdateModelviewProjection;
+
+    DrawSprite(Sprite, -SpritesData[Sprite].Width div 2, -SpritesData[Sprite].Height div 2, Frame);
+
+    openglPopMatrix;
+
+    UpdateModelviewProjection;
+
+end;
+
 procedure DrawSpritePivotedF(Sprite: TSprite; X, Y, Frame, Dir, PivotX, PivotY: LongInt; Angle: real);
 begin
 if Angle <> 0  then