diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/build.sh | 29 | ||||
-rw-r--r-- | src/crrn.c | 129 | ||||
-rw-r--r-- | src/crrn.h | 22 | ||||
-rw-r--r-- | src/data/textures/grid.png | bin | 10801 -> 0 bytes | |||
-rw-r--r-- | src/engine/sdl_linux.c | 233 | ||||
-rw-r--r-- | src/game/game.c | 117 | ||||
-rw-r--r-- | src/game/game.h | 20 | ||||
-rw-r--r-- | src/linux.c | 348 | ||||
-rw-r--r-- | src/perf.data | bin | 110468 -> 0 bytes | |||
-rwxr-xr-x | src/prge_game_example | bin | 634504 -> 0 bytes | |||
-rw-r--r-- | src/shaders/default.frag | 14 | ||||
-rw-r--r-- | src/shaders/default.vert | 18 | ||||
-rw-r--r-- | src/shaders/ui.frag | 10 | ||||
-rw-r--r-- | src/shaders/ui.vert | 10 | ||||
-rw-r--r-- | src/windows.c | 148 |
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 Binary files differdeleted file mode 100644 index eb951c3..0000000 --- a/src/data/textures/grid.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index deca599..0000000 --- a/src/perf.data +++ /dev/null diff --git a/src/prge_game_example b/src/prge_game_example Binary files differdeleted file mode 100755 index 0d82072..0000000 --- a/src/prge_game_example +++ /dev/null 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; +} |