code:
// This file is automatically generated
// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files
// To update it, refer to the bottom of builtin/mainmenu/dlg_settings_advanced.lua

fake_function() {
	gettext("Client");
	gettext("Controls");
	gettext("Build inside player");
	gettext("If enabled, you can place blocks at the position (feet + eye level) where you stand.\nThis is helpful when working with nodeboxes in small areas.");
	gettext("Flying");
	gettext("Player is able to fly without being affected by gravity.\nThis requires the \"fly\" privilege on the server.");
	gettext("Fast movement");
	gettext("Fast movement (via use key).\nThis requires the \"fast\" privilege on the server.");
	gettext("Noclip");
	gettext("If enabled together with fly mode, player is able to fly through solid nodes.\nThis requires the \"noclip\" privilege on the server.");
	gettext("Cinematic mode");
	gettext("Smooths camera when looking around. Also called look or mouse smoothing.\nUseful for recording videos.");
	gettext("Camera smoothing");
	gettext("Smooths rotation of camera. 0 to disable.");
	gettext("Camera smoothing in cinematic mode");
	gettext("Smooths rotation of camera in cinematic mode. 0 to disable.");
	gettext("Invert mouse");
	gettext("Invert vertical mouse movement.");
	gettext("Mouse sensitivity");
	gettext("Mouse sensitivity multiplier.");
	gettext("Key use for climbing/descending");
	gettext("If enabled, \"use\" key instead of \"sneak\" key is used for climbing down and descending.");
	gettext("Double tap jump for fly");
	gettext("Double-tapping the jump key toggles fly mode.");
	gettext("Always fly and fast");
	gettext("If disabled \"use\" key is used to fly fast if both fly and fast mode are enabled.");
	gettext("Rightclick repetition interval");
	gettext("The time in seconds it takes between repeated right clicks when holding the right mouse button.");
	gettext("Random input");
	gettext("Enable random user input (only used for testing).");
	gettext("Continuous forward");
	gettext("Continuous forward movement, toggled by autoforward key.");
	gettext("Enable Joysticks");
	gettext("Enable Joysticks");
	gettext("Joystick ID");
	gettext("The identifier of the joystick to use");
	gettext("Joystick Type");
	gettext("The type of joystick");
	gettext("Joystick button repetition interval");
	gettext("The time in seconds it takes between repeated events\nwhen holding down a joystick button combination.");
	gettext("Joystick frustum sensitivity");
	gettext("The sensitivity of the joystick axes for moving the\ningame view frustum around.");
	gettext("Forward key");
	gettext("Key for moving the player forward.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Backward key");
	gettext("Key for moving the player backward.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Left key");
	gettext("Key for moving the player left.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Right key");
	gettext("Key for moving the player right.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Jump key");
	gettext("Key for jumping.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Sneak key");
	gettext("Key for sneaking.\nAlso used for climbing down and descending in water if aux1_descends is disabled.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Inventory key");
	gettext("Key for opening the inventory.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Use key");
	gettext("Key for moving fast in fast mode.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Chat key");
	gettext("Key for opening the chat window.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Command key");
	gettext("Key for opening the chat window to type commands.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Command key");
	gettext("Key for opening the chat window to type local commands.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Console key");
	gettext("Key for opening the chat console.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Range select key");
	gettext("Key for toggling unlimited view range.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Fly key");
	gettext("Key for toggling flying.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Fast key");
	gettext("Key for toggling fast mode.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Noclip key");
	gettext("Key for toggling noclip mode.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Hotbar next key");
	gettext("Key for selecting the next item in the hotbar.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Hotbar previous key");
	gettext("Key for selecting the previous item in the hotbar.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Mute key");
	gettext("Key for muting the game.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Inc. volume key");
	gettext("Key for increasing the volume.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Dec. volume key");
	gettext("Key for decreasing the volume.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Autoforward key");
	gettext("Key for toggling autoforward.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Cinematic mode key");
	gettext("Key for toggling cinematic mode.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Minimap key");
	gettext("Key for toggling display of minimap.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Screenshot");
	gettext("Key for taking screenshots.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Drop item key");
	gettext("Key for dropping the currently selected item.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("View zoom key");
	gettext("Key to use view zoom when possible.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("HUD toggle key");
	gettext("Key for toggling the display of the HUD.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Chat toggle key");
	gettext("Key for toggling the display of the chat.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Large chat console key");
	gettext("Key for toggling the display of the large chat console.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Fog toggle key");
	gettext("Key for toggling the display of the fog.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Camera update toggle key");
	gettext("Key for toggling the camera update. Only used for development\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Debug info toggle key");
	gettext("Key for toggling the display of debug info.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Profiler toggle key");
	gettext("Key for toggling the display of the profiler. Used for development.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Toggle camera mode key");
	gettext("Key for switching between first- and third-person camera.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("View range increase key");
	gettext("Key for increasing the viewing range.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("View range decrease key");
	gettext("Key for decreasing the viewing range.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Print stacks");
	gettext("Key for printing debug stacks. Used for development.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
	gettext("Network");
	gettext("Server address");
	gettext("Address to connect to.\nLeave this blank to start a local server.\nNote that the address field in the main menu overrides this setting.");
	gettext("Remote port");
	gettext("Port to connect to (UDP).\nNote that the port field in the main menu overrides this setting.");
	gettext("Support older servers");
	gettext("Whether to support older servers before protocol version 25.\nEnable if you want to connect to 0.4.12 servers and before.\nServers starting with 0.4.13 will work, 0.4.12-dev servers may work.\nDisabling this option will protect your password better.");
	gettext("Saving map received from server");
	gettext("Save the map received by the client on disk.");
	gettext("Show entity selection boxes");
	gettext("Show entity selection boxes");
	gettext("Connect to external media server");
	gettext("Enable usage of remote media server (if provided by server).\nRemote servers offer a significantly faster way to download media (e.g. textures)\nwhen connecting to the server.");
	gettext("Client modding");
	gettext("Enable Lua modding support on client.\nThis support is experimental and API can change.");
	gettext("Serverlist URL");
	gettext("URL to the server list displayed in the Multiplayer Tab.");
	gettext("Serverlist file");
	gettext("File in client/serverlist/ that contains your favorite servers displayed in the Multiplayer Tab.");
	gettext("Graphics");
	gettext("In-Game");
	gettext("Basic");
	gettext("VBO");
	gettext("Enable VBO");
	gettext("Fog");
	gettext("Whether to fog out the end of the visible area.");
	gettext("Leaves style");
	gettext("Leaves style:\n-   Fancy:  all faces visible\n-   Simple: only outer faces, if defined special_tiles are used\n-   Opaque: disable transparency");
	gettext("Connect glass");
	gettext("Connects glass if supported by node.");
	gettext("Smooth lighting");
	gettext("Enable smooth lighting with simple ambient occlusion.\nDisable for speed or for different looks.");
	gettext("Clouds");
	gettext("Clouds are a client side effect.");
	gettext("3D clouds");
	gettext("Use 3D cloud look instead of flat.");
	gettext("Node highlighting");
	gettext("Method used to highlight selected object.");
	gettext("Digging particles");
	gettext("Adds particles when digging a node.");
	gettext("Filtering");
	gettext("Mipmapping");
	gettext("Use mip mapping to scale textures. May slightly increase performance.");
	gettext("Anisotropic filtering");
	gettext("Use anisotropic filtering when viewing at textures from an angle.");
	gettext("Bilinear filtering");
	gettext("Use bilinear filtering when scaling textures.");
	gettext("Trilinear filtering");
	gettext("Use trilinear filtering when scaling textures.");
	gettext("Clean transparent textures");
	gettext("Filtered textures can blend RGB values with fully-transparent neighbors,\nwhich PNG optimizers usually discard, sometimes resulting in a dark or\nlight edge to transparent textures.  Apply this filter to clean that up\nat texture load time.");
	gettext("Minimum texture size for filters");
	gettext("When using bilinear/trilinear/anisotropic filters, low-resolution textures\ncan be blurred, so automatically upscale them with nearest-neighbor\ninterpolation to preserve crisp pixels.  This sets the minimum texture size\nfor the upscaled textures; higher values look sharper, but require more\nmemory.  Powers of 2 are recommended.  Setting this higher than 1 may not\nhave a visible effect unless bilinear/trilinear/anisotropic filtering is\nenabled.");
	gettext("FSAA");
	gettext("Experimental option, might cause visible spaces between blocks\nwhen set to higher number than 0.");
	gettext("Undersampling");
	gettext("Undersampling is similar to using lower screen resolution, but it applies\nto the game world only, keeping the GUI intact.\nIt should give significant performance boost at the cost of less detailed image.");
	gettext("Shaders");
	gettext("Shaders");
	gettext("Shaders allow advanced visual effects and may increase performance on some video cards.\nThis only works with the OpenGL video backend.");
	gettext("Shader path");
	gettext("Path to shader directory. If no path is defined, default location will be used.");
	gettext("Tone Mapping");
	gettext("Filmic tone mapping");
	gettext("Enables filmic tone mapping");
	gettext("Bumpmapping");
	gettext("Bumpmapping");
	gettext("Enables bumpmapping for textures. Normalmaps need to be supplied by the texture pack\nor need to be auto-generated.\nRequires shaders to be enabled.");
	gettext("Generate normalmaps");
	gettext("Enables on the fly normalmap generation (Emboss effect).\nRequires bumpmapping to be enabled.");
	gettext("Normalmaps strength");
	gettext("Strength of generated normalmaps.");
	gettext("Normalmaps sampling");
	gettext("Defines sampling step of texture.\nA higher value results in smoother normal maps.");
	gettext("Parallax Occlusion");
	gettext("Parallax occlusion");
	gettext("Enables parallax occlusion mapping.\nRequires shaders to be enabled.");
	gettext("Parallax occlusion mode");
	gettext("0 = parallax occlusion with slope information (faster).\n1 = relief mapping (slower, more accurate).");
	gettext("Parallax occlusion strength");
	gettext("Strength of parallax.");
	gettext("Parallax occlusion iterations");
	gettext("Number of parallax occlusion iterations.");
	gettext("Parallax occlusion Scale");
	gettext("Overall scale of parallax occlusion effect.");
	gettext("Parallax occlusion bias");
	gettext("Overall bias of parallax occlusion effect, usually scale/2.");
	gettext("Waving Nodes");
	gettext("Waving water");
	gettext("Set to true enables waving water.\nRequires shaders to be enabled.");
	gettext("Waving water height");
	gettext("Waving water length");
	gettext("Waving water speed");
	gettext("Waving leaves");
	gettext("Set to true enables waving leaves.\nRequires shaders to be enabled.");
	gettext("Waving plants");
	gettext("Set to true enables waving plants.\nRequires shaders to be enabled.");
	gettext("Advanced");
	gettext("Maximum FPS");
	gettext("If FPS would go higher than this, limit it by sleeping\nto not waste CPU power for no benefit.");
	gettext("FPS in pause menu");
	gettext("Maximum FPS when game is paused.");
	gettext("Viewing range");
	gettext("View distance in nodes.");
	gettext("Screen width");
	gettext("Width component of the initial window size.");
	gettext("Screen height");
	gettext("Height component of the initial window size.");
	gettext("Full screen");
	gettext("Fullscreen mode.");
	gettext("Full screen BPP");
	gettext("Bits per pixel (aka color depth) in fullscreen mode.");
	gettext("V-Sync");
	gettext("Vertical screen synchronization.");
	gettext("Field of view");
	gettext("Field of view in degrees.");
	gettext("Field of view for zoom");
	gettext("Field of view while zooming in degrees.\nThis requires the \"zoom\" privilege on the server.");
	gettext("Gamma");
	gettext("Adjust the gamma encoding for the light tables. Higher numbers are brighter.\nThis setting is for the client only and is ignored by the server.");
	gettext("Texture path");
	gettext("Path to texture directory. All textures are first searched from here.");
	gettext("Video driver");
	gettext("The rendering back-end for Irrlicht.");
	gettext("Cloud height");
	gettext("Height on which clouds are appearing.");
	gettext("Cloud radius");
	gettext("Radius of cloud area stated in number of 64 node cloud squares.\nValues larger than 26 will start to produce sharp cutoffs at cloud area corners.");
	gettext("Enable view bobbing");
	gettext("Enables view bobbing when walking.");
	gettext("View bobbing factor");
	gettext("Enable view bobbing and amount of view bobbing.\nFor example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.");
	gettext("Fall bobbing factor");
	gettext("Multiplier for fall bobbing.\nFor example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.");
	gettext("3D mode");
	gettext("3D support.\nCurrently supported:\n-    none: no 3d output.\n-    anaglyph: cyan/magenta color 3d.\n-    interlaced: odd/even line based polarisation screen support.\n-    topbottom: split screen top/bottom.\n-    sidebyside: split screen side by side.\n-    pageflip: quadbuffer based 3d.");
	gettext("Console height");
	gettext("In-game chat console height, between 0.1 (10%) and 1.0 (100%).");
	gettext("Console color");
	gettext("In-game chat console background color (R,G,B).");
	gettext("Console alpha");
	gettext("In-game chat console background alpha (opaqueness, between 0 and 255).");
	gettext("Selection box color");
	gettext("Selection box border color (R,G,B).");
	gettext("Selection box width");
	gettext("Width of the selectionbox's lines around nodes.");
	gettext("Crosshair color");
	gettext("Crosshair color (R,G,B).");
	gettext("Crosshair alpha");
	gettext("Crosshair alpha (opaqueness, between 0 and 255).");
	gettext("Desynchronize block animation");
	gettext("Whether node texture animations should be desynchronized per mapblock.");
	gettext("Maximum hotbar width");
	gettext("Maximum proportion of current window to be used for hotbar.\nUseful if there's something to be displayed right or left of hotbar.");
	gettext("HUD scale factor");
	gettext("Modifies the size of the hudbar elements.");
	gettext("Mesh cache");
	gettext("Enables caching of facedir rotated meshes.");
	gettext("Mapblock mesh generation delay");
	gettext("Delay between mesh updates on the client in ms. Increasing this will slow\ndown the rate of mesh updates, thus reducing jitter on slower clients.");
	gettext("Mapblock mesh generator's MapBlock cache size MB");
	gettext("Size of the MapBlock cache of the mesh generator. Increasing this will\nincrease the cache hit %, reducing the data being copied from the main\nthread, thus reducing jitter.");
	gettext("Minimap");
	gettext("Enables minimap.");
	gettext("Round minimap");
	gettext("Shape of the minimap. Enabled = round, disabled = square.");
	gettext("Minimap scan height");
	gettext("True = 256\nFalse = 128\nUseable to make minimap smoother on slower machines.");
	gettext("Colored fog");
	gettext("Make fog and sky colors depend on daytime (dawn/sunset) and view direction.");
	gettext("Ambient occlusion gamma");
	gettext("The strength (darkness) of node ambient-occlusion shading.\nLower is darker, Higher is lighter. The valid range of values for this\nsetting is 0.25 to 4.0 inclusive. If the value is out of range it will be\nset to the nearest valid value.");
	gettext("Inventory items animations");
	gettext("Enables animation of inventory items.");
	gettext("Inventory image hack");
	gettext("Android systems only: Tries to create inventory textures from meshes\nwhen no supported render was found.");
	gettext("Fog Start");
	gettext("Fraction of the visible distance at which fog starts to be rendered");
	gettext("Opaque liquids");
	gettext("Makes all liquids opaque");
	gettext("Menus");
	gettext("Clouds in menu");
	gettext("Use a cloud animation for the main menu background.");
	gettext("GUI scaling");
	gettext("Scale gui by a user specified value.\nUse a nearest-neighbor-anti-alias filter to scale the GUI.\nThis will smooth over some of the rough edges, and blend\npixels when scaling down, at the cost of blurring some\nedge pixels when images are scaled by non-integer sizes.");
	gettext("GUI scaling filter");
	gettext("When gui_scaling_filter is true, all GUI images need to be\nfiltered in software, but some images are generated directly\nto hardware (e.g. render-to-texture for nodes in inventory).");
	gettext("GUI scaling filter txr2img");
	gettext("When gui_scaling_filter_txr2img is true, copy those images\nfrom hardware to software for scaling.  When false, fall back\nto the old scaling method, for video drivers that don't\nproperly support downloading textures back from hardware.");
	gettext("Tooltip delay");
	gettext("Delay showing tooltips, stated in milliseconds.");
	gettext("Freetype fonts");
	gettext("Whether freetype fonts are used, requires freetype support to be compiled in.");
	gettext("Font path");
	gettext("Path to TrueTypeFont or bitmap.");
	gettext("Font size");
	gettext("Font shadow");
	gettext("Font shadow offset, if 0 then shadow will not be drawn.");
	gettext("Font shadow alpha");
	gettext("Font shadow alpha (opaqueness, between 0 and 255).");
	gettext("Monospace font path");
	gettext("Monospace font size");
	gettext("Fallback font");
	gettext("This font will be used for certain languages.");
	gettext("Fallback font size");
	gettext("Fallback font shadow");
	gettext("Fallback font shadow alpha");
	gettext("Screenshot folder");
	gettext("Path to save screenshots at.");
	gettext("Screenshot format");
	gettext("Format of screenshots.");
	gettext("Screenshot quality");
	gettext("Screenshot quality. Only used for JPEG format.\n1 means worst quality; 100 means best quality.\nUse 0 for default quality.");
	gettext("Advanced");
	gettext("DPI");
	gettext("Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.");
	gettext("Enable console window");
	gettext("Windows systems only: Start Minetest with the command line window in the background.\nContains the same information as the file debug.txt (default name).");
	gettext("Sound");
	gettext("Sound");
	gettext("Volume");
	gettext("Advanced");
	gettext("Mapblock unload timeout");
	gettext("Timeout for client to remove unused map data from memory.");
	gettext("Mapblock limit");
	gettext("Maximum number of mapblocks for client to be kept in memory.\nSet to -1 for unlimited amount.");
	gettext("Show debug info");
	gettext("Whether to show the client debug info (has the same effect as hitting F5).");
	gettext("Server / Singleplayer");
	gettext("Server name");
	gettext("Name of the server, to be displayed when players join and in the serverlist.");
	gettext("Server description");
	gettext("Description of server, to be displayed when players join and in the serverlist.");
	gettext("Server address");
	gettext("Domain name of server, to be displayed in the serverlist.");
	gettext("Server URL");
	gettext("Homepage of server, to be displayed in the serverlist.");
	gettext("Announce server");
	gettext("Automaticaly report to the serverlist.");
	gettext("Serverlist URL");
	gettext("Announce to this serverlist.\nIf you want to announce your ipv6 address, use  serverlist_url = v6.servers.minetest.net.");
	gettext("Strip color codes");
	gettext("Remove color codes from incoming chat messages\nUse this to stop players from being able to use color in their messages");
	gettext("Network");
	gettext("Server port");
	gettext("Network port to listen (UDP).\nThis value will be overridden when starting from the main menu.");
	gettext("Bind address");
	gettext("The network interface that the server listens on.");
	gettext("Strict protocol checking");
	gettext("Enable to disallow old clients from connecting.\nOlder clients are compatible in the sense that they will not crash when connecting\nto new servers, but they may not support all new features that you are expecting.");
	gettext("Remote media");
	gettext("Specifies URL from which client fetches media instead of using UDP.\n$filename should be accessible from $remote_media$filename via cURL\n(obviously, remote_media should end with a slash).\nFiles that are not present will be fetched the usual way.");
	gettext("IPv6 server");
	gettext("Enable/disable running an IPv6 server.  An IPv6 server may be restricted\nto IPv6 clients, depending on system configuration.\nIgnored if bind_address is set.");
	gettext("Advanced");
	gettext("Maximum simultaneous block sends per client");
	gettext("Maximum number of blocks that are simultaneously sent per client.");
	gettext("Maximum simultaneous block sends total");
	gettext("Maximum number of blocks that are simultaneously sent in total.");
	gettext("Delay in sending blocks after building");
	gettext("To reduce lag, block transfers are slowed down when a player is building something.\nThis determines how long they are slowed down after placing or removing a node.");
	gettext("Max. packets per iteration");
	gettext("Maximum number of packets sent per send step, if you have a slow connection\ntry reducing it, but don't reduce it to a number below double of targeted\nclient number.");
	gettext("Game");
	gettext("Default game");
	gettext("Default game when creating a new world.\nThis will be overridden when creating a world from the main menu.");
	gettext("Message of the day");
	gettext("Message of the day displayed to players connecting.");
	gettext("Maximum users");
	gettext("Maximum number of players that can connect simultaneously.");
	gettext("Map directory");
	gettext("World directory (everything in the world is stored here).\nNot needed if starting from the main menu.");
	gettext("Item entity TTL");
	gettext("Time in seconds for item entity (dropped items) to live.\nSetting it to -1 disables the feature.");
	gettext("Status message on connection");
	gettext("If enabled, show the server status message on player connection.");
	gettext("Damage");
	gettext("Enable players getting damage and dying.");
	gettext("Creative");
	gettext("Enable creative mode for new created maps.");
	gettext("Fixed map seed");
	gettext("A chosen map seed for a new map, leave empty for random.\nWill be overridden when creating a new world in the main menu.");
	gettext("Default password");
	gettext("New users need to input this password.");
	gettext("Default privileges");
	gettext("The privileges that new users automatically get.\nSee /privs in game for a full list on your server and mod configuration.");
	gettext("Basic Privileges");
	gettext("Privileges that players with basic_privs can grant");
	gettext("Unlimited player transfer distance");
	gettext("Whether players are shown to clients without any range limit.\nDeprecated, use the setting player_transfer_distance instead.");
	gettext("Player transfer distance");
	gettext("Defines the maximal player transfer distance in blocks (0 = unlimited).");
	gettext("Player versus Player");
	gettext("Whether to allow players to damage and kill each other.");
	gettext("Static spawnpoint");
	gettext("If this is set, players will always (re)spawn at the given position.");
	gettext("Disallow empty passwords");
	gettext("If enabled, new players cannot join with an empty password.");
	gettext("Disable anticheat");
	gettext("If enabled, disable cheat prevention in multiplayer.");
	gettext("Rollback recording");
	gettext("If enabled, actions are recorded for rollback.\nThis option is only read when server starts.");
	gettext("Shutdown message");
	gettext("A message to be displayed to all clients when the server shuts down.");
	gettext("Crash message");
	gettext("A message to be displayed to all clients when the server crashes.");
	gettext("Ask to reconnect after crash");
	gettext("Whether to ask clients to reconnect after a (Lua) crash.\nSet this to true if your server is set up to restart automatically.");
	gettext("Active object send range");
	gettext("From how far clients know about objects, stated in mapblocks (16 nodes).");
	gettext("Active block range");
	gettext("How large area of blocks are subject to the active block stuff, stated in mapblocks (16 nodes).\nIn active blocks objects are loaded and ABMs run.");
	gettext("Max block send distance");
	gettext("From how far blocks are sent to clients, stated in mapblocks (16 nodes).");
	gettext("Maximum forceloaded blocks");
	gettext("Maximum number of forceloaded mapblocks.");
	gettext("Time send interval");
	gettext("Interval of sending time of day to clients.");
	gettext("Time speed");
	gettext("Controls length of day/night cycle.\nExamples: 72 = 20min, 360 = 4min, 1 = 24hour, 0 = day/night/whatever stays unchanged.");
	gettext("Map save interval");
	gettext("Interval of saving important changes in the world, stated in seconds.");
	gettext("Physics");
	gettext("Default acceleration");
	gettext("Acceleration in air");
	gettext("Fast mode acceleration");
	gettext("Walking speed");
	gettext("Crouch speed");
	gettext("Fast mode speed");
	gettext("Climbing speed");
	gettext("Jumping speed");
	gettext("Descending speed");
	gettext("Liquid fluidity");
	gettext("Liquid fluidity smoothing");
	gettext("Liquid sink");
	gettext("Gravity");
	gettext("Advanced");
	gettext("Deprecated Lua API handling");
	gettext("Handling for deprecated lua api calls:\n-    legacy: (try to) mimic old behaviour (default for release).\n-    log: mimic and log backtrace of deprecated call (default for debug).\n-    error: abort on usage of deprecated call (suggested for mod developers).");
	gettext("Max. clearobjects extra blocks");
	gettext("Number of extra blocks that can be loaded by /clearobjects at once.\nThis is a trade-off between sqlite transaction overhead and\nmemory consumption (4096=100MB, as a rule of thumb).");
	gettext("Unload unused server data");
	gettext("How much the server will wait before unloading unused mapblocks.\nHigher value is smoother, but will use more RAM.");
	gettext("Maximum objects per block");
	gettext("Maximum number of statically stored objects in a block.");
	gettext("Synchronous SQLite");
	gettext("See http://www.sqlite.org/pragma.html#pragma_synchronous");
	gettext("Dedicated server step");
	gettext("Length of a server tick and the interval at which objects are generally updated over network.");
	gettext("Active Block Management interval");
	gettext("Time in between active block management cycles");
	gettext("Active Block Modifier interval");
	gettext("Length of time between ABM execution cycles");
	gettext("NodeTimer interval");
	gettext("Length of time between NodeTimer execution cycles");
	gettext("Ignore world errors");
	gettext("If enabled, invalid world data won't cause the server to shut down.\nOnly enable this if you know what you are doing.");
	gettext("Liquid loop max");
	gettext("Max liquids processed per step.");
	gettext("Liquid queue purge time");
	gettext("The time (in seconds) that the liquids queue may grow beyond processing\ncapacity until an attempt is made to decrease its size by dumping old queue\nitems.  A value of 0 disables the functionality.");
	gettext("Liquid update tick");
	gettext("Liquid update interval in seconds.");
	gettext("block send optimize distance");
	gettext("At this distance the server will aggressively optimize which blocks are sent to clients.\nSmall values potentially improve performance a lot, at the expense of visible rendering glitches.\n(some blocks will not be rendered under water and in caves, as well as sometimes on land)\nSetting this to a value greater than max_block_send_distance disables this optimization.\nStated in mapblocks (16 nodes)");
	gettext("Server side occlusion culling");
	gettext("If enabled the server will perform map block occlusion culling based on\non the eye position of the player. This can reduce the number of blocks\nsent to the client 50-80%. The client will not longer receive most invisible\nso that the utility of noclip mode is reduced.");
	gettext("Mapgen");
	gettext("Mapgen name");
	gettext("Name of map generator to be used when creating a new world.\nCreating a world in the main menu will override this.");
	gettext("Water level");
	gettext("Water surface level of the world.");
	gettext("Max block generate distance");
	gettext("From how far blocks are generated for clients, stated in mapblocks (16 nodes).");
	gettext("Map generation limit");
	gettext("Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).\nOnly mapchunks completely within the mapgen limit are generated.\nValue is stored per-world.");
	gettext("Mapgen flags");
	gettext("Global map generation attributes.\nIn Mapgen v6 the 'decorations' flag controls all decorations except trees\nand junglegrass, in all other mapgens this flag controls all decorations.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
	gettext("Advanced");
	gettext("Chunk size");
	gettext("Size of chunks to be generated at once by mapgen, stated in mapblocks (16 nodes).");
	gettext("Mapgen debug");
	gettext("Dump the mapgen debug infos.");
	gettext("Absolute limit of emerge queues");
	gettext("Maximum number of blocks that can be queued for loading.");
	gettext("Limit of emerge queues on disk");
	gettext("Maximum number of blocks to be queued that are to be loaded from file.\nSet to blank for an appropriate amount to be chosen automatically.");
	gettext("Limit of emerge queues to generate");
	gettext("Maximum number of blocks to be queued that are to be generated.\nSet to blank for an appropriate amount to be chosen automatically.");
	gettext("Number of emerge threads");
	gettext("Number of emerge threads to use. Make this field blank, or increase this number\nto use multiple threads. On multiprocessor systems, this will improve mapgen speed greatly\nat the cost of slightly buggy caves.");
	gettext("Biome API temperature and humidity noise parameters");
	gettext("Heat noise");
	gettext("Temperature variation for biomes.");
	gettext("Heat blend noise");
	gettext("Small-scale temperature variation for blending biomes on borders.");
	gettext("Humidity noise");
	gettext("Humidity variation for biomes.");
	gettext("Humidity blend noise");
	gettext("Small-scale humidity variation for blending biomes on borders.");
	gettext("Mapgen v5");
	gettext("Mapgen v5 specific flags");
	gettext("Map generation attributes specific to Mapgen v5.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
	gettext("Cave width");
	gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
	gettext("Cavern limit");
	gettext("Y-level of cavern upper limit.");
	gettext("Cavern taper");
	gettext("Y-distance over which caverns expand to full size.");
	gettext("Cavern threshold");
	gettext("Defines full size of caverns, smaller values create larger caverns.");
	gettext("Filler depth noise");
	gettext("Variation of biome filler depth.");
	gettext("Factor noise");
	gettext("Variation of terrain vertical scale.\nWhen noise is < -0.55 terrain is near-flat.");
	gettext("Height noise");
	gettext("Y-level of average terrain surface.");
	gettext("Cave1 noise");
	gettext("First of 2 3D noises that together define tunnels.");
	gettext("Cave2 noise");
	gettext("Second of 2 3D noises that together define tunnels.");
	gettext("Cavern noise");
	gettext("3D noise defining giant caverns.");
	gettext("Mapgen v6");
	gettext("Mapgen v6 specific flags");
	gettext("Map generation attributes specific to Mapgen v6.\nThe 'snowbiomes' flag enables the new 5 biome system.\nWhen the new biome system is enabled jungles are automatically enabled and\nthe 'jungles' flag is ignored.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
	gettext("Desert noise threshold");
	gettext("Deserts occur when np_biome exceeds this value.\nWhen the new biome system is enabled, this is ignored.");
	gettext("Beach noise threshold");
	gettext("Sandy beaches occur when np_beach exceeds this value.");
	gettext("Terrain base noise");
	gettext("Y-level of lower terrain and lakebeds.");
	gettext("Terrain higher noise");
	gettext("Y-level of higher (cliff-top) terrain.");
	gettext("Steepness noise");
	gettext("Varies steepness of cliffs.");
	gettext("Height select noise");
	gettext("Defines areas of 'terrain_higher' (cliff-top terrain).");
	gettext("Mud noise");
	gettext("Varies depth of biome surface nodes.");
	gettext("Beach noise");
	gettext("Defines areas with sandy beaches.");
	gettext("Biome noise");
	gettext("Temperature variation for biomes.");
	gettext("Cave noise");
	gettext("Variation of number of caves.");
	gettext("Humidity noise");
	gettext("Humidity variation for biomes.");
	gettext("Trees noise");
	gettext("Defines tree areas and tree density.");
	gettext("Apple trees noise");
	gettext("Defines areas where trees have apples.");
	gettext("Mapgen v7");
	gettext("Mapgen v7 specific flags");
	gettext("Map generation attributes specific to Mapgen v7.\nThe 'ridges' flag enables the rivers.\nFloatlands are currently experimental and subject to change.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
	gettext("Cave width");
	gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
	gettext("Floatland mountain density");
	gettext("Controls the density of floatland mountain terrain.\nIs an offset added to the 'np_mountain' noise value.");
	gettext("Floatland mountain height");
	gettext("Typical maximum height, above and below midpoint, of floatland mountain terrain.");
	gettext("Floatland level");
	gettext("Y-level of floatland midpoint and lake surface.");
	gettext("Shadow limit");
	gettext("Y-level to which floatland shadows extend.");
	gettext("Cavern limit");
	gettext("Y-level of cavern upper limit.");
	gettext("Cavern taper");
	gettext("Y-distance over which caverns expand to full size.");
	gettext("Cavern threshold");
	gettext("Defines full size of caverns, smaller values create larger caverns.");
	gettext("Terrain base noise");
	gettext("Y-level of higher (cliff-top) terrain.");
	gettext("Terrain alt noise");
	gettext("Y-level of lower terrain and lakebeds.");
	gettext("Terrain persistence noise");
	gettext("Varies roughness of terrain.\nDefines the 'persistence' value for terrain_base and terrain_alt noises.");
	gettext("Height select noise");
	gettext("Defines areas of higher (cliff-top) terrain and affects steepness of cliffs.");
	gettext("Filler depth noise");
	gettext("Variation of biome filler depth.");
	gettext("Mountain height noise");
	gettext("Variation of maximum mountain height (in nodes).");
	gettext("Ridge underwater noise");
	gettext("Defines large-scale river channel structure.");
	gettext("Floatland base noise");
	gettext("Defines areas of floatland smooth terrain.\nSmooth floatlands occur when noise > 0.");
	gettext("Floatland base height noise");
	gettext("Variation of hill height and lake depth on floatland smooth terrain.");
	gettext("Mountain noise");
	gettext("3D noise defining mountain structure and height.\nAlso defines structure of floatland mountain terrain.");
	gettext("Ridge noise");
	gettext("3D noise defining structure of river canyon walls.");
	gettext("Cavern noise");
	gettext("3D noise defining giant caverns.");
	gettext("Cave1 noise");
	gettext("First of 2 3D noises that together define tunnels.");
	gettext("Cave2 noise");
	gettext("Second of 2 3D noises that together define tunnels.");
	gettext("Mapgen flat");
	gettext("Mapgen flat specific flags");
	gettext("Map generation attributes specific to Mapgen flat.\nOccasional lakes and hills can be added to the flat world.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
	gettext("Ground level");
	gettext("Y of flat ground.");
	gettext("Large cave depth");
	gettext("Y of upper limit of large pseudorandom caves.");
	gettext("Cave width");
	gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
	gettext("Lake threshold");
	gettext("Terrain noise threshold for lakes.\nControls proportion of world area covered by lakes.\nAdjust towards 0.0 for a larger proportion.");
	gettext("Lake steepness");
	gettext("Controls steepness/depth of lake depressions.");
	gettext("Hill threshold");
	gettext("Terrain noise threshold for hills.\nControls proportion of world area covered by hills.\nAdjust towards 0.0 for a larger proportion.");
	gettext("Hill steepness");
	gettext("Controls steepness/height of hills.");
	gettext("Terrain noise");
	gettext("Defines location and terrain of optional hills and lakes.");
	gettext("Filler depth noise");
	gettext("Variation of biome filler depth.");
	gettext("Cave1 noise");
	gettext("First of 2 3D noises that together define tunnels.");
	gettext("Cave2 noise");
	gettext("Second of 2 3D noises that together define tunnels.");
	gettext("Mapgen fractal");
	gettext("Cave width");
	gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
	gettext("Fractal type");
	gettext("Choice of 18 fractals from 9 formulas.\n1 = 4D \"Roundy\" mandelbrot set.\n2 = 4D \"Roundy\" julia set.\n3 = 4D \"Squarry\" mandelbrot set.\n4 = 4D \"Squarry\" julia set.\n5 = 4D \"Mandy Cousin\" mandelbrot set.\n6 = 4D \"Mandy Cousin\" julia set.\n7 = 4D \"Variation\" mandelbrot set.\n8 = 4D \"Variation\" julia set.\n9 = 3D \"Mandelbrot/Mandelbar\" mandelbrot set.\n10 = 3D \"Mandelbrot/Mandelbar\" julia set.\n11 = 3D \"Christmas Tree\" mandelbrot set.\n12 = 3D \"Christmas Tree\" julia set.\n13 = 3D \"Mandelbulb\" mandelbrot set.\n14 = 3D \"Mandelbulb\" julia set.\n15 = 3D \"Cosine Mandelbulb\" mandelbrot set.\n16 = 3D \"Cosine Mandelbulb\" julia set.\n17 = 4D \"Mandelbulb\" mandelbrot set.\n18 = 4D \"Mandelbulb\" julia set.");
	gettext("Iterations");
	gettext("Iterations of the recursive function.\nControls the amount of fine detail.");
	gettext("Scale");
	gettext("Approximate (X,Y,Z) scale of fractal in nodes.");
	gettext("Offset");
	gettext("(X,Y,Z) offset of fractal from world centre in units of 'scale'.\nUsed to move a suitable spawn area of low land close to (0, 0).\nThe default is suitable for mandelbrot sets, it needs to be edited for julia sets.\nRange roughly -2 to 2. Multiply by 'scale' for offset in nodes.");
	gettext("Slice w");
	gettext("W co-ordinate of the generated 3D slice of a 4D fractal.\nDetermines which 3D slice of the 4D shape is generated.\nHas no effect on 3D fractals.\nRange roughly -2 to 2.");
	gettext("Julia x");
	gettext("Julia set only: X component of hypercomplex constant determining julia shape.\nRange roughly -2 to 2.");
	gettext("Julia y");
	gettext("Julia set only: Y component of hypercomplex constant determining julia shape.\nRange roughly -2 to 2.");
	gettext("Julia z");
	gettext("Julia set only: Z component of hypercomplex constant determining julia shape.\nRange roughly -2 to 2.");
	gettext("Julia w");
	gettext("Julia set only: W component of hypercomplex constant determining julia shape.\nHas no effect on 3D fractals.\nRange roughly -2 to 2.");
	gettext("Seabed noise");
	gettext("Y-level of seabed.");
	gettext("Filler depth noise");
	gettext("Variation of biome filler depth.");
	gettext("Cave1 noise");
	gettext("First of 2 3D noises that together define tunnels.");
	gettext("Cave2 noise");
	gettext("Second of 2 3D noises that together define tunnels.");
	gettext("Mapgen Valleys");
	gettext("General");
	gettext("Valleys C Flags");
	gettext("Map generation attributes specific to Mapgen Valleys.\n'altitude_chill' makes higher elevations colder, which may cause biome issues.\n'humid_rivers' modifies the humidity around rivers and in areas where water would tend to pool,\nit may interfere with delicately adjusted biomes.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
	gettext("Altitude Chill");
	gettext("The altitude at which temperature drops by 20C");
	gettext("Large cave depth");
	gettext("Depth below which you'll find large caves.");
	gettext("Lava Features");
	gettext("Creates unpredictable lava features in caves.\nThese can make mining difficult. Zero disables them. (0-10)");
	gettext("Massive cave depth");
	gettext("Depth below which you'll find massive caves.");
	gettext("River Depth");
	gettext("How deep to make rivers");
	gettext("River Size");
	gettext("How wide to make rivers");
	gettext("Water Features");
	gettext("Creates unpredictable water features in caves.\nThese can make mining difficult. Zero disables them. (0-10)");
	gettext("Cave width");
	gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
	gettext("Noises");
	gettext("Cave noise #1");
	gettext("Caves and tunnels form at the intersection of the two noises");
	gettext("Cave noise #2");
	gettext("Caves and tunnels form at the intersection of the two noises");
	gettext("Filler Depth");
	gettext("The depth of dirt or other filler");
	gettext("Massive cave noise");
	gettext("Massive caves form here.");
	gettext("River Noise");
	gettext("River noise -- rivers occur close to zero");
	gettext("Terrain Height");
	gettext("Base terrain height");
	gettext("Valley Depth");
	gettext("Raises terrain to make valleys around the rivers");
	gettext("Valley Fill");
	gettext("Slope and fill work together to modify the heights");
	gettext("Valley Profile");
	gettext("Amplifies the valleys");
	gettext("Valley Slope");
	gettext("Slope and fill work together to modify the heights");
	gettext("Security");
	gettext("Enable mod security");
	gettext("Prevent mods from doing insecure things like running shell commands.");
	gettext("Trusted mods");
	gettext("Comma-separated list of trusted mods that are allowed to access insecure\nfunctions even when mod security is on (via request_insecure_environment()).");
	gettext("HTTP Mods");
	gettext("Comma-separated list of mods that are allowed to access HTTP APIs, which\nallow them to upload and download data to/from the internet.");
	gettext("Advanced");
	gettext("Profiling");
	gettext("Load the game profiler");
	gettext("Load the game profiler to collect game profiling data.\nProvides a /profiler command to access the compiled profile.\nUseful for mod developers and server operators.");
	gettext("Default report format");
	gettext("The default format in which profiles are being saved,\nwhen calling `/profiler save [format]` without format.");
	gettext("Report path");
	gettext("The file path relative to your worldpath in which profiles will be saved to.");
	gettext("Instrumentation");
	gettext("Entity methods");
	gettext("Instrument the methods of entities on registration.");
	gettext("Active Block Modifiers");
	gettext("Instrument the action function of Active Block Modifiers on registration.");
	gettext("Loading Block Modifiers");
	gettext("Instrument the action function of Loading Block Modifiers on registration.");
	gettext("Chatcommands");
	gettext("Instrument chatcommands on registration.");
	gettext("Global callbacks");
	gettext("Instrument global callback functions on registration.\n(anything you pass to a minetest.register_*() function)");
	gettext("Advanced");
	gettext("Builtin");
	gettext("Instrument builtin.\nThis is usually only needed by core/builtin contributors");
	gettext("Profiler");
	gettext("Have the profiler instrument itself:\n* Instrument an empty function.\nThis estimates the overhead, that instrumentation is adding (+1 function call).\n* Instrument the sampler being used to update the statistics.");
	gettext("Client and Server");
	gettext("Player name");
	gettext("Name of the player.\nWhen running a server, clients connecting with this name are admins.\nWhen starting from the main menu, this is overridden.");
	gettext("Language");
	gettext("Set the language. Leave empty to use the system language.\nA restart is required after changing this.");
	gettext("Debug log level");
	gettext("Level of logging to be written to debug.txt:\n-    <nothing> (no logging)\n-    none (messages with no level)\n-    error\n-    warning\n-    action\n-    info\n-    verbose");
	gettext("IPv6");
	gettext("IPv6 support.");
	gettext("Advanced");
	gettext("cURL timeout");
	gettext("Default timeout for cURL, stated in milliseconds.\nOnly has an effect if compiled with cURL.");
	gettext("cURL parallel limit");
	gettext("Limits number of parallel HTTP requests. Affects:\n-    Media fetch if server uses remote_media setting.\n-    Serverlist download and server announcement.\n-    Downloads performed by main menu (e.g. mod manager).\nOnly has an effect if compiled with cURL.");
	gettext("cURL file download timeout");
	gettext("Maximum time in ms a file download (e.g. a mod download) may take.");
	gettext("High-precision FPU");
	gettext("Makes DirectX work with LuaJIT. Disable if it causes troubles.");
	gettext("Main menu script");
	gettext("Replaces the default main menu with a custom one.");
	gettext("Main menu game manager");
	gettext("Main menu mod manager");
	gettext("Modstore download URL");
	gettext("Modstore mods list URL");
	gettext("Modstore details URL");
	gettext("Engine profiling data print interval");
	gettext("Print the engine's profiling data in regular intervals (in seconds). 0 = disable. Useful for developers.");
}


code:
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2013 Kahrl <kahrl@gmx.net>

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 <fstream>
#include <iterator>
#include "shader.h"
#include "irrlichttypes_extrabloated.h"
#include "debug.h"
#include "filesys.h"
#include "util/container.h"
#include "util/thread.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include <IGPUProgrammingServices.h>
#include <IMaterialRenderer.h>
#include <IMaterialRendererServices.h>
#include <IShaderConstantSetCallBack.h>
#include "EShaderTypes.h"
#include "log.h"
#include "gamedef.h"
#include "client/tile.h"

/*
	A cache from shader name to shader path
*/
MutexedMap<std::string, std::string> 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;
		StringMap::iterator 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;
		StringMap::iterator 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 \""
				<< combined << "\"" << std::endl;
			return "";
		}
		infostream << "SourceShaderCache::getOrLoad(): Loading path \""
			<< path << "\"" << std::endl;
		std::string p = readFile(path);
		if (p != "") {
			m_programs[combined] = p;
			return p;
		}
		return "";
	}
private:
	StringMap 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 ShaderCallback : public video::IShaderConstantSetCallBack
{
	std::vector<IShaderConstantSetter*> m_setters;

public:
	ShaderCallback(const std::vector<IShaderConstantSetterFactory*> &factories)
	{
		for (u32 i = 0; i < factories.size(); ++i)
			m_setters.push_back(factories[i]->create());
	}

	~ShaderCallback()
	{
		for (u32 i = 0; i < m_setters.size(); ++i)
			delete m_setters[i];
	}

	virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
	{
		video::IVideoDriver *driver = services->getVideoDriver();
		sanity_check(driver != NULL);

		bool is_highlevel = userData;

		for (u32 i = 0; i < m_setters.size(); ++i)
			m_setters[i]->onSetConstants(services, is_highlevel);
	}
};

/*
	MainShaderConstantSetter: Set basic constants required for almost everything
*/

class MainShaderConstantSetter : public IShaderConstantSetter
{
	CachedVertexShaderSetting<float, 16> m_world_view_proj;
	CachedVertexShaderSetting<float, 16> m_world;

public:
	MainShaderConstantSetter() :
		m_world_view_proj("mWorldViewProj"),
		m_world("mWorld")
	{}
	~MainShaderConstantSetter() {}

	virtual void onSetConstants(video::IMaterialRendererServices *services,
			bool is_highlevel)
	{
		video::IVideoDriver *driver = services->getVideoDriver();
		sanity_check(driver);

		// 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)
			m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
		else
			services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);

		// Set world matrix
		core::matrix4 world = driver->getTransform(video::ETS_WORLD);
		if (is_highlevel)
			m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
		else
			services->setVertexShaderConstant(world.pointer(), 4, 4);

	}
};

class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
{
public:
	virtual IShaderConstantSetter* create()
		{ return new MainShaderConstantSetter(); }
};

/*
	ShaderSource
*/

class ShaderSource : public IWritableShaderSource
{
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 addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
	{
		m_setter_factories.push_back(setter);
	}

private:

	// The id of the thread that is allowed to use irrlicht directly
	threadid_t m_main_thread;
	// The irrlicht device
	IrrlichtDevice *m_device;

	// Cache of source shaders
	// This should be only accessed from the main thread
	SourceShaderCache m_sourcecache;

	// A shader id is index in this array.
	// The first position contains a dummy shader.
	std::vector<ShaderInfo> m_shaderinfo_cache;
	// The former container is behind this mutex
	Mutex m_shaderinfo_cache_mutex;

	// Queued shader fetches (to be processed by the main thread)
	RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;

	// Global constant setter factories
	std::vector<IShaderConstantSetterFactory *> m_setter_factories;

	// Shader callbacks
	std::vector<ShaderCallback *> m_callbacks;
};

IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
{
	return new ShaderSource(device);
}

/*
	Generate shader given the shader name.
*/
ShaderInfo generate_shader(const std::string &name,
		u8 material_type, u8 drawtype,
		IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
		const std::vector<IShaderConstantSetterFactory*> &setter_factories,
		SourceShaderCache *sourcecache);

/*
	Load shader programs
*/
void load_shaders(std::string name, SourceShaderCache *sourcecache,
		video::E_DRIVER_TYPE drivertype, bool enable_shaders,
		std::string &vertex_program, std::string &pixel_program,
		std::string &geometry_program, bool &is_highlevel);

ShaderSource::ShaderSource(IrrlichtDevice *device):
		m_device(device)
{
	assert(m_device); // Pre-condition

	m_main_thread = thr_get_current_thread_id();

	// Add a dummy ShaderInfo as the first index, named ""
	m_shaderinfo_cache.push_back(ShaderInfo());

	// Add main global constant setter
	addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
}

ShaderSource::~ShaderSource()
{
	for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
			iter != m_callbacks.end(); ++iter) {
		delete *iter;
	}
	for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
			iter != m_setter_factories.end(); ++iter) {
		delete *iter;
	}
}

u32 ShaderSource::getShader(const std::string &name,
		const u8 material_type, const u8 drawtype)
{
	/*
		Get shader
	*/

	if (thr_is_current_thread(m_main_thread)) {
		return getShaderIdDirect(name, material_type, drawtype);
	} else {
		/*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/

		// We're gonna ask the result to be put into here

		static ResultQueue<std::string, u32, u8, u8> result_queue;

		// Throw a request in
		m_get_shader_queue.add(name, 0, 0, &result_queue);

		/* infostream<<"Waiting for shader from main thread, name=\""
				<<name<<"\""<<std::endl;*/

		while(true) {
			GetResult<std::string, u32, u8, u8>
				result = result_queue.pop_frontNoEx();

			if (result.key == name) {
				return result.item;
			}
			else {
				errorstream << "Got shader with invalid name: " << result.key << std::endl;
			}
		}

	}

	infostream<<"getShader(): Failed"<<std::endl;

	return 0;
}

/*
	This method generates all the shaders
*/
u32 ShaderSource::getShaderIdDirect(const std::string &name,
		const u8 material_type, const u8 drawtype)
{
	//infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;

	// Empty name means shader 0
	if(name == ""){
		infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
		return 0;
	}

	// Check if already have such instance
	for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
		ShaderInfo *info = &m_shaderinfo_cache[i];
		if(info->name == name && info->material_type == material_type &&
			info->drawtype == drawtype)
			return i;
	}

	/*
		Calling only allowed from main thread
	*/
	if (!thr_is_current_thread(m_main_thread)) {
		errorstream<<"ShaderSource::getShaderIdDirect() "
				"called not from main thread"<<std::endl;
		return 0;
	}

	ShaderInfo info = generate_shader(name, material_type, drawtype,
			m_device, m_callbacks, m_setter_factories, &m_sourcecache);

	/*
		Add shader to caches (add dummy shaders too)
	*/

	MutexAutoLock lock(m_shaderinfo_cache_mutex);

	u32 id = m_shaderinfo_cache.size();
	m_shaderinfo_cache.push_back(info);

	infostream<<"getShaderIdDirect(): "
			<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;

	return id;
}

ShaderInfo ShaderSource::getShaderInfo(u32 id)
{
	MutexAutoLock lock(m_shaderinfo_cache_mutex);

	if(id >= m_shaderinfo_cache.size())
		return ShaderInfo();

	return m_shaderinfo_cache[id];
}

void ShaderSource::processQueue()
{

}

void ShaderSource::insertSourceShader(const std::string &name_of_shader,
		const std::string &filename, const std::string &program)
{
	/*infostream<<"ShaderSource::insertSourceShader(): "
			"name_of_shader=\""<<name_of_shader<<"\", "
			"filename=\""<<filename<<"\""<<std::endl;*/

	sanity_check(thr_is_current_thread(m_main_thread));

	m_sourcecache.insert(name_of_shader, filename, program, true);
}

void ShaderSource::rebuildShaders()
{
	MutexAutoLock lock(m_shaderinfo_cache_mutex);

	/*// Oh well... just clear everything, they'll load sometime.
	m_shaderinfo_cache.clear();
	m_name_to_id.clear();*/

	/*
		FIXME: Old shader materials can't be deleted in Irrlicht,
		or can they?
		(This would be nice to do in the destructor too)
	*/

	// Recreate shaders
	for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
		ShaderInfo *info = &m_shaderinfo_cache[i];
		if(info->name != ""){
			*info = generate_shader(info->name, info->material_type,
					info->drawtype, m_device, m_callbacks,
					m_setter_factories, &m_sourcecache);
		}
	}
}

ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
		IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
		const std::vector<IShaderConstantSetterFactory*> &setter_factories,
		SourceShaderCache *sourcecache)
{
	ShaderInfo shaderinfo;
	shaderinfo.name = name;
	shaderinfo.material_type = material_type;
	shaderinfo.drawtype = drawtype;
	shaderinfo.material = video::EMT_SOLID;
	switch (material_type) {
	case TILE_MATERIAL_OPAQUE:
	case TILE_MATERIAL_LIQUID_OPAQUE:
		shaderinfo.base_material = video::EMT_SOLID;
		break;
	case TILE_MATERIAL_ALPHA:
	case TILE_MATERIAL_LIQUID_TRANSPARENT:
		shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
		break;
	case TILE_MATERIAL_BASIC:
	case TILE_MATERIAL_WAVING_LEAVES:
	case TILE_MATERIAL_WAVING_PLANTS:
		shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
		break;
	}

	bool enable_shaders = g_settings->getBool("enable_shaders");
	if (!enable_shaders)
		return shaderinfo;

	video::IVideoDriver* driver = device->getVideoDriver();
	sanity_check(driver);

	video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
	if(!gpu){
		errorstream<<"generate_shader(): "
				"failed to generate \""<<name<<"\", "
				"GPU programming not supported."
				<<std::endl;
		return shaderinfo;
	}

	// Choose shader language depending on driver type and settings
	// Then load shaders
	std::string vertex_program;
	std::string pixel_program;
	std::string geometry_program;
	bool is_highlevel;
	load_shaders(name, sourcecache, driver->getDriverType(),
			enable_shaders, vertex_program, pixel_program,
			geometry_program, is_highlevel);
	// Check hardware/driver support
	if(vertex_program != "" &&
			!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
			!driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
		infostream<<"generate_shader(): vertex shaders disabled "
				"because of missing driver/hardware support."
				<<std::endl;
		vertex_program = "";
	}
	if(pixel_program != "" &&
			!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
			!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
		infostream<<"generate_shader(): pixel shaders disabled "
				"because of missing driver/hardware support."
				<<std::endl;
		pixel_program = "";
	}
	if(geometry_program != "" &&
			!driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
		infostream<<"generate_shader(): geometry shaders disabled "
				"because of missing driver/hardware support."
				<<std::endl;
		geometry_program = "";
	}

	// If no shaders are used, don't make a separate material type
	if(vertex_program == "" && pixel_program == "" && geometry_program == "")
		return shaderinfo;

	// Create shaders header
	std::string shaders_header = "#version 120\n";

	static const char* drawTypes[] = {
		"NDT_NORMAL",
		"NDT_AIRLIKE",
		"NDT_LIQUID",
		"NDT_FLOWINGLIQUID",
		"NDT_GLASSLIKE",
		"NDT_ALLFACES",
		"NDT_ALLFACES_OPTIONAL",
		"NDT_TORCHLIKE",
		"NDT_SIGNLIKE",
		"NDT_PLANTLIKE",
		"NDT_FENCELIKE",
		"NDT_RAILLIKE",
		"NDT_NODEBOX",
		"NDT_GLASSLIKE_FRAMED",
		"NDT_FIRELIKE",
		"NDT_GLASSLIKE_FRAMED_OPTIONAL"
	};

	for (int i = 0; i < 14; i++){
		shaders_header += "#define ";
		shaders_header += drawTypes[i];
		shaders_header += " ";
		shaders_header += itos(i);
		shaders_header += "\n";
	}

	static const char* materialTypes[] = {
		"TILE_MATERIAL_BASIC",
		"TILE_MATERIAL_ALPHA",
		"TILE_MATERIAL_LIQUID_TRANSPARENT",
		"TILE_MATERIAL_LIQUID_OPAQUE",
		"TILE_MATERIAL_WAVING_LEAVES",
		"TILE_MATERIAL_WAVING_PLANTS",
		"TILE_MATERIAL_OPAQUE"
	};

	for (int i = 0; i < 7; i++){
		shaders_header += "#define ";
		shaders_header += materialTypes[i];
		shaders_header += " ";
		shaders_header += itos(i);
		shaders_header += "\n";
	}

	shaders_header += "#define MATERIAL_TYPE ";
	shaders_header += itos(material_type);
	shaders_header += "\n";
	shaders_header += "#define DRAW_TYPE ";
	shaders_header += itos(drawtype);
	shaders_header += "\n";

	if (g_settings->getBool("generate_normalmaps")) {
		shaders_header += "#define GENERATE_NORMALMAPS 1\n";
	} else {
		shaders_header += "#define GENERATE_NORMALMAPS 0\n";
	}
	shaders_header += "#define NORMALMAPS_STRENGTH ";
	shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
	shaders_header += "\n";
	float sample_step;
	int smooth = (int)g_settings->getFloat("normalmaps_smooth");
	switch (smooth){
	case 0:
		sample_step = 0.0078125; // 1.0 / 128.0
		break;
	case 1:
		sample_step = 0.00390625; // 1.0 / 256.0
		break;
	case 2:
		sample_step = 0.001953125; // 1.0 / 512.0
		break;
	default:
		sample_step = 0.0078125;
		break;
	}
	shaders_header += "#define SAMPLE_STEP ";
	shaders_header += ftos(sample_step);
	shaders_header += "\n";

	if (g_settings->getBool("enable_bumpmapping"))
		shaders_header += "#define ENABLE_BUMPMAPPING\n";

	if (g_settings->getBool("enable_parallax_occlusion")){
		int mode = g_settings->getFloat("parallax_occlusion_mode");
		float scale = g_settings->getFloat("parallax_occlusion_scale");
		float bias = g_settings->getFloat("parallax_occlusion_bias");
		int iterations = g_settings->getFloat("parallax_occlusion_iterations");
		shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
		shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
		shaders_header += itos(mode);
		shaders_header += "\n";
		shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
		shaders_header += ftos(scale);
		shaders_header += "\n";
		shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
		shaders_header += ftos(bias);
		shaders_header += "\n";
		shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
		shaders_header += itos(iterations);
		shaders_header += "\n";
	}

	shaders_header += "#define USE_NORMALMAPS ";
	if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
		shaders_header += "1\n";
	else
		shaders_header += "0\n";

	if (g_settings->getBool("enable_waving_water")){
		shaders_header += "#define ENABLE_WAVING_WATER 1\n";
		shaders_header += "#define WATER_WAVE_HEIGHT ";
		shaders_header += ftos(g_settings->getFloat("water_wave_height"));
		shaders_header += "\n";
		shaders_header += "#define WATER_WAVE_LENGTH ";
		shaders_header += ftos(g_settings->getFloat("water_wave_length"));
		shaders_header += "\n";
		shaders_header += "#define WATER_WAVE_SPEED ";
		shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
		shaders_header += "\n";
	} else{
		shaders_header += "#define ENABLE_WAVING_WATER 0\n";
	}

	shaders_header += "#define ENABLE_WAVING_LEAVES ";
	if (g_settings->getBool("enable_waving_leaves"))
		shaders_header += "1\n";
	else
		shaders_header += "0\n";

	shaders_header += "#define ENABLE_WAVING_PLANTS ";
	if (g_settings->getBool("enable_waving_plants"))
		shaders_header += "1\n";
	else
		shaders_header += "0\n";

	if (g_settings->getBool("tone_mapping"))
		shaders_header += "#define ENABLE_TONE_MAPPING\n";

	shaders_header += "#define FOG_START ";
	shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
	shaders_header += "\n";

	// Call addHighLevelShaderMaterial() or addShaderMaterial()
	const c8* vertex_program_ptr = 0;
	const c8* pixel_program_ptr = 0;
	const c8* geometry_program_ptr = 0;
	if (!vertex_program.empty()) {
		vertex_program = shaders_header + vertex_program;
		vertex_program_ptr = vertex_program.c_str();
	}
	if (!pixel_program.empty()) {
		pixel_program = shaders_header + pixel_program;
		pixel_program_ptr = pixel_program.c_str();
	}
	if (!geometry_program.empty()) {
		geometry_program = shaders_header + geometry_program;
		geometry_program_ptr = geometry_program.c_str();
	}
	ShaderCallback *cb = new ShaderCallback(setter_factories);
	s32 shadermat = -1;
	if(is_highlevel){
		infostream<<"Compiling high level shaders for "<<name<<std::endl;
		shadermat = gpu->addHighLevelShaderMaterial(
			vertex_program_ptr,   // Vertex shader program
			"vertexMain",         // Vertex shader entry point
			video::EVST_VS_1_1,   // Vertex shader version
			pixel_program_ptr,    // Pixel shader program
			"pixelMain",          // Pixel shader entry point
			video::EPST_PS_1_2,   // Pixel shader version
			geometry_program_ptr, // Geometry shader program
			"geometryMain",       // Geometry shader entry point
			video::EGST_GS_4_0,   // Geometry shader version
			scene::EPT_TRIANGLES,      // Geometry shader input
			scene::EPT_TRIANGLE_STRIP, // Geometry shader output
			0,                         // Support maximum number of vertices
			cb, // Set-constant callback
			shaderinfo.base_material,  // Base material
			1                          // Userdata passed to callback
			);
		if(shadermat == -1){
			errorstream<<"generate_shader(): "
					"failed to generate \""<<name<<"\", "
					"addHighLevelShaderMaterial failed."
					<<std::endl;
			dumpShaderProgram(warningstream, "Vertex", vertex_program);
			dumpShaderProgram(warningstream, "Pixel", pixel_program);
			dumpShaderProgram(warningstream, "Geometry", geometry_program);
			delete cb;
			return shaderinfo;
		}
	}
	else{
		infostream<<"Compiling assembly shaders for "<<name<<std::endl;
		shadermat = gpu->addShaderMaterial(
			vertex_program_ptr,   // Vertex shader program
			pixel_program_ptr,    // Pixel shader program
			cb, // Set-constant callback
			shaderinfo.base_material,  // Base material
			0                     // Userdata passed to callback
			);

		if(shadermat == -1){
			errorstream<<"generate_shader(): "
					"failed to generate \""<<name<<"\", "
					"addShaderMaterial failed."
					<<std::endl;
			dumpShaderProgram(warningstream, "Vertex", vertex_program);
			dumpShaderProgram(warningstream,"Pixel", pixel_program);
			delete cb;
			return shaderinfo;
		}
	}
	callbacks.push_back(cb);

	// HACK, TODO: investigate this better
	// Grab the material renderer once more so minetest doesn't crash on exit
	driver->getMaterialRenderer(shadermat)->grab();

	// Apply the newly created material type
	shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
	return shaderinfo;
}

void load_shaders(std::string name, SourceShaderCache *sourcecache,
		video::E_DRIVER_TYPE drivertype, bool enable_shaders,
		std::string &vertex_program, std::string &pixel_program,
		std::string &geometry_program, bool &is_highlevel)
{
	vertex_program = "";
	pixel_program = "";
	geometry_program = "";
	is_highlevel = false;

	if(enable_shaders){
		// Look for high level shaders
		if(drivertype == video::EDT_DIRECT3D9){
			// Direct3D 9: HLSL
			// (All shaders in one file)
			vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
			pixel_program = vertex_program;
			geometry_program = vertex_program;
		}
		else if(drivertype == video::EDT_OPENGL){
			// OpenGL: GLSL
			vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
			pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
			geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
		}
		if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
			is_highlevel = true;
			return;
		}
	}

}

void dumpShaderProgram(std::ostream &output_stream,
		const std::string &program_type, const std::string &program)
{
	output_stream << program_type << " shader program:" << std::endl <<
		"----------------------------------" << std::endl;
	size_t pos = 0;
	size_t prev = 0;
	s16 line = 1;
	while ((pos = program.find("\n", prev)) != std::string::npos) {
		output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
			std::endl;
		prev = pos + 1;
	}
	output_stream << line << ": " << program.substr(prev) << std::endl <<
		"End of " << program_type << " shader program." << std::endl <<
		" " << std::endl;
}

repo_name: pgimeno/minetest

license: unknown


code:
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2013 Kahrl <kahrl@gmx.net>

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.
*/

#ifndef SHADER_HEADER
#define SHADER_HEADER

#include <IMaterialRendererServices.h>
#include "irrlichttypes_extrabloated.h"
#include "threads.h"
#include <string>

class IGameDef;

/*
	shader.{h,cpp}: Shader handling stuff.
*/

/*
	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);

struct ShaderInfo {
	std::string name;
	video::E_MATERIAL_TYPE base_material;
	video::E_MATERIAL_TYPE material;
	u8 drawtype;
	u8 material_type;
	s32 user_data;

	ShaderInfo(): name(""), base_material(video::EMT_SOLID),
		material(video::EMT_SOLID),
		drawtype(0), material_type(0) {}
	virtual ~ShaderInfo() {}
};

/*
	Setter of constants for shaders
*/

namespace irr { namespace video {
	class IMaterialRendererServices;
} }

class IShaderConstantSetter {
public:
	virtual ~IShaderConstantSetter(){};
	virtual void onSetConstants(video::IMaterialRendererServices *services,
			bool is_highlevel) = 0;
};

class IShaderConstantSetterFactory {
public:
	virtual ~IShaderConstantSetterFactory() {};
	virtual IShaderConstantSetter* create() = 0;
};

template <typename T, std::size_t count=1>
class CachedShaderSetting {
	const char *m_name;
	T m_sent[count];
	bool has_been_set;
	bool is_pixel;
protected:
	CachedShaderSetting(const char *name, bool is_pixel) :
		m_name(name), has_been_set(false), is_pixel(is_pixel)
	{}
public:
	void set(const T value[count], video::IMaterialRendererServices *services)
	{
		if (has_been_set && std::equal(m_sent, m_sent + count, value))
			return;
		if (is_pixel)
			services->setPixelShaderConstant(m_name, value, count);
		else
			services->setVertexShaderConstant(m_name, value, count);
		std::copy(value, value + count, m_sent);
		has_been_set = true;
	}
};

template <typename T, std::size_t count = 1>
class CachedPixelShaderSetting : public CachedShaderSetting<T, count> {
public:
	CachedPixelShaderSetting(const char *name) :
		CachedShaderSetting<T, count>(name, true){}
};

template <typename T, std::size_t count = 1>
class CachedVertexShaderSetting : public CachedShaderSetting<T, count> {
public:
	CachedVertexShaderSetting(const char *name) :
		CachedShaderSetting<T, count>(name, false){}
};

/*
	ShaderSource creates and caches shaders.
*/

class IShaderSource {
public:
	IShaderSource(){}
	virtual ~IShaderSource(){}
	virtual u32 getShaderIdDirect(const std::string &name,
		const u8 material_type, const u8 drawtype){return 0;}
	virtual ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
	virtual u32 getShader(const std::string &name,
		const u8 material_type, const u8 drawtype){return 0;}
};

class IWritableShaderSource : public IShaderSource {
public:
	IWritableShaderSource(){}
	virtual ~IWritableShaderSource(){}
	virtual u32 getShaderIdDirect(const std::string &name,
		const u8 material_type, const u8 drawtype){return 0;}
	virtual ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
	virtual u32 getShader(const std::string &name,
		const u8 material_type, const u8 drawtype){return 0;}

	virtual void processQueue()=0;
	virtual void insertSourceShader(const std::string &name_of_shader,
		const std::string &filename, const std::string &program)=0;
	virtual void rebuildShaders()=0;
	virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
};

IWritableShaderSource* createShaderSource(IrrlichtDevice *device);

void dumpShaderProgram(std::ostream &output_stream,
	const std::string &program_type, const std::string &program);

#endif