snake

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

main.c (8987B)


      1 #define GS_IMPL
      2 #include <gs/gs.h>
      3 
      4 // Vertex data
      5 float v_data[] = {
      6     -1.0f, -1.0f,  0.0f, 0.0f,  // Top Left
      7      1.0f, -1.0f,  1.0f, 0.0f,  // Top Right
      8     -1.0f,  1.0f,  0.0f, 1.0f,  // Bottom Left
      9      1.0f,  1.0f,  1.0f, 1.0f   // Bottom Right
     10 };
     11 // Index data for quad
     12 uint32_t i_data[] = {
     13     0, 3, 2,    // First Triangle
     14     0, 1, 3     // Second Triangle
     15 };
     16 
     17 gs_command_buffer_t                      cb      = {0};
     18 gs_handle(gs_graphics_vertex_buffer_t)   vbo     = {0};
     19 gs_handle(gs_graphics_index_buffer_t)    ibo     = {0};
     20 gs_handle(gs_graphics_pipeline_t)        pip     = {0};
     21 gs_handle(gs_graphics_shader_t)          shader  = {0};
     22 gs_handle(gs_graphics_uniform_t)         u_resolution = {0};
     23 gs_handle(gs_graphics_uniform_t)         u_food   = {0};
     24 gs_handle(gs_graphics_uniform_t)         u_map   = {0};
     25 
     26 char map_names[32][32] = {0};
     27 uint32_t map_buffer[32] = {0};
     28 typedef union {
     29         int32_t xy[2];
     30         struct {
     31                 int32_t x, y;
     32         };
     33 } ivec;
     34 
     35 ivec snake[32 * 32] = {0};
     36 uint32_t head = 3;
     37 
     38 gs_vec2 food = {16.0f, 16.0f};
     39 
     40 ivec prev_move = {0};
     41 ivec move = {0};
     42 uint32_t prev_move_time = 0;
     43 
     44 void new_game()
     45 {
     46         // reinitialise buffers
     47         for (uint32_t i = 0; i < 32; i++)
     48                 map_buffer[i] = 0;
     49         for (uint32_t i = 0; i < 32 * 32; i++)
     50                 snake[i] = (ivec){0};
     51         prev_move_time = gs_platform_elapsed_time() * 0.01f;
     52         move = (ivec){1, 0};
     53         prev_move = move;
     54         head = 3;
     55 
     56         // place snake in map_buffer
     57         for (uint32_t i = 0; i <= 3; i++) {
     58                 snake[i] = (ivec){16+i,16};
     59                 map_buffer[snake[i].y] |= (1 << snake[i].x);
     60         }
     61 
     62         // place food at random position
     63         do {
     64                 food = (gs_vec2){rand() % 32, rand() % 32};
     65         } while (map_buffer[(int)food.y] & (1 << (int)food.x));
     66 }
     67 
     68 void move_snake()
     69 {
     70         prev_move = move;
     71         ivec new_pos = {snake[head].x + move.x, snake[head].y + move.y};
     72 
     73         // wrap snake
     74         if (new_pos.x > 31)      new_pos.x = 0;
     75         else if (new_pos.x < 0)  new_pos.x = 31;
     76         else if (new_pos.y > 31) new_pos.y = 0;
     77         else if (new_pos.y < 0)  new_pos.y = 31;
     78 
     79         // if new pos is food
     80         if (new_pos.x == (int)food.x && new_pos.y == (int)food.y) {
     81                 // add head to buffer
     82                 head++;
     83                 snake[head] = new_pos;
     84                 map_buffer[new_pos.y] |= (1 << new_pos.x);
     85 
     86                 // place food in a random place
     87                 do {
     88                         food = (gs_vec2){rand() % 32, rand() % 32};
     89                 } while (map_buffer[(int)food.y] & (1 << (int)food.x));
     90 
     91         } else {
     92                 // remove tail from buffer
     93                 map_buffer[snake[0].y] &= ~(1 << snake[0].x);
     94 
     95                 // move each snake piece to the next ones position
     96                 for (uint32_t i = 0; i < head; i++)
     97                         snake[i] = snake[i+1];
     98 
     99                 // check for collision
    100                 if (map_buffer[new_pos.y] & (1 << new_pos.x)) {
    101                         new_game();
    102                         return;
    103                 }
    104                 // add head to buffer
    105                 snake[head] = new_pos;
    106                 map_buffer[snake[head].y] |= (1 << snake[head].x);
    107         }
    108 }
    109 
    110 void init()
    111 {
    112         // Construct new command buffer
    113         cb = gs_command_buffer_new();
    114 
    115         // Construct vertex buffer
    116         vbo = gs_graphics_vertex_buffer_create(&(gs_graphics_vertex_buffer_desc_t) {
    117                 .data = v_data,
    118                 .size = sizeof(v_data)
    119         });
    120 
    121         // Construct index buffer
    122         ibo = gs_graphics_index_buffer_create(&(gs_graphics_index_buffer_desc_t) {
    123                 .data = i_data,
    124                 .size = sizeof(i_data)
    125         });
    126 
    127         // shader sources
    128         char* f_src = gs_platform_read_file_contents("./source/frag.glsl", "r", NULL);
    129         char* v_src = gs_platform_read_file_contents("./source/vertex.glsl", "r", NULL);
    130 
    131         // Create shader
    132         shader = gs_graphics_shader_create (&(gs_graphics_shader_desc_t) {
    133                 .sources = (gs_graphics_shader_source_desc_t[]){
    134                         {.type = GS_GRAPHICS_SHADER_STAGE_VERTEX, .source = v_src},
    135                         {.type = GS_GRAPHICS_SHADER_STAGE_FRAGMENT, .source = f_src}
    136                 },
    137                 .size = 2 * sizeof(gs_graphics_shader_source_desc_t),
    138                 .name = "quad"
    139         });
    140 
    141         // Construct uniforms
    142 
    143         // Construct layout fields for sub elements of array
    144         gs_graphics_uniform_layout_desc_t layout[32] = {0};
    145         for (uint32_t i = 0; i < 32; ++i) {
    146                 gs_snprintf(map_names[i], sizeof(map_names[i]), "[%d]", i);
    147                 layout[i].type = GS_GRAPHICS_UNIFORM_INT;
    148                 layout[i].fname = map_names[i];
    149         }
    150         u_map = gs_graphics_uniform_create(&(gs_graphics_uniform_desc_t) {
    151                 .name = "u_map",
    152                 .layout = layout,
    153                 .layout_size = 32 * sizeof(gs_graphics_uniform_layout_desc_t)
    154         });
    155         u_resolution = gs_graphics_uniform_create(&(gs_graphics_uniform_desc_t) {
    156                 .name = "u_resolution",
    157                 .layout = &(gs_graphics_uniform_layout_desc_t) {
    158                         .type = GS_GRAPHICS_UNIFORM_VEC2
    159                 }
    160         });
    161         u_food = gs_graphics_uniform_create(&(gs_graphics_uniform_desc_t) {
    162                 .name = "u_food",
    163                 .layout = &(gs_graphics_uniform_layout_desc_t) {
    164                         .type = GS_GRAPHICS_UNIFORM_VEC2
    165                 }
    166         });
    167 
    168         // init pipeline
    169         pip = gs_graphics_pipeline_create (&(gs_graphics_pipeline_desc_t) {
    170                 .raster = {
    171                         .shader = shader,
    172                         .index_buffer_element_size = sizeof(uint32_t)
    173                 },
    174                 .layout = {
    175                         .attrs = (gs_graphics_vertex_attribute_desc_t[]){
    176                                 {.format = GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2, .name = "a_pos"},
    177                                 {.format = GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2, .name = "a_uv"}
    178                         },
    179                         .size = 2 * sizeof(gs_graphics_vertex_attribute_desc_t)
    180                 }
    181         });
    182 
    183         // set random seed
    184         srand((uint32_t)time(NULL));
    185 
    186         // start game
    187         new_game();
    188 
    189         // Bindings for all buffers: vertex, index, uniforms
    190         gs_graphics_bind_desc_t binds = {
    191                 .vertex_buffers = {.desc = &(gs_graphics_bind_vertex_buffer_desc_t){.buffer = vbo}},
    192                 .index_buffers = {.desc = &(gs_graphics_bind_index_buffer_desc_t){.buffer = ibo}}
    193         };
    194 
    195         gs_graphics_begin_render_pass(&cb, GS_GRAPHICS_RENDER_PASS_DEFAULT);
    196         gs_graphics_bind_pipeline(&cb, pip);
    197         gs_graphics_apply_bindings(&cb, &binds);
    198 }
    199 
    200 void update()
    201 {
    202         // inputs
    203         if (gs_platform_key_pressed(GS_KEYCODE_ESC)) gs_engine_quit();
    204         else if (gs_platform_key_pressed(GS_KEYCODE_UP)   && prev_move.x != 0) move = (ivec){0,1};
    205         else if (gs_platform_key_pressed(GS_KEYCODE_DOWN) && prev_move.x != 0) move = (ivec){0,-1};
    206         else if (gs_platform_key_pressed(GS_KEYCODE_RIGHT)     && prev_move.y != 0) move = (ivec){1,0};
    207         else if (gs_platform_key_pressed(GS_KEYCODE_LEFT) && prev_move.y != 0) move = (ivec){-1,0};
    208 
    209         // move snake every 0.2 seconds
    210         const uint32_t time_now = gs_platform_elapsed_time() * 0.01f;
    211         const bool has_moved = time_now - prev_move_time >= 2;
    212         if (has_moved) {
    213                 move_snake();
    214                 prev_move_time = time_now;
    215         }
    216 
    217         // set uniforms
    218         gs_vec2 fbs = gs_platform_framebuffer_sizev(gs_platform_main_window());
    219         gs_graphics_bind_uniform_desc_t uniforms[] = {
    220                 (gs_graphics_bind_uniform_desc_t) {.uniform = u_map, .data = &map_buffer},
    221                 (gs_graphics_bind_uniform_desc_t) {.uniform = u_resolution, .data = &fbs},
    222                 (gs_graphics_bind_uniform_desc_t) {.uniform = u_food, .data = &food},
    223         };
    224 
    225         // Bindings for all buffers: vertex, index, uniforms
    226         gs_graphics_bind_desc_t binds = {
    227                 .uniforms = {.desc = uniforms, .size = sizeof(uniforms)}
    228         };
    229 
    230         /* Render */
    231         gs_graphics_set_viewport(&cb, 0, 0, (int32_t)fbs.x, (int32_t)fbs.y);
    232         if (has_moved)
    233                 gs_graphics_apply_bindings(&cb, &binds);
    234         gs_graphics_draw(&cb, &(gs_graphics_draw_desc_t){.start = 0, .count = 6});
    235 
    236         // Submit command buffer (syncs to GPU, MUST be done on main thread where you have your GPU context created)
    237         gs_graphics_submit_command_buffer(&cb);
    238 }
    239 
    240 gs_app_desc_t gs_main(int32_t argc, char** argv)
    241 {
    242         return (gs_app_desc_t){
    243                 .window_title = "Gunslinger Snake",
    244                 .init = init,
    245                 .update = update,
    246         };
    247 }