diff options
-rw-r--r-- | resources/sprite/tile/horizontal_bar.png | bin | 118 -> 118 bytes | |||
-rw-r--r-- | src/view/MapView.cpp | 2 | ||||
-rw-r--r-- | src/view/SpriteCache.cpp | 83 | ||||
-rw-r--r-- | src/view/SpriteCache.hpp | 26 |
4 files changed, 95 insertions, 16 deletions
diff --git a/resources/sprite/tile/horizontal_bar.png b/resources/sprite/tile/horizontal_bar.png Binary files differindex 08f99de..c666b08 100644 --- a/resources/sprite/tile/horizontal_bar.png +++ b/resources/sprite/tile/horizontal_bar.png diff --git a/src/view/MapView.cpp b/src/view/MapView.cpp index d8a69d5..c1c0639 100644 --- a/src/view/MapView.cpp +++ b/src/view/MapView.cpp @@ -59,7 +59,7 @@ MapView::MapView(const std::shared_ptr<Window> &window0, const std::vector<std:: .h = 0, }; - SDL_Surface *sprite = spriteCache->get("tile", tileset[i]); + SDL_Surface *sprite = spriteCache->get("tile", tileset[i], 0); SDL_SetSurfaceBlendMode(sprite, SDL_BLENDMODE_NONE); SDL_BlitSurface(sprite, nullptr, surface, &rect); diff --git a/src/view/SpriteCache.cpp b/src/view/SpriteCache.cpp index 82f669f..bd67346 100644 --- a/src/view/SpriteCache.cpp +++ b/src/view/SpriteCache.cpp @@ -26,6 +26,8 @@ #include "SpriteCache.hpp" +#include <cstring> + #include <SDL_image.h> @@ -33,26 +35,89 @@ namespace RPGEdit { namespace View { -std::unique_ptr<SDL_Surface, SpriteCache::SDL_Surface_deleter> SpriteCache::load(const std::string &name) { - std::string filename = "../resources/sprite/" + name + ".png"; +SpriteCache::sprite_value SpriteCache::load(const std::string &id) { + std::string filename = "../resources/sprite/" + id + ".png"; SDL_Surface *surface = IMG_Load(filename.c_str()); - return std::unique_ptr<SDL_Surface, SDL_Surface_deleter>(surface, SDL_Surface_deleter()); + return sprite_value(surface, SDL_Surface_deleter()); +} + +SpriteCache::sprite_value SpriteCache::load(const std::string &id, unsigned rotation) { + if (!rotation) + return load(id); + + sprite_value &base = get(id, 0); + SDL_Surface *surface; + + SDL_LockSurface(base.get()); + + int w = base->w, h = base->h, d = base->format->BytesPerPixel, w2, h2; + + if (rotation == 2) { + w2 = w; + h2 = h; + } + else { + w2 = h; + h2 = w; + } + + surface = SDL_CreateRGBSurface(0, w2, h2, base->format->BitsPerPixel, + base->format->Rmask, base->format->Gmask, base->format->Bmask, base->format->Amask); + + SDL_LockSurface(surface); + + uint8_t *src = reinterpret_cast<uint8_t *>(base->pixels); + uint8_t *dst = reinterpret_cast<uint8_t *>(surface->pixels); + + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + int x2, y2; + + switch (rotation) { + case 1: + x2 = y; + y2 = w - x - 1; + break; + case 2: + x2 = w - x - 1; + y2 = h - y - 1; + break; + case 3: + x2 = h - y - 1; + y2 = x; + } + + std::memcpy(dst + d * (y2*w2 + x2), src + d * (y*w + x), d); + } + } + + SDL_UnlockSurface(surface); + SDL_UnlockSurface(base.get()); + + return sprite_value(surface, SDL_Surface_deleter()); } -SDL_Surface * SpriteCache::get(const std::string &type, const std::string &name) { - std::string id = type + "/" + name; +SpriteCache::sprite_value & SpriteCache::get(const std::string &id, unsigned rotation) { + sprite_key key(id, rotation); - std::unique_ptr<SDL_Surface, SDL_Surface_deleter> &surface = sprites[id]; + sprite_value &surface = sprites[key]; if (!surface) - surface = load(id); + surface = load(id, rotation); if (!surface) - sprites.erase(sprites.find(id)); + sprites.erase(sprites.find(key)); + + return surface; +} + +SDL_Surface * SpriteCache::get(const std::string &type, const std::string &name, unsigned rotation) { + if (rotation >= 4) + return nullptr; - return surface.get(); + return get(type + "/" + name, rotation).get(); } diff --git a/src/view/SpriteCache.hpp b/src/view/SpriteCache.hpp index c08ba6f..ae01887 100644 --- a/src/view/SpriteCache.hpp +++ b/src/view/SpriteCache.hpp @@ -27,6 +27,7 @@ #pragma once #include <memory> +#include <string> #include <unordered_map> #include <SDL.h> @@ -38,19 +39,32 @@ namespace View { class SpriteCache { private: - class SDL_Surface_deleter { - public: - void operator()(SDL_Surface *surface) { + struct SDL_Surface_deleter { + void operator()(SDL_Surface *surface) const { SDL_FreeSurface(surface); } }; - std::unordered_map<std::string, std::unique_ptr<SDL_Surface, SDL_Surface_deleter>> sprites; + typedef std::pair<std::string, int> sprite_key; + typedef std::unique_ptr<SDL_Surface, SDL_Surface_deleter> sprite_value; - std::unique_ptr<SDL_Surface, SDL_Surface_deleter> load(const std::string &name); + struct sprite_key_hash { + size_t operator()(const sprite_key &k) const { + std::hash<std::string> string_hash; + std::hash<int> int_hash; + + return string_hash(k.first) ^ int_hash(k.second); + } + }; + + std::unordered_map<sprite_key, sprite_value, sprite_key_hash> sprites; + + sprite_value load(const std::string &id); + sprite_value load(const std::string &id, unsigned rotation); + sprite_value & get(const std::string &id, unsigned rotation); public: - SDL_Surface * get(const std::string &type, const std::string &name); + SDL_Surface * get(const std::string &type, const std::string &name, unsigned rotation = 0); void clear() { sprites.clear(); |