/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola Copyright (C) 2013 Kahrl 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 "shader.h" #include "irrlichttypes_extrabloated.h" #include "debug.h" #include "main.h" // for g_settings #include "filesys.h" #include "util/container.h" #include "util/thread.h" #include "settings.h" #include #include #include #include #include #include #include "EShaderTypes.h" #include "log.h" #include "gamedef.h" #include "strfnd.h" // trim() #include "tile.h" /* A cache from shader name to shader path */ MutexedMap g_shadername_to_path_cache; /* Gets the path to a shader by first checking if the file name_of_shader/filename exists in shader_path and if not, using the data path. If not found, returns "". Utilizes a thread-safe cache. */ std::string getShaderPath(const std::string &name_of_shader, const std::string &filename) { std::string combined = name_of_shader + DIR_DELIM + filename; std::string fullpath = ""; /* Check from cache */ bool incache = g_shadername_to_path_cache.get(combined, &fullpath); if(incache) return fullpath; /* Check from shader_path */ std::string shader_path = g_settings->get("shader_path"); if(shader_path != "") { std::string testpath = shader_path + DIR_DELIM + combined; if(fs::PathExists(testpath)) fullpath = testpath; } /* Check from default data directory */ if(fullpath == "") { std::string rel_path = std::string("client") + DIR_DELIM + "shaders" + DIR_DELIM + name_of_shader + DIR_DELIM + filename; std::string testpath = porting::path_share + DIR_DELIM + rel_path; if(fs::PathExists(testpath)) fullpath = testpath; } // Add to cache (also an empty result is cached) g_shadername_to_path_cache.set(combined, fullpath); // Finally return it return fullpath; } /* SourceShaderCache: A cache used for storing source shaders. */ class SourceShaderCache { public: void insert(const std::string &name_of_shader, const std::string &filename, const std::string &program, bool prefer_local) { std::string combined = name_of_shader + DIR_DELIM + filename; // Try to use local shader instead if asked to if(prefer_local){ std::string path = getShaderPath(name_of_shader, filename); if(path != ""){ std::string p = readFile(path); if(p != ""){ m_programs[combined] = p; return; } } } m_programs[combined] = program; } std::string get(const std::string &name_of_shader, const std::string &filename) { std::string combined = name_of_shader + DIR_DELIM + filename; std::map::iterator n; n = m_programs.find(combined); if(n != m_programs.end()) return n->second; return ""; } // Primarily fetches from cache, secondarily tries to read from filesystem std::string getOrLoad(const std::string &name_of_shader, const std::string &filename) { std::string combined = name_of_shader + DIR_DELIM + filename; std::map::iterator n; n = m_programs.find(combined); if(n != m_programs.end()) return n->second; std::string path = getShaderPath(name_of_shader, filename); if(path == ""){ infostream<<"SourceShaderCache::getOrLoad(): No path found for \"" < m_programs; std::string readFile(const std::string &path) { std::ifstream is(path.c_str(), std::ios::binary); if(!is.is_open()) return ""; std::ostringstream tmp_os; tmp_os << is.rdbuf(); return tmp_os.str(); } }; /* ShaderCallback: Sets constants that can be used in shaders */ class IShaderConstantSetterRegistry { public: virtual ~IShaderConstantSetterRegistry(){}; virtual void onSetConstants(video::IMaterialRendererServices *services, bool is_highlevel, const std::string &name) = 0; }; class ShaderCallback : public video::IShaderConstantSetCallBack { IShaderConstantSetterRegistry *m_scsr; std::string m_name; public: ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name): m_scsr(scsr), m_name(name) {} ~ShaderCallback() {} virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) { video::IVideoDriver *driver = services->getVideoDriver(); assert(driver); bool is_highlevel = userData; m_scsr->onSetConstants(services, is_highlevel, m_name); } }; /* MainShaderConstantSetter: Set basic constants required for almost everything */ class MainShaderConstantSetter : public IShaderConstantSetter { public: MainShaderConstantSetter(IrrlichtDevice *device) {} ~MainShaderConstantSetter() {} virtual void onSetConstants(video::IMaterialRendererServices *services, bool is_highlevel) { video::IVideoDriver *driver = services->getVideoDriver(); assert(driver); // set inverted world matrix core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD); invWorld.makeInverse(); if(is_highlevel) services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16); else services->setVertexShaderConstant(invWorld.pointer(), 0, 4); // set clip matrix core::matrix4 worldViewProj; worldViewProj = driver->getTransform(video::ETS_PROJECTION); worldViewProj *= driver->getTransform(video::ETS_VIEW); worldViewProj *= driver->getTransform(video::ETS_WORLD); if(is_highlevel) services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16); else services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4); // set transposed world matrix core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD); transWorld = transWorld.getTransposed(); if(is_highlevel) services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16); else services->setVertexShaderConstant(transWorld.pointer(), 8, 4); // set world matrix core::matrix4 world = driver->getTransform(video::ETS_WORLD); if(is_highlevel) services->setVertexShaderConstant("mWorld", world.pointer(), 16); else services->setVertexShaderConstant(world.pointer(), 8, 4); } }; /* ShaderSource */ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry { public: ShaderSource(IrrlichtDevice *device); ~ShaderSource(); /* - If shader material specified by name is found from cache, return the cached id. - Otherwise generate the shader material, add to cache and return id. The id 0 points to a null shader. Its material is EMT_SOLID. */ u32 getShaderIdDirect(const std::string &name, const u8 material_type, const u8 drawtype); /* If shader specified by the name pointed by the id doesn't exist, create it, then return id. Can be called from any thread. If called from some other thread and not found in cache, the call is queued to the main thread for processing. */ u32 getShader(const std::string &name, const u8 material_type, const u8 drawtype); ShaderInfo getShaderInfo(u32 id); // Processes queued shader requests from other threads. // Shall be called from the main thread. void processQueue(); // Insert a shader program into the cache without touching the // filesystem. Shall be called from the main thread. void insertSourceShader(const std::string &name_of_shader, const std::string &filename, const std::string &program); // Rebuild shaders from the current set of source shaders // Shall be called from the main thread. void rebuildShaders(); void addGlobalConstantSetter(IShaderConstantSetter *setter) { m_global_setters.push_back(setter); } void onSetConstants(video::IMaterialRendererServices *services, bool is_highlevel, const std::string &name); private: // The id of the thread that is allowed to use irrlicht directly threadid_t m_main/* Part of Minetest Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013 Ciaran Gultnieks <ciaran@ciarang.com> Copyright (C) 2013 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl> Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "guiVolumeChange.h" #include "debug.h" #include "serialization.h" #include <string> #include <IGUICheckBox.h> #include <IGUIButton.h> #include <IGUIScrollBar.h> #include <IGUIStaticText.h> #include <IGUIFont.h> #include "main.h" #include "settings.h" #include "gettext.h" const int ID_soundText1 = 263; const int ID_soundText2 = 264; const int ID_soundExitButton = 265; const int ID_soundSlider = 266; GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, Client* client ): GUIModalMenu(env, parent, id, menumgr) { } GUIVolumeChange::~GUIVolumeChange() { removeChildren(); } void GUIVolumeChange::removeChildren() { { gui::IGUIElement *e = getElementFromId(ID_soundText1); if(e != NULL) e->remove(); } { gui::IGUIElement *e = getElementFromId(ID_soundText2); if(e != NULL) e->remove(); } { gui::IGUIElement *e = getElementFromId(ID_soundExitButton); if(e != NULL) e->remove(); } { gui::IGUIElement *e = getElementFromId(ID_soundSlider); if(e != NULL) e->remove(); } } void GUIVolumeChange::regenerateGui(v2u32 screensize) { /* Remove stuff */ removeChildren(); /* Calculate new sizes and positions */ core::rect<s32> rect( screensize.X/2 - 380/2, screensize.Y/2 - 200/2, screensize.X/2 + 380/2, screensize.Y/2 + 200/2 ); DesiredRect = rect; recalculateAbsolutePosition(false); v2s32 size = rect.getSize(); v2s32 topleft_client(40, 0); int volume=(int)(g_settings->getFloat("sound_volume")*100); /* Add stuff */ { core::rect<s32> rect(0, 0, 120, 20); rect = rect + v2s32(size.X/2-60, size.Y/2-35); wchar_t* text = wgettext("Sound Volume: "); Environment->addStaticText(text, rect, false, true, this, ID_soundText1); delete[] text; } { core::rect<s32> rect(0, 0, 30, 20); rect = rect + v2s32(size.X/2+40, size.Y/2-35); Environment->addStaticText(core::stringw(volume).c_str(), rect, false, true, this, ID_soundText2); } { core::rect<s32> rect(0, 0, 80, 30); rect = rect + v2s32(size.X/2-80/2, size.Y/2+55); wchar_t* text = wgettext("Exit"); Environment->addButton(rect, this, ID_soundExitButton, text); delete[] text; } { core::rect<s32> rect(0, 0, 300, 20); rect = rect + v2s32(size.X/2-150, size.Y/2); gui::IGUIScrollBar *e = Environment->addScrollBar(true,