From a4d6d1bafff74e1e08aeb07792df92f312dee5a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 May 2012 18:09:45 +0200 Subject: [PATCH] added a utility for creating texture atlas at runtime --- CMakeLists.txt | 1 + apps/openmw/mwgui/cursorreplace.cpp | 3 + files/mygui/CMakeLists.txt | 1 + files/mygui/atlas1.cfg | 27 +++++++ libs/openengine/ogre/atlas.cpp | 113 ++++++++++++++++++++++++++++ libs/openengine/ogre/atlas.hpp | 27 +++++++ 6 files changed, 172 insertions(+) create mode 100644 files/mygui/atlas1.cfg create mode 100644 libs/openengine/ogre/atlas.cpp create mode 100644 libs/openengine/ogre/atlas.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ca3fe0eeb..668fcd83a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/mouselook.cpp ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp + ${LIBDIR}/openengine/ogre/atlas.cpp ) set(OENGINE_GUI ${LIBDIR}/openengine/gui/events.cpp diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp index 2079538fc..e66f54326 100644 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -13,4 +14,6 @@ CursorReplace::CursorReplace() OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); + + OEngine::Render::Atlas::createFromFile("atlas1.cfg", "mwgui1", "textures\\"); } diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ef62fb68c..2c380cd7e 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -54,6 +54,7 @@ configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYO configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) +configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/atlas1.cfg b/files/mygui/atlas1.cfg new file mode 100644 index 000000000..2a9716b77 --- /dev/null +++ b/files/mygui/atlas1.cfg @@ -0,0 +1,27 @@ +[settings] + size_x = 512 + size_y = 512 + +[tx_menubook_close_idle.dds] + x = 0 + y = 0 + +[tx_menubook_close_over.dds] + x = 128 + y = 0 + +[tx_menubook_close_pressed.dds] + x = 256 + y = 0 + +[tx_menubook_take_idle.dds] + x = 384 + y = 0 + +[tx_menubook_take_over.dds] + x = 0 + y = 32 + +[tx_menubook_take_pressed.dds] + x = 128 + y = 32 diff --git a/libs/openengine/ogre/atlas.cpp b/libs/openengine/ogre/atlas.cpp new file mode 100644 index 000000000..01b84afab --- /dev/null +++ b/libs/openengine/ogre/atlas.cpp @@ -0,0 +1,113 @@ +#include "atlas.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Ogre; +using namespace OEngine::Render; + +void Atlas::createFromFile (const std::string& filename, const std::string& textureName, const std::string& texturePrefix) +{ + ConfigFile file; + file.load(filename, ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, "\t:=", true); + + Root* root = Ogre::Root::getSingletonPtr(); + + SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); + Camera* camera = sceneMgr->createCamera("AtlasCamera"); + + int width = StringConverter::parseInt(file.getSetting("size_x", "settings")); + int height = StringConverter::parseInt(file.getSetting("size_y", "settings")); + + std::vector rectangles; + int i = 0; + + ConfigFile::SectionIterator seci = file.getSectionIterator(); + while (seci.hasMoreElements()) + { + Ogre::String sectionName = seci.peekNextKey(); + seci.getNext(); + + if (sectionName == "settings" || sectionName == "") + continue; + + MaterialPtr material = MaterialManager::getSingleton().create("AtlasMaterial" + StringConverter::toString(i), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + material->getTechnique(0)->getPass(0)->setLightingEnabled(false); + material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(texturePrefix + sectionName); + tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); + + Rectangle2D* rect = new Rectangle2D(true); + rect->setMaterial("AtlasMaterial" + StringConverter::toString(i)); + rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); + + int x = StringConverter::parseInt(file.getSetting("x", sectionName)); + int y = StringConverter::parseInt(file.getSetting("y", sectionName)); + + TexturePtr texture = TextureManager::getSingleton().getByName(texturePrefix + sectionName); + if (texture.isNull()) + { + std::cerr << "OEngine::Render::Atlas: Can't find texture " << texturePrefix + sectionName << ", skipping..." << std::endl; + continue; + } + int textureWidth = texture->getWidth(); + int textureHeight = texture->getHeight(); + + float left = x/float(width) * 2 - 1; + float top = (1-(y/float(height))) * 2 - 1; + float right = ((x+textureWidth))/float(width) * 2 - 1; + float bottom = (1-((y+textureHeight)/float(height))) * 2 - 1; + rect->setCorners(left, top, right, bottom); + + // Use infinite AAB to always stay visible + AxisAlignedBox aabInf; + aabInf.setInfinite(); + rect->setBoundingBox(aabInf); + + // Attach background to the scene + SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(rect); + + rectangles.push_back(rect); + ++i; + } + + TexturePtr destTexture = TextureManager::getSingleton().createManual( + textureName, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + width, height, + 0, + PF_FLOAT16_RGBA, + TU_RENDERTARGET); + + RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); + rtt->setAutoUpdated(false); + Viewport* vp = rtt->addViewport(camera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setBackgroundColour(ColourValue(0,0,0,0)); + + rtt->update(); + + // remove all the junk we've created + for (std::vector::iterator it=rectangles.begin(); + it!=rectangles.end(); ++it) + { + delete (*it); + } + while (i > 0) + { + MaterialManager::getSingleton().remove("AtlasMaterial" + StringConverter::toString(i-1)); + --i; + } + root->destroySceneManager(sceneMgr); +} diff --git a/libs/openengine/ogre/atlas.hpp b/libs/openengine/ogre/atlas.hpp new file mode 100644 index 000000000..5dcd409ca --- /dev/null +++ b/libs/openengine/ogre/atlas.hpp @@ -0,0 +1,27 @@ +#ifndef OENGINE_OGRE_ATLAS_HPP +#define OENGINE_OGRE_ATLAS_HPP + +#include + +namespace OEngine +{ +namespace Render +{ + + /// \brief Creates a texture atlas at runtime + class Atlas + { + public: + /** + * @param absolute path to file that specifies layout of the texture (positions of the textures it contains) + * @param name of the destination texture to save to (in memory) + * @param texture directory prefix + */ + static void createFromFile (const std::string& filename, const std::string& textureName, const std::string& texturePrefix="textures\\"); + }; + +} +} + +#endif +