summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/build.sh29
-rw-r--r--src/crrn.c129
-rw-r--r--src/crrn.h22
-rw-r--r--src/data/textures/grid.pngbin10801 -> 0 bytes
-rw-r--r--src/engine/sdl_linux.c233
-rw-r--r--src/game/game.c117
-rw-r--r--src/game/game.h20
-rw-r--r--src/linux.c348
-rw-r--r--src/perf.databin110468 -> 0 bytes
-rwxr-xr-xsrc/prge_game_examplebin634504 -> 0 bytes
-rw-r--r--src/shaders/default.frag14
-rw-r--r--src/shaders/default.vert18
-rw-r--r--src/shaders/ui.frag10
-rw-r--r--src/shaders/ui.vert10
-rw-r--r--src/windows.c148
15 files changed, 647 insertions, 451 deletions
diff --git a/src/build.sh b/src/build.sh
deleted file mode 100755
index 1591c14..0000000
--- a/src/build.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-CFLAGS='
--g
--Wall
--Wextra
--DSTBI_NO_SIMD
-'
-
-INCLUDE='
--I../lib
--I../lib/prge
--I../lib/prb
--Igame
-'
-
-LFLAGS=''
-LIBS='
--lm
--lSDL3
--lGL
--lGLEW
-'
-
-TARGET='prge_game_example'
-
-set -x
-
-time tcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $LIBS engine/sdl_linux.c && ./$TARGET
diff --git a/src/crrn.c b/src/crrn.c
new file mode 100644
index 0000000..ba250f9
--- /dev/null
+++ b/src/crrn.c
@@ -0,0 +1,129 @@
+void init(prge_context_t *ctx, game_context_t *gctx)
+{
+ gctx->camera = (camera_t){
+ .position = (v3){3.0f, 1.5f, 3.0f},
+ .fov = 90.0f,
+ .near = 0.1f,
+ .far = 1000.0f,
+ .angles = {20.0f, -45.0f, 0.0f}
+ };
+
+ char path[MAX_PATH];
+ snprintf(path, sizeof(path), "%s/data/shaders", ctx->dir);
+
+ gctx->mesh_shader = load_gl_shader(path, "mesh.vert", 0, "mesh.frag");
+ gctx->ui_shader = load_gl_shader(path, "ui.vert", 0, "ui.frag");
+ gctx->grid_shader = load_gl_shader(path, "grid.vert", 0, "grid.frag");
+
+ gctx->texture = prge_load_texture(ctx, "data/textures/grid.png", 1);
+
+ mesh_t *quad = push_arena(&ctx->arena, sizeof(mesh_t));
+ quad[0] = gen_quad_mesh(&ctx->arena, DEFAULT_TRANSFORM, 100.0f, 100.0f);
+ add_mesh_texture(quad, gctx->texture);
+
+ model_t grid_model = {DEFAULT_TRANSFORM, 1, quad};
+ grid_model.transform.rotation.x = -90.0f;
+ entity_t grid = {ENTITY_ALPHA, grid_model, V3_ZERO, V3_ZERO, BBOX_ZERO};
+ add_entity(grid, &ctx->entities);
+
+ model_t cube = prge_load_model(ctx, DEFAULT_TRANSFORM, "data/models/cube.obj");
+ add_mesh_texture(&cube.meshes[0], gctx->texture);
+
+ entity_t player = {ENTITY_COLLIDE, cube, {0.0f, 2.0f, 0.0f}, V3_ZERO, BBOX_UNIT};
+ gctx->player_id = add_entity(player, &ctx->entities);
+
+ entity_t floor = {ENTITY_COLLIDE, cube, V3_ZERO, V3_ZERO, BBOX_UNIT};
+ gctx->floor_id = add_entity(floor, &ctx->entities);
+
+ gctx->hurt_id = prge_load_sound_vorbis(ctx, "data/sounds/hurt.ogg");
+}
+
+void update_camera_first_person(game_context_t *gctx, input_t *input, float speed, float sens)
+{
+ v3 r, u, f;
+ camera_get_vecs(gctx->camera, &r, &u, &f);
+ v3 ddp = V3_ZERO;
+ if (is_key_down(input->move_forward))
+ ddp = v3_add(ddp, v3_inv(f));
+ if (is_key_down(input->move_backward))
+ ddp = v3_add(ddp, f);
+ if (is_key_down(input->move_right))
+ ddp = v3_add(ddp, r);
+ if (is_key_down(input->move_left))
+ ddp = v3_add(ddp, v3_inv(r));
+ if (is_key_down(input->move_up))
+ ddp = v3_add(ddp, u);
+ if (is_key_down(input->move_down))
+ ddp = v3_add(ddp, v3_inv(u));
+ ddp = v3_norm(ddp);
+
+ gctx->camera.position = v3_add(gctx->camera.position, gctx->camera_dp);
+ gctx->camera_dp = v3_scalef(v3_add(gctx->camera_dp, v3_scalef(ddp, input->dt*speed)), 0.8f);
+
+ if (input->mouse.capture) {
+ gctx->camera.angles.y += input->mouse.offset.x*sens;
+ gctx->camera.angles.x += input->mouse.offset.y*sens;
+ if (gctx->camera.angles.x > 89.0f)
+ gctx->camera.angles.x = 89.0f;
+ if (gctx->camera.angles.x < -89.0f)
+ gctx->camera.angles.x = -89.0f;
+ }
+}
+
+void update_and_render(prge_context_t *ctx, game_context_t *gctx)
+{
+ /* NOTE(pryazha): Update */
+ if (is_key_pressed(ctx->input.exit)) {
+ if (ctx->input.mouse.capture) {
+ ctx->input.mouse.capture = 0;
+ } else {
+ ctx->should_close = 1;
+ }
+ }
+
+ float speed = 1.0f, sens = 0.05f;
+ update_camera_first_person(gctx, &ctx->input, speed, sens);
+
+ /* TODO(pryazha): Update physics */
+ entity_t *player = get_entity(ctx->entities, gctx->player_id);
+ entity_t *floor = get_entity(ctx->entities, gctx->floor_id);
+ entity_t new = move_entity(*player, V3_UP, ctx->input.dt);
+
+ v3 color = {1.0f, 0.0f, 0.0f};
+ if (!check_collision(player, floor)) {
+ *player = new;
+ color = V3_ONE;
+ }
+
+ /* NOTE(pryazha): Render */
+ v3 bgcolor = {0.15f, 0.15f, 0.15f};
+ clear_window(bgcolor);
+
+ begin3d(ctx->window, gctx->mesh_shader, gctx->camera);
+ shader_set_v3(gctx->mesh_shader, "color", color);
+ draw_entities(ctx->entities, gctx->mesh_shader);
+ end3d();
+
+ begin3d_alpha(ctx->window, gctx->grid_shader, gctx->camera);
+ draw_entities_alpha(ctx->entities, gctx->grid_shader);
+ end3d_alpha();
+
+ int count = 2;
+ float width = (float)ctx->window.width*0.25f;
+ float height = (float)ctx->window.height*0.05f;
+ v2 start = {10, (float)ctx->window.height - height - 10};
+ v2 end = {start.x + width, start.y + height};
+ rect_t ui_rect = {start, end};
+ float padding = 5.0f;
+ ui_t ui = beginui(ctx->window, ctx->input, gctx->ui_shader,
+ ui_rect, &ctx->frame_arena, padding);
+ float button_width = width/count - 2.0f*padding;
+ float button_height = height - 2.0f*padding;
+ if (button(&ui, "capture mouse", button_width, button_height))
+ ctx->input.mouse.capture = 1;
+ if (button(&ui, "hurt sound", button_width, button_height))
+ prge_play_sound(ctx, gctx->hurt_id);
+ endui();
+
+ gctx->time += ctx->input.dt;
+}
diff --git a/src/crrn.h b/src/crrn.h
new file mode 100644
index 0000000..6d4ff99
--- /dev/null
+++ b/src/crrn.h
@@ -0,0 +1,22 @@
+#ifndef GAME_H
+#define GAME_H
+
+typedef struct {
+ texture_t texture;
+
+ camera_t camera;
+ v3 camera_dp;
+
+ shader_t mesh_shader;
+ shader_t ui_shader;
+ shader_t grid_shader;
+
+ int player_id;
+ int floor_id;
+
+ int hurt_id;
+
+ float time;
+} game_context_t;
+
+#endif /* GAME_H */
diff --git a/src/data/textures/grid.png b/src/data/textures/grid.png
deleted file mode 100644
index eb951c3..0000000
--- a/src/data/textures/grid.png
+++ /dev/null
Binary files differ
diff --git a/src/engine/sdl_linux.c b/src/engine/sdl_linux.c
deleted file mode 100644
index 806b718..0000000
--- a/src/engine/sdl_linux.c
+++ /dev/null
@@ -1,233 +0,0 @@
-#include "GL/glew.h"
-#include "SDL3/SDL.h"
-
-#include "prge.h"
-
-#include "game.h"
-#include "game.c"
-
-void process_mouse_pos(Input *input, SDL_MouseMotionEvent *mouseev)
-{
- V2 offset;
-
- input->mouse_pos = v2((F32)mouseev->x, (F32)mouseev->y);
-
- if (input->first_mouse)
- input->first_mouse = 0;
-
- offset = v2((F32)mouseev->xrel, (F32)mouseev->yrel);
- input->mouse_offset = v2add(input->mouse_offset, offset);
-}
-
-void process_key(B32 down, Key *key)
-{
- key->state = (down ? KeyState_PRESS : KeyState_RELEASE);
-}
-
-void process_keyboard(Input *input, SDL_KeyboardEvent *keyev)
-{
- switch (keyev->scancode) {
- case SDL_SCANCODE_D:
- process_key(keyev->down, &input->move_right);
- break;
- case SDL_SCANCODE_W:
- process_key(keyev->down, &input->move_forward);
- break;
- case SDL_SCANCODE_A:
- process_key(keyev->down, &input->move_left);
- break;
- case SDL_SCANCODE_S:
- process_key(keyev->down, &input->move_backward);
- break;
- case SDL_SCANCODE_E:
- process_key(keyev->down, &input->move_up);
- break;
- case SDL_SCANCODE_Q:
- process_key(keyev->down, &input->move_down);
- break;
- case SDL_SCANCODE_SPACE:
- process_key(keyev->down, &input->jump);
- break;
- case SDL_SCANCODE_RIGHT:
- process_key(keyev->down, &input->action_right);
- break;
- case SDL_SCANCODE_UP:
- process_key(keyev->down, &input->action_up);
- break;
- case SDL_SCANCODE_LEFT:
- process_key(keyev->down, &input->action_left);
- break;
- case SDL_SCANCODE_DOWN:
- process_key(keyev->down, &input->action_down);
- break;
- case SDL_SCANCODE_ESCAPE:
- process_key(keyev->down, &input->exit);
- break;
- default:
- break;
- }
-}
-
-void process_mouse_buttons(Input *input, SDL_MouseButtonEvent *buttonev)
-{
- if (buttonev->button == SDL_BUTTON_LEFT)
- process_key(buttonev->down, &input->mouse_left);
- else if (buttonev->button == SDL_BUTTON_RIGHT)
- process_key(buttonev->down, &input->mouse_right);
-}
-
-void handle_events(Window *wnd, Input *input)
-{
- SDL_Event event;
-
- while (SDL_PollEvent(&event)) {
- switch (event.type) {
- case SDL_EVENT_KEY_DOWN:
- case SDL_EVENT_KEY_UP:
- process_keyboard(input, &event.key);
- break;
- case SDL_EVENT_MOUSE_MOTION:
- process_mouse_pos(input, &event.motion);
- break;
- case SDL_EVENT_MOUSE_BUTTON_DOWN:
- case SDL_EVENT_MOUSE_BUTTON_UP:
- process_mouse_buttons(input, &event.button);
- break;
- case SDL_EVENT_WINDOW_RESIZED:
- wnd->width = event.window.data1;
- wnd->height = event.window.data2;
- break;
- default:
- break;
- }
- }
-}
-
-F32 get_elapsed_seconds(U64 cur, U64 last)
-{
- F32 res;
- res = ((F32)cur-(F32)last)/1000.0f;
- return res;
-}
-
-F32 lock_framerate(U64 last, F32 target)
-{
- F32 target_mspf, elapsed, sleep, dt;
-
- elapsed = get_elapsed_seconds(SDL_GetTicks(), last)*1000.0f;
- target_mspf = 1000.0f/target;
-
- if (elapsed < target_mspf) {
- sleep = target_mspf-elapsed;
- if (sleep > 0.0f)
- SDL_Delay(sleep);
- /*
- do {
- elapsed = get_elapsed_seconds(SDL_GetTicks(), last)*1000.0f;
- } while (elapsed < target_mspf);
- */
- }
-
- dt = get_elapsed_seconds(SDL_GetTicks(), last);
-
- return dt;
-}
-
-B32 sdl_init(Window *wnd, SDL_Window **sdl_window, SDL_GLContext *context)
-{
- U32 flags;
- GLenum error;
- Arena *tmpar;
- char *wname;
-
- if (!SDL_Init(SDL_INIT_VIDEO)) {
- SDL_Log("[ERROR] : SDL : %s\n", SDL_GetError());
- return 0;
- }
-
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-
- tmpar = arena_alloc(0);
- wname = str8tocstr(tmpar, wnd->name);
-
- flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
-
- (*sdl_window) = SDL_CreateWindow(wname, wnd->width, wnd->height, flags);
-
- arena_release(tmpar);
-
- if (!(*sdl_window)) {
- SDL_Log("[ERROR] : SDL : %s\n", SDL_GetError());
- return 0;
- }
-
- SDL_GetWindowSize(*sdl_window, &wnd->width, &wnd->height);
-
- (*context) = SDL_GL_CreateContext((*sdl_window));
- if (!(*context)) {
- SDL_Log("[ERROR] : SDL : %s\n", SDL_GetError());
- return 0;
- }
-
- error = glewInit();
- if (error != GLEW_OK) {
- SDL_Log("[ERROR] : GLEW : %s\n", glewGetErrorString(error));
- return 0;
- }
-
- return 1;
-}
-
-int main(void)
-{
- /* NOTE(pryazha): Engine init */
- Input input;
- Window wnd;
-
- input = input_init();
- wnd = window_init(800, 600, str8lit("PRGE example"));
-
- /* NOTE(pryazha): SDL and OpenGL init */
- SDL_Window *sdl_window;
- SDL_GLContext context;
- U64 last;
-
- if (!sdl_init(&wnd, &sdl_window, &context)) {
- SDL_Quit();
- return 1;
- }
-
- glEnable(GL_DEPTH_TEST);
-
- /* NOTE(pryazha): Game init */
- State state;
- MemoryZero(&state, sizeof(State));
-
- init(&state);
-
- last = SDL_GetTicks();
-
- while (input.is_running) {
- SDL_SetWindowRelativeMouseMode(sdl_window, input.capture_mouse);
-
- handle_events(&wnd, &input);
-
- input.dt = lock_framerate(last, 60.0f);
- last = SDL_GetTicks();
-
- update_and_render(&wnd, &state, &input);
-
- input_update(&input);
-
- SDL_GL_SwapWindow(sdl_window);
- }
-
- clear(&state);
-
- SDL_GL_DestroyContext(context);
- SDL_DestroyWindow(sdl_window);
- SDL_Quit();
- return 0;
-}
diff --git a/src/game/game.c b/src/game/game.c
deleted file mode 100644
index 47d70eb..0000000
--- a/src/game/game.c
+++ /dev/null
@@ -1,117 +0,0 @@
-void init(State *state)
-{
- U32 nmeshes;
- Mesh *meshes;
-
- state->parena = arena_alloc(Kilobytes(256));
-
- state->camera = camera_init(v3(0.0f, 0.0f, 3.0f),
- 90.0f, 0.1f, 100.0f,
- 0.0f, 0.0f, 0.0f);
- state->camera_dp = V3_ZERO;
-
- state->mesh_shader = load_shader("shaders/default.vert", 0, "shaders/default.frag");
- state->ui_shader = load_shader("shaders/ui.vert", 0, "shaders/ui.frag");
-
- state->texture = load_texture(state->parena, str8lit("data/textures/grid.png"), 0);
-
- nmeshes = 2;
- meshes = arena_push(state->parena, nmeshes*sizeof(Mesh));
- meshes[0] = *mesh_gen_circle(state->parena, v3(0.0f, 0.0f, 2.0f), V3_ZERO, 3.0f, 6);
- meshes[1] = *mesh_gen_quad(state->parena, V3_ZERO, v3(0.0f, 90.0f, 0.0f), 2.0f, 2.0f);
-
- mesh_add_texture(&meshes[0], state->texture);
-
- state->model = model_init(state->parena, V3_ZERO, V3_ZERO, meshes, nmeshes);
-}
-
-void update_camera_first_person(State *state, Input *input, F32 speed, F32 mouse_sens)
-{
- V3 ddp, r, u, f;
-
- camera_get_vectors_first_person(&state->camera, &r, &u, &f);
- ddp = V3_ZERO;
- if (key_is_pressed(input->move_forward))
- ddp = v3add(ddp, v3inv(f));
- if (key_is_pressed(input->move_backward))
- ddp = v3add(ddp, f);
- if (key_is_pressed(input->move_right))
- ddp = v3add(ddp, r);
- if (key_is_pressed(input->move_left))
- ddp = v3add(ddp, v3inv(r));
- if (key_is_pressed(input->move_up))
- ddp = v3add(ddp, u);
- if (key_is_pressed(input->move_down))
- ddp = v3add(ddp, v3inv(u));
- ddp = v3norm(ddp);
-
- state->camera.pos = v3add(state->camera.pos, state->camera_dp);
- state->camera_dp = v3scalef(v3add(state->camera_dp, v3scalef(ddp, input->dt*speed)), 0.8f);
-
- /* NOTE(pryazha): Camera angles */
- if (input->capture_mouse) {
- state->camera.yaw += input->mouse_offset.x*mouse_sens;
- state->camera.pitch += input->mouse_offset.y*mouse_sens;
- if (state->camera.pitch > 89.0f)
- state->camera.pitch = 89.0f;
- if (state->camera.pitch < -89.0f)
- state->camera.pitch = -89.0f;
- }
-}
-
-void update_and_render(Window *wnd, State *state, Input *input)
-{
- /* NOTE(pryazha): Update */
- if (key_first_press(input->exit)) {
- if (input->capture_mouse) {
- input->capture_mouse = 0;
- } else {
- input->is_running = 0;
- }
- }
-
- /* NOTE(pryazha): Camera movement */
- update_camera_first_person(state, input, 1.0f, 0.3f);
-
- state->model->rotate.z += 20.0f*input->dt;
- state->model->rotate.x += 20.0f*input->dt;
-
- /* NOTE(pryazha): Render */
- MAT4 proj, view;
- F32 ar;
- Arena *ui_arena;
-
- glViewport(0, 0, wnd->width, wnd->height);
-
- glClearColor(0.15f, 0.15f, 0.15f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
- ar = (F32)wnd->width/(F32)wnd->height;
- proj = camera_persp(state->camera, ar);
- view = camera_get_view_matrix_first_person(&state->camera);
-
- model_draw(state->mesh_shader, &proj, &view, state->model);
-
- glUseProgram(state->ui_shader);
- proj = ortho(0.0f, (F32)wnd->width, 0.0f, (F32)wnd->height, -1.0f, 1.0f);
- shader_set_mat4fv(state->ui_shader, "proj", proj);
- ui_arena = arena_alloc(0);
- glDisable(GL_DEPTH_TEST);
-
- if (button(wnd, state->ui_shader, input, ui_arena, str8lit("some name"),
- v2(wnd->width/8.0f, wnd->height/8.0f), 50.0f, 30.0f))
- {
- input->capture_mouse = 1;
- }
-
- glEnable(GL_DEPTH_TEST);
- glUseProgram(0);
- arena_release(ui_arena);
-
- state->t += input->dt;
-}
-
-void clear(State *state)
-{
- arena_release(state->parena);
-}
diff --git a/src/game/game.h b/src/game/game.h
deleted file mode 100644
index bd98e7e..0000000
--- a/src/game/game.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef GAME_H
-#define GAME_H
-
-typedef struct {
- Arena *parena;
-
- Texture texture;
-
- Camera camera;
- V3 camera_dp;
-
- Model *model;
-
- U32 mesh_shader;
- U32 ui_shader;
-
- F32 t;
-} State;
-
-#endif /* GAME_H */
diff --git a/src/linux.c b/src/linux.c
new file mode 100644
index 0000000..474d430
--- /dev/null
+++ b/src/linux.c
@@ -0,0 +1,348 @@
+#include "GL/glew.h"
+#include "SDL3/SDL.h"
+
+#include "prge.h"
+
+#include "crrn.h"
+#include "crrn.c"
+
+typedef struct {
+ SDL_AudioSpec spec;
+ SDL_AudioStream *stream;
+} SDLSound;
+
+typedef struct {
+ SDLSound sdlsounds[MAX_SOUNDS_PLAYING];
+ SDL_AudioDeviceID audio_device;
+ SDL_Window *window;
+ SDL_GLContext glctx;
+} SDLContext;
+
+static SDLContext sdlctx;
+
+i32 init_sdl(prge_window_t *window)
+{
+ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
+ printf("error: sdl init: %s\n", SDL_GetError());
+ return 0;
+ }
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ if (window->flags & WINDOW_MULTISAMPLE)
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
+ u32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
+ sdlctx.window = SDL_CreateWindow(window->name, window->width, window->height, flags);
+ if (!sdlctx.window) {
+ printf("error: sdl create window: %s\n", SDL_GetError());
+ return 0;
+ }
+ SDL_GetWindowSize(sdlctx.window, &window->width, &window->height);
+
+ if (!(sdlctx.glctx = SDL_GL_CreateContext(sdlctx.window))) {
+ printf("error: sdl create gl context: %s\n", SDL_GetError());
+ return 0;
+ }
+ if (!SDL_GL_MakeCurrent(sdlctx.window, sdlctx.glctx)) {
+ printf("error: sdl make context current: %s\n", SDL_GetError());
+ return 0;
+ }
+
+ if (SDL_GL_SetSwapInterval(0))
+ printf("info: vsync disabled\n");
+ else
+ printf("warning: failed to disable vsync\n");
+
+ u32 error = glewInit();
+ if (error != GLEW_OK) {
+ printf("error: glew: %s\n", glewGetErrorString(error));
+ return 0;
+ }
+ if (window->flags & WINDOW_DEPTH_TEST)
+ glEnable(GL_DEPTH_TEST);
+ if (window->flags & WINDOW_MULTISAMPLE)
+ glEnable(GL_MULTISAMPLE);
+
+ sdlctx.audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, 0);
+ if (!sdlctx.audio_device) {
+ printf("error: sdl: couldn't open audio device\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+void process_mouse_pos(input_t *input, SDL_MouseMotionEvent *event, prge_window_t window)
+{
+ input->mouse.pos = (v2){(f32)event->x, window.height - (f32)event->y};
+ if (input->mouse.first)
+ input->mouse.first = 0;
+ v2 offset = {(f32)event->xrel, (f32)event->yrel};
+ input->mouse.offset = v2_add(input->mouse.offset, offset);
+}
+
+void process_key(i32 down, prge_key_t *key)
+{
+ key->state = (down ? key_state_press : key_state_release);
+}
+
+void process_keyboard(input_t *input, SDL_KeyboardEvent *keyev)
+{
+ switch (keyev->scancode) {
+ case SDL_SCANCODE_D:
+ process_key(keyev->down, &input->move_right);
+ break;
+ case SDL_SCANCODE_W:
+ process_key(keyev->down, &input->move_forward);
+ break;
+ case SDL_SCANCODE_A:
+ process_key(keyev->down, &input->move_left);
+ break;
+ case SDL_SCANCODE_S:
+ process_key(keyev->down, &input->move_backward);
+ break;
+ case SDL_SCANCODE_E:
+ process_key(keyev->down, &input->move_up);
+ break;
+ case SDL_SCANCODE_Q:
+ process_key(keyev->down, &input->move_down);
+ break;
+ case SDL_SCANCODE_SPACE:
+ process_key(keyev->down, &input->jump);
+ break;
+ case SDL_SCANCODE_RIGHT:
+ process_key(keyev->down, &input->action_right);
+ break;
+ case SDL_SCANCODE_UP:
+ process_key(keyev->down, &input->action_up);
+ break;
+ case SDL_SCANCODE_LEFT:
+ process_key(keyev->down, &input->action_left);
+ break;
+ case SDL_SCANCODE_DOWN:
+ process_key(keyev->down, &input->action_down);
+ break;
+ case SDL_SCANCODE_ESCAPE:
+ process_key(keyev->down, &input->exit);
+ break;
+ default:
+ break;
+ }
+}
+
+void process_mouse_buttons(input_t *input, SDL_MouseButtonEvent *buttonev)
+{
+ if (buttonev->button == SDL_BUTTON_LEFT)
+ process_key(buttonev->down, &input->mouse.left);
+ else if (buttonev->button == SDL_BUTTON_RIGHT)
+ process_key(buttonev->down, &input->mouse.right);
+}
+
+void handle_events(prge_context_t *ctx)
+{
+ SDL_Event event;
+
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_EVENT_KEY_DOWN:
+ case SDL_EVENT_KEY_UP:
+ process_keyboard(&ctx->input, &event.key);
+ break;
+ case SDL_EVENT_MOUSE_MOTION:
+ process_mouse_pos(&ctx->input, &event.motion, ctx->window);
+ break;
+ case SDL_EVENT_MOUSE_BUTTON_DOWN:
+ case SDL_EVENT_MOUSE_BUTTON_UP:
+ process_mouse_buttons(&ctx->input, &event.button);
+ break;
+ case SDL_EVENT_WINDOW_RESIZED:
+ ctx->window.width = event.window.data1;
+ ctx->window.height = event.window.data2;
+ break;
+ case SDL_EVENT_QUIT:
+ ctx->should_close = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+f32 get_elapsed_seconds(u64 current, u64 last)
+{
+ f32 elapsed = ((f32)current-(f32)last)/1000.0f;
+ return elapsed;
+}
+
+f32 lock_framerate(u64 last, f32 target)
+{
+ f32 elapsed = get_elapsed_seconds(SDL_GetTicks(), last)*1000.0f;
+ if (elapsed < target) {
+ f32 sleep = target-elapsed;
+ if (sleep > 0.0f)
+ SDL_Delay(sleep);
+ do {
+ elapsed = get_elapsed_seconds(SDL_GetTicks(), last)*1000.0f;
+ } while (elapsed < target);
+ }
+ f32 dt = get_elapsed_seconds(SDL_GetTicks(), last);
+ return dt;
+}
+
+#include "stb_vorbis.c"
+
+i32 load_vorbis(arena_t *arena, sound_t *sounds, const char *filename)
+{
+ sound_t sound;
+ sound.name = filename;
+
+ i32 i = find_sound(sounds, sound.name);
+ if (i != -1) {
+ printf("info: \"%s\" already loaded\n", sound.name);
+ return i;
+ }
+
+ /* TODO(pryazha): Custom loader with arenas (or provide allocator to stb) */
+ i16 *output;
+ i32 samples = stb_vorbis_decode_filename(filename, &sound.channels,
+ &sound.freq, &output);
+ if (samples == -1) {
+ printf("error: \"%s\" failed to open\n", filename);
+ return -1;
+ }
+
+ sound.bps = sizeof(i16);
+ sound.size = sound.channels*samples*sound.bps;
+ sound.data = push_arena(arena, sound.size);
+ prb_memmove(sound.data, output, sound.size);
+ free(output);
+
+ i = load_sound(sounds, sound);
+ if (i == -1) {
+ pop_arena(arena, sound.size);
+ return i;
+ }
+
+ printf("info: \"%s\" loaded successfully\n", filename);
+
+ return i;
+}
+
+void play_sound(sound_t *sounds, sound_queue_t *queue, sound_queue_node_t *nodes, i32 id)
+{
+ if ((id == -1) && (id >= MAX_SOUNDS_LOADED)) {
+ printf("error: invalid sound id = %d\n", id);
+ return;
+ }
+
+ if (!sounds[id].data) {
+ printf("error: sound with id = %d doesn't exist\n", id);
+ return;
+ }
+
+ sound_t *sound = sounds+id;
+
+ if (!enqueue_sound(queue, nodes, sound)) {
+ printf("error: failed to enqueue the sound \"%s\"\n", sound->name);
+ return;
+ }
+
+ printf("info: queue content:\n");
+ for (sound_queue_node_t *node = queue->first; node; node = node->next) {
+ printf("%s%s", node->sound->name, (node->next ? " -> " : "\n"));
+ }
+}
+
+SDLSound *get_empty_sdl_sound()
+{
+ for (i32 i = 0; i < MAX_SOUNDS_PLAYING; i++) {
+ SDLSound *sdlsound = sdlctx.sdlsounds+i;
+ if (!sdlsound->stream)
+ return sdlsound;
+ if (SDL_GetAudioStreamAvailable(sdlsound->stream) == 0)
+ return sdlsound;
+ }
+ return 0;
+}
+
+void update_sdl_sounds(sound_queue_t *queue)
+{
+ SDLSound *sdlsound;
+ sound_t *sound;
+ SDL_AudioSpec spec;
+
+ while ((sdlsound = get_empty_sdl_sound()) && (sound = dequeue_sound(queue))) {
+ switch (sound->bps) {
+ case 2:
+ spec.format = SDL_AUDIO_S16;
+ break;
+ default:
+ printf("error: sound: \"%s\". Unsupported audio format\n", sound->name);
+ return;
+ }
+ spec.channels = sound->channels;
+ spec.freq = sound->freq;
+
+ if (sdlsound->stream) {
+ if (!prb_memeq(&sdlsound->spec, &spec, sizeof(SDL_AudioSpec))) {
+ sdlsound->spec = spec;
+ SDL_SetAudioStreamFormat(sdlsound->stream, &sdlsound->spec, 0);
+ }
+ } else {
+ sdlsound->spec = spec;
+ sdlsound->stream = SDL_CreateAudioStream(&sdlsound->spec, 0);
+ if (!sdlsound->stream) {
+ printf("error: sailed to create audio stream\n");
+ return;
+ }
+ if (!SDL_BindAudioStream(sdlctx.audio_device, sdlsound->stream)) {
+ SDL_DestroyAudioStream(sdlsound->stream);
+ printf("error: failed to bind audio stream to device\n");
+ return;
+ }
+ }
+ printf("info: playing: \"%s\"\n", sound->name);
+ SDL_PutAudioStreamData(sdlsound->stream, sound->data, sound->size);
+ }
+}
+
+i32 main(void)
+{
+ // engine init
+ prge_context_t prgectx = init_prge();
+ u32 flags = WINDOW_DEPTH_TEST | WINDOW_MULTISAMPLE;
+ prgectx.window = (prge_window_t){800, 600, "prge example", flags};
+
+ f32 fps = 60.0f;
+ f32 mspf = 1000.0f/fps;
+
+ // sdl and opengl init
+ if (!init_sdl(&prgectx.window))
+ return 1;
+
+ // game init
+ game_context_t gctx = {0};
+ init(&prgectx, &gctx);
+
+ u64 last = SDL_GetTicks();
+ while (!prgectx.should_close) {
+ SDL_SetWindowRelativeMouseMode(sdlctx.window, prgectx.input.mouse.capture);
+
+ handle_events(&prgectx);
+
+ prgectx.input.dt = lock_framerate(last, mspf);
+ last = SDL_GetTicks();
+
+ pop_arena(&prgectx.frame_arena, prgectx.frame_arena.used);
+
+ glViewport(0, 0, prgectx.window.width, prgectx.window.height);
+ update_and_render(&prgectx, &gctx);
+ update_sdl_sounds(&prgectx.sound_queue);
+ update_input(&prgectx.input);
+
+ SDL_GL_SwapWindow(sdlctx.window);
+ }
+
+ return 0;
+}
diff --git a/src/perf.data b/src/perf.data
deleted file mode 100644
index deca599..0000000
--- a/src/perf.data
+++ /dev/null
Binary files differ
diff --git a/src/prge_game_example b/src/prge_game_example
deleted file mode 100755
index 0d82072..0000000
--- a/src/prge_game_example
+++ /dev/null
Binary files differ
diff --git a/src/shaders/default.frag b/src/shaders/default.frag
deleted file mode 100644
index d5d37c7..0000000
--- a/src/shaders/default.frag
+++ /dev/null
@@ -1,14 +0,0 @@
-#version 330 core
-
-in VSOUT {
- vec2 texc;
-} vsout;
-
-out vec4 fcolor;
-
-uniform sampler2D tex0;
-
-void main(void)
-{
- fcolor = texture(tex0, vsout.texc);
-}
diff --git a/src/shaders/default.vert b/src/shaders/default.vert
deleted file mode 100644
index a7b5e08..0000000
--- a/src/shaders/default.vert
+++ /dev/null
@@ -1,18 +0,0 @@
-#version 330 core
-layout(location = 0) in vec3 apos;
-layout(location = 1) in vec2 atexc;
-
-out VSOUT {
- vec2 texc;
-} vsout;
-
-uniform mat4 proj;
-uniform mat4 view;
-uniform mat4 model;
-
-void main(void)
-{
- vsout.texc = atexc;
-
- gl_Position = proj*view*model*vec4(apos, 1.0);
-}
diff --git a/src/shaders/ui.frag b/src/shaders/ui.frag
deleted file mode 100644
index bd0bc85..0000000
--- a/src/shaders/ui.frag
+++ /dev/null
@@ -1,10 +0,0 @@
-#version 330 core
-
-out vec4 fcolor;
-
-uniform vec4 color;
-
-void main(void)
-{
- fcolor = color;
-}
diff --git a/src/shaders/ui.vert b/src/shaders/ui.vert
deleted file mode 100644
index ad5d46a..0000000
--- a/src/shaders/ui.vert
+++ /dev/null
@@ -1,10 +0,0 @@
-#version 330 core
-layout(location = 0) in vec3 apos;
-
-uniform mat4 proj;
-uniform mat4 model;
-
-void main(void)
-{
- gl_Position = proj*model*vec4(apos, 1.0);
-}
diff --git a/src/windows.c b/src/windows.c
new file mode 100644
index 0000000..a439ebe
--- /dev/null
+++ b/src/windows.c
@@ -0,0 +1,148 @@
+#include <windows.h>
+#include <gl/GL.h>
+#include <stdio.h>
+
+#include "game.hpp"
+
+struct wincontext_t {
+ HWND window;
+ HDC device_context;
+ i32 width;
+ i32 height;
+};
+
+static wincontext_t wincontext;
+static input_t input;
+
+LRESULT WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ LRESULT result = 0;
+ switch (message) {
+ case WM_DESTROY:
+ case WM_QUIT:
+ wincontext.running = 0;
+ break;
+ case WM_KEYDOWN:
+ switch (wparam) {
+ case VK_ESCAPE:
+ input.escape.current = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case WM_KEYUP:
+ switch (wparam) {
+ case VK_ESCAPE:
+ input.escape.current = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case WM_SIZE:
+ wincontext.width = LOWORD(lparam);
+ wincontext.height = HIWORD(lparam);
+ glViewport(wincontext.width, wincontext.height);
+ break;
+ default:
+ result = DefWindowProc(window, message, wparam, lparam);
+ }
+ return result;
+}
+
+void update_input(input_t *input)
+{
+ input->escape.last = input->escape.current;
+}
+
+i32 init_win(HINSTANCE instance, i32 show_cmd, i32 width, i32 height)
+{
+ WNDCLASSA window_class = {};
+ window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ window_class.lpfnWndProc = (WNDPROC)WndProc;
+ window_class.hInstance = instance;
+ window_class.hCursor = LoadCursor(0, IDC_ARROW);
+ window_class.lpszClassName = "window class";
+ if (!RegisterClass(&window_class)) {
+ printf("error: failed to register window class\n");
+ return 0;
+ }
+
+ wincontext.width = width;
+ wincontext.height = height;
+ wincontext.window = CreateWindow(window_class.lpszClassName, "game", WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, wincontext.width, wincontext.height, 0, 0, instance, 0);
+ if (!wincontext.window) {
+ printf("error: failed to create a window\n");
+ return 0;
+ }
+
+ wincontext.running = 1;
+
+ wincontext.device_context = GetDC(wincontext.window);
+ if (!wincontext.device_context) {
+ printf("error: failed to get device context\n");
+ return 0;
+ }
+
+ PIXELFORMATDESCRIPTOR pixel_format_desc = {};
+ pixel_format_desc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ pixel_format_desc.nVersion = 1;
+ pixel_format_desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pixel_format_desc.cColorBits = 32;
+ pixel_format_desc.cAlphaBits = 8;
+ pixel_format_desc.cDepthBits = 24;
+
+ i32 pixel_format = ChoosePixelFormat(wincontext.device_context, &pixel_format_desc);
+ if (!pixel_format) {
+ printf("error: failed to choose pixel format\n");
+ return 0;
+ }
+ if (!SetPixelFormat(wincontext.device_context, pixel_format, &pixel_format_desc)) {
+ printf("error: failed to set pixel format\n");
+ return 0;
+ }
+
+ HGLRC gl_context = wglCreateContext(wincontext.device_context);
+ if (!gl_context) {
+ printf("error: failed to create gl context\n");
+ return 0;
+ }
+ if (!wglMakeCurrent(wincontext.device_context, gl_context)) {
+ printf("error: failed to make gl context current\n");
+ return 0;
+ }
+
+ ShowWindow(wincontext.window, show_cmd);
+ UpdateWindow(wincontext.window);
+
+ return 1;
+}
+
+void handle_win_events()
+{
+ MSG messages;
+ while (PeekMessage(&messages, 0, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&messages);
+ DispatchMessage(&messages);
+ }
+}
+
+int WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int show_cmd)
+{
+ if (!init_win(instance, show_cmd, 1600, 900))
+ return 1;
+
+ if (!init_game()) {
+ }
+
+ while (wincontext.running) {
+ handle_win_events();
+ game_update_and_render(input);
+ update_input(&input);
+ SwapBuffers(wincontext.device_context);
+ }
+
+ return 0;
+}