@@ -18,6 +18,7 @@ use std::convert::TryFrom;
18
18
use std:: sync:: mpsc;
19
19
use std:: thread:: JoinHandle ;
20
20
use std:: time:: Duration ;
21
+ use std:: time:: SystemTime ;
21
22
22
23
pub struct App_Config {
23
24
pub title : String ,
@@ -59,15 +60,17 @@ pub struct App<'r> {
59
60
env : Env_Info ,
60
61
61
62
config : cfg:: Config ,
62
- ui_req_tx : Option < mpsc:: Sender < gfx:: ui:: UI_Request > > ,
63
+ ui_req_tx : mpsc:: Sender < gfx:: ui:: UI_Request > ,
63
64
64
65
// Resources
66
+ gfx_resources : resources:: gfx:: Gfx_Resources < ' r > ,
65
67
audio_resources : resources:: audio:: Audio_Resources < ' r > ,
66
68
67
69
// Engine Systems
68
- render_thread : Option < JoinHandle < ( ) > > ,
69
- render_thread_quit : Option < mpsc:: Sender < ( ) > > ,
70
- input_actions_rx : Option < mpsc:: Receiver < input:: Action_List > > ,
70
+ input_system : input:: Input_System ,
71
+ input_actions_rx : mpsc:: Receiver < input:: Action_List > ,
72
+ render_system : gfx:: render_system:: Render_System ,
73
+ ui_system : gfx:: ui:: UI_System ,
71
74
audio_system : audio:: system:: Audio_System ,
72
75
gameplay_system : gameplay_system:: Gameplay_System ,
73
76
}
@@ -77,16 +80,21 @@ impl<'r> App<'r> {
77
80
let env = Env_Info :: gather ( ) . unwrap ( ) ;
78
81
let config = cfg:: Config :: new_from_dir ( env. get_cfg_root ( ) ) ;
79
82
83
+ let ( input_tx, input_rx) = mpsc:: channel ( ) ;
84
+ let ( ui_tx, ui_rx) = mpsc:: channel ( ) ;
85
+
80
86
App {
81
87
time : time:: Time :: new ( ) ,
82
88
should_close : false ,
83
89
env,
84
90
config,
85
- ui_req_tx : None ,
91
+ ui_req_tx : ui_tx,
92
+ input_system : input:: Input_System :: new ( input_tx) ,
93
+ input_actions_rx : input_rx,
94
+ gfx_resources : resources:: gfx:: Gfx_Resources :: new ( ) ,
86
95
audio_resources : resources:: audio:: Audio_Resources :: new ( sound_loader) ,
87
- render_thread : None ,
88
- render_thread_quit : None ,
89
- input_actions_rx : None ,
96
+ render_system : gfx:: render_system:: Render_System :: new ( ) ,
97
+ ui_system : gfx:: ui:: UI_System :: new ( ui_rx) ,
90
98
audio_system : audio:: system:: Audio_System :: new ( 10 ) ,
91
99
gameplay_system : gameplay_system:: Gameplay_System :: new ( ) ,
92
100
}
@@ -111,116 +119,89 @@ impl<'r> App<'r> {
111
119
vec ! [ config_watcher] ,
112
120
) ?;
113
121
114
- Ok ( ( ) )
115
- }
122
+ self . gameplay_system
123
+ . init ( & mut self . gfx_resources , & self . env , & self . config ) ?;
124
+ self . render_system
125
+ . init ( gfx:: render_system:: Render_System_Config {
126
+ clear_color : colors:: rgb ( 22 , 0 , 22 ) ,
127
+ } ) ?;
116
128
117
- fn start_render_thread (
118
- & mut self ,
119
- entity_transform_rx : mpsc:: Receiver < ( Entity , C_Transform2D ) > ,
120
- camera_transform_rx : mpsc:: Receiver < C_Camera2D > ,
121
- ) {
122
- let ( input_tx, input_rx) = mpsc:: channel ( ) ;
123
- self . input_actions_rx = Some ( input_rx) ;
124
-
125
- let ( ui_tx, ui_rx) = mpsc:: channel ( ) ;
126
- self . ui_req_tx = Some ( ui_tx) ;
127
-
128
- let ( quit_tx, quit_rx) = mpsc:: channel ( ) ;
129
- self . render_thread_quit = Some ( quit_tx) ;
130
-
131
- self . render_thread = Some ( gfx:: render_system:: start_render_thread (
132
- self . env . clone ( ) ,
133
- input_tx,
134
- ui_rx,
135
- entity_transform_rx,
136
- camera_transform_rx,
137
- quit_rx,
138
- gfx:: render_system:: Render_System_Config {
139
- clear_color : colors:: rgb ( 48 , 10 , 36 ) ,
140
- } ,
141
- ) ) ;
129
+ Ok ( ( ) )
142
130
}
143
131
144
- pub fn run ( & mut self ) -> Maybe_Error {
145
- let ( et_tx, et_rx) = mpsc:: channel ( ) ;
146
- let ( cam_tx, cam_rx) = mpsc:: channel ( ) ;
147
- self . gameplay_system . init ( & self . config , et_tx, cam_tx) ?; // @Temporary workaround
148
- self . start_render_thread ( et_rx, cam_rx) ;
149
-
150
- self . start_game_loop ( ) ?;
132
+ pub fn run ( & mut self , window : & mut gfx:: window:: Window_Handle ) -> Maybe_Error {
133
+ self . start_game_loop ( window) ?;
151
134
Ok ( ( ) )
152
135
}
153
136
154
- fn start_game_loop ( & mut self ) -> Maybe_Error {
137
+ fn start_game_loop ( & mut self , window : & mut gfx :: window :: Window_Handle ) -> Maybe_Error {
155
138
let mut fps_debug = debug:: fps:: Fps_Console_Printer :: new ( & Duration :: from_secs ( 3 ) , "main" ) ;
156
- let input_actions_rx = self . input_actions_rx . take ( ) . unwrap ( ) ;
157
139
let mut execution_time = Duration :: new ( 0 , 0 ) ;
158
140
159
141
while !self . should_close {
160
- let frame_start_t = std:: time:: SystemTime :: now ( ) ;
161
-
162
142
// Update time
163
143
self . time . update ( ) ;
164
144
165
145
let dt = self . time . dt ( ) ;
166
-
167
- let update_time = Duration :: from_nanos (
168
- ( * self
146
+ let real_dt = self . time . real_dt ( ) ;
147
+ let update_time = Duration :: from_millis (
148
+ * self
169
149
. config
170
- . get_var_float_or ( "engine/gameplay/gameplay_update_tick_ms" , 10.0 )
171
- * 1_000_000.0 ) as u64 ,
150
+ . get_var_int_or ( "engine/gameplay/gameplay_update_tick_ms" , 10 )
151
+ as u64 ,
172
152
) ;
173
153
174
- // Update input
175
- // Note: due to SFML limitations, the event loop is run on the render thread.
176
- let actions = if let Ok ( new_actions) = input_actions_rx. try_recv ( ) {
177
- new_actions
178
- } else {
179
- input:: Action_List :: default ( )
180
- } ;
154
+ execution_time += dt;
181
155
156
+ // Update input
157
+ self . input_system . update ( window) ;
158
+ let actions = self . input_system . get_action_list ( ) ;
182
159
self . handle_actions ( & actions) ?;
183
160
184
- execution_time += dt ;
185
-
161
+ // Update game systems
162
+ let gameplay_start_t = SystemTime :: now ( ) ;
186
163
while execution_time > update_time {
187
- // Update game systems
188
164
self . update_game_systems ( update_time, & actions) ?;
189
165
execution_time -= update_time;
190
166
}
167
+ println ! (
168
+ "Gameplay: {} ms" ,
169
+ SystemTime :: now( )
170
+ . duration_since( gameplay_start_t)
171
+ . unwrap( )
172
+ . as_millis( )
173
+ ) ;
191
174
192
175
// Update audio
193
176
self . audio_system . update ( ) ;
194
177
195
- self . config . update ( ) ;
196
-
197
- let frame_duration = std:: time:: SystemTime :: now ( )
198
- . duration_since ( frame_start_t)
199
- . unwrap ( ) ;
200
-
201
- fps_debug. tick ( & self . time . real_dt ( ) ) ;
178
+ // Render
179
+ let render_start_t = SystemTime :: now ( ) ;
180
+ self . update_graphics (
181
+ window,
182
+ real_dt,
183
+ time:: duration_ratio ( & execution_time, & update_time) as f32 ,
184
+ ) ?;
185
+ println ! (
186
+ "Render: {} ms" ,
187
+ SystemTime :: now( )
188
+ . duration_since( render_start_t)
189
+ . unwrap( )
190
+ . as_millis( )
191
+ ) ;
202
192
203
- if frame_duration < update_time {
204
- std:: thread:: sleep ( update_time - frame_duration) ;
205
- } else {
206
- eprintln ! (
207
- "[ WARNING ] Game loop took {} ms, which is more than the requested {} ms." ,
208
- frame_duration. as_millis( ) ,
209
- update_time. as_millis( )
210
- ) ;
193
+ #[ cfg( debug_assertions) ]
194
+ {
195
+ let sleep = * self
196
+ . config
197
+ . get_var_int_or ( "engine/debug/extra_frame_sleep_ms" , 0 )
198
+ as u64 ;
199
+ std:: thread:: sleep ( Duration :: from_millis ( sleep) ) ;
211
200
}
212
- }
213
201
214
- self . render_thread_quit
215
- . as_mut ( )
216
- . unwrap ( )
217
- . send ( ( ) )
218
- . expect ( "[ ERR ] Failed to send quit message to render thread!" ) ;
219
- self . render_thread
220
- . take ( )
221
- . unwrap ( )
222
- . join ( )
223
- . expect ( "[ ERR ] Failed to join render thread!" ) ;
202
+ self . config . update ( ) ;
203
+ fps_debug. tick ( & dt) ;
204
+ }
224
205
225
206
Ok ( ( ) )
226
207
}
@@ -231,12 +212,37 @@ impl<'r> App<'r> {
231
212
Ok ( ( ) )
232
213
}
233
214
215
+ fn update_graphics (
216
+ & mut self ,
217
+ window : & mut gfx:: window:: Window_Handle ,
218
+ real_dt : Duration ,
219
+ frame_lag_normalized : f32 ,
220
+ ) -> Maybe_Error {
221
+ let smooth_by_extrapolating_velocity = * self
222
+ . config
223
+ . get_var_bool_or ( "engine/rendering/smooth_by_extrapolating_velocity" , false ) ;
224
+
225
+ gfx:: window:: set_clear_color ( window, colors:: rgb ( 0 , 0 , 0 ) ) ;
226
+ gfx:: window:: clear ( window) ;
227
+ self . render_system . update (
228
+ window,
229
+ & self . gfx_resources ,
230
+ & self . gameplay_system . get_camera ( ) ,
231
+ & self . gameplay_system . get_renderable_entities ( ) ,
232
+ frame_lag_normalized,
233
+ smooth_by_extrapolating_velocity,
234
+ ) ;
235
+ self . ui_system
236
+ . update ( & real_dt, window, & mut self . gfx_resources ) ;
237
+ gfx:: window:: display ( window) ;
238
+
239
+ Ok ( ( ) )
240
+ }
241
+
234
242
fn handle_actions ( & mut self , actions : & input:: Action_List ) -> Maybe_Error {
235
243
use gfx:: ui:: UI_Request ;
236
244
use input:: Action ;
237
245
238
- let ui_req_tx = self . ui_req_tx . as_ref ( ) . unwrap ( ) ;
239
-
240
246
if actions. has_action ( & Action :: Quit ) {
241
247
self . should_close = true ;
242
248
} else {
@@ -247,7 +253,7 @@ impl<'r> App<'r> {
247
253
if ts > 0.0 {
248
254
self . time . set_time_scale ( ts) ;
249
255
}
250
- ui_req_tx
256
+ self . ui_req_tx
251
257
. send ( UI_Request :: Add_Fadeout_Text ( format ! (
252
258
"Time scale: {:.2}" ,
253
259
self . time. get_time_scale( )
@@ -256,7 +262,7 @@ impl<'r> App<'r> {
256
262
}
257
263
Action :: Pause_Toggle => {
258
264
self . time . set_paused ( !self . time . is_paused ( ) ) ;
259
- ui_req_tx
265
+ self . ui_req_tx
260
266
. send ( UI_Request :: Add_Fadeout_Text ( String :: from (
261
267
if self . time . is_paused ( ) {
262
268
"Paused"
@@ -271,7 +277,7 @@ impl<'r> App<'r> {
271
277
let step_delta = Duration :: from_nanos (
272
278
u64:: try_from ( 1_000_000_000 / * target_fps) . unwrap ( ) ,
273
279
) ;
274
- ui_req_tx
280
+ self . ui_req_tx
275
281
. send ( UI_Request :: Add_Fadeout_Text ( format ! (
276
282
"Stepping of: {:.2} ms" ,
277
283
time:: to_secs_frac( & step_delta) * 1000.0
0 commit comments