 : scaled-velocity ( player -- velocity )
     [ velocity>> ] [ velocity-modifier>> ] bi v* ;
 
-: tick-player ( world player -- )
+: save-history ( world player -- )
+    clone swap history>> push ;
+
+:: tick-player-reverse ( world player -- )
+    player reverse-time>> :> reverse-time
+    world history>> :> history
+    history length 0 > [
+        history length reverse-time 1 - - 1 max history set-length
+        history pop world (>>player)
+    ] when ;
+
+: tick-player-forward ( world player -- )
+    2dup save-history
     [ apply-friction apply-gravity ] change-velocity
     dup scaled-velocity [ v+ [ terrain-segment>> ] dip collide ] curry with change-location
     drop ;
+
+: tick-player ( world player -- )
+    dup reverse-time>> [
+        tick-player-reverse
+    ] [
+        tick-player-forward
+    ] if ;
 
 M: terrain-world tick*
     [ dup focused?>> [ handle-input ] [ drop ] if ]

CONSTANT: terrain-vertex-row-length $[ 512 1 + 2 * ]

TUPLE: player
    location yaw pitch velocity velocity-modifier ;

TUPLE: terrain-world < game-world
    player
    sky-image sky-texture sky-program
    terrain terrain-segment terrain-texture terrain-program
    terrain-vertex-buffer ;

M: terrain-world tick-length
    drop 1000 30 /i ;

sequences sequences.product specialized-arrays.float
terrain.generation terrain.shaders ui ui.gadgets
ui.gadgets.worlds ui.pixel-formats game-worlds method-chains
math.affine-transforms noise ui.gestures combinators.short-circuit ;
IN: terrain

CONSTANT: FOV $[ 2.0 sqrt 1+ ]
CONSTANT: NEAR-PLANE $[ 1.0 1024.0 / ]
CONSTANT: FAR-PLANE 2.0
CONSTANT: PLAYER-START-LOCATION { 0.5 0.51 0.5 }
CONSTANT: VELOCITY-MODIFIER-NORMAL { 1.0 1.0 1.0 }
CONSTANT: VELOCITY-MODIFIER-FAST { 2.0 1.0 2.0 }
CONSTANT: PLAYER-HEIGHT $[ 1.0 256.0 / ]
CONSTANT: GRAVITY $[ 1.0 4096.0 / ]
CONSTANT: JUMP $[ 1.0 1024.0 / ]
