#include #include // don't use sdl's redefinition of main #define SDL_MAIN_HANDLED #include "sdl/include/SDL.h" #include "device/device.h" #include "game/game.h" void sdl_host_suggest_dimensions(uint32_t* window_w, uint32_t* window_h); void sdl_host_loop(); void sdl_host_handle_keyboard_event(SDL_KeyboardEvent event); SDL_Window* sdl_host_window; SDL_Renderer* sdl_host_renderer; SDL_Texture* sdl_host_target; int main(int argc, char** argv) { int result = 0; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) { printf("could not initialize SDL! sdl error: %s\n", SDL_GetError()); result = 1; goto sdl_done; } uint32_t window_w, window_h; sdl_host_suggest_dimensions(&window_w, &window_h); // create window sdl_host_window = SDL_CreateWindow( game_title(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int) window_w, (int) window_h, SDL_WINDOW_SHOWN ); if (sdl_host_window == NULL) { printf("could not create window! sdl error: %s\n", SDL_GetError()); result = 1; goto window_done; } // create renderer sdl_host_renderer = SDL_CreateRenderer(sdl_host_window, -1, 0); if (sdl_host_renderer == NULL) { printf("could not create renderer! sdl error: %s\n", SDL_GetError()); result = 1; goto renderer_done; } // create target sdl_host_target = SDL_CreateTexture( sdl_host_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, DEVICE_W, DEVICE_H ); if (sdl_host_target == NULL) { printf("could not create target texture! sdl error: %s\n", SDL_GetError()); result = 1; goto target_done; } sdl_host_loop(); // renderer_cleanup: SDL_DestroyRenderer(sdl_host_renderer); sdl_host_renderer = NULL; renderer_done: ; // target_cleanup: SDL_DestroyTexture(sdl_host_target); sdl_host_target = NULL; target_done: ; // window_cleanup: SDL_DestroyWindow(sdl_host_window); sdl_host_window = NULL; window_done: ; // sdl_cleanup: SDL_Quit(); sdl_done: ; return result; } void sdl_host_suggest_dimensions(uint32_t* window_w, uint32_t* window_h) { SDL_DisplayMode dm; if (SDL_GetCurrentDisplayMode(0, &dm) != 0) { printf("could not get current display mode: %s\n", SDL_GetError()); dm.w = 0; dm.h = 0; } for (int scalar = 5; scalar >= 1; scalar--) { uint32_t w = DEVICE_W * scalar; uint32_t h = DEVICE_H * scalar; if (w <= dm.w && h <= dm.h) { *window_w = w; *window_h = h; return; } } for (int scalar = 1; scalar <= 5; scalar++) { uint32_t w = DEVICE_W / scalar; uint32_t h = DEVICE_H / scalar; if (w <= dm.w && h <= dm.h) { *window_w = w; *window_h = h; return; } } *window_w = DEVICE_W; *window_h = DEVICE_H; } void sdl_host_loop() { uint32_t ticks_per_frame = 1000/60; uint32_t real_pixels[DEVICE_H][DEVICE_W]; game_init(); while (true) { uint32_t frame_start = SDL_GetTicks(); uint32_t next_frame_start = frame_start + ticks_per_frame; SDL_Event e; while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { goto quit; } if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP) { sdl_host_handle_keyboard_event(e.key); } } // trigger game logic game_update(); game_draw(); for (int x = 0; x < DEVICE_W; x++) { for (int y = 0; y < DEVICE_H; y++) { real_pixels[y][x] = device_palette[device_pixels[y][x]]; } } SDL_UpdateTexture(sdl_host_target, NULL, &real_pixels, sizeof(real_pixels[0])); SDL_RenderClear(sdl_host_renderer); SDL_RenderCopy(sdl_host_renderer, sdl_host_target, NULL, NULL); SDL_RenderPresent(sdl_host_renderer); // hold off until next frame while (SDL_GetTicks() < next_frame_start) { SDL_Delay(1); } } quit: ; } void sdl_host_handle_keyboard_event(SDL_KeyboardEvent event) { bool is_down; switch (event.type) { case SDL_KEYDOWN: is_down = true; break; case SDL_KEYUP: is_down = false; break; default: return; } if (event.repeat) { return; } DeviceButton db; switch (event.keysym.sym) { case SDLK_LEFT: db = DEVICE_BUTTON_L; break; case SDLK_RIGHT: db = DEVICE_BUTTON_R; break; case SDLK_UP: db = DEVICE_BUTTON_U; break; case SDLK_DOWN: db = DEVICE_BUTTON_D; break; case SDLK_z: db = DEVICE_BUTTON_0; break; case SDLK_x: db = DEVICE_BUTTON_1; break; case SDLK_c: db = DEVICE_BUTTON_2; break; case SDLK_v: db = DEVICE_BUTTON_3; break; default: return; } device_buttons[db] = is_down; }