diff options
author | Andrei Karas <akaras@inbox.ru> | 2012-08-13 22:18:03 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2012-09-30 02:57:13 +0300 |
commit | 135c19b4337e1ab45cff40a306eadc52a061ddef (patch) | |
tree | 0a163ca1edd542aec5570b7e451034aafb4089dd /src/resources | |
parent | 3a2bab265768c219b0c077eef10b69dfe8158131 (diff) | |
download | mv-135c19b4337e1ab45cff40a306eadc52a061ddef.tar.gz mv-135c19b4337e1ab45cff40a306eadc52a061ddef.tar.bz2 mv-135c19b4337e1ab45cff40a306eadc52a061ddef.tar.xz mv-135c19b4337e1ab45cff40a306eadc52a061ddef.zip |
add atlas textures support.
Diffstat (limited to 'src/resources')
-rw-r--r-- | src/resources/atlasmanager.cpp | 302 | ||||
-rw-r--r-- | src/resources/atlasmanager.h | 104 | ||||
-rw-r--r-- | src/resources/image.h | 1 | ||||
-rw-r--r-- | src/resources/imagehelper.cpp | 3 | ||||
-rw-r--r-- | src/resources/imagehelper.h | 7 | ||||
-rw-r--r-- | src/resources/imageset.cpp | 10 | ||||
-rw-r--r-- | src/resources/mapdb.cpp | 13 | ||||
-rw-r--r-- | src/resources/mapdb.h | 5 | ||||
-rw-r--r-- | src/resources/mapreader.cpp | 12 | ||||
-rw-r--r-- | src/resources/openglimagehelper.cpp | 17 | ||||
-rw-r--r-- | src/resources/openglimagehelper.h | 7 | ||||
-rw-r--r-- | src/resources/resourcemanager.cpp | 28 | ||||
-rw-r--r-- | src/resources/resourcemanager.h | 2 | ||||
-rw-r--r-- | src/resources/sdlimagehelper.cpp | 2 | ||||
-rw-r--r-- | src/resources/sdlimagehelper.h | 2 |
15 files changed, 499 insertions, 16 deletions
diff --git a/src/resources/atlasmanager.cpp b/src/resources/atlasmanager.cpp new file mode 100644 index 000000000..770e43412 --- /dev/null +++ b/src/resources/atlasmanager.cpp @@ -0,0 +1,302 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "main.h" + +#ifdef USE_OPENGL + +#include "resources/atlasmanager.h" +#include "resources/openglimagehelper.h" + +#include "client.h" +#include "graphics.h" +#include "graphicsmanager.h" +#include "logger.h" + +#include "utils/mathutils.h" +#include "utils/physfsrwops.h" + +#include "resources/fboinfo.h" +#include "resources/imagehelper.h" +#include "resources/imagewriter.h" +#include "resources/resourcemanager.h" + +#include "debug.h" + +AtlasManager::AtlasManager() +{ +} + +AtlasResource *AtlasManager::loadTextureAtlas(const std::string &name, + const StringVect &files) +{ + std::vector<TextureAtlas*> atlases; + std::vector<Image*> images; + AtlasResource *resource = new AtlasResource; + + loadImages(files, images); + int maxSize = OpenGLImageHelper::getTextureSize(); +// int maxSize = 1024; + + // sorting images on atlases. + simpleSort(name, atlases, images, maxSize); + + int k = 0; + for (std::vector<TextureAtlas*>::iterator it = atlases.begin(), + it_end = atlases.end(); it != it_end; ++ it) + { + TextureAtlas *atlas = *it; + if (!atlas) + continue; + + // create atlas base on sorted images + SDL_Surface *surface = createSDLAtlas(atlas); + + if (!surface) + continue; + + // debug save + ImageWriter::writePNG(surface, Client::getTempDirectory() + + "/atlas" + name + toString(k) + ".png"); + k ++; + + // covert SDL images to OpenGL + convertAtlas(atlas); + + // free SDL atlas surface + SDL_FreeSurface(surface); + + resource->atlases.push_back(atlas); + } + + return resource; +} + +void AtlasManager::loadImages(const StringVect &files, + std::vector<Image*> &images) +{ + for (StringVectCIter it = files.begin(), it_end = files.end(); + it != it_end; ++ it) + { + const std::string str = *it; + SDL_RWops *rw = PHYSFSRWOPS_openRead(str.c_str()); + Image *image = sdlImageHelper->load(rw); + if (image) + { + image->mIdPath = str; + images.push_back(image); + } + } +} + +void AtlasManager::simpleSort(const std::string &name, + std::vector<TextureAtlas*> &atlases, + std::vector<Image*> &images, int size) +{ + int x = 0; + int y = 0; + int tempHeight = 0; + TextureAtlas *atlas = new TextureAtlas(); + std::vector<Image*>::iterator it = images.begin(); + const std::vector<Image*>::const_iterator it_end = images.end(); + for (it = images.begin(); it != it_end; ++ it) + { + Image *img = *it; + if (img) + { + atlas->name = "atlas_" + name + "_" + img->getIdPath(); + break; + } + } + + for (it = images.begin(); it != it_end; ++ it) + { + Image *img = *it; + if (img) + { + AtlasItem *item = new AtlasItem(img); + item->name = img->getIdPath(); + // start next line + if (x + img->mBounds.w > size) + { + x = 0; + y += tempHeight; + tempHeight = 0; + } + + // cant put image with this height + if (y + img->mBounds.h > size) + { + x = 0; + y = 0; + atlases.push_back(atlas); + atlas = new TextureAtlas(); + atlas->name = "atlas_" + name + "_" + img->getIdPath(); + } + + if (img->mBounds.h > tempHeight) + tempHeight = img->mBounds.h; + + logger->log("image draw position: %d,%d (%d,%d)", + x, y, img->mBounds.w, img->mBounds.h); + item->x = x; + item->y = y; + atlas->items.push_back(item); + + // continue put textures in line + x += img->mBounds.w; + if (x > atlas->width) + atlas->width = x; + if (y + img->mBounds.h > atlas->height) + atlas->height = y + img->mBounds.h; + } + } + if (!atlas->items.empty()) + atlases.push_back(atlas); + else + delete atlas; +} + +SDL_Surface *AtlasManager::createSDLAtlas(TextureAtlas *atlas) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + const int rmask = 0xff000000; + const int gmask = 0x00ff0000; + const int bmask = 0x0000ff00; + const int amask = 0x000000ff; +#else + const int rmask = 0x000000ff; + const int gmask = 0x0000ff00; + const int bmask = 0x00ff0000; + const int amask = 0xff000000; +#endif + + // do not create atlas based on only one image + if (atlas->items.size() == 1) + return nullptr; + + // using only power of two sizes. + atlas->width = powerOfTwo(atlas->width); + atlas->height = powerOfTwo(atlas->height); + + // temp SDL surface for atlas + SDL_Surface *surface = SDL_CreateRGBSurface(SDL_SWSURFACE, + atlas->width, atlas->height, 32, rmask, gmask, bmask, amask); + + if (!surface) + return nullptr; + + Graphics *graphics = new Graphics(); + graphics->setTarget(surface); + graphics->_beginDraw(); + + // drawing SDL images to surface + for (std::vector<AtlasItem*>::iterator it = atlas->items.begin(), + it_end = atlas->items.end(); + it != it_end; ++ it) + { + AtlasItem *item = *it; + Image *image = item->image; + + if (image) + { + SDL_SetAlpha(image->mSDLSurface, 0, SDL_ALPHA_OPAQUE); + graphics->drawImage(image, item->x, item->y); + } + } + + delete graphics; + atlas->surface = surface; + return surface; +} + +void AtlasManager::convertAtlas(TextureAtlas *atlas) +{ + // convert surface to OpemGL image + atlas->atlasImage = imageHelper->load(atlas->surface); + Image *const image = atlas->atlasImage; + + for (std::vector<AtlasItem*>::iterator it = atlas->items.begin(), + it_end = atlas->items.end(); + it != it_end; ++ it) + { + AtlasItem *const item = *it; + // delete SDL Image + delete item->image; + // store OpenGL image + item->image = image->getSubImage(item->x, item->y, + item->width, item->height); + } +} + +void AtlasManager::injectToResources(AtlasResource *resource) +{ + ResourceManager *const resman = ResourceManager::getInstance(); + int k = 0; + for (std::vector<TextureAtlas*>::iterator it = resource->atlases.begin(), + it_end = resource->atlases.end(); it != it_end; ++ it, k ++) + { + // add each atlas image to resources + TextureAtlas *const atlas = *it; + resman->addResource(atlas->name, atlas->atlasImage); + if (atlas) + { + for (std::vector<AtlasItem*>::iterator it2 = atlas->items.begin(), + it2_end = atlas->items.end(); + it2 != it2_end; ++ it2) + { + AtlasItem *const item = *it2; + // add each atlas sub image to resources + resman->addResource(item->name, item->image); + } + } + } +} + +AtlasResource::~AtlasResource() +{ + for (std::vector<TextureAtlas*>::iterator it = atlases.begin(), + it_end = atlases.end(); it != it_end; ++ it) + { + TextureAtlas *const atlas = *it; + if (atlas) + { + for (std::vector<AtlasItem*>::iterator it2 = atlas->items.begin(), + it2_end = atlas->items.end(); + it2 != it2_end; ++ it2) + { + AtlasItem *const item = *it2; + if (item) + { + Image *const image = item->image; + if (image) + image->decRef(); + delete item; + } + } + Image *const image = atlas->atlasImage; + if (image) + image->decRef(); + delete atlas; + } + } +} + +#endif diff --git a/src/resources/atlasmanager.h b/src/resources/atlasmanager.h new file mode 100644 index 000000000..41aae86e5 --- /dev/null +++ b/src/resources/atlasmanager.h @@ -0,0 +1,104 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ATLASMANAGER_H +#define ATLASMANAGER_H + +#ifdef USE_OPENGL + +#include "resources/image.h" + +#include "utils/stringvector.h" + +#include <SDL/SDL.h> + +class Resource; + +struct AtlasItem +{ + AtlasItem(Image *image0) : + image(image0), + x(0), + y(0), + width(image0->mBounds.w), + height(image0->mBounds.h) + { + } + + Image *image; + std::string name; + int x; + int y; + int width; + int height; +}; + +struct TextureAtlas +{ + TextureAtlas() : + atlasImage(nullptr), + surface(nullptr), + width(0), + height(0) + { + } + + std::string name; + Image *atlasImage; + SDL_Surface *surface; + int width; + int height; + std::vector <AtlasItem*> items; +}; + +class AtlasResource : public Resource +{ + public: + ~AtlasResource(); + + std::vector<TextureAtlas*> atlases; +}; + +class AtlasManager +{ + public: + AtlasManager(); + + static AtlasResource *loadTextureAtlas(const std::string &name, + const StringVect &files); + + static void injectToResources(AtlasResource *resource); + + private: + static void loadImages(const StringVect &files, + std::vector<Image*> &images); + + static void simpleSort(const std::string &name, + std::vector<TextureAtlas*> &atlases, + std::vector<Image*> &images, int size); + + static SDL_Surface *createSDLAtlas(TextureAtlas *atlas); + + + static void convertAtlas(TextureAtlas *atlas); +}; + +#endif +#endif diff --git a/src/resources/image.h b/src/resources/image.h index 11d3828fd..8fafc87aa 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -59,6 +59,7 @@ class Image : public Resource friend class OpenGLImageHelper; friend class SDLImageHelper; #ifdef USE_OPENGL + friend class AtlasManager; friend class NormalOpenGLGraphics; friend class SafeOpenGLGraphics; #endif diff --git a/src/resources/imagehelper.cpp b/src/resources/imagehelper.cpp index 7ddf3221a..d2d0a78ed 100644 --- a/src/resources/imagehelper.cpp +++ b/src/resources/imagehelper.cpp @@ -37,10 +37,11 @@ #include "debug.h" ImageHelper *imageHelper = nullptr; +ImageHelper *sdlImageHelper = nullptr; bool ImageHelper::mEnableAlpha = true; -Resource *ImageHelper::load(SDL_RWops *const rw) +Image *ImageHelper::load(SDL_RWops *const rw) { SDL_Surface *const tmpImage = IMG_Load_RW(rw, 1); diff --git a/src/resources/imagehelper.h b/src/resources/imagehelper.h index 27132b7d9..fdda3b00f 100644 --- a/src/resources/imagehelper.h +++ b/src/resources/imagehelper.h @@ -54,10 +54,10 @@ class ImageHelper * @return <code>NULL</code> if an error occurred, a valid pointer * otherwise. */ - Resource *load(SDL_RWops *const rw); + Image *load(SDL_RWops *const rw); #ifdef __GNUC__ - virtual Resource *load(SDL_RWops *rw, Dye const &dye) = 0; + virtual Image *load(SDL_RWops *rw, Dye const &dye) = 0; virtual Image *load(SDL_Surface *) = 0; @@ -66,7 +66,7 @@ class ImageHelper virtual int useOpenGL() = 0; #else - virtual Resource *load(SDL_RWops *rw, Dye const &dye) + virtual Image *load(SDL_RWops *rw, Dye const &dye) { return nullptr; } virtual Image *load(SDL_Surface *) @@ -92,4 +92,5 @@ class ImageHelper }; extern ImageHelper *imageHelper; +extern ImageHelper *sdlImageHelper; #endif diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp index 2e10f74a2..6876a7b14 100644 --- a/src/resources/imageset.cpp +++ b/src/resources/imageset.cpp @@ -55,6 +55,16 @@ ImageSet::ImageSet(Image *const img, const int width, const int height, ImageSet::~ImageSet() { delete_all(mImages); +/* + for (std::vector<Image*>::iterator it = mImages.begin(), + it_end = mImages.end(); it != it_end; ++ it) + { + Image *image = *it; + if (image) + image->decRef(); + } + mImages.clear(); +*/ } Image* ImageSet::get(const size_type i) const diff --git a/src/resources/mapdb.cpp b/src/resources/mapdb.cpp index 55c3d7306..2b2beed89 100644 --- a/src/resources/mapdb.cpp +++ b/src/resources/mapdb.cpp @@ -149,3 +149,16 @@ std::string MapDB::getMapName(const std::string &name) return it->second; return name; } + +MapDB::MapInfo *MapDB::getMapAtlas(const std::string &name) +{ + MapInfoIter it = mInfos.find(name); + if (it == mInfos.end()) + return nullptr; + MapInfo *const info = &(*it).second; + AtlasIter it2 = mAtlases.find(info->atlas); + if (it2 == mAtlases.end()) + return nullptr; + info->files = &((*it2).second); + return info; +} diff --git a/src/resources/mapdb.h b/src/resources/mapdb.h index b8fd954fa..32e9f5695 100644 --- a/src/resources/mapdb.h +++ b/src/resources/mapdb.h @@ -34,6 +34,7 @@ namespace MapDB struct MapInfo { std::string atlas; + StringVect *files; }; /** @@ -52,13 +53,17 @@ namespace MapDB std::string getMapName(const std::string &name); + MapInfo *getMapAtlas(const std::string &name); + // Maps DB typedef std::map<std::string, std::string> Maps; typedef Maps::iterator MapIterator; // map to infos map typedef std::map<std::string, MapInfo> MapInfos; + typedef MapInfos::iterator MapInfoIter; // atlas to files map typedef std::map<std::string, StringVect> Atlases; + typedef Atlases::iterator AtlasIter; } #endif diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index db53e6518..f81741227 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -24,7 +24,9 @@ #include "client.h" #include "configuration.h" +#include "graphicsmanager.h" #include "logger.h" +#include "main.h" #include "map.h" #include "maplayer.h" #include "tileset.h" @@ -252,6 +254,7 @@ Map *MapReader::readMap(XmlNodePtr node, const std::string &path) // Take the filename off the path const std::string pathDir = path.substr(0, path.rfind("/") + 1); + const std::string fileName = path.substr(path.rfind("/") + 1); const int w = XML::getProperty(node, "width", 0); const int h = XML::getProperty(node, "height", 0); @@ -272,6 +275,15 @@ Map *MapReader::readMap(XmlNodePtr node, const std::string &path) Map *const map = new Map(w, h, tilew, tileh); +#ifdef USE_OPENGL + if (graphicsManager.getUseAtlases()) + { + const MapDB::MapInfo *const info = MapDB::getMapAtlas(fileName); + map->setAtlas(ResourceManager::getInstance()->getAtlas( + info->atlas, *info->files)); + } +#endif + for_each_xml_child_node(childNode, node) { if (xmlNameEqual(childNode, "tileset")) diff --git a/src/resources/openglimagehelper.cpp b/src/resources/openglimagehelper.cpp index 2ae819a11..8aed5330e 100644 --- a/src/resources/openglimagehelper.cpp +++ b/src/resources/openglimagehelper.cpp @@ -24,19 +24,19 @@ #ifdef USE_OPENGL -#include "resources/dye.h" -#include "resources/resourcemanager.h" - +#include "client.h" +#include "game.h" +#include "graphicsmanager.h" +#include "logger.h" #include "normalopenglgraphics.h" #include "safeopenglgraphics.h" -#include "client.h" -#include "logger.h" +#include "resources/dye.h" +#include "resources/image.h" +#include "resources/resourcemanager.h" #include "utils/stringutils.h" -#include "resources/image.h" - #include <SDL_image.h> #include <SDL_rotozoom.h> @@ -48,7 +48,7 @@ int OpenGLImageHelper::mTextureSize = 0; bool OpenGLImageHelper::mBlur = true; int OpenGLImageHelper::mUseOpenGL = 0; -Resource *OpenGLImageHelper::load(SDL_RWops *const rw, Dye const &dye) +Image *OpenGLImageHelper::load(SDL_RWops *const rw, Dye const &dye) { SDL_Surface *const tmpImage = IMG_Load_RW(rw, 1); @@ -300,5 +300,4 @@ int OpenGLImageHelper::useOpenGL() { return mUseOpenGL; } - #endif diff --git a/src/resources/openglimagehelper.h b/src/resources/openglimagehelper.h index c93216e12..292e18138 100644 --- a/src/resources/openglimagehelper.h +++ b/src/resources/openglimagehelper.h @@ -26,6 +26,8 @@ #include "localconsts.h" #include "main.h" +#include "utils/stringvector.h" + #include "resources/imagehelper.h" #include <SDL.h> @@ -67,7 +69,7 @@ class OpenGLImageHelper final : public ImageHelper * @return <code>NULL</code> if an error occurred, a valid pointer * otherwise. */ - Resource *load(SDL_RWops *const rw, Dye const &dye); + Image *load(SDL_RWops *const rw, Dye const &dye); /** * Loads an image from an SDL surface. @@ -107,6 +109,9 @@ class OpenGLImageHelper final : public ImageHelper */ int useOpenGL(); + static int getTextureSize() + { return mTextureSize; } + protected: /** * Returns the first power of two equal or bigger than the input. diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 9f2947dfc..5270e6f60 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -27,11 +27,13 @@ #include "configuration.h" #include "logger.h" +#include "resources/atlasmanager.h" #include "resources/dye.h" #include "resources/image.h" #include "resources/imagehelper.h" #include "resources/imageset.h" #include "resources/music.h" +#include "resources/openglimagehelper.h" #include "resources/soundeffect.h" #include "resources/spritedef.h" @@ -652,6 +654,32 @@ Image *ResourceManager::getSubImage(Image *const parent, return static_cast<Image*>(get(ss.str(), SubImageLoader::load, &rl)); } +struct AtlasLoader +{ + const std::string name; + const StringVect *files; + + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const AtlasLoader *const rl = static_cast<const AtlasLoader *const>(v); + AtlasResource *const resource = AtlasManager::loadTextureAtlas( + rl->name, *rl->files); + AtlasManager::injectToResources(resource); + return resource; + } +}; + +Resource *ResourceManager::getAtlas(const std::string &name, + const StringVect &files) +{ + AtlasLoader rl = { name, &files }; + + return get("atlas_" + name, AtlasLoader::load, &rl); +} + struct SpriteDefLoader { std::string path; diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index e20e4b3ac..551b00a33 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -212,6 +212,8 @@ class ResourceManager final Image *getSubImage(Image *const parent, const int x, const int y, const int width, const int height); + Resource *getAtlas(const std::string &name, const StringVect &files); + /** * Creates a sprite definition based on a given path and the supplied * variant. diff --git a/src/resources/sdlimagehelper.cpp b/src/resources/sdlimagehelper.cpp index 5c02d0e2e..a5423bc62 100644 --- a/src/resources/sdlimagehelper.cpp +++ b/src/resources/sdlimagehelper.cpp @@ -38,7 +38,7 @@ bool SDLImageHelper::mEnableAlphaCache = false; -Resource *SDLImageHelper::load(SDL_RWops *const rw, Dye const &dye) +Image *SDLImageHelper::load(SDL_RWops *const rw, Dye const &dye) { SDL_Surface *const tmpImage = IMG_Load_RW(rw, 1); diff --git a/src/resources/sdlimagehelper.h b/src/resources/sdlimagehelper.h index 2742755c2..6884af28d 100644 --- a/src/resources/sdlimagehelper.h +++ b/src/resources/sdlimagehelper.h @@ -52,7 +52,7 @@ class SDLImageHelper final : public ImageHelper * @return <code>NULL</code> if an error occurred, a valid pointer * otherwise. */ - Resource *load(SDL_RWops *const rw, Dye const &dye); + Image *load(SDL_RWops *const rw, Dye const &dye); /** * Loads an image from an SDL surface. |