Index: ps/trunk/binaries/data/mods/public/art/materials/alphatest.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/alphatest.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/alphatest.xml (nonexistent) @@ -1,7 +0,0 @@ - - - - - - - Property changes on: ps/trunk/binaries/data/mods/public/art/materials/alphatest.xml ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/materials/alphatest_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/alphatest_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/alphatest_spec.xml (nonexistent) @@ -1,10 +0,0 @@ - - - - - - - - - - Property changes on: ps/trunk/binaries/data/mods/public/art/materials/alphatest_spec.xml ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/materials/alphatest_ao_parallax_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/alphatest_ao_parallax_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/alphatest_ao_parallax_spec.xml (nonexistent) @@ -1,12 +0,0 @@ - - - - - - - - - - - - Property changes on: ps/trunk/binaries/data/mods/public/art/materials/alphatest_ao_parallax_spec.xml ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/binaries/data/config/default.cfg =================================================================== --- ps/trunk/binaries/data/config/default.cfg (revision 26210) +++ ps/trunk/binaries/data/config/default.cfg (revision 26211) @@ -1,582 +1,579 @@ ; 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 texturequality = 5 ; Texture resolution and quality (0 - Lowest, 1 Very Low, 2 - Low, 3 - Medium, 4 - High, 5 - Very High, 6 - Ultra) 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" ; Should not be edited. It's used only for preventing of running fixed pipeline. renderpath = default ;;;;; 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 ;;;;;;;;;;;;;;;;;;;;;;;; -; Replace alpha-blending with alpha-testing, for performance experiments -forcealphatest = false - ; 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/binaries/data/mods/public/art/materials/basic_glow.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_glow.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_glow.xml (revision 26211) @@ -1,12 +1,11 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_glow_norm.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_glow_norm.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_glow_norm.xml (revision 26211) @@ -1,13 +1,12 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_glow_wind.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_glow_wind.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_glow_wind.xml (revision 26211) @@ -1,15 +1,14 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans.xml (revision 26211) @@ -1,8 +1,7 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans_ao.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans_ao.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans_ao.xml (revision 26211) @@ -1,11 +1,10 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans_ao_parallax_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans_ao_parallax_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans_ao_parallax_spec.xml (revision 26211) @@ -1,14 +1,13 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans_norm_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans_norm_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans_norm_spec.xml (revision 26211) @@ -1,12 +1,11 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans_parallax_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans_parallax_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans_parallax_spec.xml (revision 26211) @@ -1,13 +1,12 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans_spec.xml (revision 26211) @@ -1,11 +1,10 @@ - Index: ps/trunk/binaries/data/mods/public/art/materials/blend_spec.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/blend_spec.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/art/materials/blend_spec.xml (revision 26211) @@ -1,11 +1,10 @@ - Index: ps/trunk/binaries/data/mods/public/shaders/effects/model_transparent.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/effects/model_transparent.xml (revision 26210) +++ ps/trunk/binaries/data/mods/public/shaders/effects/model_transparent.xml (revision 26211) @@ -1,103 +1,83 @@ - - - - - - - - - - - - - - - - - - - - Index: ps/trunk/source/graphics/MaterialManager.cpp =================================================================== --- ps/trunk/source/graphics/MaterialManager.cpp (revision 26210) +++ ps/trunk/source/graphics/MaterialManager.cpp (revision 26211) @@ -1,197 +1,196 @@ -/* Copyright (C) 2021 Wildfire Games. +/* 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 "MaterialManager.h" #include "graphics/PreprocessorWrapper.h" #include "maths/MathUtil.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/XML/Xeromyces.h" #include "renderer/RenderingOptions.h" #include CMaterialManager::CMaterialManager() { qualityLevel = 5.0; CFG_GET_VAL("materialmgr.quality", qualityLevel); qualityLevel = Clamp(qualityLevel, 0.0f, 10.0f); if (VfsDirectoryExists(L"art/materials/") && !CXeromyces::AddValidator(g_VFS, "material", "art/materials/material.rng")) LOGERROR("CMaterialManager: failed to load grammar file 'art/materials/material.rng'"); } CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname) { if (pathname.empty()) return CMaterial(); std::map::iterator iter = m_Materials.find(pathname); if (iter != m_Materials.end()) return iter->second; CXeromyces xeroFile; if (xeroFile.Load(g_VFS, pathname, "material") != PSRETURN_OK) return CMaterial(); #define EL(x) int el_##x = xeroFile.GetElementID(#x) #define AT(x) int at_##x = xeroFile.GetAttributeID(#x) EL(alpha_blending); EL(alternative); EL(define); EL(shader); EL(uniform); EL(renderquery); EL(required_texture); EL(conditional_define); AT(effect); AT(if); AT(define); AT(quality); AT(material); AT(name); AT(value); AT(type); AT(min); AT(max); AT(conf); #undef AT #undef EL CPreprocessorWrapper preprocessor; - preprocessor.AddDefine("CFG_FORCE_ALPHATEST", g_RenderingOptions.GetForceAlphaTest() ? "1" : "0"); CMaterial material; material.AddStaticUniform("qualityLevel", CVector4D(qualityLevel, 0, 0, 0)); XMBElement root = xeroFile.GetRoot(); XERO_ITER_EL(root, node) { int token = node.GetNodeName(); XMBAttributeList attrs = node.GetAttributes(); if (token == el_alternative) { CStr cond = attrs.GetNamedItem(at_if); if (cond.empty() || !preprocessor.TestConditional(cond)) { cond = attrs.GetNamedItem(at_quality); if (cond.empty()) continue; else { if (cond.ToFloat() <= qualityLevel) continue; } } material = LoadMaterial(VfsPath("art/materials") / attrs.GetNamedItem(at_material).FromUTF8()); break; } else if (token == el_alpha_blending) { material.SetUsesAlphaBlending(true); } else if (token == el_shader) { material.SetShaderEffect(attrs.GetNamedItem(at_effect)); } else if (token == el_define) { material.AddShaderDefine(CStrIntern(attrs.GetNamedItem(at_name)), CStrIntern(attrs.GetNamedItem(at_value))); } else if (token == el_conditional_define) { std::vector args; CStr type = attrs.GetNamedItem(at_type).c_str(); int typeID = -1; if (type == CStr("draw_range")) { typeID = DCOND_DISTANCE; float valmin = -1.0f; float valmax = -1.0f; CStr conf = attrs.GetNamedItem(at_conf); if (!conf.empty()) { CFG_GET_VAL("materialmgr." + conf + ".min", valmin); CFG_GET_VAL("materialmgr." + conf + ".max", valmax); } else { CStr dmin = attrs.GetNamedItem(at_min); if (!dmin.empty()) valmin = attrs.GetNamedItem(at_min).ToFloat(); CStr dmax = attrs.GetNamedItem(at_max); if (!dmax.empty()) valmax = attrs.GetNamedItem(at_max).ToFloat(); } args.push_back(valmin); args.push_back(valmax); if (valmin >= 0.0f) { std::stringstream sstr; sstr << valmin; material.AddShaderDefine(CStrIntern(conf + "_MIN"), CStrIntern(sstr.str())); } if (valmax >= 0.0f) { std::stringstream sstr; sstr << valmax; material.AddShaderDefine(CStrIntern(conf + "_MAX"), CStrIntern(sstr.str())); } } material.AddConditionalDefine(attrs.GetNamedItem(at_name).c_str(), attrs.GetNamedItem(at_value).c_str(), typeID, args); } else if (token == el_uniform) { std::stringstream str(attrs.GetNamedItem(at_value)); CVector4D vec; str >> vec.X >> vec.Y >> vec.Z >> vec.W; material.AddStaticUniform(attrs.GetNamedItem(at_name).c_str(), vec); } else if (token == el_renderquery) { material.AddRenderQuery(attrs.GetNamedItem(at_name).c_str()); } else if (token == el_required_texture) { material.AddRequiredSampler(attrs.GetNamedItem(at_name)); if (!attrs.GetNamedItem(at_define).empty()) material.AddShaderDefine(CStrIntern(attrs.GetNamedItem(at_define)), str_1); } } material.RecomputeCombinedShaderDefines(); m_Materials[pathname] = material; return material; } Index: ps/trunk/source/graphics/ShaderManager.cpp =================================================================== --- ps/trunk/source/graphics/ShaderManager.cpp (revision 26210) +++ ps/trunk/source/graphics/ShaderManager.cpp (revision 26211) @@ -1,560 +1,564 @@ -/* Copyright (C) 2021 Wildfire Games. +/* 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 "ShaderManager.h" #include "graphics/PreprocessorWrapper.h" #include "graphics/ShaderTechnique.h" #include "lib/config2.h" #include "lib/hash.h" #include "lib/timer.h" #include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/CStrIntern.h" #include "ps/Filesystem.h" #include "ps/Profile.h" #include "ps/XML/Xeromyces.h" #include "ps/XML/XMLWriter.h" #include "ps/VideoMode.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #define USE_SHADER_XML_VALIDATION 1 #if USE_SHADER_XML_VALIDATION # include "ps/XML/RelaxNG.h" #endif +#include + TIMER_ADD_CLIENT(tc_ShaderValidation); CShaderManager::CShaderManager() { #if USE_SHADER_XML_VALIDATION { TIMER_ACCRUE(tc_ShaderValidation); if (!CXeromyces::AddValidator(g_VFS, "shader", "shaders/program.rng")) LOGERROR("CShaderManager: failed to load grammar shaders/program.rng"); } #endif // Allow hotloading of textures RegisterFileReloadFunc(ReloadChangedFileCB, this); } CShaderManager::~CShaderManager() { UnregisterFileReloadFunc(ReloadChangedFileCB, this); } CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const CShaderDefines& defines) { CacheKey key = { name, defines }; std::map::iterator it = m_ProgramCache.find(key); if (it != m_ProgramCache.end()) return it->second; CShaderProgramPtr program; if (!NewProgram(name, defines, program)) { LOGERROR("Failed to load shader '%s'", name); program = CShaderProgramPtr(); } m_ProgramCache[key] = program; return program; } static GLenum ParseAttribSemantics(const CStr& str) { // Map known semantics onto the attribute locations documented by NVIDIA if (str == "gl_Vertex") return 0; if (str == "gl_Normal") return 2; if (str == "gl_Color") return 3; if (str == "gl_SecondaryColor") return 4; if (str == "gl_FogCoord") return 5; if (str == "gl_MultiTexCoord0") return 8; if (str == "gl_MultiTexCoord1") return 9; if (str == "gl_MultiTexCoord2") return 10; if (str == "gl_MultiTexCoord3") return 11; if (str == "gl_MultiTexCoord4") return 12; if (str == "gl_MultiTexCoord5") return 13; if (str == "gl_MultiTexCoord6") return 14; if (str == "gl_MultiTexCoord7") return 15; // Define some arbitrary names for user-defined attribute locations // that won't conflict with any standard semantics if (str == "CustomAttribute0") return 1; if (str == "CustomAttribute1") return 6; if (str == "CustomAttribute2") return 7; debug_warn("Invalid attribute semantics"); return 0; } bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefines, CShaderProgramPtr& program) { PROFILE2("loading shader"); PROFILE2_ATTR("name: %s", name); VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml"; CXeromyces XeroFile; PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); if (ret != PSRETURN_OK) return false; #if USE_SHADER_XML_VALIDATION { TIMER_ACCRUE(tc_ShaderValidation); // Serialize the XMB data and pass it to the validator XMLWriter_File shaderFile; shaderFile.SetPrettyPrint(false); shaderFile.XMB(XeroFile); bool ok = CXeromyces::ValidateEncoded("shader", name, shaderFile.GetOutput()); if (!ok) return false; } #endif // Define all the elements and attributes used in the XML file #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) EL(attrib); EL(define); EL(fragment); EL(stream); EL(uniform); EL(vertex); AT(file); AT(if); AT(loc); AT(name); AT(semantics); AT(type); AT(value); #undef AT #undef EL CPreprocessorWrapper preprocessor; preprocessor.AddDefines(baseDefines); XMBElement Root = XeroFile.GetRoot(); const bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl"); if (!isGLSL && g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB) LOGWARNING("CShaderManager::NewProgram: '%s': trying to load a non-GLSL program with enabled GLSL", name); VfsPath vertexFile; VfsPath fragmentFile; CShaderDefines defines = baseDefines; std::map vertexUniforms; std::map fragmentUniforms; std::map vertexAttribs; int streamFlags = 0; XERO_ITER_EL(Root, Child) { if (Child.GetNodeName() == el_define) { defines.Add(CStrIntern(Child.GetAttributes().GetNamedItem(at_name)), CStrIntern(Child.GetAttributes().GetNamedItem(at_value))); } else if (Child.GetNodeName() == el_vertex) { vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); XERO_ITER_EL(Child, Param) { XMBAttributeList Attrs = Param.GetAttributes(); CStr cond = Attrs.GetNamedItem(at_if); if (!cond.empty() && !preprocessor.TestConditional(cond)) continue; if (Param.GetNodeName() == el_uniform) { vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt(); } else if (Param.GetNodeName() == el_stream) { CStr StreamName = Attrs.GetNamedItem(at_name); if (StreamName == "pos") streamFlags |= STREAM_POS; else if (StreamName == "normal") streamFlags |= STREAM_NORMAL; else if (StreamName == "color") streamFlags |= STREAM_COLOR; else if (StreamName == "uv0") streamFlags |= STREAM_UV0; else if (StreamName == "uv1") streamFlags |= STREAM_UV1; else if (StreamName == "uv2") streamFlags |= STREAM_UV2; else if (StreamName == "uv3") streamFlags |= STREAM_UV3; } else if (Param.GetNodeName() == el_attrib) { int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics)); vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc; } } } else if (Child.GetNodeName() == el_fragment) { fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); XERO_ITER_EL(Child, Param) { XMBAttributeList Attrs = Param.GetAttributes(); CStr cond = Attrs.GetNamedItem(at_if); if (!cond.empty() && !preprocessor.TestConditional(cond)) continue; if (Param.GetNodeName() == el_uniform) { // A somewhat incomplete listing, missing "shadow" and "rect" versions // which are interpreted as 2D (NB: our shadowmaps may change // type based on user config). GLenum type = GL_TEXTURE_2D; CStr t = Attrs.GetNamedItem(at_type); if (t == "sampler1D") #if CONFIG2_GLES debug_warn(L"sampler1D not implemented on GLES"); #else type = GL_TEXTURE_1D; #endif else if (t == "sampler2D") type = GL_TEXTURE_2D; else if (t == "sampler3D") #if CONFIG2_GLES debug_warn(L"sampler3D not implemented on GLES"); #else type = GL_TEXTURE_3D; #endif else if (t == "samplerCube") type = GL_TEXTURE_CUBE_MAP; fragmentUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = std::make_pair(Attrs.GetNamedItem(at_loc).ToInt(), type); } } } } if (isGLSL) program = CShaderProgramPtr(CShaderProgram::ConstructGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamFlags)); else program = CShaderProgramPtr(CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags)); program->Reload(); // m_HotloadFiles[xmlFilename].insert(program); // TODO: should reload somehow when the XML changes for (const VfsPath& path : program->GetFileDependencies()) AddProgramFileDependency(program, path); return true; } static GLenum ParseComparisonFunc(const CStr& str) { if (str == "never") return GL_NEVER; if (str == "always") return GL_ALWAYS; if (str == "less") return GL_LESS; if (str == "lequal") return GL_LEQUAL; if (str == "equal") return GL_EQUAL; if (str == "gequal") return GL_GEQUAL; if (str == "greater") return GL_GREATER; if (str == "notequal") return GL_NOTEQUAL; debug_warn("Invalid comparison func"); return GL_ALWAYS; } static GLenum ParseBlendFunc(const CStr& str) { if (str == "zero") return GL_ZERO; if (str == "one") return GL_ONE; if (str == "src_color") return GL_SRC_COLOR; if (str == "one_minus_src_color") return GL_ONE_MINUS_SRC_COLOR; if (str == "dst_color") return GL_DST_COLOR; if (str == "one_minus_dst_color") return GL_ONE_MINUS_DST_COLOR; if (str == "src_alpha") return GL_SRC_ALPHA; if (str == "one_minus_src_alpha") return GL_ONE_MINUS_SRC_ALPHA; if (str == "dst_alpha") return GL_DST_ALPHA; if (str == "one_minus_dst_alpha") return GL_ONE_MINUS_DST_ALPHA; if (str == "constant_color") return GL_CONSTANT_COLOR; if (str == "one_minus_constant_color") return GL_ONE_MINUS_CONSTANT_COLOR; if (str == "constant_alpha") return GL_CONSTANT_ALPHA; if (str == "one_minus_constant_alpha") return GL_ONE_MINUS_CONSTANT_ALPHA; if (str == "src_alpha_saturate") return GL_SRC_ALPHA_SATURATE; debug_warn("Invalid blend func"); return GL_ZERO; } size_t CShaderManager::EffectCacheKeyHash::operator()(const EffectCacheKey& key) const { size_t hash = 0; hash_combine(hash, key.name.GetHash()); hash_combine(hash, key.defines.GetHash()); return hash; } bool CShaderManager::EffectCacheKey::operator==(const EffectCacheKey& b) const { return name == b.name && defines == b.defines; } CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name) { return LoadEffect(name, CShaderDefines()); } CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDefines& defines) { // Return the cached effect, if there is one EffectCacheKey key = { name, defines }; EffectCacheMap::iterator it = m_EffectCache.find(key); if (it != m_EffectCache.end()) return it->second; // First time we've seen this key, so construct a new effect: CShaderTechniquePtr tech(new CShaderTechnique()); if (!NewEffect(name.c_str(), defines, tech)) { LOGERROR("Failed to load effect '%s'", name.c_str()); tech = CShaderTechniquePtr(); } m_EffectCache[key] = tech; return tech; } bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefines, CShaderTechniquePtr& tech) { PROFILE2("loading effect"); PROFILE2_ATTR("name: %s", name); VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name) + L".xml"; CXeromyces XeroFile; PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); if (ret != PSRETURN_OK) return false; // Define all the elements and attributes used in the XML file #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) - EL(alpha); EL(blend); EL(define); EL(depth); EL(pass); EL(require); EL(sort_by_distance); AT(context); AT(dst); AT(func); - AT(ref); AT(shader); AT(shaders); AT(src); AT(mask); AT(name); AT(value); #undef AT #undef EL // Read some defines that influence how we pick techniques const CRenderer::Caps& capabilities = g_Renderer.GetCapabilities(); const bool hasARB = capabilities.m_ARBProgram; const bool hasGLSL = capabilities.m_FragmentShader && capabilities.m_VertexShader; const bool preferGLSL = g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB; // Prepare the preprocessor for conditional tests CPreprocessorWrapper preprocessor; preprocessor.AddDefines(baseDefines); XMBElement Root = XeroFile.GetRoot(); // Find all the techniques that we can use, and their preference std::vector> usableTechs; XERO_ITER_EL(Root, Technique) { int preference = 0; bool isUsable = true; XERO_ITER_EL(Technique, Child) { XMBAttributeList Attrs = Child.GetAttributes(); + // TODO: require should be an attribute of the tech and not its child. if (Child.GetNodeName() == el_require) { if (Attrs.GetNamedItem(at_shaders) == "arb") { if (!hasARB) isUsable = false; } else if (Attrs.GetNamedItem(at_shaders) == "glsl") { if (!hasGLSL) isUsable = false; if (preferGLSL) preference += 100; else preference -= 100; } else if (!Attrs.GetNamedItem(at_context).empty()) { CStr cond = Attrs.GetNamedItem(at_context); if (!preprocessor.TestConditional(cond)) isUsable = false; } } } if (isUsable) usableTechs.emplace_back(Technique, preference); } if (usableTechs.empty()) { debug_warn(L"Can't find a usable technique"); return false; } // Sort by preference, tie-break on order of specification std::stable_sort(usableTechs.begin(), usableTechs.end(), [](const std::pair& a, const std::pair& b) { return b.second < a.second; }); CShaderDefines techDefines = baseDefines; - XERO_ITER_EL(usableTechs[0].first, Child) { if (Child.GetNodeName() == el_define) { techDefines.Add(CStrIntern(Child.GetAttributes().GetNamedItem(at_name)), CStrIntern(Child.GetAttributes().GetNamedItem(at_value))); } else if (Child.GetNodeName() == el_sort_by_distance) { tech->SetSortByDistance(true); } - else if (Child.GetNodeName() == el_pass) + } + // We don't want to have a shader context depending on the order of define and + // pass tags. + // TODO: we might want to implement that in a proper way via splitting passes + // and tags in different groups in XML. + std::vector techPasses; + XERO_ITER_EL(usableTechs[0].first, Child) + { + if (Child.GetNodeName() == el_pass) { CShaderDefines passDefines = techDefines; CShaderPass pass; XERO_ITER_EL(Child, Element) { if (Element.GetNodeName() == el_define) { passDefines.Add(CStrIntern(Element.GetAttributes().GetNamedItem(at_name)), CStrIntern(Element.GetAttributes().GetNamedItem(at_value))); } - else if (Element.GetNodeName() == el_alpha) - { - GLenum func = ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func)); - float ref = Element.GetAttributes().GetNamedItem(at_ref).ToFloat(); - pass.AlphaFunc(func, ref); - } else if (Element.GetNodeName() == el_blend) { GLenum src = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_src)); GLenum dst = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_dst)); pass.BlendFunc(src, dst); } else if (Element.GetNodeName() == el_depth) { if (!Element.GetAttributes().GetNamedItem(at_func).empty()) pass.DepthFunc(ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func))); if (!Element.GetAttributes().GetNamedItem(at_mask).empty()) pass.DepthMask(Element.GetAttributes().GetNamedItem(at_mask) == "true" ? 1 : 0); } } // Load the shader program after we've read all the possibly-relevant s pass.SetShader(LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines)); - tech->AddPass(pass); + techPasses.emplace_back(std::move(pass)); } } + tech->SetPasses(std::move(techPasses)); + return true; } size_t CShaderManager::GetNumEffectsLoaded() const { return m_EffectCache.size(); } /*static*/ Status CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path) { return static_cast(param)->ReloadChangedFile(path); } Status CShaderManager::ReloadChangedFile(const VfsPath& path) { // Find all shaders using this file HotloadFilesMap::iterator files = m_HotloadFiles.find(path); if (files == m_HotloadFiles.end()) return INFO::OK; // Reload all shaders using this file for (const std::weak_ptr& ptr : files->second) if (std::shared_ptr program = ptr.lock()) program->Reload(); // TODO: hotloading changes to shader XML files and effect XML files would be nice return INFO::OK; } void CShaderManager::AddProgramFileDependency(const CShaderProgramPtr& program, const VfsPath& path) { m_HotloadFiles[path].insert(program); } Index: ps/trunk/source/graphics/ShaderTechnique.cpp =================================================================== --- ps/trunk/source/graphics/ShaderTechnique.cpp (revision 26210) +++ ps/trunk/source/graphics/ShaderTechnique.cpp (revision 26211) @@ -1,158 +1,133 @@ /* 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 "ShaderTechnique.h" #include "graphics/ShaderProgram.h" -CShaderPass::CShaderPass() : - m_HasAlpha(false), m_HasBlend(false), m_HasColorMask(false), m_HasDepthMask(false), m_HasDepthFunc(false) -{ -} +CShaderPass::CShaderPass() = default; void CShaderPass::Bind() { m_Shader->Bind(); -#if !CONFIG2_GLES - if (m_HasAlpha) - { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(m_AlphaFunc, m_AlphaRef); - } -#endif // TODO: maybe emit some warning if GLSL shaders try to use alpha test; // the test should be done inside the shader itself if (m_HasBlend) { glEnable(GL_BLEND); glBlendFunc(m_BlendSrc, m_BlendDst); } if (m_HasColorMask) glColorMask(m_ColorMaskR, m_ColorMaskG, m_ColorMaskB, m_ColorMaskA); if (m_HasDepthMask) glDepthMask(m_DepthMask); if (m_HasDepthFunc) glDepthFunc(m_DepthFunc); } void CShaderPass::Unbind() { m_Shader->Unbind(); -#if !CONFIG2_GLES - if (m_HasAlpha) - glDisable(GL_ALPHA_TEST); -#endif - if (m_HasBlend) glDisable(GL_BLEND); if (m_HasColorMask) glColorMask(1, 1, 1, 1); if (m_HasDepthMask) glDepthMask(1); if (m_HasDepthFunc) glDepthFunc(GL_LEQUAL); } -void CShaderPass::AlphaFunc(GLenum func, GLclampf ref) -{ - m_HasAlpha = true; - m_AlphaFunc = func; - m_AlphaRef = ref; -} - void CShaderPass::BlendFunc(GLenum src, GLenum dst) { m_HasBlend = true; m_BlendSrc = src; m_BlendDst = dst; } void CShaderPass::ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { m_HasColorMask = true; m_ColorMaskR = r; m_ColorMaskG = g; m_ColorMaskB = b; m_ColorMaskA = a; } void CShaderPass::DepthMask(GLboolean mask) { m_HasDepthMask = true; m_DepthMask = mask; } void CShaderPass::DepthFunc(GLenum func) { m_HasDepthFunc = true; m_DepthFunc = func; } -CShaderTechnique::CShaderTechnique() - : m_SortByDistance(false) -{ -} +CShaderTechnique::CShaderTechnique() = default; -void CShaderTechnique::AddPass(const CShaderPass& pass) +void CShaderTechnique::SetPasses(std::vector&& passes) { - m_Passes.push_back(pass); + m_Passes = std::move(passes); } int CShaderTechnique::GetNumPasses() const { return m_Passes.size(); } void CShaderTechnique::BeginPass(int pass) { ENSURE(0 <= pass && pass < (int)m_Passes.size()); m_Passes[pass].Bind(); } void CShaderTechnique::EndPass(int pass) { ENSURE(0 <= pass && pass < (int)m_Passes.size()); m_Passes[pass].Unbind(); } const CShaderProgramPtr& CShaderTechnique::GetShader(int pass) const { ENSURE(0 <= pass && pass < (int)m_Passes.size()); return m_Passes[pass].GetShader(); } bool CShaderTechnique::GetSortByDistance() const { return m_SortByDistance; } void CShaderTechnique::SetSortByDistance(bool enable) { m_SortByDistance = enable; } Index: ps/trunk/source/graphics/ShaderTechnique.h =================================================================== --- ps/trunk/source/graphics/ShaderTechnique.h (revision 26210) +++ ps/trunk/source/graphics/ShaderTechnique.h (revision 26211) @@ -1,114 +1,109 @@ /* 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 . */ #ifndef INCLUDED_SHADERTECHNIQUE #define INCLUDED_SHADERTECHNIQUE #include "graphics/ShaderProgramPtr.h" #include "graphics/ShaderTechniquePtr.h" #include "lib/ogl.h" #include /** * Implements a render pass consisting of various GL state changes and a shader, * used by CShaderTechnique. */ class CShaderPass { public: CShaderPass(); /** * Set the shader program used for rendering with this pass. */ void SetShader(const CShaderProgramPtr& shader) { m_Shader = shader; } // Add various bits of GL state to the pass: - void AlphaFunc(GLenum func, GLclampf ref); void BlendFunc(GLenum src, GLenum dst); void ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a); void DepthMask(GLboolean mask); void DepthFunc(GLenum func); /** * Set up all the GL state that was previously specified on this pass. */ void Bind(); /** * Reset the GL state to the default. */ void Unbind(); const CShaderProgramPtr& GetShader() const { return m_Shader; } private: CShaderProgramPtr m_Shader; - bool m_HasAlpha; - GLenum m_AlphaFunc; - GLclampf m_AlphaRef; - - bool m_HasBlend; + bool m_HasBlend = false; GLenum m_BlendSrc; GLenum m_BlendDst; - bool m_HasColorMask; + bool m_HasColorMask = false; GLboolean m_ColorMaskR; GLboolean m_ColorMaskG; GLboolean m_ColorMaskB; GLboolean m_ColorMaskA; - bool m_HasDepthMask; + bool m_HasDepthMask = false; GLboolean m_DepthMask; - bool m_HasDepthFunc; + bool m_HasDepthFunc = false; GLenum m_DepthFunc; }; /** * Implements a render technique consisting of a sequence of passes. * CShaderManager loads these from shader effect XML files. */ class CShaderTechnique { public: CShaderTechnique(); - void AddPass(const CShaderPass& pass); + void SetPasses(std::vector&& passes); int GetNumPasses() const; void BeginPass(int pass = 0); void EndPass(int pass = 0); const CShaderProgramPtr& GetShader(int pass = 0) const; /** * Whether this technique uses alpha blending that requires objects to be * drawn from furthest to nearest. */ bool GetSortByDistance() const; void SetSortByDistance(bool enable); private: std::vector m_Passes; - bool m_SortByDistance; + bool m_SortByDistance = false; }; #endif // INCLUDED_SHADERTECHNIQUE Index: ps/trunk/source/renderer/RenderingOptions.cpp =================================================================== --- ps/trunk/source/renderer/RenderingOptions.cpp (revision 26210) +++ ps/trunk/source/renderer/RenderingOptions.cpp (revision 26211) @@ -1,266 +1,264 @@ /* 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 "RenderingOptions.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStr.h" #include "ps/CStrInternStatic.h" #include "ps/VideoMode.h" #include "renderer/Renderer.h" #include "renderer/PostprocManager.h" #include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" CRenderingOptions g_RenderingOptions; class CRenderingOptions::ConfigHooks { public: std::vector::iterator begin() { return hooks.begin(); } std::vector::iterator end() { return hooks.end(); } template void Setup(CStr8 name, T& variable) { hooks.emplace_back(g_ConfigDB.RegisterHookAndCall(name, [name, &variable]() { CFG_GET_VAL(name, variable); })); } void Setup(CStr8 name, std::function hook) { hooks.emplace_back(g_ConfigDB.RegisterHookAndCall(name, hook)); } void clear() { hooks.clear(); } private: std::vector hooks; }; RenderPath RenderPathEnum::FromString(const CStr8& name) { if (name == "default") return DEFAULT; if (name == "fixed") return FIXED; if (name == "shader") return SHADER; LOGWARNING("Unknown render path %s", name.c_str()); return DEFAULT; } CStr8 RenderPathEnum::ToString(RenderPath path) { switch (path) { case RenderPath::DEFAULT: return "default"; case RenderPath::FIXED: return "fixed"; case RenderPath::SHADER: return "shader"; } return "default"; // Silence warning about reaching end of non-void function. } RenderDebugMode RenderDebugModeEnum::FromString(const CStr8& name) { if (name == str_RENDER_DEBUG_MODE_NONE.c_str()) return RenderDebugMode::NONE; if (name == str_RENDER_DEBUG_MODE_AO.c_str()) return RenderDebugMode::AO; if (name == str_RENDER_DEBUG_MODE_ALPHA.c_str()) return RenderDebugMode::ALPHA; if (name == str_RENDER_DEBUG_MODE_CUSTOM.c_str()) return RenderDebugMode::CUSTOM; LOGWARNING("Unknown render debug mode %s", name.c_str()); return RenderDebugMode::NONE; } CStrIntern RenderDebugModeEnum::ToString(RenderDebugMode mode) { switch (mode) { case RenderDebugMode::AO: return str_RENDER_DEBUG_MODE_AO; case RenderDebugMode::ALPHA: return str_RENDER_DEBUG_MODE_ALPHA; case RenderDebugMode::CUSTOM: return str_RENDER_DEBUG_MODE_CUSTOM; default: break; } return str_RENDER_DEBUG_MODE_NONE; } CRenderingOptions::CRenderingOptions() : m_ConfigHooks(new ConfigHooks()) { m_RenderPath = RenderPath::DEFAULT; m_Shadows = false; m_WaterEffects = false; m_WaterFancyEffects = false; m_WaterRealDepth = false; m_WaterRefraction = false; m_WaterReflection = false; m_ShadowAlphaFix = false; m_ARBProgramShadow = true; m_ShadowPCF = false; m_Particles = false; m_Silhouettes = false; m_Fog = false; - m_ForceAlphaTest = false; m_GPUSkinning = false; m_SmoothLOS = false; m_PostProc = false; m_DisplayFrustum = false; m_DisplayShadowsFrustum = false; m_RenderActors = true; } CRenderingOptions::~CRenderingOptions() { ClearHooks(); } void CRenderingOptions::ReadConfigAndSetupHooks() { m_ConfigHooks->Setup("renderpath", [this]() { CStr renderPath; CFG_GET_VAL("renderpath", renderPath); SetRenderPath(RenderPathEnum::FromString(renderPath)); }); m_ConfigHooks->Setup("shadowquality", []() { if (CRenderer::IsInitialised()) g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadowscascadecount", []() { if (CRenderer::IsInitialised()) { g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscovermap", []() { if (CRenderer::IsInitialised()) { g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscutoffdistance", []() { if (CRenderer::IsInitialised()) g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadows", [this]() { bool enabled; CFG_GET_VAL("shadows", enabled); SetShadows(enabled); }); m_ConfigHooks->Setup("shadowpcf", [this]() { bool enabled; CFG_GET_VAL("shadowpcf", enabled); SetShadowPCF(enabled); }); m_ConfigHooks->Setup("postproc", m_PostProc); m_ConfigHooks->Setup("antialiasing", []() { if (CRenderer::IsInitialised()) g_Renderer.GetPostprocManager().UpdateAntiAliasingTechnique(); }); m_ConfigHooks->Setup("sharpness", []() { if (CRenderer::IsInitialised()) g_Renderer.GetPostprocManager().UpdateSharpnessFactor(); }); m_ConfigHooks->Setup("sharpening", []() { if (CRenderer::IsInitialised()) g_Renderer.GetPostprocManager().UpdateSharpeningTechnique(); }); m_ConfigHooks->Setup("smoothlos", m_SmoothLOS); m_ConfigHooks->Setup("watereffects", m_WaterEffects); m_ConfigHooks->Setup("waterfancyeffects", m_WaterFancyEffects); m_ConfigHooks->Setup("waterrealdepth", m_WaterRealDepth); m_ConfigHooks->Setup("waterrefraction", m_WaterRefraction); m_ConfigHooks->Setup("waterreflection", m_WaterReflection); m_ConfigHooks->Setup("particles", m_Particles); m_ConfigHooks->Setup("fog", [this]() { bool enabled; CFG_GET_VAL("fog", enabled); SetFog(enabled); }); m_ConfigHooks->Setup("silhouettes", m_Silhouettes); - m_ConfigHooks->Setup("forcealphatest", m_ForceAlphaTest); m_ConfigHooks->Setup("gpuskinning", [this]() { bool enabled; CFG_GET_VAL("gpuskinning", enabled); if (enabled && g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB) LOGWARNING("GPUSkinning has been disabled, because it is not supported with ARB shaders."); else if (enabled) m_GPUSkinning = true; }); m_ConfigHooks->Setup("renderactors", m_RenderActors); } void CRenderingOptions::ClearHooks() { m_ConfigHooks->clear(); } void CRenderingOptions::SetShadows(bool value) { m_Shadows = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } void CRenderingOptions::SetShadowPCF(bool value) { m_ShadowPCF = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } void CRenderingOptions::SetFog(bool value) { m_Fog = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } void CRenderingOptions::SetRenderPath(RenderPath value) { m_RenderPath = value; if (CRenderer::IsInitialised()) g_Renderer.SetRenderPath(m_RenderPath); } void CRenderingOptions::SetRenderDebugMode(RenderDebugMode value) { m_RenderDebugMode = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } Index: ps/trunk/source/renderer/RenderingOptions.h =================================================================== --- ps/trunk/source/renderer/RenderingOptions.h (revision 26210) +++ ps/trunk/source/renderer/RenderingOptions.h (revision 26211) @@ -1,140 +1,139 @@ -/* Copyright (C) 2021 Wildfire Games. +/* 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 . */ /** * Keeps track of the settings used for rendering. * Ideally this header file should remain very quick to parse, * so avoid including other headers here unless absolutely necessary. * * Lifetime concerns: g_RenderingOptions always exists, but hooks are tied to the configDB's lifetime * an the renderer may or may not actually exist. */ #ifndef INCLUDED_RENDERINGOPTIONS #define INCLUDED_RENDERINGOPTIONS #include "ps/CStr.h" #include "ps/CStrIntern.h" class CRenderer; enum RenderPath { // If no rendering path is configured explicitly, the renderer // will choose the path when Open() is called. DEFAULT, // Classic fixed function. FIXED, // Use new ARB/GLSL system SHADER }; struct RenderPathEnum { static RenderPath FromString(const CStr8& name); static CStr8 ToString(RenderPath); }; enum class RenderDebugMode { NONE, AO, ALPHA, CUSTOM }; struct RenderDebugModeEnum { static RenderDebugMode FromString(const CStr8& name); static CStrIntern ToString(RenderDebugMode mode); }; class CRenderingOptions { // The renderer needs access to our private variables directly because capabilities have not yet been extracted // and thus sometimes it needs to change the rendering options without the side-effects. friend class CRenderer; public: CRenderingOptions(); ~CRenderingOptions(); void ReadConfigAndSetupHooks(); void ClearHooks(); #define OPTION_DEFAULT_SETTER(NAME, TYPE) \ public: void Set##NAME(TYPE value) { m_##NAME = value; }\ #define OPTION_CUSTOM_SETTER(NAME, TYPE) \ public: void Set##NAME(TYPE value);\ #define OPTION_GETTER(NAME, TYPE)\ public: TYPE Get##NAME() const { return m_##NAME; }\ #define OPTION_DEF(NAME, TYPE)\ private: TYPE m_##NAME; #define OPTION(NAME, TYPE)\ OPTION_DEFAULT_SETTER(NAME, TYPE); OPTION_GETTER(NAME, TYPE); OPTION_DEF(NAME, TYPE); #define OPTION_WITH_SIDE_EFFECT(NAME, TYPE)\ OPTION_CUSTOM_SETTER(NAME, TYPE); OPTION_GETTER(NAME, TYPE); OPTION_DEF(NAME, TYPE); OPTION_WITH_SIDE_EFFECT(Shadows, bool); OPTION_WITH_SIDE_EFFECT(ShadowPCF, bool); OPTION_WITH_SIDE_EFFECT(Fog, bool); OPTION_WITH_SIDE_EFFECT(RenderPath, RenderPath); OPTION_WITH_SIDE_EFFECT(RenderDebugMode, RenderDebugMode); OPTION(WaterEffects, bool); OPTION(WaterFancyEffects, bool); OPTION(WaterRealDepth, bool); OPTION(WaterRefraction, bool); OPTION(WaterReflection, bool); OPTION(ShadowAlphaFix, bool); OPTION(ARBProgramShadow, bool); OPTION(Particles, bool); - OPTION(ForceAlphaTest, bool); OPTION(GPUSkinning, bool); OPTION(Silhouettes, bool); OPTION(SmoothLOS, bool); OPTION(PostProc, bool); OPTION(DisplayFrustum, bool); OPTION(DisplayShadowsFrustum, bool); OPTION(RenderActors, bool); #undef OPTION_DEFAULT_SETTER #undef OPTION_CUSTOM_SETTER #undef OPTION_GETTER #undef OPTION_DEF #undef OPTION #undef OPTION_WITH_SIDE_EFFECT private: class ConfigHooks; std::unique_ptr m_ConfigHooks; // Hide this via PImpl to avoid including ConfigDB.h here. }; extern CRenderingOptions g_RenderingOptions; #endif // INCLUDED_RENDERINGOPTIONS