A 2D tile-based sandbox game.
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.

Resource.cc 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "Resource.h"
  2. #include <stdio.h>
  3. #include <SDL2/SDL_image.h>
  4. #include <regex>
  5. #include <cpptoml.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include "log.h"
  9. #include "common.h"
  10. #include "Win.h"
  11. namespace Swan {
  12. ImageResource::ImageResource(
  13. SDL_Renderer *renderer, const std::string &modpath, const std::string &id) {
  14. static std::regex first_part_re("^.*?/");
  15. SDL_RendererInfo rinfo;
  16. if (SDL_GetRendererInfo(renderer, &rinfo) < 0) {
  17. panic << "GetRendererInfo failed: " << SDL_GetError();
  18. abort();
  19. }
  20. uint32_t format = rinfo.texture_formats[0];
  21. int bpp = 32;
  22. uint32_t rmask, gmask, bmask, amask;
  23. if (SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask) < 0) {
  24. panic << "PixelFormatEnumToMasks failed: " << SDL_GetError();
  25. abort();
  26. }
  27. std::string assetpath = modpath + "/assets/" +
  28. std::regex_replace(id, first_part_re, "");
  29. surface_.reset(IMG_Load((assetpath + ".png").c_str()));
  30. // If we don't have a surface yet (either loading or conversion failed),
  31. // create a placeholder
  32. if (!surface_) {
  33. warn << "Loading image " << id << " failed: " << SDL_GetError();
  34. surface_.reset(SDL_CreateRGBSurface(
  35. 0, TILE_SIZE, TILE_SIZE, bpp, rmask, gmask, bmask, amask));
  36. SDL_FillRect(surface_.get(), NULL, SDL_MapRGB(surface_->format,
  37. PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE));
  38. }
  39. frame_height_ = 32;
  40. // Load TOML if it exists
  41. errno = ENOENT; // I don't know if ifstream is guaranteed to set errno
  42. std::ifstream tomlfile(assetpath + ".toml");
  43. if (tomlfile) {
  44. cpptoml::parser parser(tomlfile);
  45. try {
  46. auto toml = parser.parse();
  47. frame_height_ = toml->get_as<int>("height").value_or(frame_height_);
  48. } catch (cpptoml::parse_exception &exc) {
  49. warn << "Failed to parse toml file " << assetpath << ".toml: "
  50. << exc.what();
  51. }
  52. } else if (errno != ENOENT) {
  53. warn << "Couldn't open " << assetpath << ".toml: " << strerror(errno);
  54. }
  55. texture_.reset(SDL_CreateTextureFromSurface(renderer, surface_.get()));
  56. if (!texture_) {
  57. panic << "CreateTexture failed: " << SDL_GetError();
  58. abort();
  59. }
  60. num_frames_ = surface_->h / frame_height_;
  61. name_ = id;
  62. }
  63. ImageResource::ImageResource(
  64. SDL_Renderer *renderer, const std::string &name,
  65. int w, int h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
  66. surface_.reset(SDL_CreateRGBSurface(
  67. 0, TILE_SIZE, TILE_SIZE, 32,
  68. 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff));
  69. SDL_FillRect(surface_.get(), NULL, SDL_MapRGBA(surface_->format, r, g, b, a));
  70. texture_.reset(SDL_CreateTextureFromSurface(renderer, surface_.get()));
  71. if (!texture_) {
  72. panic << "CreateTexture failed: " << SDL_GetError();
  73. abort();
  74. }
  75. frame_height_ = h;
  76. num_frames_ = 1;
  77. name_ = name;
  78. }
  79. void ImageResource::tick(float dt) {
  80. switch_timer_ -= dt;
  81. if (switch_timer_ <= 0) {
  82. switch_timer_ += switch_interval_;
  83. frame_ += 1;
  84. if (frame_ >= num_frames_)
  85. frame_ = 0;
  86. }
  87. }
  88. ResourceManager::ResourceManager(Win &win) {
  89. addImage(std::make_unique<ImageResource>(
  90. win.renderer_, "@::invalid", TILE_SIZE, TILE_SIZE,
  91. PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE));
  92. addImage(std::make_unique<ImageResource>(
  93. win.renderer_, "@::air", TILE_SIZE, TILE_SIZE,
  94. 0, 0, 0, 0));
  95. }
  96. void ResourceManager::tick(float dt) {
  97. for (auto &[k, v]: images_) {
  98. v->tick(dt);
  99. }
  100. }
  101. ImageResource &ResourceManager::getImage(const std::string &name) const {
  102. auto it = images_.find(name);
  103. if (it == end(images_)) {
  104. warn << "Couldn't find image " << name << "!";
  105. return getImage("@::invalid");
  106. }
  107. return *it->second;
  108. }
  109. }