diff options
Diffstat (limited to 'src/resources/atlas')
-rw-r--r-- | src/resources/atlas/atlasitem.h | 53 | ||||
-rw-r--r-- | src/resources/atlas/atlasmanager.cpp | 379 | ||||
-rw-r--r-- | src/resources/atlas/atlasmanager.h | 70 | ||||
-rw-r--r-- | src/resources/atlas/atlasresource.cpp | 74 | ||||
-rw-r--r-- | src/resources/atlas/atlasresource.h | 53 | ||||
-rw-r--r-- | src/resources/atlas/textureatlas.h | 61 |
6 files changed, 690 insertions, 0 deletions
diff --git a/src/resources/atlas/atlasitem.h b/src/resources/atlas/atlasitem.h new file mode 100644 index 000000000..37c3b9a67 --- /dev/null +++ b/src/resources/atlas/atlasitem.h @@ -0,0 +1,53 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2015 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 RESOURCES_ATLAS_ATLASITEM_H +#define RESOURCES_ATLAS_ATLASITEM_H + +#ifdef USE_OPENGL + +#include "resources/image.h" + +#include <string> + +struct AtlasItem final +{ + explicit AtlasItem(Image *const image0) : + image(image0), + name(), + x(0), + y(0), + width(image0 ? image0->mBounds.w : 0), + height(image0 ? image0->mBounds.h : 0) + { + } + + A_DELETE_COPY(AtlasItem) + + Image *image; + std::string name; + int x; + int y; + int width; + int height; +}; + +#endif // USE_OPENGL +#endif // RESOURCES_ATLAS_ATLASITEM_H diff --git a/src/resources/atlas/atlasmanager.cpp b/src/resources/atlas/atlasmanager.cpp new file mode 100644 index 000000000..a81a6c10d --- /dev/null +++ b/src/resources/atlas/atlasmanager.cpp @@ -0,0 +1,379 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2015 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/>. + */ + +#ifdef USE_OPENGL + +#include "resources/atlas/atlasmanager.h" + +#include "settings.h" + +#ifdef DEBUG_IMAGES +#include "logger.h" +#endif + +#include "utils/mathutils.h" +#include "utils/physfscheckutils.h" +#include "utils/physfsrwops.h" +#include "utils/sdlcheckutils.h" + +#include "resources/dye.h" +#include "resources/imagehelper.h" +#include "resources/openglimagehelper.h" +#include "resources/resourcemanager.h" +#include "resources/sdlimagehelper.h" + +#include "resources/atlas/atlasitem.h" +#include "resources/atlas/atlasresource.h" +#include "resources/atlas/textureatlas.h" + +#include "debug.h" + +AtlasManager::AtlasManager() +{ +} + +AtlasResource *AtlasManager::loadTextureAtlas(const std::string &name, + const StringVect &files) +{ + BLOCK_START("AtlasManager::loadTextureAtlas") + std::vector<TextureAtlas*> atlases; + std::vector<Image*> images; + AtlasResource *resource = new AtlasResource; + + loadImages(files, images); + int maxSize = OpenGLImageHelper::getTextureSize(); +#if !defined(ANDROID) && !defined(__APPLE__) + int sz = settings.textureSize; + if (maxSize > sz) + maxSize = sz; +#endif + + // sorting images on atlases. + simpleSort(name, atlases, images, maxSize); + + FOR_EACH (std::vector<TextureAtlas*>::iterator, it, atlases) + { + TextureAtlas *const atlas = *it; + if (!atlas) + continue; + + // create atlas base on sorted images + SDL_Surface *const surface = createSDLAtlas(atlas); + + if (!surface) + continue; + + // debug save +// ImageWriter::writePNG(surface, settings.tempDir +// + "/atlas" + name + toString(k) + ".png"); +// k ++; + + // convert SDL images to OpenGL + convertAtlas(atlas); + + // free SDL atlas surface + MSDL_FreeSurface(surface); + + resource->atlases.push_back(atlas); + } + + BLOCK_END("AtlasManager::loadTextureAtlas") + return resource; +} + +void AtlasManager::loadImages(const StringVect &files, + std::vector<Image*> &images) +{ + BLOCK_START("AtlasManager::loadImages") + + FOR_EACH (StringVectCIter, it, files) + { + const std::string str = *it; + // check is image with same name already in cache + // and if yes, move it to deleted set + Resource *const res = resourceManager->getTempResource(str); + if (res) + { + // increase counter because in moveToDeleted it will be decreased. + res->incRef(); + resourceManager->moveToDeleted(res); + } + + std::string path = str; + const size_t p = path.find('|'); + Dye *d = nullptr; + if (p != std::string::npos) + { + d = new Dye(path.substr(p + 1)); + path = path.substr(0, p); + } + + SDL_RWops *const rw = MPHYSFSRWOPS_openRead(path.c_str()); + if (rw) + { + Image *const image = d ? surfaceImageHelper->load(rw, *d) + : surfaceImageHelper->load(rw); + + if (image) + { + image->mIdPath = str; +#ifdef DEBUG_IMAGES + logger->log("set name %p, %s", static_cast<void*>(image), + image->mIdPath.c_str()); +#endif + images.push_back(image); + } + } + delete d; + } + BLOCK_END("AtlasManager::loadImages") +} + +void AtlasManager::simpleSort(const std::string &restrict name, + std::vector<TextureAtlas*> &restrict atlases, + const std::vector<Image*> &restrict images, + int size) +{ + BLOCK_START("AtlasManager::simpleSort") + int x = 0; + int y = 0; + int tempHeight = 0; + TextureAtlas *atlas = new TextureAtlas(); + std::vector<Image*>::const_iterator it = images.begin(); + const std::vector<Image*>::const_iterator it_end = images.end(); + for (it = images.begin(); it != it_end; ++ it) + { + const Image *const img = *it; + if (img) + { + atlas->name = std::string("atlas_").append(name).append( + "_").append(img->getIdPath()); + break; + } + } + + for (it = images.begin(); it != it_end; ++ it) + { + Image *const img = *it; + if (img) + { + AtlasItem *const item = new AtlasItem(img); + item->name = img->getIdPath(); + // start next line + if (x + img->mBounds.w > size) + { + x = 0; + y += tempHeight; + tempHeight = 0; + } + + // can't put image with this height + if (y + img->mBounds.h > size) + { + x = 0; + y = 0; + atlases.push_back(atlas); + atlas = new TextureAtlas(); + atlas->name = std::string("atlas_").append(name).append( + "_").append(img->getIdPath()); + } + + if (img->mBounds.h > tempHeight) + tempHeight = 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; + BLOCK_END("AtlasManager::simpleSort") +} + +SDL_Surface *AtlasManager::createSDLAtlas(TextureAtlas *const atlas) +{ + BLOCK_START("AtlasManager::createSDLAtlas") +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + const unsigned int rmask = 0xff000000; + const unsigned int gmask = 0x00ff0000; + const unsigned int bmask = 0x0000ff00; + const unsigned int amask = 0x000000ff; +#else + const unsigned int rmask = 0x000000ff; + const unsigned int gmask = 0x0000ff00; + const unsigned int bmask = 0x00ff0000; + const unsigned int amask = 0xff000000; +#endif + + // do not create atlas based on only one image + if (atlas->items.size() == 1) + { + BLOCK_END("AtlasManager::createSDLAtlas") + return nullptr; + } + + // using only power of two sizes. + atlas->width = powerOfTwo(atlas->width); + atlas->height = powerOfTwo(atlas->height); + + const int width = atlas->width; + const int height = atlas->height; + BLOCK_START("AtlasManager::createSDLAtlas create surface") + // temp SDL surface for atlas + SDL_Surface *const surface = MSDL_CreateRGBSurface(SDL_SWSURFACE, + width, height, 32U, rmask, gmask, bmask, amask); + if (!surface) + { + BLOCK_END("AtlasManager::createSDLAtlas") + return nullptr; + } + BLOCK_END("AtlasManager::createSDLAtlas create surface") + + Image *image = imageHelper->load(surface); + + // drawing SDL images to surface + FOR_EACH (std::vector<AtlasItem*>::iterator, it, atlas->items) + { + AtlasItem *const item = *it; + if (image) + { + imageHelper->copySurfaceToImage(image, item->x, item->y, + item->image->mSDLSurface); + } + } + atlas->atlasImage = image; + BLOCK_END("AtlasManager::createSDLAtlas") + return surface; +} + +void AtlasManager::convertAtlas(TextureAtlas *const atlas) +{ + // no check for null pointer in atlas because it was in caller + // convert surface to OpemGL image + Image *const oldImage = atlas->atlasImage; + + if (oldImage->mSDLSurface) + { + atlas->atlasImage = imageHelper->load(atlas->atlasImage->mSDLSurface); + oldImage->decRef(); + } + + Image *const image = atlas->atlasImage; + if (!image) + return; + + image->mIdPath = atlas->name; +#ifdef DEBUG_IMAGES + logger->log("set name %p, %s", static_cast<void*>(image), + image->mIdPath.c_str()); +#endif + image->incRef(); + + FOR_EACH (std::vector<AtlasItem*>::iterator, it, atlas->items) + { + 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); + Image *const image2 = item->image; + if (image2) + { + image2->mIdPath = item->name; +#ifdef DEBUG_IMAGES + logger->log("set name %p, %s", static_cast<void*>(image2), + image2->mIdPath.c_str()); +#endif + image2->incRef(); + } + } +} + +void AtlasManager::injectToResources(const AtlasResource *const resource) +{ + if (!resource) + return; + FOR_EACH (std::vector<TextureAtlas*>::const_iterator, + it, resource->atlases) + { + // add each atlas image to resources + TextureAtlas *const atlas = *it; + if (atlas) + { + Image *const image = atlas->atlasImage; + if (image) + resourceManager->addResource(atlas->name, image); + FOR_EACH (std::vector<AtlasItem*>::iterator, it2, atlas->items) + { + AtlasItem *const item = *it2; + if (!item) + continue; + // add each atlas sub image to resources + resourceManager->addResource(item->name, item->image); + } + } + } +} + +void AtlasManager::moveToDeleted(AtlasResource *const resource) +{ + if (!resource) + return; + FOR_EACH (std::vector<TextureAtlas*>::iterator, it, resource->atlases) + { + // move each atlas image to deleted + TextureAtlas *const atlas = *it; + if (atlas) + { + Image *const image = atlas->atlasImage; + if (image) + { + // move each atlas image to deleted + resourceManager->moveToDeleted(image); + } + FOR_EACH (std::vector<AtlasItem*>::iterator, it2, atlas->items) + { + AtlasItem *const item = *it2; + if (item) + { + Image *const image2 = item->image; + if (image2) + { + // move each atlas sub image to deleted + resourceManager->moveToDeleted(image2); + } + } + } + } + } +} + +#endif diff --git a/src/resources/atlas/atlasmanager.h b/src/resources/atlas/atlasmanager.h new file mode 100644 index 000000000..b30981be6 --- /dev/null +++ b/src/resources/atlas/atlasmanager.h @@ -0,0 +1,70 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2015 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 RESOURCES_ATLAS_ATLASMANAGER_H +#define RESOURCES_ATLAS_ATLASMANAGER_H + +#ifdef USE_OPENGL + +#include "resources/image.h" + +#include "utils/stringvector.h" + +#include <SDL.h> + +class AtlasResource; +class Resource; + +struct AtlasItem; +struct TextureAtlas; + +class AtlasManager final +{ + public: + AtlasManager(); + + A_DELETE_COPY(AtlasManager) + + static AtlasResource *loadTextureAtlas(const std::string &name, + const StringVect &files) + A_WARN_UNUSED; + + static void injectToResources(const AtlasResource *const resource); + + static void moveToDeleted(AtlasResource *const resource); + + private: + static void loadImages(const StringVect &files, + std::vector<Image*> &images); + + static void simpleSort(const std::string &restrict name, + std::vector<TextureAtlas*> &restrict atlases, + const std::vector<Image*> &restrict images, + int size); + + static SDL_Surface *createSDLAtlas(TextureAtlas *const atlas) + A_WARN_UNUSED A_NONNULL(1); + + + static void convertAtlas(TextureAtlas *const atlas) A_NONNULL(1); +}; + +#endif // USE_OPENGL +#endif // RESOURCES_ATLAS_ATLASMANAGER_H diff --git a/src/resources/atlas/atlasresource.cpp b/src/resources/atlas/atlasresource.cpp new file mode 100644 index 000000000..8125131c6 --- /dev/null +++ b/src/resources/atlas/atlasresource.cpp @@ -0,0 +1,74 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2015 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/>. + */ + +#ifdef USE_OPENGL + +#include "resources/atlas/atlasresource.h" + +#include "resources/resourcemanager.h" + +#include "resources/atlas/atlasitem.h" +#include "resources/atlas/atlasmanager.h" +#include "resources/atlas/textureatlas.h" + +#include "debug.h" + +AtlasResource::~AtlasResource() +{ + FOR_EACH (std::vector<TextureAtlas*>::iterator, it, atlases) + { + TextureAtlas *const atlas = *it; + if (atlas) + { + FOR_EACH (std::vector<AtlasItem*>::iterator, it2, atlas->items) + { + AtlasItem *const item = *it2; + if (item) + { + Image *const image2 = item->image; + if (image2) + image2->decRef(); + delete item; + } + } + Image *const image = atlas->atlasImage; + if (image) + image->decRef(); + delete atlas; + } + } + resourceManager->clearDeleted(false); +} + +void AtlasResource::incRef() +{ + if (!getRefCount()) + AtlasManager::injectToResources(this); + Resource::incRef(); +} + +void AtlasResource::decRef() +{ + Resource::decRef(); + if (!getRefCount()) + AtlasManager::moveToDeleted(this); +} + +#endif diff --git a/src/resources/atlas/atlasresource.h b/src/resources/atlas/atlasresource.h new file mode 100644 index 000000000..d0c9d6548 --- /dev/null +++ b/src/resources/atlas/atlasresource.h @@ -0,0 +1,53 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2015 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 RESOURCES_ATLAS_ATLASRESOURCE_H +#define RESOURCES_ATLAS_ATLASRESOURCE_H + +#ifdef USE_OPENGL + +#include "resources/resource.h" + +#include <vector> + +class Resource; + +struct TextureAtlas; + +class AtlasResource final : public Resource +{ + public: + AtlasResource() : + atlases() + { } + + A_DELETE_COPY(AtlasResource) + + ~AtlasResource(); + + void incRef() override final; + + void decRef() override final; + + std::vector<TextureAtlas*> atlases; +}; + +#endif // USE_OPENGL +#endif // RESOURCES_ATLAS_ATLASRESOURCE_H diff --git a/src/resources/atlas/textureatlas.h b/src/resources/atlas/textureatlas.h new file mode 100644 index 000000000..1906d8bd6 --- /dev/null +++ b/src/resources/atlas/textureatlas.h @@ -0,0 +1,61 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2015 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 RESOURCES_ATLAS_TEXTUREATLAS_H +#define RESOURCES_ATLAS_TEXTUREATLAS_H + +#ifdef USE_OPENGL + +#include "utils/stringvector.h" + +#include <vector> + +#include <SDL.h> + +#include "localconsts.h" + +class AtlasResource; +class Image; +class Resource; + +struct AtlasItem; + +struct TextureAtlas final +{ + TextureAtlas() : + name(), + atlasImage(nullptr), + width(0), + height(0), + items() + { + } + + A_DELETE_COPY(TextureAtlas) + + std::string name; + Image *atlasImage; + int width; + int height; + std::vector <AtlasItem*> items; +}; + +#endif // USE_OPENGL +#endif // RESOURCES_ATLAS_TEXTUREATLAS_H |