From 3c4734d69a44aea133e5bd7df66a5dedb87785fb Mon Sep 17 00:00:00 2001 From: Kahrl Date: Tue, 20 Aug 2013 22:38:14 +0200 Subject: [PATCH] Change mainmenu texture handling + small misc changes Texture names must now be escaped in formspec elements image[], background[], image_button[], image_button_exit[]. Instead of special-case handling of texture loading (and unloading which was missing) in guiFormSpecMenu.cpp, use the newly created ISimpleTextureSource interface which is a minimal subset of ITextureSource. There is an implementation of this interface used by GUIEngine (MenuTextureSource). Fix an off-by-one bug in unescape_string; it caused requests for a texture called "\0". --- builtin/gamemgr.lua | 6 +++-- builtin/mainmenu.lua | 5 ++-- builtin/mm_menubar.lua | 5 ++-- builtin/modstore.lua | 2 +- src/game.cpp | 6 ++--- src/guiEngine.cpp | 48 ++++++++++++++++++++++++++++++++-- src/guiEngine.h | 55 ++++++++++++++++++++++++++++++++------ src/guiFormSpecMenu.cpp | 58 ++++++++++------------------------------- src/guiFormSpecMenu.h | 7 ++--- src/tile.h | 46 ++++++++++++++++---------------- src/util/string.h | 2 +- 11 files changed, 150 insertions(+), 90 deletions(-) diff --git a/builtin/gamemgr.lua b/builtin/gamemgr.lua index 8409bff03..7a5e9790f 100644 --- a/builtin/gamemgr.lua +++ b/builtin/gamemgr.lua @@ -225,7 +225,8 @@ function gamemgr.tab() if current_game.menuicon_path ~= nil and current_game.menuicon_path ~= "" then retval = retval .. - "image[5.8,-0.25;2,2;" .. current_game.menuicon_path .. "]" + "image[5.8,-0.25;2,2;" .. + engine.formspec_escape(current_game.menuicon_path) .. "]" end retval = retval .. @@ -251,7 +252,8 @@ function gamemgr.dialog_edit_game() if current_game.menuicon_path ~= nil and current_game.menuicon_path ~= "" then retval = retval .. - "image[5.25,0;2,2;" .. current_game.menuicon_path .. "]" + "image[5.25,0;2,2;" .. + engine.formspec_escape(current_game.menuicon_path) .. "]" end retval = retval .. diff --git a/builtin/mainmenu.lua b/builtin/mainmenu.lua index 787a5e280..5a1b6e929 100644 --- a/builtin/mainmenu.lua +++ b/builtin/mainmenu.lua @@ -1047,16 +1047,17 @@ function tabbuilder.tab_texture_packs() return retval .. menu.render_texture_pack_list(list) .. ";" .. index .. "]" .. - "image[0.65,0.25;4.0,3.7;"..(screenfile or no_screenshot).."]".. + "image[0.65,0.25;4.0,3.7;"..engine.formspec_escape(screenfile or no_screenshot).."]".. "textarea[1.0,3.25;3.7,1.5;;"..engine.formspec_escape(infotext or "")..";]" end -------------------------------------------------------------------------------- function tabbuilder.tab_credits() + local logofile = menu.defaulttexturedir .. "logo.png" return "vertlabel[0,-0.5;CREDITS]" .. "label[0.5,3;Minetest " .. engine.get_version() .. "]" .. "label[0.5,3.3;http://minetest.net]" .. - "image[0.5,1;" .. menu.defaulttexturedir .. "logo.png]" .. + "image[0.5,1;" .. engine.formspec_escape(logofile) .. "]" .. "textlist[3.5,-0.25;8.5,5.8;list_credits;" .. "#FFFF00" .. fgettext("Core Developers") .."," .. "Perttu Ahola (celeron55) ,".. diff --git a/builtin/mm_menubar.lua b/builtin/mm_menubar.lua index faba92a8f..c3ddbb289 100644 --- a/builtin/mm_menubar.lua +++ b/builtin/mm_menubar.lua @@ -51,7 +51,8 @@ function menubar.refresh() menubar.formspec = menubar.formspec .. "image_button[" .. buttonpos .. ",5.7;1.3,1.3;" .. - gamemgr.games[i].menuicon_path .. ";" .. btn_name .. ";;true;false]" + engine.formspec_escape(gamemgr.games[i].menuicon_path) .. ";" .. + btn_name .. ";;true;false]" else local part1 = gamemgr.games[i].id:sub(1,5) @@ -75,4 +76,4 @@ function menubar.refresh() table.insert(menubar.buttons,toadd) end -end \ No newline at end of file +end diff --git a/builtin/modstore.lua b/builtin/modstore.lua index 2f967c9b1..43f7759ad 100644 --- a/builtin/modstore.lua +++ b/builtin/modstore.lua @@ -227,7 +227,7 @@ function modstore.getmodlist(list) end retval = retval .. "image[0,".. screenshot_ypos .. ";3,2;" .. - list.data[i].texturename .. "]" + engine.formspec_escape(list.data[i].texturename) .. "]" --title + author retval = retval .."label[2.75," .. screenshot_ypos .. ";" .. diff --git a/src/game.cpp b/src/game.cpp index 5d8365781..f313ae28f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1720,7 +1720,7 @@ void the_game( GUIFormSpecMenu *menu = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, - &client, gamedef); + &client, gamedef, tsrc); InventoryLocation inventoryloc; inventoryloc.setCurrentPlayer(); @@ -2259,7 +2259,7 @@ void the_game( GUIFormSpecMenu *menu = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, - &client, gamedef); + &client, gamedef, tsrc); menu->setFormSource(current_formspec); menu->setTextDest(current_textdest); menu->drop(); @@ -2755,7 +2755,7 @@ void the_game( GUIFormSpecMenu *menu = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, - &client, gamedef); + &client, gamedef, tsrc); menu->setFormSpec(meta->getString("formspec"), inventoryloc); menu->setFormSource(new NodeMetadataFormSource( diff --git a/src/guiEngine.cpp b/src/guiEngine.cpp index f00cd039c..547f393a4 100644 --- a/src/guiEngine.cpp +++ b/src/guiEngine.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiMainMenu.h" #include "sound.h" #include "sound_openal.h" +#include "clouds.h" #include #include @@ -36,6 +37,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #endif +/******************************************************************************/ +/** TextDestGuiEngine */ /******************************************************************************/ TextDestGuiEngine::TextDestGuiEngine(GUIEngine* engine) { @@ -54,6 +57,38 @@ void TextDestGuiEngine::gotText(std::wstring text) m_engine->getScriptIface()->handleMainMenuEvent(wide_to_narrow(text)); } +/******************************************************************************/ +/** MenuTextureSource */ +/******************************************************************************/ +MenuTextureSource::MenuTextureSource(video::IVideoDriver *driver) +{ + m_driver = driver; +} + +/******************************************************************************/ +MenuTextureSource::~MenuTextureSource() +{ + for (std::set::iterator it = m_to_delete.begin(); + it != m_to_delete.end(); ++it) { + const char *tname = (*it).c_str(); + video::ITexture *texture = m_driver->getTexture(tname); + m_driver->removeTexture(texture); + } +} + +/******************************************************************************/ +video::ITexture* MenuTextureSource::getTexture(const std::string &name, u32 *id) +{ + if(id) + *id = 0; + if(name.empty()) + return NULL; + m_to_delete.insert(name); + return m_driver->getTexture(name.c_str()); +} + +/******************************************************************************/ +/** MenuMusicFetcher */ /******************************************************************************/ void MenuMusicFetcher::fetchSounds(const std::string &name, std::set &dst_paths, @@ -74,6 +109,8 @@ void MenuMusicFetcher::fetchSounds(const std::string &name, dst_paths.insert(base + DIR_DELIM + name + "."+itos(i)+".ogg"); } +/******************************************************************************/ +/** GUIEngine */ /******************************************************************************/ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, gui::IGUIElement* parent, @@ -86,6 +123,7 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, m_menumanager(menumgr), m_smgr(smgr), m_data(data), + m_texture_source(NULL), m_sound_manager(NULL), m_formspecgui(0), m_buttonhandler(0), @@ -105,6 +143,9 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, // is deleted by guiformspec! m_buttonhandler = new TextDestGuiEngine(this); + //create texture source + m_texture_source = new MenuTextureSource(m_device->getVideoDriver()); + //create soundmanager MenuMusicFetcher soundfetcher; #if USE_SOUND @@ -132,7 +173,8 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, -1, m_menumanager, 0 /* &client */, - 0 /* gamedef */); + 0 /* gamedef */, + m_texture_source); m_menu->allowClose(false); m_menu->lockSize(true,v2u32(800,600)); @@ -264,11 +306,13 @@ GUIEngine::~GUIEngine() m_irr_toplefttext->setText(L""); - //initialize texture pointers + //clean up texture pointers for (unsigned int i = 0; i < TEX_LAYER_MAX; i++) { if (m_textures[i] != 0) driver->removeTexture(m_textures[i]); } + + delete m_texture_source; if (m_cloud.clouds) m_cloud.clouds->drop(); diff --git a/src/guiEngine.h b/src/guiEngine.h index 6b7d3b6ed..484459395 100644 --- a/src/guiEngine.h +++ b/src/guiEngine.h @@ -25,17 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc., /******************************************************************************/ #include "irrlichttypes.h" #include "modalMenu.h" -#include "clouds.h" #include "guiFormSpecMenu.h" #include "sound.h" +#include "tile.h" /******************************************************************************/ /* Typedefs and macros */ /******************************************************************************/ -#define MAX_MENUBAR_BTN_COUNT 10 -#define MAX_MENUBAR_BTN_ID 256 -#define MIN_MENUBAR_BTN_ID (MAX_MENUBAR_BTN_ID - MAX_MENUBAR_BTN_COUNT) - /** texture layer ids */ typedef enum { TEX_LAYER_BACKGROUND = 0, @@ -50,8 +46,8 @@ typedef enum { /******************************************************************************/ class GUIEngine; class MainMenuScripting; +class Clouds; struct MainMenuData; -struct SimpleSoundSpec; /******************************************************************************/ /* declarations */ @@ -66,6 +62,7 @@ public: * @param engine the engine data is transmitted for further processing */ TextDestGuiEngine(GUIEngine* engine); + /** * receive fields transmitted by guiFormSpecMenu * @param fields map containing formspec field elements currently active @@ -77,18 +74,58 @@ public: * @param text textual representation of event */ void gotText(std::wstring text); + private: /** target to transmit data to */ GUIEngine* m_engine; }; +/** GUIEngine specific implementation of ISimpleTextureSource */ +class MenuTextureSource : public ISimpleTextureSource +{ +public: + /** + * default constructor + * @param driver the video driver to load textures from + */ + MenuTextureSource(video::IVideoDriver *driver); + + /** + * destructor, removes all loaded textures + */ + virtual ~MenuTextureSource(); + + /** + * get a texture, loading it if required + * @param name path to the texture + * @param id receives the texture ID, always 0 in this implementation + */ + video::ITexture* getTexture(const std::string &name, u32 *id = NULL); + +private: + /** driver to get textures from */ + video::IVideoDriver *m_driver; + /** set of texture names to delete */ + std::set m_to_delete; +}; + +/** GUIEngine specific implementation of OnDemandSoundFetcher */ class MenuMusicFetcher: public OnDemandSoundFetcher { - std::set m_fetched; public: + /** + * get sound file paths according to sound name + * @param name sound name + * @param dst_paths receives possible paths to sound files + * @param dst_datas receives binary sound data (not used here) + */ void fetchSounds(const std::string &name, std::set &dst_paths, std::set &dst_datas); + +private: + /** set of fetched sound names */ + std::set m_fetched; }; /** implementation of main menu based uppon formspecs */ @@ -150,6 +187,8 @@ private: scene::ISceneManager* m_smgr; /** pointer to data beeing transfered back to main game handling */ MainMenuData* m_data; + /** pointer to texture source */ + ISimpleTextureSource* m_texture_source; /** pointer to soundmanager*/ ISoundManager* m_sound_manager; @@ -167,7 +206,7 @@ private: bool m_startgame; /** scripting interface */ - MainMenuScripting* m_script; + MainMenuScripting* m_script; /** script basefolder */ std::string m_scriptdir; diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index bc33143a4..28cb6740e 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -69,12 +69,14 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, InventoryManager *invmgr, - IGameDef *gamedef + IGameDef *gamedef, + ISimpleTextureSource *tsrc ): GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr), m_device(dev), m_invmgr(invmgr), m_gamedef(gamedef), + m_tsrc(tsrc), m_form_src(NULL), m_text_dst(NULL), m_selected_item(NULL), @@ -483,7 +485,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) { if (parts.size() == 3) { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); - std::string name = parts[2]; + std::string name = unescape_string(parts[2]); MY_CHECKPOS("image",0); MY_CHECKGEOM("image",1); @@ -504,7 +506,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) { if (parts.size() == 2) { std::vector v_pos = split(parts[0],','); - std::string name = parts[1]; + std::string name = unescape_string(parts[1]); MY_CHECKPOS("image",0); @@ -605,7 +607,7 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) { if (parts.size() == 3) { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); - std::string name = parts[2]; + std::string name = unescape_string(parts[2]); MY_CHECKPOS("background",0); MY_CHECKGEOM("background",1); @@ -769,11 +771,6 @@ void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) { if (str_initial_selection != "") e->setSelected(stoi(str_initial_selection.c_str())-1); - //if (data->listbox_selections.find(fname_w) != data->listbox_selections.end()) { - // e->setSelected(data->listbox_selections[fname_w]); - //} - - //m_listboxes.push_back(std::pair(spec,e)); m_fields.push_back(spec); return; } @@ -1149,6 +1146,8 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std: if(data->bp_set != 2) errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<tsrc()->getTexture(image_name); - if ((parts.size() == 8)) { - pressed_texture = m_gamedef->tsrc()->getTexture(pressed_image_name); - } - } else { - if (fs::PathExists(image_name)) { - texture = Environment->getVideoDriver()->getTexture(image_name.c_str()); - m_Textures.push_back(texture); - } - if (fs::PathExists(pressed_image_name)) { - pressed_texture = Environment->getVideoDriver()->getTexture(pressed_image_name.c_str()); - m_Textures.push_back(pressed_texture); - } - } - if (parts.size() < 8) + texture = m_tsrc->getTexture(image_name); + if (parts.size() == 8) + pressed_texture = m_tsrc->getTexture(pressed_image_name); + else pressed_texture = texture; gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str()); @@ -1797,15 +1782,7 @@ void GUIFormSpecMenu::drawMenu() for(u32 i=0; itsrc()->getTexture(spec.name); - else - { - texture = driver->getTexture(spec.name.c_str()); - m_Textures.push_back(texture); - } + video::ITexture *texture = m_tsrc->getTexture(spec.name); if (texture != 0) { // Image size on screen @@ -1847,15 +1824,8 @@ void GUIFormSpecMenu::drawMenu() for(u32 i=0; igetTexture(spec.name); - if (m_gamedef != 0) - texture = m_gamedef->tsrc()->getTexture(spec.name); - else - { - texture = driver->getTexture(spec.name.c_str()); - m_Textures.push_back(texture); - } if (texture != 0) { const core::dimension2d& img_origsize = texture->getOriginalSize(); // Image size on screen diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 73c21b72d..c244e458f 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class IGameDef; class InventoryManager; +class ISimpleTextureSource; typedef enum { f_Button, @@ -176,7 +177,8 @@ public: gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, InventoryManager *invmgr, - IGameDef *gamedef + IGameDef *gamedef, + ISimpleTextureSource *tsrc ); ~GUIFormSpecMenu(); @@ -245,6 +247,7 @@ protected: irr::IrrlichtDevice* m_device; InventoryManager *m_invmgr; IGameDef *m_gamedef; + ISimpleTextureSource *m_tsrc; std::string m_formspec_string; InventoryLocation m_current_inventory_location; @@ -302,8 +305,6 @@ private: bool key_escape; } fs_key_pendig; - std::vector m_Textures; - fs_key_pendig current_keys_pending; // Determine whether listbox click was double click diff --git a/src/tile.h b/src/tile.h index 23c214350..90e180a48 100644 --- a/src/tile.h +++ b/src/tile.h @@ -82,22 +82,27 @@ struct TextureFromMeshParams TextureSource creates and caches textures. */ -class ITextureSource +class ISimpleTextureSource +{ +public: + ISimpleTextureSource(){} + virtual ~ISimpleTextureSource(){} + virtual video::ITexture* getTexture( + const std::string &name, u32 *id = NULL) = 0; +}; + +class ITextureSource : public ISimpleTextureSource { public: ITextureSource(){} virtual ~ITextureSource(){} - virtual u32 getTextureId(const std::string &name){return 0;} - virtual u32 getTextureIdDirect(const std::string &name){return 0;} - virtual std::string getTextureName(u32 id){return "";} - virtual video::ITexture* getTexture(u32 id){return NULL;} + virtual u32 getTextureId(const std::string &name)=0; + virtual u32 getTextureIdDirect(const std::string &name)=0; + virtual std::string getTextureName(u32 id)=0; + virtual video::ITexture* getTexture(u32 id)=0; virtual video::ITexture* getTexture( - const std::string &name, u32 *id = NULL){ - if(id) *id = 0; - return NULL; - } - virtual IrrlichtDevice* getDevice() - {return NULL;} + const std::string &name, u32 *id = NULL)=0; + virtual IrrlichtDevice* getDevice()=0; virtual bool isKnownSourceImage(const std::string &name)=0; virtual video::ITexture* generateTextureFromMesh( const TextureFromMeshParams ¶ms)=0; @@ -108,23 +113,20 @@ class IWritableTextureSource : public ITextureSource public: IWritableTextureSource(){} virtual ~IWritableTextureSource(){} - virtual u32 getTextureId(const std::string &name){return 0;} - virtual u32 getTextureIdDirect(const std::string &name){return 0;} - virtual std::string getTextureName(u32 id){return "";} - virtual video::ITexture* getTexture(u32 id){return NULL;} + virtual u32 getTextureId(const std::string &name)=0; + virtual u32 getTextureIdDirect(const std::string &name)=0; + virtual std::string getTextureName(u32 id)=0; + virtual video::ITexture* getTexture(u32 id)=0; virtual video::ITexture* getTexture( - const std::string &name, u32 *id = NULL){ - if(id) *id = 0; - return NULL; - } - virtual IrrlichtDevice* getDevice(){return NULL;} + const std::string &name, u32 *id = NULL)=0; + virtual IrrlichtDevice* getDevice()=0; virtual bool isKnownSourceImage(const std::string &name)=0; + virtual video::ITexture* generateTextureFromMesh( + const TextureFromMeshParams ¶ms)=0; virtual void processQueue()=0; virtual void insertSourceImage(const std::string &name, video::IImage *img)=0; virtual void rebuildImagesAndTextures()=0; - virtual video::ITexture* generateTextureFromMesh( - const TextureFromMeshParams ¶ms)=0; }; IWritableTextureSource* createTextureSource(IrrlichtDevice *device); diff --git a/src/util/string.h b/src/util/string.h index d9390e33c..7531600e3 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -307,7 +307,7 @@ inline std::string unescape_string(std::string &s) { std::string res; - for (size_t i = 0; i <= s.length(); i++) { + for (size_t i = 0; i < s.length(); i++) { if (s[i] == '\\') i++; res += s[i];