diff options
-rw-r--r-- | Spear/App.hs | 29 | ||||
-rw-r--r-- | Spear/Sys/Timer.hsc | 13 | ||||
-rw-r--r-- | Spear/Sys/Timer/timer.c | 9 | ||||
-rw-r--r-- | Spear/Sys/Timer/timer.h | 3 |
4 files changed, 42 insertions, 12 deletions
diff --git a/Spear/App.hs b/Spear/App.hs index f8afc9e..ac5f7a5 100644 --- a/Spear/App.hs +++ b/Spear/App.hs | |||
@@ -59,50 +59,55 @@ loop app window = do | |||
59 | resizeApp app (ResizeEvent width height) | 59 | resizeApp app (ResizeEvent width height) |
60 | renderApp app | 60 | renderApp app |
61 | 61 | ||
62 | let ddt = fpsToDdt . maxFPS . options $ app -- Desired frame delta time. | 62 | let ddt = fpsToDdt . maxFPS . options $ app -- Desired render time step. |
63 | let animationDdt = fpsToDdt . animationFPS . options $ app -- Desired animation time step. | 63 | let animationDdt = fpsToDdt . animationFPS . options $ app -- Desired animation time step. |
64 | 64 | ||
65 | timer <- gameIO newTimer | 65 | timer <- gameIO newTimer |
66 | gameIO $ Timer.start timer | 66 | gameIO $ Timer.start timer |
67 | loop' window ddt animationDdt 0 timer app | 67 | let lastAnimationTime = lastTick timer |
68 | loop' window ddt animationDdt lastAnimationTime timer app | ||
68 | 69 | ||
69 | loop' :: | 70 | loop' :: |
70 | Window -> | 71 | Window -> |
71 | TimeDelta -> -- Desired frame time delta. | 72 | TimeDelta -> -- Desired frame time delta. |
72 | TimeDelta -> -- Desired animation time delta. | 73 | TimeDelta -> -- Desired animation time delta. |
73 | TimeDelta -> -- Time budget. | 74 | TimePoint -> -- Time point of last animation update. |
74 | Timer -> | 75 | Timer -> |
75 | App s -> | 76 | App s -> |
76 | Game s () | 77 | Game s () |
77 | loop' window ddt animationDdt timeBudget inputTimer app = do | 78 | loop' window ddt animationDdt lastAnimationTime inputTimer app = do |
78 | timer <- gameIO $ tick inputTimer | 79 | timer <- gameIO $ tick inputTimer |
79 | windowEvents <- gameIO $ pollWindowEvents window | 80 | windowEvents <- gameIO $ pollWindowEvents window |
80 | close <- gameIO $ shouldWindowClose window | 81 | close <- gameIO $ shouldWindowClose window |
81 | 82 | ||
82 | (continue, timeBudgetNextFrame) <- case animationDdt of | 83 | (continue, lastAnimationTimeNextFrame) <- case animationDdt of |
83 | 0 -> do | 84 | 0 -> do |
84 | -- Variable time step game animation. | 85 | -- Variable time step game animation. |
85 | let t = timeDeltaToSec $ runningTime timer | 86 | let t = timeDeltaToSec $ runningTime timer |
86 | let dt = timeDeltaToSec $ deltaTime timer | 87 | let dt = timeDeltaToSec $ deltaTime timer |
87 | inputEvents <- gameIO $ pollInputEvents window | 88 | inputEvents <- gameIO $ pollInputEvents window |
88 | continue <- stepApp app t dt inputEvents | 89 | continue <- stepApp app t dt inputEvents |
89 | return (continue, 0) -- budget unused. | 90 | return (continue, lastAnimationTime) |
90 | 91 | ||
91 | _ -> do | 92 | _ -> do |
92 | -- Fixed time step animation. | 93 | -- Fixed time step animation. |
93 | let elapsed = runningTime timer | 94 | {- let elapsed = runningTime timer |
94 | let dt = timeDeltaToSec ddt | 95 | let dt = timeDeltaToSec ddt |
95 | let timeBudgetThisFrame = timeBudget + deltaTime timer | 96 | let timeBudgetThisFrame = timeBudget + deltaTime timer |
96 | let timeBudgetNextFrame = timeBudgetThisFrame `mod` ddt | 97 | let timeBudgetNextFrame = timeBudgetThisFrame `mod` ddt |
98 | let steps = timeBudgetThisFrame `div` ddt -} | ||
99 | --gameIO . print $ "Steps: " ++ show steps ++ ", Budget: " ++ show timeBudgetThisFrame ++ ", ddt: " ++ show ddt | ||
100 | let elapsed = runningTime timer | ||
101 | let dt = timeDeltaToSec ddt | ||
102 | let timeBudgetThisFrame = timeDiff lastAnimationTime (lastTick timer) | ||
97 | let steps = timeBudgetThisFrame `div` ddt | 103 | let steps = timeBudgetThisFrame `div` ddt |
98 | gameIO . print $ steps | 104 | let lastAnimationTimeNextFrame = timeAdd lastAnimationTime (timeBudgetThisFrame `mod` ddt) |
99 | 105 | --gameIO . print $ "Steps: " ++ show steps ++ ", Budget: " ++ show timeBudgetThisFrame ++ ", ddt: " ++ show ddt | |
100 | continue <- and <$> forM [1..steps] (\i -> do | 106 | continue <- and <$> forM [1..steps] (\i -> do |
101 | inputEvents <- gameIO $ pollInputEvents window | 107 | inputEvents <- gameIO $ pollInputEvents window |
102 | let t = timeDeltaToSec $ elapsed + i * ddt | 108 | let t = timeDeltaToSec $ elapsed + i * ddt |
103 | stepApp app t dt inputEvents) | 109 | stepApp app t dt inputEvents) |
104 | 110 | return (continue, lastAnimationTimeNextFrame) | |
105 | return (continue, timeBudgetNextFrame) | ||
106 | 111 | ||
107 | -- Process window events. | 112 | -- Process window events. |
108 | resized <- or <$> forM windowEvents (\event -> case event of | 113 | resized <- or <$> forM windowEvents (\event -> case event of |
@@ -121,4 +126,4 @@ loop' window ddt animationDdt timeBudget inputTimer app = do | |||
121 | gameIO $ Timer.sleep (ddt - frameTime) | 126 | gameIO $ Timer.sleep (ddt - frameTime) |
122 | 127 | ||
123 | when (continue && not close) $ do | 128 | when (continue && not close) $ do |
124 | loop' window ddt animationDdt timeBudgetNextFrame timer app | 129 | loop' window ddt animationDdt lastAnimationTimeNextFrame timer app |
diff --git a/Spear/Sys/Timer.hsc b/Spear/Sys/Timer.hsc index 98b88d6..fb18521 100644 --- a/Spear/Sys/Timer.hsc +++ b/Spear/Sys/Timer.hsc | |||
@@ -14,6 +14,7 @@ module Spear.Sys.Timer | |||
14 | , timeDeltaToSec | 14 | , timeDeltaToSec |
15 | , secToTimeDelta | 15 | , secToTimeDelta |
16 | , timePointToNs | 16 | , timePointToNs |
17 | , timeAdd | ||
17 | , sleep | 18 | , sleep |
18 | ) | 19 | ) |
19 | where | 20 | where |
@@ -115,6 +116,9 @@ foreign import ccall safe "timer.h sec_to_time_delta" | |||
115 | foreign import ccall safe "timer.h time_point_to_ns" | 116 | foreign import ccall safe "timer.h time_point_to_ns" |
116 | c_time_point_to_ns :: Ptr TimePoint -> Word64 | 117 | c_time_point_to_ns :: Ptr TimePoint -> Word64 |
117 | 118 | ||
119 | foreign import ccall safe "timer.h time_add" | ||
120 | c_time_add :: Ptr TimePoint -> TimeDelta -> Ptr TimePoint -> IO () | ||
121 | |||
118 | foreign import ccall "timer.h time_sleep" | 122 | foreign import ccall "timer.h time_sleep" |
119 | c_time_sleep :: TimeDelta -> IO () | 123 | c_time_sleep :: TimeDelta -> IO () |
120 | 124 | ||
@@ -172,6 +176,15 @@ timePointToNs t = unsafeDupablePerformIO $ alloca $ \ptr -> do | |||
172 | poke ptr t | 176 | poke ptr t |
173 | return $ c_time_point_to_ns ptr | 177 | return $ c_time_point_to_ns ptr |
174 | 178 | ||
179 | -- | Add a time delta to a timestamp. | ||
180 | timeAdd :: TimePoint -> TimeDelta -> TimePoint | ||
181 | timeAdd t dt = unsafeDupablePerformIO $ | ||
182 | alloca $ \tPtr -> | ||
183 | alloca $ \ptr -> do | ||
184 | poke tPtr t | ||
185 | c_time_add tPtr dt ptr | ||
186 | peek ptr | ||
187 | |||
175 | -- | Put the caller thread to sleep for the given amount of time. | 188 | -- | Put the caller thread to sleep for the given amount of time. |
176 | sleep :: TimeDelta -> IO () | 189 | sleep :: TimeDelta -> IO () |
177 | sleep = c_time_sleep | 190 | sleep = c_time_sleep |
diff --git a/Spear/Sys/Timer/timer.c b/Spear/Sys/Timer/timer.c index 707cd63..4a2fb2b 100644 --- a/Spear/Sys/Timer/timer.c +++ b/Spear/Sys/Timer/timer.c | |||
@@ -87,6 +87,15 @@ uint64_t time_point_to_ns(time_point* t) { | |||
87 | #endif | 87 | #endif |
88 | } | 88 | } |
89 | 89 | ||
90 | void time_add(const time_point* t, time_delta dt, time_point* out) { | ||
91 | #ifdef _WIN32 | ||
92 | *out = *t + dt; | ||
93 | #else | ||
94 | out->tv_sec = t->tv_sec + (dt / nanoseconds); | ||
95 | out->tv_nsec = t->tv_nsec + (dt % nanoseconds); | ||
96 | #endif | ||
97 | } | ||
98 | |||
90 | void time_sleep(time_delta dt) { | 99 | void time_sleep(time_delta dt) { |
91 | #ifdef _WIN32 | 100 | #ifdef _WIN32 |
92 | const int64_t ms = dt / microseconds; | 101 | const int64_t ms = dt / microseconds; |
diff --git a/Spear/Sys/Timer/timer.h b/Spear/Sys/Timer/timer.h index e426135..da4e7c7 100644 --- a/Spear/Sys/Timer/timer.h +++ b/Spear/Sys/Timer/timer.h | |||
@@ -53,6 +53,9 @@ time_delta sec_to_time_delta(double seconds); | |||
53 | /// Convert the time point to nanoseconds. | 53 | /// Convert the time point to nanoseconds. |
54 | uint64_t time_point_to_ns(time_point*); | 54 | uint64_t time_point_to_ns(time_point*); |
55 | 55 | ||
56 | /// Add a time delta to a timestamp. | ||
57 | void time_add(const time_point*, time_delta, time_point* out); | ||
58 | |||
56 | /// Put the caller thread to sleep for the given amount of time. | 59 | /// Put the caller thread to sleep for the given amount of time. |
57 | void time_sleep(time_delta dt); | 60 | void time_sleep(time_delta dt); |
58 | 61 | ||