Index: ps/trunk/binaries/data/config/default.cfg =================================================================== --- ps/trunk/binaries/data/config/default.cfg (revision 26483) +++ ps/trunk/binaries/data/config/default.cfg (revision 26484) @@ -1,589 +1,590 @@ ; Global Configuration Settings ; ; ************************************************************** ; * DO NOT EDIT THIS FILE if you want personal customisations: * ; * create a text file called "local.cfg" instead, and copy * ; * the lines from this file that you want to change. * ; * * ; * If a setting is part of a section (for instance [hotkey]) * ; * you need to append the section name at the beginning of * ; * your custom line (for instance you need to write * ; * "hotkey.pause = Space" if you want to change the pausing * ; * hotkey to the spacebar). * ; * * ; * On Linux, create: * ; * $XDG_CONFIG_HOME/0ad/config/local.cfg * ; * (Note: $XDG_CONFIG_HOME defaults to ~/.config) * ; * * ; * On OS X, create: * ; * ~/Library/Application\ Support/0ad/config/local.cfg * ; * * ; * On Windows, create: * ; * %appdata%\0ad\config\local.cfg * ; * * ; ************************************************************** ; Enable/disable windowed mode by default. (Use Alt+Enter to toggle in the game.) windowed = false ; Switches between real fullscreen and borderless window on a full display size. borderless.fullscreen = true ; Hides a window border in the windowed mode. borderless.window = false ; Show detailed tooltips (Unit stats) showdetailedtooltips = false ; Pause the game on window focus loss (Only applicable to single player mode) pauseonfocusloss = true ; Persist settings after leaving the game setup screen persistmatchsettings = true ; Default player name to use in multiplayer ; playername = "anonymous" ; Default server name or IP to use in multiplayer multiplayerserver = "127.0.0.1" ; Force a particular resolution. (If these are 0, the default is ; to keep the current desktop resolution in fullscreen mode or to ; use 1024x768 in windowed mode.) xres = 0 yres = 0 ; Force a non-standard bit depth (if 0 then use the current desktop bit depth) bpp = 0 ; Preferred display (for multidisplay setups, only works with SDL 2.0) display = 0 ; Enable Hi-DPI where supported, currently working only for testing. hidpi = false ; Allows to force GL version for SDL forceglversion = false forceglprofile = "compatibility" ; Possible values: compatibility, core, es forceglmajorversion = 3 forceglminorversion = 3 ; Big screenshot tiles screenshot.tiles = 8 screenshot.tilewidth = 480 screenshot.tileheight = 270 ; Emulate right-click with Ctrl+Click on Mac mice macmouse = false ; System settings: ; if false, actors won't be rendered but anything entity will be. renderactors = true watereffects=true ; When disabled, force usage of the fixed pipeline water. This is faster, but really, really ugly. waterfancyeffects = false waterrealdepth = true waterrefraction = true waterreflection = true shadows = true shadowquality = 0 ; Shadow map resolution. (-1 - Low, 0 - Medium, 1 - High, 2 - Very High) ; High values can crash the game when using a graphics card with low memory! shadowpcf = true ; Increases details closer to the camera but decreases performance ; especially on low hardware. shadowscascadecount = 1 shadowscascadedistanceratio = 1.7 ; Hides shadows after the distance. shadowscutoffdistance = 300.0 ; If true shadows cover the whole map instead of the camera frustum. shadowscovermap = false vsync = false particles = true fog = true silhouettes = true showsky = true ; Uses a synchonized call to a GL driver to get an error state. Useful ; for a debugging of a system without GL_KHR_debug. gl.checkerrorafterswap = false ; Different ways to draw a cursor, possible values are "sdl" and "system". ; The "system" one doesn't support a visual change of the cursor. cursorbackend = "sdl" ; Backends for all graphics rendering: ; glarb - GL with legacy assembler-like shaders, might used only for buggy drivers. ; gl - GL with GLSL shaders, should be used by default. rendererbackend = "gl" ; Enables additional debug information in renderer backend. +renderer.backend.debugcontext = "false" renderer.backend.debugmessages = "false" renderer.backend.debuglabels = "false" renderer.backend.debugscopedlabels = "false" ; Should not be edited. It's used only for preventing of running fixed pipeline. renderpath = default ; (0 - low, 1 - medium, 2 - high), higher quality means worse performance. textures.quality = 2 ; (1, 2, 4, 8 and 16) textures.maxanisotropy = 2 ;;;;; EXPERIMENTAL ;;;;; ; Experimental probably-non-working GPU skinning support; requires GLSL; use at own risk gpuskinning = false ; Use smooth LOS interpolation smoothlos = false ; Use screen-space postprocessing filters (HDR, bloom, DOF, etc). Incompatible with fixed renderpath. postproc = false ; Use anti-aliasing techniques. antialiasing = "disabled" ; Use sharpening techniques. sharpening = "disabled" sharpness = 0.3 ; Quality used for actors. max_actor_quality=200 ; Whether or not actor variants are selected randomly, possible values are "full", "limited", "none". variant_diversity = "full" ; Quality level of shader effects (set to 10 to display all effects) materialmgr.quality = 2.0 ; Maximum distance to display parallax effect. Set to 0 to disable parallax. materialmgr.PARALLAX_DIST.max = 150 ; Maximum distance to display high quality parallax effect. materialmgr.PARALLAX_HQ_DIST.max = 75 ; Maximum distance to display very high quality parallax effect. Set to 30 to enable. materialmgr.PARALLAX_VHQ_DIST.max = 0 ;;;;;;;;;;;;;;;;;;;;;;;; ; Color of the sky (in "r g b" format) skycolor = "0 0 0" [adaptivefps] session = 60 ; Throttle FPS in running games (prevents 100% CPU workload). menu = 60 ; Throttle FPS in menus only. [profiler2] server = "127.0.0.1" server.port = "8000" ; Use a free port on your machine. server.threads = "6" ; Enough for the browser's parallel connection limit [hotkey] ; Each one of the specified keys will trigger the action on the left ; for multiple-key combinations, separate keys with '+'. ; See keys.txt for the list of key names. ; > SYSTEM SETTINGS exit = "" ; 'Custom' exit to desktop, SDL handles the native command via SDL_Quit. cancel = Escape ; Close or cancel the current dialog box/popup confirm = Return ; Confirm the current command pause = Pause, "Shift+Space" ; Pause/unpause game screenshot = F2 ; Take PNG screenshot bigscreenshot = "Shift+F2" ; Take large BMP screenshot togglefullscreen = "Alt+Return" ; Toggle fullscreen/windowed mode screenshot.watermark = "Alt+K" ; Toggle product/company watermark for official screenshots wireframe = "Alt+Shift+W" ; Toggle wireframe mode silhouettes = "Alt+Shift+S" ; Toggle unit silhouettes ; > DIALOG HOTKEYS summary = "Ctrl+Tab" ; Toggle in-game summary lobby = "Alt+L" ; Show the multiplayer lobby in a dialog window. structree = "Alt+Shift+T" ; Show structure tree civinfo = "Alt+Shift+H" ; Show civilization info ; > CLIPBOARD CONTROLS copy = "Ctrl+C" ; Copy to clipboard paste = "Ctrl+V" ; Paste from clipboard cut = "Ctrl+X" ; Cut selected text and copy to the clipboard ; > CONSOLE SETTINGS console.toggle = BackQuote, F9 ; Open/close console ; > OVERLAY KEYS fps.toggle = "Alt+F" ; Toggle frame counter realtime.toggle = "Alt+T" ; Toggle current display of computer time timeelapsedcounter.toggle = "F12" ; Toggle time elapsed counter ceasefirecounter.toggle = "" ; Toggle ceasefire counter ; > HOTKEYS ONLY chat = Return ; Toggle chat window teamchat = "T" ; Toggle chat window in team chat mode privatechat = "L" ; Toggle chat window and select the previous private chat partner ; > QUICKSAVE quicksave = "Shift+F5" quickload = "Shift+F8" [hotkey.camera] reset = "R" ; Reset camera rotation to default. follow = "F" ; Follow the first unit in the selection rallypointfocus = "" ; Focus the camera on the rally point of the selected building lastattackfocus = "Space" ; Focus the camera on the last notified attack zoom.in = Plus, NumPlus ; Zoom camera in (continuous control) zoom.out = Minus, NumMinus ; Zoom camera out (continuous control) zoom.wheel.in = WheelUp ; Zoom camera in (stepped control) zoom.wheel.out = WheelDown ; Zoom camera out (stepped control) rotate.up = "Ctrl+UpArrow", "Ctrl+W" ; Rotate camera to look upwards rotate.down = "Ctrl+DownArrow", "Ctrl+S" ; Rotate camera to look downwards rotate.cw = "Ctrl+LeftArrow", "Ctrl+A", Q ; Rotate camera clockwise around terrain rotate.ccw = "Ctrl+RightArrow", "Ctrl+D", E ; Rotate camera anticlockwise around terrain rotate.wheel.cw = "Shift+WheelUp", MouseX1 ; Rotate camera clockwise around terrain (stepped control) rotate.wheel.ccw = "Shift+WheelDown", MouseX2 ; Rotate camera anticlockwise around terrain (stepped control) pan = MouseMiddle ; Enable scrolling by moving mouse left = A, LeftArrow ; Scroll or rotate left right = D, RightArrow ; Scroll or rotate right up = W, UpArrow ; Scroll or rotate up/forwards down = S, DownArrow ; Scroll or rotate down/backwards scroll.speed.increase = "Ctrl+Shift+S" ; Increase scroll speed scroll.speed.decrease = "Ctrl+Alt+S" ; Decrease scroll speed rotate.speed.increase = "Ctrl+Shift+R" ; Increase rotation speed rotate.speed.decrease = "Ctrl+Alt+R" ; Decrease rotation speed zoom.speed.increase = "Ctrl+Shift+Z" ; Increase zoom speed zoom.speed.decrease = "Ctrl+Alt+Z" ; Decrease zoom speed [hotkey.camera.jump] 1 = F5 ; Jump to position N 2 = F6 3 = F7 4 = F8 ;5 = ;6 = ;7 = ;8 = ;9 = ;10 = [hotkey.camera.jump.set] 1 = "Ctrl+F5" ; Set jump position N 2 = "Ctrl+F6" 3 = "Ctrl+F7" 4 = "Ctrl+F8" ;5 = ;6 = ;7 = ;8 = ;9 = ;10 = [hotkey.profile] toggle = "F11" ; Enable/disable real-time profiler save = "Shift+F11" ; Save current profiler data to logs/profile.txt [hotkey.profile2] toggle = "Ctrl+F11" ; Enable/disable HTTP/GPU modes for new profiler [hotkey.selection] cancel = Esc ; Un-select all units and cancel building placement add = Shift ; Add units to selection militaryonly = Alt ; Add only military units to the selection nonmilitaryonly = "Alt+Y" ; Add only non-military units to the selection idleonly = "I" ; Select only idle units woundedonly = "O" ; Select only wounded units remove = Ctrl ; Remove units from selection idlebuilder = Semicolon ; Select next idle builder idleworker = Period, NumDecimal ; Select next idle worker idlewarrior = Slash, NumDivide ; Select next idle warrior idleunit = BackSlash ; Select next idle unit offscreen = Alt ; Include offscreen units in selection singleselection = "" ; Modifier to select units individually, opposed to per formation. [hotkey.selection.group.add] 0 = "Shift+0", "Shift+Num0" 1 = "Shift+1", "Shift+Num1" 2 = "Shift+2", "Shift+Num2" 3 = "Shift+3", "Shift+Num3" 4 = "Shift+4", "Shift+Num4" 5 = "Shift+5", "Shift+Num5" 6 = "Shift+6", "Shift+Num6" 7 = "Shift+7", "Shift+Num7" 8 = "Shift+8", "Shift+Num8" 9 = "Shift+9", "Shift+Num9" [hotkey.selection.group.save] 0 = "Ctrl+0", "Ctrl+Num0" 1 = "Ctrl+1", "Ctrl+Num1" 2 = "Ctrl+2", "Ctrl+Num2" 3 = "Ctrl+3", "Ctrl+Num3" 4 = "Ctrl+4", "Ctrl+Num4" 5 = "Ctrl+5", "Ctrl+Num5" 6 = "Ctrl+6", "Ctrl+Num6" 7 = "Ctrl+7", "Ctrl+Num7" 8 = "Ctrl+8", "Ctrl+Num8" 9 = "Ctrl+9", "Ctrl+Num9" [hotkey.selection.group.select] 0 = 0, Num0 1 = 1, Num1 2 = 2, Num2 3 = 3, Num3 4 = 4, Num4 5 = 5, Num5 6 = 6, Num6 7 = 7, Num7 8 = 8, Num8 9 = 9, Num9 [hotkey.gamesetup] mapbrowser.open = "M" [hotkey.session] kill = Delete, Backspace ; Destroy selected units stop = "H" ; Stop the current action backtowork = "Y" ; The unit will go back to work unload = "U" ; Unload garrisoned units when a building/mechanical unit is selected unloadturrets = "U" ; Unload turreted units. leaveturret = "U" ; Leave turret point. move = "" ; Modifier to move to a point instead of another action (e.g. gather) attack = Ctrl ; Modifier to attack instead of another action (e.g. capture) attackmove = Ctrl ; Modifier to attackmove when clicking on a point attackmoveUnit = "Ctrl+Q" ; Modifier to attackmove targeting only units when clicking on a point garrison = Ctrl ; Modifier to garrison when clicking on building occupyturret = Ctrl ; Modifier to occupy a turret when clicking on a turret holder. autorallypoint = Ctrl ; Modifier to set the rally point on the building itself guard = "G" ; Modifier to escort/guard when clicking on unit/building patrol = "P" ; Modifier to patrol a unit repair = "J" ; Modifier to repair when clicking on building/mechanical unit queue = Shift ; Modifier to queue unit orders instead of replacing pushorderfront = "" ; Modifier to push unit orders to the front instead of replacing. orderone = Alt ; Modifier to order only one entity in selection. batchtrain = Shift ; Modifier to train units in batches massbarter = Shift ; Modifier to barter bunch of resources masstribute = Shift ; Modifier to tribute bunch of resources noconfirmation = Shift ; Do not ask confirmation when deleting a building/unit fulltradeswap = Shift ; Modifier to put the desired trade resource to 100% unloadtype = Shift ; Modifier to unload all units of type deselectgroup = Ctrl ; Modifier to deselect units when clicking group icon, instead of selecting rotate.cw = RightBracket ; Rotate building placement preview clockwise rotate.ccw = LeftBracket ; Rotate building placement preview anticlockwise snaptoedges = Ctrl ; Modifier to align new structures with nearby existing structure toggledefaultformation = "" ; Switch between null default formation and the last default formation used (defaults to "box") flare = K ; Modifier to send a flare to your allies flareactivate = "" ; Modifier to activate the mode to send a flare to your allies calltoarms = "" ; Modifier to call the selected units to the arms. ; Overlays showstatusbars = Tab ; Toggle display of status bars devcommands.toggle = "Alt+D" ; Toggle developer commands panel highlightguarding = PageDown ; Toggle highlight of guarding units highlightguarded = PageUp ; Toggle highlight of guarded units diplomacycolors = "Alt+X" ; Toggle diplomacy colors toggleattackrange = "Alt+C" ; Toggle display of attack range overlays of selected defensive structures toggleaurasrange = "Alt+V" ; Toggle display of aura range overlays of selected units and structures togglehealrange = "Alt+B" ; Toggle display of heal range overlays of selected units [hotkey.session.gui] toggle = "Alt+G" ; Toggle visibility of session GUI menu.toggle = "F10" ; Toggle in-game menu diplomacy.toggle = "Ctrl+H" ; Toggle in-game diplomacy page barter.toggle = "Ctrl+B" ; Toggle in-game barter/trade page objectives.toggle = "Ctrl+O" ; Toggle in-game objectives page tutorial.toggle = "Ctrl+P" ; Toggle in-game tutorial panel [hotkey.session.savedgames] delete = Delete, Backspace ; Delete the selected saved game asking confirmation noconfirmation = Shift ; Do not ask confirmation when deleting a game [hotkey.session.queueunit] ; > UNIT TRAINING 1 = "Z" ; add first unit type to queue 2 = "X" ; add second unit type to queue 3 = "C" ; add third unit type to queue 4 = "V" ; add fourth unit type to queue 5 = "B" ; add fivth unit type to queue 6 = "N" ; add sixth unit type to queue 7 = "M" ; add seventh unit type to queue 8 = Comma ; add eighth unit type to queue [hotkey.session.timewarp] fastforward = "Ctrl+Space" ; If timewarp mode enabled, speed up the game rewind = "Shift+Backspace" ; If timewarp mode enabled, go back to earlier point in the game [hotkey.tab] next = "Tab", "Alt+S" ; Show the next tab prev = "Shift+Tab", "Alt+W" ; Show the previous tab [hotkey.text] ; > GUI TEXTBOX HOTKEYS delete.left = "Ctrl+Backspace" ; Delete word to the left of cursor delete.right = "Ctrl+Del" ; Delete word to the right of cursor move.left = "Ctrl+LeftArrow" ; Move cursor to start of word to the left of cursor move.right = "Ctrl+RightArrow" ; Move cursor to start of word to the right of cursor [gui] cursorblinkrate = 0.5 ; Cursor blink rate in seconds (0.0 to disable blinking) scale = 1.0 ; GUI scaling factor, for improved compatibility with 4K displays [gui.gamesetup] enabletips = true ; Enable/Disable tips during gamesetup (for newcomers) assignplayers = everyone ; Whether to assign joining clients to free playerslots. Possible values: everyone, buddies, disabled. aidifficulty = 3 ; Difficulty level, from 0 (easiest) to 5 (hardest) aibehavior = "random" ; Default behavior of the AI (random, balanced, aggressive or defensive) settingsslide = true ; Enable/Disable settings panel slide [gui.loadingscreen] progressdescription = false ; Whether to display the progress percent or a textual description [gui.session] camerajump.threshold = 40 ; How close do we have to be to the actual location in order to jump back to the previous one? timeelapsedcounter = false ; Show the game duration in the top right corner ceasefirecounter = false ; Show the remaining ceasefire time in the top right corner batchtrainingsize = 5 ; Number of units to be trained per batch by default (when pressing the hotkey) scrollbatchratio = 1 ; Number of times you have to scroll to increase/decrease the batchsize by 1 flarelifetime = 6 ; How long the flare markers on the minimap are displayed in seconds woundedunithotkeythreshold = 33 ; The wounded unit hotkey considers the selected units as wounded if their health percentage falls below this number attackrange = true ; Display attack range overlays of selected defensive structures aurasrange = true ; Display aura range overlays of selected units and structures healrange = true ; Display heal range overlays of selected units rankabovestatusbar = true ; Show rank icons above status bars experiencestatusbar = true ; Show an experience status bar above each selected unit respoptooltipsort = 0 ; Sorting players in the resources and population tooltip by value (0 - no sort, -1 - ascending, 1 - descending) snaptoedges = "disabled" ; Possible values: disabled, enabled. snaptoedgesdistancethreshold = 15 ; On which distance we don't snap to edges disjointcontrolgroups = "true" ; Whether control groups are disjoint sets or entities can be in multiple control groups at the same time. defaultformation = "special/formations/box" ; For walking orders, automatically put units into this formation if they don't have one already. formationwalkonly = "true" ; Formations are disabled when giving gather/attack/... orders. howtoshownames = 0 ; Whether the specific names are show as default, as opposed to the generic names. And whether the secondary names are shown. (0 - show both; specific names primary, 1 - show both; generic names primary, 2 - show only specific names, 3 - show only generic names) selectformationasone = "true" ; Whether to select formations as a whole by default. [gui.session.minimap] blinkduration = 1.7 ; The blink duration while pinging pingduration = 50.0 ; The duration for which an entity will be pinged after an attack notification [gui.session.notifications] attack = true ; Show a chat notification if you are attacked by another player tribute = true ; Show a chat notification if an ally tributes resources to another team member if teams are locked, and all tributes in observer mode barter = true ; Show a chat notification to observers when a player bartered resources phase = completed ; Show a chat notification if you or an ally have started, aborted or completed a new phase, and phases of all players in observer mode. Possible values: none, completed, all. [gui.splashscreen] enable = true ; Enable/disable the splashscreen version = 0 ; Splashscreen version (date of last modification). By default, 0 to force splashscreen to appear at first launch [gui.session.diplomacycolors] self = "21 55 149" ; Color of your units when diplomacy colors are enabled ally = "86 180 31" ; Color of allies when diplomacy colors are enabled neutral = "231 200 5" ; Color of neutral players when diplomacy colors are enabled enemy = "150 20 20" ; Color of enemies when diplomacy colors are enabled [joystick] ; EXPERIMENTAL: joystick/gamepad settings enable = false deadzone = 8192 [chat] timestamp = true ; Show at which time chat messages have been sent [chat.session] extended = true ; Whether to display the chat history [lobby] history = 0 ; Number of past messages to display on join room = "arena26" ; Default MUC room to join server = "lobby.wildfiregames.com" ; Address of lobby server tls = true ; Whether to use TLS encryption when connecting to the server. verify_certificate = false ; Whether to reject connecting to the lobby if the TLS certificate is invalid (TODO: wait for Gloox GnuTLS trust implementation to be fixed) terms_url = "https://trac.wildfiregames.com/browser/ps/trunk/binaries/data/mods/public/gui/prelobby/common/terms/"; Allows the user to save the text and print the terms terms_of_service = "0" ; Version (hash) of the Terms of Service that the user has accepted terms_of_use = "0" ; Version (hash) of the Terms of Use that the user has accepted privacy_policy = "0" ; Version (hash) of the Privacy Policy that the user has accepted xpartamupp = "wfgbot26" ; Name of the server-side XMPP-account that manage games echelon = "echelon26" ; Name of the server-side XMPP-account that manages ratings buddies = "," ; Comma separated list of playernames that the current user has marked as buddies rememberpassword = true ; Whether to store the encrypted password in the user config [lobby.columns] gamerating = false ; Show the average rating of the participating players in a column of the gamelist [lobby.stun] enabled = true ; The STUN protocol allows hosting games without configuring the firewall and router. ; If STUN is disabled, the game relies on direct connection, UPnP and port forwarding. server = "lobby.wildfiregames.com" ; Address of the STUN server. port = 3478 ; Port of the STUN server. delay = 200 ; Duration in milliseconds that is waited between STUN messages. ; Smaller numbers speed up joins but also become less stable. [mod] enabledmods = "mod public" [modio] public_key = "RWR/X/zDEJSHEfioDC/EO2So3TRMUmAH4O6A1a3ZhMwcqQA61xqBPPGa" ; Public key corresponding to the private key valid mods are signed with disclaimer = "0" ; Version (hash) of the Disclaimer that the user has accepted [modio.v1] baseurl = "https://api.mod.io/v1" api_key = "23df258a71711ea6e4b50893acc1ba55" name_id = "0ad" [network] duplicateplayernames = false ; Rename joining player to "User (2)" if "User" is already connected, otherwise prohibit join. lateobservers = everyone ; Allow observers to join the game after it started. Possible values: everyone, buddies, disabled. observerlimit = 8 ; Prevent further observer joins in running games if this limit is reached observermaxlag = 10 ; Make clients wait for observers if they lag more than X turns behind. -1 means "never wait for observers". autocatchup = true ; Auto-accelerate the sim rate if lagging behind (as an observer). [overlay] fps = "false" ; Show frames per second in top right corner realtime = "false" ; Show current system time in top right corner netwarnings = "true" ; Show warnings if the network connection is bad [profiler2] autoenable = false ; Enable HTTP server output at startup (default off for security/performance) gpu.arb.enable = true ; Allow GL_ARB_timer_query timing mode when available gpu.ext.enable = true ; Allow GL_EXT_timer_query timing mode when available gpu.intel.enable = true ; Allow GL_INTEL_performance_queries timing mode when available [rlinterface] address = "127.0.0.1:6000" [sound] mastergain = 0.9 musicgain = 0.2 ambientgain = 0.6 actiongain = 0.7 uigain = 0.7 mindistance = 1 maxdistance = 350 maxstereoangle = 0.62 ; About PI/5 radians [sound.notify] nick = true ; Play a sound when someone mentions your name in the lobby or game gamesetup.join = false ; Play a sound when a new client joins the game setup [tinygettext] debug = false ; Print error messages each time a translation for an English string is not found. [userreport] ; Opt-in online user reporting system url_upload = "https://feedback.wildfiregames.com/report/upload/v1/" ; URL where UserReports are uploaded to url_publication = "https://feedback.wildfiregames.com/" ; URL where UserReports were analyzed and published url_terms = "https://trac.wildfiregames.com/browser/ps/trunk/binaries/data/mods/public/gui/userreport/Terms_and_Conditions.txt"; Allows the user to save the text and print the terms terms = "0" ; Version (hash) of the UserReporter Terms that the user has accepted [view] ; Camera control settings scroll.speed = 120.0 scroll.speed.modifier = 1.05 ; Multiplier for changing scroll speed rotate.x.speed = 1.2 rotate.x.min = 28.0 rotate.x.max = 60.0 rotate.x.default = 35.0 rotate.y.speed = 2.0 rotate.y.speed.wheel = 0.45 rotate.y.default = 0.0 rotate.speed.modifier = 1.05 ; Multiplier for changing rotation speed drag.speed = 0.5 zoom.speed = 256.0 zoom.speed.wheel = 32.0 zoom.min = 50.0 zoom.max = 200.0 zoom.default = 120.0 zoom.speed.modifier = 1.05 ; Multiplier for changing zoom speed pos.smoothness = 0.1 zoom.smoothness = 0.4 rotate.x.smoothness = 0.5 rotate.y.smoothness = 0.3 near = 2.0 ; Near plane distance far = 4096.0 ; Far plane distance fov = 45.0 ; Field of view (degrees), lower is narrow, higher is wide height.smoothness = 0.5 height.min = 16 Index: ps/trunk/source/ps/VideoMode.cpp =================================================================== --- ps/trunk/source/ps/VideoMode.cpp (revision 26483) +++ ps/trunk/source/ps/VideoMode.cpp (revision 26484) @@ -1,787 +1,792 @@ /* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 * (at your option) any later version. * * 0 A.D. 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. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "VideoMode.h" #include "graphics/GameView.h" #include "gui/GUIManager.h" #include "lib/config2.h" #include "lib/external_libraries/libsdl.h" #include "lib/ogl.h" #include "lib/tex/tex.h" #include "ps/CConsole.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStr.h" #include "ps/Filesystem.h" #include "ps/Game.h" #include "ps/GameSetup/Config.h" #include "ps/Pyrogenesis.h" #include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" namespace { int DEFAULT_WINDOW_W = 1024; int DEFAULT_WINDOW_H = 768; int DEFAULT_FULLSCREEN_W = 1024; int DEFAULT_FULLSCREEN_H = 768; const wchar_t DEFAULT_CURSOR_NAME[] = L"default-arrow"; } // anonymous namespace #if OS_WIN // We can't include wutil directly because GL headers conflict with Windows // until we use a proper GL loader. extern void wutil_SetAppWindow(SDL_Window* window); // After a proper HiDPI integration we should switch to manifest until // SDL has an implemented HiDPI on Windows. extern void wutil_EnableHiDPIOnWindows(); #endif CVideoMode g_VideoMode; class CVideoMode::CCursor { public: enum class CursorBackend { SDL, SYSTEM }; CCursor(); ~CCursor(); void SetCursor(const CStrW& name); void ResetCursor(); private: CursorBackend m_CursorBackend = CursorBackend::SYSTEM; SDL_Surface* m_CursorSurface = nullptr; SDL_Cursor* m_Cursor = nullptr; CStrW m_CursorName; }; CVideoMode::CCursor::CCursor() { std::string cursorBackend; CFG_GET_VAL("cursorbackend", cursorBackend); if (cursorBackend == "sdl") m_CursorBackend = CursorBackend::SDL; else m_CursorBackend = CursorBackend::SYSTEM; ResetCursor(); } CVideoMode::CCursor::~CCursor() { if (m_Cursor) SDL_FreeCursor(m_Cursor); if (m_CursorSurface) SDL_FreeSurface(m_CursorSurface); } void CVideoMode::CCursor::SetCursor(const CStrW& name) { if (m_CursorBackend == CursorBackend::SYSTEM || m_CursorName == name) return; m_CursorName = name; if (m_Cursor) SDL_FreeCursor(m_Cursor); if (m_CursorSurface) SDL_FreeSurface(m_CursorSurface); if (name.empty()) { SDL_ShowCursor(SDL_DISABLE); return; } const VfsPath pathBaseName(VfsPath(L"art/textures/cursors") / name); // Read pixel offset of the cursor's hotspot [the bit of it that's // drawn at (g_mouse_x,g_mouse_y)] from file. int hotspotX = 0, hotspotY = 0; { const VfsPath pathHotspotName = pathBaseName.ChangeExtension(L".txt"); std::shared_ptr buffer; size_t size; if (g_VFS->LoadFile(pathHotspotName, buffer, size) != INFO::OK) { LOGERROR("Can't load hotspot for cursor: %s", pathHotspotName.string8().c_str()); return; } std::wstringstream s(std::wstring(reinterpret_cast(buffer.get()), size)); s >> hotspotX >> hotspotY; } const VfsPath pathImageName = pathBaseName.ChangeExtension(L".png"); std::shared_ptr file; size_t fileSize; if (g_VFS->LoadFile(pathImageName, file, fileSize) != INFO::OK) { LOGERROR("Can't load image for cursor: %s", pathImageName.string8().c_str()); return; } Tex t; if (t.decode(file, fileSize) != INFO::OK) { LOGERROR("Can't decode image for cursor"); return; } // Convert to required BGRA format. const size_t flags = (t.m_Flags | TEX_BGR) & ~TEX_DXT; if (t.transform_to(flags) != INFO::OK) { LOGERROR("Can't transform image for cursor"); return; } void* imageBGRA = t.get_data(); if (!imageBGRA) { LOGERROR("Transformed image is empty for cursor"); return; } m_CursorSurface = SDL_CreateRGBSurfaceFrom(imageBGRA, static_cast(t.m_Width), static_cast(t.m_Height), 32, static_cast(t.m_Width * 4), 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); if (!m_CursorSurface) { LOGERROR("Can't create surface for cursor: %s", SDL_GetError()); return; } const float scale = g_VideoMode.GetScale(); if (scale != 1.0) { SDL_Surface* scaledSurface = SDL_CreateRGBSurface(0, m_CursorSurface->w * scale, m_CursorSurface->h * scale, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); if (!scaledSurface) { LOGERROR("Can't create scaled surface forcursor: %s", SDL_GetError()); return; } if (SDL_BlitScaled(m_CursorSurface, nullptr, scaledSurface, nullptr)) return; SDL_FreeSurface(m_CursorSurface); m_CursorSurface = scaledSurface; } m_Cursor = SDL_CreateColorCursor(m_CursorSurface, hotspotX, hotspotY); if (!m_Cursor) { LOGERROR("Can't create cursor: %s", SDL_GetError()); return; } SDL_SetCursor(m_Cursor); } void CVideoMode::CCursor::ResetCursor() { SetCursor(DEFAULT_CURSOR_NAME); } CVideoMode::CVideoMode() : m_WindowedW(DEFAULT_WINDOW_W), m_WindowedH(DEFAULT_WINDOW_H), m_WindowedX(0), m_WindowedY(0) { } CVideoMode::~CVideoMode() = default; void CVideoMode::ReadConfig() { bool windowed = !m_ConfigFullscreen; CFG_GET_VAL("windowed", windowed); m_ConfigFullscreen = !windowed; CFG_GET_VAL("gui.scale", m_Scale); CFG_GET_VAL("xres", m_ConfigW); CFG_GET_VAL("yres", m_ConfigH); CFG_GET_VAL("bpp", m_ConfigBPP); CFG_GET_VAL("display", m_ConfigDisplay); CFG_GET_VAL("hidpi", m_ConfigEnableHiDPI); CFG_GET_VAL("vsync", m_ConfigVSync); CStr rendererBackend; CFG_GET_VAL("rendererbackend", rendererBackend); if (rendererBackend == "glarb") m_Backend = Backend::GL_ARB; else m_Backend = Backend::GL; } bool CVideoMode::SetVideoMode(int w, int h, int bpp, bool fullscreen) { Uint32 flags = 0; if (fullscreen) { bool borderlessFullscreen = true; CFG_GET_VAL("borderless.fullscreen", borderlessFullscreen); flags |= borderlessFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; } else { bool borderlessWindow = false; CFG_GET_VAL("borderless.window", borderlessWindow); if (borderlessWindow) flags |= SDL_WINDOW_BORDERLESS; } if (!m_Window) { #if OS_WIN if (m_ConfigEnableHiDPI) wutil_EnableHiDPIOnWindows(); #endif // Note: these flags only take affect in SDL_CreateWindow flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; if (m_ConfigEnableHiDPI) flags |= SDL_WINDOW_ALLOW_HIGHDPI; m_WindowedX = m_WindowedY = SDL_WINDOWPOS_CENTERED_DISPLAY(m_ConfigDisplay); m_Window = SDL_CreateWindow(main_window_name, m_WindowedX, m_WindowedY, w, h, flags); if (!m_Window) { // If fullscreen fails, try windowed mode if (fullscreen) { LOGWARNING("Failed to set the video mode to fullscreen for the chosen resolution " "%dx%d:%d (\"%hs\"), falling back to windowed mode", w, h, bpp, SDL_GetError()); // Using default size for the window for now, as the attempted setting // could be as large, or larger than the screen size. return SetVideoMode(DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, bpp, false); } else { LOGERROR("SetVideoMode failed in SDL_CreateWindow: %dx%d:%d %d (\"%s\")", w, h, bpp, fullscreen ? 1 : 0, SDL_GetError()); return false; } } if (SDL_SetWindowDisplayMode(m_Window, NULL) < 0) { LOGERROR("SetVideoMode failed in SDL_SetWindowDisplayMode: %dx%d:%d %d (\"%s\")", w, h, bpp, fullscreen ? 1 : 0, SDL_GetError()); return false; } #if OS_WIN // We need to set the window for an error dialog. wutil_SetAppWindow(m_Window); #endif if (!CreateBackendDevice(true)) { LOGERROR("SetVideoMode failed in backend device creation: %dx%d:%d %d", w, h, bpp, fullscreen ? 1 : 0); return false; } } else { if (m_IsFullscreen != fullscreen) { if (!fullscreen) { // For some reason, when switching from fullscreen to windowed mode, // we have to set the window size and position before and after switching SDL_SetWindowSize(m_Window, w, h); SDL_SetWindowPosition(m_Window, m_WindowedX, m_WindowedY); } if (SDL_SetWindowFullscreen(m_Window, flags) < 0) { LOGERROR("SetVideoMode failed in SDL_SetWindowFullscreen: %dx%d:%d %d (\"%s\")", w, h, bpp, fullscreen ? 1 : 0, SDL_GetError()); return false; } } if (!fullscreen) { SDL_SetWindowSize(m_Window, w, h); SDL_SetWindowPosition(m_Window, m_WindowedX, m_WindowedY); } } // Grab the current video settings SDL_GetWindowSize(m_Window, &m_CurrentW, &m_CurrentH); m_CurrentBPP = bpp; if (fullscreen) SDL_SetWindowGrab(m_Window, SDL_TRUE); else SDL_SetWindowGrab(m_Window, SDL_FALSE); m_IsFullscreen = fullscreen; g_xres = m_CurrentW; g_yres = m_CurrentH; return true; } bool CVideoMode::InitSDL() { ENSURE(!m_IsInitialised); ReadConfig(); // preferred video mode = current desktop settings // (command line params may override these) // TODO: handle multi-screen and HiDPI properly. SDL_DisplayMode mode; if (SDL_GetDesktopDisplayMode(0, &mode) == 0) { m_PreferredW = mode.w; m_PreferredH = mode.h; m_PreferredBPP = SDL_BITSPERPIXEL(mode.format); m_PreferredFreq = mode.refresh_rate; } int w = m_ConfigW; int h = m_ConfigH; if (m_ConfigFullscreen) { // If fullscreen and no explicit size set, default to the desktop resolution if (w == 0 || h == 0) { w = m_PreferredW; h = m_PreferredH; } } // If no size determined, default to something sensible if (w == 0 || h == 0) { w = DEFAULT_WINDOW_W; h = DEFAULT_WINDOW_H; } if (!m_ConfigFullscreen) { // Limit the window to the screen size (if known) if (m_PreferredW) w = std::min(w, m_PreferredW); if (m_PreferredH) h = std::min(h, m_PreferredH); } int bpp = GetBestBPP(); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + bool debugContext = false; + CFG_GET_VAL("renderer.backend.debugcontext", debugContext); + if (debugContext) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + bool forceGLVersion = false; CFG_GET_VAL("forceglversion", forceGLVersion); if (forceGLVersion) { CStr forceGLProfile = "compatibility"; int forceGLMajorVersion = 3; int forceGLMinorVersion = 0; CFG_GET_VAL("forceglprofile", forceGLProfile); CFG_GET_VAL("forceglmajorversion", forceGLMajorVersion); CFG_GET_VAL("forceglminorversion", forceGLMinorVersion); int profile = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; if (forceGLProfile == "es") profile = SDL_GL_CONTEXT_PROFILE_ES; else if (forceGLProfile == "core") profile = SDL_GL_CONTEXT_PROFILE_CORE; else if (forceGLProfile != "compatibility") LOGWARNING("Unknown force GL profile '%s', compatibility profile is used", forceGLProfile.c_str()); if (forceGLMajorVersion < 1 || forceGLMinorVersion < 0) { LOGERROR("Unsupported force GL version: %d.%d", forceGLMajorVersion, forceGLMinorVersion); } else { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, forceGLMajorVersion); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, forceGLMinorVersion); } } else { #if CONFIG2_GLES // Require GLES 2.0 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #else // Some macOS and MESA drivers might not create a context even if they can // with the core profile. So disable it for a while until we can guarantee // its creation. #if OS_WIN SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); #endif } if (!SetVideoMode(w, h, bpp, m_ConfigFullscreen)) { // Fall back to a smaller depth buffer // (The rendering may be ugly but this helps when running in VMware) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); if (!SetVideoMode(w, h, bpp, m_ConfigFullscreen)) return false; } SDL_GL_SetSwapInterval(m_ConfigVSync ? 1 : 0); // Work around a bug in the proprietary Linux ATI driver (at least versions 8.16.20 and 8.14.13). // The driver appears to register its own atexit hook on context creation. // If this atexit hook is called before SDL_Quit destroys the OpenGL context, // some kind of double-free problem causes a crash and lockup in the driver. // Calling SDL_Quit twice appears to be harmless, though, and avoids the problem // by destroying the context *before* the driver's atexit hook is called. // (Note that atexit hooks are guaranteed to be called in reverse order of their registration.) atexit(SDL_Quit); // End work around. m_IsInitialised = true; if (!m_ConfigFullscreen) { m_WindowedW = w; m_WindowedH = h; } SetWindowIcon(); m_Cursor = std::make_unique(); return true; } bool CVideoMode::InitNonSDL() { ENSURE(!m_IsInitialised); ReadConfig(); m_IsInitialised = true; return true; } void CVideoMode::Shutdown() { ENSURE(m_IsInitialised); m_Cursor.reset(); m_IsFullscreen = false; m_IsInitialised = false; m_BackendDevice.reset(); if (m_Window) { SDL_DestroyWindow(m_Window); m_Window = nullptr; } } bool CVideoMode::CreateBackendDevice(const bool createSDLContext) { m_BackendDevice = Renderer::Backend::GL::CDevice::Create(createSDLContext ? m_Window : nullptr, m_Backend == Backend::GL_ARB); if (!m_BackendDevice && m_Backend == Backend::GL) { LOGERROR("Unable to create device for GL backend, switching to ARB.", static_cast(m_Backend)); m_Backend = Backend::GL_ARB; return CreateBackendDevice(createSDLContext); } return !!m_BackendDevice; } bool CVideoMode::ResizeWindow(int w, int h) { ENSURE(m_IsInitialised); // Ignore if not windowed if (m_IsFullscreen) return true; // Ignore if the size hasn't changed if (w == m_WindowedW && h == m_WindowedH) return true; int bpp = GetBestBPP(); if (!SetVideoMode(w, h, bpp, false)) return false; m_WindowedW = w; m_WindowedH = h; UpdateRenderer(w, h); return true; } void CVideoMode::Rescale(float scale) { ENSURE(m_IsInitialised); m_Scale = scale; UpdateRenderer(m_CurrentW, m_CurrentH); } float CVideoMode::GetScale() const { return m_Scale; } bool CVideoMode::SetFullscreen(bool fullscreen) { // This might get called before initialisation by psDisplayError; // if so then silently fail if (!m_IsInitialised) return false; // Check whether this is actually a change if (fullscreen == m_IsFullscreen) return true; if (!m_IsFullscreen) { // Windowed -> fullscreen: int w = 0, h = 0; // If a fullscreen size was configured, use that; else use the desktop size; else use a default if (m_ConfigFullscreen) { w = m_ConfigW; h = m_ConfigH; } if (w == 0 || h == 0) { w = m_PreferredW; h = m_PreferredH; } if (w == 0 || h == 0) { w = DEFAULT_FULLSCREEN_W; h = DEFAULT_FULLSCREEN_H; } int bpp = GetBestBPP(); if (!SetVideoMode(w, h, bpp, fullscreen)) return false; UpdateRenderer(m_CurrentW, m_CurrentH); return true; } else { // Fullscreen -> windowed: // Go back to whatever the previous window size was int w = m_WindowedW, h = m_WindowedH; int bpp = GetBestBPP(); if (!SetVideoMode(w, h, bpp, fullscreen)) return false; UpdateRenderer(w, h); return true; } } bool CVideoMode::ToggleFullscreen() { return SetFullscreen(!m_IsFullscreen); } bool CVideoMode::IsInFullscreen() const { return m_IsFullscreen; } void CVideoMode::UpdatePosition(int x, int y) { if (!m_IsFullscreen) { m_WindowedX = x; m_WindowedY = y; } } void CVideoMode::UpdateRenderer(int w, int h) { if (w < 2) w = 2; // avoid GL errors caused by invalid sizes if (h < 2) h = 2; g_xres = w; g_yres = h; SViewPort vp = { 0, 0, w, h }; if (CRenderer::IsInitialised()) { g_Renderer.SetViewport(vp); g_Renderer.Resize(w, h); } if (g_GUI) g_GUI->UpdateResolution(); if (g_Console) g_Console->UpdateScreenSize(w, h); if (g_Game) g_Game->GetView()->SetViewport(vp); } int CVideoMode::GetBestBPP() { if (m_ConfigBPP) return m_ConfigBPP; if (m_PreferredBPP) return m_PreferredBPP; return 32; } int CVideoMode::GetXRes() const { ENSURE(m_IsInitialised); return m_CurrentW; } int CVideoMode::GetYRes() const { ENSURE(m_IsInitialised); return m_CurrentH; } int CVideoMode::GetBPP() const { ENSURE(m_IsInitialised); return m_CurrentBPP; } bool CVideoMode::IsVSyncEnabled() const { ENSURE(m_IsInitialised); return m_ConfigVSync; } int CVideoMode::GetDesktopXRes() const { ENSURE(m_IsInitialised); return m_PreferredW; } int CVideoMode::GetDesktopYRes() const { ENSURE(m_IsInitialised); return m_PreferredH; } int CVideoMode::GetDesktopBPP() const { ENSURE(m_IsInitialised); return m_PreferredBPP; } int CVideoMode::GetDesktopFreq() const { ENSURE(m_IsInitialised); return m_PreferredFreq; } SDL_Window* CVideoMode::GetWindow() { ENSURE(m_IsInitialised); return m_Window; } void CVideoMode::SetWindowIcon() { // The window icon should be kept outside of art/textures/, or else it will be converted // to DDS by the archive builder and will become unusable here. Using DDS makes BGRA // conversion needlessly complicated. std::shared_ptr iconFile; size_t iconFileSize; if (g_VFS->LoadFile("art/icons/window.png", iconFile, iconFileSize) != INFO::OK) { LOGWARNING("Window icon not found."); return; } Tex iconTexture; if (iconTexture.decode(iconFile, iconFileSize) != INFO::OK) return; // Convert to required BGRA format. const size_t iconFlags = (iconTexture.m_Flags | TEX_BGR) & ~TEX_DXT; if (iconTexture.transform_to(iconFlags) != INFO::OK) return; void* bgra_img = iconTexture.get_data(); if (!bgra_img) return; SDL_Surface *iconSurface = SDL_CreateRGBSurfaceFrom(bgra_img, iconTexture.m_Width, iconTexture.m_Height, 32, iconTexture.m_Width * 4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); if (!iconSurface) return; SDL_SetWindowIcon(m_Window, iconSurface); SDL_FreeSurface(iconSurface); } void CVideoMode::SetCursor(const CStrW& name) { if (m_Cursor) m_Cursor->SetCursor(name); } void CVideoMode::ResetCursor() { if (m_Cursor) m_Cursor->ResetCursor(); }