snake

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | LICENSE

commit a8ebdcefbb5184cf9d824993faf835fb9285731c
Author: Samdal <samdal@protonmail.com>
Date:   Tue,  6 Jul 2021 03:01:21 +0200

initial commit

Diffstat:
A.gitignore | 3+++
Afrag.glsl | 17+++++++++++++++++
Amain.c | 295+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avertex.glsl | 12++++++++++++
4 files changed, 327 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +*.exe +*.out +*.o diff --git a/frag.glsl b/frag.glsl @@ -0,0 +1,17 @@ +#version 330 core +precision mediump float; + +uniform int u_map[32]; +uniform vec2 u_resolution; +uniform vec2 u_food; + +void main() +{ + vec2 st = (gl_FragCoord.xy / u_resolution.xy) * 31.0; + int x = int(floor(st.x)); + int y = int(floor(st.y)); + gl_FragColor.g = float(u_map[y] & (1 << x)); + gl_FragColor.r = float(x == int(u_food.x) && y == int(u_food.y)); + gl_FragColor.b = 0.0; + gl_FragColor.a = 1.0; +} diff --git a/main.c b/main.c @@ -0,0 +1,295 @@ +#define GS_IMPL +#include <gs/gs.h> + +// Vertex data +float v_data[] = { + -1.0f, -1.0f, 0.0f, 0.0f, // Top Left + 1.0f, -1.0f, 1.0f, 0.0f, // Top Right + -1.0f, 1.0f, 0.0f, 1.0f, // Bottom Left + 1.0f, 1.0f, 1.0f, 1.0f // Bottom Right +}; +// Index data for quad +uint32_t i_data[] = { + 0, 3, 2, // First Triangle + 0, 1, 3 // Second Triangle +}; + +gs_command_buffer_t cb = {0}; +gs_handle(gs_graphics_vertex_buffer_t) vbo = {0}; +gs_handle(gs_graphics_index_buffer_t) ibo = {0}; +gs_handle(gs_graphics_pipeline_t) pip = {0}; +gs_handle(gs_graphics_shader_t) shader = {0}; +gs_handle(gs_graphics_uniform_t) u_resolution = {0}; +gs_handle(gs_graphics_uniform_t) u_food = {0}; +gs_handle(gs_graphics_uniform_t) u_map = {0}; + +char map_names[32][256] = {0}; +uint32_t map_buffer[32] = {0}; + +// snake linked list +typedef struct snake { + gs_vec2 pos; + void* next; +} snake_t; +snake_t* tail = &(snake_t){0}; + +gs_vec2 food = {16.0f, 16.0f}; + +gs_vec2 prev_move = {0}; +gs_vec2 move = {0}; +uint32_t prev_move_time = 0; + +snake_t* eat_food(snake_t* head) +{ + // move food + map_buffer[(int)food.y] |= (1 << (int)food.x); + do { + food = (gs_vec2){rand() % 32, rand() % 32}; + } while (map_buffer[(int)food.y] & (1 << (int)food.x)); + + // Grow snake + head->next = (snake_t*)gs_malloc(sizeof(snake_t)); + gs_assert(head->next); + gs_vec2 pos = head->pos; + head = head->next; + head->pos = pos; + head->next = NULL; + return head; +} + +void free_snake() +{ + while (tail->next) { + snake_t* head = tail; + for (;;) { + snake_t* next = head->next; + if (!next->next) + break; + head = next; + } + gs_free(head->next); + head->next = NULL; + } +} + +void new_game() +{ + // reinitialise buffers + for (uint32_t i = 0; i < 32; i++) + map_buffer[i] = 0; + prev_move_time = gs_platform_elapsed_time() * 0.01f; + move = (gs_vec2){1.0f, 0.0f}; + prev_move = move; + free_snake(); + + // init tail piece + snake_t* body = tail; + body->pos = (gs_vec2){16.0f, 16.0f}; + + // place tail piece in map_buffer + map_buffer[(int)floor(body->pos.y)] |= (1 << (int)floor(body->pos.x)); + + for (uint32_t i = 1; i <= 3; i++) { + // create snake piece + body->next = (snake_t*)gs_malloc(sizeof(snake_t)); + gs_assert(body->next); + body = body->next; + + // init snake piece + body->pos = (gs_vec2){16.0f + (float)i, 16.0f}; + body->next = NULL; + + // place snake piece in map_buffer + map_buffer[(int)floor(body->pos.y)] |= (1 << (int)floor(body->pos.x)); + } + + // place food at random position + do { + food = (gs_vec2){rand() % 32, rand() % 32}; + } while (map_buffer[(int)food.y] & (1 << (int)food.x)); +} + +void move_head(snake_t* head) +{ + head->pos.x += move.x; + head->pos.y += move.y; + // wrap snake + if (head->pos.x > 31.0f) + head->pos.x = 0.0f; + else if (head->pos.x < 0.0f) + head->pos.x = 31.0f; + else if (head->pos.y > 31.0f) + head->pos.y = 0.0f; + else if (head->pos.y < 0.0f) + head->pos.y = 31.0f; +} +void move_snake() +{ + + snake_t* body = tail; + prev_move = move; + + // get head + while (body->next) + body = body->next; + + // if new pos is food + if (body->pos.x + move.x == food.x && body->pos.y + move.y == food.y) { + body = eat_food(body); + move_head(body); + } else { + // remove tail from buffer + body = tail; + map_buffer[(int)floor(body->pos.y)] &= ~(1 << (int)floor(body->pos.x)); + + // move each snake piece to the next ones position + while (body->next) { + snake_t* next = body->next; + body->pos = next->pos; + body = next; + } + + move_head(body); + + // check for collision + if (map_buffer[(int)body->pos.y] & (1 << (int)body->pos.x)) { + new_game(); + return; + } + } + // add head to buffer + map_buffer[(int)floor(body->pos.y)] |= (1 << (int)floor(body->pos.x)); +} + +void init() +{ + // Construct new command buffer + cb = gs_command_buffer_new(); + + // Construct vertex buffer + vbo = gs_graphics_vertex_buffer_create(&(gs_graphics_vertex_buffer_desc_t) { + .data = v_data, + .size = sizeof(v_data) + }); + + // Construct index buffer + ibo = gs_graphics_index_buffer_create(&(gs_graphics_index_buffer_desc_t) { + .data = i_data, + .size = sizeof(i_data) + }); + + // shader sources + char* f_src = gs_platform_read_file_contents("frag.glsl", "r", NULL); + char* v_src = gs_platform_read_file_contents("vertex.glsl", "r", NULL); + + // Create shader + shader = gs_graphics_shader_create (&(gs_graphics_shader_desc_t) { + .sources = (gs_graphics_shader_source_desc_t[]){ + {.type = GS_GRAPHICS_SHADER_STAGE_VERTEX, .source = v_src}, + {.type = GS_GRAPHICS_SHADER_STAGE_FRAGMENT, .source = f_src} + }, + .size = 2 * sizeof(gs_graphics_shader_source_desc_t), + .name = "quad" + }); + + // Construct uniforms + + // Construct layout fields for sub elements of array + gs_graphics_uniform_layout_desc_t layout[32] = {0}; + for (uint32_t i = 0; i < 32; ++i) { + gs_snprintf(map_names[i], sizeof(map_names[i]), "[%d]", i); + layout[i].type = GS_GRAPHICS_UNIFORM_INT; + layout[i].fname = map_names[i]; + } + u_map = gs_graphics_uniform_create(&(gs_graphics_uniform_desc_t) { + .name = "u_map", + .layout = layout, + .layout_size = 32 * sizeof(gs_graphics_uniform_layout_desc_t) + }); + u_resolution = gs_graphics_uniform_create(&(gs_graphics_uniform_desc_t) { + .name = "u_resolution", + .layout = &(gs_graphics_uniform_layout_desc_t) { + .type = GS_GRAPHICS_UNIFORM_VEC2 + } + }); + u_food = gs_graphics_uniform_create(&(gs_graphics_uniform_desc_t) { + .name = "u_food", + .layout = &(gs_graphics_uniform_layout_desc_t) { + .type = GS_GRAPHICS_UNIFORM_VEC2 + } + }); + + // init pipeline + pip = gs_graphics_pipeline_create (&(gs_graphics_pipeline_desc_t) { + .raster = { + .shader = shader, + .index_buffer_element_size = sizeof(uint32_t) + }, + .layout = { + .attrs = (gs_graphics_vertex_attribute_desc_t[]){ + {.format = GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2, .name = "a_pos"}, + {.format = GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2, .name = "a_uv"} + }, + .size = 2 * sizeof(gs_graphics_vertex_attribute_desc_t) + } + }); + + // set random seed + srand((uint32_t)time(NULL)); + + // start game + new_game(); +} + +void update() +{ + // inputs + if (gs_platform_key_pressed(GS_KEYCODE_ESC)) gs_engine_quit(); + if (gs_platform_key_pressed(GS_KEYCODE_RIGHT) && prev_move.y != 0.0f) move = (gs_vec2){1.0f,0.0f}; + else if (gs_platform_key_pressed(GS_KEYCODE_LEFT) && prev_move.y != 0.0f) move = (gs_vec2){-1.0f,0.0f}; + else if (gs_platform_key_pressed(GS_KEYCODE_UP) && prev_move.x != 0.0f) move = (gs_vec2){0.0f,1.0f}; + else if (gs_platform_key_pressed(GS_KEYCODE_DOWN) && prev_move.x != 0.0f) move = (gs_vec2){0.0f,-1.0f}; + + // move snake every 0.2 seconds + uint32_t time_now = gs_platform_elapsed_time() * 0.01f; + if (time_now - prev_move_time >= 2) { + move_snake(); + prev_move_time = time_now; + } + + // set uniforms + gs_vec2 fbs = gs_platform_framebuffer_sizev(gs_platform_main_window()); + gs_graphics_bind_uniform_desc_t uniforms[] = { + (gs_graphics_bind_uniform_desc_t) {.uniform = u_map, .data = &map_buffer}, + (gs_graphics_bind_uniform_desc_t) {.uniform = u_resolution, .data = &fbs}, + (gs_graphics_bind_uniform_desc_t) {.uniform = u_food, .data = &food}, + }; + + // Bindings for all buffers: vertex, index, uniforms + gs_graphics_bind_desc_t binds = { + .vertex_buffers = {.desc = &(gs_graphics_bind_vertex_buffer_desc_t){.buffer = vbo}}, + .index_buffers = {.desc = &(gs_graphics_bind_index_buffer_desc_t){.buffer = ibo}}, + .uniforms = {.desc = uniforms, .size = sizeof(uniforms)} + }; + + /* Render */ + gs_graphics_begin_render_pass(&cb, GS_GRAPHICS_RENDER_PASS_DEFAULT); + gs_graphics_set_viewport(&cb, 0, 0, (int32_t)fbs.x, (int32_t)fbs.y); + gs_graphics_bind_pipeline(&cb, pip); + gs_graphics_apply_bindings(&cb, &binds); + gs_graphics_draw(&cb, &(gs_graphics_draw_desc_t){.start = 0, .count = 6}); + gs_graphics_end_render_pass(&cb); + + // Submit command buffer (syncs to GPU, MUST be done on main thread where you have your GPU context created) + gs_graphics_submit_command_buffer(&cb); +} + +gs_app_desc_t gs_main(int32_t argc, char** argv) +{ + return (gs_app_desc_t){ + .window_title = "Gunslinger Snake", + .init = init, + .update = update, + .shutdown = free_snake, + }; +} diff --git a/vertex.glsl b/vertex.glsl @@ -0,0 +1,12 @@ +#version 330 core +precision mediump float; + +layout(location = 0) in vec2 a_pos; +layout(location = 1) in vec2 a_uv; +out vec2 uv; + +void main() +{ + gl_Position = vec4(a_pos, 0.0, 1.0); + uv = a_uv; +}