summaryrefslogtreecommitdiff
path: root/src/gui/guiEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/guiEngine.cpp')
-rw-r--r--src/gui/guiEngine.cpp587
1 files changed, 587 insertions, 0 deletions
diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp
new file mode 100644
index 000000000..e9b4e54c1
--- /dev/null
+++ b/src/gui/guiEngine.cpp
@@ -0,0 +1,587 @@
+/*
+Minetest
+Copyright (C) 2013 sapier
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "guiEngine.h"
+
+#include <IGUIStaticText.h>
+#include <ICameraSceneNode.h>
+#include "client/renderingengine.h"
+#include "scripting_mainmenu.h"
+#include "util/numeric.h"
+#include "config.h"
+#include "version.h"
+#include "porting.h"
+#include "filesys.h"
+#include "settings.h"
+#include "guiMainMenu.h"
+#include "sound.h"
+#include "sound_openal.h"
+#include "clouds.h"
+#include "httpfetch.h"
+#include "log.h"
+#include "fontengine.h"
+#include "guiscalingfilter.h"
+#include "irrlicht_changes/static_text.h"
+
+#ifdef __ANDROID__
+#include "client/tile.h"
+#include <GLES/gl.h>
+#endif
+
+
+/******************************************************************************/
+void TextDestGuiEngine::gotText(const StringMap &fields)
+{
+ m_engine->getScriptIface()->handleMainMenuButtons(fields);
+}
+
+/******************************************************************************/
+void TextDestGuiEngine::gotText(const std::wstring &text)
+{
+ m_engine->getScriptIface()->handleMainMenuEvent(wide_to_utf8(text));
+}
+
+/******************************************************************************/
+MenuTextureSource::~MenuTextureSource()
+{
+ for (const std::string &texture_to_delete : m_to_delete) {
+ const char *tname = texture_to_delete.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);
+
+#ifdef __ANDROID__
+ video::IImage *image = m_driver->createImageFromFile(name.c_str());
+ if (image) {
+ image = Align2Npot2(image, m_driver);
+ video::ITexture* retval = m_driver->addTexture(name.c_str(), image);
+ image->drop();
+ return retval;
+ }
+#endif
+ return m_driver->getTexture(name.c_str());
+}
+
+/******************************************************************************/
+/** MenuMusicFetcher */
+/******************************************************************************/
+void MenuMusicFetcher::fetchSounds(const std::string &name,
+ std::set<std::string> &dst_paths,
+ std::set<std::string> &dst_datas)
+{
+ if(m_fetched.count(name))
+ return;
+ m_fetched.insert(name);
+ std::string base;
+ base = porting::path_share + DIR_DELIM + "sounds";
+ dst_paths.insert(base + DIR_DELIM + name + ".ogg");
+ int i;
+ for(i=0; i<10; i++)
+ dst_paths.insert(base + DIR_DELIM + name + "."+itos(i)+".ogg");
+ base = porting::path_user + DIR_DELIM + "sounds";
+ dst_paths.insert(base + DIR_DELIM + name + ".ogg");
+ for(i=0; i<10; i++)
+ dst_paths.insert(base + DIR_DELIM + name + "."+itos(i)+".ogg");
+}
+
+/******************************************************************************/
+/** GUIEngine */
+/******************************************************************************/
+GUIEngine::GUIEngine(JoystickController *joystick,
+ gui::IGUIElement *parent,
+ IMenuManager *menumgr,
+ MainMenuData *data,
+ bool &kill) :
+ m_parent(parent),
+ m_menumanager(menumgr),
+ m_smgr(RenderingEngine::get_scene_manager()),
+ m_data(data),
+ m_kill(kill)
+{
+ //initialize texture pointers
+ for (image_definition &texture : m_textures) {
+ texture.texture = NULL;
+ }
+ // is deleted by guiformspec!
+ m_buttonhandler = new TextDestGuiEngine(this);
+
+ //create texture source
+ m_texture_source = new MenuTextureSource(RenderingEngine::get_video_driver());
+
+ //create soundmanager
+ MenuMusicFetcher soundfetcher;
+#if USE_SOUND
+ m_sound_manager = createOpenALSoundManager(&soundfetcher);
+#endif
+ if(!m_sound_manager)
+ m_sound_manager = &dummySoundManager;
+
+ //create topleft header
+ m_toplefttext = L"";
+
+ core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
+ g_fontengine->getTextHeight());
+ rect += v2s32(4, 0);
+
+ m_irr_toplefttext =
+ addStaticText(RenderingEngine::get_gui_env(), m_toplefttext,
+ rect, false, true, 0, -1);
+
+ //create formspecsource
+ m_formspecgui = new FormspecFormSource("");
+
+ /* Create menu */
+ m_menu = new GUIFormSpecMenu(joystick,
+ m_parent,
+ -1,
+ m_menumanager,
+ NULL /* &client */,
+ m_texture_source,
+ m_formspecgui,
+ m_buttonhandler,
+ false);
+
+ m_menu->allowClose(false);
+ m_menu->lockSize(true,v2u32(800,600));
+
+ // Initialize scripting
+
+ infostream << "GUIEngine: Initializing Lua" << std::endl;
+
+ m_script = new MainMenuScripting(this);
+
+ try {
+ m_script->setMainMenuData(&m_data->script_data);
+ m_data->script_data.errormessage = "";
+
+ if (!loadMainMenuScript()) {
+ errorstream << "No future without main menu!" << std::endl;
+ abort();
+ }
+
+ run();
+ } catch (LuaError &e) {
+ errorstream << "Main menu error: " << e.what() << std::endl;
+ m_data->script_data.errormessage = e.what();
+ }
+
+ m_menu->quitMenu();
+ m_menu->drop();
+ m_menu = NULL;
+}
+
+/******************************************************************************/
+bool GUIEngine::loadMainMenuScript()
+{
+ // Set main menu path (for core.get_mainmenu_path())
+ m_scriptdir = g_settings->get("main_menu_path");
+ if (m_scriptdir.empty()) {
+ m_scriptdir = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM + "mainmenu";
+ }
+
+ // Load builtin (which will load the main menu script)
+ std::string script = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "init.lua";
+ try {
+ m_script->loadScript(script);
+ // Menu script loaded
+ return true;
+ } catch (const ModError &e) {
+ errorstream << "GUIEngine: execution of menu script failed: "
+ << e.what() << std::endl;
+ }
+
+ return false;
+}
+
+/******************************************************************************/
+void GUIEngine::run()
+{
+ // Always create clouds because they may or may not be
+ // needed based on the game selected
+ video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+
+ cloudInit();
+
+ unsigned int text_height = g_fontengine->getTextHeight();
+
+ irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"),
+ g_settings->getU16("screen_h"));
+
+ while (RenderingEngine::run() && (!m_startgame) && (!m_kill)) {
+
+ const irr::core::dimension2d<u32> &current_screen_size =
+ RenderingEngine::get_video_driver()->getScreenSize();
+ // Verify if window size has changed and save it if it's the case
+ // Ensure evaluating settings->getBool after verifying screensize
+ // First condition is cheaper
+ if (previous_screen_size != current_screen_size &&
+ current_screen_size != irr::core::dimension2d<u32>(0,0) &&
+ g_settings->getBool("autosave_screensize")) {
+ g_settings->setU16("screen_w", current_screen_size.Width);
+ g_settings->setU16("screen_h", current_screen_size.Height);
+ previous_screen_size = current_screen_size;
+ }
+
+ //check if we need to update the "upper left corner"-text
+ if (text_height != g_fontengine->getTextHeight()) {
+ updateTopLeftTextSize();
+ text_height = g_fontengine->getTextHeight();
+ }
+
+ driver->beginScene(true, true, video::SColor(255,140,186,250));
+
+ if (m_clouds_enabled)
+ {
+ cloudPreProcess();
+ drawOverlay(driver);
+ }
+ else
+ drawBackground(driver);
+
+ drawHeader(driver);
+ drawFooter(driver);
+
+ RenderingEngine::get_gui_env()->drawAll();
+
+ driver->endScene();
+
+ if (m_clouds_enabled)
+ cloudPostProcess();
+ else
+ sleep_ms(25);
+
+ m_script->step();
+
+#ifdef __ANDROID__
+ m_menu->getAndroidUIInput();
+#endif
+ }
+}
+
+/******************************************************************************/
+GUIEngine::~GUIEngine()
+{
+ if (m_sound_manager != &dummySoundManager){
+ delete m_sound_manager;
+ m_sound_manager = NULL;
+ }
+
+ infostream<<"GUIEngine: Deinitializing scripting"<<std::endl;
+ delete m_script;
+
+ m_irr_toplefttext->setText(L"");
+
+ //clean up texture pointers
+ for (image_definition &texture : m_textures) {
+ if (texture.texture)
+ RenderingEngine::get_video_driver()->removeTexture(texture.texture);
+ }
+
+ delete m_texture_source;
+
+ if (m_cloud.clouds)
+ m_cloud.clouds->drop();
+}
+
+/******************************************************************************/
+void GUIEngine::cloudInit()
+{
+ m_cloud.clouds = new Clouds(m_smgr, -1, rand());
+ m_cloud.clouds->setHeight(100.0f);
+ m_cloud.clouds->update(v3f(0, 0, 0), video::SColor(255,200,200,255));
+
+ m_cloud.camera = m_smgr->addCameraSceneNode(0,
+ v3f(0,0,0), v3f(0, 60, 100));
+ m_cloud.camera->setFarValue(10000);
+
+ m_cloud.lasttime = RenderingEngine::get_timer_time();
+}
+
+/******************************************************************************/
+void GUIEngine::cloudPreProcess()
+{
+ u32 time = RenderingEngine::get_timer_time();
+
+ if(time > m_cloud.lasttime)
+ m_cloud.dtime = (time - m_cloud.lasttime) / 1000.0;
+ else
+ m_cloud.dtime = 0;
+
+ m_cloud.lasttime = time;
+
+ m_cloud.clouds->step(m_cloud.dtime*3);
+ m_cloud.clouds->render();
+ m_smgr->drawAll();
+}
+
+/******************************************************************************/
+void GUIEngine::cloudPostProcess()
+{
+ float fps_max = g_settings->getFloat("pause_fps_max");
+ // Time of frame without fps limit
+ u32 busytime_u32;
+
+ // not using getRealTime is necessary for wine
+ u32 time = RenderingEngine::get_timer_time();
+ if(time > m_cloud.lasttime)
+ busytime_u32 = time - m_cloud.lasttime;
+ else
+ busytime_u32 = 0;
+
+ // FPS limiter
+ u32 frametime_min = 1000./fps_max;
+
+ if (busytime_u32 < frametime_min) {
+ u32 sleeptime = frametime_min - busytime_u32;
+ RenderingEngine::get_raw_device()->sleep(sleeptime);
+ }
+}
+
+/******************************************************************************/
+void GUIEngine::drawBackground(video::IVideoDriver *driver)
+{
+ v2u32 screensize = driver->getScreenSize();
+
+ video::ITexture* texture = m_textures[TEX_LAYER_BACKGROUND].texture;
+
+ /* If no texture, draw background of solid color */
+ if(!texture){
+ video::SColor color(255,80,58,37);
+ core::rect<s32> rect(0, 0, screensize.X, screensize.Y);
+ driver->draw2DRectangle(color, rect, NULL);
+ return;
+ }
+
+ v2u32 sourcesize = texture->getOriginalSize();
+
+ if (m_textures[TEX_LAYER_BACKGROUND].tile)
+ {
+ v2u32 tilesize(
+ MYMAX(sourcesize.X,m_textures[TEX_LAYER_BACKGROUND].minsize),
+ MYMAX(sourcesize.Y,m_textures[TEX_LAYER_BACKGROUND].minsize));
+ for (unsigned int x = 0; x < screensize.X; x += tilesize.X )
+ {
+ for (unsigned int y = 0; y < screensize.Y; y += tilesize.Y )
+ {
+ draw2DImageFilterScaled(driver, texture,
+ core::rect<s32>(x, y, x+tilesize.X, y+tilesize.Y),
+ core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+ NULL, NULL, true);
+ }
+ }
+ return;
+ }
+
+ /* Draw background texture */
+ draw2DImageFilterScaled(driver, texture,
+ core::rect<s32>(0, 0, screensize.X, screensize.Y),
+ core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+ NULL, NULL, true);
+}
+
+/******************************************************************************/
+void GUIEngine::drawOverlay(video::IVideoDriver *driver)
+{
+ v2u32 screensize = driver->getScreenSize();
+
+ video::ITexture* texture = m_textures[TEX_LAYER_OVERLAY].texture;
+
+ /* If no texture, draw nothing */
+ if(!texture)
+ return;
+
+ /* Draw background texture */
+ v2u32 sourcesize = texture->getOriginalSize();
+ draw2DImageFilterScaled(driver, texture,
+ core::rect<s32>(0, 0, screensize.X, screensize.Y),
+ core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+ NULL, NULL, true);
+}
+
+/******************************************************************************/
+void GUIEngine::drawHeader(video::IVideoDriver *driver)
+{
+ core::dimension2d<u32> screensize = driver->getScreenSize();
+
+ video::ITexture* texture = m_textures[TEX_LAYER_HEADER].texture;
+
+ /* If no texture, draw nothing */
+ if(!texture)
+ return;
+
+ f32 mult = (((f32)screensize.Width / 2.0)) /
+ ((f32)texture->getOriginalSize().Width);
+
+ v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
+ ((f32)texture->getOriginalSize().Height) * mult);
+
+ // Don't draw the header if there isn't enough room
+ s32 free_space = (((s32)screensize.Height)-320)/2;
+
+ if (free_space > splashsize.Y) {
+ core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
+ splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
+ ((free_space/2)-splashsize.Y/2)+10);
+
+ video::SColor bgcolor(255,50,50,50);
+
+ draw2DImageFilterScaled(driver, texture, splashrect,
+ core::rect<s32>(core::position2d<s32>(0,0),
+ core::dimension2di(texture->getOriginalSize())),
+ NULL, NULL, true);
+ }
+}
+
+/******************************************************************************/
+void GUIEngine::drawFooter(video::IVideoDriver *driver)
+{
+ core::dimension2d<u32> screensize = driver->getScreenSize();
+
+ video::ITexture* texture = m_textures[TEX_LAYER_FOOTER].texture;
+
+ /* If no texture, draw nothing */
+ if(!texture)
+ return;
+
+ f32 mult = (((f32)screensize.Width)) /
+ ((f32)texture->getOriginalSize().Width);
+
+ v2s32 footersize(((f32)texture->getOriginalSize().Width) * mult,
+ ((f32)texture->getOriginalSize().Height) * mult);
+
+ // Don't draw the footer if there isn't enough room
+ s32 free_space = (((s32)screensize.Height)-320)/2;
+
+ if (free_space > footersize.Y) {
+ core::rect<s32> rect(0,0,footersize.X,footersize.Y);
+ rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y);
+ rect -= v2s32(footersize.X/2, 0);
+
+ draw2DImageFilterScaled(driver, texture, rect,
+ core::rect<s32>(core::position2d<s32>(0,0),
+ core::dimension2di(texture->getOriginalSize())),
+ NULL, NULL, true);
+ }
+}
+
+/******************************************************************************/
+bool GUIEngine::setTexture(texture_layer layer, std::string texturepath,
+ bool tile_image, unsigned int minsize)
+{
+ video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+
+ if (m_textures[layer].texture) {
+ driver->removeTexture(m_textures[layer].texture);
+ m_textures[layer].texture = NULL;
+ }
+
+ if (texturepath.empty() || !fs::PathExists(texturepath)) {
+ return false;
+ }
+
+ m_textures[layer].texture = driver->getTexture(texturepath.c_str());
+ m_textures[layer].tile = tile_image;
+ m_textures[layer].minsize = minsize;
+
+ if (!m_textures[layer].texture) {
+ return false;
+ }
+
+ return true;
+}
+
+/******************************************************************************/
+bool GUIEngine::downloadFile(const std::string &url, const std::string &target)
+{
+#if USE_CURL
+ std::ofstream target_file(target.c_str(), std::ios::out | std::ios::binary);
+
+ if (!target_file.good()) {
+ return false;
+ }
+
+ HTTPFetchRequest fetch_request;
+ HTTPFetchResult fetch_result;
+ fetch_request.url = url;
+ fetch_request.caller = HTTPFETCH_SYNC;
+ fetch_request.timeout = g_settings->getS32("curl_file_download_timeout");
+ httpfetch_sync(fetch_request, fetch_result);
+
+ if (!fetch_result.succeeded) {
+ return false;
+ }
+ target_file << fetch_result.data;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+/******************************************************************************/
+void GUIEngine::setTopleftText(const std::string &text)
+{
+ m_toplefttext = translate_string(utf8_to_wide(text));
+
+ updateTopLeftTextSize();
+}
+
+/******************************************************************************/
+void GUIEngine::updateTopLeftTextSize()
+{
+ core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
+ g_fontengine->getTextHeight());
+ rect += v2s32(4, 0);
+
+ m_irr_toplefttext->remove();
+ m_irr_toplefttext =
+ addStaticText(RenderingEngine::get_gui_env(), m_toplefttext,
+ rect, false, true, 0, -1);
+}
+
+/******************************************************************************/
+s32 GUIEngine::playSound(SimpleSoundSpec spec, bool looped)
+{
+ s32 handle = m_sound_manager->playSound(spec, looped);
+ return handle;
+}
+
+/******************************************************************************/
+void GUIEngine::stopSound(s32 handle)
+{
+ m_sound_manager->stopSound(handle);
+}
+
+/******************************************************************************/
+unsigned int GUIEngine::queueAsync(const std::string &serialized_func,
+ const std::string &serialized_params)
+{
+ return m_script->queueAsync(serialized_func, serialized_params);
+}
+