commit a8ebdcefbb5184cf9d824993faf835fb9285731c
Author: Samdal <samdal@protonmail.com>
Date: Tue, 6 Jul 2021 03:01:21 +0200
initial commit
Diffstat:
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;
+}