From: fgsfds Date: Mon, 2 Mar 2020 21:59:55 +0000 (+0300) Subject: added actor rendering interpolation; fixed vsync on startup X-Git-Url: http://deadsoftware.ru/gitweb?a=commitdiff_plain;h=refs%2Fheads%2Fplavnota;p=d2df-sdl.git added actor rendering interpolation; fixed vsync on startup --- diff --git a/src/game/g_game.pas b/src/game/g_game.pas index affc870..b0e9e01 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -240,6 +240,7 @@ var gPlayer2: TPlayer = nil; gPlayerDrawn: TPlayer = nil; gTime: LongWord; + gLerpFactor: Single = 1.0; gSwitchGameMode: Byte = GM_DM; gHearPoint1, gHearPoint2: THearPoint; gSoundEffectsDF: Boolean = False; @@ -2161,6 +2162,13 @@ begin end; end; + // these are in separate PreUpdate functions because they can interact during Update() + // we don't care that much about corpses and gibs + g_Player_PreUpdate(); + g_Monsters_PreUpdate(); + g_Items_PreUpdate(); + g_Weapon_PreUpdate(); + // Îáíîâëÿåì âñå îñòàëüíîå: g_Map_Update(); g_Items_Update(); @@ -3621,7 +3629,7 @@ end; procedure DrawPlayer(p: TPlayer); var - px, py, a, b, c, d, i: Integer; + px, py, a, b, c, d, i, fX, fY: Integer; //R: TRect; begin if (p = nil) or (p.FDummy) then @@ -3639,8 +3647,9 @@ begin glPushMatrix(); - px := p.GameX + PLAYER_RECT_CX; - py := p.GameY + PLAYER_RECT_CY+p.Obj.slopeUpLeft; + p.Obj.lerp(gLerpFactor, fX, fY); + px := fX + PLAYER_RECT_CX; + py := fY + PLAYER_RECT_CY+p.Obj.slopeUpLeft; if (g_dbg_scale = 1.0) and (not g_dbg_ignore_bounds) then begin @@ -3697,7 +3706,7 @@ begin p.IncCam := nclamp(p.IncCam, min(0, -120 - i), 0); end; - sY := sY - p.IncCam; + sY := sY - nlerp(p.IncCamOld, p.IncCam, gLerpFactor); if (not g_dbg_ignore_bounds) then begin @@ -7225,7 +7234,6 @@ begin end; 'r_reset': begin - sys_EnableVSync(gVSync); gRC_Width := Max(1, gRC_Width); gRC_Height := Max(1, gRC_Height); gBPP := Max(1, gBPP); @@ -7233,6 +7241,7 @@ begin e_LogWriteln('resolution changed') else e_LogWriteln('resolution not changed'); + sys_EnableVSync(gVSync); end; 'g_language': begin diff --git a/src/game/g_gfx.pas b/src/game/g_gfx.pas index 8094c4e..bf8fc5a 100644 --- a/src/game/g_gfx.pas +++ b/src/game/g_gfx.pas @@ -103,6 +103,7 @@ type PParticle = ^TParticle; TParticle = record x, y: Integer; + oldX, oldY: Integer; velX, velY: Single; accelX, accelY: Single; state: TPartState; @@ -139,6 +140,7 @@ type TOnceAnim = record AnimType: Byte; x, y: Integer; + oldX, oldY: Integer; Animation: TAnimation; end; @@ -500,6 +502,8 @@ procedure TParticle.think (); inline; end; begin + oldx := x; + oldy := y; // awake sleeping particle, if necessary if awakeDirty then begin @@ -979,6 +983,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; @@ -1077,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; @@ -1219,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; @@ -1388,6 +1399,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; @@ -1470,6 +1483,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; @@ -1649,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 @@ -1673,7 +1691,7 @@ end; procedure g_GFX_Draw (); var - a, len: Integer; + a, len, fx, fy: Integer; begin if not gpart_dbg_enabled then exit; @@ -1698,8 +1716,10 @@ 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; @@ -1716,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; diff --git a/src/game/g_items.pas b/src/game/g_items.pas index 8d476ef..88a9cba 100644 --- a/src/game/g_items.pas +++ b/src/game/g_items.pas @@ -54,6 +54,7 @@ procedure g_Items_Free(); function g_Items_Create(X, Y: Integer; ItemType: Byte; Fall, Respawnable: Boolean; AdjCoord: Boolean = False; ForcedID: Integer = -1): DWORD; procedure g_Items_SetDrop (ID: DWORD); +procedure g_Items_PreUpdate(); procedure g_Items_Update(); procedure g_Items_Draw(); procedure g_Items_DrawDrop(); @@ -462,6 +463,8 @@ begin it.dropped := false; g_Obj_Init(@it.Obj); + it.Obj.oldX := X; + it.Obj.oldY := Y; it.Obj.X := X; it.Obj.Y := Y; it.Obj.Rect.Width := ITEMSIZE[ItemType][0]; @@ -500,6 +503,18 @@ begin result := find_id; end; +procedure g_Items_PreUpdate (); +var + i: Integer; +begin + if (ggItems = nil) then Exit; + for i := 0 to High(ggItems) do + if (ggItems[i].ItemType <> ITEM_NONE) and ggItems[i].slotIsUsed then + begin + ggItems[i].Obj.oldX := ggItems[i].Obj.X; + ggItems[i].Obj.oldY := ggItems[i].Obj.Y; + end; +end; procedure g_Items_Update (); var @@ -607,6 +622,8 @@ begin Anim.Free(); end; + Obj.oldX := InitX; + Obj.oldY := InitY; Obj.X := InitX; Obj.Y := InitY; Obj.Vel.X := 0; @@ -630,7 +647,7 @@ end; procedure itemsDrawInternal (dropflag: Boolean); var - i: Integer; + i, fX, fY: Integer; it: PItem; begin if (ggItems = nil) then exit; @@ -646,13 +663,14 @@ begin begin if g_Collide(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height, sX, sY, sWidth, sHeight) then begin + Obj.lerp(gLerpFactor, fX, fY); if (Animation = nil) then begin - e_Draw(gItemsTexturesID[ItemType], Obj.X, Obj.Y, 0, true, false); + e_Draw(gItemsTexturesID[ItemType], fX, fY, 0, true, false); end else begin - Animation.Draw(Obj.X, Obj.Y, TMirrorType.None); + Animation.Draw(fX, fY, TMirrorType.None); end; if g_debug_Frames then @@ -693,6 +711,8 @@ procedure g_Items_Pick (ID: DWORD); begin if (ID < Length(ggItems)) then begin + ggItems[ID].Obj.oldX := ggItems[ID].Obj.X; + ggItems[ID].Obj.oldY := ggItems[ID].Obj.Y; ggItems[ID].alive := false; ggItems[ID].RespawnTime := IfThen(gLMSRespawn = LMS_RESPAWN_NONE, gGameSettings.ItemRespawnTime, 15) * 36; end; @@ -714,6 +734,8 @@ begin it := @ggItems[ID]; if (it.arrIdx <> Integer(ID)) then raise Exception.Create('g_Items_Remove: arrIdx desync'); + it.Obj.oldX := it.Obj.X; + it.Obj.oldY := it.Obj.Y; trig := it.SpawnTrigger; releaseItem(ID); @@ -817,6 +839,8 @@ begin for i := 0 to High(ggItems) do begin it := @ggItems[i]; + it.Obj.oldX := it.Obj.X; + it.Obj.oldY := it.Obj.Y; if not it.slotIsUsed then continue; if it.Respawnable and (it.ItemType <> ITEM_NONE) then begin diff --git a/src/game/g_monsters.pas b/src/game/g_monsters.pas index ac28f34..02e7ed5 100644 --- a/src/game/g_monsters.pas +++ b/src/game/g_monsters.pas @@ -124,6 +124,7 @@ type function Damage(aDamage: Word; VelX, VelY: Integer; SpawnerUID: Word; t: Byte): Boolean; function Heal(Value: Word): Boolean; procedure BFGHit(); + procedure PreUpdate(); procedure Update(); procedure ClientUpdate(); procedure ClientAttack(wx, wy, atx, aty: Integer); @@ -232,6 +233,7 @@ procedure g_Monsters_Init (); procedure g_Monsters_Free (clearGrid: Boolean=true); function g_Monsters_Create (MonsterType: Byte; X, Y: Integer; Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; +procedure g_Monsters_PreUpdate (); procedure g_Monsters_Update (); procedure g_Monsters_Draw (); procedure g_Monsters_DrawHealth (); @@ -1377,6 +1379,8 @@ begin FStartDirection := Direction; FStartX := GameX; FStartY := GameY; + FObj.oldX := FObj.X; + FObj.oldY := FObj.Y; end; mon.positionChanged(); @@ -1412,6 +1416,16 @@ begin end; end; +procedure g_Monsters_PreUpdate(); +var + a: Integer; +begin + if gMonsters = nil then Exit; + for a := 0 to High(gMonsters) do + if (gMonsters[a] <> nil) and (not gMonsters[a].FRemoved) then + gMonsters[a].PreUpdate(); +end; + procedure g_Monsters_Update(); var a: Integer; @@ -2209,12 +2223,14 @@ end; procedure TMonster.Draw(); var m: TMirrorType; - dx, dy, c: Integer; + dx, dy, c, fX, fY: Integer; o: TObj; begin //e_CharFont_Print(gMenuSmallFont, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, 'TYPE: '+IntToStr(FMonsterType)); //e_CharFont_Print(gMenuSmallFont, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y+16, 'STATE: '+IntToStr(FState)); + FObj.lerp(gLerpFactor, fX, fY); + // Åñëè êîëäóí ñòðåëÿåò, òî ðèñóåì îãîíü: if FMonsterType = MONSTER_VILE then if FState = MONSTATE_SHOOT then @@ -2274,7 +2290,7 @@ begin end; // Ðèñóåì: - FAnim[FCurAnim, FDirection].Draw(Obj.X+dx, Obj.Y+dy, m); + FAnim[FCurAnim, FDirection].Draw(fX+dx, fY+dy, m); end; if g_debug_Frames then @@ -2406,6 +2422,8 @@ begin FObj.X := X - FObj.Rect.X; FObj.Y := Y - FObj.Rect.Y; + FObj.oldX := FObj.X; // don't interpolate after teleport + FObj.oldY := FObj.Y; positionChanged(); if dir = 1 then @@ -2439,6 +2457,12 @@ begin Result := True; end; +procedure TMonster.PreUpdate(); +begin + FObj.oldX := FObj.X; + FObj.oldY := FObj.Y; +end; + procedure TMonster.Update(); var a, b, sx, sy, wx, wy, oldvelx: Integer; diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas index 5e95a6a..92084b1 100644 --- a/src/game/g_netmsg.pas +++ b/src/game/g_netmsg.pas @@ -2282,7 +2282,8 @@ begin GameVelY := M.ReadLongInt(); GameAccelX := M.ReadLongInt(); GameAccelY := M.ReadLongInt(); - SetLerp(TmpX, TmpY); + GameX := TmpX; + GameY := TmpY; if NetForcePlayerUpdate then Update(); end; end; diff --git a/src/game/g_options.pas b/src/game/g_options.pas index 3f53262..4a561e0 100644 --- a/src/game/g_options.pas +++ b/src/game/g_options.pas @@ -38,6 +38,7 @@ var glLegacyNPOT: Boolean; glRenderToFBO: Boolean = True; gTextureFilter: Boolean; + gLerpActors: Boolean = True; gNoSound: Boolean; gSoundLevel: Integer; gMusicLevel: Integer; @@ -327,6 +328,7 @@ initialization conRegVar('r_vsync', @gVSync, '', ''); conRegVar('r_texfilter', @gTextureFilter, '', ''); conRegVar('r_npot', @glNPOTOverride, '', ''); + conRegVar('r_interp', @gLerpActors, '', 'interpolate actors'); (* Sound *) conRegVar('s_nosound', @gNoSound, '', ''); diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas index 9d93a5b..af569ea 100644 --- a/src/game/g_phys.pas +++ b/src/game/g_phys.pas @@ -31,6 +31,9 @@ type // this is purely visual change, it won't affect anything else slopeUpLeft: Integer; // left to go slopeFramesLeft: Integer; // frames left to go + // for frame interpolation + oldX, oldY: Integer; + procedure lerp(t: Single; out fX, fY: Integer); end; const @@ -82,6 +85,11 @@ uses const SmoothSlopeFrames = 4; +procedure TObj.lerp(t: Single; out fX, fY: Integer); +begin + fX := nlerp(oldX, X, t); + fY := nlerp(oldY, Y, t); +end; function g_Obj_StayOnStep(Obj: PObj): Boolean; inline; begin diff --git a/src/game/g_player.pas b/src/game/g_player.pas index 49cd657..db39cb8 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -186,6 +186,7 @@ type FActionChanged: Boolean; FAngle: SmallInt; FFireAngle: SmallInt; + FIncCamOld: Integer; FIncCam: Integer; FShellTimer: Integer; FShellType: Byte; @@ -325,6 +326,7 @@ type procedure DrawIndicator(Color: TRGB); procedure DrawBubble(); procedure DrawGUI(); + procedure PreUpdate(); procedure Update(); virtual; procedure RememberState(); procedure RecallState(); @@ -379,6 +381,7 @@ type property GameAccelX: Integer read FObj.Accel.X write FObj.Accel.X; property GameAccelY: Integer read FObj.Accel.Y write FObj.Accel.Y; property IncCam: Integer read FIncCam write FIncCam; + property IncCamOld: Integer read FIncCamOld write FIncCamOld; property UID: Word read FUID write FUID; property JustTeleported: Boolean read FJustTeleported write FJustTeleported; property NetTime: LongWord read FNetTime write FNetTime; @@ -581,6 +584,7 @@ function g_Player_Create(ModelName: String; Color: TRGB; Team: Byte; Bot: Boole function g_Player_CreateFromState (st: TStream): Word; procedure g_Player_Remove(UID: Word); procedure g_Player_ResetTeams(); +procedure g_Player_PreUpdate(); procedure g_Player_UpdateAll(); procedure g_Player_DrawAll(); procedure g_Player_DrawDebug(p: TPlayer); @@ -1368,6 +1372,16 @@ begin SetLength(SavedStates, 0); end; +procedure g_Player_PreUpdate(); +var + i: Integer; +begin + if gPlayers = nil then Exit; + for i := 0 to High(gPlayers) do + if gPlayers[i] <> nil then + gPlayers[i].PreUpdate(); +end; + procedure g_Player_UpdateAll(); var i: Integer; @@ -1713,6 +1727,9 @@ begin if gGibs[i].alive then with gGibs[i] do begin + Obj.oldX := Obj.X; + Obj.oldY := Obj.Y; + vel := Obj.Vel; mr := g_Obj_Move(@Obj, True, False, True); positionChanged(); // this updates spatial accelerators @@ -1763,6 +1780,9 @@ begin if gShells[i].alive then with gShells[i] do begin + Obj.oldX := Obj.X; + Obj.oldY := Obj.Y; + vel := Obj.Vel; mr := g_Obj_Move(@Obj, True, False, True); positionChanged(); // this updates spatial accelerators @@ -1851,7 +1871,7 @@ procedure TShell.positionChanged (); inline; begin end; procedure g_Player_DrawCorpses(); var - i: Integer; + i, fX, fY: Integer; a: TDFPoint; begin if gGibs <> nil then @@ -1862,13 +1882,15 @@ begin if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then Continue; + Obj.lerp(gLerpFactor, fX, fY); + a.X := Obj.Rect.X+(Obj.Rect.Width div 2); a.y := Obj.Rect.Y+(Obj.Rect.Height div 2); - e_DrawAdv(ID, Obj.X, Obj.Y, 0, True, False, RAngle, @a, TMirrorType.None); + e_DrawAdv(ID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None); e_Colors := Color; - e_DrawAdv(MaskID, Obj.X, Obj.Y, 0, True, False, RAngle, @a, TMirrorType.None); + e_DrawAdv(MaskID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None); e_Colors.R := 255; e_Colors.G := 255; e_Colors.B := 255; @@ -1882,7 +1904,7 @@ end; procedure g_Player_DrawShells(); var - i: Integer; + i, fX, fY: Integer; a: TDFPoint; begin if gShells <> nil then @@ -1893,10 +1915,12 @@ begin if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then Continue; + Obj.lerp(gLerpFactor, fX, fY); + a.X := CX; a.Y := CY; - e_DrawAdv(SpriteID, Obj.X, Obj.Y, 0, True, False, RAngle, @a, TMirrorType.None); + e_DrawAdv(SpriteID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None); end; end; @@ -2338,7 +2362,7 @@ end; procedure TPlayer.DrawIndicator(Color: TRGB); var - indX, indY: Integer; + indX, indY, fX, fY: Integer; indW, indH: Word; indA: Single; a: TDFPoint; @@ -2347,6 +2371,8 @@ var c: TRGB; begin if FAlive then + begin + FObj.lerp(gLerpFactor, fX, fY); case gPlayerIndicatorStyle of 0: begin @@ -2359,29 +2385,29 @@ begin if (FObj.X + FObj.Rect.X) < 0 then begin indA := 90; - indX := FObj.X + FObj.Rect.X + FObj.Rect.Width; - indY := FObj.Y + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; + indX := fX + FObj.Rect.X + FObj.Rect.Width; + indY := fY + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; end else if (FObj.X + FObj.Rect.X + FObj.Rect.Width) > Max(gMapInfo.Width, gPlayerScreenSize.X) then begin indA := 270; - indX := FObj.X + FObj.Rect.X - indH; - indY := FObj.Y + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; + indX := fX + FObj.Rect.X - indH; + indY := fY + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; end - else if (fObj.Y - indH) < 0 then + else if (FObj.Y - indH) < 0 then begin indA := 180; - indX := FObj.X + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; - indY := FObj.Y + FObj.Rect.Y + FObj.Rect.Height; + indX := fX + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; + indY := fY + FObj.Rect.Y + FObj.Rect.Height; end else begin indA := 0; - indX := FObj.X + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; - indY := FObj.Y - indH; + indX := fX + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; + indY := fY - indH; end; indX := EnsureRange(indX, 0, Max(gMapInfo.Width, gPlayerScreenSize.X) - indW); @@ -2397,23 +2423,25 @@ begin 1: begin e_TextureFontGetSize(gStdFont, nW, nH); - indX := FObj.X + FObj.Rect.X + (FObj.Rect.Width - Length(FName) * nW) div 2; - indY := FObj.Y - nH; + indX := fX + FObj.Rect.X + (FObj.Rect.Width - Length(FName) * nW) div 2; + indY := fY - nH; e_TextureFontPrintEx(indX, indY, FName, gStdFont, Color.R, Color.G, Color.B, 1.0, True); end; end; + end; end; procedure TPlayer.DrawBubble(); var - bubX, bubY: Integer; + bubX, bubY, fX, fY: Integer; ID: LongWord; Rb, Gb, Bb, Rw, Gw, Bw: SmallInt; Dot: Byte; begin - bubX := FObj.X+FObj.Rect.X + IfThen(FDirection = TDirection.D_LEFT, -4, 18); - bubY := FObj.Y+FObj.Rect.Y - 18; + FObj.lerp(gLerpFactor, fX, fY); + bubX := fX+FObj.Rect.X + IfThen(FDirection = TDirection.D_LEFT, -4, 18); + bubY := fY+FObj.Rect.Y - 18; Rb := 64; Gb := 64; Bb := 64; @@ -2423,8 +2451,8 @@ begin case gChatBubble of 1: // simple textual non-bubble begin - bubX := FObj.X+FObj.Rect.X - 11; - bubY := FObj.Y+FObj.Rect.Y - 17; + bubX := fX+FObj.Rect.X - 11; + bubY := fY+FObj.Rect.Y - 17; e_TextureFontPrint(bubX, bubY, '[...]', gStdFont); Exit; end; @@ -2491,7 +2519,10 @@ var w, h: Word; dr: Boolean; Mirror: TMirrorType; + fX, fY: Integer; begin + FObj.lerp(gLerpFactor, fX, fY); + if FAlive then begin if Direction = TDirection.D_RIGHT then @@ -2501,8 +2532,8 @@ begin if FPunchAnim <> nil then begin - FPunchAnim.Draw(FObj.X+IfThen(Direction = TDirection.D_LEFT, 15-FObj.Rect.X, FObj.Rect.X-15), - FObj.Y+FObj.Rect.Y-11, Mirror); + FPunchAnim.Draw(fX+IfThen(Direction = TDirection.D_LEFT, 15-FObj.Rect.X, FObj.Rect.X-15), + fY+FObj.Rect.Y-11, Mirror); if FPunchAnim.played then begin FPunchAnim.Free; @@ -2515,11 +2546,11 @@ begin begin e_GetTextureSize(ID, @w, @h); if FDirection = TDirection.D_LEFT then - e_Draw(ID, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)+4, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False) + e_Draw(ID, fX+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)+4, + fY+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False) else - e_Draw(ID, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)-2, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False); + e_Draw(ID, fX+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)-2, + fY+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False); end; if FMegaRulez[MR_INVIS] > gTime then @@ -2532,15 +2563,15 @@ begin else dr := True; if dr then - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 200) + FModel.Draw(fX, fY+FObj.slopeUpLeft, 200) else - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft); + FModel.Draw(fX, fY+FObj.slopeUpLeft); end else - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 254); + FModel.Draw(fX, fY+FObj.slopeUpLeft, 254); end else - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft); + FModel.Draw(fX, fY+FObj.slopeUpLeft); end; if g_debug_Frames then @@ -4396,6 +4427,7 @@ begin ReleaseKeys(); FDamageBuffer := 0; + FIncCamOld := 0; FIncCam := 0; FBFGFireCounter := -1; FShellTimer := -1; @@ -4564,6 +4596,7 @@ var Anim: TAnimation; ID: DWORD; begin + FIncCamOld := 0; FIncCam := 0; FBFGFireCounter := -1; FShellTimer := -1; @@ -4665,6 +4698,8 @@ begin // Óñòàíîâêà êîîðäèíàò è ñáðîñ âñåõ ïàðàìåòðîâ: FObj.X := RespawnPoint.X-PLAYER_RECT.X; FObj.Y := RespawnPoint.Y-PLAYER_RECT.Y; + FObj.oldX := FObj.X; // don't interpolate after respawn + FObj.oldY := FObj.Y; FObj.Vel.X := 0; FObj.Vel.Y := 0; FObj.Accel.X := 0; @@ -4922,6 +4957,8 @@ begin FObj.X := X-PLAYER_RECT.X; FObj.Y := Y-PLAYER_RECT.Y; + FObj.oldX := FObj.X; // don't interpolate after respawn + FObj.oldY := FObj.Y; if FAlive and FGhost then begin FXTo := FObj.X; @@ -5004,6 +5041,13 @@ begin end; end; +procedure TPlayer.PreUpdate(); +begin + FIncCamOld := FIncCam; + FObj.oldX := FObj.X; + FObj.oldY := FObj.Y; +end; + procedure TPlayer.Update(); var b: Byte; @@ -5016,11 +5060,8 @@ begin NetServer := g_Game_IsNet and g_Game_IsServer; AnyServer := g_Game_IsServer; - if g_Game_IsClient and (NetInterpLevel > 0) then - DoLerp(NetInterpLevel + 1) - else - if FGhost then - DoLerp(4); + if FGhost then + DoLerp(4); if NetServer then if FClientID >= 0 then @@ -6586,17 +6627,21 @@ begin end; procedure TCorpse.Draw(); +var + fX, fY: Integer; begin if FState = CORPSE_STATE_REMOVEME then Exit; + FObj.lerp(gLerpFactor, fX, fY); + if FAnimation <> nil then - FAnimation.Draw(FObj.X, FObj.Y, TMirrorType.None); + FAnimation.Draw(fX, fY, TMirrorType.None); if FAnimationMask <> nil then begin e_Colors := FColor; - FAnimationMask.Draw(FObj.X, FObj.Y, TMirrorType.None); + FAnimationMask.Draw(fX, fY, TMirrorType.None); e_Colors.R := 255; e_Colors.G := 255; e_Colors.B := 255; @@ -6610,6 +6655,9 @@ begin if FState = CORPSE_STATE_REMOVEME then Exit; + FObj.oldX := FObj.X; + FObj.oldY := FObj.Y; + if gTime mod (GAME_TICK*2) <> 0 then begin g_Obj_Move(@FObj, True, True, True); diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas index 632cb13..bb17a41 100644 --- a/src/game/g_weapons.pas +++ b/src/game/g_weapons.pas @@ -72,6 +72,7 @@ procedure g_Weapon_dshotgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boo function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean; procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word); +procedure g_Weapon_PreUpdate(); procedure g_Weapon_Update(); procedure g_Weapon_Draw(); function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean; @@ -737,6 +738,8 @@ begin end; end; + Shots[find_id].Obj.oldX := X; + Shots[find_id].Obj.oldY := Y; Shots[find_id].Obj.X := X; Shots[find_id].Obj.Y := Y; Shots[find_id].Obj.Vel.X := XV; @@ -762,6 +765,8 @@ begin if a = 0 then a := 1; + Shots[i].Obj.oldX := x; + Shots[i].Obj.oldY := y; Shots[i].Obj.X := x; Shots[i].Obj.Y := y; Shots[i].Obj.Vel.X := (xd*s) div a; @@ -2093,6 +2098,19 @@ begin end; end; +procedure g_Weapon_PreUpdate(); +var + i: Integer; +begin + if Shots = nil then Exit; + for i := 0 to High(Shots) do + if Shots[i].ShotType <> 0 then + begin + Shots[i].Obj.oldX := Shots[i].Obj.X; + Shots[i].Obj.oldY := Shots[i].Obj.Y; + end; +end; + procedure g_Weapon_Update(); var i, a, h, cx, cy, oldvx, oldvy, tf: Integer; @@ -2501,7 +2519,7 @@ end; procedure g_Weapon_Draw(); var - i: Integer; + i, fX, fY: Integer; a: SmallInt; p: TDFPoint; begin @@ -2520,6 +2538,7 @@ begin else a := 0; + Obj.lerp(gLerpFactor, fX, fY); p.X := Obj.Rect.Width div 2; p.Y := Obj.Rect.Height div 2; @@ -2528,16 +2547,16 @@ begin if (Shots[i].ShotType = WEAPON_BARON_FIRE) or (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or (Shots[i].ShotType = WEAPON_SKEL_FIRE) then - Animation.DrawEx(Obj.X, Obj.Y, TMirrorType.None, p, a) + Animation.DrawEx(fX, fY, TMirrorType.None, p, a) else - Animation.Draw(Obj.X, Obj.Y, TMirrorType.None); + Animation.Draw(fX, fY, TMirrorType.None); end else if TextureID <> 0 then begin if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) then - e_DrawAdv(TextureID, Obj.X, Obj.Y, 0, True, False, a, @p, TMirrorType.None) + e_DrawAdv(TextureID, fX, fY, 0, True, False, a, @p, TMirrorType.None) else if (Shots[i].ShotType <> WEAPON_FLAMETHROWER) then - e_Draw(TextureID, Obj.X, Obj.Y, 0, True, False); + e_Draw(TextureID, fX, fY, 0, True, False); end; if g_debug_Frames then diff --git a/src/game/g_window.pas b/src/game/g_window.pas index 7774c0a..351edf9 100644 --- a/src/game/g_window.pas +++ b/src/game/g_window.pas @@ -52,6 +52,7 @@ const var Time, Time_Delta, Time_Old: Int64; + Frame: Int64; flag: Boolean; wNeedTimeReset: Boolean = false; wMinimized: Boolean = false; @@ -124,6 +125,7 @@ begin if wNeedTimeReset then begin + Frame := 0; Time_Delta := 28; wNeedTimeReset := false; end; @@ -167,18 +169,23 @@ begin // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ if flag then - begin Time_Old := Time - (Time_Delta mod 28); + + if (Time - Frame > 4) then + begin if (not wMinimized) then begin + if gPause or not gLerpActors then + gLerpFactor := 1.0 + else + gLerpFactor := nmin(1.0, (Time - Time_Old) / 28.0); Draw; sys_Repaint - end + end; + Frame := Time end else - begin - sys_Delay(1) // release time slice, so we won't eat 100% CPU - end; + sys_Delay(1); e_SoundUpdate(); end; diff --git a/src/shared/utils.pas b/src/shared/utils.pas index 946e4f5..57ce782 100644 --- a/src/shared/utils.pas +++ b/src/shared/utils.pas @@ -189,6 +189,7 @@ function readLongIntBE (st: TStream): LongInt; function readInt64BE (st: TStream): Int64; function readUInt64BE (st: TStream): UInt64; +function nlerp (a, b: Integer; t: Single): Integer; inline; function nmin (a, b: Byte): Byte; inline; overload; function nmin (a, b: ShortInt): ShortInt; inline; overload; @@ -1528,6 +1529,8 @@ function readUInt64BE (st: TStream): UInt64; begin readIntegerBE(st, @result, 8) // ////////////////////////////////////////////////////////////////////////// // +function nlerp (a, b: Integer; t: Single): Integer; inline; begin result := round((1.0 - t) * a + t * b); end; + function nmin (a, b: Byte): Byte; inline; overload; begin if (a < b) then result := a else result := b; end; function nmin (a, b: ShortInt): ShortInt; inline; overload; begin if (a < b) then result := a else result := b; end; function nmin (a, b: Word): Word; inline; overload; begin if (a < b) then result := a else result := b; end;