X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmain.cpp;h=eda992793641949068475179dc0afc16a71bf240;hb=0413f8ad9d0c1457819f42909ee169287effe772;hp=41cf583f5740c2bed78d1ca30dbb12040a3169a7;hpb=82073025ccc551c2fd205cc1dc6fcecac61cc7ea;p=dragonfireclient.git diff --git a/src/main.cpp b/src/main.cpp index 41cf583f5..eda992793 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,18 +1,18 @@ /* -Minetest-c55 -Copyright (C) 2010-2011 celeron55, Perttu Ahola +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola 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 +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 General Public License for more details. +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License along +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. */ @@ -47,9 +47,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include -#include "common_irrlicht.h" +#include "irrlichttypes_extrabloated.h" #include "debug.h" #include "test.h" +#include "clouds.h" #include "server.h" #include "constants.h" #include "porting.h" @@ -68,9 +69,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "log.h" #include "mods.h" -#include "utility_string.h" +#if USE_FREETYPE +#include "xCGUITTFont.h" +#endif +#include "util/string.h" #include "subgame.h" #include "quicktune.h" +#include "serverlist.h" +#include "sound.h" +#include "sound_openal.h" /* Settings. @@ -83,6 +90,10 @@ Settings *g_settings = &main_settings; Profiler main_profiler; Profiler *g_profiler = &main_profiler; +// Menu clouds are created later +Clouds *g_menuclouds = 0; +irr::scene::ISceneManager *g_menucloudsmgr = 0; + /* Debug streams */ @@ -90,8 +101,6 @@ Profiler *g_profiler = &main_profiler; // Connection std::ostream *dout_con_ptr = &dummyout; std::ostream *derr_con_ptr = &verbosestream; -//std::ostream *dout_con_ptr = &infostream; -//std::ostream *derr_con_ptr = &errorstream; // Server std::ostream *dout_server_ptr = &infostream; @@ -130,7 +139,12 @@ MainGameCallback *g_gamecallback = NULL; u32 getTimeMs() { /* Use imprecise system calls directly (from porting.h) */ - return porting::getTimeMs(); + return porting::getTime(PRECISION_MILLI); +} + +u32 getTime(TimePrecision prec) +{ + return porting::getTime(prec); } #else @@ -139,7 +153,7 @@ u32 getTimeMs() class TimeGetter { public: - virtual u32 getTime() = 0; + virtual u32 getTime(TimePrecision prec) = 0; }; // A precise irrlicht one @@ -149,11 +163,15 @@ class IrrlichtTimeGetter: public TimeGetter IrrlichtTimeGetter(IrrlichtDevice *device): m_device(device) {} - u32 getTime() + u32 getTime(TimePrecision prec) { - if(m_device == NULL) - return 0; - return m_device->getTimer()->getRealTime(); + if (prec == PRECISION_MILLI) { + if(m_device == NULL) + return 0; + return m_device->getTimer()->getRealTime(); + } else { + return porting::getTime(prec); + } } private: IrrlichtDevice *m_device; @@ -162,9 +180,9 @@ class IrrlichtTimeGetter: public TimeGetter class SimpleTimeGetter: public TimeGetter { public: - u32 getTime() + u32 getTime(TimePrecision prec) { - return porting::getTimeMs(); + return porting::getTime(prec); } }; @@ -176,9 +194,57 @@ u32 getTimeMs() { if(g_timegetter == NULL) return 0; - return g_timegetter->getTime(); + return g_timegetter->getTime(PRECISION_MILLI); } +u32 getTime(TimePrecision prec) { + if (g_timegetter == NULL) + return 0; + return g_timegetter->getTime(prec); +} +#endif + +//Client side main menu music fetcher +#ifndef SERVER +class MenuMusicFetcher: public OnDemandSoundFetcher +{ + std::set m_fetched; +public: + + void fetchSounds(const std::string &name, + std::set &dst_paths, + std::set &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"); + dst_paths.insert(base + DIR_DELIM + name + ".0.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".1.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".2.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".3.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".4.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".5.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".6.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".7.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".8.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".9.ogg"); + base = porting::path_user + DIR_DELIM + "sounds"; + dst_paths.insert(base + DIR_DELIM + name + ".ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".0.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".1.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".2.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".3.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".4.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".5.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".6.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".7.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".8.ogg"); + dst_paths.insert(base + DIR_DELIM + name + ".9.ogg"); + } +}; #endif class StderrLogOutput: public ILogOutput @@ -594,54 +660,181 @@ class RandomInputHandler : public InputHandler bool rightreleased; }; -void drawMenuBackground(video::IVideoDriver* driver) +struct MenuTextures { - core::dimension2d screensize = driver->getScreenSize(); - - video::ITexture *bgtexture = - driver->getTexture(getTexturePath("menubg.png").c_str()); - if(bgtexture) + std::string current_gameid; + bool global_textures; + video::ITexture *background; + video::ITexture *overlay; + video::ITexture *header; + video::ITexture *footer; + + MenuTextures(): + global_textures(false), + background(NULL), + overlay(NULL), + header(NULL), + footer(NULL) + {} + + static video::ITexture* getMenuTexture(const std::string &tname, + video::IVideoDriver* driver, const SubgameSpec *spec) { - s32 scaledsize = 128; - - // The important difference between destsize and screensize is - // that destsize is rounded to whole scaled pixels. - // These formulas use component-wise multiplication and division of v2u32. - v2u32 texturesize = bgtexture->getSize(); - v2u32 sourcesize = texturesize * screensize / scaledsize + v2u32(1,1); - v2u32 destsize = scaledsize * sourcesize / texturesize; - - // Default texture wrapping mode in Irrlicht is ETC_REPEAT. - driver->draw2DImage(bgtexture, - core::rect(0, 0, destsize.X, destsize.Y), - core::rect(0, 0, sourcesize.X, sourcesize.Y), - NULL, NULL, true); + if(spec){ + std::string path; + // eg. minetest_menu_background.png (for texture packs) + std::string pack_tname = spec->id + "_menu_" + tname + ".png"; + path = getTexturePath(pack_tname); + if(path != "") + return driver->getTexture(path.c_str()); + // eg. games/minetest_game/menu/background.png + path = getImagePath(spec->path + DIR_DELIM + "menu" + DIR_DELIM + tname + ".png"); + if(path != "") + return driver->getTexture(path.c_str()); + } else { + std::string path; + // eg. menu_background.png + std::string pack_tname = "menu_" + tname + ".png"; + path = getTexturePath(pack_tname); + if(path != "") + return driver->getTexture(path.c_str()); + } + return NULL; } - - video::ITexture *logotexture = - driver->getTexture(getTexturePath("menulogo.png").c_str()); - if(logotexture) + + void update(video::IVideoDriver* driver, const SubgameSpec *spec, int tab) { - v2s32 logosize(logotexture->getOriginalSize().Width, - logotexture->getOriginalSize().Height); - logosize *= 4; + if(tab == TAB_SINGLEPLAYER){ + if(spec->id == current_gameid) + return; + current_gameid = spec->id; + global_textures = false; + background = getMenuTexture("background", driver, spec); + overlay = getMenuTexture("overlay", driver, spec); + header = getMenuTexture("header", driver, spec); + footer = getMenuTexture("footer", driver, spec); + } else { + if(global_textures) + return; + current_gameid = ""; + global_textures = true; + background = getMenuTexture("background", driver, NULL); + overlay = getMenuTexture("overlay", driver, NULL); + header = getMenuTexture("header", driver, NULL); + footer = getMenuTexture("footer", driver, NULL); + } + } +}; + +void drawMenuBackground(video::IVideoDriver* driver, const MenuTextures &menutextures) +{ + v2u32 screensize = driver->getScreenSize(); + video::ITexture *texture = menutextures.background; + + /* If no texture, draw background of solid color */ + if(!texture){ + video::SColor color(255,80,58,37); + core::rect rect(0, 0, screensize.X, screensize.Y); + driver->draw2DRectangle(color, rect, NULL); + return; + } + + /* Draw background texture */ + v2u32 sourcesize = texture->getSize(); + driver->draw2DImage(texture, + core::rect(0, 0, screensize.X, screensize.Y), + core::rect(0, 0, sourcesize.X, sourcesize.Y), + NULL, NULL, true); +} + +void drawMenuOverlay(video::IVideoDriver* driver, const MenuTextures &menutextures) +{ + v2u32 screensize = driver->getScreenSize(); + video::ITexture *texture = menutextures.overlay; + + /* If no texture, draw nothing */ + if(!texture) + return; + + /* Draw overlay texture */ + v2u32 sourcesize = texture->getSize(); + driver->draw2DImage(texture, + core::rect(0, 0, screensize.X, screensize.Y), + core::rect(0, 0, sourcesize.X, sourcesize.Y), + NULL, NULL, true); +} + +void drawMenuHeader(video::IVideoDriver* driver, const MenuTextures &menutextures) +{ + core::dimension2d screensize = driver->getScreenSize(); + video::ITexture *texture = menutextures.header; + + /* If no texture, draw nothing */ + if(!texture) + return; + + f32 mult = (((f32)screensize.Width / 2)) / + ((f32)texture->getOriginalSize().Width); + + v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult, + ((f32)texture->getOriginalSize().Height) * mult); + + // Don't draw the header is there isn't enough room + s32 free_space = (((s32)screensize.Height)-320)/2; + if (free_space > splashsize.Y) { + core::rect 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); - core::rect bgrect(0, screensize.Height-logosize.Y-20, - screensize.Width, screensize.Height); - driver->draw2DRectangle(bgcolor, bgrect, NULL); - - core::rect rect(0,0,logosize.X,logosize.Y); - rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y); - rect -= v2s32(logosize.X/2, 0); - driver->draw2DImage(logotexture, rect, + + driver->draw2DImage(texture, splashrect, core::rect(core::position2d(0,0), - core::dimension2di(logotexture->getSize())), + core::dimension2di(texture->getSize())), NULL, NULL, true); } } -#endif +void drawMenuFooter(video::IVideoDriver* driver, const MenuTextures &menutextures) +{ + core::dimension2d screensize = driver->getScreenSize(); + video::ITexture *texture = menutextures.footer; + + /* 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 rect(0,0,footersize.X,footersize.Y); + rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y); + rect -= v2s32(footersize.X/2, 0); + + driver->draw2DImage(texture, rect, + core::rect(core::position2d(0,0), + core::dimension2di(texture->getSize())), + NULL, NULL, true); + } +} + +static const SubgameSpec* getMenuGame(const MainMenuData &menudata) +{ + for(size_t i=0; i map1; + std::map map1; tempf = -324; const s16 ii=300; for(s16 y=0; y &worldspecs, + std::ostream &os) +{ + for(u32 i=0; i allowed_options; - allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG, - "Show allowed options")); - allowed_options.insert("config", ValueSpec(VALUETYPE_STRING, - "Load configuration from specified file")); - allowed_options.insert("port", ValueSpec(VALUETYPE_STRING, - "Set network port (UDP)")); - allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG, - "Disable unit tests")); - allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG, - "Enable unit tests")); - allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING, - "Same as --world (deprecated)")); - allowed_options.insert("world", ValueSpec(VALUETYPE_STRING, - "Set world path (implies local game)")); - allowed_options.insert("verbose", ValueSpec(VALUETYPE_FLAG, - "Print more information to console")); - allowed_options.insert("logfile", ValueSpec(VALUETYPE_STRING, - "Set logfile path ('' = no logging)")); - allowed_options.insert("gameid", ValueSpec(VALUETYPE_STRING, - "Set gameid (\"--gameid list\" prints available ones)")); + std::map allowed_options; + allowed_options.insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG, + _("Show allowed options")))); + allowed_options.insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING, + _("Load configuration from specified file")))); + allowed_options.insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING, + _("Set network port (UDP)")))); + allowed_options.insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG, + _("Disable unit tests")))); + allowed_options.insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG, + _("Enable unit tests")))); + allowed_options.insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING, + _("Same as --world (deprecated)")))); + allowed_options.insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING, + _("Set world path (implies local game) ('list' lists all)")))); + allowed_options.insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING, + _("Set world by name (implies local game)")))); + allowed_options.insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG, + _("Print more information to console")))); + allowed_options.insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG, + _("Print even more information to console")))); + allowed_options.insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG, + _("Print enormous amounts of information to log and console")))); + allowed_options.insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING, + _("Set logfile path ('' = no logging)")))); + allowed_options.insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING, + _("Set gameid (\"--gameid list\" prints available ones)")))); #ifndef SERVER - allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG, - "Run speed tests")); - allowed_options.insert("address", ValueSpec(VALUETYPE_STRING, - "Address to connect to. ('' = local game)")); - allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG, - "Enable random user input, for testing")); - allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG, - "Run dedicated server")); - allowed_options.insert("name", ValueSpec(VALUETYPE_STRING, - "Set player name")); - allowed_options.insert("password", ValueSpec(VALUETYPE_STRING, - "Set password")); - allowed_options.insert("go", ValueSpec(VALUETYPE_FLAG, - "Disable main menu")); + allowed_options.insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG, + _("Show available video modes")))); + allowed_options.insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG, + _("Run speed tests")))); + allowed_options.insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING, + _("Address to connect to. ('' = local game)")))); + allowed_options.insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG, + _("Enable random user input, for testing")))); + allowed_options.insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG, + _("Run dedicated server")))); + allowed_options.insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING, + _("Set player name")))); + allowed_options.insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING, + _("Set password")))); + allowed_options.insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG, + _("Disable main menu")))); #endif Settings cmd_args; bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options); - if(ret == false || cmd_args.getFlag("help")) + if(ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1")) { - dstream<<"Allowed options:"<::Iterator - i = allowed_options.getIterator(); - i.atEnd() == false; i++) + dstream<<_("Allowed options:")<::iterator + i = allowed_options.begin(); + i != allowed_options.end(); ++i) { std::ostringstream os1(std::ios::binary); - os1<<" --"<getKey(); - if(i.getNode()->getValue().type == VALUETYPE_FLAG) + os1<<" --"<first; + if(i->second.type == VALUETYPE_FLAG) {} else - os1<<" "; + os1<<_(" "); dstream<getValue().help != NULL) - dstream<getValue().help; + if(i->second.help != NULL) + dstream<second.help; dstream< worldspecs = getAvailableWorlds(); + print_worldspecs(worldspecs, dstream); + return 0; + } + // Print startup message - actionstream< filenames; + std::vector filenames; filenames.push_back(porting::path_user + DIR_DELIM + "minetest.conf"); // Legacy configuration file location filenames.push_back(porting::path_user + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf"); -#ifdef RUN_IN_PLACE +#if RUN_IN_PLACE // Try also from a lower level (to aid having the same configuration // for many RUN_IN_PLACE installs) filenames.push_back(porting::path_user + @@ -945,6 +1173,31 @@ int main(int argc, char *argv[]) if(configpath == "") configpath = filenames[0]; } + + // Initialize debug streams +#define DEBUGFILE "debug.txt" +#if RUN_IN_PLACE + std::string logfile = DEBUGFILE; +#else + std::string logfile = porting::path_user+DIR_DELIM+DEBUGFILE; +#endif + if(cmd_args.exists("logfile")) + logfile = cmd_args.get("logfile"); + + log_remove_output(&main_dstream_no_stderr_log_out); + int loglevel = g_settings->getS32("debug_log_level"); + + if (loglevel == 0) //no logging + logfile = ""; + else if (loglevel > 0 && loglevel <= LMT_NUM_VALUES) + log_add_output_maxlev(&main_dstream_no_stderr_log_out, (LogMessageLevel)(loglevel - 1)); + + if(logfile != "") + debugstreams_init(false, logfile.c_str()); + else + debugstreams_init(false, NULL); + + infostream<<"logfile = "<exists("map-dir")) commanded_world = g_settings->get("map-dir"); + // World name + std::string commanded_worldname = ""; + if(cmd_args.exists("worldname")) + commanded_worldname = cmd_args.get("worldname"); + + // Strip world.mt from commanded_world + { + std::string worldmt = "world.mt"; + if(commanded_world.size() > worldmt.size() && + commanded_world.substr(commanded_world.size()-worldmt.size()) + == worldmt){ + dstream<<_("Supplied world.mt file - stripping it off.")< worldspecs = getAvailableWorlds(); + bool found = false; + for(u32 i=0; iset("server_dedicated", run_dedicated_server ? "true" : "false"); if(run_dedicated_server) { DSTACK("Dedicated server branch"); @@ -1011,45 +1309,109 @@ int main(int argc, char *argv[]) // World directory std::string world_path; + verbosestream<<_("Determining world path")< worldspecs = getAvailableWorlds(); + // If a world name was specified, select it + if(commanded_worldname != ""){ + world_path = ""; + for(u32 i=0; i 1){ + dstream<<_("Multiple worlds are available.")<" + " or --world ")<get("default_game")); + infostream<<"Using default gameid ["<get("address"); - if(cmd_args.exists("address")) - address = cmd_args.get("address"); - else if(cmd_args.exists("world")) + if(commanded_world != "") address = ""; + else if(cmd_args.exists("address")) + address = cmd_args.get("address"); std::string playername = g_settings->get("name"); if(cmd_args.exists("name")) @@ -1082,10 +1444,16 @@ int main(int argc, char *argv[]) // Resolution selection - bool fullscreen = false; + bool fullscreen = g_settings->getBool("fullscreen"); u16 screenW = g_settings->getU16("screenW"); u16 screenH = g_settings->getU16("screenH"); + // bpp, fsaa, vsync + + bool vsync = g_settings->getBool("vsync"); + u16 bits = g_settings->getU16("fullscreen_bpp"); + u16 fsaa = g_settings->getU16("fsaa"); + // Determine driver video::E_DRIVER_TYPE driverType; @@ -1104,6 +1472,14 @@ int main(int argc, char *argv[]) driverType = video::EDT_DIRECT3D9; else if(driverstring == "opengl") driverType = video::EDT_OPENGL; +#ifdef _IRR_COMPILE_WITH_OGLES1_ + else if(driverstring == "ogles1") + driverType = video::EDT_OGLES1; +#endif +#ifdef _IRR_COMPILE_WITH_OGLES2_ + else if(driverstring == "ogles2") + driverType = video::EDT_OGLES2; +#endif else { errorstream<<"WARNING: Invalid video_driver specified; defaulting " @@ -1112,15 +1488,77 @@ int main(int argc, char *argv[]) } /* - Create device and exit if creation failed + List video modes if requested */ MyEventReceiver receiver; + if(cmd_args.getFlag("videomodes")){ + IrrlichtDevice *nulldevice; + + SIrrlichtCreationParameters params = SIrrlichtCreationParameters(); + params.DriverType = video::EDT_NULL; + params.WindowSize = core::dimension2d(640, 480); + params.Bits = 24; + params.AntiAlias = fsaa; + params.Fullscreen = false; + params.Stencilbuffer = false; + params.Vsync = vsync; + params.EventReceiver = &receiver; + + nulldevice = createDeviceEx(params); + + if(nulldevice == 0) + return 1; + + dstream<<_("Available video modes (WxHxD):")<getVideoModeList(); + + if(videomode_list == 0){ + nulldevice->drop(); + return 1; + } + + s32 videomode_count = videomode_list->getVideoModeCount(); + core::dimension2d videomode_res; + s32 videomode_depth; + for (s32 i = 0; i < videomode_count; ++i){ + videomode_res = videomode_list->getVideoModeResolution(i); + videomode_depth = videomode_list->getVideoModeDepth(i); + dstream<getDesktopResolution(); + videomode_depth = videomode_list->getDesktopDepth(); + dstream<drop(); + + return 0; + } + + /* + Create device and exit if creation failed + */ + IrrlichtDevice *device; - device = createDevice(driverType, - core::dimension2d(screenW, screenH), - 16, fullscreen, false, false, &receiver); + + SIrrlichtCreationParameters params = SIrrlichtCreationParameters(); + params.DriverType = driverType; + params.WindowSize = core::dimension2d(screenW, screenH); + params.Bits = bits; + params.AntiAlias = fsaa; + params.Fullscreen = fullscreen; + params.Stencilbuffer = false; + params.Vsync = vsync; + params.EventReceiver = &receiver; + + device = createDeviceEx(params); if (device == 0) return 1; // could not create selected driver. @@ -1131,9 +1569,6 @@ int main(int argc, char *argv[]) video::IVideoDriver* driver = device->getVideoDriver(); - // Disable mipmaps (because some of them look ugly) - driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); - /* This changes the minimum allowed number of vertices in a VBO. Default is 500. @@ -1153,6 +1588,7 @@ int main(int argc, char *argv[]) { dstream<<"Running speed tests"<drop(); return 0; } @@ -1170,7 +1606,13 @@ int main(int argc, char *argv[]) guienv = device->getGUIEnvironment(); gui::IGUISkin* skin = guienv->getSkin(); + #if USE_FREETYPE + std::string font_path = g_settings->get("font_path"); + u16 font_size = g_settings->getU16("font_size"); + gui::IGUIFont *font = gui::CGUITTFont::createTTFont(guienv, font_path.c_str(), font_size); + #else gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str()); + #endif if(font) skin->setFont(font); else @@ -1191,7 +1633,26 @@ int main(int argc, char *argv[]) skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0)); skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255,70,100,50)); skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255,255,255,255)); - + +#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2 + // Irrlicht 1.8 input colours + skin->setColor(gui::EGDC_EDITABLE, video::SColor(255,128,128,128)); + skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255,96,134,49)); +#endif + + + // Create the menu clouds + if (!g_menucloudsmgr) + g_menucloudsmgr = smgr->createNewSceneManager(); + if (!g_menuclouds) + g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(), + g_menucloudsmgr, -1, rand(), 100); + g_menuclouds->update(v2f(0, 0), video::SColor(255,200,200,255)); + scene::ICameraSceneNode* camera; + camera = g_menucloudsmgr->addCameraSceneNode(0, + v3f(0,0,0), v3f(0, 60, 100)); + camera->setFarValue(10000); + /* GUI stuff */ @@ -1216,7 +1677,9 @@ int main(int argc, char *argv[]) while(device->run() && kill == false) { // Set the window caption - device->setWindowCaption(L"Minetest [Main Menu]"); + wchar_t* text = wgettext("Main Menu"); + device->setWindowCaption((std::wstring(L"Minetest [")+text+L"]").c_str()); + delete[] text; // This is used for catching disconnects try @@ -1237,6 +1700,13 @@ int main(int argc, char *argv[]) SubgameSpec gamespec; WorldSpec worldspec; + bool simple_singleplayer_mode = false; + + // These are set up based on the menu and other things + std::string current_playername = "inv£lid"; + std::string current_password = ""; + std::string current_address = "does-not-exist"; + int current_port = 0; /* Out-of-game menu loop. @@ -1260,6 +1730,14 @@ int main(int argc, char *argv[]) // Initialize menu data MainMenuData menudata; + if(g_settings->exists("selected_mainmenu_tab")) + menudata.selected_tab = g_settings->getS32("selected_mainmenu_tab"); + if(g_settings->exists("selected_serverlist")) + menudata.selected_serverlist = g_settings->getS32("selected_serverlist"); + if(g_settings->exists("selected_mainmenu_game")){ + menudata.selected_game = g_settings->get("selected_mainmenu_game"); + menudata.selected_game_name = findSubgame(menudata.selected_game).name; + } menudata.address = narrow_to_wide(address); menudata.name = narrow_to_wide(playername); menudata.port = narrow_to_wide(itos(port)); @@ -1269,16 +1747,22 @@ int main(int argc, char *argv[]) menudata.smooth_lighting = g_settings->getBool("smooth_lighting"); menudata.clouds_3d = g_settings->getBool("enable_3d_clouds"); menudata.opaque_water = g_settings->getBool("opaque_water"); + menudata.mip_map = g_settings->getBool("mip_map"); + menudata.anisotropic_filter = g_settings->getBool("anisotropic_filter"); + menudata.bilinear_filter = g_settings->getBool("bilinear_filter"); + menudata.trilinear_filter = g_settings->getBool("trilinear_filter"); + menudata.enable_shaders = g_settings->getS32("enable_shaders"); + menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals"); + menudata.enable_particles = g_settings->getBool("enable_particles"); + menudata.liquid_finite = g_settings->getBool("liquid_finite"); + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, menudata.mip_map); menudata.creative_mode = g_settings->getBool("creative_mode"); menudata.enable_damage = g_settings->getBool("enable_damage"); - // Get world listing for the menu - std::vector worldspecs = getAvailableWorlds(); - for(std::vector::const_iterator i = worldspecs.begin(); - i != worldspecs.end(); i++) - menudata.worlds.push_back(narrow_to_wide( - i->name + " [" + i->gameid + "]")); + menudata.enable_public = g_settings->getBool("server_announce"); // Default to selecting nothing menudata.selected_world = -1; + // Get world listing for the menu + std::vector worldspecs = getAvailableWorlds(); // If there is only one world, select it if(worldspecs.size() == 1){ menudata.selected_world = 0; @@ -1296,17 +1780,49 @@ int main(int argc, char *argv[]) // If a world was commanded, append and select it if(commanded_world != ""){ std::string gameid = getWorldGameId(commanded_world, true); - if(gameid == "") + std::string name = _("[--world parameter]"); + if(gameid == ""){ gameid = g_settings->get("default_game"); - WorldSpec spec(commanded_world, "[commanded world]", gameid); + name += " [new]"; + } + WorldSpec spec(commanded_world, name, gameid); worldspecs.push_back(spec); - menudata.worlds.push_back(narrow_to_wide(spec.name) - +L" ["+narrow_to_wide(spec.gameid)+L"]"); - menudata.selected_world = menudata.worlds.size()-1; + menudata.selected_world = worldspecs.size()-1; } + // Copy worldspecs to menu + menudata.worlds = worldspecs; + // Get game listing + menudata.games = getAvailableGames(); + // If selected game doesn't exist, take first from list + if(findSubgame(menudata.selected_game).id == "" && + !menudata.games.empty()){ + menudata.selected_game = menudata.games[0].id; + } + const SubgameSpec *menugame = getMenuGame(menudata); + + MenuTextures menutextures; + menutextures.update(driver, menugame, menudata.selected_tab); if(skip_main_menu == false) { + video::IVideoDriver* driver = device->getVideoDriver(); + float fps_max = g_settings->getFloat("fps_max"); + infostream<<"Waiting for other menus"<run() && kill == false) + { + if(noMenuActive()) + break; + driver->beginScene(true, true, + video::SColor(255,128,128,128)); + drawMenuBackground(driver, menutextures); + guienv->drawAll(); + driver->endScene(); + // On some computers framerate doesn't seem to be + // automatically limited + sleep_ms(25); + } + infostream<<"Waited for other menus"<getVideoDriver(); - + // Time is in milliseconds, for clouds + u32 lasttime = device->getTimer()->getTime(); + + MenuMusicFetcher soundfetcher; + ISoundManager *sound = NULL; +#if USE_SOUND + sound = createOpenALSoundManager(&soundfetcher); +#endif + if(!sound) + sound = &dummySoundManager; + SimpleSoundSpec spec; + spec.name = "main_menu"; + spec.gain = 1; + s32 handle = sound->playSound(spec, true); + infostream<<"Created main menu"<run() && kill == false) @@ -1333,57 +1862,97 @@ int main(int argc, char *argv[]) if(menu->getStatus() == true) break; - //driver->beginScene(true, true, video::SColor(255,0,0,0)); - driver->beginScene(true, true, video::SColor(255,128,128,128)); + // Game can be selected in the menu + menugame = getMenuGame(menudata); + menutextures.update(driver, menugame, menu->getTab()); + // Clouds for the main menu + bool cloud_menu_background = g_settings->getBool("menu_clouds"); + if(menugame){ + // If game has regular background and no overlay, don't use clouds + if(cloud_menu_background && menutextures.background && + !menutextures.overlay){ + cloud_menu_background = false; + } + // If game game has overlay and no regular background, always draw clouds + else if(menutextures.overlay && !menutextures.background){ + cloud_menu_background = true; + } + } + + // Time calc for the clouds + f32 dtime=0; // in seconds + if (cloud_menu_background) { + u32 time = device->getTimer()->getTime(); + if(time > lasttime) + dtime = (time - lasttime) / 1000.0; + else + dtime = 0; + lasttime = time; + } - drawMenuBackground(driver); + //driver->beginScene(true, true, video::SColor(255,0,0,0)); + driver->beginScene(true, true, video::SColor(255,140,186,250)); + + if (cloud_menu_background) { + // *3 otherwise the clouds would move very slowly + g_menuclouds->step(dtime*3); + g_menuclouds->render(); + g_menucloudsmgr->drawAll(); + drawMenuOverlay(driver, menutextures); + drawMenuHeader(driver, menutextures); + drawMenuFooter(driver, menutextures); + } else { + drawMenuBackground(driver, menutextures); + drawMenuHeader(driver, menutextures); + drawMenuFooter(driver, menutextures); + } guienv->drawAll(); - + driver->endScene(); // On some computers framerate doesn't seem to be // automatically limited - sleep_ms(25); + if (cloud_menu_background) { + // Time of frame without fps limit + float busytime; + u32 busytime_u32; + // not using getRealTime is necessary for wine + u32 time = device->getTimer()->getTime(); + if(time > lasttime) + busytime_u32 = time - lasttime; + else + busytime_u32 = 0; + busytime = busytime_u32 / 1000.0; + + // FPS limiter + u32 frametime_min = 1000./fps_max; + + if(busytime_u32 < frametime_min) { + u32 sleeptime = frametime_min - busytime_u32; + device->sleep(sleeptime); + } + } else { + sleep_ms(25); + } } - - // Break out of menu-game loop to shut down cleanly - if(device->run() == false || kill == true) - break; - + sound->stopSound(handle); + if(sound != &dummySoundManager){ + delete sound; + sound = NULL; + } + + // Save controls status + menu->readInput(&menudata); + infostream<<"Dropping main menu"<drop(); } - // Set world path to selected one - if(menudata.selected_world != -1){ - worldspec = worldspecs[menudata.selected_world]; - infostream<<"Selected world: "<setS32("selected_mainmenu_tab", menudata.selected_tab); + g_settings->setS32("selected_serverlist", menudata.selected_serverlist); + g_settings->set("selected_mainmenu_game", menudata.selected_game); g_settings->set("new_style_leaves", itos(menudata.fancy_trees)); g_settings->set("smooth_lighting", itos(menudata.smooth_lighting)); g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d)); g_settings->set("opaque_water", itos(menudata.opaque_water)); + + g_settings->set("mip_map", itos(menudata.mip_map)); + g_settings->set("anisotropic_filter", itos(menudata.anisotropic_filter)); + g_settings->set("bilinear_filter", itos(menudata.bilinear_filter)); + g_settings->set("trilinear_filter", itos(menudata.trilinear_filter)); + + g_settings->setS32("enable_shaders", menudata.enable_shaders); + g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals)); + g_settings->set("enable_particles", itos(menudata.enable_particles)); + g_settings->set("liquid_finite", itos(menudata.liquid_finite)); + g_settings->set("creative_mode", itos(menudata.creative_mode)); g_settings->set("enable_damage", itos(menudata.enable_damage)); + g_settings->set("server_announce", itos(menudata.enable_public)); g_settings->set("name", playername); g_settings->set("address", address); g_settings->set("port", itos(port)); if(menudata.selected_world != -1) g_settings->set("selected_world_path", worldspecs[menudata.selected_world].path); - // Update configuration file - if(configpath != "") - g_settings->updateConfigFile(configpath.c_str()); + + // Break out of menu-game loop to shut down cleanly + if(device->run() == false || kill == true) + break; + + current_playername = playername; + current_password = password; + current_address = address; + current_port = port; + + // If using simple singleplayer mode, override + if(simple_singleplayer_mode){ + current_playername = "singleplayer"; + current_password = ""; + current_address = ""; + current_port = 30011; + } + else if (address != "") + { + ServerListSpec server; + server["name"] = menudata.servername; + server["address"] = wide_to_narrow(menudata.address); + server["port"] = wide_to_narrow(menudata.port); + server["description"] = menudata.serverdescription; + ServerList::insert(server); + } + // Set world path to selected one + if(menudata.selected_world != -1){ + worldspec = worldspecs[menudata.selected_world]; + infostream<<"Selected world: "<set("selected_world_path", path); + g_settings->set("selected_mainmenu_game", menudata.create_world_gameid); + continue; + } + // If local game - if(address == "") + if(current_address == "") { if(menudata.selected_world == -1){ - error_message = L"No world selected and no address " - L"provided. Nothing to do."; + error_message = wgettext("No world selected and no address " + "provided. Nothing to do."); errorstream<run() == false || kill == true) break; - + /* Run game */ @@ -1459,36 +2098,28 @@ int main(int argc, char *argv[]) device, font, worldspec.path, - playername, - password, - address, - port, + current_playername, + current_password, + current_address, + current_port, error_message, configpath, chat_backend, - gamespec + gamespec, + simple_singleplayer_mode ); + smgr->clear(); } //try catch(con::PeerNotFoundException &e) { - error_message = L"Connection error (timed out?)"; - errorstream<drop(); + g_menucloudsmgr->drop(); + delete input; /* @@ -1515,6 +2150,10 @@ int main(int argc, char *argv[]) */ device->drop(); +#if USE_FREETYPE + font->drop(); +#endif + #endif // !SERVER // Update configuration file