diff -Nru 0ad-0.0.24~r24010/binaries/data/l10n/es.engine.po 0ad-0.0.24~r24155/binaries/data/l10n/es.engine.po --- 0ad-0.0.24~r24010/binaries/data/l10n/es.engine.po 2020-05-25 07:35:52.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/data/l10n/es.engine.po 2020-10-05 08:07:20.000000000 +0000 @@ -13,21 +13,23 @@ # Ignacio Casal , 2019 # fca1970 , 2014 # Juan Jaramillo , 2014-2015 -# Miguel Magdaleno Santamaría , 2020 +# Miguel Magdaleno Santamaría, 2020 # Mihai Pantazi , 2016,2018 # Mikel Soutullo , 2019 # Nacho Carretero , 2018 # OJankano , 2014 # Pablo Rodríguez , 2016 +# Rodrigo Vegas Sánchez-Ferrero , 2020 # Samuel Roman , 2016 -# Swyter , 2013-2014,2016-2018 +# Swyter ™ , 2013-2014,2016-2018 +# Swyter ™ , 2020 # tarod kaos , 2015 msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" "POT-Creation-Date: 2020-05-22 07:08+0000\n" -"PO-Revision-Date: 2020-05-22 17:31+0000\n" -"Last-Translator: Miguel Magdaleno Santamaría \n" +"PO-Revision-Date: 2020-10-04 12:19+0000\n" +"Last-Translator: Rodrigo Vegas Sánchez-Ferrero \n" "Language-Team: Spanish (http://www.transifex.com/wildfire-games/0ad/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -49,7 +51,7 @@ #: lobby/XmppClient.cpp:1216 msgid "The certificate hasn't got a known issuer." -msgstr "El certificado no tiene un emisor conocido." +msgstr "El certificado no pertenece a un emisor conocido." #: lobby/XmppClient.cpp:1217 msgid "The certificate has been revoked." @@ -57,7 +59,7 @@ #: lobby/XmppClient.cpp:1218 msgid "The certificate has expired." -msgstr "El certificado ha expirado" +msgstr "El certificado ha expirado." #: lobby/XmppClient.cpp:1219 msgid "The certificate is not yet active." @@ -65,7 +67,7 @@ #: lobby/XmppClient.cpp:1220 msgid "The certificate has not been issued for the peer connected to." -msgstr "El certificado no ha sido emitido para el par al que está conectado" +msgstr "El certificado no ha sido emitido para el extremo con el que ha conectado." #: lobby/XmppClient.cpp:1221 msgid "The certificate signer is not a certificate authority." @@ -78,7 +80,7 @@ #: lobby/XmppClient.cpp:1246 lobby/XmppClient.cpp:1290 msgid "No error" -msgstr "Sin error" +msgstr "Sin errores" #: lobby/XmppClient.cpp:1248 msgid "Player already logged in" @@ -130,7 +132,7 @@ #: lobby/XmppClient.cpp:1297 msgid "An I/O error occurred" -msgstr "Se ha producido un error de E/S (de entrada/salida)" +msgstr "Se ha producido un error de E/S" #: lobby/XmppClient.cpp:1299 msgid "The connection was refused by the server" @@ -168,7 +170,7 @@ #: lobby/XmppClient.cpp:1329 msgid "Your account has been successfully registered" -msgstr "Hemos registrado tu cuenta en el sistema." +msgstr "Tu cuenta se ha creado con éxito" #: lobby/XmppClient.cpp:1330 msgid "Not all necessary information provided" @@ -181,50 +183,50 @@ #: ps/ModIo.cpp:261 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." -msgstr "Error al iniciar la búsqueda de la identificación del juego. Error: %s;%s." +msgstr "Error al comenzar la solicitud para el id. del juego. Error: %s;%s." #: ps/ModIo.cpp:291 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." -msgstr "Error al iniciar la consulta de mods. Error: %s; %s." +msgstr "Error al iniciar la búsqueda de mods. Error: %s; %s." #: ps/ModIo.cpp:317 #, c-format msgid "Could not create mod directory: %s." -msgstr "No se pudo crear el directorio de mods: %s." +msgstr "No se ha podido crear el directorio de mods: %s." #: ps/ModIo.cpp:342 #, c-format msgid "Could not open temporary file for mod download: %s." -msgstr "No se pudo abrir el archivo temporal para la descarga de mods: %s." +msgstr "No se ha podido abrir el archivo temporal para la descarga del mod: %s." #: ps/ModIo.cpp:352 #, c-format msgid "Failed to start the download. Error: %s; %s." -msgstr "Fallo al iniciar la descarga. Error: %s; %s." +msgstr "Error al iniciar la descarga: %s; %s." #: ps/ModIo.cpp:397 #, c-format msgid "Asynchronous download failure: %s, %s." -msgstr "Fallo asíncrono en la descarga: %s, %s" +msgstr "Error de sincronía en la descarga: %s, %s." #: ps/ModIo.cpp:426 #, c-format msgid "Download failure. Server response: %s; %s." -msgstr "Fallo en la descarga. Respuesta del servidor: %s; %s." +msgstr "Error en la descarga. Respuesta del servidor: %s; %s." #: ps/ModIo.cpp:529 msgid "Mismatched filesize." -msgstr "Tamaño del archivo no coincide" +msgstr "El tamaño del archivo no coincide." #: ps/ModIo.cpp:547 #, c-format msgid "Invalid file. Expected md5 %s, got %s." -msgstr "Archivo incorrecto. md5 esperado: %s; obtenido: %s." +msgstr "Archivo incorrecto. Se esperaba el siguiente md5: %s y se ha obtenido %s." #: ps/ModIo.cpp:562 msgid "Failed to compute final hash." -msgstr "Error al calcular el último hash." +msgstr "Error al calcular el hash final." #: ps/ModIo.cpp:568 msgid "Failed to verify signature." @@ -242,4 +244,4 @@ #: ps/scripting/JSInterface_Debug.cpp:83 msgid "custom build" -msgstr "versión propia" +msgstr "revisión" diff -Nru 0ad-0.0.24~r24010/binaries/data/l10n/es_MX.engine.po 0ad-0.0.24~r24155/binaries/data/l10n/es_MX.engine.po --- 0ad-0.0.24~r24010/binaries/data/l10n/es_MX.engine.po 2020-05-25 07:35:52.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/data/l10n/es_MX.engine.po 2020-09-25 07:29:52.000000000 +0000 @@ -3,6 +3,7 @@ # This file is distributed under the same license as the Pyrogenesis project. # # Translators: +# Carlos Huihua , 2020 # Daniel Bautista , 2014 # Edgar Carballo , 2015-2016 # Fredy García , 2018 @@ -13,8 +14,8 @@ msgstr "" "Project-Id-Version: 0 A.D.\n" "POT-Creation-Date: 2020-05-22 07:08+0000\n" -"PO-Revision-Date: 2020-05-22 10:20+0000\n" -"Last-Translator: Transifex Bot <>\n" +"PO-Revision-Date: 2020-09-24 21:34+0000\n" +"Last-Translator: Carlos Huihua \n" "Language-Team: Spanish (Mexico) (http://www.transifex.com/wildfire-games/0ad/language/es_MX/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,7 +25,7 @@ #: i18n/L10n.cpp:251 msgid "Long strings" -msgstr "Cadenas largas" +msgstr "Cuerdas largas" #: lobby/XmppClient.cpp:887 msgid "unknown subtype (see logs)" @@ -48,7 +49,7 @@ #: lobby/XmppClient.cpp:1219 msgid "The certificate is not yet active." -msgstr "" +msgstr "El certificado aún no está activo." #: lobby/XmppClient.cpp:1220 msgid "The certificate has not been issued for the peer connected to." @@ -229,4 +230,4 @@ #: ps/scripting/JSInterface_Debug.cpp:83 msgid "custom build" -msgstr "custom build" +msgstr "Construcción personalizada" diff -Nru 0ad-0.0.24~r24010/binaries/data/l10n/kn.engine.po 0ad-0.0.24~r24155/binaries/data/l10n/kn.engine.po --- 0ad-0.0.24~r24010/binaries/data/l10n/kn.engine.po 2016-03-19 08:56:41.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/data/l10n/kn.engine.po 2020-11-02 10:01:51.000000000 +0000 @@ -1,161 +1,225 @@ # Translation template for Pyrogenesis. -# Copyright © 2014 Wildfire Games +# Copyright (C) 2020 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # # Translators: msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2016-03-12 18:52+0100\n" -"PO-Revision-Date: 2016-01-08 09:20+0000\n" -"Last-Translator: Adrián Chaves Fernández \n" +"POT-Creation-Date: 2020-05-22 07:08+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" "Language-Team: Kannada (http://www.transifex.com/wildfire-games/0ad/language/kn/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" -#. Translation: First item is a date and time, item between parenthesis is the -#. Subversion revision number of the current build. -#: gui/scripting/ScriptFunctions.cpp:823 -#, c-format -msgid "%s (custom build)" +#: i18n/L10n.cpp:251 +msgid "Long strings" msgstr "" -#. Translation: First item is a date and time, item between parenthesis is the -#. Subversion revision number of the current build. -#: gui/scripting/ScriptFunctions.cpp:828 -#, c-format -msgid "%s (%ls)" +#: lobby/XmppClient.cpp:887 +msgid "unknown subtype (see logs)" msgstr "" -#: gui/scripting/ScriptFunctions.cpp:849 -msgid "custom build" +#: lobby/XmppClient.cpp:1215 +msgid "The certificate is not trusted." msgstr "" -#: i18n/L10n.cpp:252 -msgid "Long strings" +#: lobby/XmppClient.cpp:1216 +msgid "The certificate hasn't got a known issuer." msgstr "" -#: lobby/XmppClient.cpp:750 -msgid "unknown subtype (see logs)" +#: lobby/XmppClient.cpp:1217 +msgid "The certificate has been revoked." +msgstr "" + +#: lobby/XmppClient.cpp:1218 +msgid "The certificate has expired." +msgstr "" + +#: lobby/XmppClient.cpp:1219 +msgid "The certificate is not yet active." +msgstr "" + +#: lobby/XmppClient.cpp:1220 +msgid "The certificate has not been issued for the peer connected to." +msgstr "" + +#: lobby/XmppClient.cpp:1221 +msgid "The certificate signer is not a certificate authority." msgstr "" -#: lobby/XmppClient.cpp:1001 lobby/XmppClient.cpp:1045 -#: lobby/XmppClient.cpp:1084 +#: lobby/XmppClient.cpp:1243 lobby/XmppClient.cpp:1287 +#: lobby/XmppClient.cpp:1326 msgid "Error" msgstr "" -#: lobby/XmppClient.cpp:1004 lobby/XmppClient.cpp:1048 +#: lobby/XmppClient.cpp:1246 lobby/XmppClient.cpp:1290 msgid "No error" msgstr "" -#: lobby/XmppClient.cpp:1006 +#: lobby/XmppClient.cpp:1248 msgid "Player already logged in" msgstr "" -#: lobby/XmppClient.cpp:1008 +#: lobby/XmppClient.cpp:1250 msgid "Forbidden" msgstr "" -#: lobby/XmppClient.cpp:1010 +#: lobby/XmppClient.cpp:1252 msgid "Internal server error" msgstr "" -#: lobby/XmppClient.cpp:1014 +#: lobby/XmppClient.cpp:1256 msgid "Not allowed" msgstr "" -#: lobby/XmppClient.cpp:1015 +#: lobby/XmppClient.cpp:1257 msgid "Not authorized" msgstr "" -#: lobby/XmppClient.cpp:1018 +#: lobby/XmppClient.cpp:1260 msgid "Recipient temporarily unavailable" msgstr "" -#: lobby/XmppClient.cpp:1020 +#: lobby/XmppClient.cpp:1262 msgid "Registration required" msgstr "" -#: lobby/XmppClient.cpp:1024 +#: lobby/XmppClient.cpp:1266 msgid "Service unavailable" msgstr "" -#: lobby/XmppClient.cpp:1029 lobby/XmppClient.cpp:1068 -#: lobby/XmppClient.cpp:1097 +#: lobby/XmppClient.cpp:1271 lobby/XmppClient.cpp:1310 msgid "Unknown error" msgstr "" -#: lobby/XmppClient.cpp:1049 +#: lobby/XmppClient.cpp:1291 msgid "Stream error" msgstr "" -#: lobby/XmppClient.cpp:1050 +#: lobby/XmppClient.cpp:1292 msgid "The incoming stream version is unsupported" msgstr "" -#: lobby/XmppClient.cpp:1051 +#: lobby/XmppClient.cpp:1293 msgid "The stream has been closed by the server" msgstr "" -#: lobby/XmppClient.cpp:1055 -msgid "An I/O error occured" +#: lobby/XmppClient.cpp:1297 +msgid "An I/O error occurred" msgstr "" -#: lobby/XmppClient.cpp:1057 +#: lobby/XmppClient.cpp:1299 msgid "The connection was refused by the server" msgstr "" -#: lobby/XmppClient.cpp:1058 +#: lobby/XmppClient.cpp:1300 msgid "Resolving the server's hostname failed" msgstr "" -#: lobby/XmppClient.cpp:1059 +#: lobby/XmppClient.cpp:1301 msgid "This system is out of memory" msgstr "" -#: lobby/XmppClient.cpp:1061 +#: lobby/XmppClient.cpp:1303 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "" -#: lobby/XmppClient.cpp:1062 +#: lobby/XmppClient.cpp:1304 msgid "The server did not offer required TLS encryption" msgstr "" -#: lobby/XmppClient.cpp:1064 +#: lobby/XmppClient.cpp:1306 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "" -#: lobby/XmppClient.cpp:1065 +#: lobby/XmppClient.cpp:1307 msgid "The user or system requested a disconnect" msgstr "" -#: lobby/XmppClient.cpp:1066 +#: lobby/XmppClient.cpp:1308 msgid "There is no active connection" msgstr "" -#: lobby/XmppClient.cpp:1087 -msgid "Success" +#: lobby/XmppClient.cpp:1329 +msgid "Your account has been successfully registered" msgstr "" -#: lobby/XmppClient.cpp:1088 +#: lobby/XmppClient.cpp:1330 msgid "Not all necessary information provided" msgstr "" -#: lobby/XmppClient.cpp:1089 +#: lobby/XmppClient.cpp:1331 msgid "Username already exists" msgstr "" -#: ps/SavedGame.cpp:133 +#: ps/ModIo.cpp:261 +#, c-format +msgid "Failure while starting querying for game id. Error: %s; %s." +msgstr "" + +#: ps/ModIo.cpp:291 +#, c-format +msgid "Failure while starting querying for mods. Error: %s; %s." +msgstr "" + +#: ps/ModIo.cpp:317 +#, c-format +msgid "Could not create mod directory: %s." +msgstr "" + +#: ps/ModIo.cpp:342 +#, c-format +msgid "Could not open temporary file for mod download: %s." +msgstr "" + +#: ps/ModIo.cpp:352 +#, c-format +msgid "Failed to start the download. Error: %s; %s." +msgstr "" + +#: ps/ModIo.cpp:397 +#, c-format +msgid "Asynchronous download failure: %s, %s." +msgstr "" + +#: ps/ModIo.cpp:426 +#, c-format +msgid "Download failure. Server response: %s; %s." +msgstr "" + +#: ps/ModIo.cpp:529 +msgid "Mismatched filesize." +msgstr "" + +#: ps/ModIo.cpp:547 +#, c-format +msgid "Invalid file. Expected md5 %s, got %s." +msgstr "" + +#: ps/ModIo.cpp:562 +msgid "Failed to compute final hash." +msgstr "" + +#: ps/ModIo.cpp:568 +msgid "Failed to verify signature." +msgstr "" + +#: ps/SavedGame.cpp:139 #, c-format msgid "Saved game to '%s'" msgstr "" -#: ps/Util.cpp:275 ps/Util.cpp:408 +#: ps/Util.cpp:280 ps/Util.cpp:283 ps/Util.cpp:424 ps/Util.cpp:427 #, c-format msgid "Screenshot written to '%s'" msgstr "" + +#: ps/scripting/JSInterface_Debug.cpp:83 +msgid "custom build" +msgstr "" diff -Nru 0ad-0.0.24~r24010/binaries/data/l10n/ko.engine.po 0ad-0.0.24~r24155/binaries/data/l10n/ko.engine.po --- 0ad-0.0.24~r24010/binaries/data/l10n/ko.engine.po 2020-06-08 07:38:58.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/data/l10n/ko.engine.po 2020-09-11 07:33:56.000000000 +0000 @@ -3,7 +3,9 @@ # This file is distributed under the same license as the Pyrogenesis project. # # Translators: -# MarongHappy , 2019 +# 76407af6b051a571d67c2577de2183db_7380deb <7a4a088c8c60986e924b802e46370579_512231>, 2016 +# JungHee Lee , 2019 +# 미워하지 않아 , 2017 # 미워하지 않아 , 2017 # 76407af6b051a571d67c2577de2183db_7380deb <7a4a088c8c60986e924b802e46370579_512231>, 2016 # 76407af6b051a571d67c2577de2183db_7380deb <7a4a088c8c60986e924b802e46370579_512231>, 2016 @@ -11,10 +13,11 @@ # Hn Dsu , 2016 # moolow , 2018 # jasonkimik , 2014 +# JungHee Lee , 2019 # Gu Hong Min , 2015 # ks k, 2019 # ks k, 2019-2020 -# MarongHappy , 2019 +# JungHee Lee , 2019 # moolow , 2018 # Muk Myung-Hee MyungHee , 2018 # VictoriaKim , 2014 @@ -27,7 +30,7 @@ msgstr "" "Project-Id-Version: 0 A.D.\n" "POT-Creation-Date: 2020-05-22 07:08+0000\n" -"PO-Revision-Date: 2020-06-07 03:04+0000\n" +"PO-Revision-Date: 2020-09-08 16:43+0000\n" "Last-Translator: ks k\n" "Language-Team: Korean (http://www.transifex.com/wildfire-games/0ad/language/ko/)\n" "MIME-Version: 1.0\n" @@ -83,7 +86,7 @@ #: lobby/XmppClient.cpp:1248 msgid "Player already logged in" -msgstr "선수는 이미 로그인되었습니다." +msgstr "선수는 이미 로그인되었습니다" #: lobby/XmppClient.cpp:1250 msgid "Forbidden" @@ -182,7 +185,7 @@ #: ps/ModIo.cpp:261 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." -msgstr "놀이 ID에 대한 조회를 시작하는 동안 오류가 발생했습니다. 오류: %s;%s" +msgstr "놀이 ID에 대한 조회를 시작하는 동안 오류가 발생했습니다 오류: %s; %s." #: ps/ModIo.cpp:291 #, c-format @@ -221,7 +224,7 @@ #: ps/ModIo.cpp:547 #, c-format msgid "Invalid file. Expected md5 %s, got %s." -msgstr "파일이 잘못되었습니다. 예상 md5 값: %s, 받은 md5 값: %s" +msgstr "파일이 잘못되었습니다. 예상 md5 값: %s, 받은 md5 값: %s." #: ps/ModIo.cpp:562 msgid "Failed to compute final hash." diff -Nru 0ad-0.0.24~r24010/binaries/data/l10n/nb.engine.po 0ad-0.0.24~r24155/binaries/data/l10n/nb.engine.po --- 0ad-0.0.24~r24010/binaries/data/l10n/nb.engine.po 2020-05-25 07:35:52.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/data/l10n/nb.engine.po 2020-10-16 07:29:19.000000000 +0000 @@ -5,6 +5,7 @@ # Translators: # Allan Nordhøy , 2016-2018 # Bjorn Erik Moen , 2015 +# Hogne Haug , 2020 # Jarl Arntzen , 2014-2016 # Kurt-Håkon Eilertsen , 2014 # Lene Raastad , 2014 @@ -13,8 +14,8 @@ msgstr "" "Project-Id-Version: 0 A.D.\n" "POT-Creation-Date: 2020-05-22 07:08+0000\n" -"PO-Revision-Date: 2020-05-22 10:20+0000\n" -"Last-Translator: Transifex Bot <>\n" +"PO-Revision-Date: 2020-10-13 17:10+0000\n" +"Last-Translator: Hogne Haug \n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/wildfire-games/0ad/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -28,35 +29,35 @@ #: lobby/XmppClient.cpp:887 msgid "unknown subtype (see logs)" -msgstr "Ukjent undertype (se loggføring)" +msgstr "Ukjent undertype (se loggene)" #: lobby/XmppClient.cpp:1215 msgid "The certificate is not trusted." -msgstr "" +msgstr "Sertifikatet er usikkert" #: lobby/XmppClient.cpp:1216 msgid "The certificate hasn't got a known issuer." -msgstr "" +msgstr "Sertifikatet har ingen kjent utsteder" #: lobby/XmppClient.cpp:1217 msgid "The certificate has been revoked." -msgstr "" +msgstr "Sertifikatet har blitt tilbakekalt" #: lobby/XmppClient.cpp:1218 msgid "The certificate has expired." -msgstr "" +msgstr "Sertifikatet har utløpt" #: lobby/XmppClient.cpp:1219 msgid "The certificate is not yet active." -msgstr "" +msgstr "Sertifikatet er ennå ikke aktivt" #: lobby/XmppClient.cpp:1220 msgid "The certificate has not been issued for the peer connected to." -msgstr "" +msgstr "Sertifikatet er ikke utstedt for den maskinen du er tilkoblet" #: lobby/XmppClient.cpp:1221 msgid "The certificate signer is not a certificate authority." -msgstr "" +msgstr "Sertifikatets utsteder er ikke en godkjent utsteder" #: lobby/XmppClient.cpp:1243 lobby/XmppClient.cpp:1287 #: lobby/XmppClient.cpp:1326 @@ -168,27 +169,27 @@ #: ps/ModIo.cpp:261 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." -msgstr "" +msgstr "Feil ved spørring etter spill-ID. Feilkode: %s; %s." #: ps/ModIo.cpp:291 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." -msgstr "" +msgstr "Feil ved spørring etter tilpasnginer (mods). Feilkode: %s; %s." #: ps/ModIo.cpp:317 #, c-format msgid "Could not create mod directory: %s." -msgstr "" +msgstr "Kunne ikke opprette mappe for tilpasningen (mod'en): %s." #: ps/ModIo.cpp:342 #, c-format msgid "Could not open temporary file for mod download: %s." -msgstr "" +msgstr "Kunne ikke åpne midlertidig mappe for nedlastning av tilpasningen (mod'en): %s." #: ps/ModIo.cpp:352 #, c-format msgid "Failed to start the download. Error: %s; %s." -msgstr "" +msgstr "Kunne ikke starte nedlastningen. Feilkode: %s; %s." #: ps/ModIo.cpp:397 #, c-format diff -Nru 0ad-0.0.24~r24010/binaries/data/l10n/zh_TW.engine.po 0ad-0.0.24~r24155/binaries/data/l10n/zh_TW.engine.po --- 0ad-0.0.24~r24010/binaries/data/l10n/zh_TW.engine.po 2020-08-14 07:32:29.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/data/l10n/zh_TW.engine.po 2020-10-23 07:31:48.000000000 +0000 @@ -13,13 +13,14 @@ # Shoichi Chou , 2018 # Tea Fiber , 2020 # WY Liu , 2020 +# Yuan , 2020 # 黃柏諺 , 2013-2014 msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" "POT-Creation-Date: 2020-05-22 07:08+0000\n" -"PO-Revision-Date: 2020-08-10 22:37+0000\n" -"Last-Translator: Tea Fiber \n" +"PO-Revision-Date: 2020-10-20 09:25+0000\n" +"Last-Translator: Yuan \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/wildfire-games/0ad/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -178,7 +179,7 @@ #: ps/ModIo.cpp:291 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." -msgstr "查詢 Mod 時發生失敗,錯誤:%s; %s" +msgstr "查詢模組時發生失敗,錯誤:%s; %s" #: ps/ModIo.cpp:317 #, c-format diff -Nru 0ad-0.0.24~r24010/binaries/system/readme.txt 0ad-0.0.24~r24155/binaries/system/readme.txt --- 0ad-0.0.24~r24010/binaries/system/readme.txt 2020-08-01 10:52:59.000000000 +0000 +++ 0ad-0.0.24~r24155/binaries/system/readme.txt 2020-11-06 23:18:16.000000000 +0000 @@ -84,22 +84,6 @@ -hashtest-full=X whether to enable computation of full hashes in replaymode (default true). Can be disabled to improve performance. -hashtest-quick=X whether to enable computation of quick hashes in replaymode (default false). Can be enabled for debugging purposes. -Windows-specific: --wQpcTscSafe allow timing via QueryPerformanceCounter despite the fact - that it's using TSC and it may be unsafe. has no effect if - a better timer (i.e. the HPET) is available. - should only be specified if: - - you are sure your system does not engage in - thermal throttling (including STPCLK) OR - - an "RDTSC patch" is installed - this flag is also useful if all other alternatives are worse - than a potentially risky or slightly broken TSC-based QPC. - --wNoMahaf prevent any physical memory mapping or direct port I/O. - this disables all ACPI-related code and thus some of the - timer backends. specify this if problems are observed with - one of the abovementioned subsystems. - Archive builder: -archivebuild=PATH system PATH of the base directory containing mod data to be archived/precached specify all mods it depends on with -mod=NAME diff -Nru 0ad-0.0.24~r24010/build/svn_revision/svn_revision.txt 0ad-0.0.24~r24155/build/svn_revision/svn_revision.txt --- 0ad-0.0.24~r24010/build/svn_revision/svn_revision.txt 2020-08-31 20:48:44.000000000 +0000 +++ 0ad-0.0.24~r24155/build/svn_revision/svn_revision.txt 2020-11-10 14:15:33.000000000 +0000 @@ -1 +1 @@ -L"24010-development" +L"24155-development" diff -Nru 0ad-0.0.24~r24010/debian/changelog 0ad-0.0.24~r24155/debian/changelog --- 0ad-0.0.24~r24010/debian/changelog 2020-08-31 21:00:10.000000000 +0000 +++ 0ad-0.0.24~r24155/debian/changelog 2020-11-10 14:28:01.000000000 +0000 @@ -1,8 +1,8 @@ -0ad (0.0.24~r24010-0ubuntu1~16.04~wfg0) xenial; urgency=medium +0ad (0.0.24~r24155-0ubuntu1~16.04~wfg0) xenial; urgency=medium * New svn release - -- Rico Tzschichholz Mon, 31 Aug 2020 23:00:10 +0200 + -- Rico Tzschichholz Tue, 10 Nov 2020 15:28:01 +0100 0ad (0.0.23.1-4) unstable; urgency=medium diff -Nru 0ad-0.0.24~r24010/source/graphics/GameView.cpp 0ad-0.0.24~r24155/source/graphics/GameView.cpp --- 0ad-0.0.24~r24010/source/graphics/GameView.cpp 2020-05-26 21:47:03.000000000 +0000 +++ 0ad-0.0.24~r24155/source/graphics/GameView.cpp 2020-11-08 11:31:32.000000000 +0000 @@ -390,18 +390,21 @@ g_Renderer.SetTerrainRenderMode(EDGED_FACES); g_Renderer.SetWaterRenderMode(EDGED_FACES); g_Renderer.SetModelRenderMode(EDGED_FACES); + g_Renderer.SetOverlayRenderMode(EDGED_FACES); } else if (g_Renderer.GetModelRenderMode() == EDGED_FACES) { g_Renderer.SetTerrainRenderMode(WIREFRAME); g_Renderer.SetWaterRenderMode(WIREFRAME); g_Renderer.SetModelRenderMode(WIREFRAME); + g_Renderer.SetOverlayRenderMode(WIREFRAME); } else { g_Renderer.SetTerrainRenderMode(SOLID); g_Renderer.SetWaterRenderMode(SOLID); g_Renderer.SetModelRenderMode(SOLID); + g_Renderer.SetOverlayRenderMode(SOLID); } return IN_HANDLED; } diff -Nru 0ad-0.0.24~r24010/source/graphics/LightEnv.h 0ad-0.0.24~r24155/source/graphics/LightEnv.h --- 0ad-0.0.24~r24010/source/graphics/LightEnv.h 2019-09-18 08:34:36.000000000 +0000 +++ 0ad-0.0.24~r24155/source/graphics/LightEnv.h 2020-11-04 12:54:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -74,30 +74,6 @@ return color * 0.5f; } - /** - * Compute the diffuse sun lighting color on terrain, for rendering with CPU lighting. - * To cope with sun overbrightness, the color is scaled by 0.5. - * - * @param normal normal vector (must have length 1) - */ - SColor4ub EvaluateTerrainDiffuseScaled(const CVector3D& normal) const - { - float dot = -normal.Dot(m_SunDir); - return ConvertRGBColorTo4ub(m_SunColor * dot * 0.5f); - } - - /** - * Compute the diffuse sun lighting factor on terrain, for rendering with shader lighting. - * - * @param normal normal vector (must have length 1) - */ - SColor4ub EvaluateTerrainDiffuseFactor(const CVector3D& normal) const - { - float dot = -normal.Dot(m_SunDir); - u8 c = static_cast(Clamp(dot * 255.f, 0.f, 255.f)); - return SColor4ub(c, c, c, 255); - } - // Comparison operators bool operator==(const CLightEnv& o) const { diff -Nru 0ad-0.0.24~r24010/source/graphics/Overlay.h 0ad-0.0.24~r24155/source/graphics/Overlay.h --- 0ad-0.0.24~r24010/source/graphics/Overlay.h 2019-12-10 23:13:37.000000000 +0000 +++ 0ad-0.0.24~r24155/source/graphics/Overlay.h 2020-11-08 14:47:25.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -89,7 +89,7 @@ /// Color to apply to the line texture, where indicated by the mask. CColor m_Color; /// (x, z) vertex coordinate pairs; y is computed automatically. - std::vector m_Coords; + std::vector m_Coords; /// Half-width of the line, in world-space units. float m_Thickness; /// Should this line be treated as a closed loop? If set, any end cap settings are ignored. @@ -128,12 +128,12 @@ */ void CreateOverlayTexture(const SOverlayDescriptor* overlayDescriptor); - void PushCoords(const float x, const float z) { m_Coords.push_back(x); m_Coords.push_back(z); } - void PushCoords(const CVector2D& v) { PushCoords(v.X, v.Y); } + void PushCoords(const float x, const float z) { m_Coords.emplace_back(x, z); } + void PushCoords(const CVector2D& v) { m_Coords.push_back(v); } void PushCoords(const std::vector& points) { - for (size_t i = 0; i < points.size(); ++i) - PushCoords(points[i]); + for (const CVector2D& point : points) + PushCoords(point); } bool IsVisibleInFrustum(const CFrustum& frustum) const; diff -Nru 0ad-0.0.24~r24010/source/graphics/ShaderProgramFFP.cpp 0ad-0.0.24~r24155/source/graphics/ShaderProgramFFP.cpp --- 0ad-0.0.24~r24010/source/graphics/ShaderProgramFFP.cpp 2016-11-23 14:09:58.000000000 +0000 +++ 0ad-0.0.24~r24155/source/graphics/ShaderProgramFFP.cpp 2020-11-03 18:59:27.000000000 +0000 @@ -1135,6 +1135,7 @@ /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& id, const CShaderDefines& defines) { + LOGWARNING("CShaderProgram::ConstructFFP: '%s': fixed pipeline is going to be removed soon, don't use its programs", id.c_str()); if (id == "dummy") return new CShaderProgramFFP_Dummy(); if (id == "overlayline") diff -Nru 0ad-0.0.24~r24010/source/gui/ObjectTypes/CInput.cpp 0ad-0.0.24~r24155/source/gui/ObjectTypes/CInput.cpp --- 0ad-0.0.24~r24010/source/gui/ObjectTypes/CInput.cpp 2020-08-03 12:39:25.000000000 +0000 +++ 0ad-0.0.24~r24155/source/gui/ObjectTypes/CInput.cpp 2020-10-27 21:19:33.000000000 +0000 @@ -179,7 +179,6 @@ int rawLength = strlen(rawText); std::wstring wtext = wstring_from_utf8(rawText); - debug_printf("SDL_TEXTEDITING: text=%s, start=%d, length=%d\n", rawText, ev->ev.edit.start, ev->ev.edit.length); m_WantedX = 0.0f; if (SelectingText()) diff -Nru 0ad-0.0.24~r24010/source/gui/ObjectTypes/CMiniMap.cpp 0ad-0.0.24~r24155/source/gui/ObjectTypes/CMiniMap.cpp --- 0ad-0.0.24~r24010/source/gui/ObjectTypes/CMiniMap.cpp 2020-07-21 02:08:50.000000000 +0000 +++ 0ad-0.0.24~r24155/source/gui/ObjectTypes/CMiniMap.cpp 2020-11-08 08:51:54.000000000 +0000 @@ -70,9 +70,11 @@ CMiniMap::CMiniMap(CGUI& pGUI) : IGUIObject(pGUI), m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0), m_TerrainDirty(true), m_MapScale(1.f), - m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), + m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), m_Mask(false), m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), m_WaterHeight(0.0) { + RegisterSetting("mask", m_Mask); + m_Clicking = false; m_MouseHovering = false; @@ -427,6 +429,7 @@ const float angle = GetAngle(); const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); + CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture. glDepthMask(0); @@ -436,26 +439,53 @@ CShaderDefines baseDefines; baseDefines.Add(str_MINIMAP_BASE, str_1); + if (m_Mask) + baseDefines.Add(str_MINIMAP_MASK, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines); tech->BeginPass(); shader = tech->GetShader(); // Draw the main textured quad shader->BindTexture(str_baseTex, m_TerrainTexture); + if (m_Mask) + { + shader->BindTexture(str_maskTex, losTexture.GetTexture()); + CMatrix3D maskTextureTransform = *losTexture.GetMinimapTextureMatrix(); + // We need to have texture coordinates in the same coordinate space. + const float scale = 1.0f / texCoordMax; + maskTextureTransform.Scale(scale, scale, 1.0f); + shader->Uniform(str_maskTextureTransform, maskTextureTransform); + } const CMatrix3D baseTransform = GetDefaultGuiMatrix(); CMatrix3D baseTextureTransform; baseTextureTransform.SetIdentity(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, baseTextureTransform); + if (m_Mask) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); - // Draw territory boundaries - glEnable(GL_BLEND); + if (!m_Mask) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); + if (m_Mask) + { + shader->BindTexture(str_maskTex, losTexture.GetTexture()); + shader->Uniform(str_maskTextureTransform, *losTexture.GetMinimapTextureMatrix()); + } const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, *territoryTransform); @@ -464,23 +494,22 @@ tech->EndPass(); // Draw the LOS quad in black, using alpha values from the LOS texture - CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); - - CShaderDefines losDefines; - losDefines.Add(str_MINIMAP_LOS, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines); - tech->BeginPass(); - shader = tech->GetShader(); - shader->BindTexture(str_baseTex, losTexture.GetTexture()); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, *losTransform); + if (!m_Mask) + { + CShaderDefines losDefines; + losDefines.Add(str_MINIMAP_LOS, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines); + tech->BeginPass(); + shader = tech->GetShader(); + shader->BindTexture(str_baseTex, losTexture.GetTexture()); + + const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix(); + shader->Uniform(str_transform, baseTransform); + shader->Uniform(str_textureTransform, *losTransform); - DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); - tech->EndPass(); + DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); + tech->EndPass(); + } glDisable(GL_BLEND); diff -Nru 0ad-0.0.24~r24010/source/gui/ObjectTypes/CMiniMap.h 0ad-0.0.24~r24155/source/gui/ObjectTypes/CMiniMap.h --- 0ad-0.0.24~r24010/source/gui/ObjectTypes/CMiniMap.h 2020-07-21 02:08:50.000000000 +0000 +++ 0ad-0.0.24~r24155/source/gui/ObjectTypes/CMiniMap.h 2020-11-08 08:51:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -83,6 +83,9 @@ // whether we need to regenerate the terrain texture bool m_TerrainDirty; + // Whether to draw a black square around and under the minimap. + bool m_Mask; + ssize_t m_Width, m_Height; // map size diff -Nru 0ad-0.0.24~r24010/source/lib/config2.h 0ad-0.0.24~r24155/source/lib/config2.h --- 0ad-0.0.24~r24010/source/lib/config2.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/config2.h 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -67,19 +67,6 @@ # endif #endif -// allow an attempt to start the Aken driver (i.e. service) at runtime. -// enable at your own risk on WinXP systems to allow access to -// better timers than Windows provides. on newer Windows versions, -// attempts to start the service from code fail unless the process -// is elevated, and definitely fail due to lack of cross-signing unless -// test-signing mode is active. -// if the user has taken explicit action to install and start the -// service via aken_install.bat, mahaf.cpp will be able to access it -// even if this is defined to 0. -#ifndef CONFIG2_MAHAF_ATTEMPT_DRIVER_START -# define CONFIG2_MAHAF_ATTEMPT_DRIVER_START 0 -#endif - // build in OpenGL ES 2.0 mode, instead of the default mode designed for // GL 1.1 + extensions. // this disables various features that are not supported by GLES. diff -Nru 0ad-0.0.24~r24010/source/lib/debug.h 0ad-0.0.24~r24155/source/lib/debug.h --- 0ad-0.0.24~r24010/source/lib/debug.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/debug.h 2020-10-25 21:00:52.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -194,15 +194,19 @@ LIB_API ErrorReaction debug_DisplayError(const wchar_t* description, size_t flags, void* context, const wchar_t* lastFuncToSkip, const wchar_t* file, int line, const char* func, atomic_bool* suppress); // simplified version for just displaying an error message -#define DEBUG_DISPLAY_ERROR(description)\ +#define DEBUG_DISPLAY_ERROR_IMPL(description, flags)\ do\ {\ CACHE_ALIGNED(u8) context[DEBUG_CONTEXT_SIZE];\ (void)debug_CaptureContext(context);\ - (void)debug_DisplayError(description, 0, context, L"debug_DisplayError", WIDEN(__FILE__), __LINE__, __func__, 0);\ + (void)debug_DisplayError(description, flags, context, L"debug_DisplayError", WIDEN(__FILE__), __LINE__, __func__, 0);\ }\ while(0) +#define DEBUG_DISPLAY_ERROR(description) DEBUG_DISPLAY_ERROR_IMPL(description, 0) +// disallow continue for the error. +#define DEBUG_DISPLAY_FATAL_ERROR(description) DEBUG_DISPLAY_ERROR_IMPL(description, DE_NO_CONTINUE) + // // filtering diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/acpi.cpp 0ad-0.0.24~r24155/source/lib/sysdep/acpi.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/acpi.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/acpi.cpp 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,12 +27,7 @@ #include "lib/sysdep/cpu.h" #include "lib/module_init.h" -#define ENABLE_MAHAF 0 -#if ENABLE_MAHAF -# include "lib/sysdep/os/win/mahaf.h" -#else # include "lib/sysdep/os/win/wfirmware.h" -#endif #pragma pack(1) @@ -108,206 +103,8 @@ return true; } - -#if ENABLE_MAHAF - -//----------------------------------------------------------------------------- -// exception-safe transactional map/use/unmap - -// note: if the OS happens to unmap our physical memory, the Unsafe* -// functions may crash. we catch this via SEH; on Unix, we'd need handlers -// for SIGBUS and/or SIGSEGV. the code is safe in that it releases the -// mapped memory and returns an error code. - -static void* SUCCEEDED = (void*)(intptr_t)1; -static void* FAILED = (void*)(intptr_t)-1; - -typedef void* (*UnsafeFunction)(PCV_u8 mem, size_t numBytes, void* arg); - -static void* CallWithSafetyBlanket(UnsafeFunction func, PCV_u8 mem, size_t numBytes, void* arg) -{ -#if MSC_VERSION - __try - { - return func(mem, numBytes, arg); - } - __except(1) - { - return FAILED; - } -#else - return func(mem, numBytes, arg); -#endif -} - -static void* TransactPhysicalMemory(uintptr_t physicalAddress, size_t numBytes, UnsafeFunction func, void* arg = 0) -{ - PCV_u8 mem = (PCV_u8)mahaf_MapPhysicalMemory(physicalAddress, numBytes); - if(!mem) - return FAILED; - void* ret = CallWithSafetyBlanket(func, mem, numBytes, arg); - mahaf_UnmapPhysicalMemory((volatile void*)mem); - return ret; -} - - -//----------------------------------------------------------------------------- -// Root System Descriptor Pointer - -struct BiosDataArea -{ - u16 serialBase[4]; - u16 parallelBase[3]; - u16 ebdaSegment; -}; - -typedef const volatile BiosDataArea* PCV_BiosDataArea; - -static void* UnsafeReadEbdaPhysicalAddress(PCV_u8 mem, size_t numBytes, void* UNUSED(arg)) -{ - ENSURE(numBytes >= sizeof(BiosDataArea)); - - PCV_BiosDataArea bda = (PCV_BiosDataArea)mem; - const uintptr_t ebdaPhysicalAddress = ((uintptr_t)bda->ebdaSegment) * 16; - return (void*)ebdaPhysicalAddress; -} - - -struct RSDP -{ - char signature[8]; // "RSD PTR " - u8 checksum; // sum of this struct = 0 - char oemId[6]; - u8 revision; // 0 for 1.0, 2 for 2.0 - u32 rsdtPhysicalAddress; -}; - -typedef const volatile RSDP* PCV_RSDP; - -static const size_t RSDP_ALIGNMENT = 16; - -static void* UnsafeLocateAndRetrieveRsdp(PCV_u8 buf, size_t numBytes, void* arg) -{ - ENSURE(numBytes >= sizeof(RSDP)); - - for(PCV_u8 p = buf; p < buf+numBytes; p += RSDP_ALIGNMENT) - { - RSDP* prsdp = (RSDP*)p; - if(memcmp(prsdp->signature, "RSD PTR ", 8) != 0) - continue; - if(ComputeChecksum(p, sizeof(RSDP)) != 0) - continue; - - memcpy(arg, prsdp, sizeof(RSDP)); - return SUCCEEDED; - } - - return FAILED; -} - -static bool RetrieveRsdp(RSDP& rsdp) -{ - // See ACPIspec30b, section 5.2.5.1: - // RSDP is either in the first KIB of the extended BIOS data area, - void* ret = TransactPhysicalMemory(0x400, 0x100, UnsafeReadEbdaPhysicalAddress); - if(ret != FAILED) - { - const uintptr_t ebdaPhysicalAddress = (uintptr_t)ret; - ret = TransactPhysicalMemory(ebdaPhysicalAddress, 0x400, UnsafeLocateAndRetrieveRsdp, &rsdp); - if(ret == SUCCEEDED) - return true; - } - - // or in read-only BIOS memory. - ret = TransactPhysicalMemory(0xE0000, 0x20000, UnsafeLocateAndRetrieveRsdp, &rsdp); - if(ret == SUCCEEDED) - return true; - - return false; // not found -} - - -//----------------------------------------------------------------------------- -// copy tables from physical memory - -static void* UnsafeAllocateAndCopyTable(PCV_u8 mem, size_t numBytes, void* arg) -{ - ENSURE(numBytes >= sizeof(AcpiTable)); - - PCV_AcpiTable table = (PCV_AcpiTable)mem; - const size_t tableSize = table->size; - - // physical memory window is smaller than the table - // (caller will map a larger window and call us again) - if(numBytes < tableSize) - { - memcpy(arg, &tableSize, sizeof(size_t)); - return 0; - } - - PCV_u8 copy = (PCV_u8)AllocateTable(tableSize); - if(!copy) - return FAILED; - - memcpy((void*)copy, (const void*)mem, tableSize); - return (void*)copy; -} - - -static const AcpiTable* AllocateAndCopyTable(uintptr_t physicalAddress) -{ - // ACPI table sizes are not known until they've been mapped. since that - // is slow, we don't always want to do it twice. the solution is to map - // enough for a typical table; if that is too small, realloc and map again. - static const size_t initialSize = 4*KiB; - size_t actualSize = 0; - void* ret = TransactPhysicalMemory(physicalAddress, initialSize, UnsafeAllocateAndCopyTable, &actualSize); - // initialSize was too small; actualSize has been set - if(ret == 0) - ret = TransactPhysicalMemory(physicalAddress, actualSize, UnsafeAllocateAndCopyTable); - // *either* of the above calls failed to allocate memory - if(ret == FAILED) - return 0; - return (const AcpiTable*)ret; -} - -#endif // ENABLE_MAHAF - - static void AllocateAndCopyTables(const AcpiTable**& tables, size_t& numTables) { -#if ENABLE_MAHAF - if(mahaf_IsPhysicalMappingDangerous()) - return; - if(mahaf_Init() != INFO::OK) - return; - - RSDP rsdp; - if(!RetrieveRsdp(rsdp)) - return; - - // Root System Descriptor Table - struct RSDT - { - AcpiTable header; - u32 tableAddresses[1]; - }; - const RSDT* rsdt = (const RSDT*)AllocateAndCopyTable(rsdp.rsdtPhysicalAddress); - if(!ValidateTable(&rsdt->header, "RSDT")) - { - DeallocateTable(rsdt); - return; - } - - numTables = (rsdt->header.size - sizeof(AcpiTable)) / sizeof(rsdt->tableAddresses[0]); - ENSURE(numTables != 0); - - tables = new const AcpiTable*[numTables]; - for(size_t i = 0; i < numTables; i++) - tables[i] = AllocateAndCopyTable(rsdt->tableAddresses[i]); - - DeallocateTable(rsdt); -#else const wfirmware::Provider provider = FOURCC_BE('A','C','P','I'); const wfirmware::TableIds tableIDs = wfirmware::GetTableIDs(provider); @@ -321,7 +118,6 @@ tables[i] = AllocateTable(table.size()); memcpy((void*)tables[i], &table[0], table.size()); } -#endif // to prevent callers from choking on invalid tables, we // zero out the corresponding tables[] entries. @@ -352,10 +148,6 @@ SAFE_ARRAY_DELETE(tables); numTables = 0; } - -#if ENABLE_MAHAF - mahaf_Shutdown(); -#endif } diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/arch/x86_x64/apic.h 0ad-0.0.24~r24155/source/lib/sysdep/arch/x86_x64/apic.h --- 0ad-0.0.24~r24010/source/lib/sysdep/arch/x86_x64/apic.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/arch/x86_x64/apic.h 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -30,8 +30,8 @@ * platform does not have an xAPIC (i.e. 7th generation x86 or below). * * rationale: the alternative of accessing the APIC mmio registers is not - * feasible - mahaf_MapPhysicalMemory only works reliably on WinXP. we also - * don't want to interfere with the OS's constant use of the APIC registers. + * feasible. We also don't want to interfere with the OS's constant use of + * the APIC registers. **/ LIB_API ApicId GetApicId(); diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/arch/x86_x64/msr.cpp 0ad-0.0.24~r24155/source/lib/sysdep/arch/x86_x64/msr.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/arch/x86_x64/msr.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/arch/x86_x64/msr.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "precompiled.h" -#include "lib/sysdep/arch/x86_x64/msr.h" - -#include "lib/sysdep/os/win/mahaf.h" -#include "lib/sysdep/arch/x86_x64/x86_x64.h" - - -namespace MSR { - -bool IsAccessible() -{ - if(!x86_x64::Cap(x86_x64::CAP_MSR)) - return false; - - // only read/writable from ring 0, so we need the driver. - if(mahaf_Init() < 0) - return false; - - return true; -} - - -bool HasEnergyPerfBias() -{ -#if 1 - // the documentation is unclear. until it improves, disable - // this, lest we provoke a GPF. - return false; -#else - if(x86_x64::Vendor() != x86_x64::VENDOR_INTEL) - return false; - - if(x86_x64::Family() < 6) - return false; - - if(x86_x64::Model() < 0xE) - return false; - - return true; -#endif -} - - -bool HasPlatformInfo() -{ - if(x86_x64::Vendor() != x86_x64::VENDOR_INTEL) - return false; - - if(x86_x64::Family() != 6) - return false; - - switch(x86_x64::Model()) - { - // section 34.4 in 253665-041US - case x86_x64::MODEL_NEHALEM_EP: - case x86_x64::MODEL_NEHALEM_EP_2: - case x86_x64::MODEL_NEHALEM_EX: - case x86_x64::MODEL_I7_I5: - return true; - - // section 34.5 - case x86_x64::MODEL_CLARKDALE: - case x86_x64::MODEL_WESTMERE_EP: - return true; - - // section 34.6 - case x86_x64::MODEL_WESTMERE_EX: - return true; - - // section 34.7 - case x86_x64::MODEL_SANDY_BRIDGE: - case x86_x64::MODEL_SANDY_BRIDGE_2: - return true; - - default: - return false; - } -} - - -bool HasUncore() -{ - if(x86_x64::Vendor() != x86_x64::VENDOR_INTEL) - return false; - - if(x86_x64::Family() != 6) - return false; - - switch(x86_x64::Model()) - { - // Xeon 5500 / i7 (section B.4.1 in 253669-037US) - case 0x1A: // Bloomfield, Gainstown - case 0x1E: // Clarksfield, Lynnfield, Jasper Forest - case 0x1F: - return true; - - // Xeon 5600 / Westmere (section B.5) - case 0x25: // Clarkdale, Arrandale - case 0x2C: // Gulftown - return true; - - default: - return false; - } -} - - -u64 Read(u64 reg) -{ - return mahaf_ReadModelSpecificRegister(reg); -} - - -void Write(u64 reg, u64 value) -{ - mahaf_WriteModelSpecificRegister(reg, value); -} - -} // namespace MSR diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/arch/x86_x64/msr.h 0ad-0.0.24~r24155/source/lib/sysdep/arch/x86_x64/msr.h --- 0ad-0.0.24~r24010/source/lib/sysdep/arch/x86_x64/msr.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/arch/x86_x64/msr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * model-specific registers - */ - -#ifndef INCLUDED_X86_X64_MSR -#define INCLUDED_X86_X64_MSR - -namespace MSR { - -enum ModelSpecificRegisters -{ - // architectural (will not change on future processors) - IA32_MISC_ENABLE = 0x1A0, - IA32_ENERGY_PERF_BIAS = 0x1B0, // requires HasEnergyPerfBias - - // PMU v1 - IA32_PMC0 = 0x0C1, - IA32_PERFEVTSEL0 = 0x186, - - // PMU v2 - IA32_PERF_GLOBAL_STATUS = 0x38E, - IA32_PERF_GLOBAL_CTRL = 0x38F, - IA32_PERF_GLOBAL_OVF_CTRL = 0x390, - - // Nehalem and later - PLATFORM_INFO = 0x0CE, // requires HasPlatformInfo - - // Nehalem, Westmere (requires HasUncore) - UNCORE_PERF_GLOBAL_CTRL = 0x391, - UNCORE_PERF_GLOBAL_STATUS = 0x392, - UNCORE_PERF_GLOBAL_OVF_CTRL = 0x393, - UNCORE_PMC0 = 0x3B0, - UNCORE_PERFEVTSEL0 = 0x3C0 -}; - -LIB_API bool IsAccessible(); - -LIB_API bool HasEnergyPerfBias(); -LIB_API bool HasPlatformInfo(); -LIB_API bool HasUncore(); - -LIB_API u64 Read(u64 reg); -LIB_API void Write(u64 reg, u64 value); - -} // namespace MSR - -#endif // #ifndef INCLUDED_X86_X64_MSR diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/aken.c 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/aken.c --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/aken.c 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/aken.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,526 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// note: staticdv cannot yet check C++ code. - -#include -#include "aken.h" -#include "intrinsics.h" - -#define WIN32_NAME L"\\DosDevices\\Aken" -#define DEVICE_NAME L"\\Device\\Aken" - -// placate PREfast -DRIVER_INITIALIZE DriverEntry; -__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH AkenCreate; -__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH AkenClose; -__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH AkenDeviceControl; -DRIVER_UNLOAD AkenUnload; - -// this driver isn't large, but it's still slightly nicer to make its -// functions pageable and thus not waste precious non-paged pool. -// #pragma code_seg is more convenient than specifying alloc_text for -// every other function. -#pragma alloc_text(INIT, DriverEntry) // => discardable -#pragma code_seg(push, "PAGE") - - -//----------------------------------------------------------------------------- -// memory mapping -//----------------------------------------------------------------------------- - -/* -there are three approaches to mapping physical memory: -(http://www.microsoft.com/whdc/driver/kernel/mem-mgmt.mspx) - -- MmMapIoSpace (http://support.microsoft.com/kb/189327/en-us). despite the - name, it maps physical pages of any kind by allocating PTEs. very easy to - implement, but occupies precious kernel address space. possible bugs: - http://www.osronline.com/showThread.cfm?link=96737 - http://support.microsoft.com/kb/925793/en-us - -- ZwMapViewOfSection of PhysicalMemory (http://tinyurl.com/yozmgy). - the code is a bit bulky, but the WinXP API prevents mapping pages with - conflicting attributes (see below). - -- MmMapLockedPagesSpecifyCache or MmGetSystemAddressForMdlSafe - (http://www.osronline.com/article.cfm?id=423). note: the latter is a macro - that calls the former. this is the 'normal' and fully documented way, - but it doesn't appear able to map a fixed physical address. - (MmAllocatePagesForMdl understandably doesn't work since some pages we - want to map are marked as unavailable for allocation, and I don't see - another documented way to fill an MDL with PFNs.) - -our choice here is forced by a very insidious issue. if someone else has -already mapped a page with different attributes (e.g. cacheable), TLBs -may end up corrupted, leading to disaster. the search for a documented -means of accessing the page frame database (to check if mapped anywhere -and determine the previously set attributes) has not borne fruit, so we -must use ZwMapViewOfSection. (if taking this up again, see -http://www.woodmann.com/forum/archive/index.php/t-6516.html ) - -note that we guess if the page will have been mapped as cacheable and -even try the opposite if that turns out to have been incorrect. -*/ - -static int IsMemoryUncacheable(DWORD64 physicalAddress64) -{ - PAGED_CODE(); - - // original PC memory - contains BIOS - if(physicalAddress64 < 0x100000) - return 1; - - return 0; -} - -static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWORD64 numBytes64, DWORD64* virtualAddress64) -{ - NTSTATUS ntStatus; - HANDLE hMemory; - LARGE_INTEGER physicalAddress; // convenience - physicalAddress.QuadPart = physicalAddress64; - - PAGED_CODE(); - - // get handle to PhysicalMemory object - { - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING objectName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); - const ULONG attributes = OBJ_CASE_INSENSITIVE; - const HANDLE rootDirectory = 0; - InitializeObjectAttributes(&objectAttributes, &objectName, attributes, rootDirectory, (PSECURITY_DESCRIPTOR)0); - ntStatus = ZwOpenSection(&hMemory, SECTION_ALL_ACCESS, &objectAttributes); - if(!NT_SUCCESS(ntStatus)) - { - KdPrint(("AkenMapPhysicalMemory: ZwOpenSection failed\n")); - return ntStatus; - } - } - - // add a reference (required to prevent the handle from being deleted) - { - PVOID physicalMemorySection = NULL; - const POBJECT_TYPE objectType = 0; // allowed since specifying KernelMode - ntStatus = ObReferenceObjectByHandle(hMemory, SECTION_ALL_ACCESS, objectType, KernelMode, &physicalMemorySection, 0); - if(!NT_SUCCESS(ntStatus)) - { - KdPrint(("AkenMapPhysicalMemory: ObReferenceObjectByHandle failed\n")); - goto close_handle; - } - } - - // note: mapmem.c does HalTranslateBusAddress, but we only care about - // system memory. translating doesn't appear to be necessary, even if - // much existing code uses it (probably due to cargo cult). - - // map desired memory into user PTEs - { - const HANDLE hProcess = (HANDLE)-1; - PVOID virtualBaseAddress = 0; // let ZwMapViewOfSection pick - const ULONG zeroBits = 0; // # high-order bits in address that must be 0 - SIZE_T mappedSize = (SIZE_T)numBytes64; // will receive the actual page-aligned size - LARGE_INTEGER physicalBaseAddress = physicalAddress; // will be rounded down to 64KB boundary - const SECTION_INHERIT inheritDisposition = ViewShare; - const ULONG allocationType = 0; - ULONG protect = PAGE_READWRITE; - if(IsMemoryUncacheable(physicalAddress64)) - protect |= PAGE_NOCACHE; - ntStatus = ZwMapViewOfSection(hMemory, hProcess, &virtualBaseAddress, zeroBits, mappedSize, &physicalBaseAddress, &mappedSize, inheritDisposition, allocationType, protect); - if(!NT_SUCCESS(ntStatus)) - { - // try again with the opposite cacheability attribute - protect ^= PAGE_NOCACHE; - ntStatus = ZwMapViewOfSection(hMemory, hProcess, &virtualBaseAddress, zeroBits, mappedSize, &physicalBaseAddress, &mappedSize, inheritDisposition, allocationType, protect); - if(!NT_SUCCESS(ntStatus)) - { - KdPrint(("AkenMapPhysicalMemory: ZwMapViewOfSection failed\n")); - goto close_handle; - } - } - - // the mapping rounded our physical base address down to the nearest - // 64KiB boundary, so adjust the virtual address accordingly. - { - const DWORD32 numBytesRoundedDown = physicalAddress.LowPart - physicalBaseAddress.LowPart; - ASSERT(numBytesRoundedDown < 0x10000); - *virtualAddress64 = (DWORD64)virtualBaseAddress + numBytesRoundedDown; - } - } - - ntStatus = STATUS_SUCCESS; - -close_handle: - // closing the handle even on success means that callers won't have to - // pass it back when unmapping. why does this work? ZwMapViewOfSection - // apparently adds a reference to hMemory. - ZwClose(hMemory); - - return ntStatus; -} - - -static NTSTATUS AkenUnmapPhysicalMemory(const DWORD64 virtualAddress) -{ - PAGED_CODE(); - - { - const HANDLE hProcess = (HANDLE)-1; - PVOID baseAddress = (PVOID)virtualAddress; - NTSTATUS ntStatus = ZwUnmapViewOfSection(hProcess, baseAddress); - if(!NT_SUCCESS(ntStatus)) - { - KdPrint(("AkenUnmapPhysicalMemory: ZwUnmapViewOfSection failed\n")); - return ntStatus; - } - } - - return STATUS_SUCCESS; -} - - -//----------------------------------------------------------------------------- -// helper functions called from DeviceControl -//----------------------------------------------------------------------------- - -static NTSTATUS AkenIoctlReadPort(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - DWORD32 value; - - PAGED_CODE(); - - if(inSize != sizeof(AkenReadPortIn) || *outSize != sizeof(AkenReadPortOut)) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenReadPortIn* in = (const AkenReadPortIn*)buf; - const USHORT port = in->port; - const UCHAR numBytes = in->numBytes; - switch(numBytes) - { - case 1: - value = (DWORD32)READ_PORT_UCHAR((PUCHAR)port); - break; - case 2: - value = (DWORD32)READ_PORT_USHORT((PUSHORT)port); - break; - case 4: - value = (DWORD32)READ_PORT_ULONG((PULONG)port); - break; - default: - return STATUS_INVALID_PARAMETER; - } - } - - { - AkenReadPortOut* out = (AkenReadPortOut*)buf; - out->value = value; - } - return STATUS_SUCCESS; -} - -static NTSTATUS AkenIoctlWritePort(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - PAGED_CODE(); - - if(inSize != sizeof(AkenWritePortIn) || *outSize != 0) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenWritePortIn* in = (const AkenWritePortIn*)buf; - const DWORD32 value = in->value; - const USHORT port = in->port; - const UCHAR numBytes = in->numBytes; - switch(numBytes) - { - case 1: - WRITE_PORT_UCHAR((PUCHAR)port, (UCHAR)(value & 0xFF)); - break; - case 2: - WRITE_PORT_USHORT((PUSHORT)port, (USHORT)(value & 0xFFFF)); - break; - case 4: - WRITE_PORT_ULONG((PULONG)port, value); - break; - default: - return STATUS_INVALID_PARAMETER; - } - } - - return STATUS_SUCCESS; -} - - -static NTSTATUS AkenIoctlMap(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - DWORD64 virtualAddress; - NTSTATUS ntStatus; - - PAGED_CODE(); - - if(inSize != sizeof(AkenMapIn) || *outSize != sizeof(AkenMapOut)) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenMapIn* in = (const AkenMapIn*)buf; - const DWORD64 physicalAddress = in->physicalAddress; - const DWORD64 numBytes = in->numBytes; - ntStatus = AkenMapPhysicalMemory(physicalAddress, numBytes, &virtualAddress); - } - - { - AkenMapOut* out = (AkenMapOut*)buf; - out->virtualAddress = virtualAddress; - } - return ntStatus; -} - -static NTSTATUS AkenIoctlUnmap(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - NTSTATUS ntStatus; - - PAGED_CODE(); - - if(inSize != sizeof(AkenUnmapIn) || *outSize != 0) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenUnmapIn* in = (const AkenUnmapIn*)buf; - const DWORD64 virtualAddress = in->virtualAddress; - ntStatus = AkenUnmapPhysicalMemory(virtualAddress); - } - - return ntStatus; -} - - -static NTSTATUS AkenIoctlReadModelSpecificRegister(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - DWORD64 value; - - PAGED_CODE(); - - if(inSize != sizeof(AkenReadRegisterIn) || *outSize != sizeof(AkenReadRegisterOut)) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenReadRegisterIn* in = (const AkenReadRegisterIn*)buf; - const DWORD64 reg = in->reg; - value = __readmsr((int)reg); - } - - { - AkenReadRegisterOut* out = (AkenReadRegisterOut*)buf; - out->value = value; - } - - return STATUS_SUCCESS; -} - -static NTSTATUS AkenIoctlWriteModelSpecificRegister(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - PAGED_CODE(); - - if(inSize != sizeof(AkenWriteRegisterIn) || *outSize != 0) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenWriteRegisterIn* in = (const AkenWriteRegisterIn*)buf; - const DWORD64 reg = in->reg; - const DWORD64 value = in->value; - __writemsr((unsigned long)reg, value); - } - - return STATUS_SUCCESS; -} - -static NTSTATUS AkenIoctlReadPerformanceMonitoringCounter(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - DWORD64 value; - - PAGED_CODE(); - - if(inSize != sizeof(AkenReadRegisterIn) || *outSize != sizeof(AkenReadRegisterOut)) - return STATUS_BUFFER_TOO_SMALL; - - { - const AkenReadRegisterIn* in = (const AkenReadRegisterIn*)buf; - const DWORD64 reg = in->reg; - value = __readpmc((unsigned long)reg); - } - - { - AkenReadRegisterOut* out = (AkenReadRegisterOut*)buf; - out->value = value; - } - - return STATUS_SUCCESS; -} - - -static NTSTATUS AkenIoctlUnknown(PVOID buf, const ULONG inSize, ULONG* outSize) -{ - PAGED_CODE(); - - KdPrint(("AkenIoctlUnknown\n")); - - *outSize = 0; - return STATUS_INVALID_DEVICE_REQUEST; -} - - -typedef NTSTATUS (*AkenIoctl)(PVOID buf, ULONG inSize, ULONG* outSize); - -static AkenIoctl AkenIoctlFromCode(ULONG ioctlCode) -{ - PAGED_CODE(); - - switch(ioctlCode) - { - case IOCTL_AKEN_READ_PORT: - return AkenIoctlReadPort; - case IOCTL_AKEN_WRITE_PORT: - return AkenIoctlWritePort; - - case IOCTL_AKEN_MAP: - return AkenIoctlMap; - case IOCTL_AKEN_UNMAP: - return AkenIoctlUnmap; - - case IOCTL_AKEN_READ_MSR: - return AkenIoctlReadModelSpecificRegister; - case IOCTL_AKEN_WRITE_MSR: - return AkenIoctlWriteModelSpecificRegister; - - default: - return AkenIoctlUnknown; - } -} - - -//----------------------------------------------------------------------------- -// entry points -//----------------------------------------------------------------------------- - -static NTSTATUS AkenCreate(IN PDEVICE_OBJECT deviceObject, IN PIRP irp) -{ - PAGED_CODE(); - - irp->IoStatus.Status = STATUS_SUCCESS; - irp->IoStatus.Information = 0; - IoCompleteRequest(irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; -} - - -static NTSTATUS AkenClose(IN PDEVICE_OBJECT deviceObject, IN PIRP irp) -{ - PAGED_CODE(); - - // same as AkenCreate ATM - irp->IoStatus.Status = STATUS_SUCCESS; - irp->IoStatus.Information = 0; - IoCompleteRequest(irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; -} - - -static NTSTATUS AkenDeviceControl(IN PDEVICE_OBJECT deviceObject, IN PIRP irp) -{ - PAGED_CODE(); - - { - // get buffer from IRP. all our IOCTLs are METHOD_BUFFERED, so buf is - // allocated by the I/O manager and used for both input and output. - PVOID buf = irp->AssociatedIrp.SystemBuffer; - PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp); - ULONG ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; - const ULONG inSize = irpStack->Parameters.DeviceIoControl.InputBufferLength; - ULONG outSize = irpStack->Parameters.DeviceIoControl.OutputBufferLength; // modified by AkenIoctl* - - const AkenIoctl akenIoctl = AkenIoctlFromCode(ioctlCode); - const NTSTATUS ntStatus = akenIoctl(buf, inSize, &outSize); - - irp->IoStatus.Information = outSize; // number of bytes to copy from buf to user's buffer - irp->IoStatus.Status = ntStatus; - IoCompleteRequest(irp, IO_NO_INCREMENT); - return ntStatus; - } -} - - -static VOID AkenUnload(IN PDRIVER_OBJECT driverObject) -{ - PAGED_CODE(); - - KdPrint(("AkenUnload\n")); - - { - UNICODE_STRING win32Name = RTL_CONSTANT_STRING(WIN32_NAME); - IoDeleteSymbolicLink(&win32Name); - } - - if(driverObject->DeviceObject) - IoDeleteDevice(driverObject->DeviceObject); -} - - -#pragma code_seg(pop) // make sure we don't countermand the alloc_text - -NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath) -{ - UNICODE_STRING deviceName = RTL_CONSTANT_STRING(DEVICE_NAME); - - // create device object - PDEVICE_OBJECT deviceObject; - { - const ULONG deviceExtensionSize = 0; - const ULONG deviceCharacteristics = FILE_DEVICE_SECURE_OPEN; - const BOOLEAN exlusive = TRUE; - NTSTATUS ntStatus = IoCreateDevice(driverObject, deviceExtensionSize, &deviceName, FILE_DEVICE_AKEN, deviceCharacteristics, exlusive, &deviceObject); - if(!NT_SUCCESS(ntStatus)) - { - KdPrint(("DriverEntry: IoCreateDevice failed\n")); - return ntStatus; - } - } - - // set entry points - driverObject->MajorFunction[IRP_MJ_CREATE] = AkenCreate; - driverObject->MajorFunction[IRP_MJ_CLOSE] = AkenClose; - driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AkenDeviceControl; - driverObject->DriverUnload = AkenUnload; - - // symlink NT device name to Win32 namespace - { - UNICODE_STRING win32Name = RTL_CONSTANT_STRING(WIN32_NAME); - NTSTATUS ntStatus = IoCreateSymbolicLink(&win32Name, &deviceName); - if(!NT_SUCCESS(ntStatus)) - { - KdPrint(("DriverEntry: IoCreateSymbolicLink failed\n")); - IoDeleteDevice(deviceObject); - return ntStatus; - } - } - - return STATUS_SUCCESS; -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/aken.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/aken.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/aken.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/aken.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Aken driver interface - */ - -// Aken - custodian of the ferryboat to the underworld in Egyptian mythology, -// and a driver that shuttles between applications and kernel mode resources. - -#ifndef INCLUDED_AKEN -#define INCLUDED_AKEN - -#define AKEN_NAME L"Aken" - -// device type -#define FILE_DEVICE_AKEN 53498 // in the "User Defined" range." - -#define AKEN_IOCTL 0x800 // 0x800..0xFFF are for 'customer' use. - -#define IOCTL_AKEN_READ_PORT CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+0, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_AKEN_WRITE_PORT CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+1, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_AKEN_MAP CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+2, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_AKEN_UNMAP CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+3, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_AKEN_READ_MSR CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+4, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_AKEN_WRITE_MSR CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+5, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_AKEN_READ_PMC CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+6, METHOD_BUFFERED, FILE_ANY_ACCESS) - - -// input and output data structures for the IOCTLs - -#pragma pack(push, 1) - -typedef struct AkenReadPortIn_ -{ - USHORT port; - UCHAR numBytes; -} -AkenReadPortIn; - -typedef struct AkenReadPortOut_ -{ - DWORD32 value; -} -AkenReadPortOut; - -typedef struct AkenWritePortIn_ -{ - DWORD32 value; - USHORT port; - UCHAR numBytes; -} -AkenWritePortIn; - -typedef struct AkenMapIn_ -{ - // note: fixed-width types allow the 32 or 64-bit Mahaf wrapper to - // interoperate with the 32 or 64-bit Aken driver. - DWORD64 physicalAddress; - DWORD64 numBytes; -} -AkenMapIn; - -typedef struct AkenMapOut_ -{ - DWORD64 virtualAddress; -} -AkenMapOut; - -typedef struct AkenUnmapIn_ -{ - DWORD64 virtualAddress; -} -AkenUnmapIn; - -typedef struct AkenReadRegisterIn_ -{ - DWORD64 reg; -} -AkenReadRegisterIn; - -typedef struct AkenReadRegisterOut_ -{ - DWORD64 value; -} -AkenReadRegisterOut; - -typedef struct AkenWriteRegisterIn_ -{ - DWORD64 reg; - DWORD64 value; -} -AkenWriteRegisterIn; - -#pragma pack(pop) - -#endif // #ifndef INCLUDED_AKEN diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/makefile 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/makefile --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/makefile 2016-07-25 09:07:45.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/sources 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/sources --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/aken/sources 2016-07-25 09:07:45.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/aken/sources 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -TARGETNAME=aken -TARGETPATH=. -TARGETTYPE=DRIVER - -SOURCES=aken.c diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/mahaf.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/mahaf.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/mahaf.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/mahaf.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,398 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * user-mode interface to Aken driver - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/mahaf.h" - -#include "lib/config2.h" -#include "lib/module_init.h" - -#include "lib/sysdep/os/win/wutil.h" -#include -#include "lib/sysdep/os/win/aken/aken.h" -#include "lib/sysdep/os/win/wversion.h" - -static HANDLE hAken = INVALID_HANDLE_VALUE; // handle to Aken driver - - -//----------------------------------------------------------------------------- -// ioctl wrappers -//----------------------------------------------------------------------------- - -static u32 ReadPort(u16 port, u8 numBytes) -{ - AkenReadPortIn in; - in.port = (USHORT)port; - in.numBytes = (UCHAR)numBytes; - AkenReadPortOut out; - - DWORD bytesReturned; - LPOVERLAPPED ovl = 0; // synchronous - const BOOL ok = DeviceIoControl(hAken, (DWORD)IOCTL_AKEN_READ_PORT, &in, sizeof(in), &out, sizeof(out), &bytesReturned, ovl); - WARN_RETURN_0_IF_FALSE(ok); - - ENSURE(bytesReturned == sizeof(out)); - return out.value; -} - -u8 mahaf_ReadPort8(u16 port) -{ - const u32 value = ReadPort(port, 1); - ENSURE(value <= 0xFF); - return (u8)(value & 0xFF); -} - -u16 mahaf_ReadPort16(u16 port) -{ - const u32 value = ReadPort(port, 2); - ENSURE(value <= 0xFFFF); - return (u16)(value & 0xFFFF); -} - -u32 mahaf_ReadPort32(u16 port) -{ - const u32 value = ReadPort(port, 4); - return value; -} - - -static void WritePort(u16 port, u32 value, u8 numBytes) -{ - AkenWritePortIn in; - in.value = (DWORD32)value; - in.port = (USHORT)port; - in.numBytes = (UCHAR)numBytes; - - DWORD bytesReturned; // unused but must be passed to DeviceIoControl - LPOVERLAPPED ovl = 0; // synchronous - BOOL ok = DeviceIoControl(hAken, (DWORD)IOCTL_AKEN_WRITE_PORT, &in, sizeof(in), 0, 0u, &bytesReturned, ovl); - WARN_IF_FALSE(ok); -} - -void mahaf_WritePort8(u16 port, u8 value) -{ - WritePort(port, (u32)value, 1); -} - -void mahaf_WritePort16(u16 port, u16 value) -{ - WritePort(port, (u32)value, 2); -} - -void mahaf_WritePort32(u16 port, u32 value) -{ - WritePort(port, value, 4); -} - - -bool mahaf_IsPhysicalMappingDangerous() -{ - // pre-XP versions don't prevent re-mapping pages with incompatible - // attributes, which may lead to disaster due to TLB corruption. - if(wversion_Number() < WVERSION_XP) - return true; - - return false; -} - - -volatile void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes) -{ - ENSURE(!mahaf_IsPhysicalMappingDangerous()); - - AkenMapIn in; - in.physicalAddress = (DWORD64)physicalAddress; - in.numBytes = (DWORD64)numBytes; - AkenMapOut out; - - DWORD bytesReturned; - LPOVERLAPPED ovl = 0; // synchronous - const BOOL ok = DeviceIoControl(hAken, (DWORD)IOCTL_AKEN_MAP, &in, sizeof(in), &out, sizeof(out), &bytesReturned, ovl); - WARN_RETURN_0_IF_FALSE(ok); - - ENSURE(bytesReturned == sizeof(out)); - volatile void* virtualAddress = (volatile void*)(uintptr_t)out.virtualAddress; - return virtualAddress; -} - - -void mahaf_UnmapPhysicalMemory(volatile void* virtualAddress) -{ - ENSURE(!mahaf_IsPhysicalMappingDangerous()); - - AkenUnmapIn in; - in.virtualAddress = (DWORD64)virtualAddress; - - DWORD bytesReturned; // unused but must be passed to DeviceIoControl - LPOVERLAPPED ovl = 0; // synchronous - BOOL ok = DeviceIoControl(hAken, (DWORD)IOCTL_AKEN_UNMAP, &in, sizeof(in), 0, 0u, &bytesReturned, ovl); - WARN_IF_FALSE(ok); -} - - -static u64 ReadRegister(DWORD ioctl, u64 reg) -{ - AkenReadRegisterIn in; - in.reg = reg; - AkenReadRegisterOut out; - - DWORD bytesReturned; - LPOVERLAPPED ovl = 0; // synchronous - const BOOL ok = DeviceIoControl(hAken, ioctl, &in, sizeof(in), &out, sizeof(out), &bytesReturned, ovl); - WARN_RETURN_0_IF_FALSE(ok); - - ENSURE(bytesReturned == sizeof(out)); - return out.value; -} - -u64 mahaf_ReadModelSpecificRegister(u64 reg) -{ - return ReadRegister((DWORD)IOCTL_AKEN_READ_MSR, reg); -} - -u64 mahaf_ReadPerformanceMonitoringCounter(u64 reg) -{ - return ReadRegister((DWORD)IOCTL_AKEN_READ_PMC, reg); -} - -void mahaf_WriteModelSpecificRegister(u64 reg, u64 value) -{ - AkenWriteRegisterIn in; - in.reg = reg; - in.value = value; - - DWORD bytesReturned; // unused but must be passed to DeviceIoControl - LPOVERLAPPED ovl = 0; // synchronous - BOOL ok = DeviceIoControl(hAken, (DWORD)IOCTL_AKEN_WRITE_MSR, &in, sizeof(in), 0, 0u, &bytesReturned, ovl); - WARN_IF_FALSE(ok); -} - - -//----------------------------------------------------------------------------- -// driver installation -//----------------------------------------------------------------------------- - -// @param access need not include SC_MANAGER_CONNECT ("implicitly specified") -static SC_HANDLE OpenServiceControlManager(DWORD access) -{ - LPCWSTR machineName = 0; // local - LPCWSTR databaseName = 0; // default - SC_HANDLE hSCM = OpenSCManagerW(machineName, databaseName, access); - if(!hSCM) - { - // ensure no other problems arose - ENSURE(GetLastError() == ERROR_ACCESS_DENIED); - - // administrator privileges are required for SC_MANAGER_CREATE_SERVICE. - // this is a problem on Vista / Win7, so users will have to use the - // separate aken_install.bat - - return 0; - } - - return hSCM; // success -} - - -static void UninstallDriver() -{ - SC_HANDLE hSCM = OpenServiceControlManager(SC_MANAGER_ENUMERATE_SERVICE); - if(!hSCM) - return; - SC_HANDLE hService = OpenServiceW(hSCM, AKEN_NAME, SERVICE_STOP|SERVICE_INTERROGATE); - if(!hService) - return; - - // stop service - SERVICE_STATUS serviceStatus; - if(!ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus)) - { - // if the problem wasn't that the service is already stopped, - // something actually went wrong. - const DWORD err = GetLastError(); - ENSURE(err == ERROR_SERVICE_NOT_ACTIVE || err == ERROR_SERVICE_CANNOT_ACCEPT_CTRL); - } - - // delete service - BOOL ok; - ok = DeleteService(hService); - WARN_IF_FALSE(ok); - ok = CloseServiceHandle(hService); - WARN_IF_FALSE(ok); - - ok = CloseServiceHandle(hSCM); - WARN_IF_FALSE(ok); -} - - -#if CONFIG2_MAHAF_ATTEMPT_DRIVER_START - -static void StartDriver(const OsPath& driverPathname) -{ - const SC_HANDLE hSCM = OpenServiceControlManager(SC_MANAGER_CREATE_SERVICE); - if(!hSCM) - { - ENSURE(GetLastError() == ERROR_ACCESS_DENIED); - SetLastError(0); - return; - } - - SC_HANDLE hService = OpenServiceW(hSCM, AKEN_NAME, SERVICE_START); - - // during development, we want to ensure the newest build is used, so - // unload and re-create the service if it's running/installed. - // as of 2008-03-24 no further changes to Aken are pending, so this is - // disabled (thus also avoiding trouble when running multiple instances) -#if 0 - if(hService) - { - BOOL ok = CloseServiceHandle(hService); - WARN_IF_FALSE(ok); - hService = 0; - UninstallDriver(); - } -#endif - - // create service (note: this just enters the service into SCM's DB; - // no error is raised if the driver binary doesn't exist etc.) - if(!hService) - { - LPCWSTR startName = 0; // LocalSystem - // NB: Windows 7 seems to insist upon backslashes (i.e. external_file_string) - hService = CreateServiceW(hSCM, AKEN_NAME, AKEN_NAME, - SERVICE_START, SERVICE_KERNEL_DRIVER, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - OsString(driverPathname).c_str(), 0, 0, 0, startName, 0); - ENSURE(hService != 0); - } - - { - DWORD numArgs = 0; - BOOL ok = StartService(hService, numArgs, 0); - if(!ok) - { - switch(GetLastError()) - { - case ERROR_SERVICE_ALREADY_RUNNING: - // ok, no action needed - break; - case ERROR_ACCESS_DENIED: - // Win7, can't start service; must use aken_install.bat - break; - case ERROR_INVALID_IMAGE_HASH: - // Win7 x86 rejects our code signing certificate; must enable - // "test signing" mode via aken_install.bat - break; - default: - // unexpected problem - DEBUG_WARN_ERR(ERR::LOGIC); - break; - } - } - } - - CloseServiceHandle(hService); - CloseServiceHandle(hSCM); -} - - -static bool Is64BitOs() -{ -#if OS_WIN64 - return true; -#else - return wutil_IsWow64(); -#endif -} - -static OsPath DriverPathname() -{ - const char* const bits = Is64BitOs()? "64" : ""; -#ifdef NDEBUG - const char* const debug = ""; -#else - const char* const debug = "d"; -#endif - char filename[PATH_MAX]; - sprintf_s(filename, ARRAY_SIZE(filename), "aken%s%s.sys", bits, debug); - return wutil_ExecutablePath() / filename; -} - -#endif // CONFIG2_MAHAF_ATTEMPT_DRIVER_START - - -//----------------------------------------------------------------------------- - -static Status Init() -{ - WinScopedPreserveLastError s; - - if(wutil_HasCommandLineArgument(L"-wNoMahaf")) - return ERR::NOT_SUPPORTED; // NOWARN - -#if CONFIG2_MAHAF_ATTEMPT_DRIVER_START - { - const OsPath driverPathname = DriverPathname(); - StartDriver(driverPathname); - } -#endif - - { - const DWORD shareMode = 0; - hAken = CreateFileW(L"\\\\.\\Aken", GENERIC_READ, shareMode, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if(hAken == INVALID_HANDLE_VALUE) - { - // GetLastError() is ERROR_FILE_NOT_FOUND if the driver isn't running, - // but this is also reached when a handle has already been opened - // (e.g. by a second instance of the same program) - in which case we must - // indicate failure so that clients won't engage in unsynchronized ring 0 operations. - SetLastError(0); - return ERR::INVALID_HANDLE; // NOWARN (happens often due to security restrictions) - } - } - - return INFO::OK; -} - -static void Shutdown() -{ - CloseHandle(hAken); - hAken = INVALID_HANDLE_VALUE; - - UninstallDriver(); -} - - -static ModuleInitState initState; - -Status mahaf_Init() -{ - return ModuleInit(&initState, Init); -} - -void mahaf_Shutdown() -{ - ModuleShutdown(&initState, Shutdown); -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/mahaf.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/mahaf.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/mahaf.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/mahaf.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * user-mode interface to Aken driver - */ - -// Mahaf - ferryman in Egyptian mythology that wakes up Aken, -// and the interface to the Aken driver. - -#ifndef INCLUDED_MAHAF -#define INCLUDED_MAHAF - -/** - * @return whether mapping physical memory is known to be dangerous - * on this platform. - * - * callable before or after mahaf_Init. - * - * note: mahaf_MapPhysicalMemory will complain if it - * is called despite this function having returned true. - **/ -LIB_API bool mahaf_IsPhysicalMappingDangerous(); - - -LIB_API Status mahaf_Init(); -LIB_API void mahaf_Shutdown(); - -LIB_API u8 mahaf_ReadPort8 (u16 port); -LIB_API u16 mahaf_ReadPort16(u16 port); -LIB_API u32 mahaf_ReadPort32(u16 port); -LIB_API void mahaf_WritePort8 (u16 port, u8 value); -LIB_API void mahaf_WritePort16(u16 port, u16 value); -LIB_API void mahaf_WritePort32(u16 port, u32 value); - -LIB_API volatile void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes); -LIB_API void mahaf_UnmapPhysicalMemory(volatile void* virtualAddress); - -LIB_API u64 mahaf_ReadModelSpecificRegister(u64 reg); -LIB_API void mahaf_WriteModelSpecificRegister(u64 reg, u64 value); - -// must be done in the driver because Windows clears CR4.PCE[8] -LIB_API u64 mahaf_ReadPerformanceMonitoringCounter(u64 reg); - -#endif // INCLUDED_MAHAF diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/counter.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/counter.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/counter.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/counter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Interface for counter implementations - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/counter.h" - -#include "lib/alignment.h" -#include "lib/sysdep/cpu.h" // cpu_CAS - -#include "lib/sysdep/os/win/whrt/tsc.h" -#include "lib/sysdep/os/win/whrt/hpet.h" -#include "lib/sysdep/os/win/whrt/pmt.h" -#include "lib/sysdep/os/win/whrt/qpc.h" -#include "lib/sysdep/os/win/whrt/tgt.h" -// to add a new counter type, simply include its header here and -// insert a case in ConstructCounterAt's switch statement. - - -//----------------------------------------------------------------------------- -// create/destroy counters - -/** - * @param id - * @param address - * @param size Maximum allowable size [bytes] of the subclass instance - * @return pointer to a newly constructed ICounter subclass of type \ at - * the given address, or 0 iff the ID is invalid. - **/ -static ICounter* ConstructCounterAt(size_t id, void* address, size_t size) -{ - // rationale for placement new: see call site. - - // counters are chosen according to the following order. rationale: - // - TSC must come before QPC and PMT to make sure a bug in the latter on - // Pentium systems doesn't come up. - // - PMT works, but is inexplicably slower than QPC on a PIII Mobile. - // - TGT really isn't as safe as the others, so it should be last. - // - low-overhead and high-resolution counters are preferred. - switch(id) - { - case 0: - return CreateCounterHPET(address, size); - case 1: - return CreateCounterTSC(address, size); - case 2: - return CreateCounterQPC(address, size); - case 3: - return CreateCounterPMT(address, size); - case 4: - return CreateCounterTGT(address, size); - default: - return 0; - } -} - - -static volatile intptr_t isCounterAllocated; - -ICounter* CreateCounter(size_t id) -{ - // we placement-new the Counter classes in a static buffer. - // this is dangerous, but we are careful to ensure alignment. it is - // unusual and thus bad, but there's also one advantage: we avoid - // using global operator new before the CRT is initialized (risky). - // - // alternatives: - // - defining as static doesn't work because the ctors (necessary for - // vptr initialization) run during _cinit, which comes after our - // first use of them. - // - using static_calloc isn't possible because we don't know the - // size until after the alloc / placement new. - - if(!cpu_CAS(&isCounterAllocated, 0, 1)) - DEBUG_WARN_ERR(ERR::LOGIC); // static counter memory is already in use! - - static const size_t memSize = 200; - static u8 mem[memSize]; - u8* alignedMem = (u8*)Align<16>((uintptr_t)mem); - const size_t bytesLeft = mem+memSize - alignedMem; - ICounter* counter = ConstructCounterAt(id, alignedMem, bytesLeft); - - return counter; -} - - -void DestroyCounter(ICounter*& counter) -{ - ENSURE(counter); - counter->Shutdown(); - counter->~ICounter(); // must be called due to placement new - counter = 0; - - isCounterAllocated = 0; -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/counter.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/counter.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/counter.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/counter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Interface for counter implementations - */ - -#ifndef INCLUDED_COUNTER -#define INCLUDED_COUNTER - -// derived implementations must be called CounterIMPL, -// where IMPL matches the WHRT_IMPL identifier. (see CREATE) -class ICounter -{ -public: - // (compiled-generated) ctor only sets up the vptr - virtual ~ICounter() {} - - virtual const char* Name() const = 0; - - // Activate with an error return value is much cleaner+safer than - // throwing exceptions in the ctor. - virtual Status Activate() = 0; - virtual void Shutdown() = 0; - - virtual bool IsSafe() const = 0; - - /** - * @return the current value of the counter (all but the lower - * CounterBits() bits must be zero) - **/ - virtual u64 Counter() const = 0; - - // note: implementations need not cache the following; that's taken - // care of by WHRT. - - /** - * @return the bit width of the counter (<= 64) - * WHRT uses this to ensure the counter (running at nominal frequency) - * doesn't overflow more than once during CALIBRATION_INTERVAL_MS. - **/ - virtual size_t CounterBits() const = 0; - - /** - * initial measurement of the tick rate. not necessarily correct - * (e.g. when using TSC: os_cpu_ClockFrequency isn't exact). - **/ - virtual double NominalFrequency() const = 0; - - /** - * actual resolution [s]. differs from 1/NominalFrequency if the - * timer adjustment is greater than 1 tick. - **/ - virtual double Resolution() const = 0; -}; - - -/** - * @return a newly created ICounter of type \ or 0 iff the ID is invalid. - * @param id integer ID (0..N-1) - * - * there can only be one active counter at a time; the previous one must - * have been destroyed before creating another! - **/ -extern ICounter* CreateCounter(size_t id); - -/** - * shut down the counter, free its resources and zero its pointer. - **/ -extern void DestroyCounter(ICounter*& counter); - -#endif // #ifndef INCLUDED_COUNTER diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/hpet.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/hpet.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/hpet.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/hpet.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,233 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using High Precision Event Timer - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/hpet.h" - -// for atomic 64-bit read/write: -#define HAVE_X64_MOVD ARCH_AMD64 && (ICC_VERSION || MSC_VERSION >= 1500) -#if HAVE_X64_MOVD -# include -#else -# include -#endif - -#include "lib/sysdep/os/win/whrt/counter.h" - -#include "lib/sysdep/os/win/win.h" -#include "lib/sysdep/os/win/mahaf.h" -#include "lib/sysdep/acpi.h" -#include "lib/bits.h" - - -class CounterHPET : public ICounter -{ -public: - CounterHPET() - : m_hpetRegisters(0) - { - } - - virtual const char* Name() const - { - return "HPET"; - } - - Status Activate() - { - RETURN_STATUS_IF_ERR(MapRegisters(m_hpetRegisters)); - - RETURN_STATUS_IF_ERR(VerifyCapabilities(m_frequency, m_counterBits)); - - // start the counter (if not already running) - Write64(CONFIG, Read64(CONFIG)|1); - // note: to avoid interfering with any other users of the timer - // (e.g. Vista QPC), we don't reset the counter value to 0. - - return INFO::OK; - } - - void Shutdown() - { - if(m_hpetRegisters) - { - mahaf_UnmapPhysicalMemory((void*)m_hpetRegisters); - m_hpetRegisters = 0; - } - } - - bool IsSafe() const - { - // the HPET having been created to address other timers' problems, - // it has no issues of its own. - return true; - } - - u64 Counter() const - { - // notes: - // - Read64 is atomic and avoids race conditions. - // - 32-bit counters (m_counterBits == 32) still allow - // reading the whole register (the upper bits are zero). - return Read64(COUNTER_VALUE); - } - - size_t CounterBits() const - { - return m_counterBits; - } - - double NominalFrequency() const - { - return m_frequency; - } - - double Resolution() const - { - return 1.0 / m_frequency; - } - -private: -#pragma pack(push, 1) - - struct HpetDescriptionTable - { - AcpiTable header; - u32 eventTimerBlockId; - AcpiGenericAddress baseAddress; - u8 sequenceNumber; - u16 minimumPeriodicTicks; - u8 attributes; - }; - -#pragma pack(pop) - - enum RegisterOffsets - { - CAPS_AND_ID = 0x00, - CONFIG = 0x10, - COUNTER_VALUE = 0xF0, - MAX_OFFSET = 0x3FF - }; - - static Status MapRegisters(volatile void*& registers) - { - if(mahaf_IsPhysicalMappingDangerous()) - return ERR::FAIL; // NOWARN (happens on Win2k) - RETURN_STATUS_IF_ERR(mahaf_Init()); // (fails without Administrator privileges) - - const HpetDescriptionTable* hpet = (const HpetDescriptionTable*)acpi_GetTable("HPET"); - if(!hpet) - return ERR::NOT_SUPPORTED; // NOWARN (HPET not reported by BIOS) - - if(hpet->baseAddress.addressSpaceId != ACPI_AS_MEMORY) - return ERR::NOT_SUPPORTED; // NOWARN (happens on some BIOSes) - // hpet->baseAddress.accessSize is reserved - const uintptr_t address = uintptr_t(hpet->baseAddress.address); - ENSURE(address % 8 == 0); // "registers are generally aligned on 64-bit boundaries" - - registers = mahaf_MapPhysicalMemory(address, MAX_OFFSET+1); - if(!registers) - WARN_RETURN(ERR::NO_MEM); - - return INFO::OK; - } - - // note: this is atomic even on 32-bit CPUs (Pentium MMX and - // above have a 64-bit data bus and MOVQ instruction) - u64 Read64(size_t offset) const - { - ENSURE(offset <= MAX_OFFSET); - ENSURE(offset % 8 == 0); - const uintptr_t address = uintptr_t(m_hpetRegisters)+offset; - const __m128i value128 = _mm_loadl_epi64((__m128i*)address); -#if HAVE_X64_MOVD - return _mm_cvtsi128_si64x(value128); -#else - __declspec(align(16)) u32 values[4]; - _mm_store_si128((__m128i*)values, value128); - return u64_from_u32(values[1], values[0]); -#endif - } - - void Write64(size_t offset, u64 value) const - { - ENSURE(offset <= MAX_OFFSET); - ENSURE(offset % 8 == 0); - ENSURE(offset != CAPS_AND_ID); // can't write to read-only registers - const uintptr_t address = uintptr_t(m_hpetRegisters)+offset; -#if HAVE_X64_MOVD - const __m128i value128 = _mm_cvtsi64x_si128(value); -#else - const __m128i value128 = _mm_set_epi32(0, 0, int(value >> 32), int(value & 0xFFFFFFFF)); -#endif - _mm_storel_epi64((__m128i*)address, value128); - } - - Status VerifyCapabilities(double& frequency, u32& counterBits) const - { - // AMD document 43366 indicates the clock generator that drives the - // HPET is "spread-capable". Wikipedia's frequency hopping article - // explains that this reduces electromagnetic interference. - // The AMD document recommends BIOS writers add SMM hooks for - // reporting the resulting slightly different frequency. - // This apparently requires calibration triggered when the HPET is - // accessed, during which the config register is -1. We'll wait - // about 1 ms (MMIO is expected to take at least 1 us) and - // then ensure the HPET timer period is within reasonable bounds. - u64 caps_and_id = Read64(CAPS_AND_ID); - for(size_t reps = 0; reps < 1000; reps++) - { - if(caps_and_id != ~u64(0)) // register seems valid - break; - caps_and_id = Read64(CAPS_AND_ID); - } - - const u8 revision = (u8)bits(caps_and_id, 0, 7); - ENSURE(revision != 0); // "the value must NOT be 00h" - counterBits = (caps_and_id & Bit(13))? 64 : 32; - const u16 vendorID = (u16)bits(caps_and_id, 16, 31); - const u32 period_fs = (u32)bits(caps_and_id, 32, 63); - ENSURE(period_fs != 0); // "a value of 0 in this field is not permitted" - frequency = 1e15 / period_fs; - debug_printf("HPET: rev=%X vendor=%X bits=%d period=%08X freq=%g\n", revision, vendorID, counterBits, period_fs, frequency); - - if(period_fs > 0x05F5E100) // 100 ns (spec guarantees >= 10 MHz) - return ERR::CORRUPTED; // avoid using HPET (e.g. if calibration was still in progress) - - return INFO::OK; - } - - volatile void* m_hpetRegisters; - double m_frequency; - u32 m_counterBits; -}; - -ICounter* CreateCounterHPET(void* address, size_t size) -{ - ENSURE(sizeof(CounterHPET) <= size); - return new(address) CounterHPET(); -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/hpet.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/hpet.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/hpet.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/hpet.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using High Precision Event Timer - */ - -#ifndef INCLUDED_HPET -#define INCLUDED_HPET - -class ICounter; -extern ICounter* CreateCounterHPET(void* address, size_t size); - -#endif // #ifndef INCLUDED_HPET diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/pit.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/pit.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/pit.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/pit.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using 82C53/4 PIT - */ - -#ifndef INCLUDED_PIT -#define INCLUDED_PIT - -// note: we don't access the PIT for two reasons: -// - it rolls over every 55 ms (1.193 MHz, 16 bit) and would have to be -// read at least that often, which would require setting high thread -// priority (dangerous). -// - reading it is slow and cannot be done by two independent users -// (the second being QPC) since the counter value must be latched. -// -// there are enough other counters anway. - -static const i64 PIT_FREQ = 1193182; // (= master oscillator frequency/12) - -#endif // #ifndef INCLUDED_PIT diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/pmt.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/pmt.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/pmt.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/pmt.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using ACPI PM timer - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/pmt.h" - -#include "lib/sysdep/os/win/whrt/counter.h" - -#include "lib/sysdep/os/win/win.h" -#include "lib/sysdep/acpi.h" -#include "lib/sysdep/os/win/mahaf.h" -#include "lib/bits.h" - -static const u32 TMR_VAL_EXT = Bit(8); // FADT flags - -//----------------------------------------------------------------------------- - - -class CounterPMT : public ICounter -{ -public: - CounterPMT() - : m_portAddress(0xFFFF) - { - } - - virtual const char* Name() const - { - return "PMT"; - } - - Status Activate() - { - // mahaf is needed for port I/O. - RETURN_STATUS_IF_ERR(mahaf_Init()); // (fails without Administrator privileges) - // (note: it's called FADT, but the signature is "FACP") - const FADT* fadt = (const FADT*)acpi_GetTable("FACP"); - if(!fadt) - return ERR::NOT_SUPPORTED; // NOWARN (ACPI tables might not be available) - m_portAddress = u16_from_larger(fadt->pmTimerPortAddress); - - return INFO::OK; - } - - void Shutdown() - { - } - - bool IsSafe() const - { - // the PMT has one issue: "Performance counter value may unexpectedly - // leap forward" (Q274323). This happens on some buggy Pentium-era - // systems under heavy PCI bus load. We are clever and observe that - // the TSC implementation would be used on such systems (because it - // has higher precedence and is safe on P5 CPUs), so the PMT is fine - // in general. - return true; - } - - u64 Counter() const - { - return mahaf_ReadPort32(m_portAddress); - } - - size_t CounterBits() const - { - // (see previous acpi_GetTable call) - const FADT* fadt = (const FADT*)acpi_GetTable("FACP"); - ENSURE(fadt); // Activate made sure FADT is available - const size_t counterBits = (fadt->flags & TMR_VAL_EXT)? 32 : 24; - return counterBits; - } - - double NominalFrequency() const - { - return (double)PMT_FREQ; - } - - double Resolution() const - { - return 1.0 / PMT_FREQ; - } - -private: - u16 m_portAddress; -}; - -ICounter* CreateCounterPMT(void* address, size_t size) -{ - ENSURE(sizeof(CounterPMT) <= size); - return new(address) CounterPMT(); -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/pmt.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/pmt.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/pmt.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/pmt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using ACPI PM timer - */ - -#ifndef INCLUDED_PMT -#define INCLUDED_PMT - -static const i64 PMT_FREQ = 3579545; // (= master oscillator frequency/4) - -class ICounter; -extern ICounter* CreateCounterPMT(void* address, size_t size); - -#endif // #ifndef INCLUDED_PMT diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/qpc.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/qpc.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/qpc.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/qpc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using QueryPerformanceCounter - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/qpc.h" - -#include "lib/sysdep/os/win/whrt/counter.h" - -#include "lib/sysdep/os_cpu.h" -#include "lib/sysdep/os/win/win.h" -#include "lib/sysdep/os/win/wutil.h" // wutil_argv -#include "lib/sysdep/os/win/whrt/pit.h" // PIT_FREQ -#include "lib/sysdep/os/win/whrt/pmt.h" // PMT_FREQ - - -class CounterQPC : public ICounter -{ -public: - CounterQPC() - : m_frequency(-1) - { - } - - virtual const char* Name() const - { - return "QPC"; - } - - Status Activate() - { - // note: QPC is observed to be universally supported, but the API - // provides for failure, so play it safe. - - LARGE_INTEGER qpcFreq, qpcValue; - const BOOL ok1 = QueryPerformanceFrequency(&qpcFreq); - const BOOL ok2 = QueryPerformanceCounter(&qpcValue); - if(!ok1 || !ok2) - WARN_RETURN(ERR::FAIL); - if(!qpcFreq.QuadPart || !qpcValue.QuadPart) - WARN_RETURN(ERR::FAIL); - - m_frequency = (i64)qpcFreq.QuadPart; - return INFO::OK; - } - - void Shutdown() - { - } - - bool IsSafe() const - { - // note: we have separate modules that directly access some of the - // counters potentially used by QPC. disabling the redundant counters - // would be ugly (increased coupling). instead, we'll make sure our - // implementations could (if necessary) coexist with QPC, but it - // shouldn't come to that since only one counter is needed/used. - - // the PIT is entirely safe (even if annoyingly slow to read) - if(m_frequency == PIT_FREQ) - return true; - - // the PMT is generally safe (see discussion in CounterPmt::IsSafe), - // but older QPC implementations had problems with 24-bit rollover. - // "System clock problem can inflate benchmark scores" - // (http://www.lionbridge.com/bi/cont2000/200012/perfcnt.asp ; no longer - // online, nor findable in Google Cache / archive.org) tells of - // incorrect values every 4.6 seconds (i.e. 24 bits @ 3.57 MHz) unless - // the timer is polled in the meantime. fortunately, this is guaranteed - // by our periodic updates (which come at least that often). - if(m_frequency == PMT_FREQ) - return true; - - // the TSC has been known to be buggy (even mentioned in MSDN). it is - // used on MP HAL systems and can be detected by comparing QPF with the - // CPU clock. we consider it unsafe unless the user promises (via - // command line) that it's patched and thus reliable on their system. - bool usesTsc = IsSimilarMagnitude((double)m_frequency, os_cpu_ClockFrequency()); - // unconfirmed reports indicate QPC sometimes uses 1/3 of the - // CPU clock frequency, so check that as well. - usesTsc |= IsSimilarMagnitude((double)m_frequency, os_cpu_ClockFrequency()/3); - if(usesTsc) - { - const bool isTscSafe = wutil_HasCommandLineArgument(L"-wQpcTscSafe"); - return isTscSafe; - } - - // the HPET is reliable and used on Vista. it can't easily be recognized - // since its frequency is variable (the spec says > 10 MHz; the master - // 14.318 MHz oscillator is often used). considering frequencies in - // [10, 100 MHz) to be a HPET would be dangerous because it may actually - // be faster or RDTSC slower. we have to exclude all other cases and - // assume it's a HPET - and thus safe - if we get here. - return true; - } - - u64 Counter() const - { - // fairly time-critical here, don't check the return value - // (IsSupported made sure it succeeded initially) - LARGE_INTEGER qpc_value; - (void)QueryPerformanceCounter(&qpc_value); - return qpc_value.QuadPart; - } - - size_t CounterBits() const - { - // there are reports of incorrect rollover handling in the PMT - // implementation of QPC (see CounterPMT::IsSafe). however, other - // counters would be used on those systems, so it's irrelevant. - // we'll report the full 64 bits. - return 64; - } - - double NominalFrequency() const - { - return (double)m_frequency; - } - - double Resolution() const - { - return 1.0 / m_frequency; - } - -private: - // used in several places and QPF is a bit slow+cumbersome. - // (i64 allows easier conversion to double) - i64 m_frequency; -}; - -ICounter* CreateCounterQPC(void* address, size_t size) -{ - ENSURE(sizeof(CounterQPC) <= size); - return new(address) CounterQPC(); -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/qpc.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/qpc.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/qpc.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/qpc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using QueryPerformanceCounter - */ - -#ifndef INCLUDED_QPC -#define INCLUDED_QPC - -class ICounter; -extern ICounter* CreateCounterQPC(void* address, size_t size); - -#endif // #ifndef INCLUDED_QPC diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tgt.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tgt.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tgt.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tgt.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using timeGetTime - */ - -// note: WinMM is delay-loaded to avoid dragging it in when this timer -// implementation isn't used. (this is relevant because its startup is -// fairly slow) - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/tgt.h" - -#include "lib/sysdep/os/win/whrt/counter.h" - -#include "lib/sysdep/os/win/win.h" -#include - -#if MSC_VERSION -#pragma comment(lib, "winmm.lib") -#endif - - -// "Guidelines For Providing Multimedia Timer Support" claims that -// speeding the timer up to 2 ms has little impact, while 1 ms -// causes significant slowdown. -static const UINT PERIOD_MS = 2; - -class CounterTGT : public ICounter -{ -public: - virtual const char* Name() const - { - return "TGT"; - } - - Status Activate() - { - // note: timeGetTime is always available and cannot fail. - - MMRESULT ret = timeBeginPeriod(PERIOD_MS); - ENSURE(ret == TIMERR_NOERROR); - - return INFO::OK; - } - - void Shutdown() - { - timeEndPeriod(PERIOD_MS); - } - - bool IsSafe() const - { - // the only point of criticism is the possibility of falling behind - // due to lost interrupts. this can happen to any interrupt-based timer - // and some systems may lack a counter-based timer, so consider TGT - // 'safe'. note that it is still only chosen when all other timers fail. - return true; - } - - u64 Counter() const - { - return timeGetTime(); - } - - size_t CounterBits() const - { - return 32; - } - - double NominalFrequency() const - { - return 1000.0; - } - - double Resolution() const - { - return PERIOD_MS*1e-3; - } -}; - -ICounter* CreateCounterTGT(void* address, size_t size) -{ - ENSURE(sizeof(CounterTGT) <= size); - return new(address) CounterTGT(); -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tgt.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tgt.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tgt.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tgt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using timeGetTime - */ - -#ifndef INCLUDED_TGT -#define INCLUDED_TGT - -class ICounter; -extern ICounter* CreateCounterTGT(void* address, size_t size); - -#endif // #ifndef INCLUDED_TGT diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tsc.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tsc.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tsc.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tsc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,259 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using RDTSC - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/tsc.h" - -#include "lib/sysdep/os/win/whrt/counter.h" - -#include "lib/bits.h" -#include "lib/sysdep/acpi.h" -#include "lib/sysdep/os_cpu.h" -#include "lib/sysdep/os/win/win.h" -#include "lib/sysdep/os/win/wutil.h" - -#if ARCH_X86_X64 -# include "lib/sysdep/arch/x86_x64/x86_x64.h" // x86_x64::rdtsc -# include "lib/sysdep/arch/x86_x64/topology.h" -# include "lib/sysdep/arch/x86_x64/msr.h" -#endif - - -//----------------------------------------------------------------------------- - -static bool IsUniprocessor() -{ - if(topology::NumPackages() != 1) - return false; - if(topology::CoresPerPackage() != 1) - return false; - return true; -} - - -static bool IsInvariantTSC() -{ -#if ARCH_X86_X64 - // (we no longer need to check x86_x64::Vendor - Intel and AMD - // agreed on the definition of this feature check) - x86_x64::CpuidRegs regs = { 0 }; - regs.eax = 0x80000007; - if(x86_x64::cpuid(®s)) - { - // TSC is invariant across P-state, C-state, turbo, and - // stop grant transitions (e.g. STPCLK) - if(regs.edx & BIT(8)) - return true; - } -#endif - - return false; -} - - -static bool IsThrottlingPossible() -{ -#if ARCH_X86_X64 - x86_x64::CpuidRegs regs = { 0 }; - switch(x86_x64::Vendor()) - { - case x86_x64::VENDOR_INTEL: - if(x86_x64::Cap(x86_x64::CAP_TM_SCC) || x86_x64::Cap(x86_x64::CAP_EST)) - return true; - break; - - case x86_x64::VENDOR_AMD: - regs.eax = 0x80000007; - if(x86_x64::cpuid(®s)) - { - enum AmdPowerNowFlags - { - PN_FREQ_ID_CTRL = BIT(1), - PN_HW_THERMAL_CTRL = BIT(4), - PN_SW_THERMAL_CTRL = BIT(5) - }; - if(regs.edx & (PN_FREQ_ID_CTRL|PN_HW_THERMAL_CTRL|PN_SW_THERMAL_CTRL)) - return true; - } - break; - - default: - break; - } -#endif - - return false; -} - - -static bool IsSandyBridge() -{ - if(x86_x64::Vendor() != x86_x64::VENDOR_INTEL) - return false; - if(x86_x64::Model() == x86_x64::MODEL_SANDY_BRIDGE) - return true; - if(x86_x64::Model() == x86_x64::MODEL_SANDY_BRIDGE_2) - return true; - return false; -} - - -//----------------------------------------------------------------------------- - -class CounterTSC : public ICounter -{ -public: - virtual const char* Name() const - { - return "TSC"; - } - - Status Activate() - { -#if ARCH_X86_X64 - if(!x86_x64::Cap(x86_x64::CAP_TSC)) - return ERR::NOT_SUPPORTED; // NOWARN (CPU doesn't support RDTSC) -#endif - - return INFO::OK; - } - - void Shutdown() - { - } - - bool IsSafe() const - { - // using the TSC for timing is subject to a litany of - // potential problems, discussed below: - - if(IsInvariantTSC()) - return true; - - // SMP or multi-core => counters are unsynchronized. both offset and - // drift could be solved by maintaining separate per-core - // counter states, but that requires atomic reads of the TSC and - // the current processor number. - // - // (otherwise, we have a subtle race condition: if preempted while - // reading the time and rescheduled on a different core, incorrect - // results may be returned, which would be unacceptable.) - // - // unfortunately this isn't possible without OS support or the - // as yet unavailable RDTSCP instruction => unsafe. - // - // (note: if the TSC is invariant, drift is no longer a concern. - // we could synchronize the TSC MSRs during initialization and avoid - // per-core counter state and the race condition mentioned above. - // however, we won't bother, since such platforms aren't yet widespread - // and would surely support the nice and safe HPET, anyway) - if(!IsUniprocessor()) - return false; - - const FADT* fadt = (const FADT*)acpi_GetTable("FACP"); - if(fadt) - { - ENSURE(fadt->header.size >= sizeof(FADT)); - - // TSC isn't incremented in deep-sleep states => unsafe. - if(fadt->IsC3Supported()) - return false; - - // frequency throttling possible => unsafe. - if(fadt->IsDutyCycleSupported()) - return false; - } - -#if ARCH_X86_X64 - // recent CPU: - //if(x86_x64::Generation() >= 7) - { - // note: 8th generation CPUs support C1-clock ramping, which causes - // drift on multi-core systems, but those were excluded above. - - // in addition to frequency changes due to P-state transitions, - // we're also subject to STPCLK throttling. this happens when - // the chipset thinks the system is dangerously overheated; the - // OS isn't even notified. this may be rare, but could cause - // incorrect results => unsafe. - //return false; - } -#endif - - // we're dealing with a single older CPU; the only problem there is - // throttling, i.e. changes to the TSC frequency. we don't want to - // disable this because it may be important for cooling. the OS - // initiates changes but doesn't notify us; jumps are too frequent - // and drastic to detect and account for => unsafe. - if(IsThrottlingPossible()) - return false; - - return true; - } - - u64 Counter() const - { - return x86_x64::rdtsc(); - } - - size_t CounterBits() const - { - return 64; - } - - double NominalFrequency() const - { - // WARNING: do not call x86_x64::ClockFrequency because it uses the - // HRT, which we're currently in the process of initializing. - // instead query CPU clock frequency via OS. - // - // note: even here, initial accuracy isn't critical because the - // clock is subject to thermal drift and would require continual - // recalibration anyway. -#if ARCH_X86_X64 - if(MSR::IsAccessible() && MSR::HasPlatformInfo()) - { - const i64 busFrequency = IsSandyBridge()? 100000000 : 133333333; - const u64 platformInfo = MSR::Read(MSR::PLATFORM_INFO); - const u8 maxNonTurboRatio = bits(platformInfo, 8, 15); - return double(maxNonTurboRatio) * busFrequency; - } - else -#endif - return os_cpu_ClockFrequency(); - } - - double Resolution() const - { - return 1.0 / NominalFrequency(); - } -}; - -ICounter* CreateCounterTSC(void* address, size_t size) -{ - ENSURE(sizeof(CounterTSC) <= size); - return new(address) CounterTSC(); -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tsc.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tsc.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/tsc.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/tsc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Timer implementation using RDTSC - */ - -#ifndef INCLUDED_TSC -#define INCLUDED_TSC - -class ICounter; -extern ICounter* CreateCounterTSC(void* address, size_t size); - -#endif // #ifndef INCLUDED_TSC diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/whrt.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/whrt.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/whrt.cpp 2018-03-10 09:58:53.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/whrt.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,313 +0,0 @@ -/* Copyright (C) 2018 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Windows High Resolution Timer - */ - -#include "precompiled.h" -#include "lib/sysdep/os/win/whrt/whrt.h" - -#include // _beginthreadex - -#include "lib/sysdep/cpu.h" -#include "lib/sysdep/os/win/wutil.h" -#include "lib/sysdep/os/win/winit.h" -#include "lib/sysdep/acpi.h" -#include "lib/bits.h" - -#include "lib/sysdep/os/win/whrt/counter.h" - -WINIT_REGISTER_EARLY_INIT2(whrt_Init); // wutil -> whrt -> wtime -WINIT_REGISTER_LATE_SHUTDOWN(whrt_Shutdown); - - -namespace ERR -{ - const Status WHRT_COUNTER_UNSAFE = 140000; -} - - -//----------------------------------------------------------------------------- -// choose best available safe counter - -// (moved into a separate function to simplify error handling) -static inline Status ActivateCounter(ICounter* counter) -{ - RETURN_STATUS_IF_ERR(counter->Activate()); - - if(!counter->IsSafe()) - return ERR::WHRT_COUNTER_UNSAFE; // NOWARN (happens often) - - return INFO::OK; -} - -/** - * @return the newly created and unique instance of the next best counter - * that is deemed safe, or 0 if all have already been created. - **/ -static ICounter* GetNextBestSafeCounter() -{ - for(;;) - { - static size_t nextCounterId = 0; - ICounter* counter = CreateCounter(nextCounterId++); - if(!counter) - return 0; // tried all, none were safe - - Status err = ActivateCounter(counter); - if(err == INFO::OK) - { - debug_printf("HRT: using name=%s freq=%f\n", counter->Name(), counter->NominalFrequency()); - return counter; // found a safe counter - } - else - { - wchar_t buf[100]; - debug_printf("HRT: activating %s failed: %s\n", counter->Name(), utf8_from_wstring(StatusDescription(err, buf, ARRAY_SIZE(buf))).c_str()); - DestroyCounter(counter); - } - } -} - - -//----------------------------------------------------------------------------- -// counter that drives the timer - -static ICounter* counter; -// (these counter properties are cached for efficiency and convenience:) -static double nominalFrequency; -static double resolution; -static size_t counterBits; -static u64 counterMask; - -static void InitCounter() -{ - // we used to support switching counters at runtime, but that's - // unnecessarily complex. it need and should only be done once. - ENSURE(counter == 0); - counter = GetNextBestSafeCounter(); - ENSURE(counter != 0); - - nominalFrequency = counter->NominalFrequency(); - resolution = counter->Resolution(); - counterBits = counter->CounterBits(); - debug_printf("HRT: counter=%s freq=%g res=%g bits=%d\n", counter->Name(), nominalFrequency, resolution, counterBits); - - // sanity checks - ENSURE(nominalFrequency >= 500.0-DBL_EPSILON); - ENSURE(resolution <= 2e-3); - ENSURE(8 <= counterBits && counterBits <= 64); - - counterMask = bit_mask(counterBits); -} - -static void ShutdownCounter() -{ - DestroyCounter(counter); -} - -static inline u64 Counter() -{ - return counter->Counter(); -} - -/** - * @return difference [ticks], taking rollover into account. - * (time-critical, so it's not called through ICounter.) - **/ -static inline u64 CounterDelta(u64 oldCounter, u64 newCounter) -{ - return (newCounter - oldCounter) & counterMask; -} - -double whrt_Resolution() -{ - ENSURE(resolution != 0.0); - return resolution; -} - - -//----------------------------------------------------------------------------- -// timer state - -// we're not going to bother calibrating the counter (i.e. measuring its -// current frequency by means of a second timer). rationale: -// - all counters except the TSC are stable and run at fixed frequencies; -// - it's not clear that any other HRT or the tick count would be useful -// as a stable time reference (if it were, we should be using it instead); -// - calibration would complicate the code (we'd have to make sure the -// secondary counter is safe and can co-exist with the primary). - -/** - * stores all timer state shared between readers and the update thread. - * (must be POD because it's used before static ctors run.) - **/ -struct TimerState -{ - // value of the counter at last update. - u64 counter; - - // total elapsed time [seconds] since first update. - // converted from tick deltas with the *then current* frequency - // (this enables calibration, which is currently not implemented, - // but leaving open the possibility costs nothing) - double time; - - u8 padding[48]; -}; - -// how do we detect when the old TimerState is no longer in use and can be -// freed? we use two static instances (avoids dynamic allocation headaches) -// and swap between them ('double-buffering'). it is assumed that all -// entered critical sections (the latching of TimerState fields) will have -// been exited before the next update comes around; if not, TimerState.time -// changes, the critical section notices and re-reads the new values. -static __declspec(align(64)) TimerState timerStates[2]; -// note: exchanging pointers is easier than XORing an index. -static volatile TimerState* volatile ts = &timerStates[0]; -static volatile TimerState* volatile ts2 = &timerStates[1]; - -static void UpdateTimerState() -{ - // how can we synchronize readers and the update thread? locks are - // preferably avoided since they're dangerous and can be slow. what we - // need to ensure is that TimerState doesn't change while another thread is - // accessing it. the first step is to linearize the update, i.e. have it - // appear to happen in an instant (done by building a new TimerState and - // having it go live by switching pointers). all that remains is to make - // reads of the state variables consistent, done by latching them all and - // retrying if an update came in the middle of this. - - const u64 currentCounter = Counter(); - const u64 deltaTicks = CounterDelta(ts->counter, currentCounter); - ts2->counter = currentCounter; - ts2->time = ts->time + deltaTicks/nominalFrequency; - ts = (volatile TimerState*)InterlockedExchangePointer((volatile PVOID*)&ts2, (PVOID)ts); -} - -double whrt_Time() -{ - // latch timer state (counter and time must be from the same update) - const volatile TimerState* state = ts; - return (state->time + CounterDelta(state->counter, Counter()) / nominalFrequency); -} - - -//----------------------------------------------------------------------------- -// update thread - -// note: we used to discipline the HRT timestamp to the system time, so it -// was advantageous to trigger updates via WinMM event (thus reducing -// instances where we're called in the middle of a scheduler tick). -// since that's no longer relevant, we prefer using a thread, because that -// avoids the dependency on WinMM and its lengthy startup time. - -// rationale: (+ and - are reasons for longer and shorter lengths) -// + minimize CPU usage -// + ensure all threads currently using TimerState return from those -// functions before the next interval -// - avoid more than 1 counter rollover per interval (InitUpdateThread makes -// sure our interval is shorter than the current counter's rollover rate) -static const DWORD UPDATE_INTERVAL_MS = 1000; - -static HANDLE hExitEvent; -static HANDLE hUpdateThread; - -static unsigned __stdcall UpdateThread(void* UNUSED(data)) -{ - debug_SetThreadName("whrt_UpdateThread"); - - for(;;) - { - const DWORD ret = WaitForSingleObject(hExitEvent, UPDATE_INTERVAL_MS); - // owner terminated or wait failed or exit event signaled - exit thread - if(ret != WAIT_TIMEOUT) - break; - - UpdateTimerState(); - } - - return 0; -} - -static inline Status InitUpdateThread() -{ - WinScopedPreserveLastError s; // CreateEvent - - // make sure our interval isn't too long - // (counterBits can be 64 => Bit() would overflow => calculate period/2) - const double period_2 = Bit(counterBits-1) / nominalFrequency; - const size_t rolloversPerInterval = size_t(UPDATE_INTERVAL_MS / i64(period_2*2.0*1000.0)); - ENSURE(rolloversPerInterval <= 1); - - hExitEvent = CreateEvent(0, TRUE, FALSE, 0); // manual reset, initially false - if(hExitEvent == INVALID_HANDLE_VALUE) - WARN_RETURN(ERR::LIMIT); - - hUpdateThread = (HANDLE)_beginthreadex(0, 0, UpdateThread, 0, 0, 0); - if(!hUpdateThread) - WARN_RETURN(ERR::LIMIT); - - return INFO::OK; -} - -static inline void ShutdownUpdateThread() -{ - // signal thread - BOOL ok = SetEvent(hExitEvent); - WARN_IF_FALSE(ok); - // the nice way is to wait for it to exit - if(WaitForSingleObject(hUpdateThread, 100) != WAIT_OBJECT_0) - TerminateThread(hUpdateThread, 0); // forcibly exit (dangerous) - CloseHandle(hExitEvent); - CloseHandle(hUpdateThread); -} - - -//----------------------------------------------------------------------------- - -static Status whrt_Init() -{ - InitCounter(); - - // latch initial counter value so that timer starts at 0 - ts->counter = Counter(); // must come before UpdateTimerState - - UpdateTimerState(); // must come before InitUpdateThread to avoid race - - RETURN_STATUS_IF_ERR(InitUpdateThread()); - - return INFO::OK; -} - - -static Status whrt_Shutdown() -{ - ShutdownUpdateThread(); - - ShutdownCounter(); - - acpi_Shutdown(); - - return INFO::OK; -} diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/whrt.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/whrt.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/whrt/whrt.h 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/whrt/whrt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Windows High Resolution Timer - */ - -#ifndef INCLUDED_WHRT -#define INCLUDED_WHRT - -extern double whrt_Resolution(); -extern double whrt_Time(); - -#endif // #ifndef INCLUDED_WHRT diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wposix/wpthread.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wposix/wpthread.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wposix/wpthread.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wposix/wpthread.cpp 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -474,72 +474,6 @@ } -// helper function for sem_timedwait - multiple return is convenient. -// converts an absolute timeout deadline into a relative length for use with -// WaitForSingleObject with the following peculiarity: if the semaphore -// could be locked immediately, abs_timeout must be ignored (see SUS). -// to that end, we return a timeout of 0 and pass back = false if -// abs_timeout is invalid. -static DWORD calc_timeout_length_ms(const struct timespec* abs_timeout, - bool& timeout_is_valid) -{ - timeout_is_valid = false; - - if(!abs_timeout) - return 0; - - // SUS requires we fail if not normalized - if(abs_timeout->tv_nsec >= 1000000000) - return 0; - - struct timespec cur_time; - if(clock_gettime(CLOCK_REALTIME, &cur_time) != 0) - return 0; - - timeout_is_valid = true; - - // convert absolute deadline to relative length, rounding up to [ms]. - // note: use i64 to avoid overflow in multiply. - const i64 ds = abs_timeout->tv_sec - cur_time.tv_sec; - const long dn = abs_timeout->tv_nsec - cur_time.tv_nsec; - i64 length_ms = ds*1000 + (dn+500000)/1000000; - // .. deadline already reached; we'll still attempt to lock once - if(length_ms < 0) - return 0; - // .. length > 49 days => result won't fit in 32 bits. most likely bogus. - // note: we're careful to avoid returning exactly -1 since - // that's the Win32 INFINITE value. - if(length_ms >= 0xFFFFFFFF) - { - WARN_IF_ERR(ERR::LIMIT); - length_ms = 0xfffffffe; - } - return (DWORD)(length_ms & 0xFFFFFFFF); -} - -int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout) -{ - bool timeout_is_valid; - DWORD timeout_ms = calc_timeout_length_ms(abs_timeout, timeout_is_valid); - - HANDLE h = HANDLE_from_sem_t(sem); - DWORD ret = WaitForSingleObject(h, timeout_ms); - // successfully decremented semaphore; bail. - if(ret == WAIT_OBJECT_0) - return 0; - - // we're going to return -1. decide what happened: - // .. abs_timeout was invalid (must not check this before trying to lock) - if(!timeout_is_valid) - errno = EINVAL; - // .. timeout reached (not a failure) - else if(ret == WAIT_TIMEOUT) - errno = ETIMEDOUT; - - return -1; -} - - // wait until semaphore is locked or a message arrives. non-portable. // // background: on Win32, UI threads must periodically pump messages, or diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wposix/wtime.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wposix/wtime.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wposix/wtime.cpp 2017-07-10 14:26:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wposix/wtime.cpp 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,15 +24,11 @@ * emulate POSIX time functionality on Windows. */ -// note: clock_gettime et al. have been removed. callers should use the -// WHRT directly, rather than needlessly translating s -> ns -> s, -// which costs time and accuracy. #include "precompiled.h" #include "lib/sysdep/os/win/wposix/wtime.h" #include "lib/sysdep/os/win/wposix/wposix_internal.h" -#include "lib/sysdep/os/win/whrt/whrt.h" WINIT_REGISTER_MAIN_INIT(wtime_Init); // whrt -> wtime @@ -91,14 +87,6 @@ stInitial_ns = (hns - posix_epoch_hns) * 100; } -// return nanoseconds since POSIX epoch. -// algorithm: add current HRT value to the startup system time -static i64 CurrentSystemTime_ns() -{ - const i64 ns = stInitial_ns + i64(whrt_Time() * _1e9); - return ns; -} - static timespec TimespecFromNs(i64 ns) { timespec ts; @@ -115,30 +103,6 @@ return size_t(ms); } - -//----------------------------------------------------------------------------- - -int clock_gettime(clockid_t clock, struct timespec* ts) -{ - ENSURE(clock == CLOCK_REALTIME || clock == CLOCK_MONOTONIC); - - const i64 ns = CurrentSystemTime_ns(); - *ts = TimespecFromNs(ns); - return 0; -} - - -int clock_getres(clockid_t clock, struct timespec* ts) -{ - ENSURE(clock == CLOCK_REALTIME || clock == CLOCK_MONOTONIC); - - const double resolution = whrt_Resolution(); - const i64 ns = i64(resolution * 1e9); - *ts = TimespecFromNs(ns); - return 0; -} - - int nanosleep(const struct timespec* rqtp, struct timespec* /* rmtp */) { const DWORD ms = (DWORD)MsFromTimespec(*rqtp); diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wposix/wtime.h 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wposix/wtime.h --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wposix/wtime.h 2017-11-29 21:16:10.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wposix/wtime.h 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -48,28 +48,7 @@ // // -typedef enum -{ - // in our implementation, these actually do the same thing - // (a timer that latches the system time at startup and uses the - // monotonic HRT to add elapsed time since then) - CLOCK_REALTIME, - CLOCK_MONOTONIC -} -clockid_t; - -// POSIX realtime clock_* -#if _MSC_VER < 1900 -struct timespec -{ - time_t tv_sec; - long tv_nsec; -}; -#endif - extern int nanosleep(const struct timespec* rqtp, struct timespec* rmtp); -extern int clock_gettime(clockid_t clock, struct timespec* ts); -extern int clock_getres(clockid_t clock, struct timespec* res); LIB_API char* strptime(const char* buf, const char* format, struct tm* timeptr); diff -Nru 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wsysdep.cpp 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wsysdep.cpp --- 0ad-0.0.24~r24010/source/lib/sysdep/os/win/wsysdep.cpp 2020-05-05 11:18:00.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/sysdep/os/win/wsysdep.cpp 2020-10-25 21:00:52.000000000 +0000 @@ -182,7 +182,8 @@ static BOOL dlg_OnInitDialog(HWND hDlg, HWND UNUSED(hWndFocus), LPARAM lParam) { - const DialogParams* params = (const DialogParams*)lParam; + const DialogParams* params = reinterpret_cast(lParam); + SetWindowLongPtr(hDlg, DWLP_USER, lParam); HWND hWnd; // need to reset for new instance of dialog @@ -195,6 +196,12 @@ EnableWindow(hWnd, FALSE); } + if(params->flags & DE_NO_CONTINUE) + { + hWnd = GetDlgItem(hDlg, IDC_CONTINUE); + EnableWindow(hWnd, FALSE); + } + // set fixed font for readability hWnd = GetDlgItem(hDlg, IDC_EDIT1); HGDIOBJ hObj = (HGDIOBJ)GetStockObject(SYSTEM_FIXED_FONT); @@ -238,6 +245,19 @@ } +static void dlg_OnClose(HWND hDlg) +{ + const DialogParams* params = reinterpret_cast( + GetWindowLongPtr(hDlg, DWLP_USER)); + if (!params) + return; + + // Interpret close as exit in case we can't continue. + if(params->flags & DE_NO_CONTINUE) + EndDialog(hDlg, ERI_EXIT); +} + + static void dlg_OnSysCommand(HWND hDlg, UINT cmd, int UNUSED(x), int UNUSED(y)) { switch(cmd & 0xFFF0) // NB: lower 4 bits are reserved @@ -275,6 +295,9 @@ case WM_SIZE: return HANDLE_WM_SIZE(hDlg, wParam, lParam, dlg_OnSize); + case WM_CLOSE: + return HANDLE_WM_CLOSE(hDlg, wParam, lParam, dlg_OnClose); + default: // we didn't process the message; caller will perform default action. return FALSE; diff -Nru 0ad-0.0.24~r24010/source/lib/timer.cpp 0ad-0.0.24~r24155/source/lib/timer.cpp --- 0ad-0.0.24~r24010/source/lib/timer.cpp 2019-12-14 22:49:44.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lib/timer.cpp 2020-11-06 23:18:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -39,7 +39,7 @@ #include "lib/sysdep/cpu.h" #if OS_WIN -# include "lib/sysdep/os/win/whrt/whrt.h" +#include "lib/sysdep/os/win/win.h" #endif #if OS_UNIX # include @@ -51,7 +51,7 @@ # define HAVE_GETTIMEOFDAY 0 #endif -#if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) || OS_WIN +#if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) # define HAVE_CLOCK_GETTIME 1 #else # define HAVE_CLOCK_GETTIME 0 @@ -62,7 +62,9 @@ // timer values than their us / ns interface, via double [seconds]. // they're also not guaranteed to be monotonic. -#if HAVE_CLOCK_GETTIME +#if OS_WIN +static LARGE_INTEGER start; +#elif HAVE_CLOCK_GETTIME static struct timespec start; #elif HAVE_GETTIMEOFDAY static struct timeval start; @@ -75,7 +77,7 @@ void timer_LatchStartTime() { #if OS_WIN - // whrt_Time starts at zero, nothing needs to be done. + ENSURE(QueryPerformanceCounter(&start)); #elif HAVE_CLOCK_GETTIME (void)clock_gettime(CLOCK_REALTIME, &start); #elif HAVE_GETTIMEOFDAY @@ -94,13 +96,17 @@ newTime = maxTime; } +// Cached because the default implementation may take several milliseconds. +static double resolution; double timer_Time() { double t; #if OS_WIN - t = whrt_Time(); + LARGE_INTEGER now; + ENSURE(QueryPerformanceCounter(&now)); + t = static_cast(now.QuadPart - start.QuadPart) * resolution; #elif HAVE_CLOCK_GETTIME ENSURE(start.tv_sec || start.tv_nsec); // must have called timer_LatchStartTime first struct timespec cur; @@ -120,13 +126,12 @@ } -// cached because the default implementation may take several milliseconds -static double resolution; - static Status InitResolution() { #if OS_WIN - resolution = whrt_Resolution(); + LARGE_INTEGER frequency; + ENSURE(QueryPerformanceFrequency(&frequency)); + resolution = 1.0 / static_cast(frequency.QuadPart); #elif HAVE_CLOCK_GETTIME struct timespec ts; if(clock_getres(CLOCK_REALTIME, &ts) == 0) diff -Nru 0ad-0.0.24~r24010/source/lobby/XmppClient.cpp 0ad-0.0.24~r24155/source/lobby/XmppClient.cpp --- 0ad-0.0.24~r24010/source/lobby/XmppClient.cpp 2020-06-14 09:49:32.000000000 +0000 +++ 0ad-0.0.24~r24155/source/lobby/XmppClient.cpp 2020-10-31 10:13:33.000000000 +0000 @@ -703,7 +703,7 @@ if ((m_isConnected && !m_initialLoadComplete) || m_GuiMessageQueue.empty()) return JS::UndefinedValue(); - JSContext* cx = scriptInterface.GetContext(); + JSContext* cx = m_ScriptInterface->GetContext(); JSAutoRequest rq(cx); // Optimize for batch message processing that is more @@ -715,34 +715,35 @@ for (const JS::Heap& message : m_GuiMessageQueue) { - scriptInterface.SetPropertyInt(messages, j++, message); + m_ScriptInterface->SetPropertyInt(messages, j++, message); // Store historic chat messages. // Only store relevant messages to minimize memory footprint. JS::RootedValue rootedMessage(cx, message); std::string type; - scriptInterface.GetProperty(rootedMessage, "type", type); + m_ScriptInterface->GetProperty(rootedMessage, "type", type); if (type != "chat") continue; std::string level; - scriptInterface.GetProperty(rootedMessage, "level", level); + m_ScriptInterface->GetProperty(rootedMessage, "level", level); if (level != "room-message" && level != "private-message") continue; JS::RootedValue historicMessage(cx); if (JS_StructuredClone(cx, rootedMessage, &historicMessage, nullptr, nullptr)) { - scriptInterface.SetProperty(historicMessage, "historic", true); - scriptInterface.FreezeObject(historicMessage, true); + m_ScriptInterface->SetProperty(historicMessage, "historic", true); + m_ScriptInterface->FreezeObject(historicMessage, true); m_HistoricGuiMessages.push_back(JS::Heap(historicMessage)); } else LOGERROR("Could not clone historic lobby GUI message!"); } - m_GuiMessageQueue.clear(); - return messages; + + // Copy the messages over to the caller script interface. + return scriptInterface.CloneValueFromOtherContext(*m_ScriptInterface, messages); } JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface) @@ -750,7 +751,7 @@ if (m_HistoricGuiMessages.empty()) return JS::UndefinedValue(); - JSContext* cx = scriptInterface.GetContext(); + JSContext* cx = m_ScriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedValue messages(cx); @@ -758,9 +759,10 @@ int j = 0; for (const JS::Heap& message : m_HistoricGuiMessages) - scriptInterface.SetPropertyInt(messages, j++, message); + m_ScriptInterface->SetPropertyInt(messages, j++, message); - return messages; + // Copy the messages over to the caller script interface. + return scriptInterface.CloneValueFromOtherContext(*m_ScriptInterface, messages); } /** diff -Nru 0ad-0.0.24~r24010/source/maths/FixedVector2D.h 0ad-0.0.24~r24155/source/maths/FixedVector2D.h --- 0ad-0.0.24~r24010/source/maths/FixedVector2D.h 2020-02-09 21:00:43.000000000 +0000 +++ 0ad-0.0.24~r24155/source/maths/FixedVector2D.h 2020-11-09 13:25:50.000000000 +0000 @@ -204,6 +204,7 @@ /** * Compute the dot product of this vector with another. + * Likely to overflow if both vectors are large-ish (around the 200 range). */ fixed Dot(const CFixedVector2D& v) const { @@ -219,6 +220,16 @@ return ret; } + /** + * @return -1, 0 or 1 if this and @v face respectively opposite directions, perpendicular, or same directions. + */ + int RelativeOrientation(const CFixedVector2D& v) const + { + i64 x = MUL_I64_I32_I32(X.GetInternalValue(), v.X.GetInternalValue()); + i64 y = MUL_I64_I32_I32(Y.GetInternalValue(), v.Y.GetInternalValue()); + return x > -y ? 1 : x < -y ? -1 : 0; + } + CFixedVector2D Perpendicular() const { return CFixedVector2D(Y, -X); diff -Nru 0ad-0.0.24~r24010/source/ps/ArchiveBuilder.cpp 0ad-0.0.24~r24155/source/ps/ArchiveBuilder.cpp --- 0ad-0.0.24~r24010/source/ps/ArchiveBuilder.cpp 2019-01-07 23:57:18.000000000 +0000 +++ 0ad-0.0.24~r24155/source/ps/ArchiveBuilder.cpp 2020-10-04 10:17:34.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -68,6 +68,11 @@ const bool noDeflate = !compress; PIArchiveWriter writer = CreateArchiveWriter_Zip(archive, noDeflate); + if (!writer) + { + debug_printf("Failed to create the archive \"%s\".", archive.string8().c_str()); + return; + } // Use CTextureManager instead of CTextureConverter directly, // so it can deal with all the loading of settings.xml files @@ -95,7 +100,7 @@ ) { VfsPath cachedPath; - debug_printf("Converting texture %s\n", realPath.string8().c_str()); + debug_printf("Converting texture \"%s\"\n", realPath.string8().c_str()); bool ok = textureManager.GenerateCachedTexture(path, cachedPath); ENSURE(ok); @@ -154,7 +159,7 @@ if (path.Extension() == L".xml") { VfsPath cachedPath; - debug_printf("Converting XML file %s\n", realPath.string8().c_str()); + debug_printf("Converting XML file \"%s\"\n", realPath.string8().c_str()); bool ok = xero.GenerateCachedXMB(m_VFS, path, cachedPath); ENSURE(ok); diff -Nru 0ad-0.0.24~r24010/source/ps/CStrInternStatic.h 0ad-0.0.24~r24155/source/ps/CStrInternStatic.h --- 0ad-0.0.24~r24010/source/ps/CStrInternStatic.h 2020-08-07 22:16:55.000000000 +0000 +++ 0ad-0.0.24~r24155/source/ps/CStrInternStatic.h 2020-11-09 18:50:40.000000000 +0000 @@ -41,6 +41,7 @@ X(MINIMAP_BASE) X(MINIMAP_LINE) X(MINIMAP_LOS) +X(MINIMAP_MASK) X(MINIMAP_POINT) X(MODE_SHADOWCAST) X(MODE_SILHOUETTEDISPLAY) @@ -86,6 +87,7 @@ X(color) X(colorAdd) X(colorMul) +X(debug_overlay) X(delta) X(depthTex) X(foamTex) @@ -101,7 +103,6 @@ X(hdr) X(height) X(instancingTransform) -X(losMap) X(losMatrix) X(losTex) X(losTex1) @@ -110,6 +111,7 @@ X(los_interp) X(mapSize) X(maskTex) +X(maskTextureTransform) X(minimap) X(modelViewMatrix) X(murkiness) @@ -150,8 +152,8 @@ X(tint) X(transform) X(translation) -X(waterEffectsTexNorm) -X(waterEffectsTexOther) +X(water_simple) +X(waterEffectsTex) X(waterTex) X(waveTex) X(waviness) diff -Nru 0ad-0.0.24~r24010/source/ps/GameSetup/GameSetup.cpp 0ad-0.0.24~r24155/source/ps/GameSetup/GameSetup.cpp --- 0ad-0.0.24~r24010/source/ps/GameSetup/GameSetup.cpp 2020-06-07 13:16:57.000000000 +0000 +++ 0ad-0.0.24~r24155/source/ps/GameSetup/GameSetup.cpp 2020-10-25 21:00:52.000000000 +0000 @@ -999,16 +999,20 @@ g_GUI = new CGUIManager(); // (must come after SetVideoMode, since it calls ogl_Init) - if (ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", NULL) != 0 // ARB + CStr8 renderPath = "default"; + CFG_GET_VAL("renderpath", renderPath); + if ((ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", NULL) != 0 // ARB && ogl_HaveExtensions(0, "GL_ARB_vertex_shader", "GL_ARB_fragment_shader", NULL) != 0) // GLSL + || RenderPathEnum::FromString(renderPath) == FIXED) { - DEBUG_DISPLAY_ERROR( + // It doesn't make sense to continue working here, because we're not + // able to display anything. + DEBUG_DISPLAY_FATAL_ERROR( L"Your graphics card doesn't appear to be fully compatible with OpenGL shaders." - L" In the future, the game will not support pre-shader graphics cards." + L" The game does not support pre-shader graphics cards." L" You are advised to try installing newer drivers and/or upgrade your graphics card." L" For more information, please see http://www.wildfiregames.com/forum/index.php?showtopic=16734" ); - // TODO: actually quit once fixed function support is dropped } const char* missing = ogl_HaveExtensions(0, @@ -1172,7 +1176,7 @@ * -autostart-nonvisual disable any graphics and sounds * -autostart-victory=SCRIPTNAME sets the victory conditions with SCRIPTNAME * located in simulation/data/settings/victory_conditions/ - * (default conquest). When the first given SCRIPTNAME is + * (default conquest). When the first given SCRIPTNAME is * "endless", no victory conditions will apply. * -autostart-wonderduration=NUM sets the victory duration NUM for wonder victory condition * (default 10 minutes) diff -Nru 0ad-0.0.24~r24010/source/ps/GameSetup/HWDetect.cpp 0ad-0.0.24~r24155/source/ps/GameSetup/HWDetect.cpp --- 0ad-0.0.24~r24010/source/ps/GameSetup/HWDetect.cpp 2020-08-03 12:23:16.000000000 +0000 +++ 0ad-0.0.24~r24155/source/ps/GameSetup/HWDetect.cpp 2020-10-02 07:35:59.000000000 +0000 @@ -20,7 +20,9 @@ #include "scriptinterface/ScriptInterface.h" #include "lib/ogl.h" +#if CONFIG2_AUDIO #include "lib/snd.h" +#endif #include "lib/svn_revision.h" #include "lib/timer.h" #include "lib/utf8.h" @@ -199,10 +201,10 @@ scriptInterface.SetProperty(settings, "gfx_card", gfx::CardName()); scriptInterface.SetProperty(settings, "gfx_drv_ver", gfx::DriverInfo()); - +#if CONFIG2_AUDIO scriptInterface.SetProperty(settings, "snd_card", snd_card); scriptInterface.SetProperty(settings, "snd_drv_ver", snd_drv_ver); - +#endif ReportSDL(scriptInterface, settings); ReportGLLimits(scriptInterface, settings); diff -Nru 0ad-0.0.24~r24010/source/ps/Util.cpp 0ad-0.0.24~r24155/source/ps/Util.cpp --- 0ad-0.0.24~r24010/source/ps/Util.cpp 2020-01-02 18:07:40.000000000 +0000 +++ 0ad-0.0.24~r24155/source/ps/Util.cpp 2020-10-02 07:35:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,7 +21,9 @@ #include "lib/posix/posix_utsname.h" #include "lib/ogl.h" +#if CONFIG2_AUDIO #include "lib/snd.h" +#endif #include "lib/timer.h" #include "lib/bits.h" // round_up #include "lib/allocators/shared_ptr.h" @@ -80,10 +82,6 @@ void WriteSystemInfo() { TIMER(L"write_sys_info"); - - // get_cpu_info and gfx_detect already called during init - see call site - snd_detect(); - struct utsname un; uname(&un); @@ -137,9 +135,13 @@ fprintf(f, "OpenGL Drivers : %s; %ls\n", glGetString(GL_VERSION), driverInfo.c_str()); fprintf(f, "Video Mode : %dx%d:%d\n", g_VideoMode.GetXRes(), g_VideoMode.GetYRes(), g_VideoMode.GetBPP()); - // sound +#if CONFIG2_AUDIO + snd_detect(); fprintf(f, "Sound Card : %s\n", snd_card.c_str()); fprintf(f, "Sound Drivers : %s\n", snd_drv_ver.c_str()); +#else + fprintf(f, "Sound : Game was compiled without audio\n"); +#endif // OpenGL extensions (write them last, since it's a lot of text) const char* exts = ogl_ExtensionString(); diff -Nru 0ad-0.0.24~r24010/source/renderer/DecalRData.cpp 0ad-0.0.24~r24155/source/renderer/DecalRData.cpp --- 0ad-0.0.24~r24010/source/renderer/DecalRData.cpp 2019-08-04 08:28:30.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/DecalRData.cpp 2020-11-04 12:54:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ #include "DecalRData.h" #include "graphics/Decal.h" -#include "graphics/LightEnv.h" #include "graphics/Model.h" #include "graphics/ShaderManager.h" #include "graphics/Terrain.h" @@ -49,10 +48,6 @@ m_Normal.elems = 3; m_Array.AddAttribute(&m_Normal); - m_DiffuseColor.type = GL_UNSIGNED_BYTE; - m_DiffuseColor.elems = 4; - m_Array.AddAttribute(&m_DiffuseColor); - m_UV.type = GL_FLOAT; m_UV.elems = 2; m_Array.AddAttribute(&m_UV); @@ -166,7 +161,6 @@ shader->VertexPointer(3, GL_FLOAT, stride, base + decal->m_Position.offset); shader->NormalPointer(GL_FLOAT, stride, base + decal->m_Normal.offset); - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + decal->m_DiffuseColor.offset); shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + decal->m_UV.offset); shader->AssertPointersBound(); @@ -213,12 +207,8 @@ m_Array.Layout(); VertexArrayIterator Position = m_Position.GetIterator(); VertexArrayIterator Normal = m_Normal.GetIterator(); - VertexArrayIterator DiffuseColor = m_DiffuseColor.GetIterator(); VertexArrayIterator UV = m_UV.GetIterator(); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); - bool cpuLighting = (g_RenderingOptions.GetRenderPath() == RenderPath::FIXED); - for (ssize_t j = j0; j <= j1; ++j) { for (ssize_t i = i0; i <= i1; ++i) @@ -237,9 +227,6 @@ *Normal = normal; Normal++; - *DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); - ++DiffuseColor; - // Map from world space back into decal texture space CVector3D inv = m_Decal->GetInvTransform().Transform(pos); (*UV)[0] = 0.5f + (inv.X - decal.m_OffsetX) / decal.m_SizeX; diff -Nru 0ad-0.0.24~r24010/source/renderer/DecalRData.h 0ad-0.0.24~r24155/source/renderer/DecalRData.h --- 0ad-0.0.24~r24010/source/renderer/DecalRData.h 2016-11-23 11:18:37.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/DecalRData.h 2020-11-04 12:54:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -49,7 +49,6 @@ VertexArray m_Array; VertexArray::Attribute m_Position; VertexArray::Attribute m_Normal; - VertexArray::Attribute m_DiffuseColor; VertexArray::Attribute m_UV; CModelDecal* m_Decal; diff -Nru 0ad-0.0.24~r24010/source/renderer/OverlayRenderer.cpp 0ad-0.0.24~r24155/source/renderer/OverlayRenderer.cpp --- 0ad-0.0.24~r24010/source/renderer/OverlayRenderer.cpp 2020-06-12 15:39:44.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/OverlayRenderer.cpp 2020-11-08 14:47:25.000000000 +0000 @@ -219,8 +219,6 @@ if (line->m_Coords.empty()) return; - ENSURE(line->m_Coords.size() % 2 == 0); - m->texlines.push_back(line); } @@ -367,6 +365,9 @@ #if CONFIG2_GLES #warning TODO: implement OverlayRenderer::RenderOverlaysBeforeWater for GLES #else + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); @@ -395,6 +396,9 @@ glLineWidth(1.f); glDepthFunc(GL_LEQUAL); glDisable(GL_BLEND); + + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } @@ -483,6 +487,10 @@ void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible) { +#if !CONFIG2_GLES + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +#endif for (size_t i = 0; i < m->texlines.size(); ++i) { SOverlayTexturedLine* line = m->texlines[i]; @@ -494,6 +502,10 @@ ENSURE(line->m_RenderData); line->m_RenderData->Render(*line, shader); } +#if !CONFIG2_GLES + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif } void OverlayRenderer::RenderQuadOverlays() @@ -522,6 +534,11 @@ if (!shader) return; +#if !CONFIG2_GLES + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +#endif + pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); @@ -584,6 +601,11 @@ glDepthMask(1); glDisable(GL_BLEND); + +#if !CONFIG2_GLES + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif } void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) @@ -593,6 +615,9 @@ #if CONFIG2_GLES #warning TODO: implement OverlayRenderer::RenderForegroundOverlays for GLES #else + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); @@ -662,6 +687,9 @@ glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); + + if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } diff -Nru 0ad-0.0.24~r24010/source/renderer/PatchRData.cpp 0ad-0.0.24~r24155/source/renderer/PatchRData.cpp --- 0ad-0.0.24~r24010/source/renderer/PatchRData.cpp 2019-10-03 12:58:47.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/PatchRData.cpp 2020-11-08 11:31:32.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -367,17 +367,13 @@ SBlendVertex dst; - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); CVector3D normal; - bool cpuLighting = (g_RenderingOptions.GetRenderPath() == RenderPath::FIXED); - size_t index = blendVertices.size(); terrain->CalcPosition(gx, gz, dst.m_Position); terrain->CalcNormal(gx, gz, normal); dst.m_Normal = normal; - dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1]; blendVertices.push_back(dst); @@ -385,7 +381,6 @@ terrain->CalcPosition(gx + 1, gz, dst.m_Position); terrain->CalcNormal(gx + 1, gz, normal); dst.m_Normal = normal; - dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1]; blendVertices.push_back(dst); @@ -393,7 +388,6 @@ terrain->CalcPosition(gx + 1, gz + 1, dst.m_Position); terrain->CalcNormal(gx + 1, gz + 1, normal); dst.m_Normal = normal; - dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1]; blendVertices.push_back(dst); @@ -401,7 +395,6 @@ terrain->CalcPosition(gx, gz + 1, dst.m_Position); terrain->CalcNormal(gx, gz + 1, normal); dst.m_Normal = normal; - dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1]; blendVertices.push_back(dst); @@ -533,39 +526,32 @@ // create both vertices and lighting colors // number of vertices in each direction in each patch - ssize_t vsize=PATCH_SIZE+1; + ssize_t vsize = PATCH_SIZE + 1; std::vector vertices; - vertices.resize(vsize*vsize); + vertices.resize(vsize * vsize); // get index of this patch - ssize_t px=m_Patch->m_X; - ssize_t pz=m_Patch->m_Z; + ssize_t px = m_Patch->m_X; + ssize_t pz = m_Patch->m_Z; - CTerrain* terrain=m_Patch->m_Parent; - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); - - bool cpuLighting = (g_RenderingOptions.GetRenderPath() == RenderPath::FIXED); + CTerrain* terrain = m_Patch->m_Parent; // build vertices - for (ssize_t j=0;jCalcPosition(ix,iz,vertices[v].m_Position); + terrain->CalcPosition(ix, iz, vertices[v].m_Position); - // Calculate diffuse lighting for this vertex - // Ambient is added by the lighting pass (since ambient is the same - // for all vertices, it need not be stored in the vertex structure) CVector3D normal; - terrain->CalcNormal(ix,iz,normal); - + terrain->CalcNormal(ix, iz, normal); vertices[v].m_Normal = normal; - - vertices[v].m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); } } @@ -828,7 +814,6 @@ GLsizei stride = sizeof(SBaseVertex); SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); @@ -1067,7 +1052,6 @@ SBlendVertex *base = (SBlendVertex *)itv->first->Bind(); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &base->m_AlphaUVs[0]); @@ -1143,7 +1127,7 @@ PROFILE_END("compute batches"); - ENSURE(!(streamflags & ~(STREAM_POS|STREAM_COLOR|STREAM_POSTOUV0|STREAM_POSTOUV1))); + ENSURE(!(streamflags & ~(STREAM_POS|STREAM_POSTOUV0|STREAM_POSTOUV1))); // Render each batch for (VertexBufferBatches::iterator itv = batches.begin(); itv != batches.end(); ++itv) @@ -1156,8 +1140,6 @@ shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position); if (streamflags & STREAM_POSTOUV1) shader->TexCoordPointer(GL_TEXTURE1, 3, GL_FLOAT, stride, &base->m_Position); - if (streamflags & STREAM_COLOR) - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); shader->AssertPointersBound(); @@ -1189,25 +1171,22 @@ CVector3D pos; std::vector line; - - ssize_t i, j; - - for (i = 0, j = 0; i <= PATCH_SIZE; ++i) + for (ssize_t i = 0, j = 0; i <= PATCH_SIZE; ++i) { terrain->CalcPosition(gx + i, gz + j, pos); line.push_back(pos); } - for (i = PATCH_SIZE, j = 1; j <= PATCH_SIZE; ++j) + for (ssize_t i = PATCH_SIZE, j = 1; j <= PATCH_SIZE; ++j) { terrain->CalcPosition(gx + i, gz + j, pos); line.push_back(pos); } - for (i = PATCH_SIZE-1, j = PATCH_SIZE; i >= 0; --i) + for (ssize_t i = PATCH_SIZE-1, j = PATCH_SIZE; i >= 0; --i) { terrain->CalcPosition(gx + i, gz + j, pos); line.push_back(pos); } - for (i = 0, j = PATCH_SIZE-1; j >= 0; --j) + for (ssize_t i = 0, j = PATCH_SIZE-1; j >= 0; --j) { terrain->CalcPosition(gx + i, gz + j, pos); line.push_back(pos); @@ -1488,7 +1467,7 @@ return; #if !CONFIG2_GLES - if (g_Renderer.m_WaterRenderMode == WIREFRAME) + if (g_Renderer.GetWaterRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif @@ -1536,7 +1515,7 @@ CVertexBuffer::Unbind(); #if !CONFIG2_GLES - if (g_Renderer.m_WaterRenderMode == WIREFRAME) + if (g_Renderer.GetWaterRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } diff -Nru 0ad-0.0.24~r24010/source/renderer/PatchRData.h 0ad-0.0.24~r24155/source/renderer/PatchRData.h --- 0ad-0.0.24~r24010/source/renderer/PatchRData.h 2019-06-12 20:03:22.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/PatchRData.h 2020-11-04 15:53:33.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,12 +18,12 @@ #ifndef INCLUDED_PATCHRDATA #define INCLUDED_PATCHRDATA -#include "graphics/SColor.h" -#include "maths/Vector2D.h" -#include "maths/Vector3D.h" #include "graphics/Patch.h" #include "graphics/RenderableObject.h" +#include "graphics/SColor.h" #include "graphics/ShaderProgramPtr.h" +#include "maths/Vector2D.h" +#include "maths/Vector3D.h" #include "renderer/VertexBufferManager.h" #include @@ -80,11 +80,9 @@ struct SBaseVertex { // vertex position CVector3D m_Position; - // diffuse color from sunlight - SColor4ub m_DiffuseColor; CVector3D m_Normal; // pad to a power of two - u8 m_Padding[4]; + u8 m_Padding[8]; }; cassert(sizeof(SBaseVertex) == 32); @@ -99,15 +97,11 @@ struct SBlendVertex { // vertex position CVector3D m_Position; - // diffuse color from sunlight - SColor4ub m_DiffuseColor; // vertex uvs for alpha texture float m_AlphaUVs[2]; CVector3D m_Normal; - // pad to a power of two - u8 m_Padding[28]; }; - cassert(sizeof(SBlendVertex) == 64); + cassert(sizeof(SBlendVertex) == 32); // Mixed Fancy/Simple water vertex description data structure struct SWaterVertex { diff -Nru 0ad-0.0.24~r24010/source/renderer/Renderer.cpp 0ad-0.0.24~r24155/source/renderer/Renderer.cpp --- 0ad-0.0.24~r24010/source/renderer/Renderer.cpp 2020-02-05 14:00:52.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/Renderer.cpp 2020-11-08 11:31:32.000000000 +0000 @@ -422,6 +422,7 @@ m_TerrainRenderMode = SOLID; m_WaterRenderMode = SOLID; m_ModelRenderMode = SOLID; + m_OverlayRenderMode = SOLID; m_ClearColor[0] = m_ClearColor[1] = m_ClearColor[2] = m_ClearColor[3] = 0; m_DisplayTerrainPriorities = false; @@ -787,11 +788,10 @@ // setup some renderstate .. pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); - glColor3f(0.5f, 0.5f, 1.0f); glLineWidth(2.0f); // render tiles edges - m->terrainRenderer.RenderPatches(cullGroup); + m->terrainRenderer.RenderPatches(cullGroup, CColor(0.5f, 0.5f, 1.0f, 1.0f)); // set color for outline glColor3f(0, 0, 1); @@ -1700,9 +1700,10 @@ scene.EnumerateObjects(refractionCamera.GetFrustum(), this); } + + // Render the waves to the Fancy effects texture + m_WaterManager->RenderWaves(frustum); } - // Render the waves to the Fancy effects texture - m_WaterManager->RenderWaves(frustum); } m_CurrentCullGroup = -1; diff -Nru 0ad-0.0.24~r24010/source/renderer/Renderer.h 0ad-0.0.24~r24155/source/renderer/Renderer.h --- 0ad-0.0.24~r24010/source/renderer/Renderer.h 2020-01-29 22:03:44.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/Renderer.h 2020-11-08 11:31:32.000000000 +0000 @@ -211,6 +211,11 @@ // get the mode to render subsequent models ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; } + // Get the mode to render subsequent overlays. + ERenderMode GetOverlayRenderMode() const { return m_OverlayRenderMode; } + // Set the mode to render subsequent overlays. + void SetOverlayRenderMode(ERenderMode mode) { m_OverlayRenderMode = mode; } + // debugging void SetDisplayTerrainPriorities(bool enabled) { m_DisplayTerrainPriorities = enabled; } @@ -358,12 +363,15 @@ int m_Width; // view height int m_Height; - // current terrain rendering mode + + // Current terrain rendering mode. ERenderMode m_TerrainRenderMode; - // current water rendering mode + // Current water rendering mode. ERenderMode m_WaterRenderMode; - // current model rendering mode + // Current model rendering mode. ERenderMode m_ModelRenderMode; + // Current overlay rendering mode. + ERenderMode m_OverlayRenderMode; CShaderDefines m_SystemShaderDefines; diff -Nru 0ad-0.0.24~r24010/source/renderer/RenderingOptions.cpp 0ad-0.0.24~r24155/source/renderer/RenderingOptions.cpp --- 0ad-0.0.24~r24010/source/renderer/RenderingOptions.cpp 2020-06-07 13:16:57.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/RenderingOptions.cpp 2020-10-13 16:48:04.000000000 +0000 @@ -112,6 +112,12 @@ CFG_GET_VAL("gpuskinning", m_GPUSkinning); CFG_GET_VAL("renderactors", m_RenderActors); + + if (m_GPUSkinning && !m_PreferGLSL) + { + LOGWARNING("GPUSkinning have been disabled, because it is not supported with PreferGLSL disabled."); + m_GPUSkinning = false; + } } void SRenderingOptions::SetShadows(bool value) @@ -134,6 +140,14 @@ void SRenderingOptions::SetPreferGLSL(bool value) { + if (m_GPUSkinning && !value) + { + LOGWARNING("GPUSkinning have been disabled, because it is not supported with PreferGLSL disabled."); + m_GPUSkinning = false; + } + else if (!m_GPUSkinning && value) + CFG_GET_VAL("gpuskinning", m_GPUSkinning); + m_PreferGLSL = value; g_Renderer.MakeShadersDirty(); g_Renderer.RecomputeSystemShaderDefines(); diff -Nru 0ad-0.0.24~r24010/source/renderer/TerrainOverlay.cpp 0ad-0.0.24~r24155/source/renderer/TerrainOverlay.cpp --- 0ad-0.0.24~r24010/source/renderer/TerrainOverlay.cpp 2020-06-12 20:52:18.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/TerrainOverlay.cpp 2020-11-09 18:50:40.000000000 +0000 @@ -309,7 +309,7 @@ matrix._23 = m_TexelsPerTile / (m_TextureH * TERRAIN_TILE_SIZE); matrix._44 = 1; - g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(cullGroup, matrix); + g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(cullGroup, matrix, m_Texture); } SColor4ub TerrainTextureOverlay::GetColor(size_t idx, u8 alpha) const diff -Nru 0ad-0.0.24~r24010/source/renderer/TerrainRenderer.cpp 0ad-0.0.24~r24155/source/renderer/TerrainRenderer.cpp --- 0ad-0.0.24~r24010/source/renderer/TerrainRenderer.cpp 2020-02-04 23:16:30.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/TerrainRenderer.cpp 2020-11-09 18:50:40.000000000 +0000 @@ -59,6 +59,25 @@ /////////////////////////////////////////////////////////////////////////////////////////////// // TerrainRenderer implementation +namespace +{ + +CShaderProgramPtr GetDummyShader() +{ + const char* shaderName; + if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER) + { + if (g_RenderingOptions.GetPreferGLSL()) + shaderName = "glsl/dummy"; + else + shaderName = "arb/dummy"; + } + else + shaderName = "fixed:dummy"; + return g_Renderer.GetShaderManager().LoadProgram(shaderName, CShaderDefines()); +} + +} // anonymous namespace /** * TerrainRenderer keeps track of which phase it is in, to detect @@ -185,8 +204,10 @@ if (visiblePatches.empty() && visibleDecals.empty()) return; - CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); + CShaderProgramPtr dummyShader = GetDummyShader(); dummyShader->Bind(); + dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + dummyShader->Uniform(str_color, CColor(0.0f, 0.0f, 0.0f, 1.0f)); // render the solid black sides of the map first g_Renderer.BindTexture(0, 0); @@ -301,7 +322,7 @@ CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture(); - int streamflags = STREAM_POS|STREAM_COLOR; + int streamflags = STREAM_POS; pglActiveTextureARB(GL_TEXTURE0); // We're not going to use a texture here, but we have to have a valid texture @@ -376,70 +397,66 @@ #endif } -void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix) +void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix, GLuint texture) { #if CONFIG2_GLES #warning TODO: implement TerrainRenderer::RenderTerrainOverlayTexture for GLES UNUSED2(cullGroup); UNUSED2(textureMatrix); + UNUSED2(texture); #else ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(0); glDisable(GL_DEPTH_TEST); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + CShaderTechniquePtr debugOverlayTech = + g_Renderer.GetShaderManager().LoadEffect(str_debug_overlay); + debugOverlayTech->BeginPass(); + CShaderProgramPtr debugOverlayShader = debugOverlayTech->GetShader(); + + debugOverlayShader->Bind(); + debugOverlayShader->BindTexture(str_baseTex, texture); + debugOverlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + debugOverlayShader->Uniform(str_textureTransform, textureMatrix); + CPatchRData::RenderStreams(visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0); - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(&textureMatrix._11); - glMatrixMode(GL_MODELVIEW); - - CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); - dummyShader->Bind(); - CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS|STREAM_POSTOUV0); - dummyShader->Unbind(); + glEnable(GL_DEPTH_TEST); // To make the overlay visible over water, render an additional map-sized - // water-height patch + // water-height patch. CBoundingBoxAligned waterBounds; - for (size_t i = 0; i < visiblePatches.size(); ++i) - { - CPatchRData* data = visiblePatches[i]; + for (CPatchRData* data : visiblePatches) waterBounds += data->GetWaterBounds(); - } if (!waterBounds.IsEmpty()) { - float h = g_Renderer.GetWaterManager()->m_WaterHeight + 0.05f; // add a delta to avoid z-fighting - float waterPos[] = { - waterBounds[0].X, h, waterBounds[0].Z, - waterBounds[1].X, h, waterBounds[0].Z, - waterBounds[0].X, h, waterBounds[1].Z, - waterBounds[1].X, h, waterBounds[1].Z + // Add a delta to avoid z-fighting. + const float height = g_Renderer.GetWaterManager()->m_WaterHeight + 0.05f; + const float waterPos[] = { + waterBounds[0].X, height, waterBounds[0].Z, + waterBounds[1].X, height, waterBounds[0].Z, + waterBounds[0].X, height, waterBounds[1].Z, + waterBounds[1].X, height, waterBounds[1].Z }; - glVertexPointer(3, GL_FLOAT, 3*sizeof(float), waterPos); - glTexCoordPointer(3, GL_FLOAT, 3*sizeof(float), waterPos); + + const GLsizei stride = sizeof(float) * 3; + debugOverlayShader->VertexPointer(3, GL_FLOAT, stride, waterPos); + debugOverlayShader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, waterPos); + debugOverlayShader->AssertPointersBound(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); + debugOverlayShader->Unbind(); + debugOverlayTech->EndPass(); glDepthMask(1); - glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif } @@ -529,7 +546,7 @@ /////////////////////////////////////////////////////////////////// // Render un-textured patches as polygons -void TerrainRenderer::RenderPatches(int cullGroup) +void TerrainRenderer::RenderPatches(int cullGroup, const CColor& color) { ENSURE(m->phase == Phase_Render); @@ -540,8 +557,10 @@ #if CONFIG2_GLES #warning TODO: implement TerrainRenderer::RenderPatches for GLES #else - CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); + CShaderProgramPtr dummyShader = GetDummyShader(); dummyShader->Bind(); + dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + dummyShader->Uniform(str_color, color); glEnableClientState(GL_VERTEX_ARRAY); CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS); @@ -747,8 +766,7 @@ if (WaterMgr->m_WaterFancyEffects) { - m->fancyWaterShader->BindTexture(str_waterEffectsTexNorm, WaterMgr->m_FancyTextureNormal); - m->fancyWaterShader->BindTexture(str_waterEffectsTexOther, WaterMgr->m_FancyTextureOther); + m->fancyWaterShader->BindTexture(str_waterEffectsTex, WaterMgr->m_FancyTexture); } if (WaterMgr->m_WaterRealDepth) @@ -758,7 +776,7 @@ m->fancyWaterShader->BindTexture(str_refractionMap, WaterMgr->m_RefractionTexture); if (WaterMgr->m_WaterReflection) m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture); - m->fancyWaterShader->BindTexture(str_losMap, losTexture.GetTextureSmooth()); + m->fancyWaterShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); @@ -779,6 +797,7 @@ if (WaterMgr->m_WaterReflection) m->fancyWaterShader->Uniform(str_reflectionMatrix, WaterMgr->m_ReflectionMatrix); } + m->fancyWaterShader->Uniform(str_ambient, lightEnv.m_TerrainAmbientColor); m->fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir()); m->fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor); m->fancyWaterShader->Uniform(str_color, WaterMgr->m_WaterColor); @@ -857,55 +876,18 @@ double period = 1.6f; int curTex = (int)(time*60/period) % 60; - WaterMgr->m_WaterTexture[curTex]->Bind(); - - // Shift the texture coordinates by these amounts to make the water "flow" - float tx = -fmod(time, 81.0)/81.0; - float ty = -fmod(time, 34.0)/34.0; - float repeatPeriod = 16.0f; - - // Perform the shifting by using texture coordinate generation - GLfloat texgenS0[4] = { 1/repeatPeriod, 0, 0, tx }; - GLfloat texgenT0[4] = { 0, 0, 1/repeatPeriod, ty }; - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS0); - glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT0); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - - // Set up texture environment to multiply vertex RGB by texture RGB. - GLfloat waterColor[4] = { WaterMgr->m_WaterColor.r, WaterMgr->m_WaterColor.g, WaterMgr->m_WaterColor.b, 1.0f }; - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, waterColor); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); - - - // Multiply by LOS texture - losTexture.BindTexture(1); - CMatrix3D losMatrix = losTexture.GetTextureMatrix(); - GLfloat texgenS1[4] = { losMatrix[0], losMatrix[4], losMatrix[8], losMatrix[12] }; - GLfloat texgenT1[4] = { losMatrix[1], losMatrix[5], losMatrix[9], losMatrix[13] }; - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1); - glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA); - - CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); - dummyShader->Bind(); + CShaderTechniquePtr waterSimpleTech = + g_Renderer.GetShaderManager().LoadEffect(str_water_simple); + waterSimpleTech->BeginPass(); + CShaderProgramPtr waterSimpleShader = waterSimpleTech->GetShader(); + + waterSimpleShader->Bind(); + waterSimpleShader->BindTexture(str_baseTex, WaterMgr->m_WaterTexture[curTex]); + waterSimpleShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); + waterSimpleShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + waterSimpleShader->Uniform(str_losMatrix, losTexture.GetTextureMatrix()); + waterSimpleShader->Uniform(str_time, static_cast(time)); + waterSimpleShader->Uniform(str_color, WaterMgr->m_WaterColor); glEnableClientState(GL_VERTEX_ARRAY); @@ -913,27 +895,18 @@ for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; - data->RenderWater(dummyShader, false, true); + data->RenderWater(waterSimpleShader, false, true); } glDisableClientState(GL_VERTEX_ARRAY); - dummyShader->Unbind(); - + waterSimpleShader->Unbind(); g_Renderer.BindTexture(1, 0); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - pglActiveTextureARB(GL_TEXTURE0_ARB); - - // Clean up the texture matrix and blend mode - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glDisable(GL_TEXTURE_2D); + + waterSimpleTech->EndPass(); #endif } diff -Nru 0ad-0.0.24~r24010/source/renderer/TerrainRenderer.h 0ad-0.0.24~r24155/source/renderer/TerrainRenderer.h --- 0ad-0.0.24~r24010/source/renderer/TerrainRenderer.h 2020-02-04 23:16:30.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/TerrainRenderer.h 2020-11-09 18:50:40.000000000 +0000 @@ -23,6 +23,8 @@ #ifndef INCLUDED_TERRAINRENDERER #define INCLUDED_TERRAINRENDERER +#include "maths/BoundingBoxAligned.h" + class CPatch; class CSimulation2; class ShadowMap; @@ -105,8 +107,9 @@ * frame before calling RenderPatches. * * @param filtered If true then only render objects that passed CullPatches. + * @param color Fill color of the patches. */ - void RenderPatches(int cullGroup); + void RenderPatches(int cullGroup, const CColor& color = CColor(0.0f, 0.0f, 0.0f, 1.0f)); /** * RenderOutlines: Render the outline of patches as lines. @@ -142,7 +145,7 @@ * by the given texture matrix. * Intended for use by TerrainTextureOverlay. */ - void RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix); + void RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix, GLuint texture); private: TerrainRendererInternals* m; diff -Nru 0ad-0.0.24~r24010/source/renderer/TexturedLineRData.cpp 0ad-0.0.24~r24155/source/renderer/TexturedLineRData.cpp --- 0ad-0.0.24~r24010/source/renderer/TexturedLineRData.cpp 2019-12-10 23:13:37.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/TexturedLineRData.cpp 2020-11-08 14:47:25.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -90,7 +90,7 @@ std::vector vertices; std::vector indices; - size_t n = line.m_Coords.size() / 2; // number of line points + const size_t n = line.m_Coords.size(); // number of line points bool closed = line.m_Closed; ENSURE(n >= 2); // minimum needed to avoid errors (also minimum value to make sense, can't draw a line between 1 point) @@ -100,12 +100,12 @@ // recompute p2 at the end of each iteration. CVector3D p0; - CVector3D p1(line.m_Coords[0], 0, line.m_Coords[1]); - CVector3D p2(line.m_Coords[2], 0, line.m_Coords[3]); + CVector3D p1(line.m_Coords[0].X, 0, line.m_Coords[0].Y); + CVector3D p2(line.m_Coords[1].X, 0, line.m_Coords[1].Y); if (closed) // grab the ending point so as to close the loop - p0 = CVector3D(line.m_Coords[(n-1)*2], 0, line.m_Coords[(n-1)*2+1]); + p0 = CVector3D(line.m_Coords[n - 1].X, 0, line.m_Coords[n - 1].Y); else // we don't want to loop around and use the direction towards the other end of the line, so create an artificial p0 that // extends the p2 -> p1 direction, and use that point instead @@ -210,7 +210,7 @@ // next iteration is the last point of the line, so create an artificial p2 that extends the p0 -> p1 direction p2 = p1 + (p1 - p0); else - p2 = CVector3D(line.m_Coords[((i+2) % n)*2], 0, line.m_Coords[((i+2) % n)*2+1]); + p2 = CVector3D(line.m_Coords[(i + 2) % n].X, 0, line.m_Coords[(i + 2) % n].Y); p2.Y = terrain.GetExactGroundLevel(p2.X, p2.Z); if (p2.Y < w) diff -Nru 0ad-0.0.24~r24010/source/renderer/WaterManager.cpp 0ad-0.0.24~r24155/source/renderer/WaterManager.cpp --- 0ad-0.0.24~r24010/source/renderer/WaterManager.cpp 2019-12-07 15:32:47.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/WaterManager.cpp 2020-09-16 18:03:51.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -125,8 +125,7 @@ m_NeedInfoUpdate = true; m_depthTT = 0; - m_FancyTextureNormal = 0; - m_FancyTextureOther = 0; + m_FancyTexture = 0; m_FancyTextureDepth = 0; m_ReflFboDepthTexture = 0; m_RefrFboDepthTexture = 0; @@ -162,8 +161,7 @@ return; glDeleteTextures(1, &m_depthTT); - glDeleteTextures(1, &m_FancyTextureNormal); - glDeleteTextures(1, &m_FancyTextureOther); + glDeleteTextures(1, &m_FancyTexture); glDeleteTextures(1, &m_FancyTextureDepth); glDeleteTextures(1, &m_ReflFboDepthTexture); glDeleteTextures(1, &m_RefrFboDepthTexture); @@ -267,15 +265,8 @@ glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); // Create the Fancy Effects texture - glGenTextures(1, &m_FancyTextureNormal); - glBindTexture(GL_TEXTURE_2D, m_FancyTextureNormal); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glGenTextures(1, &m_FancyTextureOther); - glBindTexture(GL_TEXTURE_2D, m_FancyTextureOther); + glGenTextures(1, &m_FancyTexture); + glBindTexture(GL_TEXTURE_2D, m_FancyTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); @@ -331,8 +322,7 @@ pglGenFramebuffersEXT(1, &m_FancyEffectsFBO); pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_FancyTextureNormal, 0); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_FancyTextureOther, 0); + pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_FancyTexture, 0); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_FancyTextureDepth, 0); ogl_WarnIfError(); @@ -358,10 +348,7 @@ // Resize: Updates the fancy water textures. void WaterManager::Resize() { - glBindTexture(GL_TEXTURE_2D, m_FancyTextureNormal); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)g_Renderer.GetWidth(), (GLsizei)g_Renderer.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL); - - glBindTexture(GL_TEXTURE_2D, m_FancyTextureOther); + glBindTexture(GL_TEXTURE_2D, m_FancyTexture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)g_Renderer.GetWidth(), (GLsizei)g_Renderer.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL); glBindTexture(GL_TEXTURE_2D, m_FancyTextureDepth); @@ -878,8 +865,8 @@ pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); - GLuint attachments[2] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; - pglDrawBuffers(2, attachments); + GLuint attachments[1] = { GL_COLOR_ATTACHMENT0_EXT }; + pglDrawBuffers(1, attachments); glClearColor(0.0f,0.0f, 0.0f,0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff -Nru 0ad-0.0.24~r24010/source/renderer/WaterManager.h 0ad-0.0.24~r24155/source/renderer/WaterManager.h --- 0ad-0.0.24~r24010/source/renderer/WaterManager.h 2019-09-07 08:50:55.000000000 +0000 +++ 0ad-0.0.24~r24155/source/renderer/WaterManager.h 2020-09-16 18:03:51.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -62,8 +62,7 @@ CTexturePtr m_FoamTex; GLuint m_depthTT; - GLuint m_FancyTextureNormal; - GLuint m_FancyTextureOther; + GLuint m_FancyTexture; GLuint m_FancyTextureDepth; GLuint m_ReflFboDepthTexture; GLuint m_RefrFboDepthTexture; diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/CCmpPathfinder_Common.h 0ad-0.0.24~r24155/source/simulation2/components/CCmpPathfinder_Common.h --- 0ad-0.0.24~r24010/source/simulation2/components/CCmpPathfinder_Common.h 2020-08-03 12:02:24.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/CCmpPathfinder_Common.h 2020-11-08 08:58:19.000000000 +0000 @@ -89,12 +89,10 @@ static void ClassInit(CComponentManager& componentManager) { componentManager.SubscribeToMessageType(MT_Deserialized); - componentManager.SubscribeToMessageType(MT_Update); componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays componentManager.SubscribeToMessageType(MT_TerrainChanged); componentManager.SubscribeToMessageType(MT_WaterChanged); componentManager.SubscribeToMessageType(MT_ObstructionMapShapeChanged); - componentManager.SubscribeToMessageType(MT_TurnStart); } ~CCmpPathfinder(); diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/CCmpRallyPointRenderer.cpp 0ad-0.0.24~r24155/source/simulation2/components/CCmpRallyPointRenderer.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/CCmpRallyPointRenderer.cpp 2020-06-14 20:39:03.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/CCmpRallyPointRenderer.cpp 2020-11-08 14:47:25.000000000 +0000 @@ -514,10 +514,7 @@ ENSURE(segment.m_EndIndex > segment.m_StartIndex); // End index is inclusive here for (size_t j = segment.m_StartIndex; j <= segment.m_EndIndex; ++j) - { - overlayLine.m_Coords.push_back(m_Path[index][j].X); - overlayLine.m_Coords.push_back(m_Path[index][j].Y); - } + overlayLine.m_Coords.push_back(m_Path[index][j]); m_TexturedOverlayLines[index].push_back(overlayLine); } @@ -588,11 +585,8 @@ size_t dashEndIndex = dashedLine.GetEndIndex(i); ENSURE(dashEndIndex > dashStartIndex); - for (size_t n = dashStartIndex; n < dashEndIndex; n++) - { - dashOverlay.m_Coords.push_back(dashedLine.m_Points[n].X); - dashOverlay.m_Coords.push_back(dashedLine.m_Points[n].Y); - } + for (size_t j = dashStartIndex; j < dashEndIndex; ++j) + dashOverlay.m_Coords.push_back(dashedLine.m_Points[j]); m_TexturedOverlayLines[index].push_back(dashOverlay); } diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/CCmpRangeManager.cpp 0ad-0.0.24~r24155/source/simulation2/components/CCmpRangeManager.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/CCmpRangeManager.cpp 2020-06-14 20:39:03.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/CCmpRangeManager.cpp 2020-10-31 10:21:08.000000000 +0000 @@ -173,10 +173,7 @@ i64 c2 = MUL_I64_I32_I32(c_2 - y, c); - if (d2 <= c2) - return true; - - return false; + return d2 <= c2; } struct EntityParabolicRangeOutline @@ -837,7 +834,7 @@ m_LosTilesPerSide = (m_TerrainVerticesPerSide - 1)/LOS_TILES_RATIO; for (size_t player_id = 0; player_id < m_LosPlayerCounts.size(); ++player_id) - m_LosPlayerCounts[player_id].reset(); + m_LosPlayerCounts[player_id].clear(); m_ExploredVertices.clear(); m_ExploredVertices.resize(MAX_LOS_PLAYER_ID+1, 0); diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/CCmpRangeOverlayRenderer.cpp 0ad-0.0.24~r24155/source/simulation2/components/CCmpRangeOverlayRenderer.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/CCmpRangeOverlayRenderer.cpp 2019-12-20 22:33:50.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/CCmpRangeOverlayRenderer.cpp 2020-09-27 13:12:30.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -58,9 +58,7 @@ virtual void Init(const CParamNode& UNUSED(paramNode)) { - m_EnabledInterpolate = false; - m_EnabledRenderSubmit = false; - m_Enabled = false; + m_Enabled = m_LastEnabledState = false; UpdateMessageSubscriptions(); } @@ -161,28 +159,13 @@ void UpdateMessageSubscriptions() { - bool needInterpolate = false; - bool needRenderSubmit = false; - - if (m_Enabled) - { - needInterpolate = true; - needRenderSubmit = true; - } - - if (needInterpolate != m_EnabledInterpolate) - { - GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Interpolate, this, needInterpolate); - m_EnabledInterpolate = needInterpolate; - m_Enabled = needInterpolate; - } + if (m_Enabled == m_LastEnabledState) + return; - if (needRenderSubmit != m_EnabledRenderSubmit) - { - GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, needRenderSubmit); - m_EnabledRenderSubmit = needRenderSubmit; - m_Enabled = needRenderSubmit; - } + CComponentManager& cmpManager = GetSimContext().GetComponentManager(); + cmpManager.DynamicSubscriptionNonsync(MT_Interpolate, this, m_Enabled); + cmpManager.DynamicSubscriptionNonsync(MT_RenderSubmit, this, m_Enabled); + m_LastEnabledState = m_Enabled; } void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) @@ -221,8 +204,7 @@ SimRender::ConstructTexturedLineCircle(*rangeOverlay.line.get(), origin, rangeOverlay.descriptor.m_Radius); } - bool m_EnabledInterpolate; - bool m_EnabledRenderSubmit; + bool m_LastEnabledState; bool m_Enabled; const char* TEXTURE_BASE_PATH = "art/textures/selection/"; diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/CCmpTerritoryManager.cpp 0ad-0.0.24~r24155/source/simulation2/components/CCmpTerritoryManager.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/CCmpTerritoryManager.cpp 2020-02-23 18:24:31.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/CCmpTerritoryManager.cpp 2020-11-08 14:47:25.000000000 +0000 @@ -645,11 +645,10 @@ SimRender::SmoothPointsAverage(boundaries[i].points, m_BoundaryLines.back().overlay.m_Closed); SimRender::InterpolatePointsRNS(boundaries[i].points, m_BoundaryLines.back().overlay.m_Closed, m_BorderSeparation); - std::vector& points = m_BoundaryLines.back().overlay.m_Coords; + std::vector& points = m_BoundaryLines.back().overlay.m_Coords; for (size_t j = 0; j < boundaries[i].points.size(); ++j) { - points.push_back(boundaries[i].points[j].X); - points.push_back(boundaries[i].points[j].Y); + points.push_back(boundaries[i].points[j]); if (m_EnableLineDebugOverlays) { diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/CCmpUnitMotion.cpp 0ad-0.0.24~r24155/source/simulation2/components/CCmpUnitMotion.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/CCmpUnitMotion.cpp 2020-08-06 08:40:14.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/CCmpUnitMotion.cpp 2020-11-09 13:25:50.000000000 +0000 @@ -788,10 +788,7 @@ // Send OBSTRUCTED at first - moveFailed is likely to trigger path recomputation and we might end up // recomputing too often for nothing. if (!IncrementFailedPathComputationAndMaybeNotify()) - { - CMessageMotionUpdate msg(CMessageMotionUpdate::OBSTRUCTED); - GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); - } + MoveObstructed(); m_FollowKnownImperfectPathCountdown = KNOWN_IMPERFECT_PATH_RESET_COUNTDOWN; } return; @@ -815,10 +812,7 @@ // Send OBSTRUCTED at first - moveFailed is likely to trigger path recomputation and we might end up // recomputing too often for nothing. if (!IncrementFailedPathComputationAndMaybeNotify()) - { - CMessageMotionUpdate msg(CMessageMotionUpdate::OBSTRUCTED); - GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); - } + MoveObstructed(); m_FollowKnownImperfectPathCountdown = KNOWN_IMPERFECT_PATH_RESET_COUNTDOWN; } return; @@ -1155,7 +1149,7 @@ // Check if we anticipate the target to go through us, in which case we shouldn't anticipate // (or e.g. units fleeing might suddenly turn around towards their attacker). - if ((out - cmpPosition->GetPosition2D()).Dot(tempPos - cmpPosition->GetPosition2D()) >= fixed::Zero()) + if ((out - cmpPosition->GetPosition2D()).RelativeOrientation(tempPos - cmpPosition->GetPosition2D()) >= 0) out = tempPos; } } diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/ICmpAttack.cpp 0ad-0.0.24~r24155/source/simulation2/components/ICmpAttack.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/ICmpAttack.cpp 2020-04-21 21:44:05.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/ICmpAttack.cpp 2020-10-10 15:12:17.000000000 +0000 @@ -31,10 +31,15 @@ public: DEFAULT_SCRIPT_WRAPPER(AttackScripted) - virtual float GetRepeatTime(const std::string& type) const - { - return m_Script.Call("GetRepeatTime", type); - } + virtual float GetRepeatTime(const std::string& type) const + { + return m_Script.Call("GetRepeatTime", type); + } + + virtual std::vector GetAttackTypes() const + { + return m_Script.Call>("GetAttackTypes"); + } }; REGISTER_COMPONENT_SCRIPT_WRAPPER(AttackScripted) diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/ICmpAttack.h 0ad-0.0.24~r24155/source/simulation2/components/ICmpAttack.h --- 0ad-0.0.24~r24010/source/simulation2/components/ICmpAttack.h 2020-04-21 21:44:05.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/ICmpAttack.h 2020-10-10 15:12:17.000000000 +0000 @@ -18,12 +18,14 @@ #ifndef INCLUDED_ICMPATTACK #define INCLUDED_ICMPATTACK +#include "ps/CStr.h" #include "simulation2/system/Interface.h" class ICmpAttack : public IComponent { public: virtual float GetRepeatTime(const std::string& type) const = 0; + virtual std::vector GetAttackTypes() const = 0; DECLARE_INTERFACE_TYPE(Attack) }; diff -Nru 0ad-0.0.24~r24010/source/simulation2/components/ICmpPathfinder.cpp 0ad-0.0.24~r24155/source/simulation2/components/ICmpPathfinder.cpp --- 0ad-0.0.24~r24010/source/simulation2/components/ICmpPathfinder.cpp 2017-04-03 09:58:01.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/components/ICmpPathfinder.cpp 2020-11-08 08:58:19.000000000 +0000 @@ -25,4 +25,5 @@ DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpPathfinder, SetDebugOverlay, bool) DEFINE_INTERFACE_METHOD_1("SetHierDebugOverlay", void, ICmpPathfinder, SetHierDebugOverlay, bool) DEFINE_INTERFACE_METHOD_CONST_1("GetPassabilityClass", pass_class_t, ICmpPathfinder, GetPassabilityClass, std::string) +DEFINE_INTERFACE_METHOD_0("UpdateGrid", void, ICmpPathfinder, UpdateGrid) END_INTERFACE_WRAPPER(Pathfinder) diff -Nru 0ad-0.0.24~r24010/source/simulation2/helpers/Geometry.cpp 0ad-0.0.24~r24155/source/simulation2/helpers/Geometry.cpp --- 0ad-0.0.24~r24010/source/simulation2/helpers/Geometry.cpp 2020-08-17 20:13:18.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/helpers/Geometry.cpp 2020-11-09 13:25:50.000000000 +0000 @@ -342,13 +342,13 @@ fixed hh = halfSize.Y; CFixedVector2D p = axis.Perpendicular(); - if (p.Dot((u.Multiply(hw) + v.Multiply(hh)) - a) <= fixed::Zero()) + if (p.RelativeOrientation(u.Multiply(hw) + v.Multiply(hh) - a) <= 0) return true; - if (p.Dot((u.Multiply(hw) - v.Multiply(hh)) - a) <= fixed::Zero()) + if (p.RelativeOrientation(u.Multiply(hw) - v.Multiply(hh) - a) <= 0) return true; - if (p.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a) <= fixed::Zero()) + if (p.RelativeOrientation(-u.Multiply(hw) - v.Multiply(hh) - a) <= 0) return true; - if (p.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a) <= fixed::Zero()) + if (p.RelativeOrientation(-u.Multiply(hw) + v.Multiply(hh) - a) <= 0) return true; return false; diff -Nru 0ad-0.0.24~r24010/source/simulation2/helpers/Grid.h 0ad-0.0.24~r24155/source/simulation2/helpers/Grid.h --- 0ad-0.0.24~r24010/source/simulation2/helpers/Grid.h 2020-06-13 09:05:40.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/helpers/Grid.h 2020-10-31 10:21:08.000000000 +0000 @@ -94,14 +94,12 @@ m_W = g.m_W; m_H = g.m_H; - delete[] m_Data; + SAFE_ARRAY_DELETE(m_Data); if (g.m_Data) { m_Data = new T[m_W * m_H]; copy_data(g.m_Data, dispatch{}); } - else - m_Data = NULL; return *this; } @@ -114,7 +112,7 @@ ~Grid() { - delete[] m_Data; + SAFE_ARRAY_DELETE(m_Data); } // Ensure that o and this are the same size before calling. @@ -168,20 +166,29 @@ void reset_data(default_type) { std::fill(&m_Data[0], &m_Data[m_H*m_W], T{}); } void reset_data(is_pod) { memset(m_Data, 0, m_W*m_H*sizeof(T)); } + // Reset the data to its default-constructed value (usually 0), not changing size. void reset() { if (m_Data) reset_data(dispatch{}); } + // Clear the grid setting the size to 0 and freeing any data. + void clear() + { + resize(0, 0); + } + void resize(u16 w, u16 h) { - if (m_Data) - delete[] m_Data; + SAFE_ARRAY_DELETE(m_Data); m_W = w; m_H = h; - if (m_W || m_H) - m_Data = new T[m_W * m_H]; + + if (!m_W && !m_H) + return; + + m_Data = new T[m_W * m_H]; ENSURE(m_Data); reset(); } @@ -337,13 +344,13 @@ ~SparseGrid() { reset(); - delete[] m_Data; + SAFE_ARRAY_DELETE(m_Data); } void reset() { for (size_t i = 0; i < (size_t)(m_BW*m_BH); ++i) - delete[] m_Data[i]; + SAFE_ARRAY_DELETE(m_Data[i]); // Reset m_Data by value-constructing in place with placement new. m_Data = new (m_Data) T*[m_BW*m_BH](); diff -Nru 0ad-0.0.24~r24010/source/simulation2/Simulation2.cpp 0ad-0.0.24~r24155/source/simulation2/Simulation2.cpp --- 0ad-0.0.24~r24010/source/simulation2/Simulation2.cpp 2020-07-18 17:39:59.000000000 +0000 +++ 0ad-0.0.24~r24155/source/simulation2/Simulation2.cpp 2020-11-08 08:58:19.000000000 +0000 @@ -531,19 +531,16 @@ CComponentManager& componentManager = simContext.GetComponentManager(); + CmpPtr cmpPathfinder(simContext, SYSTEM_ENTITY); + if (cmpPathfinder) + cmpPathfinder->FetchAsyncResultsAndSendMessages(); + { PROFILE2("Sim - Update Start"); CMessageTurnStart msgTurnStart; componentManager.BroadcastMessage(msgTurnStart); } - CmpPtr cmpPathfinder(simContext, SYSTEM_ENTITY); - if (cmpPathfinder) - { - cmpPathfinder->FetchAsyncResultsAndSendMessages(); - cmpPathfinder->UpdateGrid(); - } - // Push AI commands onto the queue before we use them CmpPtr cmpAIManager(simContext, SYSTEM_ENTITY); if (cmpAIManager) @@ -594,7 +591,10 @@ // Process all remaining moves if (cmpPathfinder) + { + cmpPathfinder->UpdateGrid(); cmpPathfinder->StartProcessingMoves(false); + } } void CSimulation2Impl::Interpolate(float simFrameLength, float frameOffset, float realFrameLength) diff -Nru 0ad-0.0.24~r24010/source/soundmanager/scripting/JSInterface_Sound.cpp 0ad-0.0.24~r24155/source/soundmanager/scripting/JSInterface_Sound.cpp --- 0ad-0.0.24~r24010/source/soundmanager/scripting/JSInterface_Sound.cpp 2019-09-07 13:35:45.000000000 +0000 +++ 0ad-0.0.24~r24155/source/soundmanager/scripting/JSInterface_Sound.cpp 2020-10-02 07:35:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -125,11 +125,11 @@ void ClearPlaylist(ScriptInterface::CxPrivate* UNUSED(pCxPrivate) ){} void StopMusic(ScriptInterface::CxPrivate* UNUSED(pCxPrivate) ){} void StartMusic(ScriptInterface::CxPrivate* UNUSED(pCxPrivate) ){} - void SetMasterGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float gain){} - void SetMusicGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float gain){} - void SetAmbientGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float gain){} - void SetActionGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float gain){} - void SetUIGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float gain){} + void SetMasterGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float UNUSED(gain)){} + void SetMusicGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float UNUSED(gain)){} + void SetAmbientGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float UNUSED(gain)){} + void SetActionGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float UNUSED(gain)){} + void SetUIGain(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), float UNUSED(gain)){} #endif diff -Nru 0ad-0.0.24~r24010/source/soundmanager/scripting/SoundGroup.h 0ad-0.0.24~r24155/source/soundmanager/scripting/SoundGroup.h --- 0ad-0.0.24~r24010/source/soundmanager/scripting/SoundGroup.h 2019-04-25 22:37:15.000000000 +0000 +++ 0ad-0.0.24~r24155/source/soundmanager/scripting/SoundGroup.h 2020-10-02 07:35:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -83,11 +83,11 @@ #if CONFIG2_AUDIO inline u32 FastRand(); // Contains the current sound seed for the generator - u32 m_Seed; float RandFloat(float min, float max); // We store the handles so we can load now and play later std::vector m_SoundGroups; #endif + u32 m_Seed; // We need the filenames so we can reload when necessary. std::vector m_Filenames; // The file path for the list of sound file resources diff -Nru 0ad-0.0.24~r24010/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp 0ad-0.0.24~r24155/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp --- 0ad-0.0.24~r24010/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp 2020-08-03 12:23:16.000000000 +0000 +++ 0ad-0.0.24~r24155/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp 2020-11-04 12:21:55.000000000 +0000 @@ -326,8 +326,8 @@ ID_BigScreenshot, ID_JavaScript, ID_CameraReset, - ID_RenderPathFixed, - ID_RenderPathShader, + ID_RenderPathShaderARB, + ID_RenderPathShaderGLSL, ID_DumpState, ID_DumpBinaryState, @@ -362,8 +362,8 @@ EVT_MENU(ID_CameraReset, ScenarioEditor::OnCameraReset) EVT_MENU(ID_DumpState, ScenarioEditor::OnDumpState) EVT_MENU(ID_DumpBinaryState, ScenarioEditor::OnDumpState) - EVT_MENU(ID_RenderPathFixed, ScenarioEditor::OnRenderPath) - EVT_MENU(ID_RenderPathShader, ScenarioEditor::OnRenderPath) + EVT_MENU(ID_RenderPathShaderARB, ScenarioEditor::OnRenderPath) + EVT_MENU(ID_RenderPathShaderGLSL, ScenarioEditor::OnRenderPath) EVT_MENU(ID_Manual, ScenarioEditor::OnHelp) EVT_MENU(ID_ReportBug, ScenarioEditor::OnHelp) @@ -485,8 +485,8 @@ wxMenu *menuRP = new wxMenu; menuMisc->AppendSubMenu(menuRP, _("Render &path")); - menuRP->Append(ID_RenderPathFixed, _("&Fixed function")); - menuRP->Append(ID_RenderPathShader, _("&Shader (default)")); + menuRP->Append(ID_RenderPathShaderARB, _("Shader &ARB")); + menuRP->Append(ID_RenderPathShaderGLSL, _("&Shader GLSL (default)")); } wxMenu *menuHelp = new wxMenu; @@ -928,11 +928,13 @@ { switch (event.GetId()) { - case ID_RenderPathFixed: - POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"fixed")); + case ID_RenderPathShaderARB: + POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"shader")); + POST_MESSAGE(SetViewParamB, (eRenderView::GAME, L"preferGLSL", false)); break; - case ID_RenderPathShader: + case ID_RenderPathShaderGLSL: POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"shader")); + POST_MESSAGE(SetViewParamB, (eRenderView::GAME, L"preferGLSL", true)); break; } } diff -Nru 0ad-0.0.24~r24010/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp 0ad-0.0.24~r24155/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp --- 0ad-0.0.24~r24010/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp 2020-07-24 18:53:03.000000000 +0000 +++ 0ad-0.0.24~r24155/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp 2020-09-20 09:33:18.000000000 +0000 @@ -187,8 +187,12 @@ AtObj victoryCondition = AtlasObject::LoadFromJSON(victoryConditionJson); long index = wxWindow::NewControlId(); wxString title = wxString::FromUTF8(victoryCondition["Data"]["Title"]); + std::string escapedTitle = wxString::FromUTF8(title).Lower().ToStdString(); + std::replace(escapedTitle.begin(), escapedTitle.end(), ' ', '_'); + AtObj updateCondition = *(victoryCondition["Data"]["Title"]); + updateCondition.setString(escapedTitle.c_str()); m_VictoryConditions.insert(std::pair(index, victoryCondition)); - CREATE_CHECKBOX(this, vcGridSizer, title.MakeLower(), "Select " + wxString::FromUTF8(victoryCondition["Data"]["Title"]) + " victory condition.", index); + CREATE_CHECKBOX(this, vcGridSizer, title, "Select " + title + " victory condition.", index); } victoryConditionSizer->Add(vcGridSizer); @@ -247,7 +251,9 @@ for (const std::pair& vc : m_VictoryConditions) { - if (m_MapSettingsVictoryConditions.find(wxString::FromUTF8(vc.second["Data"]["Title"]).Lower().ToStdString()) == m_MapSettingsVictoryConditions.end()) + std::string escapedTitle = wxString::FromUTF8(vc.second["Data"]["Title"]).Lower().ToStdString(); + std::replace(escapedTitle.begin(), escapedTitle.end(), ' ', '_'); + if (m_MapSettingsVictoryConditions.find(escapedTitle) == m_MapSettingsVictoryConditions.end()) continue; wxCheckBox* checkBox = wxDynamicCast(FindWindow(vc.first), wxCheckBox); @@ -366,7 +372,11 @@ m_MapSettingsVictoryConditions.erase(name); for (const std::pair& vc : m_VictoryConditions) - INSERT_VICTORY_CONDITION_CHECKBOX(wxString::FromUTF8(vc.second["Data"]["Title"]).Lower().ToStdString(), vc.first) + { + std::string escapedTitle = wxString::FromUTF8(vc.second["Data"]["Title"]).Lower().ToStdString(); + std::replace(escapedTitle.begin(), escapedTitle.end(), ' ', '_'); + INSERT_VICTORY_CONDITION_CHECKBOX(escapedTitle, vc.first) + } #undef INSERT_VICTORY_CONDITION_CHECKBOX diff -Nru 0ad-0.0.24~r24010/source/tools/atlas/GameInterface/ActorViewer.cpp 0ad-0.0.24~r24155/source/tools/atlas/GameInterface/ActorViewer.cpp --- 0ad-0.0.24~r24010/source/tools/atlas/GameInterface/ActorViewer.cpp 2020-04-21 21:44:05.000000000 +0000 +++ 0ad-0.0.24~r24155/source/tools/atlas/GameInterface/ActorViewer.cpp 2020-10-10 15:12:17.000000000 +0000 @@ -382,7 +382,7 @@ CStr anim = animation.LowerCase(); float speed = 1.0f; // Speed will be ignored if we have a repeat time. - float repeattime = 0.0f; + float repeatTime = 0.0f; m.CurrentSpeed = 0.0f; if (anim == "walk") { @@ -403,22 +403,25 @@ m.CurrentSpeed = speed; } - else if (anim == "attack_melee") - repeattime = GetRepeatTimeByAttackType("Melee"); - else if (anim == "attack_ranged") - repeattime = GetRepeatTimeByAttackType("Ranged"); - else if (anim == "attack_slaughter") - repeattime = GetRepeatTimeByAttackType("Slaughter"); - else if (anim == "attack_capture") - repeattime = GetRepeatTimeByAttackType("Capture"); + else if (anim.Find("attack_") == 0) + { + CmpPtr cmpAttack(m.Simulation2, m.Entity); + if (cmpAttack) + for (const CStr& type : cmpAttack->GetAttackTypes()) + if (anim == "attack_" + type.LowerCase()) + { + repeatTime = GetRepeatTimeByAttackType(type); + break; + } + } CmpPtr cmpVisual(m.Simulation2, m.Entity); if (cmpVisual) { // TODO: SetEntitySelection(anim) cmpVisual->SelectAnimation(anim, false, fixed::FromFloat(speed)); - if (repeattime) - cmpVisual->SetAnimationSyncRepeat(fixed::FromFloat(repeattime)); + if (repeatTime > 0.0f) + cmpVisual->SetAnimationSyncRepeat(fixed::FromFloat(repeatTime)); } // update prop list for new entity/animation (relies on needsAnimReload also getting called for entire entity changes) diff -Nru 0ad-0.0.24~r24010/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp 0ad-0.0.24~r24155/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp --- 0ad-0.0.24~r24010/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp 2019-08-25 08:57:36.000000000 +0000 +++ 0ad-0.0.24~r24155/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp 2020-11-08 11:31:32.000000000 +0000 @@ -199,6 +199,7 @@ g_Renderer.SetTerrainRenderMode(msg->wireframe ? EDGED_FACES : SOLID); g_Renderer.SetWaterRenderMode(msg->wireframe ? EDGED_FACES : SOLID); g_Renderer.SetModelRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.SetOverlayRenderMode(msg->wireframe ? EDGED_FACES : SOLID); } } diff -Nru 0ad-0.0.24~r24010/source/tools/atlas/GameInterface/View.cpp 0ad-0.0.24~r24155/source/tools/atlas/GameInterface/View.cpp --- 0ad-0.0.24~r24010/source/tools/atlas/GameInterface/View.cpp 2020-01-29 22:03:44.000000000 +0000 +++ 0ad-0.0.24~r24155/source/tools/atlas/GameInterface/View.cpp 2020-11-04 12:21:55.000000000 +0000 @@ -323,6 +323,8 @@ g_Renderer.SetDisplayTerrainPriorities(value); else if (name == L"movetool") m_DrawMoveTool = value; + else if (name == L"preferGLSL") + g_RenderingOptions.SetPreferGLSL(value); } void AtlasViewGame::SetParam(const std::wstring& name, float value)