1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include "game.h"
#include "sys.h"
#include <SDL3/SDL.h>
#include <GL/glew.h>
#define DEBUG 1
typedef struct {
SDL_Window *window;
i32 width;
i32 height;
SDL_Renderer *renderer;
u64 last_counter;
f32 dt;
} sdl_context_t;
static sdl_context_t init_sdl(i32 width, i32 height, i32 debug)
{
sdl_context_t ctx = {0};
ctx.width = width;
ctx.height = height;
SDL_Init(SDL_INIT_VIDEO);
u64 flags = SDL_WINDOW_OPENGL;
SDL_CreateWindowAndRenderer("breakout", ctx.width, ctx.height, flags, &ctx.window, &ctx.renderer);
if (debug)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GLContext glctx = SDL_GL_CreateContext(ctx.window);
SDL_GL_MakeCurrent(ctx.window, glctx);
SDL_GL_SetSwapInterval(0);
ctx.last_counter = SDL_GetPerformanceCounter();
glewInit();
return ctx;
}
static void process_sdl_key(input_t *input, i32 scancode, i32 pressed)
{
switch (scancode) {
case SDL_SCANCODE_ESCAPE:
input->escape.current = pressed;
break;
case SDL_SCANCODE_RIGHT:
input->right.current = pressed;
break;
case SDL_SCANCODE_LEFT:
input->left.current = pressed;
break;
case SDL_SCANCODE_SPACE:
input->space.current = pressed;
break;
default:
break;
}
}
static void process_sdl_events(game_t *game)
{
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
process_sdl_key(&game->input, event.key.scancode, event.key.down);
default:
break;
}
}
}
static f32 get_elapsed(u64 last_counter)
{
u64 frequency = SDL_GetPerformanceFrequency();
u64 current_counter = SDL_GetPerformanceCounter();
return (f32)(current_counter - last_counter) / (f32)frequency;
}
static void lock_framerate_sdl(sdl_context_t *ctx, i32 fps)
{
f32 elapsed = get_elapsed(ctx->last_counter) * 1000.0f;
f32 target = 1000.0f / (f32)fps;
f32 sleep = target - elapsed;
if (sleep > 0)
SDL_Delay((u32)sleep);
do {
elapsed = get_elapsed(ctx->last_counter) * 1000.0f;
} while (elapsed < target);
ctx->dt = get_elapsed(ctx->last_counter);
ctx->last_counter = SDL_GetPerformanceCounter();
}
static void fps_info(f32 dt, i32 again)
{
static f32 time = 0;
static i32 lastsec = 0;
static f32 sumdt = 0;
static i32 sumfps = 0;
static f32 frame_count = 0;
time += dt;
sumdt += dt;
sumfps += (i32)(1.0f / dt);
frame_count++;
i32 sec = (i32)time;
if (sec != 0 && sec % again == 0) {
if (lastsec != sec) {
f32 mean_dt = sumdt / frame_count;
f32 mean_fps = sumfps / frame_count;
info("time: %d dt: %f fps: %f", sec, mean_dt, mean_fps);
lastsec = sec;
sumdt = 0;
sumfps = 0;
frame_count = 0;
}
}
}
i32 main(void)
{
sdl_context_t ctx = init_sdl(1600, 800, DEBUG);
game_t game = init_game(ctx.width, ctx.height);
while (game.running) {
process_sdl_events(&game);
process_input(&game);
update_game(&game, ctx.dt);
update_input(&game.input);
lock_framerate_sdl(&ctx, 60);
fps_info(ctx.dt, 10);
render_game(game);
SDL_GL_SwapWindow(ctx.window);
}
return 0;
}
|