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

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