star-sim

Barnes-Hut gravity simulation.
git clone git://git.amin.space/star-sim.git
Log | Files | Refs | README | LICENSE

platform_sdl.c (9363B)


      1 #include "platform_sdl.h"
      2 
      3 #include "sim.h"
      4 
      5 #include <stdbool.h>
      6 #include <stdio.h>
      7 #include <string.h>
      8 
      9 #ifndef MAP_ANONYMOUS
     10 #define MAP_ANONYMOUS MAP_ANON
     11 #endif
     12 
     13 extern bool PAUSED;
     14 extern bool BRUTE_FORCE;
     15 extern bool RENDER_GRID;
     16 extern bool RENDER_BOUNDING_BOX;
     17 extern bool RENDER_TRAILS;
     18 
     19 static struct SDLOffscreenBuffer global_back_buffer;
     20 
     21 
     22 struct SDLWindowDimension sdl_get_window_dimension(SDL_Window *window)
     23 {
     24     struct SDLWindowDimension result;
     25     SDL_GetWindowSize(window, &result.width, &result.height);
     26     return(result);
     27 }
     28 
     29 
     30 void sdl_resize_texture(struct SDLOffscreenBuffer *buffer, SDL_Renderer *renderer, int width, int height)
     31 {
     32     if (buffer->memory)
     33     {
     34         free(buffer->memory);
     35     }
     36 
     37     if (buffer->texture)
     38     {
     39         SDL_DestroyTexture(buffer->texture);
     40     }
     41 
     42     buffer->texture = SDL_CreateTexture(
     43             renderer,
     44             SDL_PIXELFORMAT_ARGB8888,
     45             SDL_TEXTUREACCESS_STREAMING,
     46             width, height);
     47 
     48     buffer->width = width;
     49     buffer->height = height;
     50     buffer->pitch = width * BYTES_PER_PIXEL;
     51 
     52     buffer->memory = malloc(width * height * BYTES_PER_PIXEL);
     53 }
     54 
     55 
     56 void sdl_update_window(SDL_Renderer *renderer, struct SDLOffscreenBuffer *buffer)
     57 {
     58     if (SDL_UpdateTexture(buffer->texture, 0, buffer->memory, buffer->pitch))
     59     {
     60         // TODO(amin): Handle this error
     61     }
     62 
     63     SDL_RenderCopy(renderer, buffer->texture, 0, 0);
     64     SDL_RenderPresent(renderer);
     65 }
     66 
     67 
     68 void clear_screen(struct SDLOffscreenBuffer *buffer, uint32_t pixel_value)
     69 {
     70     // NOTE(amin): Memset is faster than nested for loops, but can only set
     71     // pixels to single byte values
     72     memset(buffer->memory, pixel_value, buffer->height * buffer->width * BYTES_PER_PIXEL);
     73 }
     74 
     75 
     76 bool handle_event(SDL_Event *event)
     77 {
     78     bool should_quit = false;
     79 
     80     switch(event->type)
     81     {
     82         case SDL_QUIT:
     83         {
     84             printf("SDL_QUIT\n");
     85             should_quit = true;
     86         } break;
     87 
     88         case SDL_KEYDOWN:
     89         case SDL_KEYUP:
     90         {
     91             SDL_Keycode key_code = event->key.keysym.sym;
     92             bool is_down = (event->key.state == SDL_PRESSED);
     93             if (is_down)
     94             {
     95                 if (key_code == SDLK_b)
     96                 {
     97                     RENDER_BOUNDING_BOX = !RENDER_BOUNDING_BOX;
     98                 }
     99                 if (key_code == SDLK_f)
    100                 {
    101                     BRUTE_FORCE = !BRUTE_FORCE;
    102                 }
    103                 if (key_code == SDLK_g)
    104                 {
    105                     RENDER_GRID = !RENDER_GRID;
    106                 }
    107                 if (key_code == SDLK_p)
    108                 {
    109                     PAUSED = !PAUSED;
    110                 }
    111                 if (key_code == SDLK_t)
    112                 {
    113                     RENDER_TRAILS = !RENDER_TRAILS;
    114                     clear_screen(&global_back_buffer, COLOR_BACKGROUND);
    115                 }
    116             }
    117         } break;
    118         case SDL_WINDOWEVENT:
    119         {
    120             switch(event->window.event)
    121             {
    122                 case SDL_WINDOWEVENT_SIZE_CHANGED:
    123                 {
    124                     SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
    125                     SDL_Renderer *renderer = SDL_GetRenderer(window);
    126                     printf("SDL_WINDOWEVENT_SIZE_CHANGED (%d, %d)\n", event->window.data1, event->window.data2);
    127                     sdl_resize_texture(&global_back_buffer, renderer, event->window.data1, event->window.data2);
    128                 } break;
    129 
    130                 case SDL_WINDOWEVENT_FOCUS_GAINED:
    131                 {
    132                     printf("SDL_WINDOWEVENT_FOCUS_GAINED\n");
    133                 } break;
    134 
    135                 case SDL_WINDOWEVENT_EXPOSED:
    136                 {
    137                     SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
    138                     SDL_Renderer *renderer = SDL_GetRenderer(window);
    139                     sdl_update_window(renderer, &global_back_buffer);
    140                 } break;
    141             }
    142         } break;
    143     }
    144     return(should_quit);
    145 }
    146 
    147 
    148 int main(int argc, char *argv[])
    149 {
    150     if (SDL_Init(SDL_INIT_VIDEO))
    151     {
    152         // TODO(amin): log SDL_Init error
    153     }
    154 
    155     SDL_Window *window = SDL_CreateWindow(
    156             TITLE,
    157             SDL_WINDOWPOS_UNDEFINED,
    158             SDL_WINDOWPOS_UNDEFINED,
    159             SCREEN_WIDTH,
    160             SCREEN_HEIGHT,
    161             SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
    162 
    163 #ifdef FULLSCREEN
    164     SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
    165 #endif
    166 
    167     if (window)
    168     {
    169         SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
    170 
    171         if (renderer)
    172         {
    173             struct SDLWindowDimension dimension = sdl_get_window_dimension(window);
    174             sdl_resize_texture(&global_back_buffer, renderer, dimension.width, dimension.height);
    175 
    176             bool running = true;
    177 
    178 #ifdef USE_TEST_SEED
    179             srand((uint32_t)0);
    180 #else
    181             srand((uint32_t)time(NULL));
    182 #endif
    183 
    184             uint64_t lag = 0;
    185             uint64_t previous_ms = (SDL_GetPerformanceCounter() * SECOND) / SDL_GetPerformanceFrequency();
    186 
    187             struct SimState sim_state;
    188             sim_init(&sim_state, dimension.width, dimension.height);
    189 
    190             while (running)
    191             {
    192                 uint64_t current_ms = (SDL_GetPerformanceCounter() * SECOND) / SDL_GetPerformanceFrequency();
    193                 uint64_t elapsed_ms = current_ms - previous_ms;
    194                 previous_ms = current_ms;
    195                 lag += elapsed_ms;
    196                 //printf("%" PRIu64 ", %" PRIu64 ", %f\n", elapsed_ms, lag, MS_PER_UPDATE);
    197 
    198                 SDL_Event event;
    199 
    200                 while (SDL_PollEvent(&event))
    201                 {
    202                     running = !handle_event(&event);
    203                 }
    204 
    205                 SDL_PumpEvents();
    206 
    207                 dimension = sdl_get_window_dimension(window);
    208 
    209                 const uint8_t *keystate = SDL_GetKeyboardState(0);
    210 
    211                 // TODO: move this to a function
    212                 if (keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_H])
    213                 {
    214                     sim_state.view.dx += 5 / sim_state.view.zoom;
    215                 }
    216                 if (keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_L])
    217                 {
    218                     sim_state.view.dx -= 5 / sim_state.view.zoom;
    219                 }
    220                 if (keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_K])
    221                 {
    222                     sim_state.view.dy += 5 / sim_state.view.zoom;
    223                 }
    224                 if (keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_J])
    225                 {
    226                     sim_state.view.dy -= 5 / sim_state.view.zoom;
    227                 }
    228                 if (keystate[SDL_SCANCODE_LEFT])
    229                 {
    230                     sim_state.view.dx += 1 / sim_state.view.zoom;
    231                 }
    232                 if (keystate[SDL_SCANCODE_RIGHT])
    233                 {
    234                     sim_state.view.dx -= 1 / sim_state.view.zoom;
    235                 }
    236                 if (keystate[SDL_SCANCODE_UP])
    237                 {
    238                     sim_state.view.dy += 1 / sim_state.view.zoom;
    239                 }
    240                 if (keystate[SDL_SCANCODE_DOWN])
    241                 {
    242                     sim_state.view.dy -= 1 / sim_state.view.zoom;
    243                 }
    244                 if (keystate[SDL_SCANCODE_EQUALS])
    245                 {
    246                     sim_state.view.zoom *= 1.01;
    247                 }
    248                 if (keystate[SDL_SCANCODE_MINUS])
    249                 {
    250                     sim_state.view.zoom *= 0.99;
    251                 }
    252                 if (keystate[SDL_SCANCODE_0])
    253                 {
    254                     sim_state.view.zoom = 1;
    255                 }
    256                 if (keystate[SDL_SCANCODE_HOME])
    257                 {
    258                     sim_state.view.dx = 0;
    259                     sim_state.view.dy = 0;
    260                     sim_state.view.zoom = 1;
    261                 }
    262 
    263                 struct OffscreenBuffer buffer;
    264                 // WARNING: these pointers are aliased until the end of the
    265                 // loop
    266                 buffer.memory = global_back_buffer.memory;
    267                 buffer.width = global_back_buffer.width;
    268                 buffer.height = global_back_buffer.height;
    269                 buffer.pitch = global_back_buffer.pitch;
    270 
    271                 if (PAUSED)
    272                 {
    273                     lag = 0;
    274                 }
    275                 else
    276                 {
    277                     while (lag >= MS_PER_UPDATE)
    278                     {
    279                         sim_update(&sim_state, buffer.width, buffer.height);
    280                         //printf("\t%" PRIu64 ", %f\n", lag, MS_PER_UPDATE);
    281                         lag -= MS_PER_UPDATE;
    282                     }
    283                 }
    284 
    285                 if (!RENDER_TRAILS)
    286                 {
    287                     clear_screen(&global_back_buffer, COLOR_BACKGROUND);
    288                 }
    289 
    290                 sim_render(&buffer, lag/SECOND, &sim_state);
    291                 sdl_update_window(renderer, &global_back_buffer);
    292                 if (elapsed_ms <= MS_PER_FRAME)
    293                 {
    294                     SDL_Delay(MS_PER_FRAME - elapsed_ms);
    295                 }
    296             }
    297 
    298             sim_cleanup(&sim_state);
    299         }
    300         else
    301         {
    302             // TODO(amin): log SDL_Renderer error
    303         }
    304     }
    305     else
    306     {
    307         // TODO(amin): log SDL_Window error
    308     }
    309 
    310     SDL_Quit();
    311     return(0);
    312 }