DEADSOFTWARE

added actor rendering interpolation; fixed vsync on startup
[d2df-sdl.git] / src / game / g_gfx.pas
index 52c885692f6a5b61f994ce3f4942a954c0718043..bf8fc5aa2fd8a5e4d90b3dbd8ca47cbfb13ecfaa 100644 (file)
@@ -2,8 +2,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -104,6 +103,7 @@ type
   PParticle = ^TParticle;
   TParticle = record
     x, y: Integer;
+    oldX, oldY: Integer;
     velX, velY: Single;
     accelX, accelY: Single;
     state: TPartState;
@@ -140,6 +140,7 @@ type
   TOnceAnim = record
     AnimType:   Byte;
     x, y:       Integer;
+    oldX, oldY: Integer;
     Animation:  TAnimation;
   end;
 
@@ -334,36 +335,38 @@ end;
 function TParticle.checkAirStreams (): Boolean;
 var
   pan: TPanel;
+  r: Integer;
 begin
   pan := g_Map_PanelAtPoint(x, y, GridTagLift);
-  result := (pan <> nil);
+  result := (pan <> nil) and WordBool(pan.PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT));
+  r := Random(3);
   if result then
   begin
-    if ((pan.PanelType and PANEL_LIFTUP) <> 0) then
-    begin
-      if (velY > -1-Random(3)) then velY -= 0.8;
-      if (abs(velX) > 0.1) then velX -= velX/10.0;
-      velX += (Random-Random)*0.2;
-      accelY := 0.15;
-    end
-    else if ((pan.PanelType and PANEL_LIFTDOWN) <> 0) then
-    begin
-      if (velY < 1+Random(3)) then velY += 0.8;
-      accelY := 0.15;
-    end
-    else if ((pan.PanelType and PANEL_LIFTLEFT) <> 0) then
-    begin
-      if (velX > -8-Random(3)) then velX -= 0.8;
-      accelY := 0.15;
-    end
-    else if ((pan.PanelType and PANEL_LIFTRIGHT) <> 0) then
-    begin
-      if (velX < 8+Random(3)) then velX += 0.8;
-      accelY := 0.15;
-    end
-    else
-    begin
-      result := false;
+    case pan.LiftType of
+      LIFTTYPE_UP:
+      begin
+        if (velY > -1-r) then velY -= 0.8;
+        if (abs(velX) > 0.1) then velX -= velX/10.0;
+        velX += (Random-Random)*0.2;
+        accelY := 0.15;
+      end;
+      LIFTTYPE_DOWN:
+      begin
+        if (velY < 1+r) then velY += 0.8;
+        accelY := 0.15;
+      end;
+      LIFTTYPE_LEFT:
+      begin
+        if (velX > -8-r) then velX -= (8+r) div 2;
+        accelY := 0.15;
+      end;
+      LIFTTYPE_RIGHT:
+      begin
+        if (velX < 8+r) then velX += (8+r) div 2;
+        accelY := 0.15;
+      end;
+      else
+        result := false;
     end;
     // awake
     if result and (state = TPartState.Sleeping) then state := TPartState.Normal;
@@ -455,7 +458,7 @@ var
   ex: Integer;
 begin
   if (not force) and (ceilingY <> Unknown) then exit;
-  if (nil = g_Map_traceToNearest(x, y, x, g_Map_MinY, GridTagObstacle, @ex, @ceilingY)) then
+  if (nil = g_Map_traceToNearest(x, y, x, g_Map_MinY, GridTagSolid, @ex, @ceilingY)) then
   begin
     ceilingY := g_Map_MinY-2;
   end;
@@ -499,6 +502,8 @@ procedure TParticle.think (); inline;
   end;
 
 begin
+  oldx := x;
+  oldy := y;
   // awake sleeping particle, if necessary
   if awakeDirty then
   begin
@@ -597,7 +602,7 @@ var
   pan: TPanel;
   dx, dy: SmallInt;
   ex, ey: Integer;
-  checkEnv: Boolean;
+  checkEnv, inAir, inStep: Boolean;
   floorJustTraced: Boolean;
   {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
   oldFloorY: Integer;
@@ -693,7 +698,7 @@ begin
     dx := round(velX);
     dy := round(velY);
 
-    if (state = TPartState.Normal) then checkAirStreams();
+    inAir := checkAirStreams();
 
     // gravity, if not stuck
     if (state <> TPartState.Stuck) and (abs(velX) < 0.1) and (abs(velY) < 0.1) then
@@ -741,7 +746,24 @@ begin
     if (dx <> 0) then
     begin
       // has some horizontal velocity
-      pan := g_Map_traceToNearest(x, y, x+dx, y+dy, GridTagObstacle, @ex, @ey);
+      inStep := False;
+      pan := g_Map_traceToNearest(x, y, x+dx, y+dy, GridTagSolid, @ex, @ey);
+      if (pan = nil) and (dy >= 0) then
+      begin
+        // do not stuck inside step
+        if g_Map_traceToNearest(x, y, x, y, GridTagStep, nil, nil) = nil then
+          // check for step panel below
+          pan := g_Map_traceToNearest(x, y, x, y+dy, GridTagStep, nil, @ey);
+        inStep := pan <> nil;
+        if inStep then
+        begin
+          // stick to panel edges
+          if ex < pan.X then
+            ex := pan.X
+          else if ex > pan.X + pan.Width - 1 then
+            ex := pan.X + pan.Width - 1;
+        end;
+      end;
       checkEnv := (x <> ex);
       x := ex;
       y := ey;
@@ -755,19 +777,24 @@ begin
       end;
       if (pan <> nil) then
       begin
-        // we stuck
-        // the only case when we can have both ceiling and wall is corner; stick to wall in this case
-        // check if we stuck to a wall
-        if (dx < 0) then dx := -1 else dx := 1;
-        if (g_Map_PanelAtPoint(x+dx, y, GridTagObstacle) <> nil) then
-        begin
-          // stuck to a wall
-          stickToWall(dx);
-        end
+        if inStep then
+          stickToWall(dx)
         else
         begin
-          // stuck to a ceiling
-          stickToCeiling();
+          // we stuck
+          // the only case when we can have both ceiling and wall is corner; stick to wall in this case
+          // check if we stuck to a wall
+          if (dx < 0) then dx := -1 else dx := 1;
+          if (g_Map_PanelAtPoint(x+dx, y, GridTagSolid) <> nil) then
+          begin
+            // stuck to a wall
+            stickToWall(dx);
+          end
+          else
+          begin
+            // stuck to a ceiling
+            stickToCeiling();
+          end;
         end;
       end;
     end
@@ -818,7 +845,7 @@ begin
                     if (y <> floorY) then continue;
                   end;
                   // environment didn't changed
-                  hitAFloor();
+                  if not inAir then hitAFloor();
                   break; // done with vertical movement
                 end;
               TFloorType.LiquidIn: // entering the liquid
@@ -836,7 +863,7 @@ begin
                   findFloor(true); // force rescan
                   if (floorType = TFloorType.Wall) and (floorY = y) then
                   begin
-                    hitAFloor();
+                    if not inAir then hitAFloor();
                     break; // done with vertical movement
                   end;
                 end;
@@ -956,16 +983,18 @@ begin
     begin
       x := fX-devX1+Random(devX2);
       y := fY-devY1+Random(devY2);
+      oldx := x;
+      oldy := y;
 
       // check for level bounds
       if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
 
       // in what environment we are starting in?
-      pan := g_Map_PanelAtPoint(x, y, (GridTagObstacle or GridTagLiquid));
+      pan := g_Map_PanelAtPoint(x, y, (GridTagSolid or GridTagLiquid));
       if (pan <> nil) then
       begin
         // either in a wall, or in a liquid
-        if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
+        if ((pan.tag and GridTagSolid) <> 0) then continue; // don't spawn in walls
         env := TEnvType.ELiquid;
       end
       else
@@ -1054,6 +1083,9 @@ begin
         accelY := 0.8;
       end;
 
+      oldx := x;
+      oldy := y;
+
       // check for level bounds
       if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
 
@@ -1196,6 +1228,8 @@ begin
     begin
       x := fX-devX1+Random(devX2);
       y := fY-devY1+Random(devY2);
+      oldx := x;
+      oldy := y;
 
       // check for level bounds
       if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
@@ -1274,7 +1308,7 @@ begin
   if (dx <> 0) then
   begin
     // has some horizontal velocity
-    pan := g_Map_traceToNearest(x, y, x+dx, y+dy, (GridTagObstacle or GridTagLiquid), @ex, @ey);
+    pan := g_Map_traceToNearest(x, y, x+dx, y+dy, (GridTagSolid or GridTagLiquid), @ex, @ey);
     if (x <> ex) then begin floorY := Unknown; ceilingY := Unknown; end; // dunno yet
     x := ex;
     y := ey;
@@ -1365,16 +1399,18 @@ begin
     begin
       x := fX-devX1+Random(devX2);
       y := fY-devY1+Random(devY2);
+      oldx := x;
+      oldy := y;
 
       // check for level bounds
       if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
 
       // in what environment we are starting in?
-      pan := g_Map_PanelAtPoint(x, y, (GridTagObstacle or GridTagLiquid));
+      pan := g_Map_PanelAtPoint(x, y, (GridTagSolid or GridTagLiquid));
       if (pan <> nil) then
       begin
         // either in a wall, or in a liquid
-        //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
+        //if ((pan.tag and GridTagSolid) <> 0) then continue; // don't spawn in walls
         //env := TEnvType.ELiquid;
         continue;
       end
@@ -1447,16 +1483,18 @@ begin
     begin
       x := fX-devX1+Random(devX2);
       y := fY-devY1+Random(devY2);
+      oldx := x;
+      oldy := y;
 
       // check for level bounds
       if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
 
       // in what environment we are starting in?
-      pan := g_Map_PanelAtPoint(x, y, (GridTagObstacle or GridTagLiquid));
+      pan := g_Map_PanelAtPoint(x, y, (GridTagSolid or GridTagLiquid));
       if (pan <> nil) then
       begin
         // either in a wall, or in a liquid
-        //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
+        //if ((pan.tag and GridTagSolid) <> 0) then continue; // don't spawn in walls
         //env := TEnvType.ELiquid;
         continue;
       end
@@ -1626,6 +1664,9 @@ begin
     for a := 0 to High(OnceAnims) do
       if OnceAnims[a].Animation <> nil then
       begin
+        OnceAnims[a].oldx := OnceAnims[a].x;
+        OnceAnims[a].oldy := OnceAnims[a].y;
+
         case OnceAnims[a].AnimType of
           ONCEANIM_SMOKE:
             begin
@@ -1650,17 +1691,7 @@ end;
 
 procedure g_GFX_Draw ();
   var
-    a, len: Integer;
-{$IFDEF USE_NANOGL}
-  type
-    Vertex = record
-      x, y: GLfloat;
-      r, g, b, a: GLfloat;
-    end;
-  var
-    count: Integer;
-    v: array of Vertex;
-{$ENDIF}
+    a, len, fx, fy: Integer;
 begin
   if not gpart_dbg_enabled then exit;
 
@@ -1675,34 +1706,6 @@ begin
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-{$IFDEF USE_NANOGL}
-    count := 0;
-    SetLength(v, Length(Particles));
-    for a := 0 to High(Particles) do
-    begin
-      with Particles[a] do
-      begin
-        if alive and (x >= sX) and (y >= sY) and (x <= sX + sWidth) and (sY <= sY + sHeight) then
-        begin
-          v[count].x := x + 0.37;
-          v[count].y := y + 0.37;
-          v[count].r := red / 255;
-          v[count].g := green / 255;
-          v[count].b := blue / 255;
-          v[count].a := alpha / 255;
-          Inc(count);
-        end;
-      end;
-    end;
-
-    glVertexPointer(2, GL_FLOAT, SizeOf(Vertex), @v[0].x);
-    glColorPointer(4, GL_FLOAT, SizeOf(Vertex), @v[0].r);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glEnableClientState(GL_COLOR_ARRAY);
-    glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    glDrawArrays(GL_POINTS, 0, count);
-{$ELSE}
     glBegin(GL_POINTS);
 
     len := High(Particles);
@@ -1713,14 +1716,15 @@ begin
         if not alive then continue;
         if (x >= sX) and (y >= sY) and (x <= sX+sWidth) and (sY <= sY+sHeight) then
         begin
+          fx := nlerp(oldx, x, gLerpFactor);
+          fy := nlerp(oldy, y, gLerpFactor);
           glColor4ub(red, green, blue, alpha);
-          glVertex2f(x+0.37, y+0.37);
+          glVertex2f(fx+0.37, fy+0.37);
         end;
       end;
     end;
 
     glEnd();
-{$ENDIF}
 
     glDisable(GL_BLEND);
   end;
@@ -1732,7 +1736,12 @@ begin
     begin
       if (OnceAnims[a].Animation <> nil) then
       begin
-        with OnceAnims[a] do Animation.Draw(x, y, TMirrorType.None);
+        with OnceAnims[a] do
+        begin
+          fx := nlerp(oldx, x, gLerpFactor);
+          fy := nlerp(oldy, y, gLerpFactor);
+          Animation.Draw(x, y, TMirrorType.None);
+        end;
       end;
     end;
   end;