2D Run-and-gun shooter inspired by One Man's Doomsday, Counter-Strike, and Metal Slug.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

144 lines
4.2 KiB

  1. #include "IZ_video.h"
  2. bool IZ_VideoIsValidWidth(u16 width) {
  3. // TODO check screen size
  4. return (320 <= width && width <= 16384);
  5. }
  6. bool IZ_VideoIsValidHeight(u16 height) {
  7. // TODO check screen size
  8. return (240 <= height && height <= 8192);
  9. }
  10. bool IZ_VideoIsValidMaxFPS(u8 max_fps) {
  11. return (10 <= max_fps && max_fps <= 200);
  12. }
  13. static IZ_ConfigItem video_config_items[] = {
  14. {
  15. IZ_CONFIG_TYPE_U16,
  16. sizeof(u16),
  17. "Video",
  18. "Width",
  19. NULL,
  20. &IZ_VIDEO_DEFAULT_STATE.config.width,
  21. IZ_VideoIsValidWidth,
  22. },
  23. {
  24. IZ_CONFIG_TYPE_U16,
  25. sizeof(u16),
  26. "Video",
  27. "Height",
  28. NULL,
  29. &IZ_VIDEO_DEFAULT_STATE.config.height,
  30. IZ_VideoIsValidHeight,
  31. },
  32. {
  33. IZ_CONFIG_TYPE_U8,
  34. sizeof(u8),
  35. "Video",
  36. "MaxFps",
  37. "-f",
  38. &IZ_VIDEO_DEFAULT_STATE.config.max_fps,
  39. IZ_VideoIsValidMaxFPS,
  40. },
  41. IZ_CONFIG_ITEM_NULL,
  42. };
  43. void IZ_VideoBindStateToConfig(IZ_VideoState* state, IZ_ConfigItem config_items[]) {
  44. config_items[0].dest = &state->config.width;
  45. config_items[1].dest = &state->config.height;
  46. config_items[2].dest = &state->config.max_fps;
  47. }
  48. IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState* state, const char* config_path) {
  49. IZ_VideoBindStateToConfig(state, video_config_items);
  50. return IZ_ConfigSave(video_config_items, config_path);
  51. }
  52. IZ_ProcedureResult IZ_VideoInitializeConfig(IZ_VideoState* state, const char* config_path, u8 argc, const char* argv[]) {
  53. IZ_VideoBindStateToConfig(state, video_config_items);
  54. if (IZ_ConfigInitialize(video_config_items, config_path, argc, argv) < 0) {
  55. return -1;
  56. }
  57. return 0;
  58. }
  59. IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, const char* config_path, u8 argc, const char* argv[]) {
  60. SDL_memcpy(state, &IZ_VIDEO_DEFAULT_STATE, sizeof(IZ_VideoState));
  61. memset(state->active_sprites, 0, sizeof(IZ_SpriteSlot) * MAX_ACTIVE_SPRITES);
  62. if (IZ_VideoInitializeConfig(state, config_path, argc, argv) < 0) {
  63. return -2;
  64. }
  65. state->last_update_at = 0u;
  66. state->user_data = user_data;
  67. SDL_Window* window = SDL_CreateWindow(
  68. IZ_APP_NAME,
  69. SDL_WINDOWPOS_CENTERED,
  70. SDL_WINDOWPOS_CENTERED,
  71. state->config.width,
  72. state->config.height,
  73. SDL_WINDOW_SHOWN
  74. );
  75. if (window == NULL) {
  76. // fprintf_s(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError());
  77. return -3;
  78. }
  79. state->window = window;
  80. state->renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
  81. return 0;
  82. }
  83. void IZ_VideoTeardown(IZ_VideoState* state) {
  84. for (u16 i = 0; i < MAX_ACTIVE_SPRITES; i += 1) {
  85. if (state->active_sprites[i].sprite.texture) {
  86. SDL_DestroyTexture(state->active_sprites[i].sprite.texture);
  87. state->active_sprites[i].sprite.texture = NULL;
  88. state->active_sprites[i].requested_at = 0;
  89. }
  90. }
  91. SDL_DestroyWindow(state->window);
  92. }
  93. // we can use IZ_Pool for memory management. Do we want to use a single pool or multiple ones?
  94. u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState* state, IZ_VideoSpritePriority priority) {
  95. // TODO:
  96. // 1. Run through all sprites in the active sprites array
  97. // 2. Check each sprite's priority and requested_at (for eviction policy)
  98. // 3. Return that new slot. (prefer returning empty slots)
  99. // 4. Return MAX_ACTIVE_SPRITES if there's no slot left)
  100. for (u16 i = 0; i < MAX_ACTIVE_SPRITES; i += 1) {
  101. if (!state->active_sprites[i].sprite.texture) {
  102. return i;
  103. }
  104. }
  105. return MAX_ACTIVE_SPRITES;
  106. }
  107. void IZ_VideoLoadSprite(IZ_VideoState* state, IZ_VideoLoadSpriteParams params, IZ_SpriteSlot* out) {
  108. char full_path[2048];
  109. sprintf(full_path, "%s/%s", params.dir, params.filename);
  110. FILE* f = fopen(full_path, "r");
  111. u32 sprite_length_bytes = ini_getl(params.dir, params.filename, 0, "assets.ini");
  112. u8* sprite = malloc(sprite_length_bytes + 1);
  113. fread(sprite, 1, sprite_length_bytes, f);
  114. SDL_SetRenderDrawBlendMode(state->renderer, SDL_BLENDMODE_BLEND);
  115. SDL_Surface* test_surface = IMG_LoadSVG_RW(SDL_RWFromConstMem(sprite, sprite_length_bytes));
  116. free(sprite);
  117. if (test_surface) {
  118. out->sprite.texture = SDL_CreateTextureFromSurface(state->renderer, test_surface);
  119. out->sprite.original_width = test_surface->w;
  120. out->sprite.original_height = test_surface->h;
  121. out->sprite.scale_factor = 1;
  122. out->sprite.rotate_degrees = 0;
  123. out->sprite.position = (IZ_Vector2D) { 0, 0 };
  124. out->sprite.flip_x = false;
  125. out->sprite.flip_y = false;
  126. SDL_FreeSurface(test_surface);
  127. }
  128. }