star-sim

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

platform_sdl.c (9343B)


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