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.

assets.cc 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. #include "assets.h"
  2. #include <SDL.h>
  3. #include <SDL_image.h>
  4. #include <cpptoml.h>
  5. #include <string.h>
  6. namespace Swan {
  7. Result<ImageAsset> loadImageAsset(
  8. const std::unordered_map<std::string, std::string> modPaths,
  9. std::string path) {
  10. auto sep = path.find("::");
  11. if (sep == std::string::npos) {
  12. return {Err, "No '::' mod separator"};
  13. }
  14. auto modPart = path.substr(0, sep);
  15. auto pathPart = path.substr(sep + 2, path.size() - sep - 2);
  16. auto modPath = modPaths.find(modPart);
  17. if (modPath == modPaths.end()) {
  18. return {Err, "No mod named '" + modPart + '\''};
  19. }
  20. std::string assetPath = modPath->second + "/assets/" + pathPart;
  21. std::string pngPath = assetPath + ".png";
  22. std::string tomlPath = assetPath + ".toml";
  23. CPtr<SDL_Surface, SDL_FreeSurface> surface(IMG_Load(pngPath.c_str()));
  24. if (!surface) {
  25. return {Err, "Loading image " + pngPath + " failed: " + SDL_GetError()};
  26. }
  27. int frameHeight = surface->h;
  28. // Load TOML if it exists
  29. errno = ENOENT; // I don't know if ifstream is guaranteed to set errno
  30. std::ifstream tomlFile(tomlPath);
  31. if (tomlFile) {
  32. cpptoml::parser parser(tomlFile);
  33. try {
  34. auto toml = parser.parse();
  35. frameHeight = toml->get_as<int>("height").value_or(frameHeight);
  36. } catch (cpptoml::parse_exception &exc) {
  37. return {Err, "Failed to parse toml file " + tomlPath + ": " + exc.what()};
  38. }
  39. } else if (errno != ENOENT) {
  40. return {Err, "Couldn't open " + tomlPath + ": " + strerror(errno)};
  41. }
  42. ImageAsset asset{
  43. .width = surface->w,
  44. .frameHeight = frameHeight,
  45. .frameCount = surface->h / frameHeight,
  46. .data = std::make_unique<unsigned char[]>(surface->w * surface->h * 4),
  47. };
  48. // TODO: Pixel formats?
  49. for (size_t y = 0; y < (size_t)surface->h; ++y) {
  50. unsigned char *src = (unsigned char *)surface->pixels + y * surface->pitch;
  51. unsigned char *dest = asset.data.get() + y * surface->w * 4;
  52. memcpy(dest, src, surface->w * 4);
  53. }
  54. return {Ok, std::move(asset)};
  55. }
  56. }