diff -Nru 0ad-0.0.25b/binaries/data/l10n/ast.engine.po 0ad-0.0.26/binaries/data/l10n/ast.engine.po --- 0ad-0.0.25b/binaries/data/l10n/ast.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/ast.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,15 +1,15 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# David Sowa , 2017-2021 -# enolp , 2017 +# David Sowa +# enolp msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-17 19:38+0000\n" -"Last-Translator: David Sowa \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: David Sowa , 2017-2022\n" "Language-Team: Asturian (http://www.transifex.com/wildfire-games/0ad/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -17,248 +17,249 @@ "Language: ast\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" -msgstr "La velocidá de desplazamientu amontó a %.1f" +msgstr "La velocidade de dislocacion augmentou a %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "La velocidá de desplazamientu amenorgó a %.1f" +msgstr "La velocidade de dislocacion aminorgou a %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" -msgstr "La velocidá de xiru xubió a X=%.3f, Y=%.3f" +msgstr "La velocidade gyratoria augmentou a X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" -msgstr "La velocidá de xiru baxó a X=%.3f, Y=%.3f" +msgstr "La velocidade gyratoria aminorgou a X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" -msgstr "La velocidá d'averamientu amontó a %.1f" +msgstr "La velocidade d’aveiradura augmentou a %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "La velocidá d'averamientu amenorgó a %.1f" +msgstr "La velocidade d’aveiradura aminorgou a %.1f" #: i18n/L10n.cpp:308 msgid "Long strings" -msgstr "Cadenes llargues" +msgstr "Cadenas lhongas" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" -msgstr "desconozse'l sotipu (ve los rexistros)" +msgstr "disconhoç-se l subtypu (veia-se los registros)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." -msgstr "El certificáu nun ye d'enfotu." +msgstr "El certificado nun je d’infhoutu." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." -msgstr "Nun se sabe quién fexo'l certificáu." +msgstr "Nun se sabe quien dieu l certificado." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." -msgstr "Revocóse'l certificáu." +msgstr "Revocou-se l certificado." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." -msgstr "El certificáu caducó." +msgstr "El certificado caducou." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." -msgstr "El certificáu nun ta activu." +msgstr "El certificado sigue inactivo." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." -msgstr "El certificáu nun s'emitió pal par al que tas coneutáu. " +msgstr "El certificado nun se dieu pa l par a l que stas conexu." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." -msgstr "Quien robló'l certificáu nun tenía autorización." +msgstr "Quien robrou l certificado nun teníe authorizacion." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" -msgstr "Fallu" +msgstr "Error" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" -msgstr "Nun hai fallos" +msgstr "Nun ha hi errores" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" -msgstr "Esi xugador yá tien la sesión aniciada" +msgstr "El xhogador ja s’authenticou" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" -msgstr "Prohíbese" +msgstr "Prohibe-se" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" -msgstr "Fallu nel sirvidor internu" +msgstr "Error internu de l servidor" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" -msgstr "Nun se permite" +msgstr "Nun se permitte" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" -msgstr "Nun s'autorizó" +msgstr "Nun s’authoriza" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" -msgstr "De momentu nun ta disponible'l destinatariu" +msgstr "El receptor nun sta disponible temporalmente" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" -msgstr "Ríquese'l rexistru" +msgstr "Requier-se l registro" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" -msgstr "El serviciu nun ta disponible" +msgstr "El servicio nun sta disponible" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" -msgstr "Desconozse'l fallu" +msgstr "Error disconhocidu" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" -msgstr "Fallu nel fluxu" +msgstr "Error de fluxu" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" -msgstr "Nun se sofita la versión del fluxu entrante" +msgstr "Nun se sofhita la version de l fluxu intrante" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" -msgstr "El fluxu zarrólu'l sirvidor" +msgstr "El fluxu atyouîu-lu l servidor" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" -msgstr "Hebo un fallu E/S" +msgstr "Houbo un error d’intrada/salida" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" -msgstr "La conexón refugóla'l sirvidor" +msgstr "La conexion recusou-la l servidor" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" -msgstr "Falló la resolución del nome d'agospiu del sirvidor" +msgstr "Houbo un falhu a l resolvere l nome hospedeiru de l servidor" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" -msgstr "Acabóse la memoria del sistema" +msgstr "Exhaurîu-se la memoria l systema" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" -msgstr "Nun pudo verificase'l certificáu'l sirvidor o la negociación TLS nun se completó con ésitu" +msgstr "Ou nun pudo comprobasse l certificado de l servidor ou nun dieu l preste la negociacion TLS" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" -msgstr "El sirvidor nun ufrió'l cifráu TLS riquíu" +msgstr "El servidor nun oufreu l cifrado TLS que se requier" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" -msgstr "Falló l'autenticación. La clave nun ye correcha o la cuenta nun esiste" +msgstr "Falhou l authenticacion. Ou nun je correcta la tyave d’accessu ou la cuonta nun existe" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" -msgstr "L'usuariu o'l sistema pidió desconeutase" +msgstr "L usuariu ou l systema pidîu disconectesse" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" -msgstr "Nun hai conexones actives" +msgstr "Nun ha hi conexiones activas" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" -msgstr "La cuenta rexistróse con ésitu" +msgstr "Registrou-se cun éxitu la tua cuonta" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" -msgstr "Nun s'apurrió tola información precisa" +msgstr "Nun s’aprovîu toda la informacion necessaria" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" -msgstr "Yá esiste esi nome d'usuariu" +msgstr "Existe ja l nome d’usuariu" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "Nun pudo escribise un mod.json esternu pal camudu comprimíu «%s». Hai que reinstalar el camudu." +msgstr "Nun pudo scribisse un mod.json externu pa la camuda comprimida “%s”. Ha hi que re-alhogare la camuda." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." -msgstr "Hebo un fallu al entamar a solicitar la identificación del xuegu. Fallu: %s; %s." +msgstr "Houbo un falhu a l intamar consultar sobre la identificacion de l xhuogu. Error: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." -msgstr "Hebo un fallu al entamar a solicitar los camudos. Fallu: %s; %s." +msgstr "Houbo un falhu a l intamar consultar sobre camudas. Error: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." -msgstr "Nun pudo criase'l direutoriu camudos: %s." +msgstr "Nun pudo creasse l directorio de la camuda: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." -msgstr "Nun pudo abrise'l ficheru temporal pa baxar el camudu: %s." +msgstr "Nun pudo abrisse l archivo temporal par apercibire la camuda: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." -msgstr "Falló al entamar la baxada. Fallu: %s; %s." +msgstr "Houbo un falhu a l intamare la percepcion. Error: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." -msgstr "Fallu de baxada asíncrona: %s, %s." +msgstr "Falhu de percepcion asýnchrona: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." -msgstr "Falló la baxada. Rempuesta del sirvidor: %s; %s." +msgstr "Falhou la percepcion. Respuosta de l servidor: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." -msgstr "Nun concasa'l tamañu del ficheru." +msgstr "Las granduras de los archivos nun concasan." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." -msgstr "Ficheru non válidu. Albidróse md5 %s, recibió %s." +msgstr "Archivo inválido. Anticipaba-se l md5 “%s”, recibîu-se “%s”." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." -msgstr "Falló al calcular el hash final." +msgstr "Houbo un falhu a l calculare la summa final." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." -msgstr "Falló al verificar la robla." +msgstr "Houbo un falhu a l comprobare la robra." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" -msgstr "La partida guardóse en '%s'" - -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "La semeya la pantalla guardóse en '%s'" +msgstr "Guardou-se la partida n “%s”" #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" -msgstr "compilación personalizada" +msgstr "compilacion personalizada" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "El semelyu archivou-se n “%s”" diff -Nru 0ad-0.0.25b/binaries/data/l10n/ca.engine.po 0ad-0.0.26/binaries/data/l10n/ca.engine.po --- 0ad-0.0.25b/binaries/data/l10n/ca.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/ca.engine.po 2022-09-23 19:16:31.000000000 +0000 @@ -1,23 +1,21 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Adrià Palouzié , 2018 -# Catalanoic , 2013 -# Catalanoic , 2013 -# Esteve Blanch , 2020 -# juan Aragó , 2018 -# Juanjo, 2016 -# Juanjo, 2016 -# Marco tom Suden, 2014 -# Marco tom Suden, 2014 -# Haommin , 2014-2016,2020 +# Adrià Palouzié +# Albert F. +# Catalanoic +# Esteve Blanch +# juan Aragó +# Juanjo +# Marco tom Suden +# Haommin msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-17 10:18+0000\n" -"Last-Translator: Transifex Bot <>\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Albert F. , 2021\n" "Language-Team: Catalan (http://www.transifex.com/wildfire-games/0ad/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,248 +23,249 @@ "Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" -msgstr "" +msgstr "Velocitat de desplaçament incrementada a %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "" +msgstr "Velocitat de desplaçament disminuïda a %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" -msgstr "" +msgstr "Velocitat de rotació incrementada a X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" -msgstr "" +msgstr "Velocitat de rotació disminuïda a X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" -msgstr "" +msgstr "Velocitat de zoom augmentada a %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "" +msgstr "Velocitat de zoom disminuïda a %.1f" #: i18n/L10n.cpp:308 msgid "Long strings" msgstr "Cadenes llargues" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "subtipus desconegut (consulteu el registre)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "El certificat no és de confiança." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "L'emissor del certificat no és conegut." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "El certificat ha estat revocat." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "El certificat ha expirat." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "El certificat encara no és actiu." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "El certificat no ha estat emès per l'interlocutor amb què s'ha connectat." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "El signant del certificat no és una autoritat certificadora." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Error" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Cap error" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "El jugador ja està connectat" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Prohibit" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Error intern del servidor" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "No està permès" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "No està autoritzat" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "El destinatari no està disponible temporalment" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Cal registrar-se" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "El servei no està disponible" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Error desconegut" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Error de transmissió" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "La versió de la transmissió entrant no és compatible" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "El servidor ha aturat la transmissió" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "S'ha produït un error d'E/S" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "El servidor ha rebutjat la connexió" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "No s'ha pogut resoldre l'adreça del servidor" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "El sistema no té prou memòria" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "No s'ha pogut verificar el certificat del servidor o no s'ha pogut completar el protocol handshake del TLS" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "El servidor no ofereix el xifrat TLS necessari" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Autenticació fallida. La contrasenya no és correcta o el compte no existeix" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "L'usuari o el sistema ha sol·licitat la desconnexió" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "No hi ha cap connexió activa" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "El vostre compte s'ha registrat correctament" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "No s'ha proporcionat tota la informació necessària" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "El nom d'usuari ja existeix" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "" +msgstr "No s'ha pogut escriure el mod.json extern per al mod comprimit '%s'. El mod hauria de ser reinstal·lat." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Hi ha hagut un error en la consulta de la identificació del joc. Error: %s;%s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Hi ha hagut un error en la consulta dels mods. Error: %s;%s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "No s'ha pogut crear el directori del mod: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "No s'ha pogut obrir un arxiu temporal per a la baixada del mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Error en començar la baixada. Error: %s;%s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Error de baixada asincrònica: %s,%s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Error en la baixada. La resposta del servidor és: %s;%s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "La mida del fitxer no coincideix." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "El fitxer no és vàlid. S'esperava md5 %s, s'ha obtingut%s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Hi ha hagut un error en computar el valor final del hash." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "No s'ha pogut verificar la signatura." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "S'ha desat la partida a \"%s\"" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "La captura de pantalla s'ha desat a \"%s\"" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "versió personalitzada" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "La captura de pantalla s'ha desat a \"%s\"" diff -Nru 0ad-0.0.25b/binaries/data/l10n/cs.engine.po 0ad-0.0.26/binaries/data/l10n/cs.engine.po --- 0ad-0.0.25b/binaries/data/l10n/cs.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/cs.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,24 +1,24 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Jakub Jelen , 2017 -# Lukáš Bačovský , 2020 -# Marek Mojžíš , 2020 -# Martin Křížek , 2021 -# fri, 2013-2016,2018 -# Pavel Šindelář , 2016 -# Petr Velička , 2021 -# Warriog , 2018 -# Tomáš Matýs , 2021 -# Vít Pelčák, 2014 -# Vojtěch Valigura , 2018 +# Jakub Jelen +# Lukáš Bačovský +# Marek Mojžíš +# Martin Křížek +# fri +# Pavel Šindelář +# Petr Velička +# Warriog +# Tomáš Matýs +# Vít Pelčák +# Vojtěch Valigura msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-26 08:42+0000\n" -"Last-Translator: Tomáš Matýs \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: fri, 2013-2016,2018,2021\n" "Language-Team: Czech (http://www.transifex.com/wildfire-games/0ad/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -26,32 +26,32 @@ "Language: cs\n" "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Rychlost posunu zvýšena na %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Rychlost posunu snížena na %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Rychlost otáčení zvýšena na X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Rychlost otáčení snížena na X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Rychlost přiblížení zvýšena na %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Rychlost přiblížení snížena na %.1f" @@ -60,214 +60,215 @@ msgid "Long strings" msgstr "Dlouhé řetězce" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "Neznámý podtyp (podívejte se na záznamy)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Certifikát není důvěryhodný." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Certifikát má neznámý eminent." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Certifikát byl revokován." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Platnost certifikátu skončila." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Certifikát ještě není aktivní." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Certifikát nebyl vydán pro protějšek, ke kterému je připojen." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." -msgstr "Podepisovatelem certifikátu není certifikátova autorita." +msgstr "Podepisovatelem certifikátu není certifikátová autorita." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Chyba" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Žádná chyba" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Hráč se už přihlásil" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Zakázáno" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Vnitřní chyba serveru" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Nepovoleno" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Neschváleno" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Příjemce dočasně nedostupný" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registrace vyžadována" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Služba nedostupná" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Neznámá chyba" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Chyba proudu" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Přicházející verze proudu není podporována" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Proud byl ukončen serverem" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Objevila se chyba vstupu/výstupu (I/O)" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Připojení bylo odmítnuto serverem" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Nepodařilo se zjistit název serveru" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Tomuto systému došla paměť" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Nepodařilo se ověřit certifikát serveru, nebo spojení nebylo úspěšně dokončeno" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Server nenabídnul požadované šifrování TLS" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Ověření neúspěšné. Nesprávné heslo nebo neexistující účet" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Uživatel nebo systém požádal o odpojení" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Žádné činné připojení" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Váš účet byl úspěšně registrován" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "406: Ne všechny potřebné informace podány" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "409: Uživatelské jméno je již používáno" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Nelze zapsat externí mod.json pro zazipovaný mod Mod'%s'. by měl být znovu nainstalován." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Selhání při spouštění dotazování se na ID hry. Chyba: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Selhání při spouštění dotazování se na mody. Chyba: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Nelze vytvořit adresář s mody: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Nelze otevřít dočasný soubor pro stažení modu: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Nepodařilo se spustit stahování. Chyba: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Selhání asynchronního stahování: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Stahování selhalo. Odpověď serveru: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Nesouhlasí velikost souboru." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Vadný soubor. Očekávaný kontrolní součet md5 %s, namísto %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Nelze vypočítat konečný hash." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Nepodařilo se ověřit podpis." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Hra uložena do '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Snímek obrazovky zapsán do '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "vlastní sestavení" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Snímek obrazovky zapsán do '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/de.engine.po 0ad-0.0.26/binaries/data/l10n/de.engine.po --- 0ad-0.0.25b/binaries/data/l10n/de.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/de.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,28 +1,27 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Wuzzy , 2018 -# xtother90, 2018-2021 -# eclipse, 2013 -# Maximilian Wagenbach , 2016 -# Heraklit of Ephesos, 2021 -# leper , 2013-2016 -# b53a4c6b86c5e58f09676ea42b536be9_2d04222 <3dd17ded6f065980fc0039767675503a_244748>, 2014 -# 999f6a43cef2718a4332fbe42b808991_de12e9e <3f94b88e9a60e6d6ccd40a3cb09a8c56_424596>, 2016 -# Thelxinoe, 2014 -# Raymond Vetter, 2014-2015 -# Silasoa , 2014 -# Tobias Stegemann , 2017 -# Tobias , 2014 -# xtother90, 2016 -# ze ro , 2021 +# Wuzzy +# xtother90 +# eclipse +# Maximilian Wagenbach +# Heraklit of Ephesos +# leper +# b53a4c6b86c5e58f09676ea42b536be9_2d04222 +# 999f6a43cef2718a4332fbe42b808991_de12e9e +# Thelxinoe +# Raymond Vetter +# Silasoa +# Tobias Stegemann +# Tobias +# ze ro msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-25 13:59+0000\n" -"Last-Translator: Heraklit of Ephesos\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: xtother90, 2018-2022\n" "Language-Team: German (http://www.transifex.com/wildfire-games/0ad/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,248 +29,249 @@ "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Scroll-Geschwindigkeit erhöht auf %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "Scroll-Geschwindigkeit vermindert auf %.1f" +msgstr "Scroll-Geschwindigkeit verringert auf %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Dreh-Geschwindigkeit erhöht auf X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" -msgstr "Dreh-Geschwindigkeit vermindert auf X=%.3f, Y=%.3f" +msgstr "Dreh-Geschwindigkeit verringert auf X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Zoom-Geschwindigkeit erhöht auf %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "Zoom-Geschwindigkeit vermindert auf %.1f" +msgstr "Zoom-Geschwindigkeit verringert auf %.1f" #: i18n/L10n.cpp:308 msgid "Long strings" msgstr "Lange Wörter" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "Unbekannter Untertyp (siehe Log-Dateien)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Das Zertifikat ist nicht vertrauenswürdig." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Das Zertifikat hat keinen bekannten Aussteller." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Das Zertifikat wurde widerrufen." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Das Zertifikat ist abgelaufen." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Das Zertifikat ist noch nicht aktiv." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Das Zertifikat ist nicht für den verbundenen Partner ausgestellt worden." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Der Unterzeichner des Zertifikats ist keine Zertifizierungsstelle." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Fehler" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Kein Fehler" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Spieler bereits angemeldet" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Verboten" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Interner Serverfehler" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Nicht erlaubt" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Nicht autorisiert" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Empfänger momentan nicht verfügbar" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registrierung erforderlich" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Service nicht verfügbar" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Unbekannter Fehler" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Datenstrom-Fehler" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Die Version des eingehenden Daten-Stroms wird nicht unterstützt." -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Der Daten-Strom wurde vom Server geschlossen." -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Ein Eingabe/Ausgabe-Fehler trat auf." -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Die Verbindung wurde vom Server abgelehnt." -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Der Hostname des Servers konnte nicht aufgelöst werden." -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Dieses System hat keinen freien Speicher mehr zur Verfügung." -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Das Zertifikat des Servers konnte nicht verifiziert werden oder der TLS-Handshake wurde nicht erfolgreich abgeschlossen." -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Der Server bietet die geforderte TLS-Verschlüsselung nicht an." -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Authentifizierung fehlgeschlagen. Passwort oder Benutzername ungültig." -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Der Benutzer oder das System forderten eine Verbindungstrennung." -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Es existiert keine aktive Verbindung." -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Dein Konto wurde erfolgreich eingerichtet." -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Nicht alle erforderlichen Informationen wurden bereitgestellt." -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Benutzername bereits in Verwendung" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "Die externe Datei mod.json für die gezippte Modifikation '%s' konnte nicht geschrieben werden. Die Modifikation sollte neu installiert werden." +msgstr "Die externe Datei mod.json für die gezippte Mod ‚%s‘ konnte nicht geschrieben werden. Die Mod sollte neu installiert werden." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Abfrage der Spiel-ID gescheitert. Fehler: %s; %s" -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." -msgstr "Abfrage der Modifikationen gescheitert. Fehler: %s; %s" +msgstr "Abfrage der Mods gescheitert. Fehler: %s; %s" -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." -msgstr "Modifikationen-Verzeichnis konnte nicht erstellt werden. Fehler: %s" +msgstr "Mod-Verzeichnis konnte nicht erstellt werden. Fehler: %s" -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." -msgstr "Temporäre Datei konnte nicht für Modifikationen-Download geöffnet werden. Fehler: %s" +msgstr "Temporäre Datei konnte nicht für Mod-Download geöffnet werden: %s" -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Download konnte nicht gestartet werden. Fehler: %s; %s" -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Asynchroner Download gescheitert. Fehler: %s, %s" -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Download gescheitert. Server-Antwort: %s; %s" -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Die Dateigrößen passen nicht zusammen." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Ungültige Datei. Erwartete MD5-Prüfsumme %s, jedoch %s erhalten." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Der endgültige Hash konnte nicht berechnet werden." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Signatur konnte nicht verifiziert werden." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" -msgstr "Spiel gespeichert unter '%s'" - -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Bildschirmfoto gespeichert unter '%s'" +msgstr "Spiel gespeichert unter ‚%s‘" #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "custom build" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Bildschirmfoto gespeichert unter ‚%s‘" diff -Nru 0ad-0.0.25b/binaries/data/l10n/el.engine.po 0ad-0.0.26/binaries/data/l10n/el.engine.po --- 0ad-0.0.25b/binaries/data/l10n/el.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/el.engine.po 2022-09-23 19:16:31.000000000 +0000 @@ -1,23 +1,22 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# LOUKAS SKOUROLIAKOS, 2015 -# Christo Keller , 2014 -# crippledmoon , 2016 -# George Litos , 2019 -# LOUKAS SKOUROLIAKOS, 2020-2021 -# malvanos , 2014-2015 -# Nicolas Auvray , 2018 -# Stephanos C. Siopoulos, 2013 -# Steven Gikas , 2016 -# Vasilis Drosos , 2017-2018 +# LOUKAS SKOUROLIAKOS +# Christo Keller +# crippledmoon +# George Litos +# malvanos +# Nicolas Auvray +# Stephanos C. Siopoulos +# Steven Gikas +# Vasilis Drosos msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-21 12:27+0000\n" -"Last-Translator: LOUKAS SKOUROLIAKOS\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: LOUKAS SKOUROLIAKOS, 2020-2021\n" "Language-Team: Greek (http://www.transifex.com/wildfire-games/0ad/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,32 +24,32 @@ "Language: el\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Ταχύτητα κύλισης αυξήθηκε σε %.1f " -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Ταχύτητα κύλισης μειώθηκε σε %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Ταχύτητα περιστροφής αυξήθηκε σε X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Ταχύτητα περιστροφής μειώθηκε σε X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Ταχύτητα εστίασης αυξήθηκε σε %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Ταχύτητα εστίασης μειώθηκε σε %.1f" @@ -59,214 +58,215 @@ msgid "Long strings" msgstr "Συμβολοσειρές μεγάλου μήκους" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "άγνωστος υπότυπος (δείτε αρχείο καταγραφής)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Το πιστοποιητικό δεν είναι αξιόπιστο." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Το πιστοποιητικό δεν έχει γνωστό εκδότη." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Το πιστοποιητικό έχει ανακληθεί." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Το πιστοποιητικό έχει λήξει." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Το πιστοποιητικό δέν είναι ενεργό ακόμα." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Το πιστοποιητικό δεν έχει εκδοθεί για τον συνδεδεμένο συνομιλητή." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Ο υπογράφων του πιστοποιητικού δεν είναι αρχή πιστοποίησης." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Σφάλμα" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Κανένα σφάλμα" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Το όνομα παίκτη χρησιμοποιείται ήδη" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Απαγορευμένος" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Εσωτερικό σφάλμα διακομιστή" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Δεν επιτρέπεται" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Μή εγκεκριμένο." -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Προσωρινά μη διαθέσιμος παραλήπτης" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Απαιτείται εγγραφή" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Μη διαθέσιμη υπηρεσία" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Άγνωστο σφάλμα" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Σφάλμα stream" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Η εισερχόμενη έκδοση της ροής δεν υποστηρίζεται" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Η ροή έχει κλειστεί από τον διακομιστή" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Σημειώθηκε λάθος Εισόδου/Εξόδου" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Η σύνδεση απορρίφθηκε από τον διακομιστή" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Η επίλυση του ονόματος του διακομιστή απέτυχε" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Το σύστημα εξαντλήθηκε από μνήμη" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Το πιστοποιητικό του διακομιστή δεν ήταν δυνατό να επαληθευτεί ή η χειραψία TLS δεν ολοκληρώθηκε με επιτυχία" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Ο εξυπηρετής δεν προσέφερε κρυπτογράφηση TLS" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Η ταυτοποίηση απέτυχε. Εσφαλμένος κωδικός πρόσβασης ή δεν υπάρχει αυτός ο λογαριασμός" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Ο χρήστης ή το σύστημα ζήτησε αποσύνδεση" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Δεν υπάρχει ενεργή σύνδεση" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Ο λογαριασμός σου έχει εγγραφεί με επιτυχία" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Δεν δόθηκαν όλες οι απαιτούμενες πληροφορίες" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Το όνομα χρήστη υπάρχει ήδη" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Δέν ήταν εφικτή η εγγραφή εξωτερικής λειτουργείας mod.json για την συμπιεσμένη λειτουργία '%s'. Η λειτουργία θα πρέπει να ξανα εγκατασταθεί." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Αποτυχία κατά την έναρξη της εξέτασης του αναγνωριστικού του παιχνιδιού. Σφάλμα: %s, %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Αποτυχία κατά την έναρξη της εξέτασης των mods. Σφάλμα: %s,%s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Δεν μπορεί να δημιουργηθεί ο φάκελος του mod: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Δεν μπορεί να ανοίξει το προσωρινό αρχείο για τη λήψη του mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Απέτυχε να ξεκινήσει η λήψη. Σφάλμα: %s, %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Αποτυχία ασύγχρονης λήψης: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Αποτυχία Λήψης. Απόκριση διακομιστή: %s, %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Εσφαλμένο μέγεθος αρχείου." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Λάθος αρχείο. Αναμενόταν md5 %s, πίρε %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Αποτυχία υπολογισμού τελικού κατακερματισμού." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Αποτυχία επαλήθευσης υπογραφής." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Αποθήκευση παιχνιδιού στο '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Το στιγμιότυπο οθόνης αποθηκέυτηκε στο '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "προσαρμοσμένη έκδοση" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Το στιγμιότυπο οθόνης αποθηκέυτηκε στο '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/en_GB.engine.po 0ad-0.0.26/binaries/data/l10n/en_GB.engine.po --- 0ad-0.0.25b/binaries/data/l10n/en_GB.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/en_GB.engine.po 2022-09-23 19:16:31.000000000 +0000 @@ -1,18 +1,18 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Andi Chandler , 2021 -# Tanksy , 2014 -# leper , 2014-2016 -# Nescio, 2020-2021 -# Martin H , 2017 +# Andi Chandler +# Tanksy +# leper +# Nescio +# Martin H msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-06 10:33+0000\n" -"Last-Translator: Nescio\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Nescio, 2020-2021\n" "Language-Team: English (United Kingdom) (http://www.transifex.com/wildfire-games/0ad/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,32 +20,32 @@ "Language: en_GB\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Scroll speed increased to %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Scroll speed decreased to %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Rotate speed increased to X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Rotate speed decreased to X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Zoom speed increased to %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Zoom speed decreased to %.1f" @@ -54,214 +54,215 @@ msgid "Long strings" msgstr "Long strings" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "unknown subtype (see logs)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "The certificate is not trusted." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "The certificate hasn't got a known issuer." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "The certificate has been revoked." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "The certificate has expired." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "The certificate is not yet active." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "The certificate has not been issued for the peer connected to." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "The certificate signer is not a certificate authority." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Error" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "No error" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Player already logged in" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Forbidden" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Internal server error" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Not allowed" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Not authorised" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Recipient temporarily unavailable" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registration required" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Service unavailable" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Unknown error" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Stream error" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "The incoming stream version is unsupported" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "The stream has been closed by the server" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "An I/O error occurred" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "The connection was refused by the server" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Resolving the server's hostname failed" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "This system is out of memory" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "The server's certificate could not be verified or the TLS handshake did not complete successfully" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "The server did not offer required TLS encryption" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Authentication failed. Incorrect password or account does not exist" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "The user or system requested a disconnect" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "There is no active connection" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Your account has been successfully registered" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Not all necessary information provided" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Username already exists" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Could not write external mod.json for zipped mod '%s'. The mod should be reinstalled." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Failure while starting querying for game id. Error: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Failure while starting querying for mods. Error: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Could not create mod directory: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Could not open temporary file for mod download: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Failed to start the download. Error: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Asynchronous download failure: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Download failure. Server response: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Mismatched filesize." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Invalid file. Expected md5 %s, got %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Failed to compute final hash." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Failed to verify signature." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Saved game to '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Screenshot written to '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "custom build" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Screenshot written to '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/engine.pot 0ad-0.0.26/binaries/data/l10n/engine.pot --- 0ad-0.0.25b/binaries/data/l10n/engine.pot 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/engine.pot 2022-09-23 19:16:38.000000000 +0000 @@ -1,42 +1,42 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. msgid "" msgstr "" "Project-Id-Version: Pyrogenesis\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-17 07:08+0000\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"POT-Creation-Date: 2022-09-12 09:35+0000\n" +"PO-Revision-Date: 2022-09-12 09:35+0000\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:659 #, c-format msgid "Scroll speed increased to %.1f" msgstr "" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:665 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:672 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:679 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:685 #, c-format msgid "Zoom speed increased to %.1f" msgstr "" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:691 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "" @@ -45,212 +45,213 @@ msgid "Long strings" msgstr "" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "" -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "" -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "" -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "" -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "" -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "" -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "" -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 lobby/XmppClient.cpp:1466 msgid "Error" msgstr "" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not complete " "successfully" msgstr "" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:93 #, c-format msgid "Could not write external mod.json for zipped mod '%s'. The mod should be reinstalled." msgstr "" -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "" -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "" -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "" -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "" -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "" -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "" -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "" -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "" -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "" -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "" -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "" -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "" +#: renderer/Renderer.cpp:565 renderer/Renderer.cpp:568 renderer/Renderer.cpp:680 +#: renderer/Renderer.cpp:683 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "" + diff -Nru 0ad-0.0.25b/binaries/data/l10n/es.engine.po 0ad-0.0.26/binaries/data/l10n/es.engine.po --- 0ad-0.0.25b/binaries/data/l10n/es.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/es.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,68 +1,67 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Adrian Sbardella , 2014 -# Albert, 2017 -# Diego Bruschetti , 2014 -# Edgardo , 2015 -# The_Gipsy , 2018 -# Eusohj Zenitram , 2021 -# Federico Palacios , 2018 -# hola jaaj , 2017 -# Ignacio Casal , 2019 -# fca1970 , 2014 -# Juan Jaramillo , 2014-2015 -# 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-2021 -# Samuel Roman , 2016 -# Swyter ™ , 2013-2014,2016-2018 -# Swyter ™ , 2020 -# tarod kaos , 2015 +# Adrian Sbardella +# Albert +# Diego Bruschetti +# Edgardo +# The_Gipsy +# Eusohj Zenitram +# Federico Palacios +# hola jaaj +# Ignacio Casal +# fca1970 +# Juan Jaramillo +# Miguel Magdaleno Santamaría +# Mihai Pantazi +# Mikel Soutullo +# Nacho Carretero +# OJankano +# Pablo Rodríguez +# Rodrigo Vegas Sánchez-Ferrero +# Samuel Roman +# Swyter +# tarod kaos msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-11 17:46+0000\n" -"Last-Translator: Rodrigo Vegas Sánchez-Ferrero \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Rodrigo Vegas Sánchez-Ferrero, 2020-2021\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" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Velocidad de desplazamiento incrementada a %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Velocidad de desplacamiento disminuida a %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Velocidad de rotación incrementada a X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Velocidad de rotación disminuida a X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Velocidad de zoom incrementada a %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Velocidad de zoom disminuida a %.1f" @@ -71,214 +70,215 @@ msgid "Long strings" msgstr "Cadenas largas" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "Subtipo desconocido (mira los registros)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "El certificado no es de confianza." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "El certificado no pertenece a un emisor conocido." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "El certificado ha sido revocado." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "El certificado ha expirado." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "El certificado todavía no está activo." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "El certificado no ha sido emitido para el extremo con el que ha conectado." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "El firmante del certificado no es una autoridad certificadora." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Error" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Sin errores" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "El jugador ya ha iniciado sesión" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Prohibido" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "El servidor ha tenido un problema" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "No está permitido" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Sin autorización" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Destinatario temporalmente fuera de servicio" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Primero tienes que registrarte" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Fuera de servicio" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Error desconocido" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Error de envío" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "La versión del mensaje recibido no se soporta" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "El servidor ha cortado la comunicación" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Se ha producido un error de E/S" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "El servidor ha rechazado la comunicación" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "No se ha podido resolver el nombre del servidor" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "El sistema no tiene suficiente memoria" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "No se pudo verificar el certificado del servidor o no se completó la conexión del todo" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "El servidor no ofrece cifrado TLS, que es necesario por seguridad" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Fallo de autenticación. Contraseña incorrecta o cuenta inexistente" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "El usuario o el sistema han pedido desconectarse" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "No hay ninguna conexión activa" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Tu cuenta se ha creado con éxito" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "No se ha proporcionado toda la información necesaria" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "El nombre de usuario ya existe" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "No se puede escribir un mod.json externo para el mod comprimido '%s'. El mod debe ser reinstalado." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Error al comenzar la solicitud para el id. del juego. Error: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Error al iniciar la búsqueda de mods. Error: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "No se ha podido crear el directorio de mods: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "No se ha podido abrir el archivo temporal para la descarga del mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Error al iniciar la descarga: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Error de sincronía en la descarga: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Error en la descarga. Respuesta del servidor: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "El tamaño del archivo no coincide." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Archivo incorrecto. Se esperaba el siguiente md5: %s y se ha obtenido: %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Error al calcular el hash final." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Error al verificar la firma." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Partida guardada en «%s»" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "La captura de pantalla se ha guardado en «%s»" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "versión propia" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "La captura de pantalla se ha guardado en «%s»" diff -Nru 0ad-0.0.25b/binaries/data/l10n/eu.engine.po 0ad-0.0.26/binaries/data/l10n/eu.engine.po --- 0ad-0.0.25b/binaries/data/l10n/eu.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/eu.engine.po 2022-09-23 19:16:34.000000000 +0000 @@ -1,18 +1,17 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Ibai Oihanguren Sala , 2014 -# Gontzal M. Pujana , 2016 -# Mielanjel Iraeta , 2017-2018,2021 -# Osoitz , 2015,2019-2020 -# Gontzal M. Pujana , 2016 +# Ibai Oihanguren Sala +# Thadah D. Denyse +# Mielanjel Iraeta +# Osoitz msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-21 17:07+0000\n" -"Last-Translator: Mielanjel Iraeta \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Mielanjel Iraeta , 2017-2018,2021\n" "Language-Team: Basque (http://www.transifex.com/wildfire-games/0ad/language/eu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,32 +19,32 @@ "Language: eu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Mugitze abiadura haraino igo da %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Mugitze abiadura haraino jaitsi da %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Biratze abiadura handituta X=%.3f, Y= %.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Biratze abiadura gutxituta X= %.3f, Y= %.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Zoomaren abiadura haraino igo da %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Zoomaren abiadura haraino jaitsi da %.1f" @@ -54,214 +53,215 @@ msgid "Long strings" msgstr "Kate luzeak" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "azpimota ezezaguna (ikusi egunkariak)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Ziurtagiria ez da fidagarritzat jotzen." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Ziurtagiriak ez du argitaratzaile ezagun bat." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Ziurtagiria baliogabetu da." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Ziurtagiriak iraungi du." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Ziurtagiria ez dago aktibo oraindik." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Ziurtagiria ez da konektatutako honentzat argitaratu." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Ziurtagiriaren sinatzailea ez da ziurtagiriak argitaratzeko elkarte bat." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Errorea" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Ez dago errorerik" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Jokalaria jadanik barruan" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Debekatuta" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Barne zerbitzari errorea" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Ez da zilegi" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Baimendu gabea" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Hartzailea ez dago momentuz eskuragarri" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Izen ematea ezinbestekoa" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Zerbitzua ez dago eskuragarri" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Errore ezezaguna" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Fluxu errorea" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Heldu den fluxu bertsioa ez da jasangarria" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Fluxua zerbitzariarengatik itxia izan da" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "S/I errore bat gertatu da" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Konexioa zerbitzariarengatik errefuxatuta" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Errorea zerbitzariaren host izena ebaztean" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Sistema hau memoria gabe dago" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Zerbitzariaren zertifikatua ezin izan da balioztatu edo TLS handshake-a ez da ondo burutu" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Zerbitzariak ez du beharrezko TLS enkripzioa erabili" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Errorea autentifikazioan. Pasahitza okerra da edo kontua ez da existitzen" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Erabiltzaileak edo sistemak deskonektatzeko eskaria bidali du" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Ez dago konexio aktiborik" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Zure kontua ondo erregistratu da" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Ez da beharrezko informazio guztia eman" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Erabiltzaile izena erabilpean" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Ezin izan da kanpoko mod.json idatzi mod-zipperako \"%s'. Mod berriro instalatu behar da." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Jokalariaren IDa kontsultatzen hasi bitartean huts egin du. Akatsa: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Mod-ak kontsultatzen hasi bitartean huts egin du. Akatsa: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Ezin izan da mod direktorioa sortu: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Ezin izan da aldi baterako fitxategia ireki mod deskargatzeko: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Ezin izan da deskargatzen hasi. Akatsa: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Deskarga asinkronoak huts egin du: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Deskargak huts egin du. Zerbitzariaren erantzuna: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Bat ez datorren fitxategi tamaina." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Fitxategi baliogabea. Espero izandako md5 %s-tik%slortuta." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Ezin izan da azken hash kalkulatu." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Sinadura egiaztatzean huts egin du." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Gorde partida hemen '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Pantaila-argazkia hemen gorde da '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "konpilazio pertsonalizatua" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Pantaila-argazkia hemen gorde da '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/fi.engine.po 0ad-0.0.26/binaries/data/l10n/fi.engine.po --- 0ad-0.0.25b/binaries/data/l10n/fi.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/fi.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,24 +1,24 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# linux_eki , 2013-2014,2016,2018 -# Järvi Eduardo , 2018 -# Jiri Grönroos , 2019 -# Matti Tuhola, 2021 -# Max Ihalempia, 2016 -# Oi Suomi On! , 2020 -# Olavi Tuomaala , 2015 -# Pauli Kaikkonen , 2016 -# Petri, 2014 -# Riku Viitanen , 2015 -# Some Dude , 2018 +# linux_eki +# Järvi Eduardo +# Jiri Grönroos +# Matti Tuhola +# Max Ihalempia +# Oi Suomi On! +# Olavi Tuomaala +# Pauli Kaikkonen +# Petri +# Riku Viitanen +# Some Dude msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-22 09:55+0000\n" -"Last-Translator: Matti Tuhola\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Jiri Grönroos , 2019,2021\n" "Language-Team: Finnish (http://www.transifex.com/wildfire-games/0ad/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -26,32 +26,32 @@ "Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Vieritysnopeutta nostettu arvoon %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Vieritysnopeutta laskettu arvoon %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Kiertonopeutta nostettu arvoon X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Kiertonopeutta laskettu arvoon X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Zoomausnopeutta nostettu arvoon %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Zoomausnopeutta laskettu arvoon %.1f" @@ -60,214 +60,215 @@ msgid "Long strings" msgstr "Long strings" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "tuntematon alatyyppi (ks. lokit)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Varmenteeseen ei luoteta." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Varmenteella ei ole tunnettua julkaisijaa." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Varmenne on kumottu." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Varmenne on vanhentunut." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Varmennetta ei ole vielä toimeenpantu." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Varmennetta ei ole julkaistu yhdistettyyn vertaiseen." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Varmenteen allekirjoittaja ei ole varmennevaltuuksinen." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Virhe" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Ei virhettä" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Pelaaja on jo kirjautunut sisään" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Kielletty" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Palvelimen sisäinen virhe" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Ei sallittu" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Ei luvallinen" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Vastaanottaja ei ole väliaikaisesti saatavilla." -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Rekisteröinti vaaditaan" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Palvelu ei ole saatavilla" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Tuntematon virhe" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Striimivirhe" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Tuleva striimiversion ei ole tuettu" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Striimi on suljettu palvelimen toimesta" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Tapahtui I/O-virhe" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Palvelin hylkäsi yhteyden" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Palvelimen isäntänimen selvitys epäonnistui" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Tällä systeemillä ei ole tarpeeksi muistia" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" -msgstr "Palvelimen sertifikaattia ei voitu todentaa tai TLS-kättely epäonnistui" +msgstr "Palvelimen varmennetta ei voitu todentaa tai TLS-kättely epäonnistui" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Palvelin ei tarjonnut vaadittavaa TLS-salausta" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Tunnistautuminen epäonnistui. Salasana on väärä tai käyttäjätunnusta ei ole olemassa" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Käyttäjä tai järjestelmä pyysi yhteyskatkaisua" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Ei aktiivista yhteyttä" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Käyttäjäsi on rekisteröity onnistuneesti" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Pakollisia tietoja puuttuu" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Käyttäjänimi on jo olemassa" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Ulkoisen mod.json-tiedoston kirjoittaminen zip-pakatulle modille '%s' epäonnistui. Modi täytyy asentaa uudelleen." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Epäonnistuminen aloittaessa pelin tunnisteen kyselyä. Virhe: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Epäonnistuminen aloitaessa modien kyselyä. Virhe: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Modihakemistoa ei voitu luoda: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Ei voitu avata väliaikaista tiedostoa modin latausta varten: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Latauksen aloitus epäonnistui. Virhe:%s;%s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Asynkroninen latausvirhe: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Lataus epäonnistui. Palvelimen vastaus: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Eriävät tiedostokoot." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Virheellinen tiedosto. Odotettiin md5:ttä %s, saatiin %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Lopullisen tiivisteen laskeminen epäonnistui." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Allekirjoitusta ei voitu varmistaa." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Peli tallennettu sijaintiin '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Kuvankaappaus tallennettu sijaintiin '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "custom build" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Kuvankaappaus tallennettu sijaintiin '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/fr.engine.po 0ad-0.0.26/binaries/data/l10n/fr.engine.po --- 0ad-0.0.25b/binaries/data/l10n/fr.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/fr.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,66 +1,66 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Arthur Jaouen , 2015 -# benjamin jasse , 2020 -# Cajetan Bouchard , 2014 -# Cyril Mercier, 2019 -# François Poirotte , 2016 -# gZen , 2014 -# Hadri man , 2018 -# Jo Du , 2021 -# Mortimer , 2018 -# Nexus nexus , 2016 -# Nicolas Auvray , 2013-2016 -# Olivier , 2013 -# PRIME Gildas , 2013 -# Raz Ou , 2021 -# b90660521634a3a6bfb9ed72c661dd1d_37387b4, 2014 -# Simon Georges , 2014 -# Polakrity , 2017-2018 -# Loki , 2013 -# tutosfaciles 48 , 2019 -# Xavier Tardieu , 2016,2021 +# Arthur Jaouen +# benjamin jasse +# Cajetan Bouchard +# Cyril Mercier +# François Poirotte +# gZen +# Hadri man +# Jo Du +# Mortimer +# Nexus nexus +# Nicolas Auvray +# Olivier +# PRIME Gildas +# Raz Ou +# b90660521634a3a6bfb9ed72c661dd1d_37387b4 +# Simon Georges +# Polakrity +# Loki +# tutosfaciles 48 +# Xavier Tardieu msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-07-26 05:32+0000\n" -"Last-Translator: Xavier Tardieu \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Xavier Tardieu , 2016,2021\n" "Language-Team: French (http://www.transifex.com/wildfire-games/0ad/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Vitesse de défilement augmentée à %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Vitesse de défilement diminuée à %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Vitesse de rotation augmentée à X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Vitesse de rotation diminuée à X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Vitesse de zoom augmentée à %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Vitesse de zoom diminuée à %.1f" @@ -69,214 +69,215 @@ msgid "Long strings" msgstr "Chaînes longues" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "sous-type inconnu (voir les journaux)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Le certificat n'est pas approuvé." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Le certificat n'a pas d'émetteur connu." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Le certificat a été révoqué." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Le certificat a expiré." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Le certificat n'est pas encore actif." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Le certificat n'a pas été émis pour le pair connecté." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Le signataire du certificat n'est pas une autorité de certification." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Erreur" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Pas d’erreur" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Joueur déjà connecté" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Interdit" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Erreur interne du serveur" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Interdit" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Non autorisé" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Destinataire temporairement indisponible" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Inscription nécessaire" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Service indisponible" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Erreur inconnue" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Erreur de flux" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "La version du flux entrant n'est pas prise en charge" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Le flux a été fermé par le serveur" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Une erreur d'E/S est survenue" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "La connexion a été refusée par le serveur" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "La résolution du nom d’hôte du serveur a échoué" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Le système n'a plus assez de mémoire" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Le certificat du serveur n'a pas pu être vérifié, ou la poignée de main TLS n'a pas abouti" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Le serveur n'a pas fourni le cryptage TLS requis" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "L’authentification a échoué. Mot de passe incorrect ou compte non existant" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "L’utilisateur ou le système a demandé une déconnexion" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Il n’y a pas de connexion active" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Votre compte a été enregistré avec succès" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Toutes les informations nécessaires n’ont pas été fournies " -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Nom d’utilisateur déjà utilisé" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Impossible d'écrire le mod.json pour le mod zippé %s. Le mod devrait être réinstallé. " -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Échec lors du démarrage de la requête de l'identifiant de jeu. Erreur : %s ; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Échec lors du démarrage de recherche de mods. Erreur : %s ; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Impossible de créer le dossier du mod : %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Impossible d'ouvrir le fichier temporaire pour le téléchargement du mod : %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Impossible de démarrer le téléchargement. Erreur : %s ; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Échec du téléchargement asynchrone : %s ; %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Échec du téléchargement. Réponse du serveur : %s ; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Incohérence dans la taille du fichier." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Fichier invalide. md5 attendu : %s, md5 reçu : %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Échec du calcul du hash final." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Échec de la vérification de la signature." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Partie sauvegardée dans '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Capture d'écran enregistrée sous '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "custom build" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Capture d'écran enregistrée sous '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/gd.engine.po 0ad-0.0.26/binaries/data/l10n/gd.engine.po --- 0ad-0.0.25b/binaries/data/l10n/gd.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/gd.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,16 +1,14 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# GunChleoc, 2013-2014,2016,2018 -# GunChleoc, 2015 -# GunChleoc, 2015 +# GunChleoc msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-24 11:00+0000\n" -"Last-Translator: GunChleoc\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: GunChleoc, 2015\n" "Language-Team: Gaelic, Scottish (http://www.transifex.com/wildfire-games/0ad/language/gd/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,32 +16,32 @@ "Language: gd\n" "Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Chaidh luaths an sgrolaidh a mheudachadh gu %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Chaidh luaths an sgrolaidh a lùghdachadh gu %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Chaidh luaths a’ chuairteachaidh a mheudachadh gu X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Chaidh luaths a’ chuairteachaidh a lùghdachadh gu X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Chaidh luaths an t-sùmaidh a mheudachadh gu %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Chaidh luaths an t-sùmaidh a lùghdachadh gu %.1f" @@ -52,214 +50,215 @@ msgid "Long strings" msgstr "Sreangan fada" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "fo-sheòrsa nach aithne duinn (thoir sùil air na logaichean)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Chan eil earbsa san teisteanas seo." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Chan eil foillsichear aithnichte aig an teisteanas seo." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Chaidh an teisteanas a chùl-ghairm." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Dh’fhalbh an ùine air an teisteanas." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Chan eil an teisteanas gnìomhach fhathast." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Cha deach an teisteanas fhoillseachadh dhan t-seise a chaidh a cheangal ris." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Chan eil foillsichear an teisteanais ’na ùghdarras teisteanachaidh." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Mearachd" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Gun mhearachd" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Tha an cluicheadair air a chlàradh a-steach mar-thà" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Toirmisgte" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Mearachd taobh a-staigh an fhrithealaiche" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Chan eil seo ceadaichte" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Tha cead a dhìth" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Chan eil am faighteir ann rè seal" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Tha clàradh riatanach" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Chan eil an t-seirbheis seo ri làimh" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Mearachd nach aithne dhuinn" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Mearachd sruthaidh" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Cha chuirear taic ris an tionndadh dhen t-sruth a-steach" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Chaidh an sruth a dhùnadh leis an fhrithealaiche" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Thachair mearachd le ion- no às-chur" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Chaidh an ceangal a dhiùltadh leis an fhrithealaiche" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Cha deach leinn ainm-òstair an fhrithealaiche fhuasgladh" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Chan eil cuimhne air fhàgail air an t-siostam" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Cha deach leinn teisteanas an fhrithealaiche a dhearbhadh no cha deach an crathadh-làimhe TLS a choileanadh" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Cha do thairg am frithealaiche an crioptachadh TLS riatanach" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Dh’fhàillig leis an dearbhadh. Chan eil am facal-faire mar bu chòir no chan eil an cunntas ann" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Dh’iarr an cleachdaiche no an siostam briseadh a’ cheangail" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Chan eil ceangal gnìomhach ann" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Chaidh an cunntas agad a chlàradh" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Cha deach gach fiosrachadh riatanach a sholar" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Tha am far-ainm ann mar-thà" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Cha b’ urrainn dhuinn am mod.json air an taobh a-muigh a sgrìobhadh dhan tuilleadan dùmhlaichte “%s”. Bu chòir dhut an tuilleadan ath-stàladh." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Thachair mearachd nuair a bha sinn ag iarraidh aithnichear a’ gheama. Mearachd: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Thachair mearachd nuair a bha sinn ag iarraidh fiosrachadh nan tuilleadan. Mearachd: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Cha b’ urrainn dhuinn pasgan nan tuilleadan a chruthachadh: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Cha b’ urrainn dhuinn faidhle sealach fhosgladh airson tuilleadan a luchdadh a-nuas: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Cha b’ urrainn dhuinn tòiseachadh air an luchdadh a-nuas. Mearachd: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Dh’fhàillig le luchdadh a-nuas neo-shioncronaichte: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Dh’fhàillig leis an luchdadh a-nuas. Freagairt an fhrithealaiche: %s, %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Chan eil meud nam faidhle a-rèir a chèile." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Faidhle mì-dhligheach. An dùil air md5 %s, ach fhuair sinn %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Cha deach leinn an hais dheireannach àireamhachadh." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Cha deach leinn an soidhneadh a dhearbhadh." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Chaidh an geama a shàbhaladh gu “%s”" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Chaidh an glacadh-sgrìn a shàbhaladh gu “%s”" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "togail ghnàthaichte" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Chaidh an glacadh-sgrìn a shàbhaladh gu “%s”" diff -Nru 0ad-0.0.25b/binaries/data/l10n/hu.engine.po 0ad-0.0.26/binaries/data/l10n/hu.engine.po --- 0ad-0.0.25b/binaries/data/l10n/hu.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/hu.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,27 +1,24 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Balázs Meskó , 2015,2018-2019 -# Balázs Meskó , 2020 -# Balázs Úr, 2015-2016 -# 12dde84ca529f511e7ad8b70de73f71c_b688a04 <2328b4f5662bb45a5de7adc879cc0db2_206283>, 2015 -# 12dde84ca529f511e7ad8b70de73f71c_b688a04 <2328b4f5662bb45a5de7adc879cc0db2_206283>, 2014-2015 -# 12dde84ca529f511e7ad8b70de73f71c_b688a04 <2328b4f5662bb45a5de7adc879cc0db2_206283>, 2014 -# Gyuris Gellért , 2016 -# Márk Kerekes , 2015 -# Peter Darvasi , 2014 -# Péter Dóbé , 2017 -# Pista Joska , 2016 -# Stew Den , 2014 -# Tibor Buzási, 2015 -# Tibor Buzási, 2015 +# Balázs Meskó +# Balázs Úr +# 12dde84ca529f511e7ad8b70de73f71c_b688a04 +# Gyuris Gellért +# Márk Kerekes +# Peter Darvasi +# Péter Dóbé +# Pista Joska +# Scael Blu +# Stew Den +# Tibor Buzási msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-17 10:18+0000\n" -"Last-Translator: Transifex Bot <>\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Balázs Meskó , 2020-2021\n" "Language-Team: Hungarian (http://www.transifex.com/wildfire-games/0ad/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -29,248 +26,249 @@ "Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" -msgstr "" +msgstr "Növelt görgetési sebesség: %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "" +msgstr "Csökkentett görgetési sebesség: %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" -msgstr "" +msgstr "Növelt forgatási sebesség: X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" -msgstr "" +msgstr "Csökkentett forgatási sebesség: X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" -msgstr "" +msgstr "Növelt nagyítási sebesség: %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "" +msgstr "Csökkentett nagyítási sebesség: %.1f" #: i18n/L10n.cpp:308 msgid "Long strings" msgstr "Hosszú szövegek" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "ismeretlen altípus (lásd a naplókat)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "A tanúsítvány nem megbízható." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "A tanúsítvány kiállítója ismeretlen." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "A tanúsítvány visszavonásra került." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "A tanúsítvány lejárt." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "A tanúsítvány még nem érvényes." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "A tanúsítvány nem a partner részére lett kiállítva." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "A tanúsítvány kiállítója nem hitelesítésszolgáltató." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Hiba" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Nincs hiba" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "A játékos már be van jelentkezve" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Megtagadva" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Belső kiszolgálóhiba" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Nem engedélyezett" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Nem jogosult" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "A címzett átmenetileg nem érhető el" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Regisztráció szükséges" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "A szolgáltatás nem érhető el" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Ismeretlen hiba" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Adatfolyam hiba" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "A bejövő adatfolyam verziója nem támogatott" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "A kiszolgáló lezárta az adatfolyamot" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "I/O hiba történt" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "A kiszolgáló visszautasította a kapcsolatot" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "A kiszolgáló gépnevének feloldása sikertelen" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "A rendszer memóriája elfogyott" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "A kiszolgáló tanúsítványa nem ellenőrizhető, vagy a TLS kézfogás sikertelen volt" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "A kiszolgáló nem biztosította a szükséges TLS titkosítást" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "A hitelesítés sikertelen. Érvénytelen jelszó vagy a fiók nem létezik." -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "A felhasználó vagy a rendszer szétkapcsolást kért" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Nincs aktív kapcsolat" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "A fiók sikeresen regisztrálva lett" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Nincs minden szükséges információ megadva" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "A felhasználónév már létezik" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "" +msgstr "A külső mod.json nem írható a(z) „%s” tömörített modnál. A modot újra kellene telepíteni." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "A játékazonosító lekérdezésének megkezdése meghiúsult. Hiba: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "A módosítások lekérdezése meghiúsult. Hiba: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Nem hozható létre módosítás könyvtár: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Nem nyitható meg ideiglenes fájl a módosítás letöltéséhez: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "A letöltés megkezdése meghiúsult. Hiba: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Az aszinkron letöltés meghiúsult: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Letöltési hiba. A kiszolgáló válasza: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Nem egyező fájlméret." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Érvénytelen fájl. Várt md5: %s, kapott: %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "A végső ellenőrzőösszeg kiszámítása meghiúsult." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Az aláírás ellenőrzése meghiúsult." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Játék elmentve ide: „%s”" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Képernyőkép elmentve ide: „%s”" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "egyéni verzió" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Képernyőkép elmentve ide: „%s”" diff -Nru 0ad-0.0.25b/binaries/data/l10n/id.engine.po 0ad-0.0.26/binaries/data/l10n/id.engine.po --- 0ad-0.0.25b/binaries/data/l10n/id.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/id.engine.po 2022-09-23 19:16:34.000000000 +0000 @@ -1,31 +1,23 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Adhika Setya Pramudita , 2016 -# Ahmad Rifa'i Faiz , 2020 -# Aziz Rahmad , 2021 -# Aziz Rahmad , 2021 -# Dito Kurnia Pratama , 2018 -# Eggar Tirtayasa , 2014 -# Ilham Nur Pratama , 2017 -# Joshua Randiny , 2016 -# Joshua Randiny , 2014-2015 -# Joshua Randiny , 2017 -# Joshua Randiny , 2014,2016-2017 -# Joshua Randiny , 2014 -# Muhammad Furqon Abrori , 2020 -# Samuel , 2016 -# Samuel , 2016-2017 -# Eggar Tirtayasa , 2014 -# Yusufabdiauzan , 2014 -# Yusufabdiauzan , 2014 +# Adhika Setya Pramudita +# Ahmad Rifa'i Faiz +# Aziz Rahmad +# Dito Kurnia Pratama +# Eggar Tirtayasa +# Ilham Nur Pratama +# Joshua Randiny +# Muhammad Furqon Abrori +# Samuel +# Yusufabdiauzan msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-07-02 03:26+0000\n" -"Last-Translator: Aziz Rahmad \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Aziz Rahmad , 2021\n" "Language-Team: Indonesian (http://www.transifex.com/wildfire-games/0ad/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -33,32 +25,32 @@ "Language: id\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Kecepatan gulir bertambah menjadi %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Kecepatan gulir berkurang menjadi %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Kecepatan putar bertambah menjadi X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Kecepatan putar berkurang menjadi X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Kecepatan pembesaran bertambah menjadi %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Kecepatan pembesaran berkurang menjadi %.1f" @@ -67,214 +59,215 @@ msgid "Long strings" msgstr "Tulisan panjang" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "subtipe tak dikenali (lihat log)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Sertifikat tidak dipercaya." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Sertifikat belum memiliki pembuat yang dikenal." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Sertifikat telah dicabut." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Sertifikat telah kadaluwarsa." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Sertifikat belum aktif." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Sertifikat belum diisukan untuk dihubungkan." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Pengesah sertifikat bukan pemilik sertifikat." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Kesalahan" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Tidak ada kesalahan" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Pemain sudah masuk" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Dilarang" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Masalah server internal" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Tidak diizinkan" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Tidak diotorisasi" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Penerima sementara tak tersedia" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Pendaftaran dibutuhkan" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Servis tidak tersedia" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Kesalahan tidak diketahui" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Kesalahan stream" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Versi stream yang masuk tidak didukung" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Stream ini telah ditutup oleh server" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Sebuah kesalahan I/O terjadi." -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Koneksi ditolak oleh server" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Penyelesaian nama server (hostname) gagal" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Sistem ini kehabisan memori" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Sertifikat server tidak dapat diverifikasi atau handshake TLS tidak selesai sempurna" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Server ini tidak mewajibkan enkripsi TLS" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Autentikasi gagal. Sandi salah atau akun tidak ada" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Pengguna atau sistem meminta pemutusan koneksi" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Tidak ada koneksi aktif" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Akun Anda berhasil didaftarkan" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Tidak semua informasi yang dibutuhkan diberikan" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Nama pengguna sudah ada" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Tidak dapat menulis mod.json external untuk mod terkompresi '%s'. Mod harus dipasang ulang." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Gagal saat memulai permintaan untuk id permainan. Kesalahan: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Gagal saat memulai permintaan untuk mod. Eror: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Tidak dapat membuat direktori mod: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Tidak dapat membuka berkas sementara untuk mengunduh mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Gagal memulai unduhan. Kesalahan: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Kegagalan unduhan tidak sinkron: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Gagal mengunduh. Respon server: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Ukuran berkas tidak cocok." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Berkas tidak sah. Seharusnya md5 %s, yang didapat %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Gagal menghitung hash akhir." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Gagal memverifikasikan tanda tangan." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Permainan disimpan ke '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Tangkapan layar disimpan ke '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "versi modifikasi" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Tangkapan layar disimpan ke '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/it.engine.po 0ad-0.0.26/binaries/data/l10n/it.engine.po --- 0ad-0.0.25b/binaries/data/l10n/it.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/it.engine.po 2022-09-23 19:16:45.000000000 +0000 @@ -1,65 +1,66 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Angelica Buonaurio , 2021 -# Christian Bellagamba , 2018 -# Claudio , 2015 -# SecondCloud500 , 2014 -# Fabio Pedretti , 2013-2014 -# Federico D'Alessio , 2018 -# George Lungu , 2018 -# Giulio Sanzone , 2016 -# Giuseppe D'Addio , 2019-2021 -# Italang, 2019 -# mattia_b89 , 2018 -# c5f3de31f3a2c4018f39966fa6563659_5b320d0, 2015-2017 -# Michele Marongiu , 2017 -# Nicola Jelmorini, 2014 -# rib ezz , 2021 -# SebastianoPistore , 2016 -# Damtux, 2013 -# andreac , 2015 -# a4278626e7142dff5ac755d9a5d2ad90_30a632c <3f9f2372eaf123b2e5436ebdc07dae53_123549>, 2013 +# Angelica Buonaurio +# Christian Bellagamba +# Claudio +# SecondCloud500 +# Fabio Pedretti +# Federico D'Alessio +# Gabriele Parini +# George Lungu +# Giulio Sanzone +# Giuseppe D'Addio +# Italang +# mattia_b89 +# c5f3de31f3a2c4018f39966fa6563659_5b320d0 +# Michele Marongiu +# Nicola Jelmorini +# rib ezz +# SebastianoPistore +# Damtux +# andreac +# a4278626e7142dff5ac755d9a5d2ad90_30a632c msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-15 23:29+0000\n" -"Last-Translator: Giuseppe D'Addio \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Gabriele Parini , 2021\n" "Language-Team: Italian (http://www.transifex.com/wildfire-games/0ad/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Velocità di scorrimento aumentata del %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "Velocità di scorrimento ridotta del %.1f" +msgstr "Velocità di scorrimento diminuita del %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Velocità di rotazione aumentata del X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Velocità di rotazione ridotta del X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Velocità dello zoom aumentata del %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Velocità dello zoom ridotta del %.1f" @@ -68,214 +69,215 @@ msgid "Long strings" msgstr "Stringhe Lunghe" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "sottotipo sconosciuto (vedi registri)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Certificato inaffidabile." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Proprietario del certificato ignoto." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Il certificato è stato revocato." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Il certificato è scaduto." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Il certificato non è ancora attivo." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Certificato non collegato a un peer." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Firmante del certificato non presente nella sua autorità." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Errore" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Nessun errore" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Giocatore già connesso" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Vietato" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Errore interno al server" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Non permesso" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Non autorizzato" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Destinatario temporaneamente non disponibile" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registrazione richiesta" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Servizio non disponibile" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Errore sconosciuto" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Errore di flusso" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "La versione del flusso in ingresso non è supportata" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Il flusso è stato chiuso dal server" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Si è verificato un errore di I/O" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "La connessione è stata rifiutata dal server" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Risoluzione dell'hostname del server fallita" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Questo sistema non dispone di memoria sufficiente" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Il certificato del server non può essere verificato o la negoziazione TLS non è stato completo con successo" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Il server non supportava la crittografia TLS richiesta" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Autenticazione fallita. Password errata o account inesistente" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "L'utente o il sistema hanno richiesto una disconnessione " -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Non c'è connessione attiva" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Il tuo account è stato registrato con successo" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Non sono state fornite tutte le informazioni necessarie" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Nome utente già esistente" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Impossibile scrivere mod.json esterna per la mod '%s'. La mod andrà reinstallata." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Errore durante la richiesta del id gioco: Errore:%s;%s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Errore durante il caricamento delle mod. Errore: %s;%s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Errore durante la creazione della cartella mod: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Errore durante l'apertura di un file temporaneo per il download della mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Errore all'avvio del download. Errore: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Errore di sincronizzazione durante il download: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Errore durante il download. Risposta del server: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "La dimensione del file non corrisponde." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "File non valido. Md5 previsto %s, ottenuto %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Errore nel calcolo dell'ultimo hash." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Errore nella verifica della firma." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Gioco salvato in '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Schermata salvata in '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "personalizzata" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Schermata salvata in '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/nl.engine.po 0ad-0.0.26/binaries/data/l10n/nl.engine.po --- 0ad-0.0.25b/binaries/data/l10n/nl.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/nl.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,35 +1,27 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Bart , 2020 -# Bart , 2020-2021 -# Charon De Beukelaer , 2015 -# Ellen Roels, 2015 -# Ellen Roels, 2015 -# Freagarach, 2021 -# Freagarach, 2019 -# Jan Jasper de Kroon , 2019 -# Marijn Billiet , 2018 -# MathiasB, 2013 -# MathiasB, 2013 -# Michiel Franssen , 2018 -# niektb , 2014,2016 -# niektb , 2014 -# tnt, 2013 -# Sander Deryckere, 2013 -# Sander Deryckere, 2013-2014 -# Sander Deryckere, 2014,2016 -# Stef Jansen , 2014 -# tnt, 2013 -# Spijker , 2017 -# Yannick Vanroy , 2014 +# rollieoo +# Charon De Beukelaer +# Ellen Roels +# Freagarach +# Jan Jasper de Kroon +# Marijn Billiet +# MathiasB +# Michiel Franssen +# niektb +# tnt +# Sander Deryckere +# Stef Jansen +# Spijker +# Yannick Vanroy msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-18 08:51+0000\n" -"Last-Translator: Bart \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: rollieoo, 2022\n" "Language-Team: Dutch (http://www.transifex.com/wildfire-games/0ad/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -37,32 +29,32 @@ "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Scrollsnelheid toegenomen tot %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Scrollsnelheid afgenomen tot %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Rotatiesnelheid toegenomen tot X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Rotatiesnelheid afgenomen tot X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Zoomsnelheid toegenomen tot %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Zoomsnelheid afgenomen tot %.1f" @@ -71,214 +63,215 @@ msgid "Long strings" msgstr "Lange teksten" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "Onbekend subtype (zie logboek)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." -msgstr "Het certificaat is niet vertrouwd." +msgstr "Het is geen vertrouwd certificaat." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Het certificaat is niet uitgegeven door een bekende verstrekker." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Het certificaat is ingetrokken." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Het certificaat is verlopen." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Het certificaat is nog niet actief." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." -msgstr "Het certificaat is niet verstrekt voor de partij waarmee je verbindt." +msgstr "Het certificaat is niet verstrekt voor de partij waarmee U verbindt." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." -msgstr "De ondertekenaar van het certificaat is geen gecertificeerde autoriteit." +msgstr "De ondertekenaar van het certificaat is geen certificatie-autoriteit." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Foutmelding" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Geen foutmelding" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Speler is al ingelogd" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Verboden" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Interne server fout" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Niet toegestaan" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Niet bevoegd" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Ontvanger is tijdelijk niet beschikbaar" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registratie vereist" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Service onbeschikbaar" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Onbekende foutmelding" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" -msgstr "Foutmelding systeem" +msgstr "Foutmelding stream" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "De inkomende streamversie wordt niet ondersteund" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Het systeem is afgesloten door de server" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Er is een I/O fout opgetreden" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "De verbinding is geweigerd door de server" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Het ophalen van de server hostname is mislukt" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Dit systeem heeft geen geheugen meer over" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Het certificaat van de server kan niet worden geverifieerd of de TLS handshake is niet succesvol voltooid" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" -msgstr "De server biedt niet de juiste TLS beveiliging" +msgstr "De server biedt niet de vereiste TLS encryptie" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Verificatie mislukt. Verkeerd wachtwoord of de gebruiker bestaat niet" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" -msgstr "De gebruiker of het systeem vroeg om de verbinding te verbreken" +msgstr "De gebruiker of het systeem vroeg de verbinding te verbreken" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Er is geen actieve verbinding" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Uw account is succesvol geregistreerd" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Niet alle noodzakelijke informatie is aanwezig" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Gebruikersnaam bestaat al" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "De externe mod '%s' kon niet uitgepakt worden. Installeer de mod opnieuw." +msgstr "De ingepakte mod '%s' kon niet opgeslagen worden. Installeer de mod opnieuw." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Fout tijdens het ophalen van het spel id. Fout:%s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Fout tijdens het ophalen van de lijst met mods. Fout: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Kon geen mod folder aanmaken: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Kon geen tijdelijk bestand aanmaken voor het downloaden van de mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Fout tijdens het starten van de download. Fout: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." -msgstr "Asynchroon downloaden gefaald: %s, %s." +msgstr "Asynchroon downloaden mislukt: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." -msgstr "Downloaden gefaald. Server respons: %s, %s." +msgstr "Downloaden mislukt. Server respons: %s, %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Bestandsgrootte is niet gelijk" -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Ongeldig bestand. Verwacht MD5 hash %s, maar kreeg %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." -msgstr "Niet geslaagd om de hash code te berekenen." +msgstr "Kon de hash code niet berekenen." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." -msgstr "Niet geslaagd om de handtekening te controleren." +msgstr "Kon de handtekening niet controleren." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Spel opgeslagen als \"%s\"" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Screenshot opgeslagen als \"%s\"" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "op maat gemaakt" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Screenshot opgeslagen als \"%s\"" diff -Nru 0ad-0.0.25b/binaries/data/l10n/pl.engine.po 0ad-0.0.26/binaries/data/l10n/pl.engine.po --- 0ad-0.0.25b/binaries/data/l10n/pl.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/pl.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,29 +1,29 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Bartosz Bobin , 2018 -# 8f109d0108020ab645eeb99d9e707e29_098f6ba , 2014 -# e9706534be4a728ed4e67375991e760b_b69146a <22edc3ec7a0ff9ecf360faca25adb468_671791>, 2018 -# Kamil Grela , 2018 -# TotalNoobPL , 2013 -# Leszek Szary, 2014 -# Lukasz B , 2016 -# Marcin S , 2021 -# Michał Garapich , 2013 -# Michał Karol, 2017 -# miragae , 2014-2015 -# zyxist , 2014 -# Piotr Lehmann , 2017 -# Przemysław Murach , 2019-2021 -# filux , 2013 -# tombox , 2016 +# Bartosz Bobin +# 8f109d0108020ab645eeb99d9e707e29_098f6ba +# e9706534be4a728ed4e67375991e760b_b69146a +# Kamil Grela +# TotalNoobPL +# Leszek Szary +# Lukasz B +# Marcin S +# Michał Garapich +# Michał Karol +# miragae +# zyxist +# Piotr Lehmann +# Przemysław Murach +# filux +# tombox msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-03 10:37+0000\n" -"Last-Translator: Marcin S \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Marcin S , 2021\n" "Language-Team: Polish (http://www.transifex.com/wildfire-games/0ad/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,32 +31,32 @@ "Language: pl\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Szybkość przewijania zwiększona do %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Szybkość przewijania zmniejszona do %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Szybkość obracania zwiększona do X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Szybkość obracania zmniejszona do X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Szybkość przybliżania zwiększona do %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Szybkość przybliżania zmniejszona do %.1f" @@ -65,214 +65,215 @@ msgid "Long strings" msgstr "Długie ciągi" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "nieznany podtyp (sprawdź log)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Niezaufany certyfikat." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Wydawca certyfikatu nie jest znany." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Certyfikat cofnięto." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Certyfikat wygasł." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Certyfikat nie jest aktywny." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Certyfikatu nie wydano jeszcze dla podłączonego klienta." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Podpisujący certyfikat nie jest rozpoznawalny." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Błąd" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Bez błędu" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Gracz jest już zalogowany" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Zabronione" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Wewnętrzny błąd serwera" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Nie jest dozwolona" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Nie jest autoryzowana" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Odbiorca czasowo niedostępny" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Wymagana rejestracja" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Usługa niedostępna" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Nieznany błąd" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Błąd transmisji" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Wersja transmisji przychodzącej nie jest wspierana" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Transmisja została zamknięta przez serwer" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Wystąpił błąd wejścia / wyjścia" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Serwer odmówił połączenia" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Nie udało się potwierdzić nazwy hosta serwera" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "W tym systemie brakuje pamięci" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Certyfikat serwera nie mógł być zweryfikowany lub TLS handshake nie został ukończony z powodzeniem" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Serwer nie oferuje wymaganego szyfrowania TLS" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Identyfikacja nie udała się. Niepoprawne hasło lub konto nie istnieje" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Użytkownik lub system zażądał rozłączenia" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Nie ma aktywnego połączenia" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Twoje konto zostało pomyślnie zarejestrowane" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Nie zapewniono wszystkich koniecznych informacji" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Nazwa użytkownika już istnieje" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Nie można zapisać pliku zewnętrznego mod.json dla spakowanego moda '%s'. Mod powinien zostać zainstalowany ponownie." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Błąd podczas odpytywania o identyfikator gry. Błąd: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Błąd podczas odpytywania o modyfikacje. Błąd: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Nie można stworzyć katalogu dla modyfikacji: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Nie można otworzyć tymczasowego pliku w celu pobrania modyfikacji: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Nie można rozpocząć pobierania. Błąd: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Błąd asynchronicznego pobierania: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Błąd pobierania. Odpowiedź serwera: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Niepasujący rozmiar pliku." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Błędny plik. Oczekiwane md5 %s, otrzymane %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Nie udało się obliczyć końcowego hash'a." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Nie udało się zweryfikować sygnatury." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Zapisano grę w '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Zrzut ekranu zapisany w '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "własna kompilacja" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Zrzut ekranu zapisany w '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/pt_BR.engine.po 0ad-0.0.26/binaries/data/l10n/pt_BR.engine.po --- 0ad-0.0.25b/binaries/data/l10n/pt_BR.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/pt_BR.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,281 +1,283 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# borg 2k , 2017 -# Canal do Kilof , 2016 -# Diógenes Oliveira , 2020 -# 1e46fd82907595ae69bafb7f4e47cd1b_169840e <1f20291f26e4e92cc88e8522999d4c5b_169576>, 2014 -# Enrico Nicoletto , 2013 -# Guilherme Soster , 2016 -# Gustavo Moitinho , 2016 -# Iago Leandro de Abreu , 2015 -# Jorno Jornade , 2018 -# Junior Lage , 2018 -# Mateus Felipe Cordeiro Caetano Pinto , 2013 -# Micael Pereira Malaquias , 2014 -# Pedro Augustus Diniz Falcão Silva , 2017 -# PedroDognani , 2015 -# Rafael Andrade , 2020 -# e05a6f0c527312287ac027cf3d3a35f5_685166c <0e3f187c36e42a887ffaef9a9e407417_190443>, 2014 -# Tiago , 2018 -# William Ferreira Dantas Neto , 2020 -# William Sandres, 2021 +# borg 2k +# Canal do Kilof +# Diógenes Oliveira +# 1e46fd82907595ae69bafb7f4e47cd1b_169840e +# Enrico Nicoletto +# Guilherme Soster +# Gustavo Moitinho +# Iago Leandro de Abreu +# João Francisco Gauze Carrer +# Junior Lage +# Mateus Felipe Cordeiro Caetano Pinto +# Micael Pereira Malaquias +# Pedro Augustus Diniz Falcão Silva +# PedroDognani +# Rafael Andrade +# e05a6f0c527312287ac027cf3d3a35f5_685166c +# Tiago +# William Ferreira Dantas Neto +# William Sandres +# Yuri Laskowski msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-26 00:10+0000\n" -"Last-Translator: William Sandres\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Yuri Laskowski , 2021\n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/wildfire-games/0ad/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Velocidade de rolagem aumentada para %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Velocidade de rolagem diminuída para %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Velocidade de rotação aumentada para X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Velocidade de rotação reduzida para X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Velocidade do zoom aumentada para %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "A velocidade do zoom diminuída para %.1f" +msgstr "Velocidade do zoom diminuída para %.1f" #: i18n/L10n.cpp:308 msgid "Long strings" msgstr "Textos longos" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" -msgstr "Subtipo desconhecido (ver registros)" +msgstr "subtipo desconhecido (ver registros)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "O certificado não é confiável." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "O certificado não possui um emissor conhecido." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "O certificado foi revogado." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "O certificado expirou." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "O certificado ainda não está ativo." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "O certificado não foi emitido para o ponto conectado." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "O assinante do certificado não é uma autoridade certificadora." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Erro" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Sem erros" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Jogador já esta logado" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Proibido" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Erro interno de servidor" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Não permitido" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Não autorizado" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Destinatário temporariamente indisponível" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registro obrigatório" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Serviço indisponível" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Erro desconhecido" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Erro de transferência" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" -msgstr "A versão transmissão de entrada não é suportada" +msgstr "A versão de entrada de transmissão não é suportada" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "O servidor fechou a transferência" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" -msgstr "Ocorreu um erro de I/O." +msgstr "Ocorreu um erro de I/O" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "A conexão foi recusada pelo servidor" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" -msgstr "Erro ao resolver o nome do Anfitrião" +msgstr "Erro ao resolver o nome do anfitrião do servidor" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "O sistema está sem memória" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "O certificado do servidor não pôde ser verificado, ou o TLS não completou a comunicação com sucesso" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "O server não exige encriptação TLS" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Falha na autenticação. Senha incorreta ou conta inexistente" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "O usuário, ou o sistema requisitou uma desconexão" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Não existem conexões ativas" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "A sua conta foi registrada com sucesso" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Nem toda informação necessária foi informada" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Nome de usuário já existe" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Não foi possível escrever mod.json externo para o mod compactado '%s'. O mod deve ser reinstalado." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Falha enquanto consultava pelo id do jogo. Erro: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Falha enquanto consultava por mods. Erro: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Não foi possível criar o diretório mod: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Não foi possível abrir um arquivo temporário para baixar o mod: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Falha ao iniciar o download. Erro: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Falha na sincronia de download: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Falha ao baixar. Resposta do servidor: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Tamanho de arquivo incorreto." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Arquivo inválido. MD5 esperado %s, obteve%s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Falha ao calcular o hash final." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Falha ao verificar a assinatura." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Jogo salvo em '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Captura de tela salva em '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "custom build" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Captura de tela salva em '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/ru.engine.po 0ad-0.0.26/binaries/data/l10n/ru.engine.po --- 0ad-0.0.25b/binaries/data/l10n/ru.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/ru.engine.po 2022-09-23 19:16:45.000000000 +0000 @@ -1,30 +1,27 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Alexander Olkhovskiy, 2013 -# Alexander Olkhovskiy, 2013 -# Boris Karalnik , 2019 -# Дмитрий Ошкало , 2017 -# Григорий Световидов , 2015 -# Ilya Andreev, 2017 -# Ivan, 2014 -# Maksim Oreshkov , 2014 -# Malik Khodjaev , 2015 -# nwtour , 2021 -# Vladislav Belov , 2015 -# Vladislav Belov , 2016,2021 -# Vladislav , 2013 -# Валерий Дмиртиевич Степанов , 2018 -# Дмитрий Ошкало , 2018 -# Евгений Кривошеев , 2020 -# Чувак, 2013 +# Alexander Olkhovskiy +# Boris Karalnik +# Дмитрий Ошкало +# Григорий Световидов +# Ilya Andreev +# Ivan +# Maksim Oreshkov +# Malik Khodjaev +# nwtour +# Vladislav Belov +# Vladislav +# Валерий Дмиртиевич Степанов +# Евгений Кривошеев +# Чувак msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-09 20:22+0000\n" -"Last-Translator: nwtour \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: nwtour , 2021\n" "Language-Team: Russian (http://www.transifex.com/wildfire-games/0ad/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -32,32 +29,32 @@ "Language: ru\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Скорость скроллинга увеличена до %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Скорость скроллинга уменьшена до %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Скорость вращения увеличена до X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Скорость вращения уменьшена до X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Скорость зума увеличена до %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Скорость зума уменьшена до %.1f" @@ -66,214 +63,215 @@ msgid "Long strings" msgstr "Длинные строки" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "неизвестный подтип (см. логи)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Сертификат не является надёжным." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "У сертификата нет известного выдающего лица." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Сертификат был отозван." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Срок действия сертификата истёк." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Сертификат ещё не активен." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Сертификат был выдан не этому узлу." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Подписавшее сертификат лицо не является сертифицирующей организацией." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Ошибка" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Нет ошибок" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Игрок уже вошел" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Запрещено" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Ошибка сервера" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Не разрешено" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Нет авторизации" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Получатель временно недоступен" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Необходима регистрация" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Сервис недоступен" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Неизвестная ошибка" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Ошибка соединения" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Версия входящего соединения не поддерживается" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Соединение было закрыто сервером" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Произошла ошибка ввода/вывода" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Соединение было разорвано сервером" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Не удалось получить имя сервера" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Этой системе не хватает памяти" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Сертификат сервера не может быть проверен или начало соединения SSL не удалось завершить успешно" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Сервер не предложил запрашиваемого TLS шифрования" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Ошибка аутентификации. Неверный пароль или аккаунт не существует" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Пользователь или система запросили отключение" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Нет активных соединений" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Ваша учетная запись успешно зарегистрирована" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Предоставлена не вся необходимая информация" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Это имя пользователя уже используется" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Не возможно записать внешний mod.json для архива мода '%s'. Мод должен быть переустановлен." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Сбой при запросе id игры. Ошибка: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Сбой при запросе модификаций. Ошибка: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Невозможно создать каталог модификаций: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Невозможно открыть временный файл для загрузки модификации: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Невозможно начать загрузку. Ошибка: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Сбой асинхронной загрузки: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Сбой загрузки. Ответ сервера: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Несовпадающий размер файла." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Файл поврежден. Ожидаемая md5 %s, полученная %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Сбой расчета финального хеша." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Сбой проверки подписи." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Игра сохранена в '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Снимок экрана записан в '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "пользовательская сборка" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Снимок экрана записан в '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/sk.engine.po 0ad-0.0.26/binaries/data/l10n/sk.engine.po --- 0ad-0.0.25b/binaries/data/l10n/sk.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/sk.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,26 +1,24 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# LeviTaule , 2018 -# LeviTaule , 2014-2016 -# Martin Plávala , 2014-2015 -# Miroslav Kadlec , 2018 -# MiroslavR , 2014 -# Patrik Špaňo , 2020 -# Roman Beňo , 2014 -# Roman 'Kaktuxista' Benji , 2014 -# Rudolf Tisoň , 2021 -# Slavomir Slovenkai , 2018,2021 -# Slavomir Slovenkai , 2021 -# Tom Hanax, 2019 -# Zuzana Miadoková, 2019,2021 +# LeviTaule +# Martin Plávala +# Miroslav Kadlec +# MiroslavR +# Patrik Špaňo +# Roman Beňo +# Roman 'Kaktuxista' Benji +# Rudolf Tisoň +# c1d3d4413723242329060e6153cf18b8_282267d +# Tom Hanax +# Zuzana Miadoková msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-19 13:56+0000\n" -"Last-Translator: Rudolf Tisoň \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Rudolf Tisoň , 2021\n" "Language-Team: Slovak (http://www.transifex.com/wildfire-games/0ad/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -28,32 +26,32 @@ "Language: sk\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Rýchlosť posunu scrollovaním zvýšená na %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Rýchlosť posunu scrollovaním znížená na %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Rýchlosť otáčania zvýšená na X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Rýchlosť otáčania znížená na X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Rýchlosť približovania zvýšená na %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Rýchlosť približovania znížená na %.1f" @@ -62,214 +60,215 @@ msgid "Long strings" msgstr "Dlhé reťazce" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "neznámy podtyp (pozri log)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Certifikát nie je dôveryhodný." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Certifikát nemá známeho vydavateľa." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Certifikát bol odvolaný." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Certifikát expiroval." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Certifikát ešte nie je aktívny." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Certifikát nebol vydaný pre peera ku ktorému bolo pripojené. " -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Podpisovateľ certifikátu nie je certifikačná autorita." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Chyba" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Bez chyby" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Hráč je už prihlásený" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Zakázané" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Interná chyba servera" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Nepovolené" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Neoprávnené" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Príjemca je dočasne nedostupný" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Vyžaduje sa registrácia" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Služba nie je dostupná" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Neznáma chyba" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Chyba dátového toku" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Prichádzajúci dátový tok je nepodporovaný" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Dátový tok bol ukončený serverom." -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Nastala chyba I/O (vstupu a výstupu) " -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Spojenie bolo zamietnuté serverom." -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Zlyhala rezolúcia názvu hostiteľa - hostname resolution" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Tento systém už nemá voľnú pamäť." -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Certifikát tohoto servera nemohol byť overený, alebo TLS handshake nebol úspešne dokončený" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Tento server neposkytol vyžadované TLS šifrovanie." -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Overenie pravosti zlyhalo. Zadané heslo nebolo správne, alebo účet neexistuje" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Užívateľ alebo systém si vyžiadal odpojenie" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Neexistuje aktívne pripojenie" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Tvoj účet bol úspešne zaregistrovaný." -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Neboli poskytnuté všetky potrebné informácie" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Užívateľské meno už existuje" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Nebolo schopné napísať Mód.json pre zazippovaný Mód'%s'. Mód by mal byť preinštalovaný." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Zlyhanie počas získavania ID hry. Chyba: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Zlyhanie počas získavania modov. Chyba: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Nepodarilo sa vytvoriť adresár modu: %s . " -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Nepodarilo sa otvoriť dočasný súbor na prevzatie modu: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Preberanie sa nepodarilo spustiť. Chyba: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Zlyhanie asynchrónneho sťahovania: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Sťahovanie zlyhalo. Odozva servera: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Nesprávna veľkosť súboru. " -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Neplatný súbor. Očakávalo sa md5%s mám %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Nepodarilo sa vypočítať konečný hash." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Nepodarilo sa overiť podpis. " -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Hra uložená do '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Snímok obrazovky uložený do '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "vlastný build" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Snímok obrazovky uložený do '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/sv.engine.po 0ad-0.0.26/binaries/data/l10n/sv.engine.po --- 0ad-0.0.25b/binaries/data/l10n/sv.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/sv.engine.po 2022-09-23 19:16:38.000000000 +0000 @@ -1,23 +1,21 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# 0a7f9ff4c411567131ab21a7587f6066, 2014 -# Erik Johansson , 2014,2016 -# Hans Kunkell , 2019 -# Jacob Carlsson , 2015 -# efef6ec5b435a041fce803c7f8af77d2_2341d43, 2020 -# Martin H , 2020 -# Martin H , 2016 -# Martin H , 2016 -# Martin H , 2017-2019 -# theschitz , 2015 +# Albin Nilsson +# 0a7f9ff4c411567131ab21a7587f6066 +# Erik Johansson +# Hans Kunkell +# Jacob Carlsson +# efef6ec5b435a041fce803c7f8af77d2_2341d43 +# Martin H +# theschitz msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-17 10:18+0000\n" -"Last-Translator: Transifex Bot <>\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Albin Nilsson , 2021\n" "Language-Team: Swedish (http://www.transifex.com/wildfire-games/0ad/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,248 +23,249 @@ "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" -msgstr "" +msgstr "Scrollhastighet ökat till %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "" +msgstr "Scrollhastighet minskat till %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" -msgstr "" +msgstr "Rotationshastighet ökat till X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" -msgstr "" +msgstr "Rotationshastighet minskat till X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" -msgstr "" +msgstr "Zoomhastighet ökat till %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "" +msgstr "Zoomhastighet minskat till %.1f" #: i18n/L10n.cpp:308 msgid "Long strings" msgstr "Långa strängar" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "Okänd subtyp (se loggar)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Certifikatet är ej betrott." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Certifikatet har ingen känd ägare." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Certifikatet har återkallats." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Certifikatet har gått ur." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Certifikatet är inte aktivt än." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Certifikatet har inte utfärdats för denna ansluta noden." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Certifikatets signerare är ingen giltig certificate authority." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Fel" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Inget fel" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Spelare redan inloggad" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Förbjudet" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Internt serverfel" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Ej tillåtet" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Ej autoriserat" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Mottagare tillfälligt ej tillgänglig" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Registrering krävs" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Service ej tillgänglig" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Okänt fel" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Stream fel" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Versionen av den inkommande streamen stöds ej" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Servern har stängt streamen" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Ett I/O fel har inträffat" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Servern nekade anslutningen" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Kunde ej lösa upp serverns hostname" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Systemet är slut på minne" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Serverns certifikat kunde ej verifieras eller TLS Handshaken kunde ej slutföras." -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Servern erbjuder ej den krävda TLS-krypteringen" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Autentisering misslyckades. Felaktigt lösenord eller kontot finns inte." -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Användaren eller systemet begär en frånkoppling" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Det finns ingen aktiv anslutning" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Ditt konto har registrerats" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Inte all nödvändig information angiven" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Användarnamn redan registrerat" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "" +msgstr "Kunde inte skriva extern mod.json för zippat mod '%s'. Moddet borde ominstalleras." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Fel vid början av förfrågan om spel-id. Fel: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Fel vid början av förfrågan om mods. Fel: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Kunde inte skapa mod-mapp: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Kunde inte öppna temporär fil för mod-hämtning: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Det gick inte att starta hämtningen: Fel %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Asynkron hämtning misslyckades: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Hämtningsfel. Serverrespons: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Felaktigt filstorlek." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Ogiltig fil. Förväntade md5 %s, fick %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Kunde inte beräkna slutgiltig hash." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Kunde inte verifiera signatur." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Spel sparat till '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Skärmdump sparad till '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "egenkompilerad" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Skärmdump sparad till '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/tr.engine.po 0ad-0.0.26/binaries/data/l10n/tr.engine.po --- 0ad-0.0.25b/binaries/data/l10n/tr.engine.po 2021-07-27 21:56:34.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/tr.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,28 +1,28 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# Abdullah Ilgaz , 2014 -# AMG , 2015 -# AMG , 2015 -# Cem Aktas , 2021 -# Doğu Kan, 2013 -# Emre Cıklatekerlio , 2014 -# Erman Yolcu , 2016 -# Ferhat Olçum , 2018 -# Günay Yılmaz, 2019-2020 -# İrfan Sunay , 2018 -# Kemal Oktay Aktoğan , 2017 -# sicey , 2015 -# Taha Karadoğan , 2016 -# Volkan Gezer , 2013-2014 -# yakup , 2014,2016-2017,2019 +# Abdullah Ilgaz +# AMG +# Cem Aktas +# Doğu Kan +# Emre Cıklatekerlio +# 703c12db2ef19cb60ee4cbbc0578beae_b1935ed +# Ferhat Olçum +# Günay Yılmaz +# İrfan Sunay +# Kemal Oktay Aktoğan +# On Fi +# sicey +# Taha Karadoğan +# Volkan Gezer +# yakup msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-06-11 15:32+0000\n" -"Last-Translator: Cem Aktas \n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: On Fi, 2021\n" "Language-Team: Turkish (http://www.transifex.com/wildfire-games/0ad/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,248 +30,249 @@ "Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" -msgstr "Kaydırma hızı %.1f arttırıldı." +msgstr "Kaydırma hızı %1 arttırıldı." -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" -msgstr "Kaydrma hızı %.1f azaltıldı." +msgstr "Kaydrma hızı %1 azaltıldı." -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" -msgstr "Dödürme hızı X=%.3f, Y=%.3f arttırıldı." +msgstr "Döndürme hızı X= %1, Y= %1 arttırıldı." -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" -msgstr "Döndrme hızı X=%.3f, Y=%.3f azaltıldı." +msgstr "Döndürme hızı X= %1, Y= %1 azaltıldı." -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" -msgstr "Yakınlaştırma hızı %.1f arttırıldı." +msgstr "Yakınlaştırma hızı %1 arttırıldı." -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" -msgstr "Yakınlaştırma hızı %.1f azaltıldı." +msgstr "Yakınlaştırma hızı %1 azaltıldı." #: i18n/L10n.cpp:308 msgid "Long strings" msgstr "Uzun dizgeler" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "bilinmeyen alttür (kayıtlara bakın)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Sertifikaya güvenilmiyor." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Sertifikanın bilinen bir yayıncısı yok." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Sertifika iptal edildi." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Sertifikanın süresi doldu." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Sertifika henüz aktif değil." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Sertifika, bağlı olan eş için verilmemiş." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Sertifika imzalayan bir sertifika yetkilisi değil." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Hata" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Hata yok" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Oyuncu zaten giriş yaptı" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Yasaklanmış" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Sunucu içi hata" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "İzin verilmemektedir" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Yetkiniz yok" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Alıcı geçici olarak kullanılamıyor" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Kayıt gerekli" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Hizmet kullanım dışı" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Bilinmeyen hata" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Akış hatası" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Gelen akış sürümü desteklenmiyor." -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Bu akış sunucu tarafından kapatıldı." -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Bir G/Ç hatası oluştu" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Bu bağlantı sunucu tarafından reddedildi" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Sunucu isim hatası çözülüyor" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Sistem belleği yetersiz." -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Sunucu sertifikası onaylanamıyor veya bu TLS başarılı şekilde doğrulanamıyor" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Bu sunucu TLS şifreleme gerekliliklerini sunamıyor" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Kimlik doğrulama başarısız oldu. Geçersiz şifre veya hesap yok" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Bu kullanıcı veya sistem bağlantının kesilmesine ihtiyaç duyuyor" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Aktif bağlantı yok" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Hesabın başarıyla kaydedildi" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "bütün önemli bilgi karşılanamadı" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Kullanıcı adı zaten var" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." msgstr "Sıkıştırılmış mod '%s' için harici mod.json yazılamadı. Mod yeniden kurulmalı." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Oyun ID'sini sorgulamaya başlarken hata oluştu. Hata: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Modları sorgulamaya başlarken hata oluştu. Hata: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Mod dizini oluşturulamıyor: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Mod yüklemesi için geçici dosya açılamıyor: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Yüklemeyi başlatmada hata. Hata: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Asenkron yükleme hatası: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Yükleme hatası. Server cevabı: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Eşleşmeyen dosya boyutu." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Geçersiz dosya. md5 umduk %s, %s bulduk." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Son HASH hesaplamasında hata." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "İmza doğrulamasında hata." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Oyun buraya kaydedildi: '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Ekran görüntüsü buraya kaydedildi: '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "özel inşa" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Ekran görüntüsü buraya kaydedildi: '%s'" diff -Nru 0ad-0.0.25b/binaries/data/l10n/uk.engine.po 0ad-0.0.26/binaries/data/l10n/uk.engine.po --- 0ad-0.0.25b/binaries/data/l10n/uk.engine.po 2021-07-27 21:56:40.000000000 +0000 +++ 0ad-0.0.26/binaries/data/l10n/uk.engine.po 2022-09-23 19:16:39.000000000 +0000 @@ -1,25 +1,26 @@ # Translation template for Pyrogenesis. -# Copyright (C) 2021 Wildfire Games +# Copyright (C) 2022 Wildfire Games # This file is distributed under the same license as the Pyrogenesis project. # Translators: -# AlexKR , 2015 -# Andriy Nahirnjak , 2014 -# Cecil Rhodes , 2020 -# 009ee41e4c490a944b98e20dd0cc29dd_e31b370 <3a1cdc1a7c52cc59f91bdc5fed0a3a77_882482>, 2020 -# Dmytro Ryl'kov , 2018 -# Oleg Adept , 2020 -# Victor Butko , 2014 -# 85c91c3444bcf82d63b07801f727e341, 2020 -# Андрій Бандура , 2016 -# Микола Франчук , 2018,2021 -# Сергій Дубик , 2014 -# Тарас Коржик , 2016 +# AlexKR +# Andriy Nahirnjak +# Cecil Rhodes +# 009ee41e4c490a944b98e20dd0cc29dd_e31b370 +# Dmytro Ryl'kov +# Lemak Maksym +# Олег Вормов +# Victor Butko +# 85c91c3444bcf82d63b07801f727e341 +# Андрій Бандура +# Микола Франчук +# Сергій Дубик +# Тарас Коржик msgid "" msgstr "" "Project-Id-Version: 0 A.D.\n" -"POT-Creation-Date: 2021-05-17 07:08+0000\n" -"PO-Revision-Date: 2021-05-17 10:18+0000\n" -"Last-Translator: Transifex Bot <>\n" +"POT-Creation-Date: 2022-01-07 08:19+0000\n" +"PO-Revision-Date: 2013-06-22 12:54+0000\n" +"Last-Translator: Lemak Maksym, 2022\n" "Language-Team: Ukrainian (http://www.transifex.com/wildfire-games/0ad/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -27,32 +28,32 @@ "Language: uk\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" -#: graphics/CameraController.cpp:656 +#: graphics/CameraController.cpp:657 #, c-format msgid "Scroll speed increased to %.1f" msgstr "Швидкість прокрутки збільшена до %.1f" -#: graphics/CameraController.cpp:662 +#: graphics/CameraController.cpp:663 #, c-format msgid "Scroll speed decreased to %.1f" msgstr "Швидкість прокрутки зменшена до %.1f" -#: graphics/CameraController.cpp:669 +#: graphics/CameraController.cpp:670 #, c-format msgid "Rotate speed increased to X=%.3f, Y=%.3f" msgstr "Швидкість повороту збільшена до X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:676 +#: graphics/CameraController.cpp:677 #, c-format msgid "Rotate speed decreased to X=%.3f, Y=%.3f" msgstr "Швидкість повороту зменшена до X=%.3f, Y=%.3f" -#: graphics/CameraController.cpp:682 +#: graphics/CameraController.cpp:683 #, c-format msgid "Zoom speed increased to %.1f" msgstr "Швидкість приближення збільшена до %.1f" -#: graphics/CameraController.cpp:688 +#: graphics/CameraController.cpp:689 #, c-format msgid "Zoom speed decreased to %.1f" msgstr "Швидкість приближення зменшена до %.1f" @@ -61,214 +62,215 @@ msgid "Long strings" msgstr "Довгі рядки" -#: lobby/XmppClient.cpp:1026 +#: lobby/XmppClient.cpp:1024 msgid "unknown subtype (see logs)" msgstr "невідомий підтип (дивитися журнали)" -#: lobby/XmppClient.cpp:1357 +#: lobby/XmppClient.cpp:1355 msgid "The certificate is not trusted." msgstr "Сертифікат не є довіреним." -#: lobby/XmppClient.cpp:1358 +#: lobby/XmppClient.cpp:1356 msgid "The certificate hasn't got a known issuer." msgstr "Сертифікат не має відомого видавця." -#: lobby/XmppClient.cpp:1359 +#: lobby/XmppClient.cpp:1357 msgid "The certificate has been revoked." msgstr "Сертифікат відкликаний." -#: lobby/XmppClient.cpp:1360 +#: lobby/XmppClient.cpp:1358 msgid "The certificate has expired." msgstr "Термін дії сертифікату минув." -#: lobby/XmppClient.cpp:1361 +#: lobby/XmppClient.cpp:1359 msgid "The certificate is not yet active." msgstr "Сертифікат ще не активний." -#: lobby/XmppClient.cpp:1362 +#: lobby/XmppClient.cpp:1360 msgid "The certificate has not been issued for the peer connected to." msgstr "Сертифікат не виданий для однорангового підключеного." -#: lobby/XmppClient.cpp:1363 +#: lobby/XmppClient.cpp:1361 msgid "The certificate signer is not a certificate authority." msgstr "Підписант сертифіката не є органом сертифікації." -#: lobby/XmppClient.cpp:1385 lobby/XmppClient.cpp:1429 -#: lobby/XmppClient.cpp:1468 +#: lobby/XmppClient.cpp:1383 lobby/XmppClient.cpp:1427 +#: lobby/XmppClient.cpp:1466 msgid "Error" msgstr "Помилка" -#: lobby/XmppClient.cpp:1388 lobby/XmppClient.cpp:1432 +#: lobby/XmppClient.cpp:1386 lobby/XmppClient.cpp:1430 msgid "No error" msgstr "Немає помилки" -#: lobby/XmppClient.cpp:1390 +#: lobby/XmppClient.cpp:1388 msgid "Player already logged in" msgstr "Гравець уже ввійшов у систему" -#: lobby/XmppClient.cpp:1392 +#: lobby/XmppClient.cpp:1390 msgid "Forbidden" msgstr "Заборонено" -#: lobby/XmppClient.cpp:1394 +#: lobby/XmppClient.cpp:1392 msgid "Internal server error" msgstr "Внутрішня помилка сервера" -#: lobby/XmppClient.cpp:1398 +#: lobby/XmppClient.cpp:1396 msgid "Not allowed" msgstr "Не дозволено" -#: lobby/XmppClient.cpp:1399 +#: lobby/XmppClient.cpp:1397 msgid "Not authorized" msgstr "Не авторізовано" -#: lobby/XmppClient.cpp:1402 +#: lobby/XmppClient.cpp:1400 msgid "Recipient temporarily unavailable" msgstr "Одержувач тимчасово недоступний" -#: lobby/XmppClient.cpp:1404 +#: lobby/XmppClient.cpp:1402 msgid "Registration required" msgstr "Потрібна реєстрація" -#: lobby/XmppClient.cpp:1408 +#: lobby/XmppClient.cpp:1406 msgid "Service unavailable" msgstr "Сервіс недоступний" -#: lobby/XmppClient.cpp:1413 lobby/XmppClient.cpp:1452 +#: lobby/XmppClient.cpp:1411 lobby/XmppClient.cpp:1450 msgid "Unknown error" msgstr "Невідома помилка" -#: lobby/XmppClient.cpp:1433 +#: lobby/XmppClient.cpp:1431 msgid "Stream error" msgstr "Помилка потоку" -#: lobby/XmppClient.cpp:1434 +#: lobby/XmppClient.cpp:1432 msgid "The incoming stream version is unsupported" msgstr "Версія вхідного потоку не підтримується" -#: lobby/XmppClient.cpp:1435 +#: lobby/XmppClient.cpp:1433 msgid "The stream has been closed by the server" msgstr "Потік був закритий сервером" -#: lobby/XmppClient.cpp:1439 +#: lobby/XmppClient.cpp:1437 msgid "An I/O error occurred" msgstr "Виникла помилка вводу/виводу" -#: lobby/XmppClient.cpp:1441 +#: lobby/XmppClient.cpp:1439 msgid "The connection was refused by the server" msgstr "Підключення було розірвано сервером" -#: lobby/XmppClient.cpp:1442 +#: lobby/XmppClient.cpp:1440 msgid "Resolving the server's hostname failed" msgstr "Дозволення ім'я власника сервера не вдалося" -#: lobby/XmppClient.cpp:1443 +#: lobby/XmppClient.cpp:1441 msgid "This system is out of memory" msgstr "Ця система не має достатньої кількості пам’яті" -#: lobby/XmppClient.cpp:1445 +#: lobby/XmppClient.cpp:1443 msgid "" "The server's certificate could not be verified or the TLS handshake did not " "complete successfully" msgstr "Сертифікат сервера не вдалося перевірити або успішно виконати рукостискання TLS" -#: lobby/XmppClient.cpp:1446 +#: lobby/XmppClient.cpp:1444 msgid "The server did not offer required TLS encryption" msgstr "Сервер не запропонував необхідне шифрування TLS" -#: lobby/XmppClient.cpp:1448 +#: lobby/XmppClient.cpp:1446 msgid "Authentication failed. Incorrect password or account does not exist" msgstr "Аутентифікацію не вдалося. Неправильний пароль або обліковий запис не існує" -#: lobby/XmppClient.cpp:1449 +#: lobby/XmppClient.cpp:1447 msgid "The user or system requested a disconnect" msgstr "Користувач або система вимагали відключення" -#: lobby/XmppClient.cpp:1450 +#: lobby/XmppClient.cpp:1448 msgid "There is no active connection" msgstr "Немає активного підключення" -#: lobby/XmppClient.cpp:1471 +#: lobby/XmppClient.cpp:1469 msgid "Your account has been successfully registered" msgstr "Ваш обліковий запис було успішно зареєстровано" -#: lobby/XmppClient.cpp:1472 +#: lobby/XmppClient.cpp:1470 msgid "Not all necessary information provided" msgstr "Надана не вся необхідна інформація" -#: lobby/XmppClient.cpp:1473 +#: lobby/XmppClient.cpp:1471 msgid "Username already exists" msgstr "Користувач з таким ім'ям вже існує" -#: ps/Mod.cpp:84 +#: ps/Mod.cpp:82 #, c-format msgid "" "Could not write external mod.json for zipped mod '%s'. The mod should be " "reinstalled." -msgstr "" +msgstr "Не можливр записати зовнішній mod.json для zip-архівованої модифікації '%s'. Модифікацію слід перевстановити." -#: ps/ModIo.cpp:263 +#: ps/ModIo.cpp:264 #, c-format msgid "Failure while starting querying for game id. Error: %s; %s." msgstr "Помилка під час запуску запиту на ідентифікатор гри. Помилка: %s; %s." -#: ps/ModIo.cpp:293 +#: ps/ModIo.cpp:294 #, c-format msgid "Failure while starting querying for mods. Error: %s; %s." msgstr "Помилка під час запуску запитів для модифікацій. Помилка: %s; %s." -#: ps/ModIo.cpp:319 +#: ps/ModIo.cpp:320 #, c-format msgid "Could not create mod directory: %s." msgstr "Не вдалося створити каталог модифікацій: %s." -#: ps/ModIo.cpp:344 +#: ps/ModIo.cpp:345 #, c-format msgid "Could not open temporary file for mod download: %s." msgstr "Не вдалося відкрити тимчасовий файл для завантаження модифікацій: %s." -#: ps/ModIo.cpp:354 +#: ps/ModIo.cpp:355 #, c-format msgid "Failed to start the download. Error: %s; %s." msgstr "Не вдалося розпочати завантаження. Помилка: %s; %s." -#: ps/ModIo.cpp:399 +#: ps/ModIo.cpp:400 #, c-format msgid "Asynchronous download failure: %s, %s." msgstr "Помилка асинхронного завантаження: %s, %s." -#: ps/ModIo.cpp:427 +#: ps/ModIo.cpp:428 #, c-format msgid "Download failure. Server response: %s; %s." msgstr "Помилка завантаження. Відповідь сервера: %s; %s." -#: ps/ModIo.cpp:530 +#: ps/ModIo.cpp:534 msgid "Mismatched filesize." msgstr "Невідповідний розмір файлу." -#: ps/ModIo.cpp:548 +#: ps/ModIo.cpp:552 #, c-format msgid "Invalid file. Expected md5 %s, got %s." msgstr "Невірний файл. Очікуваний md5 %s, отриманий %s." -#: ps/ModIo.cpp:563 +#: ps/ModIo.cpp:567 msgid "Failed to compute final hash." msgstr "Не вдалося розрахувати остаточний хеш." -#: ps/ModIo.cpp:569 +#: ps/ModIo.cpp:573 msgid "Failed to verify signature." msgstr "Не вдалося перевірити підпис." -#: ps/SavedGame.cpp:141 +#: ps/SavedGame.cpp:142 #, c-format msgid "Saved game to '%s'" msgstr "Збережено гру до '%s'" -#: ps/Util.cpp:289 ps/Util.cpp:292 ps/Util.cpp:437 ps/Util.cpp:440 -#, c-format -msgid "Screenshot written to '%s'" -msgstr "Знімок екрану записаний до '%s'" - #: ps/scripting/JSInterface_Debug.cpp:87 msgid "custom build" msgstr "користувацька збірка" + +#: renderer/Renderer.cpp:614 renderer/Renderer.cpp:617 +#: renderer/Renderer.cpp:754 renderer/Renderer.cpp:757 +#, c-format +msgid "Screenshot written to '%s'" +msgstr "Знімок екрану записаний до '%s'" diff -Nru 0ad-0.0.25b/binaries/data/mods/_test.minimal/fonts/console.fnt 0ad-0.0.26/binaries/data/mods/_test.minimal/fonts/console.fnt --- 0ad-0.0.25b/binaries/data/mods/_test.minimal/fonts/console.fnt 2021-07-27 21:56:33.000000000 +0000 +++ 0ad-0.0.26/binaries/data/mods/_test.minimal/fonts/console.fnt 2022-09-23 19:16:34.000000000 +0000 @@ -1,7 +1,9 @@ -100 +101 256 256 +a 606 -20 +15 +12 32 0 256 0 0 0 0 5 33 250 154 3 11 1 11 4 34 121 18 5 4 0 11 5 Binary files /tmp/tmp39yh8n0d/woTvBEdUpR/0ad-0.0.25b/binaries/data/mods/_test.tex/art/textures/b/npot.png and /tmp/tmp39yh8n0d/CCpWyu1Pac/0ad-0.0.26/binaries/data/mods/_test.tex/art/textures/b/npot.png differ diff -Nru 0ad-0.0.25b/binaries/system/readme.txt 0ad-0.0.26/binaries/system/readme.txt --- 0ad-0.0.25b/binaries/system/readme.txt 2021-07-27 21:38:07.000000000 +0000 +++ 0ad-0.0.26/binaries/system/readme.txt 2022-09-23 19:08:41.000000000 +0000 @@ -13,7 +13,7 @@ -autostart-aidiff=PLAYER:DIFF sets the DIFFiculty of PLAYER's AI (0: sandbox, 5: very hard) -autostart-aiseed=AISEED sets the seed used for the AI random generator (default 0, use -1 for random) -autostart-player=NUMBER sets the playerID in non-networked games (default 1, use -1 for observer) --autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV (skirmish and random maps only) +-autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV (skirmish and random maps only). Use random for a random civ. -autostart-team=PLAYER:TEAM sets the team for PLAYER (e.g. 2:2). -autostart-ceasefire=NUM sets a ceasefire duration NUM (default 0 minutes) -autostart-nonvisual disable any graphics and sounds @@ -33,9 +33,9 @@ Examples: 1) "Bob" will host a 2 player game on the Arcadia map: - -autostart="scenarios/Arcadia" -autostart-host -autostart-host-players=2 -autostart-playername="Bob" + -autostart="scenarios/arcadia" -autostart-host -autostart-host-players=2 -autostart-playername="Bob" "Alice" joins the match as player 2: - -autostart="scenarios/Arcadia" -autostart-client=127.0.0.1 -autostart-playername="Alice" + -autostart-client=127.0.0.1 -autostart-playername="Alice" The players use the developer overlay to control players. 2) Load Alpine Lakes random map with random seed, 2 players (Athens and Britons), and player 2 is PetraBot: -autostart="random/alpine_lakes" -autostart-seed=-1 -autostart-players=2 -autostart-civ=1:athen -autostart-civ=2:brit -autostart-ai=2:petra diff -Nru 0ad-0.0.25b/build/jenkins/dockerfiles/build-base.Dockerfile 0ad-0.0.26/build/jenkins/dockerfiles/build-base.Dockerfile --- 0ad-0.0.25b/build/jenkins/dockerfiles/build-base.Dockerfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/dockerfiles/build-base.Dockerfile 2022-09-23 19:16:45.000000000 +0000 @@ -2,11 +2,8 @@ RUN useradd -ms /bin/bash --uid 1006 builder -RUN apt-get -qq update - # 0 A.D. dependencies. -RUN apt-get install -qqy \ - build-essential \ +RUN apt-get -qq update && apt-get install -qqy \ cmake \ curl \ libboost-dev \ @@ -15,6 +12,7 @@ libcurl4-gnutls-dev \ libenet-dev \ libfmt-dev \ + libfreetype6-dev \ libgloox-dev \ libgnutls28-dev \ libgtk-3-dev \ @@ -25,25 +23,18 @@ libogg-dev \ libopenal-dev \ libpng-dev \ - libsodium-dev \ libsdl2-dev \ + libsodium-dev \ libvorbis-dev \ libwxgtk3.0-dev \ libxcursor-dev \ - libxml2-dev \ libxml-simple-perl \ + libxml2-dev \ llvm-7 \ - zlib1g-dev \ - && apt-get clean - -# Other utilities -RUN apt-get install -qqy \ python3-dev \ python3-pip \ - rsync \ - subversion \ - vim \ - mkdocs + zlib1g-dev \ + && apt-get clean # Install rust and Cargo via rustup USER builder diff -Nru 0ad-0.0.25b/build/jenkins/dockerfiles/clang7.Dockerfile 0ad-0.0.26/build/jenkins/dockerfiles/clang7.Dockerfile --- 0ad-0.0.25b/build/jenkins/dockerfiles/clang7.Dockerfile 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/dockerfiles/clang7.Dockerfile 2022-09-23 19:16:40.000000000 +0000 @@ -0,0 +1,9 @@ +FROM build-base:latest + +RUN apt-get install -qqy clang-7 lld-7 + +USER builder + +ENV CC clang-7 +ENV CXX clang++-7 +ENV LDFLAGS -fuse-ld=lld-7 diff -Nru 0ad-0.0.25b/build/jenkins/dockerfiles/gcc7.Dockerfile 0ad-0.0.26/build/jenkins/dockerfiles/gcc7.Dockerfile --- 0ad-0.0.25b/build/jenkins/dockerfiles/gcc7.Dockerfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/dockerfiles/gcc7.Dockerfile 2022-09-23 19:16:40.000000000 +0000 @@ -6,5 +6,5 @@ ENV LIBCC gcc-7 ENV LIBCXX g++-7 -ENV PSCC gcc-7 -ENV PSCXX g++-7 +ENV CC gcc-7 +ENV CXX g++-7 diff -Nru 0ad-0.0.25b/build/jenkins/dockerfiles/translations.Dockerfile 0ad-0.0.26/build/jenkins/dockerfiles/translations.Dockerfile --- 0ad-0.0.25b/build/jenkins/dockerfiles/translations.Dockerfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/dockerfiles/translations.Dockerfile 2022-09-23 19:16:40.000000000 +0000 @@ -1,7 +1,7 @@ FROM build-base # This silences a transifex-client warning -RUN apt-get install -qqy git +RUN apt-get install -qqy git subversion RUN pip3 install transifex-client lxml babel diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/design-docs.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/design-docs.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/design-docs.Jenkinsfile 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/design-docs.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -0,0 +1,54 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +// This pipeline is used to build the design document. + +pipeline { + agent { + node { + label 'LinuxSlave' + } + } + stages { + stage("Checkout") { + steps { + ws("/zpool0/design-docs"){ + git "https://code.wildfiregames.com/source/design.git" + } + } + } + stage("Generate") { + steps { + ws("/zpool0/design-docs"){ + sh "mkdocs build" + } + } + } + stage("Upload") { + steps { + ws("/zpool0/design-docs"){ + sh "rsync -rti --delete-after --progress site/ docs.wildfiregames.com:~/www/design/" + } + } + } + } + post { + always { + step([$class: 'PhabricatorNotifier']) + } + } +} diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-custom.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-custom.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-custom.Jenkinsfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-custom.Jenkinsfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* Copyright (C) 2021 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -pipeline { - agent { - node { - label 'LinuxSlave' - customWorkspace '/zpool0/trunk' - } - } - parameters { - string(name: 'DIFF_ID', defaultValue: '', description: '(optional) ID of the Phabricator Differential.') - booleanParam(name: 'NO_PCH', defaultValue: false, description: 'Run this build without PCH.') - booleanParam(name: 'DEBUG', defaultValue: false, description: 'Compile in debug mode.') - } - - stages { - stage("Setup") { - steps { - sh "sudo zfs clone zpool0/gcc7@latest zpool0/custom" - } - } - stage("Apply Differential") { - when { - expression { return params.DIFF_ID != "" } - } - steps { - ws("/zpool0/custom") { - sh "arc patch --diff ${params.DIFF_ID} --force" - } - } - } - stage("PCH clean up") { - when { - expression { return params.NO_PCH } - } - steps { - ws("/zpool0/custom") { - sh "rm -rf build/workspaces/gcc/" - } - } - } - stage("Build") { - steps { - script { - ws("/zpool0/custom") { - // Destroy test *.cpp files as they use (invalid) absolute paths. - sh 'python3 -c \"import glob; print(\\\" \\\".join(glob.glob(\\\"source/**/tests/**.cpp\\\", recursive=True)));\" | xargs rm -v' - // Hack: ignore NVTT - sh "echo '' > libraries/source/nvtt/build.sh" - docker.image("0ad-gcc7:latest").inside { - stage("Update Workspaces") { - if (params.NO_PCH) { - sh "build/workspaces/update-workspaces.sh -j1 --without-pch" - } else { - sh "build/workspaces/update-workspaces.sh -j1" - } - } - stage("Build") { - if (params.DEBUG) { - sh "cd build/workspaces/gcc/ && make -j1 config=debug" - } - sh "cd build/workspaces/gcc/ && make -j1 config=release" - } - stage("Run tests") { - if (params.DEBUG) { - sh "binaries/system/test_dbg" - } - sh "binaries/system/test" - } - } - } - } - } - } - } - post { - always { - sh "sudo zfs destroy zpool0/custom" - } - } -} diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-differential-custom.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-differential-custom.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-differential-custom.Jenkinsfile 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-differential-custom.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -0,0 +1,194 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +// This pipeline is used to build patches on various compilers. + +def compilers = [] +if (params["With Clang"]) +{ + compilers = ["clang7"] +} +else +{ + compilers = ["gcc7"] +} + +def patchesMap = compilers.collectEntries { + ["${it}": patch(it)] +} +def patch(compiler) { + return { + stage("Patch: ${compiler}") { + try { + ws("/zpool0/${compiler}") { + sh "arc patch ${params.DIFF_ID} --force" + } + } catch(e) { + sh "sudo zfs rollback zpool0/${compiler}@latest" + throw e + } + } + } +} + +def buildsMap = compilers.collectEntries { + ["${it}": build(it)] +} +def build(compiler) { + return { + stage("Build: ${compiler}") { + try { + ws("/zpool0/${compiler}") { + docker.image("0ad-${compiler}:latest").inside { + script { + def NoAudioOption = "" + def NoPchOption = "" + def GlesOption = "" + def NoLobbyOption = "" + + if (params["No PCH"]) + { + NoPchOption="--without-pch " + } + if (params["OpenGL ES"]) + { + GlesOption="--gles " + } + if (params["No Audio"]) + { + NoAudioOption="--without-audio " + } + if (params["No Lobby"]) + { + NoLobbyOption="--without-lobby " + } + + sh "build/workspaces/update-workspaces.sh ${NoAudioOption}${GlesOption}${NoPchOption}${NoLobbyOption} -j1" + } + test_env="this is test env" + withEnv(["CXXFLAGS=${params.CXXFLAGS}", "CFLAGS=${params.CFLAGS}", "LDFLAGS=${params.LDFLAGS}"]){ + if (params["CXXFLAGS"]) + { + echo "Custom CXXFLAGS: ${env.CXXFLAGS}" + } + if (params["CFLAGS"]) + { + echo "Custom CFLAGS: ${env.CFLAGS}" + } + if (params["Debug Build"]) + { + def debugBuildErrorFile = "builderr-debug-${compiler}.log" + try { + try { + sh ''' + CC_VERSION="$($CC --version | sed -e \'s/version//g\' -e \'s/(.*)//g' -e \'s/\\s//\' | sed 1q)" + CXX_VERSION="$($CXX --version | sed -e \'s/version//g\' -e \'s/(.*)//g' -e \'s/\\s//\' | sed 1q)" + echo "Building pyrogenesis in debug with $CC_VERSION/$CXX_VERSION using 2 jobs..." + ''' + sh "cd build/workspaces/gcc/ && make config=debug clean && make -j2 config=debug 2> ../../../${debugBuildErrorFile}" + } catch(e) { + sh "rm -rf build/workspaces/gcc/obj/test_Debug" + throw e + } + } catch(e) { + throw e + } finally { + archiveArtifacts artifacts: "${debugBuildErrorFile}", fingerprint: true + } + + def debugBuildTestFile = "cxxtest-debug-${compiler}.log" + try { + sh "binaries/system/test_dbg > ${debugBuildTestFile}" + } catch (e) { + echo (message: readFile (file: "${debugBuildTestFile}")) + throw e + } finally { + archiveArtifacts artifacts: "${debugBuildTestFile}", fingerprint: true + } + } + def releaseBuildErrorFile = "builderr-release-${compiler}.log" + try { + try { + sh ''' + CC_VERSION="$($CC --version | sed -e \'s/version//g\' -e \'s/(.*)//g' -e \'s/\\s//\' | sed 1q)" + CXX_VERSION="$($CXX --version | sed -e \'s/version//g\' -e \'s/(.*)//g' -e \'s/\\s//\' | sed 1q)" + echo "Building pyrogenesis in release with $CC_VERSION/$CXX_VERSION using 2 jobs..." + ''' + sh "cd build/workspaces/gcc/ && make clean && make -j2 config=release 2> ../../../${releaseBuildErrorFile}" + } catch(e) { + sh "rm -rf build/workspaces/gcc/obj/test_Release" + throw e + } + } catch(e) { + throw e + } finally { + archiveArtifacts artifacts: "${releaseBuildErrorFile}", fingerprint: true + } + + def releaseBuildTestFile = "cxxtest-release-${compiler}.log" + try { + sh "binaries/system/test > ${releaseBuildTestFile}" + } catch (e) { + echo (message: readFile (file: "${releaseBuildTestFile}")) + throw e + } finally { + archiveArtifacts artifacts: "${releaseBuildTestFile}", fingerprint: true + } + } + } + } + } catch (e) { + throw e + } finally { + sh "sudo zfs rollback zpool0/${compiler}@latest" + } + } + } +} + +pipeline { + agent { + node { + label 'LinuxSlave' + customWorkspace '/zpool0/trunk' + } + } + parameters { + string(name: 'DIFF_ID', defaultValue: '', description: 'ID of the Phabricator Differential.') + booleanParam(name: 'OpenGL ES', defaultValue: false, description: 'Build with --gles.') + booleanParam(name: 'No PCH', defaultValue: false, description: 'Build with --without-pch.') + booleanParam(name: 'No Audio', defaultValue: false, description: 'Build with --without-audio.') + booleanParam(name: 'No Lobby', defaultValue: false, description: 'Build with --without-lobby.') + } + + stages { + stage("Patch") { + when { expression { return !!params.DIFF_ID } } + steps { + script { parallel patchesMap } + } + } + stage("Build") { + options { + timeout(time: 2, unit: 'HOURS') + } + steps { + script { parallel buildsMap } + } + } + } +} diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-differential.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-differential.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-differential.Jenkinsfile 2021-07-27 21:57:40.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-differential.Jenkinsfile 2022-09-23 19:16:45.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ // This pipeline is used to build patches on various compilers. -def compilers = ["gcc7"] +def compilers = ["gcc7", "clang7"] def patchesMap = compilers.collectEntries { ["${it}": patch(it)] @@ -46,6 +46,7 @@ try { ws("/zpool0/${compiler}") { docker.image("0ad-${compiler}:latest").inside { + sh "build/workspaces/update-workspaces.sh -j1 --jenkins-tests" try { @@ -120,6 +121,7 @@ stages { stage("Patch") { + when { expression { return !!params.DIFF_ID } } steps { sh "arc patch --diff ${params.DIFF_ID} --force" script { parallel patchesMap } @@ -157,13 +159,13 @@ steps { script { try { - // arc lint outputs an empty file on success - unless there is nothing to lint. + // arc lint outputs an empty file on success - unless there is nothing to lint. // On failure, it'll output the file and a failure error code. // Explicitly checking for the file presence is thus best to detect the linter did run - sh 'arc lint --output jenkins --outfile .phabricator-lint && touch .phabricator-lint' + sh 'arc lint --never-apply-patches --output jenkins --outfile .phabricator-lint && touch .phabricator-lint' } catch (e) { if (!fileExists(".phabricator-lint")) { - sh '''echo '{ "path": "general", code": "Jenkins", "severity": "error", "name": "ci-error", "description": "Error running lint", "bypassChangedLineFiltering": true }' > .phabricator-lint ''' + sh '''echo '{"General":[{"line": 0, "char": 0, "code": "Jenkins", "severity": "error", "name": "ci-error", "description": "Error running lint", "original": null, "replacement": null, "granularity": 1, "locations": [], "bypassChangedLineFiltering": true, "context": null}]}' > .phabricator-lint ''' } } } @@ -172,7 +174,7 @@ stage("Data checks") { steps { warnError('CheckRefs.pl script failed!') { - sh "cd source/tools/entity/ && perl checkrefs.pl --check-map-xml --validate-templates 2> data-errors.txt" + sh "cd source/tools/entity/ && python3 checkrefs.py -tax 2> data-errors.txt" } } } diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-docs.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-docs.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-docs.Jenkinsfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-docs.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -1,73 +1,80 @@ -/* Copyright (C) 2021 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -// This pipeline is used to build the documentation. - -pipeline { - agent { - node { - label 'LinuxSlave' - } - } - stages { - stage("Setup") { - steps { - sh "sudo zfs clone zpool0/gcc7@latest zpool0/entity-docs" - } - } - stage("Engine docs") { - steps { - ws("/zpool0/entity-docs"){ - sh "cd docs/doxygen/ && doxygen config" - } - } - } - stage("Build") { - steps { - ws("/zpool0/entity-docs"){ - sh "build/workspaces/update-workspaces.sh --disable-atlas --without-tests -j1" - sh "cd build/workspaces/gcc/ && make pyrogenesis -j1" - } - } - } - stage("Entity docs") { - steps { - ws("/zpool0/entity-docs"){ - sh "cd binaries/system/ && ./pyrogenesis -mod=public -dumpSchema" - sh "cd source/tools/entdocs/ && ./build.sh" - } - } - } - stage("Upload") { - steps { - ws("/zpool0/entity-docs"){ - sh "rsync -rti --delete-after --progress docs/doxygen/html/ docs.wildfiregames.com:~/www/pyrogenesis/" - sh "rsync -ti --progress source/tools/entdocs/entity-docs.html docs.wildfiregames.com:~/www/entity-docs/trunk.html" - sh "rsync -ti --progress source/tools/entdocs/entity-docs.css docs.wildfiregames.com:~/www/entity-docs/" - } - } - } - } - post { - always { - ws("/zpool0/trunk") { - sleep 10 - sh "sudo zfs destroy zpool0/entity-docs" - } - } - } -} +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +// This pipeline is used to build the documentation. + +pipeline { + agent { + node { + label 'LinuxSlave' + } + } + stages { + stage("Setup") { + steps { + sh "sudo zfs clone zpool0/gcc7@latest zpool0/entity-docs" + } + } + stage("Engine docs") { + steps { + ws("/zpool0/entity-docs"){ + sh "cd docs/doxygen/ && doxygen config" + } + } + } + stage("Build") { + steps { + ws("/zpool0/entity-docs"){ + sh "build/workspaces/update-workspaces.sh --disable-atlas --without-tests -j1" + sh "cd build/workspaces/gcc/ && make pyrogenesis -j1" + } + } + } + stage("Entity docs") { + steps { + ws("/zpool0/entity-docs"){ + sh "cd binaries/system/ && ./pyrogenesis -mod=public -dumpSchema" + sh "cd source/tools/entdocs/ && ./build.sh" + } + } + } + stage("Template Analyzer") { + steps { + ws("/zpool0/entity-docs"){ + sh "cd source/tools/templatesanalyzer/ && python3 unitTables.py" + } + } + } + stage("Upload") { + steps { + ws("/zpool0/entity-docs"){ + sh "rsync -rti --delete-after --progress docs/doxygen/html/ docs.wildfiregames.com:~/www/pyrogenesis/" + sh "rsync -ti --progress source/tools/entdocs/entity-docs.html docs.wildfiregames.com:~/www/entity-docs/trunk.html" + sh "rsync -ti --progress source/tools/templatesanalyzer/unit_summary_table.html docs.wildfiregames.com:~/www/templatesanalyzer/index.html" + } + } + } + } + post { + always { + ws("/zpool0/trunk") { + sleep 10 + sh "sudo zfs destroy zpool0/entity-docs" + } + } + } +} diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-rebuild.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-rebuild.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-rebuild.Jenkinsfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-rebuild.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ // This pipeline is used to build a clean base from scratch in order to // use ZFS snapshots efficiently. -def compilers = ["gcc7"] +def compilers = ["gcc7", "clang7"] def volumeUpdatesMap = compilers.collectEntries { ["${it}": volumeUpdate(it)] diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-svn-no-pch.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-svn-no-pch.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-svn-no-pch.Jenkinsfile 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-svn-no-pch.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -0,0 +1,64 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +// This pipeline is used to build the documentation. + +pipeline { + agent { + node { + label 'LinuxSlave' + } + } + stages { + stage("Setup") { + steps { + sh "sudo zfs clone zpool0/gcc7@latest zpool0/docker-nopch" + } + } + stage("Build") { + steps { + ws("/zpool0/docker-nopch"){ + dir('build/workspaces/'){ + sh "./update-workspaces.sh -j1 --without-pch" + dir('gcc/'){ + sh "make clean" + sh "make -j1" + } + } + } + } + } + stage("Test") { + steps { + ws("/zpool0/docker-nopch"){ + dir('build/workspaces/gcc'){ + // as where it was built else nothing is generated. + sh "../../../binaries/system/test" + } + } + } + } + } + post { + always { + ws("/zpool0/trunk") { + sleep 10 + sh "sudo zfs destroy zpool0/docker-nopch" + } + } + } +} diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/docker-translations.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/docker-translations.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/docker-translations.Jenkinsfile 2021-07-27 21:57:40.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/docker-translations.Jenkinsfile 2022-09-23 19:16:40.000000000 +0000 @@ -29,6 +29,11 @@ stage("Prepare volume") { steps { sh "sudo zfs clone zpool0/trunk@latest zpool0/translations" + ws('/zpool0/translations') { + sh "svn revert . -R" + sh "svn st | cut -c 9- | xargs rm -rf" + sh "svn up" + } } } @@ -36,7 +41,11 @@ steps { ws('/zpool0/translations') { withDockerContainer("0ad-translations:latest") { - sh "sh source/tools/i18n/maintenanceTasks.sh" + sh "python3 --version" + dir("source/tools/i18n/") { + sh "./maintenanceTasks.sh" + sh "python3 generateDebugTranslation.py --long" + } } } } @@ -47,7 +56,6 @@ ws('/zpool0/translations') { withCredentials([usernamePassword(credentialsId: 'redacted', passwordVariable: 'SVNPASS', usernameVariable: 'SVNUSER')]) { sh "svn relocate --username ${SVNUSER} --password ${SVNPASS} --no-auth-cache https://svn.wildfiregames.com/svn/ps/trunk" - sh "svn add --force binaries/" sh "svn commit --username ${SVNUSER} --password ${SVNPASS} --no-auth-cache --non-interactive -m '[i18n] Updated POT and PO files.'" } } diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/macos-all-bundles.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/macos-all-bundles.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/macos-all-bundles.Jenkinsfile 2021-08-25 14:46:06.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/macos-all-bundles.Jenkinsfile 2022-09-23 19:16:45.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,9 +24,12 @@ } parameters { - string(name: 'BUNDLE_VERSION', defaultValue: '0.0.24dev', description: 'Bundle Version') + string(name: 'BUNDLE_VERSION', defaultValue: '0.0.26dev', description: 'Bundle Version') string(name: 'SVN_REV', defaultValue: 'HEAD', description: 'For instance 21000') booleanParam(name: 'ONLY_MOD', defaultValue: true, description: 'Only archive the mod mod.') + booleanParam(name: 'DO_GZIP', defaultValue: true, description: 'Create .gz unix tarballs as well as .xz') + booleanParam(name: 'FULL_REBUILD', defaultValue: true, description: 'Do a full rebuild (safer for release, slower).') + booleanParam(name: 'WINDOWS_UNIX', defaultValue: true, description: 'Build windows and unix bundles.') } stages { @@ -37,45 +40,62 @@ steps { script { try { - svn "https://svn.wildfiregames.com/public/ps/trunk@${params.SVN_REV}" + sh "svn co https://svn.wildfiregames.com/public/ps/trunk@${params.SVN_REV} ." } catch(e) { sh "svn cleanup" sleep 300 throw e } + sh "svn cleanup" + // Delete unknown files everywhere except libraries/ + sh "svn st --no-ignore . --depth immediates | cut -c 9- | xargs rm -rfv" + sh "svn st --no-ignore {binaries/,build/,source/} | cut -c 9- | xargs rm -rfv" + if (params.FULL_REBUILD) { + // Also delete libraries/ + sh "svn st --no-ignore | cut -c 9- | xargs rm -rfv" + } + sh "svn revert . -R" } - sh "svn cleanup" - sh "svn revert . -R" - sh "svn st --no-ignore | cut -c 9- | xargs rm -rfv" } } stage("Compile Mac Executable") { steps { - sh "source/tools/dist/build-osx-executable.sh" + sh "JOBS=\"-j\$(sysctl -n hw.ncpu)\" FULL_REBUILD=${params.FULL_REBUILD} source/tools/dist/build-osx-executable.sh" } } stage("Create archive data") { steps { - sh "ONLY_MOD=${ONLY_MOD} source/tools/dist/build-archives.sh" + sh "JOBS=\"-j\$(sysctl -n hw.ncpu)\" ONLY_MOD=${params.ONLY_MOD} source/tools/dist/build-archives.sh" } } stage("Create Mac Bundle") { steps { - sh "python3 source/tools/dist/build-osx-bundle.py ${BUNDLE_VERSION}" + sh "python3 source/tools/dist/build-osx-bundle.py ${params.BUNDLE_VERSION}" } } stage("Create Windows installer & *nix files") { steps { - // The files created by the mac compilation need to be deleted - sh "svn st binaries/ --no-ignore | cut -c 9- | xargs rm -rf" - sh "svn st build/ --no-ignore | cut -c 9- | xargs rm -rf" - sh "svn st libraries/ --no-ignore | cut -c 9- | xargs rm -rf" - // The generated tests use hardcoded paths so they must be deleted as well. - sh 'python3 -c \"import glob; print(\\\" \\\".join(glob.glob(\\\"source/**/tests/**.cpp\\\", recursive=True)));\" | xargs rm -v' - sh "svn revert build/ -R" - - // Then run the core object. - sh "BUNDLE_VERSION=${BUNDLE_VERSION} source/tools/dist/build-unix-win32.sh" + script { + if(params.WINDOWS_UNIX) + { + // The files created by the mac compilation need to be deleted + sh "svn st {binaries/,build/} --no-ignore | cut -c 9- | xargs rm -rfv" + // Hide the libraries folder. + sh "mv libraries/ temp_libraries/" + sh "svn revert libraries/ -R" + // The generated tests use hardcoded paths so they must be deleted as well. + sh 'python3 -c \"import glob; print(\\\" \\\".join(glob.glob(\\\"source/**/tests/**.cpp\\\", recursive=True)));\" | xargs rm -v' + sh "svn revert build/ -R" + try { + // Then run the core object. + sh "JOBS=\"-j\$(sysctl -n hw.ncpu)\" BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh" + } finally { + // Un-hide the libraries. + sh "rm -rfv libraries/" + sh "mv temp_libraries/ libraries/" + } + } + } } } } diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/macos-differential.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/macos-differential.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/macos-differential.Jenkinsfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/macos-differential.Jenkinsfile 2022-08-21 12:46:46.000000000 +0000 @@ -35,7 +35,7 @@ steps { script { try { - svn "https://svn.wildfiregames.com/public/ps/trunk" + sh "svn update" } catch(e) { sh "svn cleanup" sleep 300 @@ -51,8 +51,10 @@ try { sh "arc patch --diff ${params.DIFF_ID} --force" } catch (e) { + sh "svn st binaries/data/ | cut -c 9- | xargs rm -rfv" + sh "svn st source/ | cut -c 9- | xargs rm -rfv" + sh "svn st -q | cut -c 9- | xargs rm -rfv" sh "svn revert -R ." - sh "svn st | cut -c 9- | xargs rm -rf" sh "arc patch --diff ${params.DIFF_ID} --force" } } @@ -112,10 +114,10 @@ catchError { sh ''' for file in builderr-*.txt ; do - if [ -s "$file" ]; then - echo "$file" >> .phabricator-comment - cat "$file" >> .phabricator-comment - fi + if [ -s "$file" ]; then + echo "$file" >> .phabricator-comment + cat "$file" >> .phabricator-comment + fi done ''' } @@ -130,9 +132,10 @@ throw e } finally { sh "rm -f .phabricator-comment builderr-*.txt cxxtest-*.xml" + sh "svn st binaries/data/ | cut -c 9- | xargs rm -rfv" + sh "svn st source/ | cut -c 9- | xargs rm -rfv" + sh "svn st -q | cut -c 9- | xargs rm -rfv" sh "svn revert -R ." - sh "svn st binaries/data/ | cut -c 9- | xargs rm -rf" - sh "svn st source/ | cut -c 9- | xargs rm -rf" } } } diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/vs2015-autobuild.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/vs2015-autobuild.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/vs2015-autobuild.Jenkinsfile 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/vs2015-autobuild.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -55,12 +55,12 @@ stage('Setup workspace') { steps { - bat "del binaries\\system\\pyrogenesis.pdb binaries\\system\\pyrogenesis.exe" - script { + bat "del binaries\\system\\pyrogenesis.pdb binaries\\system\\pyrogenesis.exe" + script { if (env.atlas == 'true') { echo "atlas is enabled" AtlasOption = "--atlas" - AtlasPrj = "/t:AtlasUI" + AtlasPrj = "/t:AtlasUI /t:ActorEditor" bat "(robocopy /MIR C:\\wxwidgets-3.1.4\\lib libraries\\win32\\wxwidgets\\lib) ^& IF %ERRORLEVEL% LEQ 1 exit 0" bat "(robocopy /MIR C:\\wxwidgets-3.1.4\\include libraries\\win32\\wxwidgets\\include) ^& IF %ERRORLEVEL% LEQ 1 exit 0" bat "del binaries\\system\\AtlasUI.dll" @@ -76,23 +76,24 @@ bat "del binaries\\system\\Collada.dll" } output = bat(returnStdout: true, script: 'svnversion source -n').trim() - output = output.readLines().drop(1).join("") + output = (output.readLines().drop(1).join("").toInteger() + 1) } bat "cd build\\workspaces && update-workspaces.bat ${AtlasOption} ${GlooxOption} --large-address-aware --jenkins-tests" bat "echo L\"${output}\" > build\\svn_revision\\svn_revision.txt" + bat "echo ${output}" } } stage ('Build') { steps { - bat("cd build\\workspaces\\vs2017 && \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\" pyrogenesis.sln /m:${jobs} /p:PlatformToolset=v141_xp /t:pyrogenesis ${AtlasPrj} /t:test /p:Configuration=Release") + bat("cd build\\workspaces\\vs2017 && \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\" pyrogenesis.sln /nologo /p:XPDeprecationWarning=false /p:XPDeprecationWarning=false /m:${jobs} /p:PlatformToolset=v141_xp /t:pyrogenesis ${AtlasPrj} /t:test /p:Configuration=Release") } } stage ('Build debug glooxwrapper') { when { environment name: 'gloox', value: 'true'} steps { - bat("cd build\\workspaces\\vs2017 && \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\" pyrogenesis.sln /m:${jobs} /p:PlatformToolset=v141_xp /t:glooxwrapper /p:Configuration=Debug") + bat("cd build\\workspaces\\vs2017 && \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\" pyrogenesis.sln /nologo /p:XPDeprecationWarning=false /p:XPDeprecationWarning=false /m:${jobs} /p:PlatformToolset=v141_xp /t:glooxwrapper /p:Configuration=Debug") } } @@ -110,11 +111,11 @@ steps { bat "svn changelist --remove --recursive --cl commit ." script { - if (env.pyrogenesis == 'true') { + if (env.pyrogenesis == 'true') { bat "svn changelist commit binaries\\system\\pyrogenesis.pdb binaries\\system\\pyrogenesis.exe" } if (env.atlas == 'true') { - bat "svn changelist commit binaries\\system\\AtlasUI.dll" + bat "svn changelist commit binaries\\system\\AtlasUI.dll binaries\\system\\ActorEditor.exe" } if (env.collada == 'true') { bat "svn changelist commit binaries\\system\\Collada.dll" diff -Nru 0ad-0.0.25b/build/jenkins/pipelines/vs2015-differential.Jenkinsfile 0ad-0.0.26/build/jenkins/pipelines/vs2015-differential.Jenkinsfile --- 0ad-0.0.25b/build/jenkins/pipelines/vs2015-differential.Jenkinsfile 2021-07-27 21:57:40.000000000 +0000 +++ 0ad-0.0.26/build/jenkins/pipelines/vs2015-differential.Jenkinsfile 2022-09-23 19:16:41.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,6 +18,13 @@ // This pipeline is used to build patches on MSVC 15.0 (Visual Studio 2017). def jobs = "2" +def visualStudioPath = "\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\"" +def cleanFiles() { + bat 'powershell.exe "svn st -q | ForEach-Object { Remove-Item -ErrorAction Ignore -Recurse -Force -Verbose -LiteralPath $_.substring(8) } " ' + bat 'powershell.exe "svn st binaries/data | ForEach-Object { Remove-Item -ErrorAction Ignore -Recurse -Verbose -Force -LiteralPath $_.substring(8) } " ' + bat 'powershell.exe "svn st source/ | ForEach-Object { Remove-Item -ErrorAction Ignore -Recurse -Force -Verbose -LiteralPath $_.substring(8) } " ' + bat 'svn revert -R .' +} pipeline { agent { label 'WindowsSlave' } options { @@ -53,8 +60,7 @@ try { bat "arc patch --diff ${params.DIFF_ID} --force" } catch (e) { - bat 'svn revert -R .' - bat 'powershell.exe "svn st --no-ignore | %% {$_.substring(8)} | del -r" ' + cleanFiles() bat "arc patch --diff ${params.DIFF_ID} --force" } } @@ -62,15 +68,15 @@ } stage ('Update-Workspace') { steps { - bat "(robocopy /MIR C:\\wxwidgets3.0.4\\lib libraries\\win32\\wxwidgets\\lib) ^& IF %ERRORLEVEL% LEQ 1 exit 0" - bat "(robocopy /MIR C:\\wxwidgets3.0.4\\include libraries\\win32\\wxwidgets\\include) ^& IF %ERRORLEVEL% LEQ 1 exit 0" + bat "(robocopy /MIR /NDL /NJH /NJS /NP /NS /NC C:\\wxwidgets3.0.4\\lib libraries\\win32\\wxwidgets\\lib) ^& IF %ERRORLEVEL% LEQ 1 exit 0" + bat "(robocopy /MIR /NDL /NJH /NJS /NP /NS /NC C:\\wxwidgets3.0.4\\include libraries\\win32\\wxwidgets\\include) ^& IF %ERRORLEVEL% LEQ 1 exit 0" bat "cd build\\workspaces && update-workspaces.bat --atlas --build-shared-glooxwrapper --jenkins-tests" } } stage ('Debug: Build') { steps { dir('build\\workspaces\\vs2017'){ - bat("\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\" pyrogenesis.sln /p:XPDeprecationWarning=false /m:${jobs} /p:PlatformToolset=v141_xp /t:pyrogenesis /t:AtlasUI /t:test /p:Configuration=Debug -clp:Warningsonly -clp:ErrorsOnly > ..\\..\\..\\build-errors-debug.txt 2>&1") + bat("${visualStudioPath} pyrogenesis.sln /nologo /p:XPDeprecationWarning=false /m:${jobs} /p:PlatformToolset=v141_xp /t:pyrogenesis /t:AtlasUI /t:test /p:Configuration=Debug -clp:Warningsonly -clp:ErrorsOnly > ..\\..\\..\\build-errors-debug.txt 2>&1") } } post { @@ -84,7 +90,7 @@ timeout(time: 30) } steps { - catchError { // Debug tests might not work on Windows, see #3753. uncomment just below if they do work. + catchError { script { try { bat 'binaries\\system\\test_dbg.exe > cxxtest_debug.xml' @@ -97,16 +103,18 @@ post { failure { echo (message: readFile (file: "cxxtest_debug.xml")) + archiveArtifacts artifacts: "cxxtest_debug.xml", fingerprint: true } always { junit "cxxtest_debug.xml" + archiveArtifacts artifacts: "cxxtest_debug.xml", fingerprint: true } } } stage ('Release: Build') { steps { dir('build\\workspaces\\vs2017'){ - bat("\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe\" pyrogenesis.sln /p:XPDeprecationWarning=false /m:${jobs} /p:PlatformToolset=v141_xp /t:pyrogenesis /t:AtlasUI /t:test /p:Configuration=Release -clp:Warningsonly -clp:ErrorsOnly > ..\\..\\..\\build-errors-release.txt 2>&1") + bat("${visualStudioPath} pyrogenesis.sln /nologo /p:XPDeprecationWarning=false /m:${jobs} /p:PlatformToolset=v141_xp /t:pyrogenesis /t:AtlasUI /t:test /p:Configuration=Release -clp:Warningsonly -clp:ErrorsOnly > ..\\..\\..\\build-errors-release.txt 2>&1") } } post { @@ -136,9 +144,9 @@ always { script { catchError { - bat "if exist build-errors-debug.txt echo Debug: >> .phabricator-comment" + bat 'powershell.exe "if (![String]::IsNullOrWhiteSpace((Get-Content -ErrorAction Ignore -Path build-errors-debug.txt))) { Add-Content .phabricator-comment Debug: }" ' bat "if exist build-errors-debug.txt type build-errors-debug.txt >> .phabricator-comment" - bat "if exist build-errors-release.txt echo Release: >> .phabricator-comment" + bat 'powershell.exe "if (![String]::IsNullOrWhiteSpace((Get-Content -ErrorAction Ignore -Path build-errors-release.txt))) { Add-Content .phabricator-comment Release: }" ' bat "if exist build-errors-release.txt type build-errors-release.txt >> .phabricator-comment" } try { @@ -153,9 +161,7 @@ bat 'del build-errors-debug.txt' bat 'del build-errors-release.txt' bat 'del cxxtest_*.xml' - bat 'svn revert -R .' - bat 'powershell.exe "svn st binaries/data | %% {$_.substring(8)} | del -r " ' - bat 'powershell.exe "svn st source/ | %% {$_.substring(8)} | del -r " ' + cleanFiles() } } } diff -Nru 0ad-0.0.25b/build/premake/extern_libs5.lua 0ad-0.0.26/build/premake/extern_libs5.lua --- 0ad-0.0.25b/build/premake/extern_libs5.lua 2021-07-27 21:57:08.000000000 +0000 +++ 0ad-0.0.26/build/premake/extern_libs5.lua 2022-08-21 12:45:49.000000000 +0000 @@ -39,6 +39,11 @@ pkgconfig = require "pkgconfig" +-- Configure pkgconfig for MacOSX systems +if os.istarget("macosx") then + pkgconfig.additional_pc_path = libraries_dir .. "pkgconfig/" + pkgconfig.static_link_libs = true +end local function add_delayload(name, suffix, def) @@ -228,18 +233,21 @@ }, enet = { compile_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_include_paths("enet") + else + pkgconfig.add_includes("libenet") end end, link_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_lib_paths("enet") + add_default_links({ + win_names = { "enet" }, + }) + else + pkgconfig.add_links("libenet") end - add_default_links({ - win_names = { "enet" }, - unix_names = { "enet" }, - }) end, }, fcollada = { @@ -265,16 +273,18 @@ }, fmt = { compile_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_include_paths("fmt") + elseif os.istarget("macosx") then + pkgconfig.add_includes("fmt") end -- With Linux & BSD, we assume that fmt is installed in a standard location. -- - -- It would be nice to not assume, and to instead use pkgconfig: however that + -- It would be nice to not assume, and to instead use pkg-config: however that -- requires fmt 5.3.0 or greater. -- - -- Unfortunately (at the time of writing) only 69 out of 95 (~72.6%) of distros + -- Unfortunately (at the time of writing) only 92 out of 114 (~80.7%) of distros -- that provide a fmt package meet this, according to -- https://repology.org/badge/vertical-allrepos/fmt.svg?minversion=5.3 -- @@ -284,38 +294,55 @@ -- Mint). -- -- When fmt 5.3 (or better) becomes more widely used, then we can safely use the - -- following line: - -- pkgconfig.add_includes("fmt") + -- same line as we currently use for osx end, link_settings = function() - if os.istarget("windows") or os.istarget("macosx") then - add_default_lib_paths("fmt") - end - if os.istarget("windows") then + add_default_lib_paths("fmt") add_default_links({ win_names = { "fmt" }, dbg_suffix = "d", no_delayload = 1, }) + elseif os.istarget("macosx") then + -- See comment above as to why this is not also used on Linux or BSD. + pkgconfig.add_links("fmt") else add_default_links({ unix_names = { "fmt" }, }) - - -- See comment above as to why this is commented out. - -- pkgconfig.add_links("fmt") end end }, + freetype = { + compile_settings = function() + if os.istarget("windows") then + add_default_include_paths("freetype") + else + pkgconfig.add_includes("freetype2") + end + end, + link_settings = function() + if os.istarget("windows") then + add_default_lib_paths("freetype") + else + pkgconfig.add_links("freetype2") + end + add_default_links({ + win_names = { "freetype" }, + no_delayload = 1, + }) + end, + }, + glad = { + add_source_include_paths("glad") + }, gloox = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("gloox") else - -- Support GLOOX_CONFIG for overriding the default (pkg-config --cflags gloox) - -- i.e. on OSX where it gets set in update-workspaces.sh - pkgconfig.add_includes("gloox", os.getenv("GLOOX_CONFIG")) + pkgconfig.add_includes("gloox") end end, link_settings = function() @@ -326,17 +353,12 @@ no_delayload = 1, }) else - pkgconfig.add_links("gloox", os.getenv("GLOOX_CONFIG")) + pkgconfig.add_links("gloox") if os.istarget("macosx") then - -- Manually add gnutls dependencies, those are not present in gloox's pkg-config - add_default_lib_paths("nettle") - add_default_lib_paths("gmp") - add_default_links({ - osx_names = { "nettle", "hogweed", "gmp" }, - }) + -- gloox depends on gnutls, but doesn't identify this via pkg-config + pkgconfig.add_links("gnutls") end - end end, }, @@ -373,9 +395,7 @@ if os.istarget("windows") then add_default_include_paths("icu") else - -- Support ICU_CONFIG for overriding the default (pkg-config --cflags icu-i18n) - -- i.e. on OSX where it gets set in update-workspaces.sh - pkgconfig.add_includes("icu-i18n", os.getenv("ICU_CONFIG"), "--cppflags") + pkgconfig.add_includes("icu-i18n") end end, link_settings = function() @@ -387,25 +407,27 @@ no_delayload = 1, }) else - pkgconfig.add_links("icu-i18n", os.getenv("ICU_CONFIG"), "--ldflags-searchpath --ldflags-libsonly --ldflags-system") + pkgconfig.add_links("icu-i18n") end end, }, libcurl = { compile_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_include_paths("libcurl") + else + pkgconfig.add_includes("libcurl") end end, link_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_lib_paths("libcurl") + else + pkgconfig.add_links("libcurl") end add_default_links({ win_names = { "libcurl" }, - unix_names = { "curl" }, - osx_names = { "curl", "z" }, - osx_frameworks = { "Security" } + osx_frameworks = { "Security" }, -- Not supplied by curl's pkg-config }) end, }, @@ -414,9 +436,7 @@ if os.istarget("windows") then add_default_include_paths("libpng") else - -- Support LIBPNG_CONFIG for overriding the default (pkg-config --cflags libpng) - -- i.e. on OSX where it gets set in update-workspaces.sh - pkgconfig.add_includes("libpng", os.getenv("LIBPNG_CONFIG")) + pkgconfig.add_includes("libpng") end end, link_settings = function() @@ -426,24 +446,27 @@ win_names = { "libpng16" }, }) else - pkgconfig.add_links("libpng", os.getenv("LIBPNG_CONFIG"), "--ldflags") + pkgconfig.add_links("libpng") end end, }, libsodium = { compile_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_include_paths("libsodium") + else + pkgconfig.add_includes("libsodium") end end, link_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_lib_paths("libsodium") + add_default_links({ + win_names = { "libsodium" }, + }) + else + pkgconfig.add_links("libsodium") end - add_default_links({ - win_names = { "libsodium" }, - unix_names = { "sodium" }, - }) end, }, libxml2 = { @@ -451,14 +474,13 @@ if os.istarget("windows") then add_default_include_paths("libxml2") else - -- Support XML2_CONFIG for overriding the default (pkg-config --cflags libxml-2.0) - -- i.e. on OSX where it gets set in update-workspaces.sh - pkgconfig.add_includes("libxml-2.0", os.getenv("XML2_CONFIG")) - end - if os.istarget("macosx") then - -- libxml2 needs _REENTRANT or __MT__ for thread support; - -- OS X doesn't get either set by default, so do it manually - defines { "_REENTRANT" } + pkgconfig.add_includes("libxml-2.0") + + if os.istarget("macosx") then + -- libxml2 needs _REENTRANT or __MT__ for thread support; + -- OS X doesn't get either set by default, so do it manually + defines { "_REENTRANT" } + end end end, link_settings = function() @@ -470,24 +492,48 @@ links { "libxml2" } filter { } else - pkgconfig.add_links("libxml-2.0", os.getenv("XML2_CONFIG")) + pkgconfig.add_links("libxml-2.0") end end, }, miniupnpc = { compile_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_include_paths("miniupnpc") + elseif os.istarget("macosx") then + pkgconfig.add_includes("miniupnpc") end + + -- On Linux and BSD systems we assume miniupnpc is installed in a standard location. + -- + -- Support for pkg-config was added in v2.1 of miniupnpc (May 2018). However, the + -- implementation was flawed - it provided the wrong path to the project's headers. + -- This was corrected in v2.2.1 (December 2020). + -- + -- At the time of writing, of the 123 Linux and BSD package repositories tracked by + -- Repology that supply a version of miniupnpc: + -- * 88 (~71.54%) have >= v2.1, needed to locate libraries + -- * 50 (~40.65%) have >= v2.2.1, needed to (correctly) locate headers + -- + -- Once more recent versions become more widespread, we can safely start to use + -- pkg-config to find miniupnpc on Linux and BSD systems. + -- https://repology.org/badge/vertical-allrepos/miniupnpc.svg?minversion=2.2.1 end, link_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_lib_paths("miniupnpc") + add_default_links({ + win_names = { "miniupnpc" }, + }) + elseif os.istarget("macosx") then + pkgconfig.add_links("miniupnpc") + else + -- Once miniupnpc v2.1 or better becomes near-universal (see above comment), + -- we can use pkg-config for Linux and BSD. + add_default_links({ + unix_names = { "miniupnpc" }, + }) end - add_default_links({ - win_names = { "miniupnpc" }, - unix_names = { "miniupnpc" }, - }) end, }, nvtt = { @@ -513,44 +559,24 @@ compile_settings = function() if os.istarget("windows") then add_default_include_paths("openal") + elseif not os.istarget("macosx") then + pkgconfig.add_includes("openal") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("openal") - end - add_default_links({ - win_names = { "openal32" }, - unix_names = { "openal" }, - osx_frameworks = { "OpenAL" }, - dbg_suffix = "", - no_delayload = 1, -- delayload seems to cause errors on startup - }) - end, - }, - opengl = { - compile_settings = function() - if os.istarget("windows") then - add_default_include_paths("opengl") - end - end, - link_settings = function() - if os.istarget("windows") then - add_default_lib_paths("opengl") - end - if _OPTIONS["gles"] then add_default_links({ - unix_names = { "GLESv2" }, + win_names = { "openal32" }, dbg_suffix = "", + no_delayload = 1, -- delayload seems to cause errors on startup }) - else + elseif os.istarget("macosx") then add_default_links({ - win_names = { "opengl32", "gdi32" }, - unix_names = { "GL" }, - osx_frameworks = { "OpenGL" }, - dbg_suffix = "", - no_delayload = 1, -- delayload seems to cause errors on startup + osx_frameworks = { "OpenAL" }, }) + else + pkgconfig.add_links("openal") end end, }, @@ -559,16 +585,14 @@ if os.istarget("windows") then includedirs { libraries_dir .. "sdl2/include/SDL" } elseif not _OPTIONS["android"] then - -- Support SDL2_CONFIG for overriding the default (pkg-config sdl2) - -- i.e. on OSX where it gets set in update-workspaces.sh - pkgconfig.add_includes("sdl2", os.getenv("SDL2_CONFIG")) + pkgconfig.add_includes("sdl2") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("sdl2") elseif not _OPTIONS["android"] then - pkgconfig.add_links("sdl2", os.getenv("SDL2_CONFIG")) + pkgconfig.add_links("sdl2") end end, }, @@ -622,38 +646,40 @@ }, valgrind = { compile_settings = function() - add_source_include_paths("valgrind") + -- Optional dependency + -- + -- valgrind doesn't support windows: + -- https://valgrind.org/info/platforms.html + if _OPTIONS["with-valgrind"] and not os.istarget("windows") then + pkgconfig.add_includes("valgrind") + defines { "CONFIG2_VALGRIND=1" } + end end, }, vorbis = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("vorbis") - elseif os.istarget("macosx") then - add_default_include_paths("libogg") - add_default_include_paths("vorbis") + else + pkgconfig.add_includes("ogg") + pkgconfig.add_includes("vorbisfile") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("vorbis") - elseif os.istarget("macosx") then - add_default_lib_paths("libogg") - add_default_lib_paths("vorbis") - end - -- TODO: We need to force linking with these as currently - -- they need to be loaded explicitly on execution - if os.getversion().description == "OpenBSD" then add_default_links({ - unix_names = { "ogg", - "vorbis" }, + win_names = { "libvorbisfile" }, }) + elseif os.getversion().description == "OpenBSD" then + -- TODO: We need to force linking with these as currently + -- they need to be loaded explicitly on execution + add_default_links({ + unix_names = { "ogg", "vorbis" }, + }) + else + pkgconfig.add_links("vorbisfile") end - add_default_links({ - win_names = { "libvorbisfile" }, - unix_names = { "vorbisfile" }, - osx_names = { "vorbis", "vorbisenc", "vorbisfile", "ogg" }, - }) end, }, wxwidgets = { @@ -691,19 +717,22 @@ }, zlib = { compile_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_include_paths("zlib") + else + pkgconfig.add_includes("zlib") end end, link_settings = function() - if os.istarget("windows") or os.istarget("macosx") then + if os.istarget("windows") then add_default_lib_paths("zlib") + add_default_links({ + win_names = { "zlib1" }, + no_delayload = 1, + }) + else + pkgconfig.add_links("zlib") end - add_default_links({ - win_names = { "zlib1" }, - unix_names = { "z" }, - no_delayload = 1, - }) end, }, } diff -Nru 0ad-0.0.25b/build/premake/pkgconfig/pkgconfig.lua 0ad-0.0.26/build/premake/pkgconfig/pkgconfig.lua --- 0ad-0.0.25b/build/premake/pkgconfig/pkgconfig.lua 2021-07-27 21:57:39.000000000 +0000 +++ 0ad-0.0.26/build/premake/pkgconfig/pkgconfig.lua 2022-08-21 12:45:49.000000000 +0000 @@ -1,5 +1,8 @@ local m = {} -m._VERSION = "1.1.0-dev" +m._VERSION = "1.1.1-dev" + +m.additional_pc_path = nil +m.static_link_libs = false local function os_capture(cmd) return io.popen(cmd, 'r'):read('*a'):gsub("\n", " ") @@ -8,7 +11,8 @@ function m.add_includes(lib, alternative_cmd, alternative_flags) local result if not alternative_cmd then - result = os_capture("pkg-config --cflags "..lib) + local pc_path = m.additional_pc_path and "PKG_CONFIG_PATH="..m.additional_pc_path or "" + result = os_capture(pc_path.." pkg-config --cflags "..lib) else if not alternative_flags then result = os_capture(alternative_cmd.." --cflags") @@ -42,9 +46,11 @@ function m.add_links(lib, alternative_cmd, alternative_flags) local result if not alternative_cmd then - result = os_capture("pkg-config --libs "..lib) + local pc_path = m.additional_pc_path and "PKG_CONFIG_PATH="..m.additional_pc_path or "" + local static = m.static_link_libs and " --static " or "" + result = os_capture(pc_path.." pkg-config --libs "..static..lib) else - if not alternative_flags then + if not alternative_flags then result = os_capture(alternative_cmd.." --libs") else result = os_capture(alternative_cmd.." "..alternative_flags) diff -Nru 0ad-0.0.25b/build/premake/premake5.lua 0ad-0.0.26/build/premake/premake5.lua --- 0ad-0.0.25b/build/premake/premake5.lua 2021-07-27 21:57:08.000000000 +0000 +++ 0ad-0.0.26/build/premake/premake5.lua 2022-09-23 19:16:45.000000000 +0000 @@ -8,6 +8,7 @@ newoption { trigger = "outpath", description = "Location for generated project files" } newoption { trigger = "with-system-mozjs", description = "Search standard paths for libmozjs60, instead of using bundled copy" } newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" } +newoption { trigger = "with-valgrind", description = "Enable Valgrind support (non-Windows only)" } newoption { trigger = "without-audio", description = "Disable use of OpenAL/Ogg/Vorbis APIs" } newoption { trigger = "without-lobby", description = "Disable the use of gloox and the multiplayer lobby" } newoption { trigger = "without-miniupnpc", description = "Disable use of miniupnpc for port forwarding" } @@ -60,38 +61,52 @@ end end --- detect CPU architecture (simplistic, currently only supports x86, amd64 and ARM) +-- detect CPU architecture (simplistic) +-- The user can target an architecture with HOSTTYPE, but the game still selects some know value. arch = "x86" +macos_arch = "x86_64" + if _OPTIONS["android"] then arch = "arm" elseif os.istarget("windows") then - if os.getenv("PROCESSOR_ARCHITECTURE") == "amd64" or os.getenv("PROCESSOR_ARCHITEW6432") == "amd64" then + if os.getenv("HOSTTYPE") then + arch = os.getenv("HOSTTYPE") + elseif os.getenv("PROCESSOR_ARCHITECTURE") == "amd64" or os.getenv("PROCESSOR_ARCHITEW6432") == "amd64" then arch = "amd64" end else - arch = os.getenv("HOSTTYPE") - if arch == "x86_64" or arch == "amd64" then - arch = "amd64" + local machine = "x86_64" + if os.getenv("HOSTTYPE") and os.getenv("HOSTTYPE") ~= '' then + machine = os.getenv("HOSTTYPE") else os.execute(cc .. " -dumpmachine > .gccmachine.tmp") local f = io.open(".gccmachine.tmp", "r") - local machine = f:read("*line") + machine = f:read("*line") f:close() - if string.find(machine, "x86_64") == 1 or string.find(machine, "amd64") == 1 then - arch = "amd64" - elseif string.find(machine, "i.86") == 1 then - arch = "x86" - elseif string.find(machine, "arm") == 1 then - arch = "arm" - elseif string.find(machine, "aarch64") == 1 then + end + -- Special handling on mac os where xcode needs special flags. + if os.istarget("macosx") then + if string.find(machine, "arm64") then arch = "aarch64" - elseif string.find(machine, "e2k") == 1 then - arch = "e2k" - elseif string.find(machine, "ppc64") == 1 or string.find(machine, "powerpc64") == 1 then - arch = "ppc64" + macos_arch = "arm64" else - print("WARNING: Cannot determine architecture from GCC, assuming x86") + arch = "amd64" + macos_arch = "x86_64" end + elseif string.find(machine, "x86_64") == 1 or string.find(machine, "amd64") == 1 then + arch = "amd64" + elseif string.find(machine, "i.86") == 1 then + arch = "x86" + elseif string.find(machine, "arm") == 1 then + arch = "arm" + elseif string.find(machine, "aarch64") == 1 then + arch = "aarch64" + elseif string.find(machine, "e2k") == 1 then + arch = "e2k" + elseif string.find(machine, "ppc64") == 1 or string.find(machine, "powerpc64") == 1 then + arch = "ppc64" + else + print("WARNING: Cannot determine architecture from GCC, assuming x86") end end @@ -200,10 +215,6 @@ defines { "CONFIG2_MINIUPNPC=0" } end - -- required for the lowlevel library. must be set from all projects that use it, otherwise it assumes it is - -- being used as a DLL (which is currently not the case in 0ad) - defines { "LIB_STATIC_LINK" } - -- Enable C++17 standard. filter "action:vs*" buildoptions { "/std:c++17" } @@ -303,7 +314,9 @@ -- while tuning for generic to have good performance on every -- supported CPU. -- Note that all these features are already supported on amd64. - "-march=pentium3 -mtune=generic" + "-march=pentium3 -mtune=generic", + -- This allows x86 operating systems to handle the 2GB+ public mod. + "-D_FILE_OFFSET_BITS=64" } end end @@ -323,8 +336,8 @@ links { "gcov" } end - -- MacOS 10.12 only supports processors with SSE 4.1, so enable that. - if os.istarget("macosx") then + -- MacOS 10.12 only supports intel processors with SSE 4.1, so enable that. + if os.istarget("macosx") and arch == "amd64" then buildoptions { "-msse4.1" } end @@ -548,8 +561,14 @@ -- The exception to this principle is Atlas UI, which is not a static library. rtti "off" - if os.istarget("macosx") and _OPTIONS["macosx-version-min"] then - xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + if os.istarget("macosx") then + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } + if _OPTIONS["macosx-version-min"] then + xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + end end end @@ -572,8 +591,14 @@ if os.istarget("windows") then links { "delayimp" } - elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then - xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + elseif os.istarget("macosx") then + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } + if _OPTIONS["macosx-version-min"] then + xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + end end end @@ -705,7 +730,6 @@ } extern_libs = { "boost", - "opengl", "spidermonkey", "fmt", } @@ -746,7 +770,6 @@ "spidermonkey", "sdl", -- key definitions "libxml2", - "opengl", "zlib", "boost", "enet", @@ -756,6 +779,7 @@ "iconv", "libsodium", "fmt", + "freetype", } if not _OPTIONS["without-audio"] then @@ -770,16 +794,20 @@ "graphics", "graphics/scripting", "renderer", + "renderer/backend", + "renderer/backend/dummy", + "renderer/backend/gl", + "renderer/backend/vulkan", "renderer/scripting", "third_party/mikktspace", "third_party/ogre3d_preprocessor" } extern_libs = { - "opengl", "sdl", -- key definitions "spidermonkey", -- for graphics/scripting "boost", "fmt", + "freetype", "icu", } if not _OPTIONS["without-nvtt"] then @@ -795,7 +823,6 @@ extern_libs = { "boost", "sdl", -- key definitions - "opengl", "spidermonkey", "fmt", } @@ -813,7 +840,6 @@ extern_libs = { "spidermonkey", "sdl", -- key definitions - "opengl", "boost", "enet", "tinygettext", @@ -848,7 +874,6 @@ "boost", "sdl", "openal", - "opengl", "libpng", "zlib", "valgrind", @@ -912,6 +937,26 @@ setup_static_lib_project("lowlevel", source_dirs, extern_libs, extra_params) + extern_libs = { "glad" } + if not os.istarget("windows") and not _OPTIONS["android"] and not os.istarget("macosx") then + -- X11 should only be linked on *nix + table.insert(used_extern_libs, "x11") + end + setup_static_lib_project("gladwrapper", {}, used_extern_libs, { no_pch = 1 }) + glad_path = libraries_source_dir.."glad/" + sysincludedirs { glad_path.."include" } + if _OPTIONS["gles"] then + files { glad_path.."src/gles2.cpp" } + else + files { glad_path.."src/gl.cpp" } + if os.istarget("windows") then + files { glad_path.."src/wgl.cpp" } + elseif os.istarget("linux") or os.istarget("bsd") then + files { glad_path.."src/egl.cpp", glad_path.."src/glx.cpp" } + end + end + + -- Third-party libraries that are built as part of the main project, -- not built externally and then linked source_dirs = { @@ -944,7 +989,6 @@ -- used for main EXE as well as test used_extern_libs = { - "opengl", "sdl", "libpng", @@ -963,6 +1007,7 @@ "iconv", "libsodium", "fmt", + "freetype", "valgrind", } @@ -1080,6 +1125,11 @@ links { "pthread" } links { "ApplicationServices.framework", "Cocoa.framework", "CoreFoundation.framework" } + + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } if _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end @@ -1111,6 +1161,14 @@ -- Link to required libraries links { "winmm", "delayimp" } + elseif os.istarget("macosx") then + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } + if _OPTIONS["macosx-version-min"] then + xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + end elseif os.istarget("linux") or os.istarget("bsd") then if os.getversion().description == "FreeBSD" then buildoptions { "-fPIC" } @@ -1230,6 +1288,12 @@ else -- Non-Windows, = Unix links { "AtlasObject" } + if os.istarget("macosx") then + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } + end end links { "AtlasUI" } @@ -1293,6 +1357,11 @@ buildoptions { "-fno-strict-aliasing" } -- On OSX, fcollada uses a few utility functions from coreservices links { "CoreServices.framework" } + + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } end end @@ -1439,8 +1508,14 @@ includedirs { source_root .. "pch/test/" } - elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then - xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + elseif os.istarget("macosx") then + architecture(macos_arch) + buildoptions { "-arch " .. macos_arch } + linkoptions { "-arch " .. macos_arch } + xcodebuildsettings { ARCHS = macos_arch } + if _OPTIONS["macosx-version-min"] then + xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } + end end end diff -Nru 0ad-0.0.25b/build/resources/0ad.desktop 0ad-0.0.26/build/resources/0ad.desktop --- 0ad-0.0.25b/build/resources/0ad.desktop 2021-07-27 21:57:40.000000000 +0000 +++ 0ad-0.0.26/build/resources/0ad.desktop 2022-08-21 12:46:46.000000000 +0000 @@ -1,12 +1,14 @@ [Desktop Entry] -Version=1.0 +Version=1.4 Name=0 A.D. -Exec=0ad +Exec=0ad %F Icon=0ad Terminal=false MimeType=application/x-pyromod+zip; Type=Application Categories=Game;StrategyGame; +# Use the most powerful GPU available by default (i.e. a dedicated Nvidia or AMD card instead of the integrated Intel card) +PrefersNonDefaultGPU=true Comment=A real-time strategy game of ancient warfare Comment[de]=Ein Echtzeitstrategiespiel, das die Kriegsführung der Antike behandelt Comment[es]=Un juego de estrategia en tiempo real de guerra antigua @@ -16,7 +18,7 @@ Comment[pl]=Gra strategiczna czasu rzeczywistego o wojnach starożytnych Comment[pt_BR]=Um jogo em tempo real de guerra antiga Comment[ru]=Игра в жанре исторической стратегии в реальном времени -Keywords=RTS;Realtime Strategy;Economic Simulation Game;History;Warfare;Infantry;Cavalry;Siege Engines;Fortress;Celtics;Hellenes;Athenians;Britons;Carthaginians;Gauls;Iberians;Macedonians;Mauryans;Persians;Ptolemies;Romans;Seleucids;Spartans; +Keywords=RTS;Real-Time Strategy;Economic Simulation Game;History;Warfare;Infantry;Cavalry;Siege Engines;Fortress;Celtics;Hellenes;Athenians;Britons;Carthaginians;Gauls;Iberians;Macedonians;Mauryas;Persians;Ptolemies;Romans;Seleucids;Spartans; Actions=Atlas; [Desktop Action Atlas] diff -Nru 0ad-0.0.25b/build/svn_revision/svn_revision.txt 0ad-0.0.26/build/svn_revision/svn_revision.txt --- 0ad-0.0.25b/build/svn_revision/svn_revision.txt 2021-08-25 14:46:07.000000000 +0000 +++ 0ad-0.0.26/build/svn_revision/svn_revision.txt 2022-09-23 20:38:50.000000000 +0000 @@ -1 +1 @@ -L"25860-release" +L"27104-release" diff -Nru 0ad-0.0.25b/build/workspaces/clean-workspaces.sh 0ad-0.0.26/build/workspaces/clean-workspaces.sh --- 0ad-0.0.25b/build/workspaces/clean-workspaces.sh 2021-07-27 21:57:40.000000000 +0000 +++ 0ad-0.0.26/build/workspaces/clean-workspaces.sh 2022-08-21 12:46:47.000000000 +0000 @@ -61,8 +61,9 @@ (cd ../premake/premake5/build/gmake2.macosx && ${MAKE} clean) (cd ../premake/premake5/build/gmake2.unix && ${MAKE} clean) -echo "Removing generated test files..." +echo "Removing generated stub and test files..." +find ../../source -name "stub_*.cpp" -type f -exec rm {} \; find ../../source -name "test_*.cpp" -type f -not -name "test_setup.cpp" -exec rm {} \; echo "Cleaning build output..." diff -Nru 0ad-0.0.25b/build/workspaces/update-workspaces.sh 0ad-0.0.26/build/workspaces/update-workspaces.sh --- 0ad-0.0.25b/build/workspaces/update-workspaces.sh 2021-07-27 21:57:40.000000000 +0000 +++ 0ad-0.0.26/build/workspaces/update-workspaces.sh 2022-09-23 19:16:41.000000000 +0000 @@ -61,6 +61,18 @@ if [ "$enable_atlas" = "true" ]; then premake_args="${premake_args} --atlas" + if [ "$(uname -s)" = "Darwin" ]; then + # Provide path to wx-config on OS X (as wxwidgets doesn't support pkgconfig) + export WX_CONFIG="${WX_CONFIG:="$(pwd)/../../libraries/osx/wxwidgets/bin/wx-config"}" + else + export WX_CONFIG="${WX_CONFIG:="wx-config"}" + fi + + if [ ! -x "$(command -v $WX_CONFIG)" ] + then + echo 'WX_CONFIG must be set and valid or wx-config must be present when --atlas is passed as argument.' + exit 1 + fi fi cd "$(dirname $0)" @@ -69,14 +81,6 @@ if [ "`uname -s`" = "Darwin" ]; then # Set minimal SDK version export MIN_OSX_VERSION=${MIN_OSX_VERSION:="10.12"} - - # Set *_CONFIG variables on OS X, to override the path to e.g. sdl2-config - export GLOOX_CONFIG=${GLOOX_CONFIG:="$(pwd)/../../libraries/osx/gloox/bin/gloox-config"} - export ICU_CONFIG=${ICU_CONFIG:="$(pwd)/../../libraries/osx/icu/bin/icu-config"} - export LIBPNG_CONFIG=${PNG_CONFIG:="$(pwd)/../../libraries/osx/libpng/bin/libpng-config"} - export SDL2_CONFIG=${SDL2_CONFIG:="$(pwd)/../../libraries/osx/sdl2/bin/sdl2-config"} - export WX_CONFIG=${WX_CONFIG:="$(pwd)/../../libraries/osx/wxwidgets/bin/wx-config"} - export XML2_CONFIG=${XML2_CONFIG:="$(pwd)/../../libraries/osx/libxml2/bin/xml2-config"} fi # Don't want to build bundled libs on OS X @@ -89,7 +93,7 @@ (cd ../../libraries/source/fcollada && MAKE=${MAKE} JOBS=${JOBS} ./build.sh) || die "FCollada build failed" echo if [ "$with_system_mozjs" = "false" ]; then - (cd ../../libraries/source/spidermonkey && MAKE=${MAKE} JOBS=${JOBS} ./build.sh) || die "SpiderMonkey build failed" + (cd ../../libraries/source/spidermonkey && MAKE=${MAKE} JOBS=${JOBS} PYTHONNOUSERSITE=true ./build.sh) || die "SpiderMonkey build failed" fi echo if [ "$with_system_nvtt" = "false" ] && [ "$without_nvtt" = "false" ]; then diff -Nru 0ad-0.0.25b/debian/changelog 0ad-0.0.26/debian/changelog --- 0ad-0.0.25b/debian/changelog 2022-08-21 06:03:22.000000000 +0000 +++ 0ad-0.0.26/debian/changelog 2022-10-02 16:14:33.000000000 +0000 @@ -1,14 +1,19 @@ -0ad (0.0.25b-2build2) kinetic; urgency=medium +0ad (0.0.26-1) unstable; urgency=medium - * No-change rebuild against libfmt9 + * New upstream release. + * Fix "New upstream release - version 0.0.26" (Closes: #1020649) + * d/p/fix-build-mozjs-with-python-3.10.patch: removed because added upstream + * d/p/fix-build-atlas-gcc11-glibc-2.35.patch: removed because added upstream + * d/control: add libfreetype-dev in Build-Depends: to fix build error + * d/p/Disable-test_regression_rP26522.patch: remove test + * d/copyright: update file list and fix lintian warnings + * d/watch: upgrade version and fix lintian warning + * d/control: update Standards-Version: 4.6.1. No change needed + * d/rules: remove use of --dbgsym-migration= + * d/contol: upgrade debhelper-compat from 12 to 13 + * d/s/lintian-overrides: rename tag insane-line-length-in-source-file - -- Steve Langasek Sun, 21 Aug 2022 06:03:22 +0000 - -0ad (0.0.25b-2build1) kinetic; urgency=medium - - * No-change rebuild against latest icu - - -- Jeremy Bicha Fri, 29 Apr 2022 11:30:24 -0400 + -- Ludovic Rousseau Sun, 02 Oct 2022 18:14:33 +0200 0ad (0.0.25b-2) unstable; urgency=medium @@ -31,17 +36,17 @@ 0ad (0.0.25b-1) unstable; urgency=medium [David W. Kennedy ] - * Package new upstream release. + * Package new upstream release. * d/control: Update required versions of dependencies. * d/copyright: Update and correct copyright information of debian package and embedded libraries * d/install: Install binaries/system/readme.txt as README.command-line.txt, also mark install executable to support renaming README.txt with dh-exec. - * d/rules: Clean up build files for libnvtt and spidermonkey in + * d/rules: Clean up build files for libnvtt and spidermonkey in dh_auto_clean. - * d/rules: Exclude libmozjs78-ps-release.so from dh_dwz in order to work + * d/rules: Exclude libmozjs78-ps-release.so from dh_dwz in order to work around a crash in dwz. - * d/source/local-options: Abort on changes to the upstream source code + * d/source/local-options: Abort on changes to the upstream source code before committing to the upstream branch of Debian Salsa VCS * d/watch: Update URL for releases. diff -Nru 0ad-0.0.25b/debian/control 0ad-0.0.26/debian/control --- 0ad-0.0.25b/debian/control 2022-08-21 06:03:21.000000000 +0000 +++ 0ad-0.0.26/debian/control 2022-10-02 16:14:33.000000000 +0000 @@ -1,8 +1,7 @@ Source: 0ad Section: games Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Games Team +Maintainer: Debian Games Team Uploaders: Vincent Cheng , Ludovic Rousseau @@ -11,7 +10,7 @@ automake, cargo, cmake, - debhelper-compat (= 12), + debhelper-compat (= 13), dh-exec (>= 0.1), dpkg-dev (>= 1.15.5), libboost-dev (>= 1.57.0.1), @@ -19,6 +18,7 @@ libcurl4-gnutls-dev (>= 7.32.0) | libcurl4-dev (>= 7.32.0), libenet-dev (>= 1.3), libfmt-dev (>= 4.0.0), + libfreetype-dev, libgloox-dev (>= 1.0.10), libicu-dev (>= 67.1-4~), libminiupnpc-dev (>= 1.6), @@ -37,7 +37,7 @@ rustc (>= 1.41), tzdata, zlib1g-dev (>= 1:1.2.3) -Standards-Version: 4.5.0 +Standards-Version: 4.6.1 Homepage: https://play0ad.com/ Vcs-Git: https://salsa.debian.org/games-team/0ad.git Vcs-Browser: https://salsa.debian.org/games-team/0ad diff -Nru 0ad-0.0.25b/debian/copyright 0ad-0.0.26/debian/copyright --- 0ad-0.0.25b/debian/copyright 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/copyright 2022-10-02 16:14:33.000000000 +0000 @@ -12,7 +12,7 @@ 2010 Bertrand Marc 2011-2020 Vincent Cheng 2011-2012 Ansgar Burchardt - 2017-2021 Ludovic Rousseau + 2017-2022 Ludovic Rousseau 2019 Bruno Kleinert 2021 Phil Morrell 2021 Pino Toscano @@ -78,87 +78,83 @@ Files: libraries/source/nvtt/src/src/nvcore/Array.h libraries/source/nvtt/src/src/nvcore/Array.inl - libraries/source/nvtt/src/src/nvcore/Containers.h libraries/source/nvtt/src/src/nvcore/Debug.cpp libraries/source/nvtt/src/src/nvcore/Debug.h + libraries/source/nvtt/src/src/nvcore/DefsGnucDarwin.h + libraries/source/nvtt/src/src/nvcore/DefsGnucLinux.h + libraries/source/nvtt/src/src/nvcore/DefsGnucWin32.h libraries/source/nvtt/src/src/nvcore/DefsVcWin32.h libraries/source/nvtt/src/src/nvcore/FileSystem.cpp libraries/source/nvtt/src/src/nvcore/FileSystem.h libraries/source/nvtt/src/src/nvcore/ForEach.h libraries/source/nvtt/src/src/nvcore/Hash.h - libraries/source/nvtt/src/src/nvcore/Library.h libraries/source/nvtt/src/src/nvcore/Memory.cpp libraries/source/nvtt/src/src/nvcore/Memory.h - libraries/source/nvtt/src/src/nvcore/Prefetch.h + libraries/source/nvtt/src/src/nvcore/nvcore.h libraries/source/nvtt/src/src/nvcore/Ptr.h libraries/source/nvtt/src/src/nvcore/RefCounted.h libraries/source/nvtt/src/src/nvcore/StdStream.h + libraries/source/nvtt/src/src/nvcore/Stream.h libraries/source/nvtt/src/src/nvcore/StrLib.cpp libraries/source/nvtt/src/src/nvcore/StrLib.h - libraries/source/nvtt/src/src/nvcore/Stream.h - libraries/source/nvtt/src/src/nvcore/TextReader.cpp - libraries/source/nvtt/src/src/nvcore/TextReader.h libraries/source/nvtt/src/src/nvcore/TextWriter.cpp libraries/source/nvtt/src/src/nvcore/TextWriter.h libraries/source/nvtt/src/src/nvcore/Timer.cpp libraries/source/nvtt/src/src/nvcore/Timer.h - libraries/source/nvtt/src/src/nvcore/Tokenizer.cpp - libraries/source/nvtt/src/src/nvcore/Tokenizer.h libraries/source/nvtt/src/src/nvcore/Utils.h - libraries/source/nvtt/src/src/nvcore/nvcore.h + libraries/source/nvtt/src/src/nvimage/BlockDXT.cpp + libraries/source/nvtt/src/src/nvimage/BlockDXT.h + libraries/source/nvtt/src/src/nvimage/CMakeLists.txt libraries/source/nvtt/src/src/nvimage/ColorBlock.cpp libraries/source/nvtt/src/src/nvimage/ColorBlock.h libraries/source/nvtt/src/src/nvimage/ColorSpace.cpp libraries/source/nvtt/src/src/nvimage/ColorSpace.h + libraries/source/nvtt/src/src/nvimage/DirectDrawSurface.cpp + libraries/source/nvtt/src/src/nvimage/DirectDrawSurface.h + libraries/source/nvtt/src/src/nvimage/ErrorMetric.cpp + libraries/source/nvtt/src/src/nvimage/ErrorMetric.h libraries/source/nvtt/src/src/nvimage/Filter.cpp libraries/source/nvtt/src/src/nvimage/Filter.h libraries/source/nvtt/src/src/nvimage/FloatImage.cpp libraries/source/nvtt/src/src/nvimage/FloatImage.h - libraries/source/nvtt/src/src/nvimage/HoleFilling.cpp - libraries/source/nvtt/src/src/nvimage/HoleFilling.h libraries/source/nvtt/src/src/nvimage/Image.cpp libraries/source/nvtt/src/src/nvimage/Image.h libraries/source/nvtt/src/src/nvimage/ImageIO.cpp libraries/source/nvtt/src/src/nvimage/ImageIO.h libraries/source/nvtt/src/src/nvimage/KtxFile.cpp libraries/source/nvtt/src/src/nvimage/KtxFile.h - libraries/source/nvtt/src/src/nvimage/NormalMipmap.cpp - libraries/source/nvtt/src/src/nvimage/NormalMipmap.h + libraries/source/nvtt/src/src/nvimage/NormalMap.cpp + libraries/source/nvtt/src/src/nvimage/NormalMap.h + libraries/source/nvtt/src/src/nvimage/nvimage.h + libraries/source/nvtt/src/src/nvimage/PixelFormat.h libraries/source/nvtt/src/src/nvimage/PsdFile.h libraries/source/nvtt/src/src/nvimage/Quantize.cpp libraries/source/nvtt/src/src/nvimage/Quantize.h libraries/source/nvtt/src/src/nvimage/TgaFile.h - libraries/source/nvtt/src/src/nvimage/nvimage.h - libraries/source/nvtt/src/src/nvmath/Basis.cpp - libraries/source/nvtt/src/src/nvmath/Basis.h + libraries/source/nvtt/src/src/nvimage/ValveTextureFormat.h libraries/source/nvtt/src/src/nvmath/Box.cpp libraries/source/nvtt/src/src/nvmath/Box.h + libraries/source/nvtt/src/src/nvmath/Box.inl libraries/source/nvtt/src/src/nvmath/Color.cpp libraries/source/nvtt/src/src/nvmath/Color.h libraries/source/nvtt/src/src/nvmath/Color.inl libraries/source/nvtt/src/src/nvmath/Fitting.cpp libraries/source/nvtt/src/src/nvmath/Fitting.h + libraries/source/nvtt/src/src/nvmath/ftoi.h libraries/source/nvtt/src/src/nvmath/Matrix.h libraries/source/nvtt/src/src/nvmath/Matrix.inl - libraries/source/nvtt/src/src/nvmath/Montecarlo.cpp - libraries/source/nvtt/src/src/nvmath/Montecarlo.h + libraries/source/nvtt/src/src/nvmath/nvmath.h libraries/source/nvtt/src/src/nvmath/PackedFloat.cpp libraries/source/nvtt/src/src/nvmath/PackedFloat.h libraries/source/nvtt/src/src/nvmath/Plane.cpp libraries/source/nvtt/src/src/nvmath/Plane.h libraries/source/nvtt/src/src/nvmath/Plane.inl - libraries/source/nvtt/src/src/nvmath/Quaternion.h - libraries/source/nvtt/src/src/nvmath/Random.cpp - libraries/source/nvtt/src/src/nvmath/Random.h libraries/source/nvtt/src/src/nvmath/SimdVector.h libraries/source/nvtt/src/src/nvmath/SphericalHarmonic.cpp libraries/source/nvtt/src/src/nvmath/SphericalHarmonic.h - libraries/source/nvtt/src/src/nvmath/Triangle.cpp - libraries/source/nvtt/src/src/nvmath/Triangle.h + libraries/source/nvtt/src/src/nvmath/Vector.cpp libraries/source/nvtt/src/src/nvmath/Vector.h libraries/source/nvtt/src/src/nvmath/Vector.inl - libraries/source/nvtt/src/src/nvmath/ftoi.h - libraries/source/nvtt/src/src/nvmath/nvmath.h libraries/source/nvtt/src/src/nvthread/Atomic.h libraries/source/nvtt/src/src/nvthread/Event.cpp libraries/source/nvtt/src/src/nvthread/Event.h @@ -210,11 +206,6 @@ Copyright: 1998-2020 Mozilla Corporation License: MPL-2.0 and GPL-2.0 and LGPL-2.1 -Files: libraries/source/valgrind/* -Copyright: 2003-2012 Josef Weidendorfer - 2000-2012 Julian Seward -License: BSD-4-clause - License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -547,35 +538,3 @@ . On Debian systems, the complete text of the Mozilla Public License, version 2 can be found in "/usr/share/common-licenses/MPL-2.0". - -License: BSD-4-clause - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - . - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - . - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - . - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - . - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - . - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru 0ad-0.0.25b/debian/patches/Disable-test_regression_rP26522.patch 0ad-0.0.26/debian/patches/Disable-test_regression_rP26522.patch --- 0ad-0.0.25b/debian/patches/Disable-test_regression_rP26522.patch 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/debian/patches/Disable-test_regression_rP26522.patch 2022-10-02 16:14:33.000000000 +0000 @@ -0,0 +1,42 @@ +Description: Disable a failing regression test + In TestCGUIText::test_regression_rP26522: + ./source/gui/tests/test_CGUIText.h:319: Error: Expected ((g_VFS->Mount(L"", DataDir() / "mods" / "mod" / "", VFS_MOUNT_MUST_EXIST)) == INFO::OK), found (-110100 != 0) + ERROR: Failed to open font file fonts/sans-bold-13.fnt + ERROR: Failed to open font file fonts/sans-10.fnt + ./source/gui/tests/test_CGUIText.h:332: Error: Expected (text.GetSize().Height == 14 + 9 + 8 * 2), found (22.0000 != 39) + .............................................................................................................................................................................................................................................Skipping globalscripts tests (can't find binaries/data/mods/public/globalscripts/tests/) + .Skipping component scripts tests (can't find binaries/data/mods/public/simulation/components/tests/setup.js) + ................................................................................................................ + Failed 1 and Skipped 0 of 391 tests + Success rate: 99% +Author: Ludovic Rousseau +Forwarded: https://trac.wildfiregames.com/ticket/6630 +Last-Update: 2022-10-02 + +--- a/source/gui/tests/test_CGUIText.h ++++ b/source/gui/tests/test_CGUIText.h +@@ -314,24 +314,6 @@ + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + padding * 2); + } + +- void test_regression_rP26522() +- { +- TS_ASSERT_OK(g_VFS->Mount(L"", DataDir() / "mods" / "mod" / "", VFS_MOUNT_MUST_EXIST)); +- +- CGUI gui(g_ScriptContext); +- +- const CStrW font = L"sans-bold-13"; +- CGUIString string; +- CGUIText text; +- +- // rP26522 introduced a bug that triggered in rare cases with word-wrapping. +- string.SetValue(L"90–120 min"); +- text = CGUIText(gui, string, L"sans-bold-13", 53, 8.f, EAlign::LEFT, nullptr); +- +- TS_ASSERT_EQUALS(text.GetTextCalls().size(), 2); +- TS_ASSERT_EQUALS(text.GetSize().Height, 14 + 9 + 8 * 2); +- } +- + void test_multiple_blank_spaces() + { + CGUI gui(g_ScriptContext); diff -Nru 0ad-0.0.25b/debian/patches/fix-build-atlas-gcc11-glibc-2.35.patch 0ad-0.0.26/debian/patches/fix-build-atlas-gcc11-glibc-2.35.patch --- 0ad-0.0.25b/debian/patches/fix-build-atlas-gcc11-glibc-2.35.patch 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/patches/fix-build-atlas-gcc11-glibc-2.35.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -From: Vladislav Belov -Date: Thu, 3 Mar 2022 19:10:05 +0100 -Subject: Replaces M_PIf by M_PI in Atlas, - fixes compilation with gcc 11.2.0 and glibc 2.35. - -There was added a workaround in glibc to fix tests. - -Refs: -https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103735 -https://sourceware.org/bugzilla/show_bug.cgi?id=28713 - -Origin: upstream, commit:https://trac.wildfiregames.com/changeset/26536 -Bug-Debian: https://bugs.debian.org/1008075 -Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=2045149 ---- - .../Sections/Environment/Environment.cpp | 88 ++++++++++++++-------- - 1 file changed, 57 insertions(+), 31 deletions(-) - -diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp -index d4796ec..2cc2652 100644 ---- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp -+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp -@@ -1,4 +1,4 @@ --/* Copyright (C) 2021 Wildfire Games. -+/* Copyright (C) 2022 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify -@@ -29,8 +29,6 @@ using AtlasMessage::Shareable; - - static Observable g_EnvironmentSettings; - --const float M_PIf = 3.14159265f; -- - ////////////////////////////////////////////////////////////////////////// - - class VariableSliderBox : public wxPanel -@@ -85,12 +83,15 @@ public: - : wxPanel(parent), - m_Var(var) - { -- m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableListBox::OnSettingsChange, this); -+ m_Conn = g_EnvironmentSettings.RegisterObserver( -+ 0, &VariableListBox::OnSettingsChange, this); - - m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label); - SetSizer(m_Sizer); - -- m_Combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxArrayString(), wxCB_READONLY), -+ m_Combo = new wxComboBox( -+ this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, -+ wxArrayString(), wxCB_READONLY), - m_Sizer->Add(m_Combo, wxSizerFlags().Expand()); - } - -@@ -206,8 +207,9 @@ static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings) - POST_COMMAND(SetEnvironmentSettings, (settings)); - } - --EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) --: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer) -+EnvironmentSidebar::EnvironmentSidebar( -+ ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) -+ : Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer) - { - wxSizer* scrollSizer = new wxBoxSizer(wxVERTICAL); - wxScrolledWindow* scrolledWindow = new wxScrolledWindow(this); -@@ -217,15 +219,24 @@ EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* - - wxSizer* waterSizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _T("Water settings")); - scrollSizer->Add(waterSizer, wxSizerFlags().Expand()); -- waterSizer->Add(new wxButton(scrolledWindow, ID_RecomputeWaterData, _("Reset Water Data")), wxSizerFlags().Expand()); -- waterSizer->Add(m_WaterTypeList = new VariableListBox(scrolledWindow, _("Water Type"), g_EnvironmentSettings.watertype), wxSizerFlags().Expand()); -- waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Water height"), g_EnvironmentSettings.waterheight, 0.f, 1.2f), wxSizerFlags().Expand()); -- waterSizer->Add(new wxButton(scrolledWindow, ID_PickWaterHeight, _("Pick Water Height")), wxSizerFlags().Expand()); -- waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0.f, 10.f), wxSizerFlags().Expand()); -- waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Water murkiness"), g_EnvironmentSettings.watermurkiness, 0.f, 1.f), wxSizerFlags().Expand()); -- waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Wind angle"), g_EnvironmentSettings.windangle, -M_PIf, M_PIf), wxSizerFlags().Expand()); -- waterSizer->Add(new VariableColorBox(scrolledWindow, _("Water color"), g_EnvironmentSettings.watercolor), wxSizerFlags().Expand()); -- waterSizer->Add(new VariableColorBox(scrolledWindow, _("Water tint"), g_EnvironmentSettings.watertint), wxSizerFlags().Expand()); -+ waterSizer->Add(new wxButton( -+ scrolledWindow, ID_RecomputeWaterData, _("Reset Water Data")), wxSizerFlags().Expand()); -+ waterSizer->Add(m_WaterTypeList = new VariableListBox( -+ scrolledWindow, _("Water Type"), g_EnvironmentSettings.watertype), wxSizerFlags().Expand()); -+ waterSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Water height"), g_EnvironmentSettings.waterheight, 0.f, 1.2f), wxSizerFlags().Expand()); -+ waterSizer->Add(new wxButton( -+ scrolledWindow, ID_PickWaterHeight, _("Pick Water Height")), wxSizerFlags().Expand()); -+ waterSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0.f, 10.f), wxSizerFlags().Expand()); -+ waterSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Water murkiness"), g_EnvironmentSettings.watermurkiness, 0.f, 1.f), wxSizerFlags().Expand()); -+ waterSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Wind angle"), g_EnvironmentSettings.windangle, -static_cast(M_PI), static_cast(M_PI)), wxSizerFlags().Expand()); -+ waterSizer->Add(new VariableColorBox( -+ scrolledWindow, _("Water color"), g_EnvironmentSettings.watercolor), wxSizerFlags().Expand()); -+ waterSizer->Add(new VariableColorBox( -+ scrolledWindow, _("Water tint"), g_EnvironmentSettings.watertint), wxSizerFlags().Expand()); - - std::vector list; - list.push_back(L"ocean"); list.push_back(L"lake"); list.push_back(L"clap"); -@@ -235,25 +246,40 @@ EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* - wxSizer* sunSizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _T("Sun / lighting settings")); - scrollSizer->Add(sunSizer, wxSizerFlags().Expand().Border(wxTOP, 8)); - -- sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -M_PIf, M_PIf), wxSizerFlags().Expand()); -- sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -M_PIf/2, M_PIf/2), wxSizerFlags().Expand()); -- sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Sun overbrightness"), g_EnvironmentSettings.sunoverbrightness, 1.0f, 3.0f), wxSizerFlags().Expand()); -- sunSizer->Add(new LightControl(scrolledWindow, wxSize(150, 150), g_EnvironmentSettings)); -- sunSizer->Add(new VariableColorBox(scrolledWindow, _("Sun color"), g_EnvironmentSettings.suncolor), wxSizerFlags().Expand()); -- sunSizer->Add(m_SkyList = new VariableListBox(scrolledWindow, _("Sky set"), g_EnvironmentSettings.skyset), wxSizerFlags().Expand()); -- sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Fog Factor"), g_EnvironmentSettings.fogfactor, 0.0f, 0.01f), wxSizerFlags().Expand()); -- sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Fog Thickness"), g_EnvironmentSettings.fogmax, 0.5f, 0.0f), wxSizerFlags().Expand()); -- sunSizer->Add(new VariableColorBox(scrolledWindow, _("Fog color"), g_EnvironmentSettings.fogcolor), wxSizerFlags().Expand()); -- sunSizer->Add(new VariableColorBox(scrolledWindow, _("Ambient color"), g_EnvironmentSettings.ambientcolor), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -static_cast(M_PI), static_cast(M_PI)), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -static_cast(M_PI) / 2.0f, static_cast(M_PI) / 2.0f), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Sun overbrightness"), g_EnvironmentSettings.sunoverbrightness, 1.0f, 3.0f), wxSizerFlags().Expand()); -+ sunSizer->Add(new LightControl( -+ scrolledWindow, wxSize(150, 150), g_EnvironmentSettings)); -+ sunSizer->Add(new VariableColorBox( -+ scrolledWindow, _("Sun color"), g_EnvironmentSettings.suncolor), wxSizerFlags().Expand()); -+ sunSizer->Add(m_SkyList = new VariableListBox( -+ scrolledWindow, _("Sky set"), g_EnvironmentSettings.skyset), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Fog Factor"), g_EnvironmentSettings.fogfactor, 0.0f, 0.01f), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Fog Thickness"), g_EnvironmentSettings.fogmax, 0.5f, 0.0f), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableColorBox( -+ scrolledWindow, _("Fog color"), g_EnvironmentSettings.fogcolor), wxSizerFlags().Expand()); -+ sunSizer->Add(new VariableColorBox( -+ scrolledWindow, _("Ambient color"), g_EnvironmentSettings.ambientcolor), wxSizerFlags().Expand()); - - wxSizer* postProcSizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _T("Post-processing settings")); - scrollSizer->Add(postProcSizer, wxSizerFlags().Expand().Border(wxTOP, 8)); - -- postProcSizer->Add(m_PostEffectList = new VariableListBox(scrolledWindow, _("Post Effect"), g_EnvironmentSettings.posteffect), wxSizerFlags().Expand()); -- postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Brightness"), g_EnvironmentSettings.brightness, -0.5f, 0.5f), wxSizerFlags().Expand()); -- postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Contrast (HDR)"), g_EnvironmentSettings.contrast, 0.5f, 1.5f), wxSizerFlags().Expand()); -- postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Saturation"), g_EnvironmentSettings.saturation, 0.0f, 2.0f), wxSizerFlags().Expand()); -- postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Bloom"), g_EnvironmentSettings.bloom, 0.2f, 0.0f), wxSizerFlags().Expand()); -+ postProcSizer->Add(m_PostEffectList = new VariableListBox( -+ scrolledWindow, _("Post Effect"), g_EnvironmentSettings.posteffect), wxSizerFlags().Expand()); -+ postProcSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Brightness"), g_EnvironmentSettings.brightness, -0.5f, 0.5f), wxSizerFlags().Expand()); -+ postProcSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Contrast (HDR)"), g_EnvironmentSettings.contrast, 0.5f, 1.5f), wxSizerFlags().Expand()); -+ postProcSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Saturation"), g_EnvironmentSettings.saturation, 0.0f, 2.0f), wxSizerFlags().Expand()); -+ postProcSizer->Add(new VariableSliderBox( -+ scrolledWindow, _("Bloom"), g_EnvironmentSettings.bloom, 0.2f, 0.0f), wxSizerFlags().Expand()); - - m_Conn = g_EnvironmentSettings.RegisterObserver(0, &SendToGame); - } diff -Nru 0ad-0.0.25b/debian/patches/fix-build-mozjs-with-python-3.10.patch 0ad-0.0.26/debian/patches/fix-build-mozjs-with-python-3.10.patch --- 0ad-0.0.25b/debian/patches/fix-build-mozjs-with-python-3.10.patch 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/patches/fix-build-mozjs-with-python-3.10.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,167 +0,0 @@ -From: s0600204 -Date: Wed, 23 Feb 2022 21:30:38 +0100 -Subject: Fix building spidermonkey on systems with python 3.10 - -Tested by: - -Langbart - macOS 10.15.7: homebrewed python 3.9.9 & 3.10.1 -andy5995 - Manjaro 21.2.3: python 3.10.2 -s0600204 - ArchLinux: python 3.10.2 - -Bug: https://wildfiregames.com/forum/topic/65901-christmas-testing-bundle/#comment-472056 -Origin: upstream, commit:https://trac.wildfiregames.com/changeset/26475 -Origin: https://code.wildfiregames.com/D4437 -Bug-Debian: https://bugs.debian.org/1008075 ---- - .../spidermonkey/FixPythonCollectionABC.diff | 87 ++++++++++++++++++++++ - .../spidermonkey/FixVirtualenvForPython310.diff | 15 ++++ - libraries/source/spidermonkey/patch.sh | 13 ++++ - 3 files changed, 115 insertions(+) - create mode 100644 libraries/source/spidermonkey/FixPythonCollectionABC.diff - create mode 100644 libraries/source/spidermonkey/FixVirtualenvForPython310.diff - -diff --git a/libraries/source/spidermonkey/FixPythonCollectionABC.diff b/libraries/source/spidermonkey/FixPythonCollectionABC.diff -new file mode 100644 -index 0000000..536a534 ---- /dev/null -+++ b/libraries/source/spidermonkey/FixPythonCollectionABC.diff -@@ -0,0 +1,87 @@ -+--- a/python/mach/mach/config.py -++++ b/python/mach/mach/config.py -+@@ -144,7 +144,7 @@ -+ return _ -+ -+ -+-class ConfigSettings(collections.Mapping): -++class ConfigSettings(collections.abc.Mapping): -+ """Interface for configuration settings. -+ -+ This is the main interface to the configuration. -+@@ -190,7 +190,7 @@ -+ will result in exceptions being raised. -+ """ -+ -+- class ConfigSection(collections.MutableMapping, object): -++ class ConfigSection(collections.abc.MutableMapping, object): -+ """Represents an individual config section.""" -+ def __init__(self, config, name, settings): -+ object.__setattr__(self, '_config', config) -+--- a/python/mach/mach/decorators.py -++++ b/python/mach/mach/decorators.py -+@@ -159,7 +159,7 @@ -+ 'Conditions argument must take a list ' + \ -+ 'of functions. Found %s instead.' -+ -+- if not isinstance(command.conditions, collections.Iterable): -++ if not isinstance(command.conditions, collections.abc.Iterable): -+ msg = msg % (command.name, type(command.conditions)) -+ raise MachError(msg) -+ -+--- a/python/mach/mach/main.py -++++ b/python/mach/mach/main.py -+@@ -16,7 +16,7 @@ -+ import sys -+ import traceback -+ import uuid -+-from collections import Iterable -++from collections.abc import Iterable -+ -+ from six import string_types -+ -+--- a/python/mozbuild/mozbuild/backend/configenvironment.py -++++ b/python/mozbuild/mozbuild/backend/configenvironment.py -+@@ -9,7 +9,8 @@ -+ import sys -+ import json -+ -+-from collections import Iterable, OrderedDict -++from collections import OrderedDict -++from collections.abc import Iterable -+ from types import ModuleType -+ -+ import mozpack.path as mozpath -+--- a/python/mozbuild/mozbuild/makeutil.py -++++ b/python/mozbuild/mozbuild/makeutil.py -+@@ -7,7 +7,7 @@ -+ import os -+ import re -+ import six -+-from collections import Iterable -++from collections.abc import Iterable -+ -+ -+ class Makefile(object): -+--- a/python/mozbuild/mozbuild/util.py -++++ b/python/mozbuild/mozbuild/util.py -+@@ -782,7 +782,7 @@ -+ self._strings = StrictOrderingOnAppendList() -+ self._children = {} -+ -+- class StringListAdaptor(collections.Sequence): -++ class StringListAdaptor(collections.abc.Sequence): -+ def __init__(self, hsl): -+ self._hsl = hsl -+ -+--- a/testing/mozbase/manifestparser/manifestparser/filters.py -++++ b/testing/mozbase/manifestparser/manifestparser/filters.py -+@@ -15,1 +15,2 @@ -+-from collections import defaultdict, MutableSequence -++from collections import defaultdict -++from collections.abc import MutableSequence -+--- a/third_party/python/pipenv/pipenv/vendor/jinja2/sandbox.py -++++ b/third_party/python/pipenv/pipenv/vendor/jinja2/sandbox.py -+@@ -82,1 +82,1 @@ -+-from collections import MutableSet, MutableMapping, MutableSequence -++from collections.abc import MutableSet, MutableMapping, MutableSequence -diff --git a/libraries/source/spidermonkey/FixVirtualenvForPython310.diff b/libraries/source/spidermonkey/FixVirtualenvForPython310.diff -new file mode 100644 -index 0000000..d023c63 ---- /dev/null -+++ b/libraries/source/spidermonkey/FixVirtualenvForPython310.diff -@@ -0,0 +1,15 @@ -+--- a/third_party/python/virtualenv/virtualenv.py -++++ b/third_party/python/virtualenv/virtualenv.py -+@@ -1804,7 +1804,11 @@ -+ pass -+ else: -+ # noinspection PyProtectedMember -+- if sysconfig._get_default_scheme() == "posix_local": -++ try: # Python >= 3.10 -++ default_scheme = sysconfig.get_default_scheme() -++ except: # Python < 3.10 -++ default_scheme = sysconfig._get_default_scheme() -++ if default_scheme == "posix_local": -+ local_path = os.path.join(home_dir, "local") -+ if not os.path.exists(local_path): -+ os.mkdir(local_path) -diff --git a/libraries/source/spidermonkey/patch.sh b/libraries/source/spidermonkey/patch.sh -index 9059fd6..ca2b67c 100644 ---- a/libraries/source/spidermonkey/patch.sh -+++ b/libraries/source/spidermonkey/patch.sh -@@ -19,6 +19,14 @@ patch -p1 < ../FixSharedArray.diff - # (mentionned in the comments, no patch/commit found) - patch -p1 < ../FixPublicExport.diff - -+# In python 3.10 `sysconfig._get_default_scheme()` was renamed to -+# `sysconfig.get_default_scheme()`. This breaks the version of -+# `virtualenv` bundled with the spidermonkey source code. -+# -+# It is assumed that the updated version fetched for macOS systems -+# above does not have this problem. -+patch -p1 < ../FixVirtualenvForPython310.diff -+ - # Fix Rooted not working on VS17 - # https://bugzilla.mozilla.org/show_bug.cgi?id=1679736 - # (Landed in 85) -@@ -34,6 +42,11 @@ patch -p1 < ../FixMSVCRootedVoid.diff - # so this patches it to an arbitrarily high Mac OS 11 - patch -p1 < ../FixMacBuild.diff - -+# In python 3.3, the Collections' Abstract Base Classes were moved from `collections` to -+# `collections.abc`, and aliases were set up for backwards compatibility. -+# In python 3.10, these aliases were removed, requiring all code that used them to update. -+patch -p1 < ../FixPythonCollectionABC.diff -+ - # Fix FP access breaking compilation on RPI3+ - # https://bugzilla.mozilla.org/show_bug.cgi?id=1526653 - # https://bugzilla.mozilla.org/show_bug.cgi?id=1536491 diff -Nru 0ad-0.0.25b/debian/patches/series 0ad-0.0.26/debian/patches/series --- 0ad-0.0.25b/debian/patches/series 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/patches/series 2022-10-02 16:14:33.000000000 +0000 @@ -2,5 +2,4 @@ allow-build-with-root.patch fix-bindir.patch Fix-build-mozjs-on-armhf.patch -fix-build-mozjs-with-python-3.10.patch -fix-build-atlas-gcc11-glibc-2.35.patch +Disable-test_regression_rP26522.patch diff -Nru 0ad-0.0.25b/debian/patches/TestStunClient 0ad-0.0.26/debian/patches/TestStunClient --- 0ad-0.0.25b/debian/patches/TestStunClient 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/patches/TestStunClient 2022-10-02 16:14:33.000000000 +0000 @@ -1,4 +1,4 @@ -Description: remove this test since it fails in the build environement +Description: remove this test since it fails in the build environment The failure is: In TestStunClient::test_local_ip: ./source/network/tests/test_StunClient.h:43: Error: Assertion failed: StunClient::FindLocalIP(ip) diff -Nru 0ad-0.0.25b/debian/rules 0ad-0.0.26/debian/rules --- 0ad-0.0.25b/debian/rules 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/rules 2022-10-02 16:14:33.000000000 +0000 @@ -56,9 +56,6 @@ install -Dm 0755 build/resources/0ad.sh $(CURDIR)/debian/tmp/usr/games/0ad dh_auto_install -override_dh_strip: - dh_strip --dbgsym-migration='0ad-dbg (<< 0.0.20-2~)' - override_dh_makeshlibs: dh_makeshlibs -Xusr/lib/games/0ad diff -Nru 0ad-0.0.25b/debian/source/lintian-overrides 0ad-0.0.26/debian/source/lintian-overrides --- 0ad-0.0.25b/debian/source/lintian-overrides 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/source/lintian-overrides 2022-10-02 16:14:33.000000000 +0000 @@ -6,18 +6,18 @@ # (they trigger lintian errors because they are not named the same as the # non-minified files in debian/missing-sources/, or contain inline # javascript dependencies). See debian/missing-sources/README.txt for details. -0ad source: insane-line-length-in-source-file source/tools/replayprofile/jquery.flot.js line length is 2981 characters (>512) +0ad source: very-long-line-length-in-source-file source/tools/replayprofile/jquery.flot.js line length is 2981 characters (>512) 0ad source: source-contains-prebuilt-javascript-object source/tools/replayprofile/jquery.flot.js line length is 2981 characters (>512) -0ad source: source-is-missing source/tools/replayprofile/jquery.flot.js line length is 2981 characters (>512) -0ad source: insane-line-length-in-source-file source/tools/replayprofile/jquery.flot.navigate.js line length is 1984 characters (>512) +0ad source: source-is-missing [source/tools/replayprofile/jquery.flot.js] +0ad source: very-long-line-length-in-source-file source/tools/replayprofile/jquery.flot.navigate.js line length is 1984 characters (>512) 0ad source: source-contains-prebuilt-javascript-object source/tools/replayprofile/jquery.flot.navigate.js line length is 1984 characters (>512) -0ad source: source-is-missing source/tools/replayprofile/jquery.flot.navigate.js line length is 1984 characters (>512) -0ad source: insane-line-length-in-source-file source/tools/templatesanalyzer/tablefilter/tablefilter.js line length is 32005 characters (>512) +0ad source: source-is-missing [source/tools/replayprofile/jquery.flot.navigate.js] +0ad source: very-long-line-length-in-source-file source/tools/templatesanalyzer/tablefilter/tablefilter.js line length is 32005 characters (>512) 0ad source: source-contains-prebuilt-javascript-object source/tools/templatesanalyzer/tablefilter/tablefilter.js line length is 32005 characters (>512) -0ad source: source-is-missing source/tools/templatesanalyzer/tablefilter/tablefilter.js line length is 32005 characters (>512) -0ad source: insane-line-length-in-source-file source/tools/templatesanalyzer/tablefilter/tf-1.js line length is 32004 characters (>512) +0ad source: source-is-missing [source/tools/templatesanalyzer/tablefilter/tablefilter.js] +0ad source: very-long-line-length-in-source-file source/tools/templatesanalyzer/tablefilter/tf-1.js line length is 32004 characters (>512) 0ad source: source-contains-prebuilt-javascript-object source/tools/templatesanalyzer/tablefilter/tf-1.js line length is 32004 characters (>512) -0ad source: source-is-missing source/tools/templatesanalyzer/tablefilter/tf-1.js line length is 32004 characters (>512) +0ad source: source-is-missing [source/tools/templatesanalyzer/tablefilter/tf-1.js] ## Currently unused overrides/comments: # These files actually are non-minified source code. Silly lintian assumes diff -Nru 0ad-0.0.25b/debian/watch 0ad-0.0.26/debian/watch --- 0ad-0.0.25b/debian/watch 2022-03-28 11:29:22.000000000 +0000 +++ 0ad-0.0.26/debian/watch 2022-10-02 16:14:33.000000000 +0000 @@ -1,2 +1,2 @@ -version=3 +version=4 https://releases.wildfiregames.com/0ad-([\d\.]+)-.*-unix-build\.tar\.gz diff -Nru 0ad-0.0.25b/libraries/source/fcollada/src/FCollada/pre-requisites_and_license.rtf 0ad-0.0.26/libraries/source/fcollada/src/FCollada/pre-requisites_and_license.rtf --- 0ad-0.0.25b/libraries/source/fcollada/src/FCollada/pre-requisites_and_license.rtf 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/fcollada/src/FCollada/pre-requisites_and_license.rtf 2022-09-23 20:37:02.000000000 +0000 @@ -0,0 +1,34 @@ +{\rtf1\ansi\ansicpg1252\uc1\deff0\stshfdbch11\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1041{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} +{\f11\fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho{\*\falt ?l?r ??\'81\'66c};}{\f36\fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}@MS Mincho;}{\f37\froman\fcharset238\fprq2 Times New Roman CE;} +{\f38\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f40\froman\fcharset161\fprq2 Times New Roman Greek;}{\f41\froman\fcharset162\fprq2 Times New Roman Tur;}{\f42\froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\f43\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f44\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f45\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f47\fswiss\fcharset238\fprq2 Arial CE;} +{\f48\fswiss\fcharset204\fprq2 Arial Cyr;}{\f50\fswiss\fcharset161\fprq2 Arial Greek;}{\f51\fswiss\fcharset162\fprq2 Arial Tur;}{\f52\fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f53\fswiss\fcharset178\fprq2 Arial (Arabic);} +{\f54\fswiss\fcharset186\fprq2 Arial Baltic;}{\f55\fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f149\fmodern\fcharset0\fprq1 MS Mincho Western{\*\falt ?l?r ??\'81\'66c};}{\f147\fmodern\fcharset238\fprq1 MS Mincho CE{\*\falt ?l?r ??\'81\'66c};} +{\f148\fmodern\fcharset204\fprq1 MS Mincho Cyr{\*\falt ?l?r ??\'81\'66c};}{\f150\fmodern\fcharset161\fprq1 MS Mincho Greek{\*\falt ?l?r ??\'81\'66c};}{\f151\fmodern\fcharset162\fprq1 MS Mincho Tur{\*\falt ?l?r ??\'81\'66c};} +{\f154\fmodern\fcharset186\fprq1 MS Mincho Baltic{\*\falt ?l?r ??\'81\'66c};}{\f399\fmodern\fcharset0\fprq1 @MS Mincho Western;}{\f397\fmodern\fcharset238\fprq1 @MS Mincho CE;}{\f398\fmodern\fcharset204\fprq1 @MS Mincho Cyr;} +{\f400\fmodern\fcharset161\fprq1 @MS Mincho Greek;}{\f401\fmodern\fcharset162\fprq1 @MS Mincho Tur;}{\f404\fmodern\fcharset186\fprq1 @MS Mincho Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0; +\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128; +\red192\green192\blue192;}{\stylesheet{\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1041\loch\f0\hich\af0\dbch\af11\cgrid\langnp1033\langfenp1041 \snext0 Normal;}{\*\cs10 \additive \ssemihidden +Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\rsidtbl \rsid14640435}{\*\generator Micr +osoft Word 11.0.5604;}{\info{\author Guillaume Laforte}{\operator Guillaume Laforte}{\creatim\yr2006\mo9\dy28\hr13\min56}{\revtim\yr2006\mo9\dy28\hr13\min56}{\version2}{\edmins0}{\nofpages1}{\nofwords90}{\nofchars517}{\*\company Feeling Software Inc.} +{\nofcharsws606}{\vern24689}}\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3 +\jcompress\viewkind4\viewscale100\nolnhtadjtbl\rsidroot14640435 \fet0\sectd \linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3 +\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} +{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain +\ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 \fs24\lang1033\langfe1041\loch\af0\hich\af0\dbch\af11\cgrid\langnp1033\langfenp1041 {\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 Pre-requisites for FCollada}{\f1\fs20\insrsid14640435 +\par \hich\af1\dbch\af11\loch\f1 Before proceeding with this installer, verify that you comply with the following pre-requisites: +\par +\par \hich\af1\dbch\af11\loch\f1 1. }{\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 This software is only supported with Microsoft Visual Studio \hich\af1\dbch\af11\loch\f1 200}{\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 5}{ +\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 . At the moment, we do not have the time and resources to support other operating systems and compilers. +\par +\par \hich\af1\dbch\af11\loch\f1 If you encounter problems with this software, or would like to suggest enhancements, visit the }{\field{\*\fldinst {\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 HYPERLINK "http://www.feelingsoftware.com/bugzilla/" }{ +\f1\fs20\insrsid14640435\charrsid14640435 {\*\datafield +00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b5200000068007400740070003a002f002f007700770077002e006600650065006c0069006e00670073006f006600740077006100720065002e0063006f006d002f006200750067007a0069006c006c0061002f000000} +}}{\fldrslt {\f1\fs20\ul\cf2\insrsid14640435 \hich\af1\dbch\af11\loch\f1 Fe\hich\af1\dbch\af11\loch\f1 eling Software bugzilla}}}{\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 .\line +\par }{\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 LICENSE +\par }{\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 This software is distributed under the }{\field{\*\fldinst {\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 HYPERLINK "http://www.opensource.org/licenses/mit-license.php" }{ +\f1\fs20\insrsid14640435\charrsid14640435 {\*\datafield +00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b6600000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006d00690074002d006c006900 +630065006e00730065002e007000680070000000}}}{\fldrslt {\f1\fs20\ul\cf2\insrsid14640435 \hich\af1\dbch\af11\loch\f1 MIT License}}}{\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 +\par }} \ No newline at end of file diff -Nru "/tmp/tmp39yh8n0d/woTvBEdUpR/0ad-0.0.25b/libraries/source/fcollada/src/FCollada/Pre-requisites and License.rtf" "/tmp/tmp39yh8n0d/CCpWyu1Pac/0ad-0.0.26/libraries/source/fcollada/src/FCollada/Pre-requisites and License.rtf" --- "/tmp/tmp39yh8n0d/woTvBEdUpR/0ad-0.0.25b/libraries/source/fcollada/src/FCollada/Pre-requisites and License.rtf" 2021-08-25 14:44:22.000000000 +0000 +++ "/tmp/tmp39yh8n0d/CCpWyu1Pac/0ad-0.0.26/libraries/source/fcollada/src/FCollada/Pre-requisites and License.rtf" 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -{\rtf1\ansi\ansicpg1252\uc1\deff0\stshfdbch11\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1041{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f11\fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho{\*\falt ?l?r ??\'81\'66c};}{\f36\fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}@MS Mincho;}{\f37\froman\fcharset238\fprq2 Times New Roman CE;} -{\f38\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f40\froman\fcharset161\fprq2 Times New Roman Greek;}{\f41\froman\fcharset162\fprq2 Times New Roman Tur;}{\f42\froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\f43\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f44\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f45\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f47\fswiss\fcharset238\fprq2 Arial CE;} -{\f48\fswiss\fcharset204\fprq2 Arial Cyr;}{\f50\fswiss\fcharset161\fprq2 Arial Greek;}{\f51\fswiss\fcharset162\fprq2 Arial Tur;}{\f52\fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f53\fswiss\fcharset178\fprq2 Arial (Arabic);} -{\f54\fswiss\fcharset186\fprq2 Arial Baltic;}{\f55\fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f149\fmodern\fcharset0\fprq1 MS Mincho Western{\*\falt ?l?r ??\'81\'66c};}{\f147\fmodern\fcharset238\fprq1 MS Mincho CE{\*\falt ?l?r ??\'81\'66c};} -{\f148\fmodern\fcharset204\fprq1 MS Mincho Cyr{\*\falt ?l?r ??\'81\'66c};}{\f150\fmodern\fcharset161\fprq1 MS Mincho Greek{\*\falt ?l?r ??\'81\'66c};}{\f151\fmodern\fcharset162\fprq1 MS Mincho Tur{\*\falt ?l?r ??\'81\'66c};} -{\f154\fmodern\fcharset186\fprq1 MS Mincho Baltic{\*\falt ?l?r ??\'81\'66c};}{\f399\fmodern\fcharset0\fprq1 @MS Mincho Western;}{\f397\fmodern\fcharset238\fprq1 @MS Mincho CE;}{\f398\fmodern\fcharset204\fprq1 @MS Mincho Cyr;} -{\f400\fmodern\fcharset161\fprq1 @MS Mincho Greek;}{\f401\fmodern\fcharset162\fprq1 @MS Mincho Tur;}{\f404\fmodern\fcharset186\fprq1 @MS Mincho Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0; -\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128; -\red192\green192\blue192;}{\stylesheet{\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1041\loch\f0\hich\af0\dbch\af11\cgrid\langnp1033\langfenp1041 \snext0 Normal;}{\*\cs10 \additive \ssemihidden -Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv -\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\rsidtbl \rsid14640435}{\*\generator Micr -osoft Word 11.0.5604;}{\info{\author Guillaume Laforte}{\operator Guillaume Laforte}{\creatim\yr2006\mo9\dy28\hr13\min56}{\revtim\yr2006\mo9\dy28\hr13\min56}{\version2}{\edmins0}{\nofpages1}{\nofwords90}{\nofchars517}{\*\company Feeling Software Inc.} -{\nofcharsws606}{\vern24689}}\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3 -\jcompress\viewkind4\viewscale100\nolnhtadjtbl\rsidroot14640435 \fet0\sectd \linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3 -\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} -{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain -\ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 \fs24\lang1033\langfe1041\loch\af0\hich\af0\dbch\af11\cgrid\langnp1033\langfenp1041 {\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 Pre-requisites for FCollada}{\f1\fs20\insrsid14640435 -\par \hich\af1\dbch\af11\loch\f1 Before proceeding with this installer, verify that you comply with the following pre-requisites: -\par -\par \hich\af1\dbch\af11\loch\f1 1. }{\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 This software is only supported with Microsoft Visual Studio \hich\af1\dbch\af11\loch\f1 200}{\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 5}{ -\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 . At the moment, we do not have the time and resources to support other operating systems and compilers. -\par -\par \hich\af1\dbch\af11\loch\f1 If you encounter problems with this software, or would like to suggest enhancements, visit the }{\field{\*\fldinst {\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 HYPERLINK "http://www.feelingsoftware.com/bugzilla/" }{ -\f1\fs20\insrsid14640435\charrsid14640435 {\*\datafield -00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b5200000068007400740070003a002f002f007700770077002e006600650065006c0069006e00670073006f006600740077006100720065002e0063006f006d002f006200750067007a0069006c006c0061002f000000} -}}{\fldrslt {\f1\fs20\ul\cf2\insrsid14640435 \hich\af1\dbch\af11\loch\f1 Fe\hich\af1\dbch\af11\loch\f1 eling Software bugzilla}}}{\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 .\line -\par }{\b\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 LICENSE -\par }{\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 This software is distributed under the }{\field{\*\fldinst {\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 HYPERLINK "http://www.opensource.org/licenses/mit-license.php" }{ -\f1\fs20\insrsid14640435\charrsid14640435 {\*\datafield -00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b6600000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006d00690074002d006c006900 -630065006e00730065002e007000680070000000}}}{\fldrslt {\f1\fs20\ul\cf2\insrsid14640435 \hich\af1\dbch\af11\loch\f1 MIT License}}}{\f1\fs20\insrsid14640435 \hich\af1\dbch\af11\loch\f1 -\par }} \ No newline at end of file diff -Nru 0ad-0.0.25b/libraries/source/glad/extensions/gles2.txt 0ad-0.0.26/libraries/source/glad/extensions/gles2.txt --- 0ad-0.0.25b/libraries/source/glad/extensions/gles2.txt 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/extensions/gles2.txt 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,8 @@ +GL_EXT_texture_compression_s3tc +GL_EXT_texture_filter_anisotropic +GL_EXT_texture_format_BGRA8888 +GL_KHR_debug +GL_OES_depth32 +GL_OES_mapbuffer +GL_OES_rgb8_rgba8 +GL_OES_texture_border_clamp diff -Nru 0ad-0.0.25b/libraries/source/glad/extensions/gl.txt 0ad-0.0.26/libraries/source/glad/extensions/gl.txt --- 0ad-0.0.25b/libraries/source/glad/extensions/gl.txt 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/extensions/gl.txt 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,35 @@ +GL_ARB_draw_buffers +GL_ARB_draw_instanced +GL_ARB_fragment_program +GL_ARB_fragment_shader +GL_ARB_framebuffer_object +GL_ARB_geometry_shader4 +GL_ARB_instanced_arrays +GL_ARB_map_buffer_range +GL_ARB_multitexture +GL_ARB_occlusion_query +GL_ARB_shader_objects +GL_ARB_shading_language_100 +GL_ARB_sync +GL_ARB_texture_compression +GL_ARB_texture_multisample +GL_ARB_texture_rectangle +GL_ARB_timer_query +GL_ARB_vertex_buffer_object +GL_ARB_vertex_program +GL_ARB_vertex_shader +GL_EXT_bgra +GL_EXT_blend_color +GL_EXT_blend_minmax +GL_EXT_draw_range_elements +GL_EXT_framebuffer_blit +GL_EXT_framebuffer_multisample +GL_EXT_framebuffer_object +GL_EXT_gpu_shader4 +GL_EXT_packed_depth_stencil +GL_EXT_texture_array +GL_EXT_texture_compression_s3tc +GL_EXT_texture_filter_anisotropic +GL_EXT_texture_lod_bias +GL_EXT_transform_feedback +GL_KHR_debug diff -Nru 0ad-0.0.25b/libraries/source/glad/extensions/glx.txt 0ad-0.0.26/libraries/source/glad/extensions/glx.txt --- 0ad-0.0.25b/libraries/source/glad/extensions/glx.txt 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/extensions/glx.txt 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,2 @@ +GLX_MESA_query_renderer +GLX_SGI_swap_control diff -Nru 0ad-0.0.25b/libraries/source/glad/extensions/wgl.txt 0ad-0.0.26/libraries/source/glad/extensions/wgl.txt --- 0ad-0.0.25b/libraries/source/glad/extensions/wgl.txt 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/extensions/wgl.txt 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1 @@ +WGL_EXT_swap_control diff -Nru 0ad-0.0.25b/libraries/source/glad/include/EGL/eglplatform.h 0ad-0.0.26/libraries/source/glad/include/EGL/eglplatform.h --- 0ad-0.0.25b/libraries/source/glad/include/EGL/eglplatform.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/EGL/eglplatform.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,169 @@ +#ifndef __eglplatform_h_ +#define __eglplatform_h_ + +/* +** Copyright 2007-2020 The Khronos Group Inc. +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* Platform-specific types and definitions for egl.h + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by filing an issue or pull request on the public Khronos EGL Registry, at + * https://www.github.com/KhronosGroup/EGL-Registry/ + */ + +#include + +/* Macros used in EGL function prototype declarations. + * + * EGL functions should be prototyped as: + * + * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); + * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); + * + * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h + */ + +#ifndef EGLAPI +#define EGLAPI KHRONOS_APICALL +#endif + +#ifndef EGLAPIENTRY +#define EGLAPIENTRY KHRONOS_APIENTRY +#endif +#define EGLAPIENTRYP EGLAPIENTRY* + +/* The types NativeDisplayType, NativeWindowType, and NativePixmapType + * are aliases of window-system-dependent types, such as X Display * or + * Windows Device Context. They must be defined in platform-specific + * code below. The EGL-prefixed versions of Native*Type are the same + * types, renamed in EGL 1.3 so all types in the API start with "EGL". + * + * Khronos STRONGLY RECOMMENDS that you use the default definitions + * provided below, since these changes affect both binary and source + * portability of applications using EGL running on different EGL + * implementations. + */ + +#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES) + +typedef void *EGLNativeDisplayType; +typedef void *EGLNativePixmapType; +typedef void *EGLNativeWindowType; + +#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include + +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; + +#elif defined(__EMSCRIPTEN__) + +typedef int EGLNativeDisplayType; +typedef int EGLNativePixmapType; +typedef int EGLNativeWindowType; + +#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ + +typedef int EGLNativeDisplayType; +typedef void *EGLNativePixmapType; +typedef void *EGLNativeWindowType; + +#elif defined(WL_EGL_PLATFORM) + +typedef struct wl_display *EGLNativeDisplayType; +typedef struct wl_egl_pixmap *EGLNativePixmapType; +typedef struct wl_egl_window *EGLNativeWindowType; + +#elif defined(__GBM__) + +typedef struct gbm_device *EGLNativeDisplayType; +typedef struct gbm_bo *EGLNativePixmapType; +typedef void *EGLNativeWindowType; + +#elif defined(__ANDROID__) || defined(ANDROID) + +struct ANativeWindow; +struct egl_native_pixmap_t; + +typedef void* EGLNativeDisplayType; +typedef struct egl_native_pixmap_t* EGLNativePixmapType; +typedef struct ANativeWindow* EGLNativeWindowType; + +#elif defined(USE_OZONE) + +typedef intptr_t EGLNativeDisplayType; +typedef intptr_t EGLNativePixmapType; +typedef intptr_t EGLNativeWindowType; + +#elif defined(USE_X11) + +/* X11 (tentative) */ +#include +#include + +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; + +#elif defined(__unix__) + +typedef void *EGLNativeDisplayType; +typedef khronos_uintptr_t EGLNativePixmapType; +typedef khronos_uintptr_t EGLNativeWindowType; + +#elif defined(__APPLE__) + +typedef int EGLNativeDisplayType; +typedef void *EGLNativePixmapType; +typedef void *EGLNativeWindowType; + +#elif defined(__HAIKU__) + +#include + +typedef void *EGLNativeDisplayType; +typedef khronos_uintptr_t EGLNativePixmapType; +typedef khronos_uintptr_t EGLNativeWindowType; + +#elif defined(__Fuchsia__) + +typedef void *EGLNativeDisplayType; +typedef khronos_uintptr_t EGLNativePixmapType; +typedef khronos_uintptr_t EGLNativeWindowType; + +#else +#error "Platform not recognized" +#endif + +/* EGL 1.2 types, renamed for consistency in EGL 1.3 */ +typedef EGLNativeDisplayType NativeDisplayType; +typedef EGLNativePixmapType NativePixmapType; +typedef EGLNativeWindowType NativeWindowType; + + +/* Define EGLint. This must be a signed integral type large enough to contain + * all legal attribute names and values passed into and out of EGL, whether + * their type is boolean, bitmask, enumerant (symbolic constant), integer, + * handle, or other. While in general a 32-bit integer will suffice, if + * handles are 64 bit types, then EGLint should be defined as a signed 64-bit + * integer type. + */ +typedef khronos_int32_t EGLint; + + +/* C++ / C typecast macros for special EGL handle values */ +#if defined(__cplusplus) +#define EGL_CAST(type, value) (static_cast(value)) +#else +#define EGL_CAST(type, value) ((type) (value)) +#endif + +#endif /* __eglplatform_h */ diff -Nru 0ad-0.0.25b/libraries/source/glad/include/glad/egl.h 0ad-0.0.26/libraries/source/glad/include/glad/egl.h --- 0ad-0.0.25b/libraries/source/glad/include/glad/egl.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/glad/egl.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,540 @@ +/** + * Loader generated by glad 2.0.0-beta on Mon May 9 20:31:48 2022 + * + * Generator: C/C++ + * Specification: egl + * Extensions: 0 + * + * APIs: + * - egl=1.5 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False + * - MX = False + * - MX_GLOBAL = False + * - ON_DEMAND = False + * + * Commandline: + * --api='egl=1.5' --extensions='' c + * + * Online: + * http://glad.sh/#api=egl%3D1.5&extensions=&generator=c&options= + * + */ + +#ifndef GLAD_EGL_H_ +#define GLAD_EGL_H_ + + +#define GLAD_EGL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.0-beta" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define EGL_ALPHA_FORMAT 0x3088 +#define EGL_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_ALPHA_FORMAT_PRE 0x308C +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BACK_BUFFER 0x3084 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_BLUE_SIZE 0x3022 +#define EGL_BUFFER_DESTROYED 0x3095 +#define EGL_BUFFER_PRESERVED 0x3094 +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_CLIENT_APIS 0x308D +#define EGL_CL_EVENT_HANDLE 0x309C +#define EGL_COLORSPACE 0x3087 +#define EGL_COLORSPACE_LINEAR 0x308A +#define EGL_COLORSPACE_sRGB 0x3089 +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_CONDITION_SATISFIED 0x30F6 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_CONFORMANT 0x3042 +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_CONTEXT_LOST 0x300E +#define EGL_CONTEXT_MAJOR_VERSION 0x3098 +#define EGL_CONTEXT_MINOR_VERSION 0x30FB +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 +#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 +#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2 +#define EGL_CORE_NATIVE_ENGINE 0x305B +#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0) +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_DISPLAY_SCALING 10000 +#define EGL_DONT_CARE EGL_CAST(EGLint,-1) +#define EGL_DRAW 0x3059 +#define EGL_EXTENSIONS 0x3055 +#define EGL_FALSE 0 +#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF +#define EGL_GL_COLORSPACE 0x309D +#define EGL_GL_COLORSPACE_LINEAR 0x308A +#define EGL_GL_COLORSPACE_SRGB 0x3089 +#define EGL_GL_RENDERBUFFER 0x30B9 +#define EGL_GL_TEXTURE_2D 0x30B1 +#define EGL_GL_TEXTURE_3D 0x30B2 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 +#define EGL_GL_TEXTURE_LEVEL 0x30BC +#define EGL_GL_TEXTURE_ZOFFSET 0x30BD +#define EGL_GREEN_SIZE 0x3023 +#define EGL_HEIGHT 0x3056 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_IMAGE_PRESERVED 0x30D2 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_LEVEL 0x3029 +#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF +#define EGL_LUMINANCE_BUFFER 0x308F +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_NONE 0x3038 +#define EGL_NON_CONFORMANT_CONFIG 0x3051 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) +#define EGL_NO_IMAGE EGL_CAST(EGLImage,0) +#define EGL_NO_RESET_NOTIFICATION 0x31BE +#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0) +#define EGL_NO_SYNC EGL_CAST(EGLSync,0) +#define EGL_NO_TEXTURE 0x305C +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_OPENGL_ES3_BIT 0x00000040 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENVG_API 0x30A1 +#define EGL_OPENVG_BIT 0x0002 +#define EGL_OPENVG_IMAGE 0x3096 +#define EGL_PBUFFER_BIT 0x0001 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_PIXMAP_BIT 0x0002 +#define EGL_READ 0x305A +#define EGL_RED_SIZE 0x3024 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_RGB_BUFFER 0x308E +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SIGNALED 0x30F2 +#define EGL_SINGLE_BUFFER 0x3085 +#define EGL_SLOW_CONFIG 0x3050 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SUCCESS 0x3000 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 +#define EGL_SYNC_CL_EVENT 0x30FE +#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF +#define EGL_SYNC_CONDITION 0x30F8 +#define EGL_SYNC_FENCE 0x30F9 +#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 +#define EGL_SYNC_STATUS 0x30F1 +#define EGL_SYNC_TYPE 0x30F7 +#define EGL_TEXTURE_2D 0x305F +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_TIMEOUT_EXPIRED 0x30F5 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_TRANSPARENT_RGB 0x3052 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRUE 1 +#define EGL_UNKNOWN EGL_CAST(EGLint,-1) +#define EGL_UNSIGNALED 0x30F3 +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_COLORSPACE_LINEAR 0x308A +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 +#define EGL_VG_COLORSPACE_sRGB 0x3089 +#define EGL_WIDTH 0x3057 +#define EGL_WINDOW_BIT 0x0004 + + +#include +#include + + + + + + + + + + + +struct AHardwareBuffer; +struct wl_buffer; +struct wl_display; +struct wl_resource; + +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef intptr_t EGLAttribKHR; +typedef intptr_t EGLAttrib; +typedef void *EGLClientBuffer; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDeviceEXT; +typedef void *EGLDisplay; +typedef void *EGLImage; +typedef void *EGLImageKHR; +typedef void *EGLLabelKHR; +typedef void *EGLObjectKHR; +typedef void *EGLOutputLayerEXT; +typedef void *EGLOutputPortEXT; +typedef void *EGLStreamKHR; +typedef void *EGLSurface; +typedef void *EGLSync; +typedef void *EGLSyncKHR; +typedef void *EGLSyncNV; +typedef void (*__eglMustCastToProperFunctionPointerType)(void); +typedef khronos_utime_nanoseconds_t EGLTimeKHR; +typedef khronos_utime_nanoseconds_t EGLTime; +typedef khronos_utime_nanoseconds_t EGLTimeNV; +typedef khronos_utime_nanoseconds_t EGLuint64NV; +typedef khronos_uint64_t EGLuint64KHR; +typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; +typedef int EGLNativeFileDescriptorKHR; +typedef khronos_ssize_t EGLsizeiANDROID; +typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); +typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); +struct EGLClientPixmapHI { + void *pData; + EGLint iWidth; + EGLint iHeight; + EGLint iStride; +}; +typedef void (GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); +#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC +#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC +#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC +#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC + + +#define EGL_VERSION_1_0 1 +GLAD_API_CALL int GLAD_EGL_VERSION_1_0; +#define EGL_VERSION_1_1 1 +GLAD_API_CALL int GLAD_EGL_VERSION_1_1; +#define EGL_VERSION_1_2 1 +GLAD_API_CALL int GLAD_EGL_VERSION_1_2; +#define EGL_VERSION_1_3 1 +GLAD_API_CALL int GLAD_EGL_VERSION_1_3; +#define EGL_VERSION_1_4 1 +GLAD_API_CALL int GLAD_EGL_VERSION_1_4; +#define EGL_VERSION_1_5 1 +GLAD_API_CALL int GLAD_EGL_VERSION_1_5; + + +typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint * attrib_list, EGLConfig * configs, EGLint config_size, EGLint * num_config); +typedef EGLint (GLAD_API_PTR *PFNEGLCLIENTWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLCOPYBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); +typedef EGLContext (GLAD_API_PTR *PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint * attrib_list); +typedef EGLImage (GLAD_API_PTR *PFNEGLCREATEIMAGEPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list); +typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC)(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint * attrib_list); +typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERSURFACEPROC)(EGLDisplay dpy, EGLConfig config, const EGLint * attrib_list); +typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint * attrib_list); +typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list); +typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list); +typedef EGLSync (GLAD_API_PTR *PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list); +typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSYNCPROC)(EGLDisplay dpy, EGLSync sync); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGSPROC)(EGLDisplay dpy, EGLConfig * configs, EGLint config_size, EGLint * num_config); +typedef EGLContext (GLAD_API_PTR *PFNEGLGETCURRENTCONTEXTPROC)(void); +typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETCURRENTDISPLAYPROC)(void); +typedef EGLSurface (GLAD_API_PTR *PFNEGLGETCURRENTSURFACEPROC)(EGLint readdraw); +typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id); +typedef EGLint (GLAD_API_PTR *PFNEGLGETERRORPROC)(void); +typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void * native_display, const EGLAttrib * attrib_list); +typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char * procname); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +typedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value); +typedef const char * (GLAD_API_PTR *PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint * value); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETHREADPROC)(void); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLSURFACEATTRIBPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLTERMINATEPROC)(EGLDisplay dpy); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITCLIENTPROC)(void); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITGLPROC)(void); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITNATIVEPROC)(EGLint engine); +typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags); + +GLAD_API_CALL PFNEGLBINDAPIPROC glad_eglBindAPI; +#define eglBindAPI glad_eglBindAPI +GLAD_API_CALL PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage; +#define eglBindTexImage glad_eglBindTexImage +GLAD_API_CALL PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig; +#define eglChooseConfig glad_eglChooseConfig +GLAD_API_CALL PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync; +#define eglClientWaitSync glad_eglClientWaitSync +GLAD_API_CALL PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers; +#define eglCopyBuffers glad_eglCopyBuffers +GLAD_API_CALL PFNEGLCREATECONTEXTPROC glad_eglCreateContext; +#define eglCreateContext glad_eglCreateContext +GLAD_API_CALL PFNEGLCREATEIMAGEPROC glad_eglCreateImage; +#define eglCreateImage glad_eglCreateImage +GLAD_API_CALL PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer; +#define eglCreatePbufferFromClientBuffer glad_eglCreatePbufferFromClientBuffer +GLAD_API_CALL PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface; +#define eglCreatePbufferSurface glad_eglCreatePbufferSurface +GLAD_API_CALL PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface; +#define eglCreatePixmapSurface glad_eglCreatePixmapSurface +GLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface; +#define eglCreatePlatformPixmapSurface glad_eglCreatePlatformPixmapSurface +GLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface; +#define eglCreatePlatformWindowSurface glad_eglCreatePlatformWindowSurface +GLAD_API_CALL PFNEGLCREATESYNCPROC glad_eglCreateSync; +#define eglCreateSync glad_eglCreateSync +GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface; +#define eglCreateWindowSurface glad_eglCreateWindowSurface +GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext; +#define eglDestroyContext glad_eglDestroyContext +GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage; +#define eglDestroyImage glad_eglDestroyImage +GLAD_API_CALL PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface; +#define eglDestroySurface glad_eglDestroySurface +GLAD_API_CALL PFNEGLDESTROYSYNCPROC glad_eglDestroySync; +#define eglDestroySync glad_eglDestroySync +GLAD_API_CALL PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib; +#define eglGetConfigAttrib glad_eglGetConfigAttrib +GLAD_API_CALL PFNEGLGETCONFIGSPROC glad_eglGetConfigs; +#define eglGetConfigs glad_eglGetConfigs +GLAD_API_CALL PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext; +#define eglGetCurrentContext glad_eglGetCurrentContext +GLAD_API_CALL PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay; +#define eglGetCurrentDisplay glad_eglGetCurrentDisplay +GLAD_API_CALL PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface; +#define eglGetCurrentSurface glad_eglGetCurrentSurface +GLAD_API_CALL PFNEGLGETDISPLAYPROC glad_eglGetDisplay; +#define eglGetDisplay glad_eglGetDisplay +GLAD_API_CALL PFNEGLGETERRORPROC glad_eglGetError; +#define eglGetError glad_eglGetError +GLAD_API_CALL PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay; +#define eglGetPlatformDisplay glad_eglGetPlatformDisplay +GLAD_API_CALL PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress; +#define eglGetProcAddress glad_eglGetProcAddress +GLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib; +#define eglGetSyncAttrib glad_eglGetSyncAttrib +GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize; +#define eglInitialize glad_eglInitialize +GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent; +#define eglMakeCurrent glad_eglMakeCurrent +GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI; +#define eglQueryAPI glad_eglQueryAPI +GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext; +#define eglQueryContext glad_eglQueryContext +GLAD_API_CALL PFNEGLQUERYSTRINGPROC glad_eglQueryString; +#define eglQueryString glad_eglQueryString +GLAD_API_CALL PFNEGLQUERYSURFACEPROC glad_eglQuerySurface; +#define eglQuerySurface glad_eglQuerySurface +GLAD_API_CALL PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage; +#define eglReleaseTexImage glad_eglReleaseTexImage +GLAD_API_CALL PFNEGLRELEASETHREADPROC glad_eglReleaseThread; +#define eglReleaseThread glad_eglReleaseThread +GLAD_API_CALL PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib; +#define eglSurfaceAttrib glad_eglSurfaceAttrib +GLAD_API_CALL PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers; +#define eglSwapBuffers glad_eglSwapBuffers +GLAD_API_CALL PFNEGLSWAPINTERVALPROC glad_eglSwapInterval; +#define eglSwapInterval glad_eglSwapInterval +GLAD_API_CALL PFNEGLTERMINATEPROC glad_eglTerminate; +#define eglTerminate glad_eglTerminate +GLAD_API_CALL PFNEGLWAITCLIENTPROC glad_eglWaitClient; +#define eglWaitClient glad_eglWaitClient +GLAD_API_CALL PFNEGLWAITGLPROC glad_eglWaitGL; +#define eglWaitGL glad_eglWaitGL +GLAD_API_CALL PFNEGLWAITNATIVEPROC glad_eglWaitNative; +#define eglWaitNative glad_eglWaitNative +GLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync; +#define eglWaitSync glad_eglWaitSync + + + + + +GLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load); + + +#ifdef __cplusplus +} +#endif +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/include/glad/gles2.h 0ad-0.0.26/libraries/source/glad/include/glad/gles2.h --- 0ad-0.0.25b/libraries/source/glad/include/glad/gles2.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/glad/gles2.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,1119 @@ +/** + * Loader generated by glad 2.0.0-beta on Tue Mar 29 08:49:05 2022 + * + * Generator: C/C++ + * Specification: gl + * Extensions: 8 + * + * APIs: + * - gles2=2.0 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False + * - MX = False + * - MX_GLOBAL = False + * - ON_DEMAND = False + * + * Commandline: + * --api='gles2=2.0' --extensions='GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_format_BGRA8888,GL_KHR_debug,GL_OES_depth32,GL_OES_mapbuffer,GL_OES_rgb8_rgba8,GL_OES_texture_border_clamp' c + * + * Online: + * http://glad.sh/#api=gles2%3D2.0&extensions=GL_EXT_texture_compression_s3tc%2CGL_EXT_texture_filter_anisotropic%2CGL_EXT_texture_format_BGRA8888%2CGL_KHR_debug%2CGL_OES_depth32%2CGL_OES_mapbuffer%2CGL_OES_rgb8_rgba8%2CGL_OES_texture_border_clamp&generator=c&options= + * + */ + +#ifndef GLAD_GLES2_H_ +#define GLAD_GLES2_H_ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#ifdef __gl2_h_ + #error OpenGL ES 2 header already included (API: gles2), remove previous include! +#endif +#define __gl2_h_ 1 +#ifdef __gl3_h_ + #error OpenGL ES 3 header already included (API: gles2), remove previous include! +#endif +#define __gl3_h_ 1 +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#define GLAD_GLES2 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.0-beta" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALPHA 0x1906 +#define GL_ALPHA_BITS 0x0D55 +#define GL_ALWAYS 0x0207 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_BACK 0x0405 +#define GL_BGRA_EXT 0x80E1 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLUE_BITS 0x0D54 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_BUFFER_ACCESS_OES 0x88BB +#define GL_BUFFER_KHR 0x82E0 +#define GL_BUFFER_MAPPED_OES 0x88BC +#define GL_BUFFER_MAP_POINTER_OES 0x88BD +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_BYTE 0x1400 +#define GL_CCW 0x0901 +#define GL_CLAMP_TO_BORDER_OES 0x812D +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_CW 0x0900 +#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define GL_DEBUG_OUTPUT_KHR 0x92E0 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define GL_DEBUG_SOURCE_API_KHR 0x8246 +#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define GL_DECR 0x1E03 +#define GL_DECR_WRAP 0x8508 +#define GL_DELETE_STATUS 0x8B80 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT32_OES 0x81A7 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DITHER 0x0BD0 +#define GL_DONT_CARE 0x1100 +#define GL_DST_ALPHA 0x0304 +#define GL_DST_COLOR 0x0306 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_EQUAL 0x0202 +#define GL_EXTENSIONS 0x1F03 +#define GL_FALSE 0 +#define GL_FASTEST 0x1101 +#define GL_FIXED 0x140C +#define GL_FLOAT 0x1406 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRONT 0x0404 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_FRONT_FACE 0x0B46 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_GEQUAL 0x0206 +#define GL_GREATER 0x0204 +#define GL_GREEN_BITS 0x0D53 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_HIGH_INT 0x8DF5 +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_INCR 0x1E02 +#define GL_INCR_WRAP 0x8507 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_INT 0x1404 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_OPERATION 0x0502 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVERT 0x150A +#define GL_KEEP 0x1E00 +#define GL_LEQUAL 0x0203 +#define GL_LESS 0x0201 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINK_STATUS 0x8B82 +#define GL_LOW_FLOAT 0x8DF0 +#define GL_LOW_INT 0x8DF3 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_NEAREST 0x2600 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEVER 0x0200 +#define GL_NICEST 0x1102 +#define GL_NONE 0 +#define GL_NOTEQUAL 0x0205 +#define GL_NO_ERROR 0 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_ONE 1 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_POINTS 0x0000 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_PROGRAM_KHR 0x82E2 +#define GL_PROGRAM_PIPELINE_KHR 0x82E4 +#define GL_QUERY_KHR 0x82E3 +#define GL_RED_BITS 0x0D52 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERER 0x1F01 +#define GL_REPEAT 0x2901 +#define GL_REPLACE 0x1E01 +#define GL_RGB 0x1907 +#define GL_RGB565 0x8D62 +#define GL_RGB5_A1 0x8057 +#define GL_RGB8_OES 0x8051 +#define GL_RGBA 0x1908 +#define GL_RGBA4 0x8056 +#define GL_RGBA8_OES 0x8058 +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_KHR 0x82E6 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_KHR 0x82E1 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_TYPE 0x8B4F +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_SHORT 0x1402 +#define GL_SRC_ALPHA 0x0302 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_SRC_COLOR 0x0300 +#define GL_STACK_OVERFLOW_KHR 0x0503 +#define GL_STACK_UNDERFLOW_KHR 0x0504 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STREAM_DRAW 0x88E0 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_BORDER_COLOR_OES 0x1004 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRUE 1 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_INT 0x1405 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_VENDOR 0x1F00 +#define GL_VERSION 0x1F02 +#define GL_VERTEX_ARRAY_KHR 0x8074 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_VIEWPORT 0x0BA2 +#define GL_WRITE_ONLY_OES 0x88B9 +#define GL_ZERO 0 + + +#include +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptr; +#else +typedef khronos_intptr_t GLintptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptrARB; +#else +typedef khronos_intptr_t GLintptrARB; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptr; +#else +typedef khronos_ssize_t GLsizeiptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptrARB; +#else +typedef khronos_ssize_t GLsizeiptrARB; +#endif +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); + + +#define GL_ES_VERSION_2_0 1 +GLAD_API_CALL int GLAD_GL_ES_VERSION_2_0; +#define GL_EXT_texture_compression_s3tc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; +#define GL_EXT_texture_filter_anisotropic 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic; +#define GL_EXT_texture_format_BGRA8888 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_format_BGRA8888; +#define GL_KHR_debug 1 +GLAD_API_CALL int GLAD_GL_KHR_debug; +#define GL_OES_depth32 1 +GLAD_API_CALL int GLAD_GL_OES_depth32; +#define GL_OES_mapbuffer 1 +GLAD_API_CALL int GLAD_GL_OES_mapbuffer; +#define GL_OES_rgb8_rgba8 1 +GLAD_API_CALL int GLAD_GL_OES_rgb8_rgba8; +#define GL_OES_texture_border_clamp 1 +GLAD_API_CALL int GLAD_GL_OES_texture_border_clamp; + + +typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); +typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); +typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d); +typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); +typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void * userParam); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); +typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); +typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); +typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVOESPROC)(GLenum target, GLenum pname, void ** params); +typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); +typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); +typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETPOINTERVKHRPROC)(GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision); +typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); +typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); +typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); +typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); +typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); +typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); +typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); +typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); +typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFEROESPROC)(GLenum target, GLenum access); +typedef void (GLAD_API_PTR *PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); +typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, const GLuint * param); +typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length); +typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, const GLuint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFEROESPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); + +GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +GLAD_API_CALL PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; +#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR +GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; +#define glDebugMessageControlKHR glad_glDebugMessageControlKHR +GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; +#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR +GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +GLAD_API_CALL PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES; +#define glGetBufferPointervOES glad_glGetBufferPointervOES +GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; +#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR +GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +GLAD_API_CALL PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; +#define glGetObjectLabelKHR glad_glGetObjectLabelKHR +GLAD_API_CALL PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; +#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR +GLAD_API_CALL PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; +#define glGetPointervKHR glad_glGetPointervKHR +GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES; +#define glGetSamplerParameterIivOES glad_glGetSamplerParameterIivOES +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES; +#define glGetSamplerParameterIuivOES glad_glGetSamplerParameterIuivOES +GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +GLAD_API_CALL PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES; +#define glGetTexParameterIivOES glad_glGetTexParameterIivOES +GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES; +#define glGetTexParameterIuivOES glad_glGetTexParameterIuivOES +GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +GLAD_API_CALL PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +GLAD_API_CALL PFNGLMAPBUFFEROESPROC glad_glMapBufferOES; +#define glMapBufferOES glad_glMapBufferOES +GLAD_API_CALL PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; +#define glObjectLabelKHR glad_glObjectLabelKHR +GLAD_API_CALL PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; +#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR +GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +GLAD_API_CALL PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; +#define glPopDebugGroupKHR glad_glPopDebugGroupKHR +GLAD_API_CALL PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; +#define glPushDebugGroupKHR glad_glPushDebugGroupKHR +GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +#define glReleaseShaderCompiler glad_glReleaseShaderCompiler +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES; +#define glSamplerParameterIivOES glad_glSamplerParameterIivOES +GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES; +#define glSamplerParameterIuivOES glad_glSamplerParameterIuivOES +GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary; +#define glShaderBinary glad_glShaderBinary +GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +GLAD_API_CALL PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES; +#define glTexParameterIivOES glad_glTexParameterIivOES +GLAD_API_CALL PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES; +#define glTexParameterIuivOES glad_glTexParameterIuivOES +GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +GLAD_API_CALL PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES; +#define glUnmapBufferOES glad_glUnmapBufferOES +GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport + + + + + +GLAD_API_CALL int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadGLES2( GLADloadfunc load); + + + +#ifdef __cplusplus +} +#endif +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/include/glad/gl.h 0ad-0.0.26/libraries/source/glad/include/glad/gl.h --- 0ad-0.0.25b/libraries/source/glad/include/glad/gl.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/glad/gl.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,4271 @@ +/** + * Loader generated by glad 2.0.0-beta on Wed Mar 30 00:33:29 2022 + * + * Generator: C/C++ + * Specification: gl + * Extensions: 35 + * + * APIs: + * - gl:core=2.1 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False + * - MX = False + * - MX_GLOBAL = False + * - ON_DEMAND = False + * + * Commandline: + * --api='gl:core=2.1' --extensions='GL_ARB_draw_buffers,GL_ARB_draw_instanced,GL_ARB_fragment_program,GL_ARB_fragment_shader,GL_ARB_framebuffer_object,GL_ARB_geometry_shader4,GL_ARB_instanced_arrays,GL_ARB_map_buffer_range,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_shader_objects,GL_ARB_shading_language_100,GL_ARB_sync,GL_ARB_texture_compression,GL_ARB_texture_multisample,GL_ARB_texture_rectangle,GL_ARB_timer_query,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_EXT_bgra,GL_EXT_blend_color,GL_EXT_blend_minmax,GL_EXT_draw_range_elements,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_packed_depth_stencil,GL_EXT_texture_array,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_lod_bias,GL_EXT_transform_feedback,GL_KHR_debug' c + * + * Online: + * http://glad.sh/#api=gl%3Acore%3D2.1&extensions=GL_ARB_draw_buffers%2CGL_ARB_draw_instanced%2CGL_ARB_fragment_program%2CGL_ARB_fragment_shader%2CGL_ARB_framebuffer_object%2CGL_ARB_geometry_shader4%2CGL_ARB_instanced_arrays%2CGL_ARB_map_buffer_range%2CGL_ARB_multitexture%2CGL_ARB_occlusion_query%2CGL_ARB_shader_objects%2CGL_ARB_shading_language_100%2CGL_ARB_sync%2CGL_ARB_texture_compression%2CGL_ARB_texture_multisample%2CGL_ARB_texture_rectangle%2CGL_ARB_timer_query%2CGL_ARB_vertex_buffer_object%2CGL_ARB_vertex_program%2CGL_ARB_vertex_shader%2CGL_EXT_bgra%2CGL_EXT_blend_color%2CGL_EXT_blend_minmax%2CGL_EXT_draw_range_elements%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_multisample%2CGL_EXT_framebuffer_object%2CGL_EXT_gpu_shader4%2CGL_EXT_packed_depth_stencil%2CGL_EXT_texture_array%2CGL_EXT_texture_compression_s3tc%2CGL_EXT_texture_filter_anisotropic%2CGL_EXT_texture_lod_bias%2CGL_EXT_transform_feedback%2CGL_KHR_debug&generator=c&options= + * + */ + +#ifndef GLAD_GL_H_ +#define GLAD_GL_H_ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#ifdef __gl_h_ + #error OpenGL (gl.h) header already included (API: gl), remove previous include! +#endif +#define __gl_h_ 1 +#ifdef __gl3_h_ + #error OpenGL (gl3.h) header already included (API: gl), remove previous include! +#endif +#define __gl3_h_ 1 +#ifdef __glext_h_ + #error OpenGL (glext.h) header already included (API: gl), remove previous include! +#endif +#define __glext_h_ 1 +#ifdef __gl3ext_h_ + #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include! +#endif +#define __gl3ext_h_ 1 +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#define GLAD_GL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.0-beta" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define GL_2D 0x0600 +#define GL_2_BYTES 0x1407 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_3_BYTES 0x1408 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_4_BYTES 0x1409 +#define GL_ACCUM 0x0100 +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ADD 0x0104 +#define GL_ADD_SIGNED 0x8574 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_ALPHA 0x1906 +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_ALPHA_BITS 0x0D55 +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_ALWAYS 0x0207 +#define GL_AMBIENT 0x1200 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_AND 0x1501 +#define GL_AND_INVERTED 0x1504 +#define GL_AND_REVERSE 0x1502 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_AUX_BUFFERS 0x0C00 +#define GL_BACK 0x0405 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_BGRA_EXT 0x80E1 +#define GL_BGR_EXT 0x80E0 +#define GL_BITMAP 0x1A00 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_COLOR_EXT 0x8005 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_EQUATION_EXT 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLUE 0x1905 +#define GL_BLUE_BIAS 0x0D1B +#define GL_BLUE_BITS 0x0D54 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BOOL 0x8B56 +#define GL_BOOL_ARB 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC2_ARB 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC3_ARB 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_BOOL_VEC4_ARB 0x8B59 +#define GL_BUFFER 0x82E0 +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_BYTE 0x1400 +#define GL_C3F_V3F 0x2A24 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_CCW 0x0901 +#define GL_CLAMP 0x2900 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_CLEAR 0x1500 +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_COEFF 0x0A00 +#define GL_COLOR 0x1800 +#define GL_COLOR_ARRAY 0x8076 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_INDEX 0x1900 +#define GL_COLOR_INDEXES 0x1603 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_COLOR_SUM 0x8458 +#define GL_COLOR_SUM_ARB 0x8458 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_COMBINE 0x8570 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +#define GL_CONDITION_SATISFIED 0x911C +#define GL_CONSTANT 0x8576 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_CONSTANT_ALPHA_EXT 0x8003 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_CONSTANT_COLOR_EXT 0x8001 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_COORD_REPLACE 0x8862 +#define GL_COPY 0x1503 +#define GL_COPY_INVERTED 0x150C +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_CURRENT_BIT 0x00000001 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_MATRIX_ARB 0x8641 +#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_CURRENT_QUERY 0x8865 +#define GL_CURRENT_QUERY_ARB 0x8865 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 +#define GL_CW 0x0900 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DECAL 0x2101 +#define GL_DECR 0x1E03 +#define GL_DECR_WRAP 0x8508 +#define GL_DELETE_STATUS 0x8B80 +#define GL_DEPTH 0x1801 +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_DEPTH_BIAS 0x0D1F +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DIFFUSE 0x1201 +#define GL_DITHER 0x0BD0 +#define GL_DOMAIN 0x0A02 +#define GL_DONT_CARE 0x1100 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +#define GL_DOUBLE 0x140A +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_DRAW_BUFFER15_ARB 0x8834 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_DST_ALPHA 0x0304 +#define GL_DST_COLOR 0x0306 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_DYNAMIC_COPY_ARB 0x88EA +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_EDGE_FLAG 0x0B43 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_EMISSION 0x1600 +#define GL_ENABLE_BIT 0x00002000 +#define GL_EQUAL 0x0202 +#define GL_EQUIV 0x1509 +#define GL_EVAL_BIT 0x00010000 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 +#define GL_EXTENSIONS 0x1F03 +#define GL_EYE_LINEAR 0x2400 +#define GL_EYE_PLANE 0x2502 +#define GL_FALSE 0 +#define GL_FASTEST 0x1101 +#define GL_FEEDBACK 0x1C01 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_FILL 0x1B02 +#define GL_FLAT 0x1D00 +#define GL_FLOAT 0x1406 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT2_ARB 0x8B5A +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT3_ARB 0x8B5B +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4 0x8B5C +#define GL_FLOAT_MAT4_ARB 0x8B5C +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC2_ARB 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC3_ARB 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FLOAT_VEC4_ARB 0x8B52 +#define GL_FOG 0x0B60 +#define GL_FOG_BIT 0x00000080 +#define GL_FOG_COLOR 0x0B66 +#define GL_FOG_COORD 0x8451 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_END 0x0B64 +#define GL_FOG_HINT 0x0C54 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_START 0x0B63 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_FRAGMENT_SHADER_ARB 0x8B30 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_FRONT 0x0404 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_FRONT_FACE 0x0B46 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_ADD_EXT 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define GL_GEQUAL 0x0206 +#define GL_GREATER 0x0204 +#define GL_GREEN 0x1904 +#define GL_GREEN_BIAS 0x0D19 +#define GL_GREEN_BITS 0x0D53 +#define GL_GREEN_SCALE 0x0D18 +#define GL_HINT_BIT 0x00008000 +#define GL_INCR 0x1E02 +#define GL_INCR_WRAP 0x8507 +#define GL_INDEX_ARRAY 0x8077 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_BITS 0x0D51 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_INDEX_MODE 0x0C30 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_INT 0x1404 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C +#define GL_INTERPOLATE 0x8575 +#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define GL_INT_SAMPLER_2D_EXT 0x8DCA +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define GL_INT_SAMPLER_3D_EXT 0x8DCB +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC2_ARB 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC3_ARB 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_INT_VEC4_ARB 0x8B55 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_INVALID_OPERATION 0x0502 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVERT 0x150A +#define GL_KEEP 0x1E00 +#define GL_LEFT 0x0406 +#define GL_LEQUAL 0x0203 +#define GL_LESS 0x0201 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LINE 0x1B01 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINES 0x0001 +#define GL_LINES_ADJACENCY_ARB 0x000A +#define GL_LINE_BIT 0x00000004 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define GL_LINE_TOKEN 0x0702 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINK_STATUS 0x8B82 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_BIT 0x00020000 +#define GL_LIST_INDEX 0x0B33 +#define GL_LIST_MODE 0x0B30 +#define GL_LOAD 0x0101 +#define GL_LOGIC_OP 0x0BF1 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_STENCIL 0x0D11 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MATRIX0_ARB 0x88C0 +#define GL_MATRIX10_ARB 0x88CA +#define GL_MATRIX11_ARB 0x88CB +#define GL_MATRIX12_ARB 0x88CC +#define GL_MATRIX13_ARB 0x88CD +#define GL_MATRIX14_ARB 0x88CE +#define GL_MATRIX15_ARB 0x88CF +#define GL_MATRIX16_ARB 0x88D0 +#define GL_MATRIX17_ARB 0x88D1 +#define GL_MATRIX18_ARB 0x88D2 +#define GL_MATRIX19_ARB 0x88D3 +#define GL_MATRIX1_ARB 0x88C1 +#define GL_MATRIX20_ARB 0x88D4 +#define GL_MATRIX21_ARB 0x88D5 +#define GL_MATRIX22_ARB 0x88D6 +#define GL_MATRIX23_ARB 0x88D7 +#define GL_MATRIX24_ARB 0x88D8 +#define GL_MATRIX25_ARB 0x88D9 +#define GL_MATRIX26_ARB 0x88DA +#define GL_MATRIX27_ARB 0x88DB +#define GL_MATRIX28_ARB 0x88DC +#define GL_MATRIX29_ARB 0x88DD +#define GL_MATRIX2_ARB 0x88C2 +#define GL_MATRIX30_ARB 0x88DE +#define GL_MATRIX31_ARB 0x88DF +#define GL_MATRIX3_ARB 0x88C3 +#define GL_MATRIX4_ARB 0x88C4 +#define GL_MATRIX5_ARB 0x88C5 +#define GL_MATRIX6_ARB 0x88C6 +#define GL_MATRIX7_ARB 0x88C7 +#define GL_MATRIX8_ARB 0x88C8 +#define GL_MATRIX9_ARB 0x88C9 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_MAX 0x8008 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_EXT 0x8008 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 +#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 +#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MIN 0x8007 +#define GL_MIN_EXT 0x8007 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MODELVIEW 0x1700 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_MODULATE 0x2100 +#define GL_MULT 0x0103 +#define GL_MULTISAMPLE 0x809D +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_N3F_V3F 0x2A25 +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_NAND 0x150E +#define GL_NEAREST 0x2600 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEVER 0x0200 +#define GL_NICEST 0x1102 +#define GL_NONE 0 +#define GL_NOOP 0x1505 +#define GL_NOR 0x1508 +#define GL_NORMALIZE 0x0BA1 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_MAP 0x8511 +#define GL_NOTEQUAL 0x0205 +#define GL_NO_ERROR 0 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 +#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 +#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 +#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 +#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 +#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 +#define GL_OBJECT_PLANE 0x2501 +#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 +#define GL_OBJECT_SUBTYPE_ARB 0x8B4F +#define GL_OBJECT_TYPE 0x9112 +#define GL_OBJECT_TYPE_ARB 0x8B4E +#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 +#define GL_ONE 1 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_OPERAND2_RGB 0x8592 +#define GL_OR 0x1507 +#define GL_ORDER 0x0A01 +#define GL_OR_INVERTED 0x150D +#define GL_OR_REVERSE 0x150B +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_POINT 0x1B00 +#define GL_POINTS 0x0000 +#define GL_POINT_BIT 0x00000002 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_POINT_SPRITE 0x8861 +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_POINT_TOKEN 0x0701 +#define GL_POLYGON 0x0009 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_POSITION 0x1203 +#define GL_PREVIOUS 0x8578 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define GL_PROGRAM 0x82E2 +#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_PROGRAM_BINDING_ARB 0x8677 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define GL_PROGRAM_LENGTH_ARB 0x8627 +#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define GL_PROGRAM_OBJECT_ARB 0x8B40 +#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define GL_PROJECTION 0x1701 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 +#define GL_Q 0x2003 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_QUERY 0x82E3 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_ARB 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#define GL_R 0x2002 +#define GL_R3_G3_B2 0x2A10 +#define GL_RASTERIZER_DISCARD_EXT 0x8C89 +#define GL_READ_BUFFER 0x0C02 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_READ_ONLY 0x88B8 +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_READ_WRITE 0x88BA +#define GL_READ_WRITE_ARB 0x88BA +#define GL_RED 0x1903 +#define GL_RED_BIAS 0x0D15 +#define GL_RED_BITS 0x0D52 +#define GL_RED_SCALE 0x0D14 +#define GL_REFLECTION_MAP 0x8512 +#define GL_RENDER 0x1C00 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERER 0x1F01 +#define GL_RENDER_MODE 0x0C40 +#define GL_REPEAT 0x2901 +#define GL_REPLACE 0x1E01 +#define GL_RESCALE_NORMAL 0x803A +#define GL_RETURN 0x0102 +#define GL_RGB 0x1907 +#define GL_RGB10 0x8052 +#define GL_RGB10_A2 0x8059 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB5_A1 0x8057 +#define GL_RGB8 0x8051 +#define GL_RGBA 0x1908 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGBA8 0x8058 +#define GL_RGBA_MODE 0x0C31 +#define GL_RGB_SCALE 0x8573 +#define GL_RIGHT 0x0407 +#define GL_S 0x2000 +#define GL_SAMPLER 0x82E6 +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_1D_ARB 0x8B5D +#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_2D_ARB 0x8B5E +#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_3D_ARB 0x8B5F +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_CUBE_ARB 0x8B60 +#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SAMPLES_PASSED_ARB 0x8914 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SELECT 0x1C02 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_SET 0x150F +#define GL_SHADER 0x82E1 +#define GL_SHADER_OBJECT_ARB 0x8B48 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_TYPE 0x8B4F +#define GL_SHADE_MODEL 0x0B54 +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C +#define GL_SHININESS 0x1601 +#define GL_SHORT 0x1402 +#define GL_SIGNALED 0x9119 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SMOOTH 0x1D01 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_SOURCE2_RGB 0x8582 +#define GL_SPECULAR 0x1202 +#define GL_SPHERE_MAP 0x2402 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_ALPHA 0x8589 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_ALPHA 0x858A +#define GL_SRC2_RGB 0x8582 +#define GL_SRC_ALPHA 0x0302 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_SRC_COLOR 0x0300 +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_STATIC_COPY 0x88E6 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_INDEX 0x1901 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STEREO 0x0C33 +#define GL_STREAM_COPY 0x88E2 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_SUBTRACT 0x84E7 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_SYNC_STATUS 0x9114 +#define GL_T 0x2001 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_T4F_V4F 0x2A28 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE10_ARB 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE11_ARB 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE12_ARB 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE13_ARB 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE14_ARB 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE15_ARB 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE16_ARB 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE17_ARB 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE18_ARB 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE19_ARB 0x84D3 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE20_ARB 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE21_ARB 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE22_ARB 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE23_ARB 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE24_ARB 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE25_ARB 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE26_ARB 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE27_ARB 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE28_ARB 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE29_ARB 0x84DD +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE30_ARB 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_TEXTURE31_ARB 0x84DF +#define GL_TEXTURE3_ARB 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE4_ARB 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE5_ARB 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE6_ARB 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE7_ARB 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE8_ARB 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE9_ARB 0x84C9 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_TEXTURE_3D 0x806F +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_BORDER 0x1005 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_ENV 0x2300 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_TIMESTAMP 0x8E28 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F +#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define GL_TRIANGLE_FAN 0x0006 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D +#define GL_TRUE 1 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNSIGNALED 0x9118 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_INT 0x1405 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_VENDOR 0x1F00 +#define GL_VERSION 0x1F02 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_VERTEX_PROGRAM_ARB 0x8620 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_VERTEX_SHADER_ARB 0x8B31 +#define GL_VIEWPORT 0x0BA2 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_WAIT_FAILED 0x911D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_WRITE_ONLY 0x88B9 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_XOR 0x1506 +#define GL_ZERO 0 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 + + +#include +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +// See https://bugs.freedesktop.org/show_bug.cgi?id=66346 +// macOS considers those to be different. +// typedef void *GLhandleARB; +typedef GLuint GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptr; +#else +typedef khronos_intptr_t GLintptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptrARB; +#else +typedef khronos_intptr_t GLintptrARB; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptr; +#else +typedef khronos_ssize_t GLsizeiptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptrARB; +#else +typedef khronos_ssize_t GLsizeiptrARB; +#endif +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); + + +#define GL_VERSION_1_0 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_0; +#define GL_VERSION_1_1 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_1; +#define GL_VERSION_1_2 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_2; +#define GL_VERSION_1_3 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_3; +#define GL_VERSION_1_4 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_4; +#define GL_VERSION_1_5 1 +GLAD_API_CALL int GLAD_GL_VERSION_1_5; +#define GL_VERSION_2_0 1 +GLAD_API_CALL int GLAD_GL_VERSION_2_0; +#define GL_VERSION_2_1 1 +GLAD_API_CALL int GLAD_GL_VERSION_2_1; +#define GL_ARB_draw_buffers 1 +GLAD_API_CALL int GLAD_GL_ARB_draw_buffers; +#define GL_ARB_draw_instanced 1 +GLAD_API_CALL int GLAD_GL_ARB_draw_instanced; +#define GL_ARB_fragment_program 1 +GLAD_API_CALL int GLAD_GL_ARB_fragment_program; +#define GL_ARB_fragment_shader 1 +GLAD_API_CALL int GLAD_GL_ARB_fragment_shader; +#define GL_ARB_framebuffer_object 1 +GLAD_API_CALL int GLAD_GL_ARB_framebuffer_object; +#define GL_ARB_geometry_shader4 1 +GLAD_API_CALL int GLAD_GL_ARB_geometry_shader4; +#define GL_ARB_instanced_arrays 1 +GLAD_API_CALL int GLAD_GL_ARB_instanced_arrays; +#define GL_ARB_map_buffer_range 1 +GLAD_API_CALL int GLAD_GL_ARB_map_buffer_range; +#define GL_ARB_multitexture 1 +GLAD_API_CALL int GLAD_GL_ARB_multitexture; +#define GL_ARB_occlusion_query 1 +GLAD_API_CALL int GLAD_GL_ARB_occlusion_query; +#define GL_ARB_shader_objects 1 +GLAD_API_CALL int GLAD_GL_ARB_shader_objects; +#define GL_ARB_shading_language_100 1 +GLAD_API_CALL int GLAD_GL_ARB_shading_language_100; +#define GL_ARB_sync 1 +GLAD_API_CALL int GLAD_GL_ARB_sync; +#define GL_ARB_texture_compression 1 +GLAD_API_CALL int GLAD_GL_ARB_texture_compression; +#define GL_ARB_texture_multisample 1 +GLAD_API_CALL int GLAD_GL_ARB_texture_multisample; +#define GL_ARB_texture_rectangle 1 +GLAD_API_CALL int GLAD_GL_ARB_texture_rectangle; +#define GL_ARB_timer_query 1 +GLAD_API_CALL int GLAD_GL_ARB_timer_query; +#define GL_ARB_vertex_buffer_object 1 +GLAD_API_CALL int GLAD_GL_ARB_vertex_buffer_object; +#define GL_ARB_vertex_program 1 +GLAD_API_CALL int GLAD_GL_ARB_vertex_program; +#define GL_ARB_vertex_shader 1 +GLAD_API_CALL int GLAD_GL_ARB_vertex_shader; +#define GL_EXT_bgra 1 +GLAD_API_CALL int GLAD_GL_EXT_bgra; +#define GL_EXT_blend_color 1 +GLAD_API_CALL int GLAD_GL_EXT_blend_color; +#define GL_EXT_blend_minmax 1 +GLAD_API_CALL int GLAD_GL_EXT_blend_minmax; +#define GL_EXT_draw_range_elements 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_range_elements; +#define GL_EXT_framebuffer_blit 1 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_blit; +#define GL_EXT_framebuffer_multisample 1 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_multisample; +#define GL_EXT_framebuffer_object 1 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_object; +#define GL_EXT_gpu_shader4 1 +GLAD_API_CALL int GLAD_GL_EXT_gpu_shader4; +#define GL_EXT_packed_depth_stencil 1 +GLAD_API_CALL int GLAD_GL_EXT_packed_depth_stencil; +#define GL_EXT_texture_array 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_array; +#define GL_EXT_texture_compression_s3tc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; +#define GL_EXT_texture_filter_anisotropic 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic; +#define GL_EXT_texture_lod_bias 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_lod_bias; +#define GL_EXT_transform_feedback 1 +GLAD_API_CALL int GLAD_GL_EXT_transform_feedback; +#define GL_KHR_debug 1 +GLAD_API_CALL int GLAD_GL_KHR_debug; + + +typedef void (GLAD_API_PTR *PFNGLACCUMPROC)(GLenum op, GLfloat value); +typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREARBPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); +typedef GLboolean (GLAD_API_PTR *PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint * textures, GLboolean * residences); +typedef void (GLAD_API_PTR *PFNGLARRAYELEMENTPROC)(GLint i); +typedef void (GLAD_API_PTR *PFNGLATTACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB obj); +typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLBEGINPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +typedef void (GLAD_API_PTR *PFNGLBEGINQUERYARBPROC)(GLenum target, GLuint id); +typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKEXTPROC)(GLenum primitiveMode); +typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONARBPROC)(GLhandleARB programObj, GLuint index, const GLcharARB * name); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERARBPROC)(GLenum target, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEEXTPROC)(GLenum target, GLuint index, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFEROFFSETEXTPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEEXTPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONEXTPROC)(GLuint program, GLuint color, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFEREXTPROC)(GLenum target, GLuint framebuffer); +typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMARBPROC)(GLenum target, GLuint program); +typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFEREXTPROC)(GLenum target, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void (GLAD_API_PTR *PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte * bitmap); +typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLBLENDCOLOREXTPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONEXTPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFEREXTPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); +typedef void (GLAD_API_PTR *PFNGLBUFFERDATAARBPROC)(GLenum target, GLsizeiptrARB size, const void * data, GLenum usage); +typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); +typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void * data); +typedef void (GLAD_API_PTR *PFNGLCALLLISTPROC)(GLuint list); +typedef void (GLAD_API_PTR *PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void * lists); +typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth); +typedef void (GLAD_API_PTR *PFNGLCLEARINDEXPROC)(GLfloat c); +typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLCLIENTACTIVETEXTUREARBPROC)(GLenum texture); +typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GLAD_API_PTR *PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble * equation); +typedef void (GLAD_API_PTR *PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UBVPROC)(const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3UIVPROC)(const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +typedef void (GLAD_API_PTR *PFNGLCOLOR3USVPROC)(const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UBVPROC)(const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4UIVPROC)(const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); +typedef void (GLAD_API_PTR *PFNGLCOLOR4USVPROC)(const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAD_API_PTR *PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERARBPROC)(GLhandleARB shaderObj); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); +typedef GLhandleARB (GLAD_API_PTR *PFNGLCREATEPROGRAMOBJECTARBPROC)(void); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); +typedef GLhandleARB (GLAD_API_PTR *PFNGLCREATESHADEROBJECTARBPROC)(GLenum shaderType); +typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void * userParam); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); +typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSARBPROC)(GLsizei n, const GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSEXTPROC)(GLsizei n, const GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); +typedef void (GLAD_API_PTR *PFNGLDELETEOBJECTARBPROC)(GLhandleARB obj); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMSARBPROC)(GLsizei n, const GLuint * programs); +typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESARBPROC)(GLsizei n, const GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSEXTPROC)(GLsizei n, const GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync); +typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); +typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); +typedef void (GLAD_API_PTR *PFNGLDETACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB attachedObj); +typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLDISABLECLIENTSTATEPROC)(GLenum array); +typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDARBPROC)(GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSARBPROC)(GLsizei n, const GLenum * bufs); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDARBPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSEXTPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLEDGEFLAGVPROC)(const GLboolean * flag); +typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLENABLECLIENTSTATEPROC)(GLenum array); +typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYARBPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLENDPROC)(void); +typedef void (GLAD_API_PTR *PFNGLENDLISTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLENDQUERYARBPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKEXTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DPROC)(GLdouble u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DVPROC)(const GLdouble * u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FPROC)(GLfloat u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FVPROC)(const GLfloat * u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DVPROC)(const GLdouble * u); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); +typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FVPROC)(const GLfloat * u); +typedef void (GLAD_API_PTR *PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); +typedef void (GLAD_API_PTR *PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +typedef void (GLAD_API_PTR *PFNGLEVALPOINT1PROC)(GLint i); +typedef void (GLAD_API_PTR *PFNGLEVALPOINT2PROC)(GLint i, GLint j); +typedef void (GLAD_API_PTR *PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat * buffer); +typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDDPROC)(GLdouble coord); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDDVPROC)(const GLdouble * coord); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDFPROC)(GLfloat coord); +typedef void (GLAD_API_PTR *PFNGLFOGCOORDFVPROC)(const GLfloat * coord); +typedef void (GLAD_API_PTR *PFNGLFOGFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLFOGFVPROC)(GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLFOGIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLFOGIVPROC)(GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREFACEARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLGENBUFFERSARBPROC)(GLsizei n, GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSEXTPROC)(GLsizei n, GLuint * framebuffers); +typedef GLuint (GLAD_API_PTR *PFNGLGENLISTSPROC)(GLsizei range); +typedef void (GLAD_API_PTR *PFNGLGENPROGRAMSARBPROC)(GLsizei n, GLuint * programs); +typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLGENQUERIESARBPROC)(GLsizei n, GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSEXTPROC)(GLsizei n, GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPEXTPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, GLint * size, GLenum * type, GLcharARB * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, GLint * size, GLenum * type, GLcharARB * name); +typedef void (GLAD_API_PTR *PFNGLGETATTACHEDOBJECTSARBPROC)(GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj); +typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); +typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); +typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB * name); +typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVARBPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVARBPROC)(GLenum target, GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data); +typedef void (GLAD_API_PTR *PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble * equation); +typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img); +typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint level, void * img); +typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); +typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data); +typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); +typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONEXTPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); +typedef GLhandleARB (GLAD_API_PTR *PFNGLGETHANDLEARBPROC)(GLenum pname); +typedef void (GLAD_API_PTR *PFNGLGETINFOLOGARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint * v); +typedef void (GLAD_API_PTR *PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPARAMETERFVARBPROC)(GLhandleARB obj, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPARAMETERIVARBPROC)(GLhandleARB obj, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat * values); +typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint * values); +typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort * values); +typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte * mask); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMENVPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMENVPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMSTRINGARBPROC)(GLenum target, GLenum pname, void * string); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVARBPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVARBPROC)(GLuint id, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVARBPROC)(GLuint id, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYIVARBPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); +typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source); +typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); +typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); +typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei * length, GLint * values); +typedef void (GLAD_API_PTR *PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name); +typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); +typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB * name); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVARBPROC)(GLhandleARB programObj, GLint location, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVARBPROC)(GLhandleARB programObj, GLint location, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVEXTPROC)(GLuint program, GLint location, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVEXTPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVEXTPROC)(GLuint index, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVARBPROC)(GLuint index, GLenum pname, void ** pointer); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVARBPROC)(GLuint index, GLenum pname, GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVARBPROC)(GLuint index, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVARBPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLINDEXMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLINDEXDPROC)(GLdouble c); +typedef void (GLAD_API_PTR *PFNGLINDEXDVPROC)(const GLdouble * c); +typedef void (GLAD_API_PTR *PFNGLINDEXFPROC)(GLfloat c); +typedef void (GLAD_API_PTR *PFNGLINDEXFVPROC)(const GLfloat * c); +typedef void (GLAD_API_PTR *PFNGLINDEXIPROC)(GLint c); +typedef void (GLAD_API_PTR *PFNGLINDEXIVPROC)(const GLint * c); +typedef void (GLAD_API_PTR *PFNGLINDEXSPROC)(GLshort c); +typedef void (GLAD_API_PTR *PFNGLINDEXSVPROC)(const GLshort * c); +typedef void (GLAD_API_PTR *PFNGLINDEXUBPROC)(GLubyte c); +typedef void (GLAD_API_PTR *PFNGLINDEXUBVPROC)(const GLubyte * c); +typedef void (GLAD_API_PTR *PFNGLINITNAMESPROC)(void); +typedef void (GLAD_API_PTR *PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void * pointer); +typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERARBPROC)(GLuint buffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); +typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFEREXTPROC)(GLuint framebuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISLISTPROC)(GLuint list); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMARBPROC)(GLuint program); +typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id); +typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYARBPROC)(GLuint id); +typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFEREXTPROC)(GLuint renderbuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); +typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync); +typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); +typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); +typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMARBPROC)(GLhandleARB programObj); +typedef void (GLAD_API_PTR *PFNGLLISTBASEPROC)(GLuint base); +typedef void (GLAD_API_PTR *PFNGLLOADIDENTITYPROC)(void); +typedef void (GLAD_API_PTR *PFNGLLOADMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLLOADMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLLOADNAMEPROC)(GLuint name); +typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode); +typedef void (GLAD_API_PTR *PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble * points); +typedef void (GLAD_API_PTR *PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat * points); +typedef void (GLAD_API_PTR *PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble * points); +typedef void (GLAD_API_PTR *PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat * points); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERARBPROC)(GLenum target, GLenum access); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GLAD_API_PTR *PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); +typedef void (GLAD_API_PTR *PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); +typedef void (GLAD_API_PTR *PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +typedef void (GLAD_API_PTR *PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLMATRIXMODEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLMULTMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLMULTMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble * m); +typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat * m); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DARBPROC)(GLenum target, GLdouble s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DVARBPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FARBPROC)(GLenum target, GLfloat s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FVARBPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IARBPROC)(GLenum target, GLint s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IVARBPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SARBPROC)(GLenum target, GLshort s); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SVARBPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DARBPROC)(GLenum target, GLdouble s, GLdouble t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DVARBPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FARBPROC)(GLenum target, GLfloat s, GLfloat t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FVARBPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IARBPROC)(GLenum target, GLint s, GLint t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IVARBPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SARBPROC)(GLenum target, GLshort s, GLshort t); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SVARBPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DARBPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DVARBPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FARBPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FVARBPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IARBPROC)(GLenum target, GLint s, GLint t, GLint r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IVARBPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SARBPROC)(GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SVARBPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DARBPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DVARBPROC)(GLenum target, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FARBPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FVARBPROC)(GLenum target, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IARBPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IVARBPROC)(GLenum target, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SARBPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SVARBPROC)(GLenum target, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLNEWLISTPROC)(GLuint list, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); +typedef void (GLAD_API_PTR *PFNGLNORMAL3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELPROC)(const void * ptr, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAD_API_PTR *PFNGLPASSTHROUGHPROC)(GLfloat token); +typedef void (GLAD_API_PTR *PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat * values); +typedef void (GLAD_API_PTR *PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint * values); +typedef void (GLAD_API_PTR *PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort * values); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size); +typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void (GLAD_API_PTR *PFNGLPOLYGONSTIPPLEPROC)(const GLubyte * mask); +typedef void (GLAD_API_PTR *PFNGLPOPATTRIBPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPCLIENTATTRIBPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPMATRIXPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPNAMEPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint * textures, const GLfloat * priorities); +typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLPROGRAMENVPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIARBPROC)(GLuint program, GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMSTRINGARBPROC)(GLenum target, GLenum format, GLsizei len, const void * string); +typedef void (GLAD_API_PTR *PFNGLPUSHATTRIBPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); +typedef void (GLAD_API_PTR *PFNGLPUSHMATRIXPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPUSHNAMEPROC)(GLuint name); +typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IPROC)(GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src); +typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +typedef void (GLAD_API_PTR *PFNGLRECTDVPROC)(const GLdouble * v1, const GLdouble * v2); +typedef void (GLAD_API_PTR *PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +typedef void (GLAD_API_PTR *PFNGLRECTFVPROC)(const GLfloat * v1, const GLfloat * v2); +typedef void (GLAD_API_PTR *PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); +typedef void (GLAD_API_PTR *PFNGLRECTIVPROC)(const GLint * v1, const GLint * v2); +typedef void (GLAD_API_PTR *PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +typedef void (GLAD_API_PTR *PFNGLRECTSVPROC)(const GLshort * v1, const GLshort * v2); +typedef GLint (GLAD_API_PTR *PFNGLRENDERMODEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USVPROC)(const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint * buffer); +typedef void (GLAD_API_PTR *PFNGLSHADEMODELPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); +typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEARBPROC)(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** string, const GLint * length); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DPROC)(GLdouble s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FPROC)(GLfloat s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SPROC)(GLshort s); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IPROC)(GLint s, GLint t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); +typedef void (GLAD_API_PTR *PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble * params); +typedef void (GLAD_API_PTR *PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode); +typedef void (GLAD_API_PTR *PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FARBPROC)(GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IARBPROC)(GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVARBPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIEXTPROC)(GLint location, GLuint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVEXTPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FARBPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IARBPROC)(GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVARBPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIEXTPROC)(GLint location, GLuint v0, GLuint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVEXTPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FARBPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IARBPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVARBPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIEXTPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVEXTPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FARBPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVARBPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IARBPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVARBPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIEXTPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVEXTPROC)(GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target); +typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERARBPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMOBJECTARBPROC)(GLhandleARB programObj); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMARBPROC)(GLhandleARB programObj); +typedef void (GLAD_API_PTR *PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX2IPROC)(GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX2SPROC)(GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLVERTEX2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLVERTEX3SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLVERTEX4SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DARBPROC)(GLuint index, GLdouble x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVARBPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FARBPROC)(GLuint index, GLfloat x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVARBPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SARBPROC)(GLuint index, GLshort x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVARBPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DARBPROC)(GLuint index, GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVARBPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FARBPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVARBPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SARBPROC)(GLuint index, GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVARBPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVARBPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVARBPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVARBPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVARBPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVARBPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVARBPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBARBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVARBPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVARBPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVARBPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVARBPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVARBPROC)(GLuint index, const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVARBPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVARBPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVARBPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVARBPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVARBPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVARBPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORARBPROC)(GLuint index, GLuint divisor); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IEXTPROC)(GLuint index, GLint x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVEXTPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIEXTPROC)(GLuint index, GLuint x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVEXTPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IEXTPROC)(GLuint index, GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVEXTPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIEXTPROC)(GLuint index, GLuint x, GLuint y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVEXTPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IEXTPROC)(GLuint index, GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVEXTPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIEXTPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVEXTPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVEXTPROC)(GLuint index, const GLbyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IEXTPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVEXTPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVEXTPROC)(GLuint index, const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVEXTPROC)(GLuint index, const GLubyte * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIEXTPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVEXTPROC)(GLuint index, const GLuint * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVEXTPROC)(GLuint index, const GLushort * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTEREXTPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERARBPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SVPROC)(const GLshort * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DVPROC)(const GLdouble * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FVPROC)(const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IVPROC)(const GLint * v); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SVPROC)(const GLshort * v); + +GLAD_API_CALL PFNGLACCUMPROC glad_glAccum; +#define glAccum glad_glAccum +GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +GLAD_API_CALL PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB; +#define glActiveTextureARB glad_glActiveTextureARB +GLAD_API_CALL PFNGLALPHAFUNCPROC glad_glAlphaFunc; +#define glAlphaFunc glad_glAlphaFunc +GLAD_API_CALL PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +#define glAreTexturesResident glad_glAreTexturesResident +GLAD_API_CALL PFNGLARRAYELEMENTPROC glad_glArrayElement; +#define glArrayElement glad_glArrayElement +GLAD_API_CALL PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB; +#define glAttachObjectARB glad_glAttachObjectARB +GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +GLAD_API_CALL PFNGLBEGINPROC glad_glBegin; +#define glBegin glad_glBegin +GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +GLAD_API_CALL PFNGLBEGINQUERYARBPROC glad_glBeginQueryARB; +#define glBeginQueryARB glad_glBeginQueryARB +GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKEXTPROC glad_glBeginTransformFeedbackEXT; +#define glBeginTransformFeedbackEXT glad_glBeginTransformFeedbackEXT +GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +GLAD_API_CALL PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB; +#define glBindAttribLocationARB glad_glBindAttribLocationARB +GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +GLAD_API_CALL PFNGLBINDBUFFERARBPROC glad_glBindBufferARB; +#define glBindBufferARB glad_glBindBufferARB +GLAD_API_CALL PFNGLBINDBUFFERBASEEXTPROC glad_glBindBufferBaseEXT; +#define glBindBufferBaseEXT glad_glBindBufferBaseEXT +GLAD_API_CALL PFNGLBINDBUFFEROFFSETEXTPROC glad_glBindBufferOffsetEXT; +#define glBindBufferOffsetEXT glad_glBindBufferOffsetEXT +GLAD_API_CALL PFNGLBINDBUFFERRANGEEXTPROC glad_glBindBufferRangeEXT; +#define glBindBufferRangeEXT glad_glBindBufferRangeEXT +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT; +#define glBindFragDataLocationEXT glad_glBindFragDataLocationEXT +GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +GLAD_API_CALL PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT; +#define glBindFramebufferEXT glad_glBindFramebufferEXT +GLAD_API_CALL PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB; +#define glBindProgramARB glad_glBindProgramARB +GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +GLAD_API_CALL PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT; +#define glBindRenderbufferEXT glad_glBindRenderbufferEXT +GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +GLAD_API_CALL PFNGLBITMAPPROC glad_glBitmap; +#define glBitmap glad_glBitmap +GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +GLAD_API_CALL PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT; +#define glBlendColorEXT glad_glBlendColorEXT +GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +GLAD_API_CALL PFNGLBLENDEQUATIONEXTPROC glad_glBlendEquationEXT; +#define glBlendEquationEXT glad_glBlendEquationEXT +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +GLAD_API_CALL PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT; +#define glBlitFramebufferEXT glad_glBlitFramebufferEXT +GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +GLAD_API_CALL PFNGLBUFFERDATAARBPROC glad_glBufferDataARB; +#define glBufferDataARB glad_glBufferDataARB +GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +GLAD_API_CALL PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB; +#define glBufferSubDataARB glad_glBufferSubDataARB +GLAD_API_CALL PFNGLCALLLISTPROC glad_glCallList; +#define glCallList glad_glCallList +GLAD_API_CALL PFNGLCALLLISTSPROC glad_glCallLists; +#define glCallLists glad_glCallLists +GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT; +#define glCheckFramebufferStatusEXT glad_glCheckFramebufferStatusEXT +GLAD_API_CALL PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +GLAD_API_CALL PFNGLCLEARACCUMPROC glad_glClearAccum; +#define glClearAccum glad_glClearAccum +GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +GLAD_API_CALL PFNGLCLEARINDEXPROC glad_glClearIndex; +#define glClearIndex glad_glClearIndex +GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +GLAD_API_CALL PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +#define glClientActiveTexture glad_glClientActiveTexture +GLAD_API_CALL PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB; +#define glClientActiveTextureARB glad_glClientActiveTextureARB +GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +GLAD_API_CALL PFNGLCLIPPLANEPROC glad_glClipPlane; +#define glClipPlane glad_glClipPlane +GLAD_API_CALL PFNGLCOLOR3BPROC glad_glColor3b; +#define glColor3b glad_glColor3b +GLAD_API_CALL PFNGLCOLOR3BVPROC glad_glColor3bv; +#define glColor3bv glad_glColor3bv +GLAD_API_CALL PFNGLCOLOR3DPROC glad_glColor3d; +#define glColor3d glad_glColor3d +GLAD_API_CALL PFNGLCOLOR3DVPROC glad_glColor3dv; +#define glColor3dv glad_glColor3dv +GLAD_API_CALL PFNGLCOLOR3FPROC glad_glColor3f; +#define glColor3f glad_glColor3f +GLAD_API_CALL PFNGLCOLOR3FVPROC glad_glColor3fv; +#define glColor3fv glad_glColor3fv +GLAD_API_CALL PFNGLCOLOR3IPROC glad_glColor3i; +#define glColor3i glad_glColor3i +GLAD_API_CALL PFNGLCOLOR3IVPROC glad_glColor3iv; +#define glColor3iv glad_glColor3iv +GLAD_API_CALL PFNGLCOLOR3SPROC glad_glColor3s; +#define glColor3s glad_glColor3s +GLAD_API_CALL PFNGLCOLOR3SVPROC glad_glColor3sv; +#define glColor3sv glad_glColor3sv +GLAD_API_CALL PFNGLCOLOR3UBPROC glad_glColor3ub; +#define glColor3ub glad_glColor3ub +GLAD_API_CALL PFNGLCOLOR3UBVPROC glad_glColor3ubv; +#define glColor3ubv glad_glColor3ubv +GLAD_API_CALL PFNGLCOLOR3UIPROC glad_glColor3ui; +#define glColor3ui glad_glColor3ui +GLAD_API_CALL PFNGLCOLOR3UIVPROC glad_glColor3uiv; +#define glColor3uiv glad_glColor3uiv +GLAD_API_CALL PFNGLCOLOR3USPROC glad_glColor3us; +#define glColor3us glad_glColor3us +GLAD_API_CALL PFNGLCOLOR3USVPROC glad_glColor3usv; +#define glColor3usv glad_glColor3usv +GLAD_API_CALL PFNGLCOLOR4BPROC glad_glColor4b; +#define glColor4b glad_glColor4b +GLAD_API_CALL PFNGLCOLOR4BVPROC glad_glColor4bv; +#define glColor4bv glad_glColor4bv +GLAD_API_CALL PFNGLCOLOR4DPROC glad_glColor4d; +#define glColor4d glad_glColor4d +GLAD_API_CALL PFNGLCOLOR4DVPROC glad_glColor4dv; +#define glColor4dv glad_glColor4dv +GLAD_API_CALL PFNGLCOLOR4FPROC glad_glColor4f; +#define glColor4f glad_glColor4f +GLAD_API_CALL PFNGLCOLOR4FVPROC glad_glColor4fv; +#define glColor4fv glad_glColor4fv +GLAD_API_CALL PFNGLCOLOR4IPROC glad_glColor4i; +#define glColor4i glad_glColor4i +GLAD_API_CALL PFNGLCOLOR4IVPROC glad_glColor4iv; +#define glColor4iv glad_glColor4iv +GLAD_API_CALL PFNGLCOLOR4SPROC glad_glColor4s; +#define glColor4s glad_glColor4s +GLAD_API_CALL PFNGLCOLOR4SVPROC glad_glColor4sv; +#define glColor4sv glad_glColor4sv +GLAD_API_CALL PFNGLCOLOR4UBPROC glad_glColor4ub; +#define glColor4ub glad_glColor4ub +GLAD_API_CALL PFNGLCOLOR4UBVPROC glad_glColor4ubv; +#define glColor4ubv glad_glColor4ubv +GLAD_API_CALL PFNGLCOLOR4UIPROC glad_glColor4ui; +#define glColor4ui glad_glColor4ui +GLAD_API_CALL PFNGLCOLOR4UIVPROC glad_glColor4uiv; +#define glColor4uiv glad_glColor4uiv +GLAD_API_CALL PFNGLCOLOR4USPROC glad_glColor4us; +#define glColor4us glad_glColor4us +GLAD_API_CALL PFNGLCOLOR4USVPROC glad_glColor4usv; +#define glColor4usv glad_glColor4usv +GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +GLAD_API_CALL PFNGLCOLORMATERIALPROC glad_glColorMaterial; +#define glColorMaterial glad_glColorMaterial +GLAD_API_CALL PFNGLCOLORPOINTERPROC glad_glColorPointer; +#define glColorPointer glad_glColorPointer +GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +GLAD_API_CALL PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB; +#define glCompileShaderARB glad_glCompileShaderARB +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB; +#define glCompressedTexImage1DARB glad_glCompressedTexImage1DARB +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB; +#define glCompressedTexImage2DARB glad_glCompressedTexImage2DARB +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB; +#define glCompressedTexImage3DARB glad_glCompressedTexImage3DARB +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB; +#define glCompressedTexSubImage1DARB glad_glCompressedTexSubImage1DARB +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB; +#define glCompressedTexSubImage2DARB glad_glCompressedTexSubImage2DARB +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB; +#define glCompressedTexSubImage3DARB glad_glCompressedTexSubImage3DARB +GLAD_API_CALL PFNGLCOPYPIXELSPROC glad_glCopyPixels; +#define glCopyPixels glad_glCopyPixels +GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +GLAD_API_CALL PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB; +#define glCreateProgramObjectARB glad_glCreateProgramObjectARB +GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +GLAD_API_CALL PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB; +#define glCreateShaderObjectARB glad_glCreateShaderObjectARB +GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; +#define glDebugMessageCallback glad_glDebugMessageCallback +GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; +#define glDebugMessageControl glad_glDebugMessageControl +GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; +#define glDebugMessageInsert glad_glDebugMessageInsert +GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +GLAD_API_CALL PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB; +#define glDeleteBuffersARB glad_glDeleteBuffersARB +GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT; +#define glDeleteFramebuffersEXT glad_glDeleteFramebuffersEXT +GLAD_API_CALL PFNGLDELETELISTSPROC glad_glDeleteLists; +#define glDeleteLists glad_glDeleteLists +GLAD_API_CALL PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB; +#define glDeleteObjectARB glad_glDeleteObjectARB +GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +GLAD_API_CALL PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB; +#define glDeleteProgramsARB glad_glDeleteProgramsARB +GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +GLAD_API_CALL PFNGLDELETEQUERIESARBPROC glad_glDeleteQueriesARB; +#define glDeleteQueriesARB glad_glDeleteQueriesARB +GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +GLAD_API_CALL PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT; +#define glDeleteRenderbuffersEXT glad_glDeleteRenderbuffersEXT +GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +GLAD_API_CALL PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB; +#define glDetachObjectARB glad_glDetachObjectARB +GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +GLAD_API_CALL PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +#define glDisableClientState glad_glDisableClientState +GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB; +#define glDisableVertexAttribArrayARB glad_glDisableVertexAttribArrayARB +GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB; +#define glDrawArraysInstancedARB glad_glDrawArraysInstancedARB +GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +GLAD_API_CALL PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB; +#define glDrawBuffersARB glad_glDrawBuffersARB +GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB; +#define glDrawElementsInstancedARB glad_glDrawElementsInstancedARB +GLAD_API_CALL PFNGLDRAWPIXELSPROC glad_glDrawPixels; +#define glDrawPixels glad_glDrawPixels +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSEXTPROC glad_glDrawRangeElementsEXT; +#define glDrawRangeElementsEXT glad_glDrawRangeElementsEXT +GLAD_API_CALL PFNGLEDGEFLAGPROC glad_glEdgeFlag; +#define glEdgeFlag glad_glEdgeFlag +GLAD_API_CALL PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +#define glEdgeFlagPointer glad_glEdgeFlagPointer +GLAD_API_CALL PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +#define glEdgeFlagv glad_glEdgeFlagv +GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +GLAD_API_CALL PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +#define glEnableClientState glad_glEnableClientState +GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB; +#define glEnableVertexAttribArrayARB glad_glEnableVertexAttribArrayARB +GLAD_API_CALL PFNGLENDPROC glad_glEnd; +#define glEnd glad_glEnd +GLAD_API_CALL PFNGLENDLISTPROC glad_glEndList; +#define glEndList glad_glEndList +GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +GLAD_API_CALL PFNGLENDQUERYARBPROC glad_glEndQueryARB; +#define glEndQueryARB glad_glEndQueryARB +GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKEXTPROC glad_glEndTransformFeedbackEXT; +#define glEndTransformFeedbackEXT glad_glEndTransformFeedbackEXT +GLAD_API_CALL PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +#define glEvalCoord1d glad_glEvalCoord1d +GLAD_API_CALL PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +#define glEvalCoord1dv glad_glEvalCoord1dv +GLAD_API_CALL PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +#define glEvalCoord1f glad_glEvalCoord1f +GLAD_API_CALL PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +#define glEvalCoord1fv glad_glEvalCoord1fv +GLAD_API_CALL PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +#define glEvalCoord2d glad_glEvalCoord2d +GLAD_API_CALL PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +#define glEvalCoord2dv glad_glEvalCoord2dv +GLAD_API_CALL PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +#define glEvalCoord2f glad_glEvalCoord2f +GLAD_API_CALL PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +#define glEvalCoord2fv glad_glEvalCoord2fv +GLAD_API_CALL PFNGLEVALMESH1PROC glad_glEvalMesh1; +#define glEvalMesh1 glad_glEvalMesh1 +GLAD_API_CALL PFNGLEVALMESH2PROC glad_glEvalMesh2; +#define glEvalMesh2 glad_glEvalMesh2 +GLAD_API_CALL PFNGLEVALPOINT1PROC glad_glEvalPoint1; +#define glEvalPoint1 glad_glEvalPoint1 +GLAD_API_CALL PFNGLEVALPOINT2PROC glad_glEvalPoint2; +#define glEvalPoint2 glad_glEvalPoint2 +GLAD_API_CALL PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +#define glFeedbackBuffer glad_glFeedbackBuffer +GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +GLAD_API_CALL PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +#define glFogCoordPointer glad_glFogCoordPointer +GLAD_API_CALL PFNGLFOGCOORDDPROC glad_glFogCoordd; +#define glFogCoordd glad_glFogCoordd +GLAD_API_CALL PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +#define glFogCoorddv glad_glFogCoorddv +GLAD_API_CALL PFNGLFOGCOORDFPROC glad_glFogCoordf; +#define glFogCoordf glad_glFogCoordf +GLAD_API_CALL PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +#define glFogCoordfv glad_glFogCoordfv +GLAD_API_CALL PFNGLFOGFPROC glad_glFogf; +#define glFogf glad_glFogf +GLAD_API_CALL PFNGLFOGFVPROC glad_glFogfv; +#define glFogfv glad_glFogfv +GLAD_API_CALL PFNGLFOGIPROC glad_glFogi; +#define glFogi glad_glFogi +GLAD_API_CALL PFNGLFOGIVPROC glad_glFogiv; +#define glFogiv glad_glFogiv +GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT; +#define glFramebufferRenderbufferEXT glad_glFramebufferRenderbufferEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT; +#define glFramebufferTexture1DEXT glad_glFramebufferTexture1DEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT; +#define glFramebufferTexture2DEXT glad_glFramebufferTexture2DEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT; +#define glFramebufferTexture3DEXT glad_glFramebufferTexture3DEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB; +#define glFramebufferTextureARB glad_glFramebufferTextureARB +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB; +#define glFramebufferTextureFaceARB glad_glFramebufferTextureFaceARB +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB; +#define glFramebufferTextureLayerARB glad_glFramebufferTextureLayerARB +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glad_glFramebufferTextureLayerEXT; +#define glFramebufferTextureLayerEXT glad_glFramebufferTextureLayerEXT +GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +GLAD_API_CALL PFNGLFRUSTUMPROC glad_glFrustum; +#define glFrustum glad_glFrustum +GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +GLAD_API_CALL PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB; +#define glGenBuffersARB glad_glGenBuffersARB +GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +GLAD_API_CALL PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT; +#define glGenFramebuffersEXT glad_glGenFramebuffersEXT +GLAD_API_CALL PFNGLGENLISTSPROC glad_glGenLists; +#define glGenLists glad_glGenLists +GLAD_API_CALL PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB; +#define glGenProgramsARB glad_glGenProgramsARB +GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +GLAD_API_CALL PFNGLGENQUERIESARBPROC glad_glGenQueriesARB; +#define glGenQueriesARB glad_glGenQueriesARB +GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +GLAD_API_CALL PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT; +#define glGenRenderbuffersEXT glad_glGenRenderbuffersEXT +GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +GLAD_API_CALL PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; +#define glGenerateMipmapEXT glad_glGenerateMipmapEXT +GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +GLAD_API_CALL PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB; +#define glGetActiveAttribARB glad_glGetActiveAttribARB +GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +GLAD_API_CALL PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB; +#define glGetActiveUniformARB glad_glGetActiveUniformARB +GLAD_API_CALL PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB; +#define glGetAttachedObjectsARB glad_glGetAttachedObjectsARB +GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +GLAD_API_CALL PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB; +#define glGetAttribLocationARB glad_glGetAttribLocationARB +GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB; +#define glGetBufferParameterivARB glad_glGetBufferParameterivARB +GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +GLAD_API_CALL PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB; +#define glGetBufferPointervARB glad_glGetBufferPointervARB +GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +GLAD_API_CALL PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB; +#define glGetBufferSubDataARB glad_glGetBufferSubDataARB +GLAD_API_CALL PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +#define glGetClipPlane glad_glGetClipPlane +GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB; +#define glGetCompressedTexImageARB glad_glGetCompressedTexImageARB +GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; +#define glGetDebugMessageLog glad_glGetDebugMessageLog +GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +GLAD_API_CALL PFNGLGETFRAGDATALOCATIONEXTPROC glad_glGetFragDataLocationEXT; +#define glGetFragDataLocationEXT glad_glGetFragDataLocationEXT +GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT; +#define glGetFramebufferAttachmentParameterivEXT glad_glGetFramebufferAttachmentParameterivEXT +GLAD_API_CALL PFNGLGETHANDLEARBPROC glad_glGetHandleARB; +#define glGetHandleARB glad_glGetHandleARB +GLAD_API_CALL PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB; +#define glGetInfoLogARB glad_glGetInfoLogARB +GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +GLAD_API_CALL PFNGLGETLIGHTFVPROC glad_glGetLightfv; +#define glGetLightfv glad_glGetLightfv +GLAD_API_CALL PFNGLGETLIGHTIVPROC glad_glGetLightiv; +#define glGetLightiv glad_glGetLightiv +GLAD_API_CALL PFNGLGETMAPDVPROC glad_glGetMapdv; +#define glGetMapdv glad_glGetMapdv +GLAD_API_CALL PFNGLGETMAPFVPROC glad_glGetMapfv; +#define glGetMapfv glad_glGetMapfv +GLAD_API_CALL PFNGLGETMAPIVPROC glad_glGetMapiv; +#define glGetMapiv glad_glGetMapiv +GLAD_API_CALL PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +#define glGetMaterialfv glad_glGetMaterialfv +GLAD_API_CALL PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +#define glGetMaterialiv glad_glGetMaterialiv +GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +GLAD_API_CALL PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; +#define glGetObjectLabel glad_glGetObjectLabel +GLAD_API_CALL PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB; +#define glGetObjectParameterfvARB glad_glGetObjectParameterfvARB +GLAD_API_CALL PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB; +#define glGetObjectParameterivARB glad_glGetObjectParameterivARB +GLAD_API_CALL PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; +#define glGetObjectPtrLabel glad_glGetObjectPtrLabel +GLAD_API_CALL PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +#define glGetPixelMapfv glad_glGetPixelMapfv +GLAD_API_CALL PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +#define glGetPixelMapuiv glad_glGetPixelMapuiv +GLAD_API_CALL PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +#define glGetPixelMapusv glad_glGetPixelMapusv +GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv; +#define glGetPointerv glad_glGetPointerv +GLAD_API_CALL PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +#define glGetPolygonStipple glad_glGetPolygonStipple +GLAD_API_CALL PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB; +#define glGetProgramEnvParameterdvARB glad_glGetProgramEnvParameterdvARB +GLAD_API_CALL PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB; +#define glGetProgramEnvParameterfvARB glad_glGetProgramEnvParameterfvARB +GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +GLAD_API_CALL PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB; +#define glGetProgramLocalParameterdvARB glad_glGetProgramLocalParameterdvARB +GLAD_API_CALL PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB; +#define glGetProgramLocalParameterfvARB glad_glGetProgramLocalParameterfvARB +GLAD_API_CALL PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB; +#define glGetProgramStringARB glad_glGetProgramStringARB +GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +GLAD_API_CALL PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB; +#define glGetProgramivARB glad_glGetProgramivARB +GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; +#define glGetQueryObjecti64v glad_glGetQueryObjecti64v +GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +GLAD_API_CALL PFNGLGETQUERYOBJECTIVARBPROC glad_glGetQueryObjectivARB; +#define glGetQueryObjectivARB glad_glGetQueryObjectivARB +GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; +#define glGetQueryObjectui64v glad_glGetQueryObjectui64v +GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +GLAD_API_CALL PFNGLGETQUERYOBJECTUIVARBPROC glad_glGetQueryObjectuivARB; +#define glGetQueryObjectuivARB glad_glGetQueryObjectuivARB +GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +GLAD_API_CALL PFNGLGETQUERYIVARBPROC glad_glGetQueryivARB; +#define glGetQueryivARB glad_glGetQueryivARB +GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT; +#define glGetRenderbufferParameterivEXT glad_glGetRenderbufferParameterivEXT +GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +GLAD_API_CALL PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB; +#define glGetShaderSourceARB glad_glGetShaderSourceARB +GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +GLAD_API_CALL PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +#define glGetTexEnvfv glad_glGetTexEnvfv +GLAD_API_CALL PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +#define glGetTexEnviv glad_glGetTexEnviv +GLAD_API_CALL PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +#define glGetTexGendv glad_glGetTexGendv +GLAD_API_CALL PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +#define glGetTexGenfv glad_glGetTexGenfv +GLAD_API_CALL PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +#define glGetTexGeniv glad_glGetTexGeniv +GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC glad_glGetTransformFeedbackVaryingEXT; +#define glGetTransformFeedbackVaryingEXT glad_glGetTransformFeedbackVaryingEXT +GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +GLAD_API_CALL PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB; +#define glGetUniformLocationARB glad_glGetUniformLocationARB +GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +GLAD_API_CALL PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB; +#define glGetUniformfvARB glad_glGetUniformfvARB +GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +GLAD_API_CALL PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB; +#define glGetUniformivARB glad_glGetUniformivARB +GLAD_API_CALL PFNGLGETUNIFORMUIVEXTPROC glad_glGetUniformuivEXT; +#define glGetUniformuivEXT glad_glGetUniformuivEXT +GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVEXTPROC glad_glGetVertexAttribIivEXT; +#define glGetVertexAttribIivEXT glad_glGetVertexAttribIivEXT +GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT; +#define glGetVertexAttribIuivEXT glad_glGetVertexAttribIuivEXT +GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB; +#define glGetVertexAttribPointervARB glad_glGetVertexAttribPointervARB +GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +GLAD_API_CALL PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB; +#define glGetVertexAttribdvARB glad_glGetVertexAttribdvARB +GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +GLAD_API_CALL PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB; +#define glGetVertexAttribfvARB glad_glGetVertexAttribfvARB +GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB; +#define glGetVertexAttribivARB glad_glGetVertexAttribivARB +GLAD_API_CALL PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +GLAD_API_CALL PFNGLINDEXMASKPROC glad_glIndexMask; +#define glIndexMask glad_glIndexMask +GLAD_API_CALL PFNGLINDEXPOINTERPROC glad_glIndexPointer; +#define glIndexPointer glad_glIndexPointer +GLAD_API_CALL PFNGLINDEXDPROC glad_glIndexd; +#define glIndexd glad_glIndexd +GLAD_API_CALL PFNGLINDEXDVPROC glad_glIndexdv; +#define glIndexdv glad_glIndexdv +GLAD_API_CALL PFNGLINDEXFPROC glad_glIndexf; +#define glIndexf glad_glIndexf +GLAD_API_CALL PFNGLINDEXFVPROC glad_glIndexfv; +#define glIndexfv glad_glIndexfv +GLAD_API_CALL PFNGLINDEXIPROC glad_glIndexi; +#define glIndexi glad_glIndexi +GLAD_API_CALL PFNGLINDEXIVPROC glad_glIndexiv; +#define glIndexiv glad_glIndexiv +GLAD_API_CALL PFNGLINDEXSPROC glad_glIndexs; +#define glIndexs glad_glIndexs +GLAD_API_CALL PFNGLINDEXSVPROC glad_glIndexsv; +#define glIndexsv glad_glIndexsv +GLAD_API_CALL PFNGLINDEXUBPROC glad_glIndexub; +#define glIndexub glad_glIndexub +GLAD_API_CALL PFNGLINDEXUBVPROC glad_glIndexubv; +#define glIndexubv glad_glIndexubv +GLAD_API_CALL PFNGLINITNAMESPROC glad_glInitNames; +#define glInitNames glad_glInitNames +GLAD_API_CALL PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +#define glInterleavedArrays glad_glInterleavedArrays +GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +GLAD_API_CALL PFNGLISBUFFERARBPROC glad_glIsBufferARB; +#define glIsBufferARB glad_glIsBufferARB +GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +GLAD_API_CALL PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT; +#define glIsFramebufferEXT glad_glIsFramebufferEXT +GLAD_API_CALL PFNGLISLISTPROC glad_glIsList; +#define glIsList glad_glIsList +GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +GLAD_API_CALL PFNGLISPROGRAMARBPROC glad_glIsProgramARB; +#define glIsProgramARB glad_glIsProgramARB +GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +GLAD_API_CALL PFNGLISQUERYARBPROC glad_glIsQueryARB; +#define glIsQueryARB glad_glIsQueryARB +GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +GLAD_API_CALL PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT; +#define glIsRenderbufferEXT glad_glIsRenderbufferEXT +GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +GLAD_API_CALL PFNGLLIGHTMODELFPROC glad_glLightModelf; +#define glLightModelf glad_glLightModelf +GLAD_API_CALL PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +#define glLightModelfv glad_glLightModelfv +GLAD_API_CALL PFNGLLIGHTMODELIPROC glad_glLightModeli; +#define glLightModeli glad_glLightModeli +GLAD_API_CALL PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +#define glLightModeliv glad_glLightModeliv +GLAD_API_CALL PFNGLLIGHTFPROC glad_glLightf; +#define glLightf glad_glLightf +GLAD_API_CALL PFNGLLIGHTFVPROC glad_glLightfv; +#define glLightfv glad_glLightfv +GLAD_API_CALL PFNGLLIGHTIPROC glad_glLighti; +#define glLighti glad_glLighti +GLAD_API_CALL PFNGLLIGHTIVPROC glad_glLightiv; +#define glLightiv glad_glLightiv +GLAD_API_CALL PFNGLLINESTIPPLEPROC glad_glLineStipple; +#define glLineStipple glad_glLineStipple +GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +GLAD_API_CALL PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB; +#define glLinkProgramARB glad_glLinkProgramARB +GLAD_API_CALL PFNGLLISTBASEPROC glad_glListBase; +#define glListBase glad_glListBase +GLAD_API_CALL PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +#define glLoadIdentity glad_glLoadIdentity +GLAD_API_CALL PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +#define glLoadMatrixd glad_glLoadMatrixd +GLAD_API_CALL PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +#define glLoadMatrixf glad_glLoadMatrixf +GLAD_API_CALL PFNGLLOADNAMEPROC glad_glLoadName; +#define glLoadName glad_glLoadName +GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd +GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf +GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +GLAD_API_CALL PFNGLMAP1DPROC glad_glMap1d; +#define glMap1d glad_glMap1d +GLAD_API_CALL PFNGLMAP1FPROC glad_glMap1f; +#define glMap1f glad_glMap1f +GLAD_API_CALL PFNGLMAP2DPROC glad_glMap2d; +#define glMap2d glad_glMap2d +GLAD_API_CALL PFNGLMAP2FPROC glad_glMap2f; +#define glMap2f glad_glMap2f +GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +GLAD_API_CALL PFNGLMAPBUFFERARBPROC glad_glMapBufferARB; +#define glMapBufferARB glad_glMapBufferARB +GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +GLAD_API_CALL PFNGLMAPGRID1DPROC glad_glMapGrid1d; +#define glMapGrid1d glad_glMapGrid1d +GLAD_API_CALL PFNGLMAPGRID1FPROC glad_glMapGrid1f; +#define glMapGrid1f glad_glMapGrid1f +GLAD_API_CALL PFNGLMAPGRID2DPROC glad_glMapGrid2d; +#define glMapGrid2d glad_glMapGrid2d +GLAD_API_CALL PFNGLMAPGRID2FPROC glad_glMapGrid2f; +#define glMapGrid2f glad_glMapGrid2f +GLAD_API_CALL PFNGLMATERIALFPROC glad_glMaterialf; +#define glMaterialf glad_glMaterialf +GLAD_API_CALL PFNGLMATERIALFVPROC glad_glMaterialfv; +#define glMaterialfv glad_glMaterialfv +GLAD_API_CALL PFNGLMATERIALIPROC glad_glMateriali; +#define glMateriali glad_glMateriali +GLAD_API_CALL PFNGLMATERIALIVPROC glad_glMaterialiv; +#define glMaterialiv glad_glMaterialiv +GLAD_API_CALL PFNGLMATRIXMODEPROC glad_glMatrixMode; +#define glMatrixMode glad_glMatrixMode +GLAD_API_CALL PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +#define glMultMatrixd glad_glMultMatrixd +GLAD_API_CALL PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +#define glMultMatrixf glad_glMultMatrixf +GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +#define glMultTransposeMatrixd glad_glMultTransposeMatrixd +GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +#define glMultTransposeMatrixf glad_glMultTransposeMatrixf +GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +GLAD_API_CALL PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +#define glMultiTexCoord1d glad_glMultiTexCoord1d +GLAD_API_CALL PFNGLMULTITEXCOORD1DARBPROC glad_glMultiTexCoord1dARB; +#define glMultiTexCoord1dARB glad_glMultiTexCoord1dARB +GLAD_API_CALL PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +#define glMultiTexCoord1dv glad_glMultiTexCoord1dv +GLAD_API_CALL PFNGLMULTITEXCOORD1DVARBPROC glad_glMultiTexCoord1dvARB; +#define glMultiTexCoord1dvARB glad_glMultiTexCoord1dvARB +GLAD_API_CALL PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +#define glMultiTexCoord1f glad_glMultiTexCoord1f +GLAD_API_CALL PFNGLMULTITEXCOORD1FARBPROC glad_glMultiTexCoord1fARB; +#define glMultiTexCoord1fARB glad_glMultiTexCoord1fARB +GLAD_API_CALL PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +#define glMultiTexCoord1fv glad_glMultiTexCoord1fv +GLAD_API_CALL PFNGLMULTITEXCOORD1FVARBPROC glad_glMultiTexCoord1fvARB; +#define glMultiTexCoord1fvARB glad_glMultiTexCoord1fvARB +GLAD_API_CALL PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +#define glMultiTexCoord1i glad_glMultiTexCoord1i +GLAD_API_CALL PFNGLMULTITEXCOORD1IARBPROC glad_glMultiTexCoord1iARB; +#define glMultiTexCoord1iARB glad_glMultiTexCoord1iARB +GLAD_API_CALL PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +#define glMultiTexCoord1iv glad_glMultiTexCoord1iv +GLAD_API_CALL PFNGLMULTITEXCOORD1IVARBPROC glad_glMultiTexCoord1ivARB; +#define glMultiTexCoord1ivARB glad_glMultiTexCoord1ivARB +GLAD_API_CALL PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +#define glMultiTexCoord1s glad_glMultiTexCoord1s +GLAD_API_CALL PFNGLMULTITEXCOORD1SARBPROC glad_glMultiTexCoord1sARB; +#define glMultiTexCoord1sARB glad_glMultiTexCoord1sARB +GLAD_API_CALL PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +#define glMultiTexCoord1sv glad_glMultiTexCoord1sv +GLAD_API_CALL PFNGLMULTITEXCOORD1SVARBPROC glad_glMultiTexCoord1svARB; +#define glMultiTexCoord1svARB glad_glMultiTexCoord1svARB +GLAD_API_CALL PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +#define glMultiTexCoord2d glad_glMultiTexCoord2d +GLAD_API_CALL PFNGLMULTITEXCOORD2DARBPROC glad_glMultiTexCoord2dARB; +#define glMultiTexCoord2dARB glad_glMultiTexCoord2dARB +GLAD_API_CALL PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +#define glMultiTexCoord2dv glad_glMultiTexCoord2dv +GLAD_API_CALL PFNGLMULTITEXCOORD2DVARBPROC glad_glMultiTexCoord2dvARB; +#define glMultiTexCoord2dvARB glad_glMultiTexCoord2dvARB +GLAD_API_CALL PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +#define glMultiTexCoord2f glad_glMultiTexCoord2f +GLAD_API_CALL PFNGLMULTITEXCOORD2FARBPROC glad_glMultiTexCoord2fARB; +#define glMultiTexCoord2fARB glad_glMultiTexCoord2fARB +GLAD_API_CALL PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +#define glMultiTexCoord2fv glad_glMultiTexCoord2fv +GLAD_API_CALL PFNGLMULTITEXCOORD2FVARBPROC glad_glMultiTexCoord2fvARB; +#define glMultiTexCoord2fvARB glad_glMultiTexCoord2fvARB +GLAD_API_CALL PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +#define glMultiTexCoord2i glad_glMultiTexCoord2i +GLAD_API_CALL PFNGLMULTITEXCOORD2IARBPROC glad_glMultiTexCoord2iARB; +#define glMultiTexCoord2iARB glad_glMultiTexCoord2iARB +GLAD_API_CALL PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +#define glMultiTexCoord2iv glad_glMultiTexCoord2iv +GLAD_API_CALL PFNGLMULTITEXCOORD2IVARBPROC glad_glMultiTexCoord2ivARB; +#define glMultiTexCoord2ivARB glad_glMultiTexCoord2ivARB +GLAD_API_CALL PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +#define glMultiTexCoord2s glad_glMultiTexCoord2s +GLAD_API_CALL PFNGLMULTITEXCOORD2SARBPROC glad_glMultiTexCoord2sARB; +#define glMultiTexCoord2sARB glad_glMultiTexCoord2sARB +GLAD_API_CALL PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +#define glMultiTexCoord2sv glad_glMultiTexCoord2sv +GLAD_API_CALL PFNGLMULTITEXCOORD2SVARBPROC glad_glMultiTexCoord2svARB; +#define glMultiTexCoord2svARB glad_glMultiTexCoord2svARB +GLAD_API_CALL PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +#define glMultiTexCoord3d glad_glMultiTexCoord3d +GLAD_API_CALL PFNGLMULTITEXCOORD3DARBPROC glad_glMultiTexCoord3dARB; +#define glMultiTexCoord3dARB glad_glMultiTexCoord3dARB +GLAD_API_CALL PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +#define glMultiTexCoord3dv glad_glMultiTexCoord3dv +GLAD_API_CALL PFNGLMULTITEXCOORD3DVARBPROC glad_glMultiTexCoord3dvARB; +#define glMultiTexCoord3dvARB glad_glMultiTexCoord3dvARB +GLAD_API_CALL PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +#define glMultiTexCoord3f glad_glMultiTexCoord3f +GLAD_API_CALL PFNGLMULTITEXCOORD3FARBPROC glad_glMultiTexCoord3fARB; +#define glMultiTexCoord3fARB glad_glMultiTexCoord3fARB +GLAD_API_CALL PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +#define glMultiTexCoord3fv glad_glMultiTexCoord3fv +GLAD_API_CALL PFNGLMULTITEXCOORD3FVARBPROC glad_glMultiTexCoord3fvARB; +#define glMultiTexCoord3fvARB glad_glMultiTexCoord3fvARB +GLAD_API_CALL PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +#define glMultiTexCoord3i glad_glMultiTexCoord3i +GLAD_API_CALL PFNGLMULTITEXCOORD3IARBPROC glad_glMultiTexCoord3iARB; +#define glMultiTexCoord3iARB glad_glMultiTexCoord3iARB +GLAD_API_CALL PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +#define glMultiTexCoord3iv glad_glMultiTexCoord3iv +GLAD_API_CALL PFNGLMULTITEXCOORD3IVARBPROC glad_glMultiTexCoord3ivARB; +#define glMultiTexCoord3ivARB glad_glMultiTexCoord3ivARB +GLAD_API_CALL PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +#define glMultiTexCoord3s glad_glMultiTexCoord3s +GLAD_API_CALL PFNGLMULTITEXCOORD3SARBPROC glad_glMultiTexCoord3sARB; +#define glMultiTexCoord3sARB glad_glMultiTexCoord3sARB +GLAD_API_CALL PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +#define glMultiTexCoord3sv glad_glMultiTexCoord3sv +GLAD_API_CALL PFNGLMULTITEXCOORD3SVARBPROC glad_glMultiTexCoord3svARB; +#define glMultiTexCoord3svARB glad_glMultiTexCoord3svARB +GLAD_API_CALL PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +#define glMultiTexCoord4d glad_glMultiTexCoord4d +GLAD_API_CALL PFNGLMULTITEXCOORD4DARBPROC glad_glMultiTexCoord4dARB; +#define glMultiTexCoord4dARB glad_glMultiTexCoord4dARB +GLAD_API_CALL PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +#define glMultiTexCoord4dv glad_glMultiTexCoord4dv +GLAD_API_CALL PFNGLMULTITEXCOORD4DVARBPROC glad_glMultiTexCoord4dvARB; +#define glMultiTexCoord4dvARB glad_glMultiTexCoord4dvARB +GLAD_API_CALL PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +#define glMultiTexCoord4f glad_glMultiTexCoord4f +GLAD_API_CALL PFNGLMULTITEXCOORD4FARBPROC glad_glMultiTexCoord4fARB; +#define glMultiTexCoord4fARB glad_glMultiTexCoord4fARB +GLAD_API_CALL PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +#define glMultiTexCoord4fv glad_glMultiTexCoord4fv +GLAD_API_CALL PFNGLMULTITEXCOORD4FVARBPROC glad_glMultiTexCoord4fvARB; +#define glMultiTexCoord4fvARB glad_glMultiTexCoord4fvARB +GLAD_API_CALL PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +#define glMultiTexCoord4i glad_glMultiTexCoord4i +GLAD_API_CALL PFNGLMULTITEXCOORD4IARBPROC glad_glMultiTexCoord4iARB; +#define glMultiTexCoord4iARB glad_glMultiTexCoord4iARB +GLAD_API_CALL PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +#define glMultiTexCoord4iv glad_glMultiTexCoord4iv +GLAD_API_CALL PFNGLMULTITEXCOORD4IVARBPROC glad_glMultiTexCoord4ivARB; +#define glMultiTexCoord4ivARB glad_glMultiTexCoord4ivARB +GLAD_API_CALL PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +#define glMultiTexCoord4s glad_glMultiTexCoord4s +GLAD_API_CALL PFNGLMULTITEXCOORD4SARBPROC glad_glMultiTexCoord4sARB; +#define glMultiTexCoord4sARB glad_glMultiTexCoord4sARB +GLAD_API_CALL PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +#define glMultiTexCoord4sv glad_glMultiTexCoord4sv +GLAD_API_CALL PFNGLMULTITEXCOORD4SVARBPROC glad_glMultiTexCoord4svARB; +#define glMultiTexCoord4svARB glad_glMultiTexCoord4svARB +GLAD_API_CALL PFNGLNEWLISTPROC glad_glNewList; +#define glNewList glad_glNewList +GLAD_API_CALL PFNGLNORMAL3BPROC glad_glNormal3b; +#define glNormal3b glad_glNormal3b +GLAD_API_CALL PFNGLNORMAL3BVPROC glad_glNormal3bv; +#define glNormal3bv glad_glNormal3bv +GLAD_API_CALL PFNGLNORMAL3DPROC glad_glNormal3d; +#define glNormal3d glad_glNormal3d +GLAD_API_CALL PFNGLNORMAL3DVPROC glad_glNormal3dv; +#define glNormal3dv glad_glNormal3dv +GLAD_API_CALL PFNGLNORMAL3FPROC glad_glNormal3f; +#define glNormal3f glad_glNormal3f +GLAD_API_CALL PFNGLNORMAL3FVPROC glad_glNormal3fv; +#define glNormal3fv glad_glNormal3fv +GLAD_API_CALL PFNGLNORMAL3IPROC glad_glNormal3i; +#define glNormal3i glad_glNormal3i +GLAD_API_CALL PFNGLNORMAL3IVPROC glad_glNormal3iv; +#define glNormal3iv glad_glNormal3iv +GLAD_API_CALL PFNGLNORMAL3SPROC glad_glNormal3s; +#define glNormal3s glad_glNormal3s +GLAD_API_CALL PFNGLNORMAL3SVPROC glad_glNormal3sv; +#define glNormal3sv glad_glNormal3sv +GLAD_API_CALL PFNGLNORMALPOINTERPROC glad_glNormalPointer; +#define glNormalPointer glad_glNormalPointer +GLAD_API_CALL PFNGLOBJECTLABELPROC glad_glObjectLabel; +#define glObjectLabel glad_glObjectLabel +GLAD_API_CALL PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; +#define glObjectPtrLabel glad_glObjectPtrLabel +GLAD_API_CALL PFNGLORTHOPROC glad_glOrtho; +#define glOrtho glad_glOrtho +GLAD_API_CALL PFNGLPASSTHROUGHPROC glad_glPassThrough; +#define glPassThrough glad_glPassThrough +GLAD_API_CALL PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +#define glPixelMapfv glad_glPixelMapfv +GLAD_API_CALL PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +#define glPixelMapuiv glad_glPixelMapuiv +GLAD_API_CALL PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +#define glPixelMapusv glad_glPixelMapusv +GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +GLAD_API_CALL PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +#define glPixelTransferf glad_glPixelTransferf +GLAD_API_CALL PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +#define glPixelTransferi glad_glPixelTransferi +GLAD_API_CALL PFNGLPIXELZOOMPROC glad_glPixelZoom; +#define glPixelZoom glad_glPixelZoom +GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +GLAD_API_CALL PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +#define glPolygonStipple glad_glPolygonStipple +GLAD_API_CALL PFNGLPOPATTRIBPROC glad_glPopAttrib; +#define glPopAttrib glad_glPopAttrib +GLAD_API_CALL PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +#define glPopClientAttrib glad_glPopClientAttrib +GLAD_API_CALL PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; +#define glPopDebugGroup glad_glPopDebugGroup +GLAD_API_CALL PFNGLPOPMATRIXPROC glad_glPopMatrix; +#define glPopMatrix glad_glPopMatrix +GLAD_API_CALL PFNGLPOPNAMEPROC glad_glPopName; +#define glPopName glad_glPopName +GLAD_API_CALL PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +#define glPrioritizeTextures glad_glPrioritizeTextures +GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB; +#define glProgramEnvParameter4dARB glad_glProgramEnvParameter4dARB +GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB; +#define glProgramEnvParameter4dvARB glad_glProgramEnvParameter4dvARB +GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB; +#define glProgramEnvParameter4fARB glad_glProgramEnvParameter4fARB +GLAD_API_CALL PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB; +#define glProgramEnvParameter4fvARB glad_glProgramEnvParameter4fvARB +GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB; +#define glProgramLocalParameter4dARB glad_glProgramLocalParameter4dARB +GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB; +#define glProgramLocalParameter4dvARB glad_glProgramLocalParameter4dvARB +GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB; +#define glProgramLocalParameter4fARB glad_glProgramLocalParameter4fARB +GLAD_API_CALL PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB; +#define glProgramLocalParameter4fvARB glad_glProgramLocalParameter4fvARB +GLAD_API_CALL PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB; +#define glProgramParameteriARB glad_glProgramParameteriARB +GLAD_API_CALL PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB; +#define glProgramStringARB glad_glProgramStringARB +GLAD_API_CALL PFNGLPUSHATTRIBPROC glad_glPushAttrib; +#define glPushAttrib glad_glPushAttrib +GLAD_API_CALL PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +#define glPushClientAttrib glad_glPushClientAttrib +GLAD_API_CALL PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; +#define glPushDebugGroup glad_glPushDebugGroup +GLAD_API_CALL PFNGLPUSHMATRIXPROC glad_glPushMatrix; +#define glPushMatrix glad_glPushMatrix +GLAD_API_CALL PFNGLPUSHNAMEPROC glad_glPushName; +#define glPushName glad_glPushName +GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter; +#define glQueryCounter glad_glQueryCounter +GLAD_API_CALL PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +#define glRasterPos2d glad_glRasterPos2d +GLAD_API_CALL PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +#define glRasterPos2dv glad_glRasterPos2dv +GLAD_API_CALL PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +#define glRasterPos2f glad_glRasterPos2f +GLAD_API_CALL PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +#define glRasterPos2fv glad_glRasterPos2fv +GLAD_API_CALL PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +#define glRasterPos2i glad_glRasterPos2i +GLAD_API_CALL PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +#define glRasterPos2iv glad_glRasterPos2iv +GLAD_API_CALL PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +#define glRasterPos2s glad_glRasterPos2s +GLAD_API_CALL PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +#define glRasterPos2sv glad_glRasterPos2sv +GLAD_API_CALL PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +#define glRasterPos3d glad_glRasterPos3d +GLAD_API_CALL PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +#define glRasterPos3dv glad_glRasterPos3dv +GLAD_API_CALL PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +#define glRasterPos3f glad_glRasterPos3f +GLAD_API_CALL PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +#define glRasterPos3fv glad_glRasterPos3fv +GLAD_API_CALL PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +#define glRasterPos3i glad_glRasterPos3i +GLAD_API_CALL PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +#define glRasterPos3iv glad_glRasterPos3iv +GLAD_API_CALL PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +#define glRasterPos3s glad_glRasterPos3s +GLAD_API_CALL PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +#define glRasterPos3sv glad_glRasterPos3sv +GLAD_API_CALL PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +#define glRasterPos4d glad_glRasterPos4d +GLAD_API_CALL PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +#define glRasterPos4dv glad_glRasterPos4dv +GLAD_API_CALL PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +#define glRasterPos4f glad_glRasterPos4f +GLAD_API_CALL PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +#define glRasterPos4fv glad_glRasterPos4fv +GLAD_API_CALL PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +#define glRasterPos4i glad_glRasterPos4i +GLAD_API_CALL PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +#define glRasterPos4iv glad_glRasterPos4iv +GLAD_API_CALL PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +#define glRasterPos4s glad_glRasterPos4s +GLAD_API_CALL PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +#define glRasterPos4sv glad_glRasterPos4sv +GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +GLAD_API_CALL PFNGLRECTDPROC glad_glRectd; +#define glRectd glad_glRectd +GLAD_API_CALL PFNGLRECTDVPROC glad_glRectdv; +#define glRectdv glad_glRectdv +GLAD_API_CALL PFNGLRECTFPROC glad_glRectf; +#define glRectf glad_glRectf +GLAD_API_CALL PFNGLRECTFVPROC glad_glRectfv; +#define glRectfv glad_glRectfv +GLAD_API_CALL PFNGLRECTIPROC glad_glRecti; +#define glRecti glad_glRecti +GLAD_API_CALL PFNGLRECTIVPROC glad_glRectiv; +#define glRectiv glad_glRectiv +GLAD_API_CALL PFNGLRECTSPROC glad_glRects; +#define glRects glad_glRects +GLAD_API_CALL PFNGLRECTSVPROC glad_glRectsv; +#define glRectsv glad_glRectsv +GLAD_API_CALL PFNGLRENDERMODEPROC glad_glRenderMode; +#define glRenderMode glad_glRenderMode +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT; +#define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; +#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT +GLAD_API_CALL PFNGLROTATEDPROC glad_glRotated; +#define glRotated glad_glRotated +GLAD_API_CALL PFNGLROTATEFPROC glad_glRotatef; +#define glRotatef glad_glRotatef +GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +GLAD_API_CALL PFNGLSCALEDPROC glad_glScaled; +#define glScaled glad_glScaled +GLAD_API_CALL PFNGLSCALEFPROC glad_glScalef; +#define glScalef glad_glScalef +GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +GLAD_API_CALL PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +#define glSecondaryColor3b glad_glSecondaryColor3b +GLAD_API_CALL PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +#define glSecondaryColor3bv glad_glSecondaryColor3bv +GLAD_API_CALL PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +#define glSecondaryColor3d glad_glSecondaryColor3d +GLAD_API_CALL PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +#define glSecondaryColor3dv glad_glSecondaryColor3dv +GLAD_API_CALL PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +#define glSecondaryColor3f glad_glSecondaryColor3f +GLAD_API_CALL PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +#define glSecondaryColor3fv glad_glSecondaryColor3fv +GLAD_API_CALL PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +#define glSecondaryColor3i glad_glSecondaryColor3i +GLAD_API_CALL PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +#define glSecondaryColor3iv glad_glSecondaryColor3iv +GLAD_API_CALL PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +#define glSecondaryColor3s glad_glSecondaryColor3s +GLAD_API_CALL PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +#define glSecondaryColor3sv glad_glSecondaryColor3sv +GLAD_API_CALL PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +#define glSecondaryColor3ub glad_glSecondaryColor3ub +GLAD_API_CALL PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +#define glSecondaryColor3ubv glad_glSecondaryColor3ubv +GLAD_API_CALL PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +#define glSecondaryColor3ui glad_glSecondaryColor3ui +GLAD_API_CALL PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +#define glSecondaryColor3uiv glad_glSecondaryColor3uiv +GLAD_API_CALL PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +#define glSecondaryColor3us glad_glSecondaryColor3us +GLAD_API_CALL PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +#define glSecondaryColor3usv glad_glSecondaryColor3usv +GLAD_API_CALL PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +#define glSecondaryColorPointer glad_glSecondaryColorPointer +GLAD_API_CALL PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +#define glSelectBuffer glad_glSelectBuffer +GLAD_API_CALL PFNGLSHADEMODELPROC glad_glShadeModel; +#define glShadeModel glad_glShadeModel +GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +GLAD_API_CALL PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB; +#define glShaderSourceARB glad_glShaderSourceARB +GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +GLAD_API_CALL PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +#define glTexCoord1d glad_glTexCoord1d +GLAD_API_CALL PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +#define glTexCoord1dv glad_glTexCoord1dv +GLAD_API_CALL PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +#define glTexCoord1f glad_glTexCoord1f +GLAD_API_CALL PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +#define glTexCoord1fv glad_glTexCoord1fv +GLAD_API_CALL PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +#define glTexCoord1i glad_glTexCoord1i +GLAD_API_CALL PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +#define glTexCoord1iv glad_glTexCoord1iv +GLAD_API_CALL PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +#define glTexCoord1s glad_glTexCoord1s +GLAD_API_CALL PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +#define glTexCoord1sv glad_glTexCoord1sv +GLAD_API_CALL PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +#define glTexCoord2d glad_glTexCoord2d +GLAD_API_CALL PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +#define glTexCoord2dv glad_glTexCoord2dv +GLAD_API_CALL PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +#define glTexCoord2f glad_glTexCoord2f +GLAD_API_CALL PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +#define glTexCoord2fv glad_glTexCoord2fv +GLAD_API_CALL PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +#define glTexCoord2i glad_glTexCoord2i +GLAD_API_CALL PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +#define glTexCoord2iv glad_glTexCoord2iv +GLAD_API_CALL PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +#define glTexCoord2s glad_glTexCoord2s +GLAD_API_CALL PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +#define glTexCoord2sv glad_glTexCoord2sv +GLAD_API_CALL PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +#define glTexCoord3d glad_glTexCoord3d +GLAD_API_CALL PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +#define glTexCoord3dv glad_glTexCoord3dv +GLAD_API_CALL PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +#define glTexCoord3f glad_glTexCoord3f +GLAD_API_CALL PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +#define glTexCoord3fv glad_glTexCoord3fv +GLAD_API_CALL PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +#define glTexCoord3i glad_glTexCoord3i +GLAD_API_CALL PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +#define glTexCoord3iv glad_glTexCoord3iv +GLAD_API_CALL PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +#define glTexCoord3s glad_glTexCoord3s +GLAD_API_CALL PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +#define glTexCoord3sv glad_glTexCoord3sv +GLAD_API_CALL PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +#define glTexCoord4d glad_glTexCoord4d +GLAD_API_CALL PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +#define glTexCoord4dv glad_glTexCoord4dv +GLAD_API_CALL PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +#define glTexCoord4f glad_glTexCoord4f +GLAD_API_CALL PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +#define glTexCoord4fv glad_glTexCoord4fv +GLAD_API_CALL PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +#define glTexCoord4i glad_glTexCoord4i +GLAD_API_CALL PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +#define glTexCoord4iv glad_glTexCoord4iv +GLAD_API_CALL PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +#define glTexCoord4s glad_glTexCoord4s +GLAD_API_CALL PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +#define glTexCoord4sv glad_glTexCoord4sv +GLAD_API_CALL PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +#define glTexCoordPointer glad_glTexCoordPointer +GLAD_API_CALL PFNGLTEXENVFPROC glad_glTexEnvf; +#define glTexEnvf glad_glTexEnvf +GLAD_API_CALL PFNGLTEXENVFVPROC glad_glTexEnvfv; +#define glTexEnvfv glad_glTexEnvfv +GLAD_API_CALL PFNGLTEXENVIPROC glad_glTexEnvi; +#define glTexEnvi glad_glTexEnvi +GLAD_API_CALL PFNGLTEXENVIVPROC glad_glTexEnviv; +#define glTexEnviv glad_glTexEnviv +GLAD_API_CALL PFNGLTEXGENDPROC glad_glTexGend; +#define glTexGend glad_glTexGend +GLAD_API_CALL PFNGLTEXGENDVPROC glad_glTexGendv; +#define glTexGendv glad_glTexGendv +GLAD_API_CALL PFNGLTEXGENFPROC glad_glTexGenf; +#define glTexGenf glad_glTexGenf +GLAD_API_CALL PFNGLTEXGENFVPROC glad_glTexGenfv; +#define glTexGenfv glad_glTexGenfv +GLAD_API_CALL PFNGLTEXGENIPROC glad_glTexGeni; +#define glTexGeni glad_glTexGeni +GLAD_API_CALL PFNGLTEXGENIVPROC glad_glTexGeniv; +#define glTexGeniv glad_glTexGeniv +GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC glad_glTransformFeedbackVaryingsEXT; +#define glTransformFeedbackVaryingsEXT glad_glTransformFeedbackVaryingsEXT +GLAD_API_CALL PFNGLTRANSLATEDPROC glad_glTranslated; +#define glTranslated glad_glTranslated +GLAD_API_CALL PFNGLTRANSLATEFPROC glad_glTranslatef; +#define glTranslatef glad_glTranslatef +GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +GLAD_API_CALL PFNGLUNIFORM1FARBPROC glad_glUniform1fARB; +#define glUniform1fARB glad_glUniform1fARB +GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +GLAD_API_CALL PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB; +#define glUniform1fvARB glad_glUniform1fvARB +GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +GLAD_API_CALL PFNGLUNIFORM1IARBPROC glad_glUniform1iARB; +#define glUniform1iARB glad_glUniform1iARB +GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +GLAD_API_CALL PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB; +#define glUniform1ivARB glad_glUniform1ivARB +GLAD_API_CALL PFNGLUNIFORM1UIEXTPROC glad_glUniform1uiEXT; +#define glUniform1uiEXT glad_glUniform1uiEXT +GLAD_API_CALL PFNGLUNIFORM1UIVEXTPROC glad_glUniform1uivEXT; +#define glUniform1uivEXT glad_glUniform1uivEXT +GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +GLAD_API_CALL PFNGLUNIFORM2FARBPROC glad_glUniform2fARB; +#define glUniform2fARB glad_glUniform2fARB +GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +GLAD_API_CALL PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB; +#define glUniform2fvARB glad_glUniform2fvARB +GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +GLAD_API_CALL PFNGLUNIFORM2IARBPROC glad_glUniform2iARB; +#define glUniform2iARB glad_glUniform2iARB +GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +GLAD_API_CALL PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB; +#define glUniform2ivARB glad_glUniform2ivARB +GLAD_API_CALL PFNGLUNIFORM2UIEXTPROC glad_glUniform2uiEXT; +#define glUniform2uiEXT glad_glUniform2uiEXT +GLAD_API_CALL PFNGLUNIFORM2UIVEXTPROC glad_glUniform2uivEXT; +#define glUniform2uivEXT glad_glUniform2uivEXT +GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +GLAD_API_CALL PFNGLUNIFORM3FARBPROC glad_glUniform3fARB; +#define glUniform3fARB glad_glUniform3fARB +GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +GLAD_API_CALL PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB; +#define glUniform3fvARB glad_glUniform3fvARB +GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +GLAD_API_CALL PFNGLUNIFORM3IARBPROC glad_glUniform3iARB; +#define glUniform3iARB glad_glUniform3iARB +GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +GLAD_API_CALL PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB; +#define glUniform3ivARB glad_glUniform3ivARB +GLAD_API_CALL PFNGLUNIFORM3UIEXTPROC glad_glUniform3uiEXT; +#define glUniform3uiEXT glad_glUniform3uiEXT +GLAD_API_CALL PFNGLUNIFORM3UIVEXTPROC glad_glUniform3uivEXT; +#define glUniform3uivEXT glad_glUniform3uivEXT +GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +GLAD_API_CALL PFNGLUNIFORM4FARBPROC glad_glUniform4fARB; +#define glUniform4fARB glad_glUniform4fARB +GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +GLAD_API_CALL PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB; +#define glUniform4fvARB glad_glUniform4fvARB +GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +GLAD_API_CALL PFNGLUNIFORM4IARBPROC glad_glUniform4iARB; +#define glUniform4iARB glad_glUniform4iARB +GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +GLAD_API_CALL PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB; +#define glUniform4ivARB glad_glUniform4ivARB +GLAD_API_CALL PFNGLUNIFORM4UIEXTPROC glad_glUniform4uiEXT; +#define glUniform4uiEXT glad_glUniform4uiEXT +GLAD_API_CALL PFNGLUNIFORM4UIVEXTPROC glad_glUniform4uivEXT; +#define glUniform4uivEXT glad_glUniform4uivEXT +GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB; +#define glUniformMatrix2fvARB glad_glUniformMatrix2fvARB +GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB; +#define glUniformMatrix3fvARB glad_glUniformMatrix3fvARB +GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB; +#define glUniformMatrix4fvARB glad_glUniformMatrix4fvARB +GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +GLAD_API_CALL PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB; +#define glUnmapBufferARB glad_glUnmapBufferARB +GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +GLAD_API_CALL PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB; +#define glUseProgramObjectARB glad_glUseProgramObjectARB +GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +GLAD_API_CALL PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB; +#define glValidateProgramARB glad_glValidateProgramARB +GLAD_API_CALL PFNGLVERTEX2DPROC glad_glVertex2d; +#define glVertex2d glad_glVertex2d +GLAD_API_CALL PFNGLVERTEX2DVPROC glad_glVertex2dv; +#define glVertex2dv glad_glVertex2dv +GLAD_API_CALL PFNGLVERTEX2FPROC glad_glVertex2f; +#define glVertex2f glad_glVertex2f +GLAD_API_CALL PFNGLVERTEX2FVPROC glad_glVertex2fv; +#define glVertex2fv glad_glVertex2fv +GLAD_API_CALL PFNGLVERTEX2IPROC glad_glVertex2i; +#define glVertex2i glad_glVertex2i +GLAD_API_CALL PFNGLVERTEX2IVPROC glad_glVertex2iv; +#define glVertex2iv glad_glVertex2iv +GLAD_API_CALL PFNGLVERTEX2SPROC glad_glVertex2s; +#define glVertex2s glad_glVertex2s +GLAD_API_CALL PFNGLVERTEX2SVPROC glad_glVertex2sv; +#define glVertex2sv glad_glVertex2sv +GLAD_API_CALL PFNGLVERTEX3DPROC glad_glVertex3d; +#define glVertex3d glad_glVertex3d +GLAD_API_CALL PFNGLVERTEX3DVPROC glad_glVertex3dv; +#define glVertex3dv glad_glVertex3dv +GLAD_API_CALL PFNGLVERTEX3FPROC glad_glVertex3f; +#define glVertex3f glad_glVertex3f +GLAD_API_CALL PFNGLVERTEX3FVPROC glad_glVertex3fv; +#define glVertex3fv glad_glVertex3fv +GLAD_API_CALL PFNGLVERTEX3IPROC glad_glVertex3i; +#define glVertex3i glad_glVertex3i +GLAD_API_CALL PFNGLVERTEX3IVPROC glad_glVertex3iv; +#define glVertex3iv glad_glVertex3iv +GLAD_API_CALL PFNGLVERTEX3SPROC glad_glVertex3s; +#define glVertex3s glad_glVertex3s +GLAD_API_CALL PFNGLVERTEX3SVPROC glad_glVertex3sv; +#define glVertex3sv glad_glVertex3sv +GLAD_API_CALL PFNGLVERTEX4DPROC glad_glVertex4d; +#define glVertex4d glad_glVertex4d +GLAD_API_CALL PFNGLVERTEX4DVPROC glad_glVertex4dv; +#define glVertex4dv glad_glVertex4dv +GLAD_API_CALL PFNGLVERTEX4FPROC glad_glVertex4f; +#define glVertex4f glad_glVertex4f +GLAD_API_CALL PFNGLVERTEX4FVPROC glad_glVertex4fv; +#define glVertex4fv glad_glVertex4fv +GLAD_API_CALL PFNGLVERTEX4IPROC glad_glVertex4i; +#define glVertex4i glad_glVertex4i +GLAD_API_CALL PFNGLVERTEX4IVPROC glad_glVertex4iv; +#define glVertex4iv glad_glVertex4iv +GLAD_API_CALL PFNGLVERTEX4SPROC glad_glVertex4s; +#define glVertex4s glad_glVertex4s +GLAD_API_CALL PFNGLVERTEX4SVPROC glad_glVertex4sv; +#define glVertex4sv glad_glVertex4sv +GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +GLAD_API_CALL PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB; +#define glVertexAttrib1dARB glad_glVertexAttrib1dARB +GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +GLAD_API_CALL PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB; +#define glVertexAttrib1dvARB glad_glVertexAttrib1dvARB +GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +GLAD_API_CALL PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB; +#define glVertexAttrib1fARB glad_glVertexAttrib1fARB +GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +GLAD_API_CALL PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB; +#define glVertexAttrib1fvARB glad_glVertexAttrib1fvARB +GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +GLAD_API_CALL PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB; +#define glVertexAttrib1sARB glad_glVertexAttrib1sARB +GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +GLAD_API_CALL PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB; +#define glVertexAttrib1svARB glad_glVertexAttrib1svARB +GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +GLAD_API_CALL PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB; +#define glVertexAttrib2dARB glad_glVertexAttrib2dARB +GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +GLAD_API_CALL PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB; +#define glVertexAttrib2dvARB glad_glVertexAttrib2dvARB +GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +GLAD_API_CALL PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB; +#define glVertexAttrib2fARB glad_glVertexAttrib2fARB +GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +GLAD_API_CALL PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB; +#define glVertexAttrib2fvARB glad_glVertexAttrib2fvARB +GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +GLAD_API_CALL PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB; +#define glVertexAttrib2sARB glad_glVertexAttrib2sARB +GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +GLAD_API_CALL PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB; +#define glVertexAttrib2svARB glad_glVertexAttrib2svARB +GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +GLAD_API_CALL PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB; +#define glVertexAttrib3dARB glad_glVertexAttrib3dARB +GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +GLAD_API_CALL PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB; +#define glVertexAttrib3dvARB glad_glVertexAttrib3dvARB +GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +GLAD_API_CALL PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB; +#define glVertexAttrib3fARB glad_glVertexAttrib3fARB +GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +GLAD_API_CALL PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB; +#define glVertexAttrib3fvARB glad_glVertexAttrib3fvARB +GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +GLAD_API_CALL PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB; +#define glVertexAttrib3sARB glad_glVertexAttrib3sARB +GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +GLAD_API_CALL PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB; +#define glVertexAttrib3svARB glad_glVertexAttrib3svARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +GLAD_API_CALL PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB; +#define glVertexAttrib4NbvARB glad_glVertexAttrib4NbvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +GLAD_API_CALL PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB; +#define glVertexAttrib4NivARB glad_glVertexAttrib4NivARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +GLAD_API_CALL PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB; +#define glVertexAttrib4NsvARB glad_glVertexAttrib4NsvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +GLAD_API_CALL PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB; +#define glVertexAttrib4NubARB glad_glVertexAttrib4NubARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB; +#define glVertexAttrib4NubvARB glad_glVertexAttrib4NubvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB; +#define glVertexAttrib4NuivARB glad_glVertexAttrib4NuivARB +GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB; +#define glVertexAttrib4NusvARB glad_glVertexAttrib4NusvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +GLAD_API_CALL PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB; +#define glVertexAttrib4bvARB glad_glVertexAttrib4bvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +GLAD_API_CALL PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB; +#define glVertexAttrib4dARB glad_glVertexAttrib4dARB +GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +GLAD_API_CALL PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB; +#define glVertexAttrib4dvARB glad_glVertexAttrib4dvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +GLAD_API_CALL PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB; +#define glVertexAttrib4fARB glad_glVertexAttrib4fARB +GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +GLAD_API_CALL PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB; +#define glVertexAttrib4fvARB glad_glVertexAttrib4fvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +GLAD_API_CALL PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB; +#define glVertexAttrib4ivARB glad_glVertexAttrib4ivARB +GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +GLAD_API_CALL PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB; +#define glVertexAttrib4sARB glad_glVertexAttrib4sARB +GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +GLAD_API_CALL PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB; +#define glVertexAttrib4svARB glad_glVertexAttrib4svARB +GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +GLAD_API_CALL PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB; +#define glVertexAttrib4ubvARB glad_glVertexAttrib4ubvARB +GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +GLAD_API_CALL PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB; +#define glVertexAttrib4uivARB glad_glVertexAttrib4uivARB +GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +GLAD_API_CALL PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB; +#define glVertexAttrib4usvARB glad_glVertexAttrib4usvARB +GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB; +#define glVertexAttribDivisorARB glad_glVertexAttribDivisorARB +GLAD_API_CALL PFNGLVERTEXATTRIBI1IEXTPROC glad_glVertexAttribI1iEXT; +#define glVertexAttribI1iEXT glad_glVertexAttribI1iEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI1IVEXTPROC glad_glVertexAttribI1ivEXT; +#define glVertexAttribI1ivEXT glad_glVertexAttribI1ivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI1UIEXTPROC glad_glVertexAttribI1uiEXT; +#define glVertexAttribI1uiEXT glad_glVertexAttribI1uiEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVEXTPROC glad_glVertexAttribI1uivEXT; +#define glVertexAttribI1uivEXT glad_glVertexAttribI1uivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI2IEXTPROC glad_glVertexAttribI2iEXT; +#define glVertexAttribI2iEXT glad_glVertexAttribI2iEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI2IVEXTPROC glad_glVertexAttribI2ivEXT; +#define glVertexAttribI2ivEXT glad_glVertexAttribI2ivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI2UIEXTPROC glad_glVertexAttribI2uiEXT; +#define glVertexAttribI2uiEXT glad_glVertexAttribI2uiEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVEXTPROC glad_glVertexAttribI2uivEXT; +#define glVertexAttribI2uivEXT glad_glVertexAttribI2uivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI3IEXTPROC glad_glVertexAttribI3iEXT; +#define glVertexAttribI3iEXT glad_glVertexAttribI3iEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI3IVEXTPROC glad_glVertexAttribI3ivEXT; +#define glVertexAttribI3ivEXT glad_glVertexAttribI3ivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI3UIEXTPROC glad_glVertexAttribI3uiEXT; +#define glVertexAttribI3uiEXT glad_glVertexAttribI3uiEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVEXTPROC glad_glVertexAttribI3uivEXT; +#define glVertexAttribI3uivEXT glad_glVertexAttribI3uivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4BVEXTPROC glad_glVertexAttribI4bvEXT; +#define glVertexAttribI4bvEXT glad_glVertexAttribI4bvEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4IEXTPROC glad_glVertexAttribI4iEXT; +#define glVertexAttribI4iEXT glad_glVertexAttribI4iEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4IVEXTPROC glad_glVertexAttribI4ivEXT; +#define glVertexAttribI4ivEXT glad_glVertexAttribI4ivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4SVEXTPROC glad_glVertexAttribI4svEXT; +#define glVertexAttribI4svEXT glad_glVertexAttribI4svEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVEXTPROC glad_glVertexAttribI4ubvEXT; +#define glVertexAttribI4ubvEXT glad_glVertexAttribI4ubvEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4UIEXTPROC glad_glVertexAttribI4uiEXT; +#define glVertexAttribI4uiEXT glad_glVertexAttribI4uiEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVEXTPROC glad_glVertexAttribI4uivEXT; +#define glVertexAttribI4uivEXT glad_glVertexAttribI4uivEXT +GLAD_API_CALL PFNGLVERTEXATTRIBI4USVEXTPROC glad_glVertexAttribI4usvEXT; +#define glVertexAttribI4usvEXT glad_glVertexAttribI4usvEXT +GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTEREXTPROC glad_glVertexAttribIPointerEXT; +#define glVertexAttribIPointerEXT glad_glVertexAttribIPointerEXT +GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB; +#define glVertexAttribPointerARB glad_glVertexAttribPointerARB +GLAD_API_CALL PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +#define glVertexPointer glad_glVertexPointer +GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +GLAD_API_CALL PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +#define glWindowPos2d glad_glWindowPos2d +GLAD_API_CALL PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +#define glWindowPos2dv glad_glWindowPos2dv +GLAD_API_CALL PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +#define glWindowPos2f glad_glWindowPos2f +GLAD_API_CALL PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +#define glWindowPos2fv glad_glWindowPos2fv +GLAD_API_CALL PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +#define glWindowPos2i glad_glWindowPos2i +GLAD_API_CALL PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +#define glWindowPos2iv glad_glWindowPos2iv +GLAD_API_CALL PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +#define glWindowPos2s glad_glWindowPos2s +GLAD_API_CALL PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +#define glWindowPos2sv glad_glWindowPos2sv +GLAD_API_CALL PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +#define glWindowPos3d glad_glWindowPos3d +GLAD_API_CALL PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +#define glWindowPos3dv glad_glWindowPos3dv +GLAD_API_CALL PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +#define glWindowPos3f glad_glWindowPos3f +GLAD_API_CALL PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +#define glWindowPos3fv glad_glWindowPos3fv +GLAD_API_CALL PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +#define glWindowPos3i glad_glWindowPos3i +GLAD_API_CALL PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +#define glWindowPos3iv glad_glWindowPos3iv +GLAD_API_CALL PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +#define glWindowPos3s glad_glWindowPos3s +GLAD_API_CALL PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +#define glWindowPos3sv glad_glWindowPos3sv + + + + + +GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadGL( GLADloadfunc load); + + + +#ifdef __cplusplus +} +#endif +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/include/glad/glx.h 0ad-0.0.26/libraries/source/glad/include/glad/glx.h --- 0ad-0.0.25b/libraries/source/glad/include/glad/glx.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/glad/glx.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,585 @@ +/** + * Loader generated by glad 2.0.0-beta on Tue Mar 29 08:49:06 2022 + * + * Generator: C/C++ + * Specification: glx + * Extensions: 2 + * + * APIs: + * - glx=1.4 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False + * - MX = False + * - MX_GLOBAL = False + * - ON_DEMAND = False + * + * Commandline: + * --api='glx=1.4' --extensions='GLX_MESA_query_renderer,GLX_SGI_swap_control' c + * + * Online: + * http://glad.sh/#api=glx%3D1.4&extensions=GLX_MESA_query_renderer%2CGLX_SGI_swap_control&generator=c&options= + * + */ + +#ifndef GLAD_GLX_H_ +#define GLAD_GLX_H_ + +#ifdef GLX_H + #error GLX header already included (API: glx), remove previous include! +#endif +#define GLX_H 1 + + +#include +#include +#include + +#include + +#define GLAD_GLX + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.0-beta" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define GLX_ACCUM_ALPHA_SIZE 17 +#define GLX_ACCUM_BLUE_SIZE 16 +#define GLX_ACCUM_BUFFER_BIT 0x00000080 +#define GLX_ACCUM_GREEN_SIZE 15 +#define GLX_ACCUM_RED_SIZE 14 +#define GLX_ALPHA_SIZE 11 +#define GLX_AUX_BUFFERS 7 +#define GLX_AUX_BUFFERS_BIT 0x00000010 +#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 +#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 +#define GLX_BAD_ATTRIBUTE 2 +#define GLX_BAD_CONTEXT 5 +#define GLX_BAD_ENUM 7 +#define GLX_BAD_SCREEN 1 +#define GLX_BAD_VALUE 6 +#define GLX_BAD_VISUAL 4 +#define GLX_BLUE_SIZE 10 +#define GLX_BUFFER_SIZE 2 +#define GLX_BufferSwapComplete 1 +#define GLX_COLOR_INDEX_BIT 0x00000002 +#define GLX_COLOR_INDEX_TYPE 0x8015 +#define GLX_CONFIG_CAVEAT 0x20 +#define GLX_DAMAGED 0x8020 +#define GLX_DEPTH_BUFFER_BIT 0x00000020 +#define GLX_DEPTH_SIZE 12 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_DONT_CARE 0xFFFFFFFF +#define GLX_DOUBLEBUFFER 5 +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_EVENT_MASK 0x801F +#define GLX_EXTENSIONS 0x3 +#define GLX_EXTENSION_NAME "GLX" +#define GLX_FBCONFIG_ID 0x8013 +#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 +#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 +#define GLX_GRAY_SCALE 0x8006 +#define GLX_GREEN_SIZE 9 +#define GLX_HEIGHT 0x801E +#define GLX_LARGEST_PBUFFER 0x801C +#define GLX_LEVEL 3 +#define GLX_MAX_PBUFFER_HEIGHT 0x8017 +#define GLX_MAX_PBUFFER_PIXELS 0x8018 +#define GLX_MAX_PBUFFER_WIDTH 0x8016 +#define GLX_NONE 0x8000 +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_NO_EXTENSION 3 +#define GLX_PBUFFER 0x8023 +#define GLX_PBUFFER_BIT 0x00000004 +#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 +#define GLX_PBUFFER_HEIGHT 0x8040 +#define GLX_PBUFFER_WIDTH 0x8041 +#define GLX_PIXMAP_BIT 0x00000002 +#define GLX_PRESERVED_CONTENTS 0x801B +#define GLX_PSEUDO_COLOR 0x8004 +#define GLX_PbufferClobber 0 +#define GLX_RED_SIZE 8 +#define GLX_RENDERER_ACCELERATED_MESA 0x8186 +#define GLX_RENDERER_DEVICE_ID_MESA 0x8184 +#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B +#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A +#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D +#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C +#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 +#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 +#define GLX_RENDERER_VENDOR_ID_MESA 0x8183 +#define GLX_RENDERER_VERSION_MESA 0x8185 +#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_RGBA 4 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_SAMPLES 100001 +#define GLX_SAMPLE_BUFFERS 100000 +#define GLX_SAVED 0x8021 +#define GLX_SCREEN 0x800C +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_STATIC_COLOR 0x8005 +#define GLX_STATIC_GRAY 0x8007 +#define GLX_STENCIL_BUFFER_BIT 0x00000040 +#define GLX_STENCIL_SIZE 13 +#define GLX_STEREO 6 +#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 +#define GLX_TRANSPARENT_BLUE_VALUE 0x27 +#define GLX_TRANSPARENT_GREEN_VALUE 0x26 +#define GLX_TRANSPARENT_INDEX 0x8009 +#define GLX_TRANSPARENT_INDEX_VALUE 0x24 +#define GLX_TRANSPARENT_RED_VALUE 0x25 +#define GLX_TRANSPARENT_RGB 0x8008 +#define GLX_TRANSPARENT_TYPE 0x23 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_USE_GL 1 +#define GLX_VENDOR 0x1 +#define GLX_VERSION 0x2 +#define GLX_VISUAL_ID 0x800B +#define GLX_WIDTH 0x801D +#define GLX_WINDOW 0x8022 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_X_RENDERABLE 0x8012 +#define GLX_X_VISUAL_TYPE 0x22 +#define __GLX_NUMBER_EVENTS 17 + + +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GLX_OML_sync_control extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif + + + + + + + + + + + + + + + + +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) + +#else + +#endif + +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) + +#else + +#endif + + + + + + + +typedef XID GLXFBConfigID; +typedef struct __GLXFBConfigRec *GLXFBConfig; +typedef XID GLXContextID; +typedef struct __GLXcontextRec *GLXContext; +typedef XID GLXPixmap; +typedef XID GLXDrawable; +typedef XID GLXWindow; +typedef XID GLXPbuffer; +typedef void (GLAD_API_PTR *__GLXextFuncPtr)(void); +typedef XID GLXVideoCaptureDeviceNV; +typedef unsigned int GLXVideoDeviceNV; +typedef XID GLXVideoSourceSGIX; +typedef XID GLXFBConfigIDSGIX; +typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; +typedef XID GLXPbufferSGIX; +typedef struct { + int event_type; /* GLX_DAMAGED or GLX_SAVED */ + int draw_type; /* GLX_WINDOW or GLX_PBUFFER */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came for SendEvent request */ + Display *display; /* display the event was read from */ + GLXDrawable drawable; /* XID of Drawable */ + unsigned int buffer_mask; /* mask indicating which buffers are affected */ + unsigned int aux_buffer; /* which aux buffer was affected */ + int x, y; + int width, height; + int count; /* if nonzero, at least this many more */ +} GLXPbufferClobberEvent; +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + GLXDrawable drawable; /* drawable on which event was requested in event mask */ + int event_type; + int64_t ust; + int64_t msc; + int64_t sbc; +} GLXBufferSwapComplete; +typedef union __GLXEvent { + GLXPbufferClobberEvent glxpbufferclobber; + GLXBufferSwapComplete glxbufferswapcomplete; + long pad[24]; +} GLXEvent; +typedef struct { + int type; + unsigned long serial; + Bool send_event; + Display *display; + int extension; + int evtype; + GLXDrawable window; + Bool stereo_tree; +} GLXStereoNotifyEventEXT; +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came for SendEvent request */ + Display *display; /* display the event was read from */ + GLXDrawable drawable; /* i.d. of Drawable */ + int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ + int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ + unsigned int mask; /* mask indicating which buffers are affected*/ + int x, y; + int width, height; + int count; /* if nonzero, at least this many more */ +} GLXBufferClobberEventSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int networkId; +} GLXHyperpipeNetworkSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int channel; + unsigned int participationType; + int timeSlice; +} GLXHyperpipeConfigSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int srcXOrigin, srcYOrigin, srcWidth, srcHeight; + int destXOrigin, destYOrigin, destWidth, destHeight; +} GLXPipeRect; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int XOrigin, YOrigin, maxHeight, maxWidth; +} GLXPipeRectLimits; + + +#define GLX_VERSION_1_0 1 +GLAD_API_CALL int GLAD_GLX_VERSION_1_0; +#define GLX_VERSION_1_1 1 +GLAD_API_CALL int GLAD_GLX_VERSION_1_1; +#define GLX_VERSION_1_2 1 +GLAD_API_CALL int GLAD_GLX_VERSION_1_2; +#define GLX_VERSION_1_3 1 +GLAD_API_CALL int GLAD_GLX_VERSION_1_3; +#define GLX_VERSION_1_4 1 +GLAD_API_CALL int GLAD_GLX_VERSION_1_4; +#define GLX_MESA_query_renderer 1 +GLAD_API_CALL int GLAD_GLX_MESA_query_renderer; +#define GLX_SGI_swap_control 1 +GLAD_API_CALL int GLAD_GLX_SGI_swap_control; + + +typedef GLXFBConfig * (GLAD_API_PTR *PFNGLXCHOOSEFBCONFIGPROC)(Display * dpy, int screen, const int * attrib_list, int * nelements); +typedef XVisualInfo * (GLAD_API_PTR *PFNGLXCHOOSEVISUALPROC)(Display * dpy, int screen, int * attribList); +typedef void (GLAD_API_PTR *PFNGLXCOPYCONTEXTPROC)(Display * dpy, GLXContext src, GLXContext dst, unsigned long mask); +typedef GLXContext (GLAD_API_PTR *PFNGLXCREATECONTEXTPROC)(Display * dpy, XVisualInfo * vis, GLXContext shareList, Bool direct); +typedef GLXPixmap (GLAD_API_PTR *PFNGLXCREATEGLXPIXMAPPROC)(Display * dpy, XVisualInfo * visual, Pixmap pixmap); +typedef GLXContext (GLAD_API_PTR *PFNGLXCREATENEWCONTEXTPROC)(Display * dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); +typedef GLXPbuffer (GLAD_API_PTR *PFNGLXCREATEPBUFFERPROC)(Display * dpy, GLXFBConfig config, const int * attrib_list); +typedef GLXPixmap (GLAD_API_PTR *PFNGLXCREATEPIXMAPPROC)(Display * dpy, GLXFBConfig config, Pixmap pixmap, const int * attrib_list); +typedef GLXWindow (GLAD_API_PTR *PFNGLXCREATEWINDOWPROC)(Display * dpy, GLXFBConfig config, Window win, const int * attrib_list); +typedef void (GLAD_API_PTR *PFNGLXDESTROYCONTEXTPROC)(Display * dpy, GLXContext ctx); +typedef void (GLAD_API_PTR *PFNGLXDESTROYGLXPIXMAPPROC)(Display * dpy, GLXPixmap pixmap); +typedef void (GLAD_API_PTR *PFNGLXDESTROYPBUFFERPROC)(Display * dpy, GLXPbuffer pbuf); +typedef void (GLAD_API_PTR *PFNGLXDESTROYPIXMAPPROC)(Display * dpy, GLXPixmap pixmap); +typedef void (GLAD_API_PTR *PFNGLXDESTROYWINDOWPROC)(Display * dpy, GLXWindow win); +typedef const char * (GLAD_API_PTR *PFNGLXGETCLIENTSTRINGPROC)(Display * dpy, int name); +typedef int (GLAD_API_PTR *PFNGLXGETCONFIGPROC)(Display * dpy, XVisualInfo * visual, int attrib, int * value); +typedef GLXContext (GLAD_API_PTR *PFNGLXGETCURRENTCONTEXTPROC)(void); +typedef Display * (GLAD_API_PTR *PFNGLXGETCURRENTDISPLAYPROC)(void); +typedef GLXDrawable (GLAD_API_PTR *PFNGLXGETCURRENTDRAWABLEPROC)(void); +typedef GLXDrawable (GLAD_API_PTR *PFNGLXGETCURRENTREADDRAWABLEPROC)(void); +typedef int (GLAD_API_PTR *PFNGLXGETFBCONFIGATTRIBPROC)(Display * dpy, GLXFBConfig config, int attribute, int * value); +typedef GLXFBConfig * (GLAD_API_PTR *PFNGLXGETFBCONFIGSPROC)(Display * dpy, int screen, int * nelements); +typedef __GLXextFuncPtr (GLAD_API_PTR *PFNGLXGETPROCADDRESSPROC)(const GLubyte * procName); +typedef void (GLAD_API_PTR *PFNGLXGETSELECTEDEVENTPROC)(Display * dpy, GLXDrawable draw, unsigned long * event_mask); +typedef XVisualInfo * (GLAD_API_PTR *PFNGLXGETVISUALFROMFBCONFIGPROC)(Display * dpy, GLXFBConfig config); +typedef Bool (GLAD_API_PTR *PFNGLXISDIRECTPROC)(Display * dpy, GLXContext ctx); +typedef Bool (GLAD_API_PTR *PFNGLXMAKECONTEXTCURRENTPROC)(Display * dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +typedef Bool (GLAD_API_PTR *PFNGLXMAKECURRENTPROC)(Display * dpy, GLXDrawable drawable, GLXContext ctx); +typedef int (GLAD_API_PTR *PFNGLXQUERYCONTEXTPROC)(Display * dpy, GLXContext ctx, int attribute, int * value); +typedef Bool (GLAD_API_PTR *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)(int attribute, unsigned int * value); +typedef const char * (GLAD_API_PTR *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC)(int attribute); +typedef void (GLAD_API_PTR *PFNGLXQUERYDRAWABLEPROC)(Display * dpy, GLXDrawable draw, int attribute, unsigned int * value); +typedef Bool (GLAD_API_PTR *PFNGLXQUERYEXTENSIONPROC)(Display * dpy, int * errorb, int * event); +typedef const char * (GLAD_API_PTR *PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display * dpy, int screen); +typedef Bool (GLAD_API_PTR *PFNGLXQUERYRENDERERINTEGERMESAPROC)(Display * dpy, int screen, int renderer, int attribute, unsigned int * value); +typedef const char * (GLAD_API_PTR *PFNGLXQUERYRENDERERSTRINGMESAPROC)(Display * dpy, int screen, int renderer, int attribute); +typedef const char * (GLAD_API_PTR *PFNGLXQUERYSERVERSTRINGPROC)(Display * dpy, int screen, int name); +typedef Bool (GLAD_API_PTR *PFNGLXQUERYVERSIONPROC)(Display * dpy, int * maj, int * min); +typedef void (GLAD_API_PTR *PFNGLXSELECTEVENTPROC)(Display * dpy, GLXDrawable draw, unsigned long event_mask); +typedef void (GLAD_API_PTR *PFNGLXSWAPBUFFERSPROC)(Display * dpy, GLXDrawable drawable); +typedef int (GLAD_API_PTR *PFNGLXSWAPINTERVALSGIPROC)(int interval); +typedef void (GLAD_API_PTR *PFNGLXUSEXFONTPROC)(Font font, int first, int count, int list); +typedef void (GLAD_API_PTR *PFNGLXWAITGLPROC)(void); +typedef void (GLAD_API_PTR *PFNGLXWAITXPROC)(void); + +GLAD_API_CALL PFNGLXCHOOSEFBCONFIGPROC glad_glXChooseFBConfig; +#define glXChooseFBConfig glad_glXChooseFBConfig +GLAD_API_CALL PFNGLXCHOOSEVISUALPROC glad_glXChooseVisual; +#define glXChooseVisual glad_glXChooseVisual +GLAD_API_CALL PFNGLXCOPYCONTEXTPROC glad_glXCopyContext; +#define glXCopyContext glad_glXCopyContext +GLAD_API_CALL PFNGLXCREATECONTEXTPROC glad_glXCreateContext; +#define glXCreateContext glad_glXCreateContext +GLAD_API_CALL PFNGLXCREATEGLXPIXMAPPROC glad_glXCreateGLXPixmap; +#define glXCreateGLXPixmap glad_glXCreateGLXPixmap +GLAD_API_CALL PFNGLXCREATENEWCONTEXTPROC glad_glXCreateNewContext; +#define glXCreateNewContext glad_glXCreateNewContext +GLAD_API_CALL PFNGLXCREATEPBUFFERPROC glad_glXCreatePbuffer; +#define glXCreatePbuffer glad_glXCreatePbuffer +GLAD_API_CALL PFNGLXCREATEPIXMAPPROC glad_glXCreatePixmap; +#define glXCreatePixmap glad_glXCreatePixmap +GLAD_API_CALL PFNGLXCREATEWINDOWPROC glad_glXCreateWindow; +#define glXCreateWindow glad_glXCreateWindow +GLAD_API_CALL PFNGLXDESTROYCONTEXTPROC glad_glXDestroyContext; +#define glXDestroyContext glad_glXDestroyContext +GLAD_API_CALL PFNGLXDESTROYGLXPIXMAPPROC glad_glXDestroyGLXPixmap; +#define glXDestroyGLXPixmap glad_glXDestroyGLXPixmap +GLAD_API_CALL PFNGLXDESTROYPBUFFERPROC glad_glXDestroyPbuffer; +#define glXDestroyPbuffer glad_glXDestroyPbuffer +GLAD_API_CALL PFNGLXDESTROYPIXMAPPROC glad_glXDestroyPixmap; +#define glXDestroyPixmap glad_glXDestroyPixmap +GLAD_API_CALL PFNGLXDESTROYWINDOWPROC glad_glXDestroyWindow; +#define glXDestroyWindow glad_glXDestroyWindow +GLAD_API_CALL PFNGLXGETCLIENTSTRINGPROC glad_glXGetClientString; +#define glXGetClientString glad_glXGetClientString +GLAD_API_CALL PFNGLXGETCONFIGPROC glad_glXGetConfig; +#define glXGetConfig glad_glXGetConfig +GLAD_API_CALL PFNGLXGETCURRENTCONTEXTPROC glad_glXGetCurrentContext; +#define glXGetCurrentContext glad_glXGetCurrentContext +GLAD_API_CALL PFNGLXGETCURRENTDISPLAYPROC glad_glXGetCurrentDisplay; +#define glXGetCurrentDisplay glad_glXGetCurrentDisplay +GLAD_API_CALL PFNGLXGETCURRENTDRAWABLEPROC glad_glXGetCurrentDrawable; +#define glXGetCurrentDrawable glad_glXGetCurrentDrawable +GLAD_API_CALL PFNGLXGETCURRENTREADDRAWABLEPROC glad_glXGetCurrentReadDrawable; +#define glXGetCurrentReadDrawable glad_glXGetCurrentReadDrawable +GLAD_API_CALL PFNGLXGETFBCONFIGATTRIBPROC glad_glXGetFBConfigAttrib; +#define glXGetFBConfigAttrib glad_glXGetFBConfigAttrib +GLAD_API_CALL PFNGLXGETFBCONFIGSPROC glad_glXGetFBConfigs; +#define glXGetFBConfigs glad_glXGetFBConfigs +GLAD_API_CALL PFNGLXGETPROCADDRESSPROC glad_glXGetProcAddress; +#define glXGetProcAddress glad_glXGetProcAddress +GLAD_API_CALL PFNGLXGETSELECTEDEVENTPROC glad_glXGetSelectedEvent; +#define glXGetSelectedEvent glad_glXGetSelectedEvent +GLAD_API_CALL PFNGLXGETVISUALFROMFBCONFIGPROC glad_glXGetVisualFromFBConfig; +#define glXGetVisualFromFBConfig glad_glXGetVisualFromFBConfig +GLAD_API_CALL PFNGLXISDIRECTPROC glad_glXIsDirect; +#define glXIsDirect glad_glXIsDirect +GLAD_API_CALL PFNGLXMAKECONTEXTCURRENTPROC glad_glXMakeContextCurrent; +#define glXMakeContextCurrent glad_glXMakeContextCurrent +GLAD_API_CALL PFNGLXMAKECURRENTPROC glad_glXMakeCurrent; +#define glXMakeCurrent glad_glXMakeCurrent +GLAD_API_CALL PFNGLXQUERYCONTEXTPROC glad_glXQueryContext; +#define glXQueryContext glad_glXQueryContext +GLAD_API_CALL PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glad_glXQueryCurrentRendererIntegerMESA; +#define glXQueryCurrentRendererIntegerMESA glad_glXQueryCurrentRendererIntegerMESA +GLAD_API_CALL PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC glad_glXQueryCurrentRendererStringMESA; +#define glXQueryCurrentRendererStringMESA glad_glXQueryCurrentRendererStringMESA +GLAD_API_CALL PFNGLXQUERYDRAWABLEPROC glad_glXQueryDrawable; +#define glXQueryDrawable glad_glXQueryDrawable +GLAD_API_CALL PFNGLXQUERYEXTENSIONPROC glad_glXQueryExtension; +#define glXQueryExtension glad_glXQueryExtension +GLAD_API_CALL PFNGLXQUERYEXTENSIONSSTRINGPROC glad_glXQueryExtensionsString; +#define glXQueryExtensionsString glad_glXQueryExtensionsString +GLAD_API_CALL PFNGLXQUERYRENDERERINTEGERMESAPROC glad_glXQueryRendererIntegerMESA; +#define glXQueryRendererIntegerMESA glad_glXQueryRendererIntegerMESA +GLAD_API_CALL PFNGLXQUERYRENDERERSTRINGMESAPROC glad_glXQueryRendererStringMESA; +#define glXQueryRendererStringMESA glad_glXQueryRendererStringMESA +GLAD_API_CALL PFNGLXQUERYSERVERSTRINGPROC glad_glXQueryServerString; +#define glXQueryServerString glad_glXQueryServerString +GLAD_API_CALL PFNGLXQUERYVERSIONPROC glad_glXQueryVersion; +#define glXQueryVersion glad_glXQueryVersion +GLAD_API_CALL PFNGLXSELECTEVENTPROC glad_glXSelectEvent; +#define glXSelectEvent glad_glXSelectEvent +GLAD_API_CALL PFNGLXSWAPBUFFERSPROC glad_glXSwapBuffers; +#define glXSwapBuffers glad_glXSwapBuffers +GLAD_API_CALL PFNGLXSWAPINTERVALSGIPROC glad_glXSwapIntervalSGI; +#define glXSwapIntervalSGI glad_glXSwapIntervalSGI +GLAD_API_CALL PFNGLXUSEXFONTPROC glad_glXUseXFont; +#define glXUseXFont glad_glXUseXFont +GLAD_API_CALL PFNGLXWAITGLPROC glad_glXWaitGL; +#define glXWaitGL glad_glXWaitGL +GLAD_API_CALL PFNGLXWAITXPROC glad_glXWaitX; +#define glXWaitX glad_glXWaitX + + + + + +GLAD_API_CALL int gladLoadGLXUserPtr(Display *display, int screen, GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadGLX(Display *display, int screen, GLADloadfunc load); + + +#ifdef __cplusplus +} +#endif +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/include/glad/wgl.h 0ad-0.0.26/libraries/source/glad/include/glad/wgl.h --- 0ad-0.0.25b/libraries/source/glad/include/glad/wgl.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/glad/wgl.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,298 @@ +/** + * Loader generated by glad 2.0.0-beta on Tue Mar 29 08:49:07 2022 + * + * Generator: C/C++ + * Specification: wgl + * Extensions: 3 + * + * APIs: + * - wgl=1.0 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False + * - MX = False + * - MX_GLOBAL = False + * - ON_DEMAND = False + * + * Commandline: + * --api='wgl=1.0' --extensions='WGL_ARB_extensions_string,WGL_EXT_extensions_string,WGL_EXT_swap_control' c + * + * Online: + * http://glad.sh/#api=wgl%3D1.0&extensions=WGL_ARB_extensions_string%2CWGL_EXT_extensions_string%2CWGL_EXT_swap_control&generator=c&options= + * + */ + +#ifndef GLAD_WGL_H_ +#define GLAD_WGL_H_ + +#include +#include + +#define GLAD_WGL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.0-beta" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define WGL_FONT_LINES 0 +#define WGL_FONT_POLYGONS 1 +#define WGL_SWAP_MAIN_PLANE 0x00000001 +#define WGL_SWAP_OVERLAY1 0x00000002 +#define WGL_SWAP_OVERLAY10 0x00000400 +#define WGL_SWAP_OVERLAY11 0x00000800 +#define WGL_SWAP_OVERLAY12 0x00001000 +#define WGL_SWAP_OVERLAY13 0x00002000 +#define WGL_SWAP_OVERLAY14 0x00004000 +#define WGL_SWAP_OVERLAY15 0x00008000 +#define WGL_SWAP_OVERLAY2 0x00000004 +#define WGL_SWAP_OVERLAY3 0x00000008 +#define WGL_SWAP_OVERLAY4 0x00000010 +#define WGL_SWAP_OVERLAY5 0x00000020 +#define WGL_SWAP_OVERLAY6 0x00000040 +#define WGL_SWAP_OVERLAY7 0x00000080 +#define WGL_SWAP_OVERLAY8 0x00000100 +#define WGL_SWAP_OVERLAY9 0x00000200 +#define WGL_SWAP_UNDERLAY1 0x00010000 +#define WGL_SWAP_UNDERLAY10 0x02000000 +#define WGL_SWAP_UNDERLAY11 0x04000000 +#define WGL_SWAP_UNDERLAY12 0x08000000 +#define WGL_SWAP_UNDERLAY13 0x10000000 +#define WGL_SWAP_UNDERLAY14 0x20000000 +#define WGL_SWAP_UNDERLAY15 0x40000000 +#define WGL_SWAP_UNDERLAY2 0x00020000 +#define WGL_SWAP_UNDERLAY3 0x00040000 +#define WGL_SWAP_UNDERLAY4 0x00080000 +#define WGL_SWAP_UNDERLAY5 0x00100000 +#define WGL_SWAP_UNDERLAY6 0x00200000 +#define WGL_SWAP_UNDERLAY7 0x00400000 +#define WGL_SWAP_UNDERLAY8 0x00800000 +#define WGL_SWAP_UNDERLAY9 0x01000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct _GPU_DEVICE { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD Flags; + RECT rcVirtualScreen; +}; +DECLARE_HANDLE(HPBUFFERARB); +DECLARE_HANDLE(HPBUFFEREXT); +DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); +DECLARE_HANDLE(HPVIDEODEV); +DECLARE_HANDLE(HPGPUNV); +DECLARE_HANDLE(HGPUNV); +DECLARE_HANDLE(HVIDEOINPUTDEVICENV); +typedef struct _GPU_DEVICE GPU_DEVICE; +typedef struct _GPU_DEVICE *PGPU_DEVICE; + + +#define WGL_VERSION_1_0 1 +GLAD_API_CALL int GLAD_WGL_VERSION_1_0; +#define WGL_ARB_extensions_string 1 +GLAD_API_CALL int GLAD_WGL_ARB_extensions_string; +#define WGL_EXT_extensions_string 1 +GLAD_API_CALL int GLAD_WGL_EXT_extensions_string; +#define WGL_EXT_swap_control 1 +GLAD_API_CALL int GLAD_WGL_EXT_swap_control; + + +typedef int (GLAD_API_PTR *PFNCHOOSEPIXELFORMATPROC)(HDC hDc, const PIXELFORMATDESCRIPTOR * pPfd); +typedef int (GLAD_API_PTR *PFNDESCRIBEPIXELFORMATPROC)(HDC hdc, int ipfd, UINT cjpfd, const PIXELFORMATDESCRIPTOR * ppfd); +typedef UINT (GLAD_API_PTR *PFNGETENHMETAFILEPIXELFORMATPROC)(HENHMETAFILE hemf, const PIXELFORMATDESCRIPTOR * ppfd); +typedef int (GLAD_API_PTR *PFNGETPIXELFORMATPROC)(HDC hdc); +typedef BOOL (GLAD_API_PTR *PFNSETPIXELFORMATPROC)(HDC hdc, int ipfd, const PIXELFORMATDESCRIPTOR * ppfd); +typedef BOOL (GLAD_API_PTR *PFNSWAPBUFFERSPROC)(HDC hdc); +typedef BOOL (GLAD_API_PTR *PFNWGLCOPYCONTEXTPROC)(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask); +typedef HGLRC (GLAD_API_PTR *PFNWGLCREATECONTEXTPROC)(HDC hDc); +typedef HGLRC (GLAD_API_PTR *PFNWGLCREATELAYERCONTEXTPROC)(HDC hDc, int level); +typedef BOOL (GLAD_API_PTR *PFNWGLDELETECONTEXTPROC)(HGLRC oldContext); +typedef BOOL (GLAD_API_PTR *PFNWGLDESCRIBELAYERPLANEPROC)(HDC hDc, int pixelFormat, int layerPlane, UINT nBytes, const LAYERPLANEDESCRIPTOR * plpd); +typedef HGLRC (GLAD_API_PTR *PFNWGLGETCURRENTCONTEXTPROC)(void); +typedef HDC (GLAD_API_PTR *PFNWGLGETCURRENTDCPROC)(void); +typedef const char * (GLAD_API_PTR *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); +typedef const char * (GLAD_API_PTR *PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); +typedef int (GLAD_API_PTR *PFNWGLGETLAYERPALETTEENTRIESPROC)(HDC hdc, int iLayerPlane, int iStart, int cEntries, const COLORREF * pcr); +typedef PROC (GLAD_API_PTR *PFNWGLGETPROCADDRESSPROC)(LPCSTR lpszProc); +typedef int (GLAD_API_PTR *PFNWGLGETSWAPINTERVALEXTPROC)(void); +typedef BOOL (GLAD_API_PTR *PFNWGLMAKECURRENTPROC)(HDC hDc, HGLRC newContext); +typedef BOOL (GLAD_API_PTR *PFNWGLREALIZELAYERPALETTEPROC)(HDC hdc, int iLayerPlane, BOOL bRealize); +typedef int (GLAD_API_PTR *PFNWGLSETLAYERPALETTEENTRIESPROC)(HDC hdc, int iLayerPlane, int iStart, int cEntries, const COLORREF * pcr); +typedef BOOL (GLAD_API_PTR *PFNWGLSHARELISTSPROC)(HGLRC hrcSrvShare, HGLRC hrcSrvSource); +typedef BOOL (GLAD_API_PTR *PFNWGLSWAPINTERVALEXTPROC)(int interval); +typedef BOOL (GLAD_API_PTR *PFNWGLSWAPLAYERBUFFERSPROC)(HDC hdc, UINT fuFlags); +typedef BOOL (GLAD_API_PTR *PFNWGLUSEFONTBITMAPSPROC)(HDC hDC, DWORD first, DWORD count, DWORD listBase); +typedef BOOL (GLAD_API_PTR *PFNWGLUSEFONTBITMAPSAPROC)(HDC hDC, DWORD first, DWORD count, DWORD listBase); +typedef BOOL (GLAD_API_PTR *PFNWGLUSEFONTBITMAPSWPROC)(HDC hDC, DWORD first, DWORD count, DWORD listBase); +typedef BOOL (GLAD_API_PTR *PFNWGLUSEFONTOUTLINESPROC)(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf); +typedef BOOL (GLAD_API_PTR *PFNWGLUSEFONTOUTLINESAPROC)(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf); +typedef BOOL (GLAD_API_PTR *PFNWGLUSEFONTOUTLINESWPROC)(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf); + +GLAD_API_CALL PFNWGLGETEXTENSIONSSTRINGARBPROC glad_wglGetExtensionsStringARB; +#define wglGetExtensionsStringARB glad_wglGetExtensionsStringARB +GLAD_API_CALL PFNWGLGETEXTENSIONSSTRINGEXTPROC glad_wglGetExtensionsStringEXT; +#define wglGetExtensionsStringEXT glad_wglGetExtensionsStringEXT +GLAD_API_CALL PFNWGLGETSWAPINTERVALEXTPROC glad_wglGetSwapIntervalEXT; +#define wglGetSwapIntervalEXT glad_wglGetSwapIntervalEXT +GLAD_API_CALL PFNWGLSWAPINTERVALEXTPROC glad_wglSwapIntervalEXT; +#define wglSwapIntervalEXT glad_wglSwapIntervalEXT + + + + + +GLAD_API_CALL int gladLoadWGLUserPtr(HDC hdc, GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadWGL(HDC hdc, GLADloadfunc load); + + +#ifdef __cplusplus +} +#endif +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/include/KHR/khrplatform.h 0ad-0.0.26/libraries/source/glad/include/KHR/khrplatform.h --- 0ad-0.0.25b/libraries/source/glad/include/KHR/khrplatform.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/include/KHR/khrplatform.h 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,311 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are 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 Materials. +** +** THE MATERIALS ARE 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 +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff -Nru 0ad-0.0.25b/libraries/source/glad/README.md 0ad-0.0.26/libraries/source/glad/README.md --- 0ad-0.0.25b/libraries/source/glad/README.md 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/README.md 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,40 @@ +## Introduction + +This folder contains the files generated by the glad GL loader for the game. + +## Instructions + +Download glad v2: +```sh +git clone https://github.com/Dav1dde/glad.git -b glad2 +``` + +Install the python dependencies +```sh +cd glad +pip install -r requirements.txt +``` + +Build the source files for all four backends with their respective extensions +- GL + ```sh + python -m glad --api="gl:core=2.1" --extensions="../extensions/gl.txt" --out-path="../" + ``` +- GLES2 + ```sh + python -m glad --api="gles2=2.0" --extensions="../extensions/gles2.txt" --out-path="../" + ``` +- GLX + ```sh + python -m glad --api="glx=1.4" --extensions="../extensions/glx.txt" --out-path="../" + ``` +- WGL + ```sh + python -m glad --api="wgl=1.0" --extensions="../extensions/wgl.txt" --out-path="../" + ``` +- EGL + ```sh + python -m glad --api="egl=1.5" --extensions="../extensions/egl.txt" --out-path="../" + ``` + +Rename all files to .cpp to prevent compilation warnings diff -Nru 0ad-0.0.25b/libraries/source/glad/src/egl.cpp 0ad-0.0.26/libraries/source/glad/src/egl.cpp --- 0ad-0.0.25b/libraries/source/glad/src/egl.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/src/egl.cpp 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,251 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_EGL_VERSION_1_0 = 0; +int GLAD_EGL_VERSION_1_1 = 0; +int GLAD_EGL_VERSION_1_2 = 0; +int GLAD_EGL_VERSION_1_3 = 0; +int GLAD_EGL_VERSION_1_4 = 0; +int GLAD_EGL_VERSION_1_5 = 0; + + + +PFNEGLBINDAPIPROC glad_eglBindAPI = NULL; +PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage = NULL; +PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig = NULL; +PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync = NULL; +PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers = NULL; +PFNEGLCREATECONTEXTPROC glad_eglCreateContext = NULL; +PFNEGLCREATEIMAGEPROC glad_eglCreateImage = NULL; +PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer = NULL; +PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface = NULL; +PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface = NULL; +PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL; +PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL; +PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL; +PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL; +PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL; +PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL; +PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface = NULL; +PFNEGLDESTROYSYNCPROC glad_eglDestroySync = NULL; +PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib = NULL; +PFNEGLGETCONFIGSPROC glad_eglGetConfigs = NULL; +PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext = NULL; +PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay = NULL; +PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface = NULL; +PFNEGLGETDISPLAYPROC glad_eglGetDisplay = NULL; +PFNEGLGETERRORPROC glad_eglGetError = NULL; +PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL; +PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL; +PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL; +PFNEGLINITIALIZEPROC glad_eglInitialize = NULL; +PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL; +PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL; +PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL; +PFNEGLQUERYSTRINGPROC glad_eglQueryString = NULL; +PFNEGLQUERYSURFACEPROC glad_eglQuerySurface = NULL; +PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage = NULL; +PFNEGLRELEASETHREADPROC glad_eglReleaseThread = NULL; +PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib = NULL; +PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers = NULL; +PFNEGLSWAPINTERVALPROC glad_eglSwapInterval = NULL; +PFNEGLTERMINATEPROC glad_eglTerminate = NULL; +PFNEGLWAITCLIENTPROC glad_eglWaitClient = NULL; +PFNEGLWAITGLPROC glad_eglWaitGL = NULL; +PFNEGLWAITNATIVEPROC glad_eglWaitNative = NULL; +PFNEGLWAITSYNCPROC glad_eglWaitSync = NULL; + + +static void glad_egl_load_EGL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_EGL_VERSION_1_0) return; + glad_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) load(userptr, "eglChooseConfig"); + glad_eglCopyBuffers = (PFNEGLCOPYBUFFERSPROC) load(userptr, "eglCopyBuffers"); + glad_eglCreateContext = (PFNEGLCREATECONTEXTPROC) load(userptr, "eglCreateContext"); + glad_eglCreatePbufferSurface = (PFNEGLCREATEPBUFFERSURFACEPROC) load(userptr, "eglCreatePbufferSurface"); + glad_eglCreatePixmapSurface = (PFNEGLCREATEPIXMAPSURFACEPROC) load(userptr, "eglCreatePixmapSurface"); + glad_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) load(userptr, "eglCreateWindowSurface"); + glad_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) load(userptr, "eglDestroyContext"); + glad_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) load(userptr, "eglDestroySurface"); + glad_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) load(userptr, "eglGetConfigAttrib"); + glad_eglGetConfigs = (PFNEGLGETCONFIGSPROC) load(userptr, "eglGetConfigs"); + glad_eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay"); + glad_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) load(userptr, "eglGetCurrentSurface"); + glad_eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay"); + glad_eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError"); + glad_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) load(userptr, "eglGetProcAddress"); + glad_eglInitialize = (PFNEGLINITIALIZEPROC) load(userptr, "eglInitialize"); + glad_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) load(userptr, "eglMakeCurrent"); + glad_eglQueryContext = (PFNEGLQUERYCONTEXTPROC) load(userptr, "eglQueryContext"); + glad_eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString"); + glad_eglQuerySurface = (PFNEGLQUERYSURFACEPROC) load(userptr, "eglQuerySurface"); + glad_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) load(userptr, "eglSwapBuffers"); + glad_eglTerminate = (PFNEGLTERMINATEPROC) load(userptr, "eglTerminate"); + glad_eglWaitGL = (PFNEGLWAITGLPROC) load(userptr, "eglWaitGL"); + glad_eglWaitNative = (PFNEGLWAITNATIVEPROC) load(userptr, "eglWaitNative"); +} +static void glad_egl_load_EGL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_EGL_VERSION_1_1) return; + glad_eglBindTexImage = (PFNEGLBINDTEXIMAGEPROC) load(userptr, "eglBindTexImage"); + glad_eglReleaseTexImage = (PFNEGLRELEASETEXIMAGEPROC) load(userptr, "eglReleaseTexImage"); + glad_eglSurfaceAttrib = (PFNEGLSURFACEATTRIBPROC) load(userptr, "eglSurfaceAttrib"); + glad_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) load(userptr, "eglSwapInterval"); +} +static void glad_egl_load_EGL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_EGL_VERSION_1_2) return; + glad_eglBindAPI = (PFNEGLBINDAPIPROC) load(userptr, "eglBindAPI"); + glad_eglCreatePbufferFromClientBuffer = (PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) load(userptr, "eglCreatePbufferFromClientBuffer"); + glad_eglQueryAPI = (PFNEGLQUERYAPIPROC) load(userptr, "eglQueryAPI"); + glad_eglReleaseThread = (PFNEGLRELEASETHREADPROC) load(userptr, "eglReleaseThread"); + glad_eglWaitClient = (PFNEGLWAITCLIENTPROC) load(userptr, "eglWaitClient"); +} +static void glad_egl_load_EGL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_EGL_VERSION_1_4) return; + glad_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) load(userptr, "eglGetCurrentContext"); +} +static void glad_egl_load_EGL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_EGL_VERSION_1_5) return; + glad_eglClientWaitSync = (PFNEGLCLIENTWAITSYNCPROC) load(userptr, "eglClientWaitSync"); + glad_eglCreateImage = (PFNEGLCREATEIMAGEPROC) load(userptr, "eglCreateImage"); + glad_eglCreatePlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) load(userptr, "eglCreatePlatformPixmapSurface"); + glad_eglCreatePlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) load(userptr, "eglCreatePlatformWindowSurface"); + glad_eglCreateSync = (PFNEGLCREATESYNCPROC) load(userptr, "eglCreateSync"); + glad_eglDestroyImage = (PFNEGLDESTROYIMAGEPROC) load(userptr, "eglDestroyImage"); + glad_eglDestroySync = (PFNEGLDESTROYSYNCPROC) load(userptr, "eglDestroySync"); + glad_eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYPROC) load(userptr, "eglGetPlatformDisplay"); + glad_eglGetSyncAttrib = (PFNEGLGETSYNCATTRIBPROC) load(userptr, "eglGetSyncAttrib"); + glad_eglWaitSync = (PFNEGLWAITSYNCPROC) load(userptr, "eglWaitSync"); +} + + + +static int glad_egl_get_extensions(EGLDisplay display, const char **extensions) { + *extensions = eglQueryString(display, EGL_EXTENSIONS); + + return extensions != NULL; +} + +static int glad_egl_has_extension(const char *extensions, const char *ext) { + const char *loc; + const char *terminator; + if(extensions == NULL) { + return 0; + } + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +} + +static GLADapiproc glad_egl_get_proc_from_userptr(void *userptr, const char *name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_egl_find_extensions_egl(EGLDisplay display) { + const char *extensions; + if (!glad_egl_get_extensions(display, &extensions)) return 0; + + (void) glad_egl_has_extension; + + return 1; +} + +static int glad_egl_find_core_egl(EGLDisplay display) { + int major, minor; + const char *version; + + if (display == NULL) { + display = EGL_NO_DISPLAY; /* this is usually NULL, better safe than sorry */ + } + if (display == EGL_NO_DISPLAY) { + display = eglGetCurrentDisplay(); + } +#ifdef EGL_VERSION_1_4 + if (display == EGL_NO_DISPLAY) { + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + } +#endif +#ifndef EGL_VERSION_1_5 + if (display == EGL_NO_DISPLAY) { + return 0; + } +#endif + + version = eglQueryString(display, EGL_VERSION); + (void) eglGetError(); + + if (version == NULL) { + major = 1; + minor = 0; + } else { + GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); + } + + GLAD_EGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_EGL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_EGL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_EGL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_EGL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_EGL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void* userptr) { + int version; + eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay"); + eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay"); + eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString"); + eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError"); + if (eglGetDisplay == NULL || eglGetCurrentDisplay == NULL || eglQueryString == NULL || eglGetError == NULL) return 0; + + version = glad_egl_find_core_egl(display); + if (!version) return 0; + glad_egl_load_EGL_VERSION_1_0(load, userptr); + glad_egl_load_EGL_VERSION_1_1(load, userptr); + glad_egl_load_EGL_VERSION_1_2(load, userptr); + glad_egl_load_EGL_VERSION_1_4(load, userptr); + glad_egl_load_EGL_VERSION_1_5(load, userptr); + + if (!glad_egl_find_extensions_egl(display)) return 0; + + + return version; +} + +int gladLoadEGL(EGLDisplay display, GLADloadfunc load) { + return gladLoadEGLUserPtr(display, glad_egl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + +#ifdef __cplusplus +} +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/src/gl.cpp 0ad-0.0.26/libraries/source/glad/src/gl.cpp --- 0ad-0.0.25b/libraries/source/glad/src/gl.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/src/gl.cpp 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,2152 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_GL_VERSION_1_0 = 0; +int GLAD_GL_VERSION_1_1 = 0; +int GLAD_GL_VERSION_1_2 = 0; +int GLAD_GL_VERSION_1_3 = 0; +int GLAD_GL_VERSION_1_4 = 0; +int GLAD_GL_VERSION_1_5 = 0; +int GLAD_GL_VERSION_2_0 = 0; +int GLAD_GL_VERSION_2_1 = 0; +int GLAD_GL_ARB_draw_buffers = 0; +int GLAD_GL_ARB_draw_instanced = 0; +int GLAD_GL_ARB_fragment_program = 0; +int GLAD_GL_ARB_fragment_shader = 0; +int GLAD_GL_ARB_framebuffer_object = 0; +int GLAD_GL_ARB_geometry_shader4 = 0; +int GLAD_GL_ARB_instanced_arrays = 0; +int GLAD_GL_ARB_map_buffer_range = 0; +int GLAD_GL_ARB_multitexture = 0; +int GLAD_GL_ARB_occlusion_query = 0; +int GLAD_GL_ARB_shader_objects = 0; +int GLAD_GL_ARB_shading_language_100 = 0; +int GLAD_GL_ARB_sync = 0; +int GLAD_GL_ARB_texture_compression = 0; +int GLAD_GL_ARB_texture_multisample = 0; +int GLAD_GL_ARB_texture_rectangle = 0; +int GLAD_GL_ARB_timer_query = 0; +int GLAD_GL_ARB_vertex_buffer_object = 0; +int GLAD_GL_ARB_vertex_program = 0; +int GLAD_GL_ARB_vertex_shader = 0; +int GLAD_GL_EXT_bgra = 0; +int GLAD_GL_EXT_blend_color = 0; +int GLAD_GL_EXT_blend_minmax = 0; +int GLAD_GL_EXT_draw_range_elements = 0; +int GLAD_GL_EXT_framebuffer_blit = 0; +int GLAD_GL_EXT_framebuffer_multisample = 0; +int GLAD_GL_EXT_framebuffer_object = 0; +int GLAD_GL_EXT_gpu_shader4 = 0; +int GLAD_GL_EXT_packed_depth_stencil = 0; +int GLAD_GL_EXT_texture_array = 0; +int GLAD_GL_EXT_texture_compression_s3tc = 0; +int GLAD_GL_EXT_texture_filter_anisotropic = 0; +int GLAD_GL_EXT_texture_lod_bias = 0; +int GLAD_GL_EXT_transform_feedback = 0; +int GLAD_GL_KHR_debug = 0; + + + +PFNGLACCUMPROC glad_glAccum = NULL; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB = NULL; +PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL; +PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL; +PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL; +PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINPROC glad_glBegin = NULL; +PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; +PFNGLBEGINQUERYARBPROC glad_glBeginQueryARB = NULL; +PFNGLBEGINTRANSFORMFEEDBACKEXTPROC glad_glBeginTransformFeedbackEXT = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDBUFFERARBPROC glad_glBindBufferARB = NULL; +PFNGLBINDBUFFERBASEEXTPROC glad_glBindBufferBaseEXT = NULL; +PFNGLBINDBUFFEROFFSETEXTPROC glad_glBindBufferOffsetEXT = NULL; +PFNGLBINDBUFFERRANGEEXTPROC glad_glBindBufferRangeEXT = NULL; +PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT = NULL; +PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBITMAPPROC glad_glBitmap = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONEXTPROC glad_glBlendEquationEXT = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; +PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERDATAARBPROC glad_glBufferDataARB = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB = NULL; +PFNGLCALLLISTPROC glad_glCallList = NULL; +PFNGLCALLLISTSPROC glad_glCallLists = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARACCUMPROC glad_glClearAccum = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; +PFNGLCLEARINDEXPROC glad_glClearIndex = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL; +PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB = NULL; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; +PFNGLCLIPPLANEPROC glad_glClipPlane = NULL; +PFNGLCOLOR3BPROC glad_glColor3b = NULL; +PFNGLCOLOR3BVPROC glad_glColor3bv = NULL; +PFNGLCOLOR3DPROC glad_glColor3d = NULL; +PFNGLCOLOR3DVPROC glad_glColor3dv = NULL; +PFNGLCOLOR3FPROC glad_glColor3f = NULL; +PFNGLCOLOR3FVPROC glad_glColor3fv = NULL; +PFNGLCOLOR3IPROC glad_glColor3i = NULL; +PFNGLCOLOR3IVPROC glad_glColor3iv = NULL; +PFNGLCOLOR3SPROC glad_glColor3s = NULL; +PFNGLCOLOR3SVPROC glad_glColor3sv = NULL; +PFNGLCOLOR3UBPROC glad_glColor3ub = NULL; +PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL; +PFNGLCOLOR3UIPROC glad_glColor3ui = NULL; +PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL; +PFNGLCOLOR3USPROC glad_glColor3us = NULL; +PFNGLCOLOR3USVPROC glad_glColor3usv = NULL; +PFNGLCOLOR4BPROC glad_glColor4b = NULL; +PFNGLCOLOR4BVPROC glad_glColor4bv = NULL; +PFNGLCOLOR4DPROC glad_glColor4d = NULL; +PFNGLCOLOR4DVPROC glad_glColor4dv = NULL; +PFNGLCOLOR4FPROC glad_glColor4f = NULL; +PFNGLCOLOR4FVPROC glad_glColor4fv = NULL; +PFNGLCOLOR4IPROC glad_glColor4i = NULL; +PFNGLCOLOR4IVPROC glad_glColor4iv = NULL; +PFNGLCOLOR4SPROC glad_glColor4s = NULL; +PFNGLCOLOR4SVPROC glad_glColor4sv = NULL; +PFNGLCOLOR4UBPROC glad_glColor4ub = NULL; +PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL; +PFNGLCOLOR4UIPROC glad_glColor4ui = NULL; +PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL; +PFNGLCOLOR4USPROC glad_glColor4us = NULL; +PFNGLCOLOR4USVPROC glad_glColor4usv = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL; +PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB = NULL; +PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL; +PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL; +PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT = NULL; +PFNGLDELETELISTSPROC glad_glDeleteLists = NULL; +PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB = NULL; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; +PFNGLDELETEQUERIESARBPROC glad_glDeleteQueriesARB = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; +PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB = NULL; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; +PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB = NULL; +PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; +PFNGLDRAWRANGEELEMENTSEXTPROC glad_glDrawRangeElementsEXT = NULL; +PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL; +PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL; +PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB = NULL; +PFNGLENDPROC glad_glEnd = NULL; +PFNGLENDLISTPROC glad_glEndList = NULL; +PFNGLENDQUERYPROC glad_glEndQuery = NULL; +PFNGLENDQUERYARBPROC glad_glEndQueryARB = NULL; +PFNGLENDTRANSFORMFEEDBACKEXTPROC glad_glEndTransformFeedbackEXT = NULL; +PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL; +PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL; +PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL; +PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL; +PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL; +PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL; +PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL; +PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL; +PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL; +PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL; +PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL; +PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL; +PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL; +PFNGLFENCESYNCPROC glad_glFenceSync = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; +PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL; +PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL; +PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL; +PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL; +PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL; +PFNGLFOGFPROC glad_glFogf = NULL; +PFNGLFOGFVPROC glad_glFogfv = NULL; +PFNGLFOGIPROC glad_glFogi = NULL; +PFNGLFOGIVPROC glad_glFogiv = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB = NULL; +PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB = NULL; +PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glad_glFramebufferTextureLayerEXT = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLFRUSTUMPROC glad_glFrustum = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT = NULL; +PFNGLGENLISTSPROC glad_glGenLists = NULL; +PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB = NULL; +PFNGLGENQUERIESPROC glad_glGenQueries = NULL; +PFNGLGENQUERIESARBPROC glad_glGenQueriesARB = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB = NULL; +PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB = NULL; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; +PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB = NULL; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; +PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB = NULL; +PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB = NULL; +PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL; +PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATALOCATIONEXTPROC glad_glGetFragDataLocationEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGETHANDLEARBPROC glad_glGetHandleARB = NULL; +PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB = NULL; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL; +PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL; +PFNGLGETMAPDVPROC glad_glGetMapdv = NULL; +PFNGLGETMAPFVPROC glad_glGetMapfv = NULL; +PFNGLGETMAPIVPROC glad_glGetMapiv = NULL; +PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL; +PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; +PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL; +PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB = NULL; +PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB = NULL; +PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL; +PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL; +PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL; +PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL; +PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; +PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL; +PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB = NULL; +PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB = NULL; +PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB = NULL; +PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB = NULL; +PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; +PFNGLGETQUERYOBJECTIVARBPROC glad_glGetQueryObjectivARB = NULL; +PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; +PFNGLGETQUERYOBJECTUIVARBPROC glad_glGetQueryObjectuivARB = NULL; +PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; +PFNGLGETQUERYIVARBPROC glad_glGetQueryivARB = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; +PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL; +PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL; +PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL; +PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL; +PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC glad_glGetTransformFeedbackVaryingEXT = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB = NULL; +PFNGLGETUNIFORMUIVEXTPROC glad_glGetUniformuivEXT = NULL; +PFNGLGETVERTEXATTRIBIIVEXTPROC glad_glGetVertexAttribIivEXT = NULL; +PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB = NULL; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; +PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLINDEXMASKPROC glad_glIndexMask = NULL; +PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL; +PFNGLINDEXDPROC glad_glIndexd = NULL; +PFNGLINDEXDVPROC glad_glIndexdv = NULL; +PFNGLINDEXFPROC glad_glIndexf = NULL; +PFNGLINDEXFVPROC glad_glIndexfv = NULL; +PFNGLINDEXIPROC glad_glIndexi = NULL; +PFNGLINDEXIVPROC glad_glIndexiv = NULL; +PFNGLINDEXSPROC glad_glIndexs = NULL; +PFNGLINDEXSVPROC glad_glIndexsv = NULL; +PFNGLINDEXUBPROC glad_glIndexub = NULL; +PFNGLINDEXUBVPROC glad_glIndexubv = NULL; +PFNGLINITNAMESPROC glad_glInitNames = NULL; +PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISBUFFERARBPROC glad_glIsBufferARB = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT = NULL; +PFNGLISLISTPROC glad_glIsList = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISPROGRAMARBPROC glad_glIsProgramARB = NULL; +PFNGLISQUERYPROC glad_glIsQuery = NULL; +PFNGLISQUERYARBPROC glad_glIsQueryARB = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISSYNCPROC glad_glIsSync = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL; +PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL; +PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL; +PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL; +PFNGLLIGHTFPROC glad_glLightf = NULL; +PFNGLLIGHTFVPROC glad_glLightfv = NULL; +PFNGLLIGHTIPROC glad_glLighti = NULL; +PFNGLLIGHTIVPROC glad_glLightiv = NULL; +PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB = NULL; +PFNGLLISTBASEPROC glad_glListBase = NULL; +PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL; +PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL; +PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL; +PFNGLLOADNAMEPROC glad_glLoadName = NULL; +PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL; +PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL; +PFNGLLOGICOPPROC glad_glLogicOp = NULL; +PFNGLMAP1DPROC glad_glMap1d = NULL; +PFNGLMAP1FPROC glad_glMap1f = NULL; +PFNGLMAP2DPROC glad_glMap2d = NULL; +PFNGLMAP2FPROC glad_glMap2f = NULL; +PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; +PFNGLMAPBUFFERARBPROC glad_glMapBufferARB = NULL; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; +PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL; +PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL; +PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL; +PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL; +PFNGLMATERIALFPROC glad_glMaterialf = NULL; +PFNGLMATERIALFVPROC glad_glMaterialfv = NULL; +PFNGLMATERIALIPROC glad_glMateriali = NULL; +PFNGLMATERIALIVPROC glad_glMaterialiv = NULL; +PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL; +PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL; +PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL; +PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL; +PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; +PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL; +PFNGLMULTITEXCOORD1DARBPROC glad_glMultiTexCoord1dARB = NULL; +PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL; +PFNGLMULTITEXCOORD1DVARBPROC glad_glMultiTexCoord1dvARB = NULL; +PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL; +PFNGLMULTITEXCOORD1FARBPROC glad_glMultiTexCoord1fARB = NULL; +PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL; +PFNGLMULTITEXCOORD1FVARBPROC glad_glMultiTexCoord1fvARB = NULL; +PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL; +PFNGLMULTITEXCOORD1IARBPROC glad_glMultiTexCoord1iARB = NULL; +PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL; +PFNGLMULTITEXCOORD1IVARBPROC glad_glMultiTexCoord1ivARB = NULL; +PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL; +PFNGLMULTITEXCOORD1SARBPROC glad_glMultiTexCoord1sARB = NULL; +PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL; +PFNGLMULTITEXCOORD1SVARBPROC glad_glMultiTexCoord1svARB = NULL; +PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL; +PFNGLMULTITEXCOORD2DARBPROC glad_glMultiTexCoord2dARB = NULL; +PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL; +PFNGLMULTITEXCOORD2DVARBPROC glad_glMultiTexCoord2dvARB = NULL; +PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL; +PFNGLMULTITEXCOORD2FARBPROC glad_glMultiTexCoord2fARB = NULL; +PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL; +PFNGLMULTITEXCOORD2FVARBPROC glad_glMultiTexCoord2fvARB = NULL; +PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL; +PFNGLMULTITEXCOORD2IARBPROC glad_glMultiTexCoord2iARB = NULL; +PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL; +PFNGLMULTITEXCOORD2IVARBPROC glad_glMultiTexCoord2ivARB = NULL; +PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL; +PFNGLMULTITEXCOORD2SARBPROC glad_glMultiTexCoord2sARB = NULL; +PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL; +PFNGLMULTITEXCOORD2SVARBPROC glad_glMultiTexCoord2svARB = NULL; +PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL; +PFNGLMULTITEXCOORD3DARBPROC glad_glMultiTexCoord3dARB = NULL; +PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL; +PFNGLMULTITEXCOORD3DVARBPROC glad_glMultiTexCoord3dvARB = NULL; +PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL; +PFNGLMULTITEXCOORD3FARBPROC glad_glMultiTexCoord3fARB = NULL; +PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL; +PFNGLMULTITEXCOORD3FVARBPROC glad_glMultiTexCoord3fvARB = NULL; +PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL; +PFNGLMULTITEXCOORD3IARBPROC glad_glMultiTexCoord3iARB = NULL; +PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL; +PFNGLMULTITEXCOORD3IVARBPROC glad_glMultiTexCoord3ivARB = NULL; +PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL; +PFNGLMULTITEXCOORD3SARBPROC glad_glMultiTexCoord3sARB = NULL; +PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL; +PFNGLMULTITEXCOORD3SVARBPROC glad_glMultiTexCoord3svARB = NULL; +PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL; +PFNGLMULTITEXCOORD4DARBPROC glad_glMultiTexCoord4dARB = NULL; +PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL; +PFNGLMULTITEXCOORD4DVARBPROC glad_glMultiTexCoord4dvARB = NULL; +PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL; +PFNGLMULTITEXCOORD4FARBPROC glad_glMultiTexCoord4fARB = NULL; +PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL; +PFNGLMULTITEXCOORD4FVARBPROC glad_glMultiTexCoord4fvARB = NULL; +PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL; +PFNGLMULTITEXCOORD4IARBPROC glad_glMultiTexCoord4iARB = NULL; +PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL; +PFNGLMULTITEXCOORD4IVARBPROC glad_glMultiTexCoord4ivARB = NULL; +PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL; +PFNGLMULTITEXCOORD4SARBPROC glad_glMultiTexCoord4sARB = NULL; +PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL; +PFNGLMULTITEXCOORD4SVARBPROC glad_glMultiTexCoord4svARB = NULL; +PFNGLNEWLISTPROC glad_glNewList = NULL; +PFNGLNORMAL3BPROC glad_glNormal3b = NULL; +PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL; +PFNGLNORMAL3DPROC glad_glNormal3d = NULL; +PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL; +PFNGLNORMAL3FPROC glad_glNormal3f = NULL; +PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL; +PFNGLNORMAL3IPROC glad_glNormal3i = NULL; +PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL; +PFNGLNORMAL3SPROC glad_glNormal3s = NULL; +PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL; +PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL; +PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL; +PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL; +PFNGLORTHOPROC glad_glOrtho = NULL; +PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL; +PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL; +PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL; +PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL; +PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL; +PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL; +PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; +PFNGLPOINTSIZEPROC glad_glPointSize = NULL; +PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL; +PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL; +PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL; +PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL; +PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL; +PFNGLPOPNAMEPROC glad_glPopName = NULL; +PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL; +PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB = NULL; +PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB = NULL; +PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB = NULL; +PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB = NULL; +PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB = NULL; +PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB = NULL; +PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL; +PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL; +PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL; +PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL; +PFNGLPUSHNAMEPROC glad_glPushName = NULL; +PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; +PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL; +PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL; +PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL; +PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL; +PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL; +PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL; +PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL; +PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL; +PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL; +PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL; +PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL; +PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL; +PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL; +PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL; +PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL; +PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL; +PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL; +PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL; +PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL; +PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL; +PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL; +PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL; +PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL; +PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL; +PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRECTDPROC glad_glRectd = NULL; +PFNGLRECTDVPROC glad_glRectdv = NULL; +PFNGLRECTFPROC glad_glRectf = NULL; +PFNGLRECTFVPROC glad_glRectfv = NULL; +PFNGLRECTIPROC glad_glRecti = NULL; +PFNGLRECTIVPROC glad_glRectiv = NULL; +PFNGLRECTSPROC glad_glRects = NULL; +PFNGLRECTSVPROC glad_glRectsv = NULL; +PFNGLRENDERMODEPROC glad_glRenderMode = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL; +PFNGLROTATEDPROC glad_glRotated = NULL; +PFNGLROTATEFPROC glad_glRotatef = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; +PFNGLSCALEDPROC glad_glScaled = NULL; +PFNGLSCALEFPROC glad_glScalef = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL; +PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL; +PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL; +PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL; +PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL; +PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL; +PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL; +PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL; +PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL; +PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL; +PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL; +PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL; +PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL; +PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL; +PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL; +PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL; +PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL; +PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL; +PFNGLSHADEMODELPROC glad_glShadeModel = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL; +PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL; +PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL; +PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL; +PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL; +PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL; +PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL; +PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL; +PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL; +PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL; +PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL; +PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL; +PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL; +PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL; +PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL; +PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL; +PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL; +PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL; +PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL; +PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL; +PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL; +PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL; +PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL; +PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL; +PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL; +PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL; +PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL; +PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL; +PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL; +PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL; +PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL; +PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL; +PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL; +PFNGLTEXENVFPROC glad_glTexEnvf = NULL; +PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL; +PFNGLTEXENVIPROC glad_glTexEnvi = NULL; +PFNGLTEXENVIVPROC glad_glTexEnviv = NULL; +PFNGLTEXGENDPROC glad_glTexGend = NULL; +PFNGLTEXGENDVPROC glad_glTexGendv = NULL; +PFNGLTEXGENFPROC glad_glTexGenf = NULL; +PFNGLTEXGENFVPROC glad_glTexGenfv = NULL; +PFNGLTEXGENIPROC glad_glTexGeni = NULL; +PFNGLTEXGENIVPROC glad_glTexGeniv = NULL; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC glad_glTransformFeedbackVaryingsEXT = NULL; +PFNGLTRANSLATEDPROC glad_glTranslated = NULL; +PFNGLTRANSLATEFPROC glad_glTranslatef = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FARBPROC glad_glUniform1fARB = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IARBPROC glad_glUniform1iARB = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB = NULL; +PFNGLUNIFORM1UIEXTPROC glad_glUniform1uiEXT = NULL; +PFNGLUNIFORM1UIVEXTPROC glad_glUniform1uivEXT = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FARBPROC glad_glUniform2fARB = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IARBPROC glad_glUniform2iARB = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB = NULL; +PFNGLUNIFORM2UIEXTPROC glad_glUniform2uiEXT = NULL; +PFNGLUNIFORM2UIVEXTPROC glad_glUniform2uivEXT = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FARBPROC glad_glUniform3fARB = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IARBPROC glad_glUniform3iARB = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB = NULL; +PFNGLUNIFORM3UIEXTPROC glad_glUniform3uiEXT = NULL; +PFNGLUNIFORM3UIVEXTPROC glad_glUniform3uivEXT = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FARBPROC glad_glUniform4fARB = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IARBPROC glad_glUniform4iARB = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB = NULL; +PFNGLUNIFORM4UIEXTPROC glad_glUniform4uiEXT = NULL; +PFNGLUNIFORM4UIVEXTPROC glad_glUniform4uivEXT = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB = NULL; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB = NULL; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB = NULL; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; +PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB = NULL; +PFNGLVERTEX2DPROC glad_glVertex2d = NULL; +PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL; +PFNGLVERTEX2FPROC glad_glVertex2f = NULL; +PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL; +PFNGLVERTEX2IPROC glad_glVertex2i = NULL; +PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL; +PFNGLVERTEX2SPROC glad_glVertex2s = NULL; +PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL; +PFNGLVERTEX3DPROC glad_glVertex3d = NULL; +PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL; +PFNGLVERTEX3FPROC glad_glVertex3f = NULL; +PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL; +PFNGLVERTEX3IPROC glad_glVertex3i = NULL; +PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL; +PFNGLVERTEX3SPROC glad_glVertex3s = NULL; +PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL; +PFNGLVERTEX4DPROC glad_glVertex4d = NULL; +PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL; +PFNGLVERTEX4FPROC glad_glVertex4f = NULL; +PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL; +PFNGLVERTEX4IPROC glad_glVertex4i = NULL; +PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL; +PFNGLVERTEX4SPROC glad_glVertex4s = NULL; +PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; +PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB = NULL; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; +PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB = NULL; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; +PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB = NULL; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; +PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB = NULL; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; +PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB = NULL; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; +PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB = NULL; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; +PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB = NULL; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; +PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB = NULL; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; +PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB = NULL; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; +PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB = NULL; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; +PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB = NULL; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; +PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB = NULL; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; +PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB = NULL; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; +PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB = NULL; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; +PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB = NULL; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; +PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB = NULL; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; +PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB = NULL; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; +PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB = NULL; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; +PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB = NULL; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; +PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB = NULL; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; +PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB = NULL; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; +PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB = NULL; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; +PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB = NULL; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; +PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB = NULL; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; +PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB = NULL; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; +PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB = NULL; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; +PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB = NULL; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; +PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB = NULL; +PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB = NULL; +PFNGLVERTEXATTRIBI1IEXTPROC glad_glVertexAttribI1iEXT = NULL; +PFNGLVERTEXATTRIBI1IVEXTPROC glad_glVertexAttribI1ivEXT = NULL; +PFNGLVERTEXATTRIBI1UIEXTPROC glad_glVertexAttribI1uiEXT = NULL; +PFNGLVERTEXATTRIBI1UIVEXTPROC glad_glVertexAttribI1uivEXT = NULL; +PFNGLVERTEXATTRIBI2IEXTPROC glad_glVertexAttribI2iEXT = NULL; +PFNGLVERTEXATTRIBI2IVEXTPROC glad_glVertexAttribI2ivEXT = NULL; +PFNGLVERTEXATTRIBI2UIEXTPROC glad_glVertexAttribI2uiEXT = NULL; +PFNGLVERTEXATTRIBI2UIVEXTPROC glad_glVertexAttribI2uivEXT = NULL; +PFNGLVERTEXATTRIBI3IEXTPROC glad_glVertexAttribI3iEXT = NULL; +PFNGLVERTEXATTRIBI3IVEXTPROC glad_glVertexAttribI3ivEXT = NULL; +PFNGLVERTEXATTRIBI3UIEXTPROC glad_glVertexAttribI3uiEXT = NULL; +PFNGLVERTEXATTRIBI3UIVEXTPROC glad_glVertexAttribI3uivEXT = NULL; +PFNGLVERTEXATTRIBI4BVEXTPROC glad_glVertexAttribI4bvEXT = NULL; +PFNGLVERTEXATTRIBI4IEXTPROC glad_glVertexAttribI4iEXT = NULL; +PFNGLVERTEXATTRIBI4IVEXTPROC glad_glVertexAttribI4ivEXT = NULL; +PFNGLVERTEXATTRIBI4SVEXTPROC glad_glVertexAttribI4svEXT = NULL; +PFNGLVERTEXATTRIBI4UBVEXTPROC glad_glVertexAttribI4ubvEXT = NULL; +PFNGLVERTEXATTRIBI4UIEXTPROC glad_glVertexAttribI4uiEXT = NULL; +PFNGLVERTEXATTRIBI4UIVEXTPROC glad_glVertexAttribI4uivEXT = NULL; +PFNGLVERTEXATTRIBI4USVEXTPROC glad_glVertexAttribI4usvEXT = NULL; +PFNGLVERTEXATTRIBIPOINTEREXTPROC glad_glVertexAttribIPointerEXT = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB = NULL; +PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +PFNGLWAITSYNCPROC glad_glWaitSync = NULL; +PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL; +PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL; +PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL; +PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL; +PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL; +PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL; +PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL; +PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL; +PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL; +PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL; +PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL; +PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL; +PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL; +PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; +PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; +PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; + + +static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glAccum = (PFNGLACCUMPROC) load(userptr, "glAccum"); + glad_glAlphaFunc = (PFNGLALPHAFUNCPROC) load(userptr, "glAlphaFunc"); + glad_glBegin = (PFNGLBEGINPROC) load(userptr, "glBegin"); + glad_glBitmap = (PFNGLBITMAPPROC) load(userptr, "glBitmap"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); + glad_glCallList = (PFNGLCALLLISTPROC) load(userptr, "glCallList"); + glad_glCallLists = (PFNGLCALLLISTSPROC) load(userptr, "glCallLists"); + glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); + glad_glClearAccum = (PFNGLCLEARACCUMPROC) load(userptr, "glClearAccum"); + glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, "glClearDepth"); + glad_glClearIndex = (PFNGLCLEARINDEXPROC) load(userptr, "glClearIndex"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); + glad_glClipPlane = (PFNGLCLIPPLANEPROC) load(userptr, "glClipPlane"); + glad_glColor3b = (PFNGLCOLOR3BPROC) load(userptr, "glColor3b"); + glad_glColor3bv = (PFNGLCOLOR3BVPROC) load(userptr, "glColor3bv"); + glad_glColor3d = (PFNGLCOLOR3DPROC) load(userptr, "glColor3d"); + glad_glColor3dv = (PFNGLCOLOR3DVPROC) load(userptr, "glColor3dv"); + glad_glColor3f = (PFNGLCOLOR3FPROC) load(userptr, "glColor3f"); + glad_glColor3fv = (PFNGLCOLOR3FVPROC) load(userptr, "glColor3fv"); + glad_glColor3i = (PFNGLCOLOR3IPROC) load(userptr, "glColor3i"); + glad_glColor3iv = (PFNGLCOLOR3IVPROC) load(userptr, "glColor3iv"); + glad_glColor3s = (PFNGLCOLOR3SPROC) load(userptr, "glColor3s"); + glad_glColor3sv = (PFNGLCOLOR3SVPROC) load(userptr, "glColor3sv"); + glad_glColor3ub = (PFNGLCOLOR3UBPROC) load(userptr, "glColor3ub"); + glad_glColor3ubv = (PFNGLCOLOR3UBVPROC) load(userptr, "glColor3ubv"); + glad_glColor3ui = (PFNGLCOLOR3UIPROC) load(userptr, "glColor3ui"); + glad_glColor3uiv = (PFNGLCOLOR3UIVPROC) load(userptr, "glColor3uiv"); + glad_glColor3us = (PFNGLCOLOR3USPROC) load(userptr, "glColor3us"); + glad_glColor3usv = (PFNGLCOLOR3USVPROC) load(userptr, "glColor3usv"); + glad_glColor4b = (PFNGLCOLOR4BPROC) load(userptr, "glColor4b"); + glad_glColor4bv = (PFNGLCOLOR4BVPROC) load(userptr, "glColor4bv"); + glad_glColor4d = (PFNGLCOLOR4DPROC) load(userptr, "glColor4d"); + glad_glColor4dv = (PFNGLCOLOR4DVPROC) load(userptr, "glColor4dv"); + glad_glColor4f = (PFNGLCOLOR4FPROC) load(userptr, "glColor4f"); + glad_glColor4fv = (PFNGLCOLOR4FVPROC) load(userptr, "glColor4fv"); + glad_glColor4i = (PFNGLCOLOR4IPROC) load(userptr, "glColor4i"); + glad_glColor4iv = (PFNGLCOLOR4IVPROC) load(userptr, "glColor4iv"); + glad_glColor4s = (PFNGLCOLOR4SPROC) load(userptr, "glColor4s"); + glad_glColor4sv = (PFNGLCOLOR4SVPROC) load(userptr, "glColor4sv"); + glad_glColor4ub = (PFNGLCOLOR4UBPROC) load(userptr, "glColor4ub"); + glad_glColor4ubv = (PFNGLCOLOR4UBVPROC) load(userptr, "glColor4ubv"); + glad_glColor4ui = (PFNGLCOLOR4UIPROC) load(userptr, "glColor4ui"); + glad_glColor4uiv = (PFNGLCOLOR4UIVPROC) load(userptr, "glColor4uiv"); + glad_glColor4us = (PFNGLCOLOR4USPROC) load(userptr, "glColor4us"); + glad_glColor4usv = (PFNGLCOLOR4USVPROC) load(userptr, "glColor4usv"); + glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); + glad_glColorMaterial = (PFNGLCOLORMATERIALPROC) load(userptr, "glColorMaterial"); + glad_glCopyPixels = (PFNGLCOPYPIXELSPROC) load(userptr, "glCopyPixels"); + glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); + glad_glDeleteLists = (PFNGLDELETELISTSPROC) load(userptr, "glDeleteLists"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, "glDepthRange"); + glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, "glDrawBuffer"); + glad_glDrawPixels = (PFNGLDRAWPIXELSPROC) load(userptr, "glDrawPixels"); + glad_glEdgeFlag = (PFNGLEDGEFLAGPROC) load(userptr, "glEdgeFlag"); + glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC) load(userptr, "glEdgeFlagv"); + glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); + glad_glEnd = (PFNGLENDPROC) load(userptr, "glEnd"); + glad_glEndList = (PFNGLENDLISTPROC) load(userptr, "glEndList"); + glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC) load(userptr, "glEvalCoord1d"); + glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC) load(userptr, "glEvalCoord1dv"); + glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC) load(userptr, "glEvalCoord1f"); + glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC) load(userptr, "glEvalCoord1fv"); + glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC) load(userptr, "glEvalCoord2d"); + glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC) load(userptr, "glEvalCoord2dv"); + glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC) load(userptr, "glEvalCoord2f"); + glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC) load(userptr, "glEvalCoord2fv"); + glad_glEvalMesh1 = (PFNGLEVALMESH1PROC) load(userptr, "glEvalMesh1"); + glad_glEvalMesh2 = (PFNGLEVALMESH2PROC) load(userptr, "glEvalMesh2"); + glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC) load(userptr, "glEvalPoint1"); + glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC) load(userptr, "glEvalPoint2"); + glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC) load(userptr, "glFeedbackBuffer"); + glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); + glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); + glad_glFogf = (PFNGLFOGFPROC) load(userptr, "glFogf"); + glad_glFogfv = (PFNGLFOGFVPROC) load(userptr, "glFogfv"); + glad_glFogi = (PFNGLFOGIPROC) load(userptr, "glFogi"); + glad_glFogiv = (PFNGLFOGIVPROC) load(userptr, "glFogiv"); + glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); + glad_glFrustum = (PFNGLFRUSTUMPROC) load(userptr, "glFrustum"); + glad_glGenLists = (PFNGLGENLISTSPROC) load(userptr, "glGenLists"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); + glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC) load(userptr, "glGetClipPlane"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, "glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); + glad_glGetLightfv = (PFNGLGETLIGHTFVPROC) load(userptr, "glGetLightfv"); + glad_glGetLightiv = (PFNGLGETLIGHTIVPROC) load(userptr, "glGetLightiv"); + glad_glGetMapdv = (PFNGLGETMAPDVPROC) load(userptr, "glGetMapdv"); + glad_glGetMapfv = (PFNGLGETMAPFVPROC) load(userptr, "glGetMapfv"); + glad_glGetMapiv = (PFNGLGETMAPIVPROC) load(userptr, "glGetMapiv"); + glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC) load(userptr, "glGetMaterialfv"); + glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC) load(userptr, "glGetMaterialiv"); + glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC) load(userptr, "glGetPixelMapfv"); + glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC) load(userptr, "glGetPixelMapuiv"); + glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC) load(userptr, "glGetPixelMapusv"); + glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC) load(userptr, "glGetPolygonStipple"); + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC) load(userptr, "glGetTexEnvfv"); + glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC) load(userptr, "glGetTexEnviv"); + glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC) load(userptr, "glGetTexGendv"); + glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC) load(userptr, "glGetTexGenfv"); + glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC) load(userptr, "glGetTexGeniv"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, "glGetTexImage"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); + glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); + glad_glIndexMask = (PFNGLINDEXMASKPROC) load(userptr, "glIndexMask"); + glad_glIndexd = (PFNGLINDEXDPROC) load(userptr, "glIndexd"); + glad_glIndexdv = (PFNGLINDEXDVPROC) load(userptr, "glIndexdv"); + glad_glIndexf = (PFNGLINDEXFPROC) load(userptr, "glIndexf"); + glad_glIndexfv = (PFNGLINDEXFVPROC) load(userptr, "glIndexfv"); + glad_glIndexi = (PFNGLINDEXIPROC) load(userptr, "glIndexi"); + glad_glIndexiv = (PFNGLINDEXIVPROC) load(userptr, "glIndexiv"); + glad_glIndexs = (PFNGLINDEXSPROC) load(userptr, "glIndexs"); + glad_glIndexsv = (PFNGLINDEXSVPROC) load(userptr, "glIndexsv"); + glad_glInitNames = (PFNGLINITNAMESPROC) load(userptr, "glInitNames"); + glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); + glad_glIsList = (PFNGLISLISTPROC) load(userptr, "glIsList"); + glad_glLightModelf = (PFNGLLIGHTMODELFPROC) load(userptr, "glLightModelf"); + glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC) load(userptr, "glLightModelfv"); + glad_glLightModeli = (PFNGLLIGHTMODELIPROC) load(userptr, "glLightModeli"); + glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC) load(userptr, "glLightModeliv"); + glad_glLightf = (PFNGLLIGHTFPROC) load(userptr, "glLightf"); + glad_glLightfv = (PFNGLLIGHTFVPROC) load(userptr, "glLightfv"); + glad_glLighti = (PFNGLLIGHTIPROC) load(userptr, "glLighti"); + glad_glLightiv = (PFNGLLIGHTIVPROC) load(userptr, "glLightiv"); + glad_glLineStipple = (PFNGLLINESTIPPLEPROC) load(userptr, "glLineStipple"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); + glad_glListBase = (PFNGLLISTBASEPROC) load(userptr, "glListBase"); + glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC) load(userptr, "glLoadIdentity"); + glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC) load(userptr, "glLoadMatrixd"); + glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC) load(userptr, "glLoadMatrixf"); + glad_glLoadName = (PFNGLLOADNAMEPROC) load(userptr, "glLoadName"); + glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, "glLogicOp"); + glad_glMap1d = (PFNGLMAP1DPROC) load(userptr, "glMap1d"); + glad_glMap1f = (PFNGLMAP1FPROC) load(userptr, "glMap1f"); + glad_glMap2d = (PFNGLMAP2DPROC) load(userptr, "glMap2d"); + glad_glMap2f = (PFNGLMAP2FPROC) load(userptr, "glMap2f"); + glad_glMapGrid1d = (PFNGLMAPGRID1DPROC) load(userptr, "glMapGrid1d"); + glad_glMapGrid1f = (PFNGLMAPGRID1FPROC) load(userptr, "glMapGrid1f"); + glad_glMapGrid2d = (PFNGLMAPGRID2DPROC) load(userptr, "glMapGrid2d"); + glad_glMapGrid2f = (PFNGLMAPGRID2FPROC) load(userptr, "glMapGrid2f"); + glad_glMaterialf = (PFNGLMATERIALFPROC) load(userptr, "glMaterialf"); + glad_glMaterialfv = (PFNGLMATERIALFVPROC) load(userptr, "glMaterialfv"); + glad_glMateriali = (PFNGLMATERIALIPROC) load(userptr, "glMateriali"); + glad_glMaterialiv = (PFNGLMATERIALIVPROC) load(userptr, "glMaterialiv"); + glad_glMatrixMode = (PFNGLMATRIXMODEPROC) load(userptr, "glMatrixMode"); + glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC) load(userptr, "glMultMatrixd"); + glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC) load(userptr, "glMultMatrixf"); + glad_glNewList = (PFNGLNEWLISTPROC) load(userptr, "glNewList"); + glad_glNormal3b = (PFNGLNORMAL3BPROC) load(userptr, "glNormal3b"); + glad_glNormal3bv = (PFNGLNORMAL3BVPROC) load(userptr, "glNormal3bv"); + glad_glNormal3d = (PFNGLNORMAL3DPROC) load(userptr, "glNormal3d"); + glad_glNormal3dv = (PFNGLNORMAL3DVPROC) load(userptr, "glNormal3dv"); + glad_glNormal3f = (PFNGLNORMAL3FPROC) load(userptr, "glNormal3f"); + glad_glNormal3fv = (PFNGLNORMAL3FVPROC) load(userptr, "glNormal3fv"); + glad_glNormal3i = (PFNGLNORMAL3IPROC) load(userptr, "glNormal3i"); + glad_glNormal3iv = (PFNGLNORMAL3IVPROC) load(userptr, "glNormal3iv"); + glad_glNormal3s = (PFNGLNORMAL3SPROC) load(userptr, "glNormal3s"); + glad_glNormal3sv = (PFNGLNORMAL3SVPROC) load(userptr, "glNormal3sv"); + glad_glOrtho = (PFNGLORTHOPROC) load(userptr, "glOrtho"); + glad_glPassThrough = (PFNGLPASSTHROUGHPROC) load(userptr, "glPassThrough"); + glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC) load(userptr, "glPixelMapfv"); + glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC) load(userptr, "glPixelMapuiv"); + glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC) load(userptr, "glPixelMapusv"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, "glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); + glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC) load(userptr, "glPixelTransferf"); + glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC) load(userptr, "glPixelTransferi"); + glad_glPixelZoom = (PFNGLPIXELZOOMPROC) load(userptr, "glPixelZoom"); + glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, "glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, "glPolygonMode"); + glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC) load(userptr, "glPolygonStipple"); + glad_glPopAttrib = (PFNGLPOPATTRIBPROC) load(userptr, "glPopAttrib"); + glad_glPopMatrix = (PFNGLPOPMATRIXPROC) load(userptr, "glPopMatrix"); + glad_glPopName = (PFNGLPOPNAMEPROC) load(userptr, "glPopName"); + glad_glPushAttrib = (PFNGLPUSHATTRIBPROC) load(userptr, "glPushAttrib"); + glad_glPushMatrix = (PFNGLPUSHMATRIXPROC) load(userptr, "glPushMatrix"); + glad_glPushName = (PFNGLPUSHNAMEPROC) load(userptr, "glPushName"); + glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC) load(userptr, "glRasterPos2d"); + glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC) load(userptr, "glRasterPos2dv"); + glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC) load(userptr, "glRasterPos2f"); + glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC) load(userptr, "glRasterPos2fv"); + glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC) load(userptr, "glRasterPos2i"); + glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC) load(userptr, "glRasterPos2iv"); + glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC) load(userptr, "glRasterPos2s"); + glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC) load(userptr, "glRasterPos2sv"); + glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC) load(userptr, "glRasterPos3d"); + glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC) load(userptr, "glRasterPos3dv"); + glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC) load(userptr, "glRasterPos3f"); + glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC) load(userptr, "glRasterPos3fv"); + glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC) load(userptr, "glRasterPos3i"); + glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC) load(userptr, "glRasterPos3iv"); + glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC) load(userptr, "glRasterPos3s"); + glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC) load(userptr, "glRasterPos3sv"); + glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC) load(userptr, "glRasterPos4d"); + glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC) load(userptr, "glRasterPos4dv"); + glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC) load(userptr, "glRasterPos4f"); + glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC) load(userptr, "glRasterPos4fv"); + glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC) load(userptr, "glRasterPos4i"); + glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC) load(userptr, "glRasterPos4iv"); + glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC) load(userptr, "glRasterPos4s"); + glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC) load(userptr, "glRasterPos4sv"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); + glad_glRectd = (PFNGLRECTDPROC) load(userptr, "glRectd"); + glad_glRectdv = (PFNGLRECTDVPROC) load(userptr, "glRectdv"); + glad_glRectf = (PFNGLRECTFPROC) load(userptr, "glRectf"); + glad_glRectfv = (PFNGLRECTFVPROC) load(userptr, "glRectfv"); + glad_glRecti = (PFNGLRECTIPROC) load(userptr, "glRecti"); + glad_glRectiv = (PFNGLRECTIVPROC) load(userptr, "glRectiv"); + glad_glRects = (PFNGLRECTSPROC) load(userptr, "glRects"); + glad_glRectsv = (PFNGLRECTSVPROC) load(userptr, "glRectsv"); + glad_glRenderMode = (PFNGLRENDERMODEPROC) load(userptr, "glRenderMode"); + glad_glRotated = (PFNGLROTATEDPROC) load(userptr, "glRotated"); + glad_glRotatef = (PFNGLROTATEFPROC) load(userptr, "glRotatef"); + glad_glScaled = (PFNGLSCALEDPROC) load(userptr, "glScaled"); + glad_glScalef = (PFNGLSCALEFPROC) load(userptr, "glScalef"); + glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); + glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC) load(userptr, "glSelectBuffer"); + glad_glShadeModel = (PFNGLSHADEMODELPROC) load(userptr, "glShadeModel"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); + glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); + glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC) load(userptr, "glTexCoord1d"); + glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC) load(userptr, "glTexCoord1dv"); + glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC) load(userptr, "glTexCoord1f"); + glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC) load(userptr, "glTexCoord1fv"); + glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC) load(userptr, "glTexCoord1i"); + glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC) load(userptr, "glTexCoord1iv"); + glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC) load(userptr, "glTexCoord1s"); + glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC) load(userptr, "glTexCoord1sv"); + glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC) load(userptr, "glTexCoord2d"); + glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC) load(userptr, "glTexCoord2dv"); + glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC) load(userptr, "glTexCoord2f"); + glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC) load(userptr, "glTexCoord2fv"); + glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC) load(userptr, "glTexCoord2i"); + glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC) load(userptr, "glTexCoord2iv"); + glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC) load(userptr, "glTexCoord2s"); + glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC) load(userptr, "glTexCoord2sv"); + glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC) load(userptr, "glTexCoord3d"); + glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC) load(userptr, "glTexCoord3dv"); + glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC) load(userptr, "glTexCoord3f"); + glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC) load(userptr, "glTexCoord3fv"); + glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC) load(userptr, "glTexCoord3i"); + glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC) load(userptr, "glTexCoord3iv"); + glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC) load(userptr, "glTexCoord3s"); + glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC) load(userptr, "glTexCoord3sv"); + glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC) load(userptr, "glTexCoord4d"); + glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC) load(userptr, "glTexCoord4dv"); + glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC) load(userptr, "glTexCoord4f"); + glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC) load(userptr, "glTexCoord4fv"); + glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC) load(userptr, "glTexCoord4i"); + glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC) load(userptr, "glTexCoord4iv"); + glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC) load(userptr, "glTexCoord4s"); + glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC) load(userptr, "glTexCoord4sv"); + glad_glTexEnvf = (PFNGLTEXENVFPROC) load(userptr, "glTexEnvf"); + glad_glTexEnvfv = (PFNGLTEXENVFVPROC) load(userptr, "glTexEnvfv"); + glad_glTexEnvi = (PFNGLTEXENVIPROC) load(userptr, "glTexEnvi"); + glad_glTexEnviv = (PFNGLTEXENVIVPROC) load(userptr, "glTexEnviv"); + glad_glTexGend = (PFNGLTEXGENDPROC) load(userptr, "glTexGend"); + glad_glTexGendv = (PFNGLTEXGENDVPROC) load(userptr, "glTexGendv"); + glad_glTexGenf = (PFNGLTEXGENFPROC) load(userptr, "glTexGenf"); + glad_glTexGenfv = (PFNGLTEXGENFVPROC) load(userptr, "glTexGenfv"); + glad_glTexGeni = (PFNGLTEXGENIPROC) load(userptr, "glTexGeni"); + glad_glTexGeniv = (PFNGLTEXGENIVPROC) load(userptr, "glTexGeniv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, "glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); + glad_glTranslated = (PFNGLTRANSLATEDPROC) load(userptr, "glTranslated"); + glad_glTranslatef = (PFNGLTRANSLATEFPROC) load(userptr, "glTranslatef"); + glad_glVertex2d = (PFNGLVERTEX2DPROC) load(userptr, "glVertex2d"); + glad_glVertex2dv = (PFNGLVERTEX2DVPROC) load(userptr, "glVertex2dv"); + glad_glVertex2f = (PFNGLVERTEX2FPROC) load(userptr, "glVertex2f"); + glad_glVertex2fv = (PFNGLVERTEX2FVPROC) load(userptr, "glVertex2fv"); + glad_glVertex2i = (PFNGLVERTEX2IPROC) load(userptr, "glVertex2i"); + glad_glVertex2iv = (PFNGLVERTEX2IVPROC) load(userptr, "glVertex2iv"); + glad_glVertex2s = (PFNGLVERTEX2SPROC) load(userptr, "glVertex2s"); + glad_glVertex2sv = (PFNGLVERTEX2SVPROC) load(userptr, "glVertex2sv"); + glad_glVertex3d = (PFNGLVERTEX3DPROC) load(userptr, "glVertex3d"); + glad_glVertex3dv = (PFNGLVERTEX3DVPROC) load(userptr, "glVertex3dv"); + glad_glVertex3f = (PFNGLVERTEX3FPROC) load(userptr, "glVertex3f"); + glad_glVertex3fv = (PFNGLVERTEX3FVPROC) load(userptr, "glVertex3fv"); + glad_glVertex3i = (PFNGLVERTEX3IPROC) load(userptr, "glVertex3i"); + glad_glVertex3iv = (PFNGLVERTEX3IVPROC) load(userptr, "glVertex3iv"); + glad_glVertex3s = (PFNGLVERTEX3SPROC) load(userptr, "glVertex3s"); + glad_glVertex3sv = (PFNGLVERTEX3SVPROC) load(userptr, "glVertex3sv"); + glad_glVertex4d = (PFNGLVERTEX4DPROC) load(userptr, "glVertex4d"); + glad_glVertex4dv = (PFNGLVERTEX4DVPROC) load(userptr, "glVertex4dv"); + glad_glVertex4f = (PFNGLVERTEX4FPROC) load(userptr, "glVertex4f"); + glad_glVertex4fv = (PFNGLVERTEX4FVPROC) load(userptr, "glVertex4fv"); + glad_glVertex4i = (PFNGLVERTEX4IPROC) load(userptr, "glVertex4i"); + glad_glVertex4iv = (PFNGLVERTEX4IVPROC) load(userptr, "glVertex4iv"); + glad_glVertex4s = (PFNGLVERTEX4SPROC) load(userptr, "glVertex4s"); + glad_glVertex4sv = (PFNGLVERTEX4SVPROC) load(userptr, "glVertex4sv"); + glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); +} +static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC) load(userptr, "glAreTexturesResident"); + glad_glArrayElement = (PFNGLARRAYELEMENTPROC) load(userptr, "glArrayElement"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); + glad_glColorPointer = (PFNGLCOLORPOINTERPROC) load(userptr, "glColorPointer"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, "glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, "glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); + glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC) load(userptr, "glDisableClientState"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); + glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC) load(userptr, "glEdgeFlagPointer"); + glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC) load(userptr, "glEnableClientState"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv"); + glad_glIndexPointer = (PFNGLINDEXPOINTERPROC) load(userptr, "glIndexPointer"); + glad_glIndexub = (PFNGLINDEXUBPROC) load(userptr, "glIndexub"); + glad_glIndexubv = (PFNGLINDEXUBVPROC) load(userptr, "glIndexubv"); + glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC) load(userptr, "glInterleavedArrays"); + glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); + glad_glNormalPointer = (PFNGLNORMALPOINTERPROC) load(userptr, "glNormalPointer"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); + glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC) load(userptr, "glPopClientAttrib"); + glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC) load(userptr, "glPrioritizeTextures"); + glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC) load(userptr, "glPushClientAttrib"); + glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC) load(userptr, "glTexCoordPointer"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, "glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); + glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC) load(userptr, "glVertexPointer"); +} +static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D"); + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D"); +} +static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); + glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC) load(userptr, "glClientActiveTexture"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, "glCompressedTexImage1D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, "glCompressedTexSubImage1D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, "glGetCompressedTexImage"); + glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC) load(userptr, "glLoadTransposeMatrixd"); + glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC) load(userptr, "glLoadTransposeMatrixf"); + glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC) load(userptr, "glMultTransposeMatrixd"); + glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC) load(userptr, "glMultTransposeMatrixf"); + glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC) load(userptr, "glMultiTexCoord1d"); + glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC) load(userptr, "glMultiTexCoord1dv"); + glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC) load(userptr, "glMultiTexCoord1f"); + glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC) load(userptr, "glMultiTexCoord1fv"); + glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC) load(userptr, "glMultiTexCoord1i"); + glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC) load(userptr, "glMultiTexCoord1iv"); + glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC) load(userptr, "glMultiTexCoord1s"); + glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC) load(userptr, "glMultiTexCoord1sv"); + glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC) load(userptr, "glMultiTexCoord2d"); + glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC) load(userptr, "glMultiTexCoord2dv"); + glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC) load(userptr, "glMultiTexCoord2f"); + glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC) load(userptr, "glMultiTexCoord2fv"); + glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC) load(userptr, "glMultiTexCoord2i"); + glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC) load(userptr, "glMultiTexCoord2iv"); + glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC) load(userptr, "glMultiTexCoord2s"); + glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC) load(userptr, "glMultiTexCoord2sv"); + glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC) load(userptr, "glMultiTexCoord3d"); + glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC) load(userptr, "glMultiTexCoord3dv"); + glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC) load(userptr, "glMultiTexCoord3f"); + glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC) load(userptr, "glMultiTexCoord3fv"); + glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC) load(userptr, "glMultiTexCoord3i"); + glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC) load(userptr, "glMultiTexCoord3iv"); + glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC) load(userptr, "glMultiTexCoord3s"); + glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC) load(userptr, "glMultiTexCoord3sv"); + glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC) load(userptr, "glMultiTexCoord4d"); + glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC) load(userptr, "glMultiTexCoord4dv"); + glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC) load(userptr, "glMultiTexCoord4f"); + glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC) load(userptr, "glMultiTexCoord4fv"); + glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC) load(userptr, "glMultiTexCoord4i"); + glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC) load(userptr, "glMultiTexCoord4iv"); + glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC) load(userptr, "glMultiTexCoord4s"); + glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC) load(userptr, "glMultiTexCoord4sv"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); +} +static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); + glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC) load(userptr, "glFogCoordPointer"); + glad_glFogCoordd = (PFNGLFOGCOORDDPROC) load(userptr, "glFogCoordd"); + glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC) load(userptr, "glFogCoorddv"); + glad_glFogCoordf = (PFNGLFOGCOORDFPROC) load(userptr, "glFogCoordf"); + glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC) load(userptr, "glFogCoordfv"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, "glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, "glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, "glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, "glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, "glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, "glPointParameteriv"); + glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC) load(userptr, "glSecondaryColor3b"); + glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC) load(userptr, "glSecondaryColor3bv"); + glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC) load(userptr, "glSecondaryColor3d"); + glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC) load(userptr, "glSecondaryColor3dv"); + glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC) load(userptr, "glSecondaryColor3f"); + glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC) load(userptr, "glSecondaryColor3fv"); + glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC) load(userptr, "glSecondaryColor3i"); + glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC) load(userptr, "glSecondaryColor3iv"); + glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC) load(userptr, "glSecondaryColor3s"); + glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC) load(userptr, "glSecondaryColor3sv"); + glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC) load(userptr, "glSecondaryColor3ub"); + glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC) load(userptr, "glSecondaryColor3ubv"); + glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC) load(userptr, "glSecondaryColor3ui"); + glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC) load(userptr, "glSecondaryColor3uiv"); + glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC) load(userptr, "glSecondaryColor3us"); + glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC) load(userptr, "glSecondaryColor3usv"); + glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC) load(userptr, "glSecondaryColorPointer"); + glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC) load(userptr, "glWindowPos2d"); + glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC) load(userptr, "glWindowPos2dv"); + glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC) load(userptr, "glWindowPos2f"); + glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC) load(userptr, "glWindowPos2fv"); + glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC) load(userptr, "glWindowPos2i"); + glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC) load(userptr, "glWindowPos2iv"); + glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC) load(userptr, "glWindowPos2s"); + glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC) load(userptr, "glWindowPos2sv"); + glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC) load(userptr, "glWindowPos3d"); + glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC) load(userptr, "glWindowPos3dv"); + glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC) load(userptr, "glWindowPos3f"); + glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC) load(userptr, "glWindowPos3fv"); + glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC) load(userptr, "glWindowPos3i"); + glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC) load(userptr, "glWindowPos3iv"); + glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC) load(userptr, "glWindowPos3s"); + glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC) load(userptr, "glWindowPos3sv"); +} +static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries"); + glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); + glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, "glGetBufferSubData"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, "glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv"); + glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); + glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, "glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer"); +} +static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, "glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, "glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, "glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, "glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, "glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, "glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, "glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, "glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, "glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, "glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, "glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, "glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, "glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, "glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, "glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, "glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, "glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, "glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, "glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, "glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, "glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, "glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, "glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, "glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, "glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, "glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, "glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, "glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, "glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); +} +static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv"); +} +static void glad_gl_load_GL_ARB_draw_buffers( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_draw_buffers) return; + glad_glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) load(userptr, "glDrawBuffersARB"); +} +static void glad_gl_load_GL_ARB_draw_instanced( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_draw_instanced) return; + glad_glDrawArraysInstancedARB = (PFNGLDRAWARRAYSINSTANCEDARBPROC) load(userptr, "glDrawArraysInstancedARB"); + glad_glDrawElementsInstancedARB = (PFNGLDRAWELEMENTSINSTANCEDARBPROC) load(userptr, "glDrawElementsInstancedARB"); +} +static void glad_gl_load_GL_ARB_fragment_program( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_fragment_program) return; + glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) load(userptr, "glBindProgramARB"); + glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) load(userptr, "glDeleteProgramsARB"); + glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) load(userptr, "glGenProgramsARB"); + glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) load(userptr, "glGetProgramEnvParameterdvARB"); + glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) load(userptr, "glGetProgramEnvParameterfvARB"); + glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) load(userptr, "glGetProgramLocalParameterdvARB"); + glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) load(userptr, "glGetProgramLocalParameterfvARB"); + glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) load(userptr, "glGetProgramStringARB"); + glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) load(userptr, "glGetProgramivARB"); + glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC) load(userptr, "glIsProgramARB"); + glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) load(userptr, "glProgramEnvParameter4dARB"); + glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) load(userptr, "glProgramEnvParameter4dvARB"); + glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) load(userptr, "glProgramEnvParameter4fARB"); + glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) load(userptr, "glProgramEnvParameter4fvARB"); + glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) load(userptr, "glProgramLocalParameter4dARB"); + glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) load(userptr, "glProgramLocalParameter4dvARB"); + glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) load(userptr, "glProgramLocalParameter4fARB"); + glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) load(userptr, "glProgramLocalParameter4fvARB"); + glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) load(userptr, "glProgramStringARB"); +} +static void glad_gl_load_GL_ARB_framebuffer_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_framebuffer_object) return; + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample"); +} +static void glad_gl_load_GL_ARB_geometry_shader4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_geometry_shader4) return; + glad_glFramebufferTextureARB = (PFNGLFRAMEBUFFERTEXTUREARBPROC) load(userptr, "glFramebufferTextureARB"); + glad_glFramebufferTextureFaceARB = (PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) load(userptr, "glFramebufferTextureFaceARB"); + glad_glFramebufferTextureLayerARB = (PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) load(userptr, "glFramebufferTextureLayerARB"); + glad_glProgramParameteriARB = (PFNGLPROGRAMPARAMETERIARBPROC) load(userptr, "glProgramParameteriARB"); +} +static void glad_gl_load_GL_ARB_instanced_arrays( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_instanced_arrays) return; + glad_glVertexAttribDivisorARB = (PFNGLVERTEXATTRIBDIVISORARBPROC) load(userptr, "glVertexAttribDivisorARB"); +} +static void glad_gl_load_GL_ARB_map_buffer_range( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_map_buffer_range) return; + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange"); +} +static void glad_gl_load_GL_ARB_multitexture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_multitexture) return; + glad_glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) load(userptr, "glActiveTextureARB"); + glad_glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) load(userptr, "glClientActiveTextureARB"); + glad_glMultiTexCoord1dARB = (PFNGLMULTITEXCOORD1DARBPROC) load(userptr, "glMultiTexCoord1dARB"); + glad_glMultiTexCoord1dvARB = (PFNGLMULTITEXCOORD1DVARBPROC) load(userptr, "glMultiTexCoord1dvARB"); + glad_glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC) load(userptr, "glMultiTexCoord1fARB"); + glad_glMultiTexCoord1fvARB = (PFNGLMULTITEXCOORD1FVARBPROC) load(userptr, "glMultiTexCoord1fvARB"); + glad_glMultiTexCoord1iARB = (PFNGLMULTITEXCOORD1IARBPROC) load(userptr, "glMultiTexCoord1iARB"); + glad_glMultiTexCoord1ivARB = (PFNGLMULTITEXCOORD1IVARBPROC) load(userptr, "glMultiTexCoord1ivARB"); + glad_glMultiTexCoord1sARB = (PFNGLMULTITEXCOORD1SARBPROC) load(userptr, "glMultiTexCoord1sARB"); + glad_glMultiTexCoord1svARB = (PFNGLMULTITEXCOORD1SVARBPROC) load(userptr, "glMultiTexCoord1svARB"); + glad_glMultiTexCoord2dARB = (PFNGLMULTITEXCOORD2DARBPROC) load(userptr, "glMultiTexCoord2dARB"); + glad_glMultiTexCoord2dvARB = (PFNGLMULTITEXCOORD2DVARBPROC) load(userptr, "glMultiTexCoord2dvARB"); + glad_glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) load(userptr, "glMultiTexCoord2fARB"); + glad_glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC) load(userptr, "glMultiTexCoord2fvARB"); + glad_glMultiTexCoord2iARB = (PFNGLMULTITEXCOORD2IARBPROC) load(userptr, "glMultiTexCoord2iARB"); + glad_glMultiTexCoord2ivARB = (PFNGLMULTITEXCOORD2IVARBPROC) load(userptr, "glMultiTexCoord2ivARB"); + glad_glMultiTexCoord2sARB = (PFNGLMULTITEXCOORD2SARBPROC) load(userptr, "glMultiTexCoord2sARB"); + glad_glMultiTexCoord2svARB = (PFNGLMULTITEXCOORD2SVARBPROC) load(userptr, "glMultiTexCoord2svARB"); + glad_glMultiTexCoord3dARB = (PFNGLMULTITEXCOORD3DARBPROC) load(userptr, "glMultiTexCoord3dARB"); + glad_glMultiTexCoord3dvARB = (PFNGLMULTITEXCOORD3DVARBPROC) load(userptr, "glMultiTexCoord3dvARB"); + glad_glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC) load(userptr, "glMultiTexCoord3fARB"); + glad_glMultiTexCoord3fvARB = (PFNGLMULTITEXCOORD3FVARBPROC) load(userptr, "glMultiTexCoord3fvARB"); + glad_glMultiTexCoord3iARB = (PFNGLMULTITEXCOORD3IARBPROC) load(userptr, "glMultiTexCoord3iARB"); + glad_glMultiTexCoord3ivARB = (PFNGLMULTITEXCOORD3IVARBPROC) load(userptr, "glMultiTexCoord3ivARB"); + glad_glMultiTexCoord3sARB = (PFNGLMULTITEXCOORD3SARBPROC) load(userptr, "glMultiTexCoord3sARB"); + glad_glMultiTexCoord3svARB = (PFNGLMULTITEXCOORD3SVARBPROC) load(userptr, "glMultiTexCoord3svARB"); + glad_glMultiTexCoord4dARB = (PFNGLMULTITEXCOORD4DARBPROC) load(userptr, "glMultiTexCoord4dARB"); + glad_glMultiTexCoord4dvARB = (PFNGLMULTITEXCOORD4DVARBPROC) load(userptr, "glMultiTexCoord4dvARB"); + glad_glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) load(userptr, "glMultiTexCoord4fARB"); + glad_glMultiTexCoord4fvARB = (PFNGLMULTITEXCOORD4FVARBPROC) load(userptr, "glMultiTexCoord4fvARB"); + glad_glMultiTexCoord4iARB = (PFNGLMULTITEXCOORD4IARBPROC) load(userptr, "glMultiTexCoord4iARB"); + glad_glMultiTexCoord4ivARB = (PFNGLMULTITEXCOORD4IVARBPROC) load(userptr, "glMultiTexCoord4ivARB"); + glad_glMultiTexCoord4sARB = (PFNGLMULTITEXCOORD4SARBPROC) load(userptr, "glMultiTexCoord4sARB"); + glad_glMultiTexCoord4svARB = (PFNGLMULTITEXCOORD4SVARBPROC) load(userptr, "glMultiTexCoord4svARB"); +} +static void glad_gl_load_GL_ARB_occlusion_query( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_occlusion_query) return; + glad_glBeginQueryARB = (PFNGLBEGINQUERYARBPROC) load(userptr, "glBeginQueryARB"); + glad_glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) load(userptr, "glDeleteQueriesARB"); + glad_glEndQueryARB = (PFNGLENDQUERYARBPROC) load(userptr, "glEndQueryARB"); + glad_glGenQueriesARB = (PFNGLGENQUERIESARBPROC) load(userptr, "glGenQueriesARB"); + glad_glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) load(userptr, "glGetQueryObjectivARB"); + glad_glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) load(userptr, "glGetQueryObjectuivARB"); + glad_glGetQueryivARB = (PFNGLGETQUERYIVARBPROC) load(userptr, "glGetQueryivARB"); + glad_glIsQueryARB = (PFNGLISQUERYARBPROC) load(userptr, "glIsQueryARB"); +} +static void glad_gl_load_GL_ARB_shader_objects( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_shader_objects) return; + glad_glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) load(userptr, "glAttachObjectARB"); + glad_glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) load(userptr, "glCompileShaderARB"); + glad_glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) load(userptr, "glCreateProgramObjectARB"); + glad_glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) load(userptr, "glCreateShaderObjectARB"); + glad_glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) load(userptr, "glDeleteObjectARB"); + glad_glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) load(userptr, "glDetachObjectARB"); + glad_glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) load(userptr, "glGetActiveUniformARB"); + glad_glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) load(userptr, "glGetAttachedObjectsARB"); + glad_glGetHandleARB = (PFNGLGETHANDLEARBPROC) load(userptr, "glGetHandleARB"); + glad_glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) load(userptr, "glGetInfoLogARB"); + glad_glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) load(userptr, "glGetObjectParameterfvARB"); + glad_glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) load(userptr, "glGetObjectParameterivARB"); + glad_glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) load(userptr, "glGetShaderSourceARB"); + glad_glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) load(userptr, "glGetUniformLocationARB"); + glad_glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) load(userptr, "glGetUniformfvARB"); + glad_glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) load(userptr, "glGetUniformivARB"); + glad_glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) load(userptr, "glLinkProgramARB"); + glad_glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) load(userptr, "glShaderSourceARB"); + glad_glUniform1fARB = (PFNGLUNIFORM1FARBPROC) load(userptr, "glUniform1fARB"); + glad_glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) load(userptr, "glUniform1fvARB"); + glad_glUniform1iARB = (PFNGLUNIFORM1IARBPROC) load(userptr, "glUniform1iARB"); + glad_glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) load(userptr, "glUniform1ivARB"); + glad_glUniform2fARB = (PFNGLUNIFORM2FARBPROC) load(userptr, "glUniform2fARB"); + glad_glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) load(userptr, "glUniform2fvARB"); + glad_glUniform2iARB = (PFNGLUNIFORM2IARBPROC) load(userptr, "glUniform2iARB"); + glad_glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) load(userptr, "glUniform2ivARB"); + glad_glUniform3fARB = (PFNGLUNIFORM3FARBPROC) load(userptr, "glUniform3fARB"); + glad_glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) load(userptr, "glUniform3fvARB"); + glad_glUniform3iARB = (PFNGLUNIFORM3IARBPROC) load(userptr, "glUniform3iARB"); + glad_glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) load(userptr, "glUniform3ivARB"); + glad_glUniform4fARB = (PFNGLUNIFORM4FARBPROC) load(userptr, "glUniform4fARB"); + glad_glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) load(userptr, "glUniform4fvARB"); + glad_glUniform4iARB = (PFNGLUNIFORM4IARBPROC) load(userptr, "glUniform4iARB"); + glad_glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) load(userptr, "glUniform4ivARB"); + glad_glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) load(userptr, "glUniformMatrix2fvARB"); + glad_glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) load(userptr, "glUniformMatrix3fvARB"); + glad_glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) load(userptr, "glUniformMatrix4fvARB"); + glad_glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) load(userptr, "glUseProgramObjectARB"); + glad_glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) load(userptr, "glValidateProgramARB"); +} +static void glad_gl_load_GL_ARB_sync( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_sync) return; + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync"); + glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv"); + glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync"); +} +static void glad_gl_load_GL_ARB_texture_compression( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_texture_compression) return; + glad_glCompressedTexImage1DARB = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) load(userptr, "glCompressedTexImage1DARB"); + glad_glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) load(userptr, "glCompressedTexImage2DARB"); + glad_glCompressedTexImage3DARB = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) load(userptr, "glCompressedTexImage3DARB"); + glad_glCompressedTexSubImage1DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) load(userptr, "glCompressedTexSubImage1DARB"); + glad_glCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) load(userptr, "glCompressedTexSubImage2DARB"); + glad_glCompressedTexSubImage3DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) load(userptr, "glCompressedTexSubImage3DARB"); + glad_glGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) load(userptr, "glGetCompressedTexImageARB"); +} +static void glad_gl_load_GL_ARB_texture_multisample( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_texture_multisample) return; + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, "glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, "glTexImage3DMultisample"); +} +static void glad_gl_load_GL_ARB_timer_query( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_timer_query) return; + glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, "glGetQueryObjecti64v"); + glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, "glGetQueryObjectui64v"); + glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, "glQueryCounter"); +} +static void glad_gl_load_GL_ARB_vertex_buffer_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_vertex_buffer_object) return; + glad_glBindBufferARB = (PFNGLBINDBUFFERARBPROC) load(userptr, "glBindBufferARB"); + glad_glBufferDataARB = (PFNGLBUFFERDATAARBPROC) load(userptr, "glBufferDataARB"); + glad_glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) load(userptr, "glBufferSubDataARB"); + glad_glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) load(userptr, "glDeleteBuffersARB"); + glad_glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) load(userptr, "glGenBuffersARB"); + glad_glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) load(userptr, "glGetBufferParameterivARB"); + glad_glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) load(userptr, "glGetBufferPointervARB"); + glad_glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) load(userptr, "glGetBufferSubDataARB"); + glad_glIsBufferARB = (PFNGLISBUFFERARBPROC) load(userptr, "glIsBufferARB"); + glad_glMapBufferARB = (PFNGLMAPBUFFERARBPROC) load(userptr, "glMapBufferARB"); + glad_glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC) load(userptr, "glUnmapBufferARB"); +} +static void glad_gl_load_GL_ARB_vertex_program( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_vertex_program) return; + glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) load(userptr, "glBindProgramARB"); + glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) load(userptr, "glDeleteProgramsARB"); + glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glDisableVertexAttribArrayARB"); + glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glEnableVertexAttribArrayARB"); + glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) load(userptr, "glGenProgramsARB"); + glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) load(userptr, "glGetProgramEnvParameterdvARB"); + glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) load(userptr, "glGetProgramEnvParameterfvARB"); + glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) load(userptr, "glGetProgramLocalParameterdvARB"); + glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) load(userptr, "glGetProgramLocalParameterfvARB"); + glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) load(userptr, "glGetProgramStringARB"); + glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) load(userptr, "glGetProgramivARB"); + glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) load(userptr, "glGetVertexAttribPointervARB"); + glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) load(userptr, "glGetVertexAttribdvARB"); + glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) load(userptr, "glGetVertexAttribfvARB"); + glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) load(userptr, "glGetVertexAttribivARB"); + glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC) load(userptr, "glIsProgramARB"); + glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) load(userptr, "glProgramEnvParameter4dARB"); + glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) load(userptr, "glProgramEnvParameter4dvARB"); + glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) load(userptr, "glProgramEnvParameter4fARB"); + glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) load(userptr, "glProgramEnvParameter4fvARB"); + glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) load(userptr, "glProgramLocalParameter4dARB"); + glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) load(userptr, "glProgramLocalParameter4dvARB"); + glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) load(userptr, "glProgramLocalParameter4fARB"); + glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) load(userptr, "glProgramLocalParameter4fvARB"); + glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) load(userptr, "glProgramStringARB"); + glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) load(userptr, "glVertexAttrib1dARB"); + glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) load(userptr, "glVertexAttrib1dvARB"); + glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) load(userptr, "glVertexAttrib1fARB"); + glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) load(userptr, "glVertexAttrib1fvARB"); + glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) load(userptr, "glVertexAttrib1sARB"); + glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) load(userptr, "glVertexAttrib1svARB"); + glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) load(userptr, "glVertexAttrib2dARB"); + glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) load(userptr, "glVertexAttrib2dvARB"); + glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) load(userptr, "glVertexAttrib2fARB"); + glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) load(userptr, "glVertexAttrib2fvARB"); + glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) load(userptr, "glVertexAttrib2sARB"); + glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) load(userptr, "glVertexAttrib2svARB"); + glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) load(userptr, "glVertexAttrib3dARB"); + glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) load(userptr, "glVertexAttrib3dvARB"); + glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) load(userptr, "glVertexAttrib3fARB"); + glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) load(userptr, "glVertexAttrib3fvARB"); + glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) load(userptr, "glVertexAttrib3sARB"); + glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) load(userptr, "glVertexAttrib3svARB"); + glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) load(userptr, "glVertexAttrib4NbvARB"); + glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) load(userptr, "glVertexAttrib4NivARB"); + glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) load(userptr, "glVertexAttrib4NsvARB"); + glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) load(userptr, "glVertexAttrib4NubARB"); + glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) load(userptr, "glVertexAttrib4NubvARB"); + glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) load(userptr, "glVertexAttrib4NuivARB"); + glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) load(userptr, "glVertexAttrib4NusvARB"); + glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) load(userptr, "glVertexAttrib4bvARB"); + glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) load(userptr, "glVertexAttrib4dARB"); + glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) load(userptr, "glVertexAttrib4dvARB"); + glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) load(userptr, "glVertexAttrib4fARB"); + glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) load(userptr, "glVertexAttrib4fvARB"); + glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) load(userptr, "glVertexAttrib4ivARB"); + glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) load(userptr, "glVertexAttrib4sARB"); + glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) load(userptr, "glVertexAttrib4svARB"); + glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) load(userptr, "glVertexAttrib4ubvARB"); + glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) load(userptr, "glVertexAttrib4uivARB"); + glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) load(userptr, "glVertexAttrib4usvARB"); + glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) load(userptr, "glVertexAttribPointerARB"); +} +static void glad_gl_load_GL_ARB_vertex_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_vertex_shader) return; + glad_glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) load(userptr, "glBindAttribLocationARB"); + glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glDisableVertexAttribArrayARB"); + glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) load(userptr, "glEnableVertexAttribArrayARB"); + glad_glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) load(userptr, "glGetActiveAttribARB"); + glad_glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) load(userptr, "glGetAttribLocationARB"); + glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) load(userptr, "glGetVertexAttribPointervARB"); + glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) load(userptr, "glGetVertexAttribdvARB"); + glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) load(userptr, "glGetVertexAttribfvARB"); + glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) load(userptr, "glGetVertexAttribivARB"); + glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) load(userptr, "glVertexAttrib1dARB"); + glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) load(userptr, "glVertexAttrib1dvARB"); + glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) load(userptr, "glVertexAttrib1fARB"); + glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) load(userptr, "glVertexAttrib1fvARB"); + glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) load(userptr, "glVertexAttrib1sARB"); + glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) load(userptr, "glVertexAttrib1svARB"); + glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) load(userptr, "glVertexAttrib2dARB"); + glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) load(userptr, "glVertexAttrib2dvARB"); + glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) load(userptr, "glVertexAttrib2fARB"); + glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) load(userptr, "glVertexAttrib2fvARB"); + glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) load(userptr, "glVertexAttrib2sARB"); + glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) load(userptr, "glVertexAttrib2svARB"); + glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) load(userptr, "glVertexAttrib3dARB"); + glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) load(userptr, "glVertexAttrib3dvARB"); + glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) load(userptr, "glVertexAttrib3fARB"); + glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) load(userptr, "glVertexAttrib3fvARB"); + glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) load(userptr, "glVertexAttrib3sARB"); + glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) load(userptr, "glVertexAttrib3svARB"); + glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) load(userptr, "glVertexAttrib4NbvARB"); + glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) load(userptr, "glVertexAttrib4NivARB"); + glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) load(userptr, "glVertexAttrib4NsvARB"); + glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) load(userptr, "glVertexAttrib4NubARB"); + glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) load(userptr, "glVertexAttrib4NubvARB"); + glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) load(userptr, "glVertexAttrib4NuivARB"); + glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) load(userptr, "glVertexAttrib4NusvARB"); + glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) load(userptr, "glVertexAttrib4bvARB"); + glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) load(userptr, "glVertexAttrib4dARB"); + glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) load(userptr, "glVertexAttrib4dvARB"); + glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) load(userptr, "glVertexAttrib4fARB"); + glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) load(userptr, "glVertexAttrib4fvARB"); + glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) load(userptr, "glVertexAttrib4ivARB"); + glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) load(userptr, "glVertexAttrib4sARB"); + glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) load(userptr, "glVertexAttrib4svARB"); + glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) load(userptr, "glVertexAttrib4ubvARB"); + glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) load(userptr, "glVertexAttrib4uivARB"); + glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) load(userptr, "glVertexAttrib4usvARB"); + glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) load(userptr, "glVertexAttribPointerARB"); +} +static void glad_gl_load_GL_EXT_blend_color( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_blend_color) return; + glad_glBlendColorEXT = (PFNGLBLENDCOLOREXTPROC) load(userptr, "glBlendColorEXT"); +} +static void glad_gl_load_GL_EXT_blend_minmax( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_blend_minmax) return; + glad_glBlendEquationEXT = (PFNGLBLENDEQUATIONEXTPROC) load(userptr, "glBlendEquationEXT"); +} +static void glad_gl_load_GL_EXT_draw_range_elements( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_range_elements) return; + glad_glDrawRangeElementsEXT = (PFNGLDRAWRANGEELEMENTSEXTPROC) load(userptr, "glDrawRangeElementsEXT"); +} +static void glad_gl_load_GL_EXT_framebuffer_blit( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_framebuffer_blit) return; + glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) load(userptr, "glBlitFramebufferEXT"); +} +static void glad_gl_load_GL_EXT_framebuffer_multisample( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_framebuffer_multisample) return; + glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) load(userptr, "glRenderbufferStorageMultisampleEXT"); +} +static void glad_gl_load_GL_EXT_framebuffer_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_framebuffer_object) return; + glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) load(userptr, "glBindFramebufferEXT"); + glad_glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) load(userptr, "glBindRenderbufferEXT"); + glad_glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) load(userptr, "glCheckFramebufferStatusEXT"); + glad_glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) load(userptr, "glDeleteFramebuffersEXT"); + glad_glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) load(userptr, "glDeleteRenderbuffersEXT"); + glad_glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) load(userptr, "glFramebufferRenderbufferEXT"); + glad_glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) load(userptr, "glFramebufferTexture1DEXT"); + glad_glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) load(userptr, "glFramebufferTexture2DEXT"); + glad_glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) load(userptr, "glFramebufferTexture3DEXT"); + glad_glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) load(userptr, "glGenFramebuffersEXT"); + glad_glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) load(userptr, "glGenRenderbuffersEXT"); + glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) load(userptr, "glGenerateMipmapEXT"); + glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) load(userptr, "glGetFramebufferAttachmentParameterivEXT"); + glad_glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) load(userptr, "glGetRenderbufferParameterivEXT"); + glad_glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) load(userptr, "glIsFramebufferEXT"); + glad_glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) load(userptr, "glIsRenderbufferEXT"); + glad_glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) load(userptr, "glRenderbufferStorageEXT"); +} +static void glad_gl_load_GL_EXT_gpu_shader4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_gpu_shader4) return; + glad_glBindFragDataLocationEXT = (PFNGLBINDFRAGDATALOCATIONEXTPROC) load(userptr, "glBindFragDataLocationEXT"); + glad_glGetFragDataLocationEXT = (PFNGLGETFRAGDATALOCATIONEXTPROC) load(userptr, "glGetFragDataLocationEXT"); + glad_glGetUniformuivEXT = (PFNGLGETUNIFORMUIVEXTPROC) load(userptr, "glGetUniformuivEXT"); + glad_glGetVertexAttribIivEXT = (PFNGLGETVERTEXATTRIBIIVEXTPROC) load(userptr, "glGetVertexAttribIivEXT"); + glad_glGetVertexAttribIuivEXT = (PFNGLGETVERTEXATTRIBIUIVEXTPROC) load(userptr, "glGetVertexAttribIuivEXT"); + glad_glUniform1uiEXT = (PFNGLUNIFORM1UIEXTPROC) load(userptr, "glUniform1uiEXT"); + glad_glUniform1uivEXT = (PFNGLUNIFORM1UIVEXTPROC) load(userptr, "glUniform1uivEXT"); + glad_glUniform2uiEXT = (PFNGLUNIFORM2UIEXTPROC) load(userptr, "glUniform2uiEXT"); + glad_glUniform2uivEXT = (PFNGLUNIFORM2UIVEXTPROC) load(userptr, "glUniform2uivEXT"); + glad_glUniform3uiEXT = (PFNGLUNIFORM3UIEXTPROC) load(userptr, "glUniform3uiEXT"); + glad_glUniform3uivEXT = (PFNGLUNIFORM3UIVEXTPROC) load(userptr, "glUniform3uivEXT"); + glad_glUniform4uiEXT = (PFNGLUNIFORM4UIEXTPROC) load(userptr, "glUniform4uiEXT"); + glad_glUniform4uivEXT = (PFNGLUNIFORM4UIVEXTPROC) load(userptr, "glUniform4uivEXT"); + glad_glVertexAttribI1iEXT = (PFNGLVERTEXATTRIBI1IEXTPROC) load(userptr, "glVertexAttribI1iEXT"); + glad_glVertexAttribI1ivEXT = (PFNGLVERTEXATTRIBI1IVEXTPROC) load(userptr, "glVertexAttribI1ivEXT"); + glad_glVertexAttribI1uiEXT = (PFNGLVERTEXATTRIBI1UIEXTPROC) load(userptr, "glVertexAttribI1uiEXT"); + glad_glVertexAttribI1uivEXT = (PFNGLVERTEXATTRIBI1UIVEXTPROC) load(userptr, "glVertexAttribI1uivEXT"); + glad_glVertexAttribI2iEXT = (PFNGLVERTEXATTRIBI2IEXTPROC) load(userptr, "glVertexAttribI2iEXT"); + glad_glVertexAttribI2ivEXT = (PFNGLVERTEXATTRIBI2IVEXTPROC) load(userptr, "glVertexAttribI2ivEXT"); + glad_glVertexAttribI2uiEXT = (PFNGLVERTEXATTRIBI2UIEXTPROC) load(userptr, "glVertexAttribI2uiEXT"); + glad_glVertexAttribI2uivEXT = (PFNGLVERTEXATTRIBI2UIVEXTPROC) load(userptr, "glVertexAttribI2uivEXT"); + glad_glVertexAttribI3iEXT = (PFNGLVERTEXATTRIBI3IEXTPROC) load(userptr, "glVertexAttribI3iEXT"); + glad_glVertexAttribI3ivEXT = (PFNGLVERTEXATTRIBI3IVEXTPROC) load(userptr, "glVertexAttribI3ivEXT"); + glad_glVertexAttribI3uiEXT = (PFNGLVERTEXATTRIBI3UIEXTPROC) load(userptr, "glVertexAttribI3uiEXT"); + glad_glVertexAttribI3uivEXT = (PFNGLVERTEXATTRIBI3UIVEXTPROC) load(userptr, "glVertexAttribI3uivEXT"); + glad_glVertexAttribI4bvEXT = (PFNGLVERTEXATTRIBI4BVEXTPROC) load(userptr, "glVertexAttribI4bvEXT"); + glad_glVertexAttribI4iEXT = (PFNGLVERTEXATTRIBI4IEXTPROC) load(userptr, "glVertexAttribI4iEXT"); + glad_glVertexAttribI4ivEXT = (PFNGLVERTEXATTRIBI4IVEXTPROC) load(userptr, "glVertexAttribI4ivEXT"); + glad_glVertexAttribI4svEXT = (PFNGLVERTEXATTRIBI4SVEXTPROC) load(userptr, "glVertexAttribI4svEXT"); + glad_glVertexAttribI4ubvEXT = (PFNGLVERTEXATTRIBI4UBVEXTPROC) load(userptr, "glVertexAttribI4ubvEXT"); + glad_glVertexAttribI4uiEXT = (PFNGLVERTEXATTRIBI4UIEXTPROC) load(userptr, "glVertexAttribI4uiEXT"); + glad_glVertexAttribI4uivEXT = (PFNGLVERTEXATTRIBI4UIVEXTPROC) load(userptr, "glVertexAttribI4uivEXT"); + glad_glVertexAttribI4usvEXT = (PFNGLVERTEXATTRIBI4USVEXTPROC) load(userptr, "glVertexAttribI4usvEXT"); + glad_glVertexAttribIPointerEXT = (PFNGLVERTEXATTRIBIPOINTEREXTPROC) load(userptr, "glVertexAttribIPointerEXT"); +} +static void glad_gl_load_GL_EXT_texture_array( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_array) return; + glad_glFramebufferTextureLayerEXT = (PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) load(userptr, "glFramebufferTextureLayerEXT"); +} +static void glad_gl_load_GL_EXT_transform_feedback( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_transform_feedback) return; + glad_glBeginTransformFeedbackEXT = (PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) load(userptr, "glBeginTransformFeedbackEXT"); + glad_glBindBufferBaseEXT = (PFNGLBINDBUFFERBASEEXTPROC) load(userptr, "glBindBufferBaseEXT"); + glad_glBindBufferOffsetEXT = (PFNGLBINDBUFFEROFFSETEXTPROC) load(userptr, "glBindBufferOffsetEXT"); + glad_glBindBufferRangeEXT = (PFNGLBINDBUFFERRANGEEXTPROC) load(userptr, "glBindBufferRangeEXT"); + glad_glEndTransformFeedbackEXT = (PFNGLENDTRANSFORMFEEDBACKEXTPROC) load(userptr, "glEndTransformFeedbackEXT"); + glad_glGetTransformFeedbackVaryingEXT = (PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) load(userptr, "glGetTransformFeedbackVaryingEXT"); + glad_glTransformFeedbackVaryingsEXT = (PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) load(userptr, "glTransformFeedbackVaryingsEXT"); +} +static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_debug) return; + glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load(userptr, "glDebugMessageCallback"); + glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load(userptr, "glDebugMessageControl"); + glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load(userptr, "glDebugMessageInsert"); + glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load(userptr, "glGetDebugMessageLog"); + glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load(userptr, "glGetObjectLabel"); + glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load(userptr, "glGetObjectPtrLabel"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv"); + glad_glObjectLabel = (PFNGLOBJECTLABELPROC) load(userptr, "glObjectLabel"); + glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load(userptr, "glObjectPtrLabel"); + glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load(userptr, "glPopDebugGroup"); + glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load(userptr, "glPushDebugGroup"); +} + + + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define GLAD_GL_IS_SOME_NEW_VERSION 1 +#else +#define GLAD_GL_IS_SOME_NEW_VERSION 0 +#endif + +static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { +#if GLAD_GL_IS_SOME_NEW_VERSION + if(GLAD_VERSION_MAJOR(version) < 3) { +#else + (void) version; + (void) out_num_exts_i; + (void) out_exts_i; +#endif + if (glad_glGetString == NULL) { + return 0; + } + *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); +#if GLAD_GL_IS_SOME_NEW_VERSION + } else { + unsigned int index = 0; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { + return 0; + } + glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); + } + if (exts_i == NULL) { + return 0; + } + for(index = 0; index < num_exts_i; index++) { + const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp) + 1; + + char *local_str = (char*) malloc(len * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, len * sizeof(char)); + } + + exts_i[index] = local_str; + } + + *out_num_exts_i = num_exts_i; + *out_exts_i = exts_i; + } +#endif + return 1; +} +static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { + if (exts_i != NULL) { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + free((void *) (exts_i[index])); + } + free((void *)exts_i); + exts_i = NULL; + } +} +static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { + if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } + } else { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + if(strcmp(e, ext) == 0) { + return 1; + } + } + } + return 0; +} + +static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_gl_find_extensions_gl( int version) { + const char *exts = NULL; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; + + GLAD_GL_ARB_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_buffers"); + GLAD_GL_ARB_draw_instanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_draw_instanced"); + GLAD_GL_ARB_fragment_program = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_program"); + GLAD_GL_ARB_fragment_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_fragment_shader"); + GLAD_GL_ARB_framebuffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_framebuffer_object"); + GLAD_GL_ARB_geometry_shader4 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_geometry_shader4"); + GLAD_GL_ARB_instanced_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_instanced_arrays"); + GLAD_GL_ARB_map_buffer_range = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_map_buffer_range"); + GLAD_GL_ARB_multitexture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multitexture"); + GLAD_GL_ARB_occlusion_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_occlusion_query"); + GLAD_GL_ARB_shader_objects = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shader_objects"); + GLAD_GL_ARB_shading_language_100 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_shading_language_100"); + GLAD_GL_ARB_sync = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_sync"); + GLAD_GL_ARB_texture_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_compression"); + GLAD_GL_ARB_texture_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_multisample"); + GLAD_GL_ARB_texture_rectangle = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_texture_rectangle"); + GLAD_GL_ARB_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_timer_query"); + GLAD_GL_ARB_vertex_buffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_buffer_object"); + GLAD_GL_ARB_vertex_program = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_program"); + GLAD_GL_ARB_vertex_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_vertex_shader"); + GLAD_GL_EXT_bgra = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_bgra"); + GLAD_GL_EXT_blend_color = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_color"); + GLAD_GL_EXT_blend_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_minmax"); + GLAD_GL_EXT_draw_range_elements = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_range_elements"); + GLAD_GL_EXT_framebuffer_blit = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_blit"); + GLAD_GL_EXT_framebuffer_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_multisample"); + GLAD_GL_EXT_framebuffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_object"); + GLAD_GL_EXT_gpu_shader4 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_gpu_shader4"); + GLAD_GL_EXT_packed_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_packed_depth_stencil"); + GLAD_GL_EXT_texture_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_array"); + GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc"); + GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_anisotropic"); + GLAD_GL_EXT_texture_lod_bias = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_lod_bias"); + GLAD_GL_EXT_transform_feedback = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_transform_feedback"); + GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug"); + + glad_gl_free_extensions(exts_i, num_exts_i); + + return 1; +} + +static int glad_gl_find_core_gl(void) { + int i; + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + "OpenGL SC ", + NULL + }; + int major = 0; + int minor = 0; + version = (const char*) glad_glGetString(GL_VERSION); + if (!version) return 0; + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + + GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); + + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) { + int version; + + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + if(glad_glGetString == NULL) return 0; + if(glad_glGetString(GL_VERSION) == NULL) return 0; + version = glad_gl_find_core_gl(); + + glad_gl_load_GL_VERSION_1_0(load, userptr); + glad_gl_load_GL_VERSION_1_1(load, userptr); + glad_gl_load_GL_VERSION_1_2(load, userptr); + glad_gl_load_GL_VERSION_1_3(load, userptr); + glad_gl_load_GL_VERSION_1_4(load, userptr); + glad_gl_load_GL_VERSION_1_5(load, userptr); + glad_gl_load_GL_VERSION_2_0(load, userptr); + glad_gl_load_GL_VERSION_2_1(load, userptr); + + if (!glad_gl_find_extensions_gl(version)) return 0; + glad_gl_load_GL_ARB_draw_buffers(load, userptr); + glad_gl_load_GL_ARB_draw_instanced(load, userptr); + glad_gl_load_GL_ARB_fragment_program(load, userptr); + glad_gl_load_GL_ARB_framebuffer_object(load, userptr); + glad_gl_load_GL_ARB_geometry_shader4(load, userptr); + glad_gl_load_GL_ARB_instanced_arrays(load, userptr); + glad_gl_load_GL_ARB_map_buffer_range(load, userptr); + glad_gl_load_GL_ARB_multitexture(load, userptr); + glad_gl_load_GL_ARB_occlusion_query(load, userptr); + glad_gl_load_GL_ARB_shader_objects(load, userptr); + glad_gl_load_GL_ARB_sync(load, userptr); + glad_gl_load_GL_ARB_texture_compression(load, userptr); + glad_gl_load_GL_ARB_texture_multisample(load, userptr); + glad_gl_load_GL_ARB_timer_query(load, userptr); + glad_gl_load_GL_ARB_vertex_buffer_object(load, userptr); + glad_gl_load_GL_ARB_vertex_program(load, userptr); + glad_gl_load_GL_ARB_vertex_shader(load, userptr); + glad_gl_load_GL_EXT_blend_color(load, userptr); + glad_gl_load_GL_EXT_blend_minmax(load, userptr); + glad_gl_load_GL_EXT_draw_range_elements(load, userptr); + glad_gl_load_GL_EXT_framebuffer_blit(load, userptr); + glad_gl_load_GL_EXT_framebuffer_multisample(load, userptr); + glad_gl_load_GL_EXT_framebuffer_object(load, userptr); + glad_gl_load_GL_EXT_gpu_shader4(load, userptr); + glad_gl_load_GL_EXT_texture_array(load, userptr); + glad_gl_load_GL_EXT_transform_feedback(load, userptr); + glad_gl_load_GL_KHR_debug(load, userptr); + + + + return version; +} + + +int gladLoadGL( GLADloadfunc load) { + return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + + + +#ifdef __cplusplus +} +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/src/gles2.cpp 0ad-0.0.26/libraries/source/glad/src/gles2.cpp --- 0ad-0.0.25b/libraries/source/glad/src/gles2.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/src/gles2.cpp 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,559 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_GL_ES_VERSION_2_0 = 0; +int GLAD_GL_EXT_texture_compression_s3tc = 0; +int GLAD_GL_EXT_texture_filter_anisotropic = 0; +int GLAD_GL_EXT_texture_format_BGRA8888 = 0; +int GLAD_GL_KHR_debug = 0; +int GLAD_GL_OES_depth32 = 0; +int GLAD_GL_OES_mapbuffer = 0; +int GLAD_GL_OES_rgb8_rgba8 = 0; +int GLAD_GL_OES_texture_border_clamp = 0; + + + +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; +PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; +PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES = NULL; +PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL; +PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL; +PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES = NULL; +PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES = NULL; +PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLMAPBUFFEROESPROC glad_glMapBufferOES = NULL; +PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL; +PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL; +PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES = NULL; +PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES = NULL; +PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; + + +static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ES_VERSION_2_0) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); + glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); + glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); + glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); + glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); + glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); + glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); + glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); + glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); + glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); + glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); + glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); + glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); + glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); + glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); + glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); + glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); + glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); + glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); + glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); + glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); +} +static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_debug) return; + glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC) load(userptr, "glDebugMessageCallbackKHR"); + glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC) load(userptr, "glDebugMessageControlKHR"); + glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC) load(userptr, "glDebugMessageInsertKHR"); + glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC) load(userptr, "glGetDebugMessageLogKHR"); + glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC) load(userptr, "glGetObjectLabelKHR"); + glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC) load(userptr, "glGetObjectPtrLabelKHR"); + glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC) load(userptr, "glGetPointervKHR"); + glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC) load(userptr, "glObjectLabelKHR"); + glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC) load(userptr, "glObjectPtrLabelKHR"); + glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC) load(userptr, "glPopDebugGroupKHR"); + glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC) load(userptr, "glPushDebugGroupKHR"); +} +static void glad_gl_load_GL_OES_mapbuffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_mapbuffer) return; + glad_glGetBufferPointervOES = (PFNGLGETBUFFERPOINTERVOESPROC) load(userptr, "glGetBufferPointervOES"); + glad_glMapBufferOES = (PFNGLMAPBUFFEROESPROC) load(userptr, "glMapBufferOES"); + glad_glUnmapBufferOES = (PFNGLUNMAPBUFFEROESPROC) load(userptr, "glUnmapBufferOES"); +} +static void glad_gl_load_GL_OES_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_border_clamp) return; + glad_glGetSamplerParameterIivOES = (PFNGLGETSAMPLERPARAMETERIIVOESPROC) load(userptr, "glGetSamplerParameterIivOES"); + glad_glGetSamplerParameterIuivOES = (PFNGLGETSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glGetSamplerParameterIuivOES"); + glad_glGetTexParameterIivOES = (PFNGLGETTEXPARAMETERIIVOESPROC) load(userptr, "glGetTexParameterIivOES"); + glad_glGetTexParameterIuivOES = (PFNGLGETTEXPARAMETERIUIVOESPROC) load(userptr, "glGetTexParameterIuivOES"); + glad_glSamplerParameterIivOES = (PFNGLSAMPLERPARAMETERIIVOESPROC) load(userptr, "glSamplerParameterIivOES"); + glad_glSamplerParameterIuivOES = (PFNGLSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glSamplerParameterIuivOES"); + glad_glTexParameterIivOES = (PFNGLTEXPARAMETERIIVOESPROC) load(userptr, "glTexParameterIivOES"); + glad_glTexParameterIuivOES = (PFNGLTEXPARAMETERIUIVOESPROC) load(userptr, "glTexParameterIuivOES"); +} + + + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define GLAD_GL_IS_SOME_NEW_VERSION 1 +#else +#define GLAD_GL_IS_SOME_NEW_VERSION 0 +#endif + +static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { +#if GLAD_GL_IS_SOME_NEW_VERSION + if(GLAD_VERSION_MAJOR(version) < 3) { +#else + (void) version; + (void) out_num_exts_i; + (void) out_exts_i; +#endif + if (glad_glGetString == NULL) { + return 0; + } + *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); +#if GLAD_GL_IS_SOME_NEW_VERSION + } else { + unsigned int index = 0; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { + return 0; + } + glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); + } + if (exts_i == NULL) { + return 0; + } + for(index = 0; index < num_exts_i; index++) { + const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp) + 1; + + char *local_str = (char*) malloc(len * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, len * sizeof(char)); + } + + exts_i[index] = local_str; + } + + *out_num_exts_i = num_exts_i; + *out_exts_i = exts_i; + } +#endif + return 1; +} +static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { + if (exts_i != NULL) { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + free((void *) (exts_i[index])); + } + free((void *)exts_i); + exts_i = NULL; + } +} +static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { + if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } + } else { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + if(strcmp(e, ext) == 0) { + return 1; + } + } + } + return 0; +} + +static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_gl_find_extensions_gles2( int version) { + const char *exts = NULL; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; + + GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc"); + GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_anisotropic"); + GLAD_GL_EXT_texture_format_BGRA8888 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_BGRA8888"); + GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug"); + GLAD_GL_OES_depth32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth32"); + GLAD_GL_OES_mapbuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_mapbuffer"); + GLAD_GL_OES_rgb8_rgba8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_rgb8_rgba8"); + GLAD_GL_OES_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_border_clamp"); + + glad_gl_free_extensions(exts_i, num_exts_i); + + return 1; +} + +static int glad_gl_find_core_gles2(void) { + int i; + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + "OpenGL SC ", + NULL + }; + int major = 0; + int minor = 0; + version = (const char*) glad_glGetString(GL_VERSION); + if (!version) return 0; + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + + GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); + + GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) { + int version; + + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + if(glad_glGetString == NULL) return 0; + if(glad_glGetString(GL_VERSION) == NULL) return 0; + version = glad_gl_find_core_gles2(); + + glad_gl_load_GL_ES_VERSION_2_0(load, userptr); + + if (!glad_gl_find_extensions_gles2(version)) return 0; + glad_gl_load_GL_KHR_debug(load, userptr); + glad_gl_load_GL_OES_mapbuffer(load, userptr); + glad_gl_load_GL_OES_texture_border_clamp(load, userptr); + + + + return version; +} + + +int gladLoadGLES2( GLADloadfunc load) { + return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + + + +#ifdef __cplusplus +} +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/src/glx.cpp 0ad-0.0.26/libraries/source/glad/src/glx.cpp --- 0ad-0.0.25b/libraries/source/glad/src/glx.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/src/glx.cpp 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,245 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_GLX_VERSION_1_0 = 0; +int GLAD_GLX_VERSION_1_1 = 0; +int GLAD_GLX_VERSION_1_2 = 0; +int GLAD_GLX_VERSION_1_3 = 0; +int GLAD_GLX_VERSION_1_4 = 0; +int GLAD_GLX_MESA_query_renderer = 0; +int GLAD_GLX_SGI_swap_control = 0; + + + +PFNGLXCHOOSEFBCONFIGPROC glad_glXChooseFBConfig = NULL; +PFNGLXCHOOSEVISUALPROC glad_glXChooseVisual = NULL; +PFNGLXCOPYCONTEXTPROC glad_glXCopyContext = NULL; +PFNGLXCREATECONTEXTPROC glad_glXCreateContext = NULL; +PFNGLXCREATEGLXPIXMAPPROC glad_glXCreateGLXPixmap = NULL; +PFNGLXCREATENEWCONTEXTPROC glad_glXCreateNewContext = NULL; +PFNGLXCREATEPBUFFERPROC glad_glXCreatePbuffer = NULL; +PFNGLXCREATEPIXMAPPROC glad_glXCreatePixmap = NULL; +PFNGLXCREATEWINDOWPROC glad_glXCreateWindow = NULL; +PFNGLXDESTROYCONTEXTPROC glad_glXDestroyContext = NULL; +PFNGLXDESTROYGLXPIXMAPPROC glad_glXDestroyGLXPixmap = NULL; +PFNGLXDESTROYPBUFFERPROC glad_glXDestroyPbuffer = NULL; +PFNGLXDESTROYPIXMAPPROC glad_glXDestroyPixmap = NULL; +PFNGLXDESTROYWINDOWPROC glad_glXDestroyWindow = NULL; +PFNGLXGETCLIENTSTRINGPROC glad_glXGetClientString = NULL; +PFNGLXGETCONFIGPROC glad_glXGetConfig = NULL; +PFNGLXGETCURRENTCONTEXTPROC glad_glXGetCurrentContext = NULL; +PFNGLXGETCURRENTDISPLAYPROC glad_glXGetCurrentDisplay = NULL; +PFNGLXGETCURRENTDRAWABLEPROC glad_glXGetCurrentDrawable = NULL; +PFNGLXGETCURRENTREADDRAWABLEPROC glad_glXGetCurrentReadDrawable = NULL; +PFNGLXGETFBCONFIGATTRIBPROC glad_glXGetFBConfigAttrib = NULL; +PFNGLXGETFBCONFIGSPROC glad_glXGetFBConfigs = NULL; +PFNGLXGETPROCADDRESSPROC glad_glXGetProcAddress = NULL; +PFNGLXGETSELECTEDEVENTPROC glad_glXGetSelectedEvent = NULL; +PFNGLXGETVISUALFROMFBCONFIGPROC glad_glXGetVisualFromFBConfig = NULL; +PFNGLXISDIRECTPROC glad_glXIsDirect = NULL; +PFNGLXMAKECONTEXTCURRENTPROC glad_glXMakeContextCurrent = NULL; +PFNGLXMAKECURRENTPROC glad_glXMakeCurrent = NULL; +PFNGLXQUERYCONTEXTPROC glad_glXQueryContext = NULL; +PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glad_glXQueryCurrentRendererIntegerMESA = NULL; +PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC glad_glXQueryCurrentRendererStringMESA = NULL; +PFNGLXQUERYDRAWABLEPROC glad_glXQueryDrawable = NULL; +PFNGLXQUERYEXTENSIONPROC glad_glXQueryExtension = NULL; +PFNGLXQUERYEXTENSIONSSTRINGPROC glad_glXQueryExtensionsString = NULL; +PFNGLXQUERYRENDERERINTEGERMESAPROC glad_glXQueryRendererIntegerMESA = NULL; +PFNGLXQUERYRENDERERSTRINGMESAPROC glad_glXQueryRendererStringMESA = NULL; +PFNGLXQUERYSERVERSTRINGPROC glad_glXQueryServerString = NULL; +PFNGLXQUERYVERSIONPROC glad_glXQueryVersion = NULL; +PFNGLXSELECTEVENTPROC glad_glXSelectEvent = NULL; +PFNGLXSWAPBUFFERSPROC glad_glXSwapBuffers = NULL; +PFNGLXSWAPINTERVALSGIPROC glad_glXSwapIntervalSGI = NULL; +PFNGLXUSEXFONTPROC glad_glXUseXFont = NULL; +PFNGLXWAITGLPROC glad_glXWaitGL = NULL; +PFNGLXWAITXPROC glad_glXWaitX = NULL; + + +static void glad_glx_load_GLX_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_VERSION_1_0) return; + glad_glXChooseVisual = (PFNGLXCHOOSEVISUALPROC) load(userptr, "glXChooseVisual"); + glad_glXCopyContext = (PFNGLXCOPYCONTEXTPROC) load(userptr, "glXCopyContext"); + glad_glXCreateContext = (PFNGLXCREATECONTEXTPROC) load(userptr, "glXCreateContext"); + glad_glXCreateGLXPixmap = (PFNGLXCREATEGLXPIXMAPPROC) load(userptr, "glXCreateGLXPixmap"); + glad_glXDestroyContext = (PFNGLXDESTROYCONTEXTPROC) load(userptr, "glXDestroyContext"); + glad_glXDestroyGLXPixmap = (PFNGLXDESTROYGLXPIXMAPPROC) load(userptr, "glXDestroyGLXPixmap"); + glad_glXGetConfig = (PFNGLXGETCONFIGPROC) load(userptr, "glXGetConfig"); + glad_glXGetCurrentContext = (PFNGLXGETCURRENTCONTEXTPROC) load(userptr, "glXGetCurrentContext"); + glad_glXGetCurrentDrawable = (PFNGLXGETCURRENTDRAWABLEPROC) load(userptr, "glXGetCurrentDrawable"); + glad_glXIsDirect = (PFNGLXISDIRECTPROC) load(userptr, "glXIsDirect"); + glad_glXMakeCurrent = (PFNGLXMAKECURRENTPROC) load(userptr, "glXMakeCurrent"); + glad_glXQueryExtension = (PFNGLXQUERYEXTENSIONPROC) load(userptr, "glXQueryExtension"); + glad_glXQueryVersion = (PFNGLXQUERYVERSIONPROC) load(userptr, "glXQueryVersion"); + glad_glXSwapBuffers = (PFNGLXSWAPBUFFERSPROC) load(userptr, "glXSwapBuffers"); + glad_glXUseXFont = (PFNGLXUSEXFONTPROC) load(userptr, "glXUseXFont"); + glad_glXWaitGL = (PFNGLXWAITGLPROC) load(userptr, "glXWaitGL"); + glad_glXWaitX = (PFNGLXWAITXPROC) load(userptr, "glXWaitX"); +} +static void glad_glx_load_GLX_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_VERSION_1_1) return; + glad_glXGetClientString = (PFNGLXGETCLIENTSTRINGPROC) load(userptr, "glXGetClientString"); + glad_glXQueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRINGPROC) load(userptr, "glXQueryExtensionsString"); + glad_glXQueryServerString = (PFNGLXQUERYSERVERSTRINGPROC) load(userptr, "glXQueryServerString"); +} +static void glad_glx_load_GLX_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_VERSION_1_2) return; + glad_glXGetCurrentDisplay = (PFNGLXGETCURRENTDISPLAYPROC) load(userptr, "glXGetCurrentDisplay"); +} +static void glad_glx_load_GLX_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_VERSION_1_3) return; + glad_glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) load(userptr, "glXChooseFBConfig"); + glad_glXCreateNewContext = (PFNGLXCREATENEWCONTEXTPROC) load(userptr, "glXCreateNewContext"); + glad_glXCreatePbuffer = (PFNGLXCREATEPBUFFERPROC) load(userptr, "glXCreatePbuffer"); + glad_glXCreatePixmap = (PFNGLXCREATEPIXMAPPROC) load(userptr, "glXCreatePixmap"); + glad_glXCreateWindow = (PFNGLXCREATEWINDOWPROC) load(userptr, "glXCreateWindow"); + glad_glXDestroyPbuffer = (PFNGLXDESTROYPBUFFERPROC) load(userptr, "glXDestroyPbuffer"); + glad_glXDestroyPixmap = (PFNGLXDESTROYPIXMAPPROC) load(userptr, "glXDestroyPixmap"); + glad_glXDestroyWindow = (PFNGLXDESTROYWINDOWPROC) load(userptr, "glXDestroyWindow"); + glad_glXGetCurrentReadDrawable = (PFNGLXGETCURRENTREADDRAWABLEPROC) load(userptr, "glXGetCurrentReadDrawable"); + glad_glXGetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) load(userptr, "glXGetFBConfigAttrib"); + glad_glXGetFBConfigs = (PFNGLXGETFBCONFIGSPROC) load(userptr, "glXGetFBConfigs"); + glad_glXGetSelectedEvent = (PFNGLXGETSELECTEDEVENTPROC) load(userptr, "glXGetSelectedEvent"); + glad_glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) load(userptr, "glXGetVisualFromFBConfig"); + glad_glXMakeContextCurrent = (PFNGLXMAKECONTEXTCURRENTPROC) load(userptr, "glXMakeContextCurrent"); + glad_glXQueryContext = (PFNGLXQUERYCONTEXTPROC) load(userptr, "glXQueryContext"); + glad_glXQueryDrawable = (PFNGLXQUERYDRAWABLEPROC) load(userptr, "glXQueryDrawable"); + glad_glXSelectEvent = (PFNGLXSELECTEVENTPROC) load(userptr, "glXSelectEvent"); +} +static void glad_glx_load_GLX_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_VERSION_1_4) return; + glad_glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC) load(userptr, "glXGetProcAddress"); +} +static void glad_glx_load_GLX_MESA_query_renderer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_MESA_query_renderer) return; + glad_glXQueryCurrentRendererIntegerMESA = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) load(userptr, "glXQueryCurrentRendererIntegerMESA"); + glad_glXQueryCurrentRendererStringMESA = (PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) load(userptr, "glXQueryCurrentRendererStringMESA"); + glad_glXQueryRendererIntegerMESA = (PFNGLXQUERYRENDERERINTEGERMESAPROC) load(userptr, "glXQueryRendererIntegerMESA"); + glad_glXQueryRendererStringMESA = (PFNGLXQUERYRENDERERSTRINGMESAPROC) load(userptr, "glXQueryRendererStringMESA"); +} +static void glad_glx_load_GLX_SGI_swap_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GLX_SGI_swap_control) return; + glad_glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) load(userptr, "glXSwapIntervalSGI"); +} + + + +static int glad_glx_has_extension(Display *display, int screen, const char *ext) { +#ifndef GLX_VERSION_1_1 + (void) display; + (void) screen; + (void) ext; +#else + const char *terminator; + const char *loc; + const char *extensions; + + if (glXQueryExtensionsString == NULL) { + return 0; + } + + extensions = glXQueryExtensionsString(display, screen); + + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) + break; + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#endif + + return 0; +} + +static GLADapiproc glad_glx_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_glx_find_extensions(Display *display, int screen) { + GLAD_GLX_MESA_query_renderer = glad_glx_has_extension(display, screen, "GLX_MESA_query_renderer"); + GLAD_GLX_SGI_swap_control = glad_glx_has_extension(display, screen, "GLX_SGI_swap_control"); + return 1; +} + +static int glad_glx_find_core_glx(Display **display, int *screen) { + int major = 0, minor = 0; + if(*display == NULL) { +#ifdef GLAD_GLX_NO_X11 + (void) screen; + return 0; +#else + *display = XOpenDisplay(0); + if (*display == NULL) { + return 0; + } + *screen = XScreenNumberOfScreen(XDefaultScreenOfDisplay(*display)); +#endif + } + glXQueryVersion(*display, &major, &minor); + GLAD_GLX_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GLX_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GLX_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GLX_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GLX_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadGLXUserPtr(Display *display, int screen, GLADuserptrloadfunc load, void *userptr) { + int version; + glXQueryVersion = (PFNGLXQUERYVERSIONPROC) load(userptr, "glXQueryVersion"); + if(glXQueryVersion == NULL) return 0; + version = glad_glx_find_core_glx(&display, &screen); + + glad_glx_load_GLX_VERSION_1_0(load, userptr); + glad_glx_load_GLX_VERSION_1_1(load, userptr); + glad_glx_load_GLX_VERSION_1_2(load, userptr); + glad_glx_load_GLX_VERSION_1_3(load, userptr); + glad_glx_load_GLX_VERSION_1_4(load, userptr); + + if (!glad_glx_find_extensions(display, screen)) return 0; + glad_glx_load_GLX_MESA_query_renderer(load, userptr); + glad_glx_load_GLX_SGI_swap_control(load, userptr); + + return version; +} + +int gladLoadGLX(Display *display, int screen, GLADloadfunc load) { + return gladLoadGLXUserPtr(display, screen, glad_glx_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + +#ifdef __cplusplus +} +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/src/wgl.cpp 0ad-0.0.26/libraries/source/glad/src/wgl.cpp --- 0ad-0.0.25b/libraries/source/glad/src/wgl.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/src/wgl.cpp 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_WGL_VERSION_1_0 = 0; +int GLAD_WGL_ARB_extensions_string = 0; +int GLAD_WGL_EXT_extensions_string = 0; +int GLAD_WGL_EXT_swap_control = 0; + + + +PFNWGLGETEXTENSIONSSTRINGARBPROC glad_wglGetExtensionsStringARB = NULL; +PFNWGLGETEXTENSIONSSTRINGEXTPROC glad_wglGetExtensionsStringEXT = NULL; +PFNWGLGETSWAPINTERVALEXTPROC glad_wglGetSwapIntervalEXT = NULL; +PFNWGLSWAPINTERVALEXTPROC glad_wglSwapIntervalEXT = NULL; + + +static void glad_wgl_load_WGL_ARB_extensions_string(GLADuserptrloadfunc load, void *userptr) { + if(!GLAD_WGL_ARB_extensions_string) return; + glad_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) load(userptr, "wglGetExtensionsStringARB"); +} +static void glad_wgl_load_WGL_EXT_extensions_string(GLADuserptrloadfunc load, void *userptr) { + if(!GLAD_WGL_EXT_extensions_string) return; + glad_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) load(userptr, "wglGetExtensionsStringEXT"); +} +static void glad_wgl_load_WGL_EXT_swap_control(GLADuserptrloadfunc load, void *userptr) { + if(!GLAD_WGL_EXT_swap_control) return; + glad_wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) load(userptr, "wglGetSwapIntervalEXT"); + glad_wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) load(userptr, "wglSwapIntervalEXT"); +} + + + +static int glad_wgl_has_extension(HDC hdc, const char *ext) { + const char *terminator; + const char *loc; + const char *extensions; + + if(wglGetExtensionsStringEXT == NULL && wglGetExtensionsStringARB == NULL) + return 0; + + if(wglGetExtensionsStringARB == NULL || hdc == INVALID_HANDLE_VALUE) + extensions = wglGetExtensionsStringEXT(); + else + extensions = wglGetExtensionsStringARB(hdc); + + if(extensions == NULL || ext == NULL) + return 0; + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) + break; + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) + { + return 1; + } + extensions = terminator; + } + + return 0; +} + +static GLADapiproc glad_wgl_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_wgl_find_extensions_wgl(HDC hdc) { + GLAD_WGL_ARB_extensions_string = glad_wgl_has_extension(hdc, "WGL_ARB_extensions_string"); + GLAD_WGL_EXT_extensions_string = glad_wgl_has_extension(hdc, "WGL_EXT_extensions_string"); + GLAD_WGL_EXT_swap_control = glad_wgl_has_extension(hdc, "WGL_EXT_swap_control"); + return 1; +} + +static int glad_wgl_find_core_wgl(void) { + int major = 1, minor = 0; + GLAD_WGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadWGLUserPtr(HDC hdc, GLADuserptrloadfunc load, void *userptr) { + int version; + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) load(userptr, "wglGetExtensionsStringARB"); + wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) load(userptr, "wglGetExtensionsStringEXT"); + if(wglGetExtensionsStringARB == NULL && wglGetExtensionsStringEXT == NULL) return 0; + version = glad_wgl_find_core_wgl(); + + + if (!glad_wgl_find_extensions_wgl(hdc)) return 0; + glad_wgl_load_WGL_ARB_extensions_string(load, userptr); + glad_wgl_load_WGL_EXT_extensions_string(load, userptr); + glad_wgl_load_WGL_EXT_swap_control(load, userptr); + + return version; +} + +int gladLoadWGL(HDC hdc, GLADloadfunc load) { + return gladLoadWGLUserPtr(hdc, glad_wgl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + +#ifdef __cplusplus +} +#endif diff -Nru 0ad-0.0.25b/libraries/source/glad/update-headers.cmd 0ad-0.0.26/libraries/source/glad/update-headers.cmd --- 0ad-0.0.25b/libraries/source/glad/update-headers.cmd 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/update-headers.cmd 2022-09-23 20:37:15.000000000 +0000 @@ -0,0 +1,11 @@ +@echo off +cd glad +python -m glad --api="gl:core=2.1" --extensions="../extensions/gl.txt" --out-path="../" +python -m glad --api="gles2=2.0" --extensions="../extensions/gles2.txt" --out-path="../" +python -m glad --api="glx=1.4" --extensions="../extensions/glx.txt" --out-path="../" +python -m glad --api="wgl=1.0" --extensions="../extensions/wgl.txt" --out-path="../" +cd .. +MOVE src\gl.c src\gl.cpp +MOVE src\gles2.c src\gles2.cpp +MOVE src\glx.c src\glx.cpp +MOVE src\wgl.c src\wgl.cpp diff -Nru 0ad-0.0.25b/libraries/source/glad/update-headers.sh 0ad-0.0.26/libraries/source/glad/update-headers.sh --- 0ad-0.0.25b/libraries/source/glad/update-headers.sh 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/glad/update-headers.sh 2022-09-23 20:37:14.000000000 +0000 @@ -0,0 +1,13 @@ +#!/bin/sh +cd glad +python -m glad --api="gl:core=2.1" --extensions="../extensions/gl.txt" --out-path="../" +python -m glad --api="gles2=2.0" --extensions="../extensions/gles2.txt" --out-path="../" +python -m glad --api="glx=1.4" --extensions="../extensions/glx.txt" --out-path="../" +python -m glad --api="wgl=1.0" --extensions="../extensions/wgl.txt" --out-path="../" +python -m glad --api="egl=1.5" --extensions="../extensions/egl.txt" --out-path="../" +cd .. +mv src/gl.c src/gl.cpp +mv src/gles2.c src/gles2.cpp +mv src/glx.c src/glx.cpp +mv src/wgl.c src/wgl.cpp +mv src/egl.c src/egl.cpp diff -Nru 0ad-0.0.25b/libraries/source/nvtt/build.sh 0ad-0.0.26/libraries/source/nvtt/build.sh --- 0ad-0.0.25b/libraries/source/nvtt/build.sh 2021-08-25 14:44:54.000000000 +0000 +++ 0ad-0.0.26/libraries/source/nvtt/build.sh 2022-09-23 20:36:55.000000000 +0000 @@ -6,6 +6,7 @@ LDFLAGS=${LDFLAGS:=""} CFLAGS=${CFLAGS:=""} CXXFLAGS=${CXXFLAGS:=""} +CMAKE_FLAGS=${CMAKE_FLAGS:=""} if [ -e .already-built ] && [ "$(cat .already-built)" = "${LIB_VERSION}" ] then @@ -31,6 +32,7 @@ -DCMAKE_C_FLAGS="$CFLAGS" \ -DCMAKE_CXX_FLAGS="$CXXFLAGS" \ -DCMAKE_BUILD_TYPE=Release \ + $CMAKE_FLAGS \ -DBINDIR=bin \ -DLIBDIR=lib \ -DPNG=0 \ @@ -40,10 +42,11 @@ -DCMAKE_LINK_FLAGS="$LDFLAGS" \ -DCMAKE_C_FLAGS="$CFLAGS" \ -DCMAKE_CXX_FLAGS="$CXXFLAGS" \ - -DNVTT_SHARED=1 \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ + $CMAKE_FLAGS \ + -DNVTT_SHARED=1 \ -DOpenGL_GL_PREFERENCE=GLVND \ - -DCMAKE_BUILD_TYPE=Release \ -DBINDIR=bin \ -DLIBDIR=lib \ -G "Unix Makefiles" diff -Nru 0ad-0.0.25b/libraries/source/nvtt/src/src/nvcore/Debug.cpp 0ad-0.0.26/libraries/source/nvtt/src/src/nvcore/Debug.cpp --- 0ad-0.0.25b/libraries/source/nvtt/src/src/nvcore/Debug.cpp 2021-08-25 14:44:56.000000000 +0000 +++ 0ad-0.0.26/libraries/source/nvtt/src/src/nvcore/Debug.cpp 2022-09-23 20:36:48.000000000 +0000 @@ -607,6 +607,9 @@ # elif NV_CPU_ARM ucontext_t * ucp = (ucontext_t *)secret; return (void *) ucp->uc_mcontext->__ss.__pc; +# elif NV_CPU_AARCH64 + ucontext_t * ucp = (ucontext_t *)secret; + return (void *) ucp->uc_mcontext->__ss.__pc; # else # error "Unknown CPU" # endif diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/build.sh 0ad-0.0.26/libraries/source/spidermonkey/build.sh --- 0ad-0.0.25b/libraries/source/spidermonkey/build.sh 2021-08-25 14:44:51.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/build.sh 2022-09-23 20:36:41.000000000 +0000 @@ -5,7 +5,7 @@ # This should match the version in config/milestone.txt FOLDER="mozjs-78.6.0" # If same-version changes are needed, increment this. -LIB_VERSION="78.6.0+2" +LIB_VERSION="78.6.0+3" LIB_NAME="mozjs78-ps" # Since this script is called by update-workspaces.sh, we want to quickly @@ -49,6 +49,19 @@ if [ "`uname -s`" = "Darwin" ] then + ARCH=${ARCH:=""} + if [ -z "${ARCH}" ]; then + if [ "`uname -m`" == "arm64" ]; then + ARCH="aarch64" + else + ARCH="x86_64" + fi + elif [ $ARCH == "arm64" ]; then + # SM78 doesn't know about arm64 yet, and that's passed by build-osx-libs.sh, so fix it explicitly. + ARCH="aarch64" + fi + CONF_OPTS="${CONF_OPTS} --target=$ARCH-apple-darwin" + # Link to custom-built zlib export PKG_CONFIG_PATH="=${ZLIB_DIR}:${PKG_CONFIG_PATH}" CONF_OPTS="${CONF_OPTS} --with-system-zlib" @@ -107,6 +120,8 @@ # Apply patches cd "$FOLDER" . ../patch.sh + # Copy a more recent autoconf config.guess to handle ARM macs properly. + cp -f ../config.guess build/autoconf/ # Prevent complaining that configure is outdated. touch ./js/src/configure else diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/config.guess 0ad-0.0.26/libraries/source/spidermonkey/config.guess --- 0ad-0.0.25b/libraries/source/spidermonkey/config.guess 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/config.guess 2022-09-23 20:36:26.000000000 +0000 @@ -0,0 +1,1687 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2020 Free Software Foundation, Inc. + +timestamp='2020-07-12' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2020 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD="$driver" + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if test -f /.attbin/uname ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "$UNAME_SYSTEM" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ + echo unknown)` + case "$UNAME_MACHINE_ARCH" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown + ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "$UNAME_MACHINE_ARCH" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "$UNAME_MACHINE_ARCH" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "$UNAME_VERSION" in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "$machine-${os}${release}${abi-}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" + exit ;; + *:ekkoBSD:*:*) + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" + exit ;; + *:SolidBSD:*:*) + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" + exit ;; + *:OS108:*:*) + echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:MirBSD:*:*) + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:Sortix:*:*) + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Twizzler:*:*) + echo "$UNAME_MACHINE"-unknown-twizzler + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix"$UNAME_RELEASE" + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux"$UNAME_RELEASE" + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos"$UNAME_RELEASE" + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos"$UNAME_RELEASE" + ;; + sun4) + echo sparc-sun-sunos"$UNAME_RELEASE" + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos"$UNAME_RELEASE" + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint"$UNAME_RELEASE" + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint"$UNAME_RELEASE" + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint"$UNAME_RELEASE" + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten"$UNAME_RELEASE" + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten"$UNAME_RELEASE" + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix"$UNAME_RELEASE" + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix"$UNAME_RELEASE" + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix"$UNAME_RELEASE" + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos"$UNAME_RELEASE" + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] + then + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] + then + echo m88k-dg-dgux"$UNAME_RELEASE" + else + echo m88k-dg-dguxbcs"$UNAME_RELEASE" + fi + else + echo i586-dg-dgux"$UNAME_RELEASE" + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "$sc_cpu_version" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "$sc_kernel_bits" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "$HP_ARCH" = "" ]; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ "$HP_ARCH" = hppa2.0w ] + then + set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" + exit ;; + 3050*:HI-UX:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo "$UNAME_MACHINE"-unknown-osf1mk + else + echo "$UNAME_MACHINE"-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi"$UNAME_RELEASE" + exit ;; + *:BSD/OS:*:*) + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" + exit ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi + else + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf + fi + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case "$UNAME_PROCESSOR" in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + i*:CYGWIN*:*) + echo "$UNAME_MACHINE"-pc-cygwin + exit ;; + *:MINGW64*:*) + echo "$UNAME_MACHINE"-pc-mingw64 + exit ;; + *:MINGW*:*) + echo "$UNAME_MACHINE"-pc-mingw32 + exit ;; + *:MSYS*:*) + echo "$UNAME_MACHINE"-pc-msys + exit ;; + i*:PW*:*) + echo "$UNAME_MACHINE"-pc-pw32 + exit ;; + *:Interix*:*) + case "$UNAME_MACHINE" in + x86) + echo i586-pc-interix"$UNAME_RELEASE" + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix"$UNAME_RELEASE" + exit ;; + IA64) + echo ia64-unknown-interix"$UNAME_RELEASE" + exit ;; + esac ;; + i*:UWIN*:*) + echo "$UNAME_MACHINE"-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-pc-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + *:GNU:*:*) + # the GNU system + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" + exit ;; + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix + exit ;; + aarch64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + else + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + cris:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + crisv32:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + e2k:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + frv:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + hexagon:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + ia64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + k1om:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m32r*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m68*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + MIPS_ENDIAN=el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + MIPS_ENDIAN= + #else + MIPS_ENDIAN= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-"$LIBC" + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-"$LIBC" + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-"$LIBC" + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-"$LIBC" + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-"$LIBC" + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-"$LIBC" + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-"$LIBC" + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" + exit ;; + sh64*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sh*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + tile*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + vax:Linux:*:*) + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" + exit ;; + x86_64:Linux:*:*) + set_cc_for_build + LIBCABI=$LIBC + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_X32 >/dev/null + then + LIBCABI="$LIBC"x32 + fi + fi + echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" + exit ;; + xtensa*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo "$UNAME_MACHINE"-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo "$UNAME_MACHINE"-unknown-stop + exit ;; + i*86:atheos:*:*) + echo "$UNAME_MACHINE"-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo "$UNAME_MACHINE"-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos"$UNAME_RELEASE" + exit ;; + i*86:*DOS:*:*) + echo "$UNAME_MACHINE"-pc-msdosdjgpp + exit ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos"$UNAME_RELEASE" + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos"$UNAME_RELEASE" + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv"$UNAME_RELEASE" + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo "$UNAME_MACHINE"-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo "$UNAME_MACHINE"-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux"$UNAME_RELEASE" + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv"$UNAME_RELEASE" + else + echo mips-unknown-sysv"$UNAME_RELEASE" + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux"$UNAME_RELEASE" + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux"$UNAME_RELEASE" + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux"$UNAME_RELEASE" + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux"$UNAME_RELEASE" + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux"$UNAME_RELEASE" + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Rhapsody:*:*) + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" + exit ;; + arm64:Darwin:*:*) + echo aarch64-apple-darwin"$UNAME_RELEASE" + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build + fi + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE + fi + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + # shellcheck disable=SC2154 + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo "$UNAME_MACHINE"-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux"$UNAME_RELEASE" + exit ;; + *:DragonFly:*:*) + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "$UNAME_MACHINE" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" + exit ;; + i*86:rdos:*:*) + echo "$UNAME_MACHINE"-pc-rdos + exit ;; + i*86:AROS:*:*) + echo "$UNAME_MACHINE"-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo "$UNAME_MACHINE"-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; + *:Unleashed:*:*) + echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" + exit ;; +esac + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF +fi + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/FixMacBuild.diff 0ad-0.0.26/libraries/source/spidermonkey/FixMacBuild.diff --- 0ad-0.0.25b/libraries/source/spidermonkey/FixMacBuild.diff 2021-08-25 14:44:38.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/FixMacBuild.diff 2022-09-23 20:36:27.000000000 +0000 @@ -13,12 +13,84 @@ js_flags.append('-Xclang') --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure -@@ -141,7 +141,7 @@ +@@ -141,7 +141,6 @@ @imports(_from='biplist', _import='readPlist') def macos_sdk(sdk, host): sdk_min_version = Version('10.11') - sdk_max_version = Version('10.15.4') -+ sdk_max_version = Version('11.99') if sdk: - sdk = sdk[0] \ No newline at end of file + sdk = sdk[0] +@@ -170,11 +169,6 @@ + 'You may need to point to it using --with-macos-sdk= in your ' + 'mozconfig. Various SDK versions are available from ' + 'https://github.com/phracker/MacOSX-SDKs' % (version, sdk_min_version)) +- if version > sdk_max_version: +- die('SDK version "%s" is unsupported. Please downgrade to version ' +- '%s. You may need to point to it using --with-macos-sdk= in ' +- 'your mozconfig. Various SDK versions are available from ' +- 'https://github.com/phracker/MacOSX-SDKs' % (version, sdk_max_version)) + return sdk + + set_config('MACOS_SDK_DIR', macos_sdk) +--- a/build/moz.configure/init.configure ++++ b/build/moz.configure/init.configure +@@ -375,9 +375,6 @@ + sys.exit(subprocess.call([python] + sys.argv)) + + # We are now in the virtualenv +- if not distutils.sysconfig.get_python_lib(): +- die('Could not determine python site packages directory') +- + str_version = '.'.join(str(v) for v in version) + + return namespace( +--- a/js/src/jit/arm64/vixl/MozCpu-vixl.cpp ++++ b/js/src/jit/arm64/vixl/MozCpu-vixl.cpp +@@ -69,7 +69,7 @@ void CPU::SetUp() { + + + uint32_t CPU::GetCacheType() { +-#if defined(__aarch64__) && !defined(_MSC_VER) ++#if defined(__aarch64__) && (defined(__linux__) || defined(__android__)) + uint64_t cache_type_register; + // Copy the content of the cache type register to a core register. + __asm__ __volatile__ ("mrs %[ctr], ctr_el0" // NOLINT +--- a/js/src/wasm/WasmSignalHandlers.cpp ++++ b/js/src/wasm/WasmSignalHandlers.cpp +@@ -226,6 +226,10 @@ using mozilla::DebugOnly; + # define R13_sig(p) ((p)->thread.__sp) + # define R14_sig(p) ((p)->thread.__lr) + # define R15_sig(p) ((p)->thread.__pc) ++# define EPC_sig(p) ((p)->thread.__pc) ++# define RFP_sig(p) ((p)->thread.__fp) ++# define R31_sig(p) ((p)->thread.__sp) ++# define RLR_sig(p) ((p)->thread.__lr) + #else + # error "Don't know how to read/write to the thread state via the mcontext_t." + #endif +@@ -351,6 +355,12 @@ struct macos_arm_context { + arm_neon_state_t float_; + }; + # define CONTEXT macos_arm_context ++# elif defined(__aarch64__) ++struct macos_aarch64_context { ++ arm_thread_state64_t thread; ++ arm_neon_state64_t float_; ++}; ++# define CONTEXT macos_aarch64_context + # else + # error Unsupported architecture + # endif +@@ -816,6 +826,11 @@ static bool HandleMachException(const ExceptionRequest& request) { + unsigned int float_state_count = ARM_NEON_STATE_COUNT; + int thread_state = ARM_THREAD_STATE; + int float_state = ARM_NEON_STATE; ++# elif defined(__aarch64__) ++ unsigned int thread_state_count = ARM_THREAD_STATE64_COUNT; ++ unsigned int float_state_count = ARM_NEON_STATE64_COUNT; ++ int thread_state = ARM_THREAD_STATE64; ++ int float_state = ARM_NEON_STATE64; + # else + # error Unsupported architecture + # endif diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/FixPythonCollectionABC.diff 0ad-0.0.26/libraries/source/spidermonkey/FixPythonCollectionABC.diff --- 0ad-0.0.25b/libraries/source/spidermonkey/FixPythonCollectionABC.diff 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/FixPythonCollectionABC.diff 2022-09-23 20:36:41.000000000 +0000 @@ -0,0 +1,87 @@ +--- a/python/mach/mach/config.py ++++ b/python/mach/mach/config.py +@@ -144,7 +144,7 @@ + return _ + + +-class ConfigSettings(collections.Mapping): ++class ConfigSettings(collections.abc.Mapping): + """Interface for configuration settings. + + This is the main interface to the configuration. +@@ -190,7 +190,7 @@ + will result in exceptions being raised. + """ + +- class ConfigSection(collections.MutableMapping, object): ++ class ConfigSection(collections.abc.MutableMapping, object): + """Represents an individual config section.""" + def __init__(self, config, name, settings): + object.__setattr__(self, '_config', config) +--- a/python/mach/mach/decorators.py ++++ b/python/mach/mach/decorators.py +@@ -159,7 +159,7 @@ + 'Conditions argument must take a list ' + \ + 'of functions. Found %s instead.' + +- if not isinstance(command.conditions, collections.Iterable): ++ if not isinstance(command.conditions, collections.abc.Iterable): + msg = msg % (command.name, type(command.conditions)) + raise MachError(msg) + +--- a/python/mach/mach/main.py ++++ b/python/mach/mach/main.py +@@ -16,7 +16,7 @@ + import sys + import traceback + import uuid +-from collections import Iterable ++from collections.abc import Iterable + + from six import string_types + +--- a/python/mozbuild/mozbuild/backend/configenvironment.py ++++ b/python/mozbuild/mozbuild/backend/configenvironment.py +@@ -9,7 +9,8 @@ + import sys + import json + +-from collections import Iterable, OrderedDict ++from collections import OrderedDict ++from collections.abc import Iterable + from types import ModuleType + + import mozpack.path as mozpath +--- a/python/mozbuild/mozbuild/makeutil.py ++++ b/python/mozbuild/mozbuild/makeutil.py +@@ -7,7 +7,7 @@ + import os + import re + import six +-from collections import Iterable ++from collections.abc import Iterable + + + class Makefile(object): +--- a/python/mozbuild/mozbuild/util.py ++++ b/python/mozbuild/mozbuild/util.py +@@ -782,7 +782,7 @@ + self._strings = StrictOrderingOnAppendList() + self._children = {} + +- class StringListAdaptor(collections.Sequence): ++ class StringListAdaptor(collections.abc.Sequence): + def __init__(self, hsl): + self._hsl = hsl + +--- a/testing/mozbase/manifestparser/manifestparser/filters.py ++++ b/testing/mozbase/manifestparser/manifestparser/filters.py +@@ -15,1 +15,2 @@ +-from collections import defaultdict, MutableSequence ++from collections import defaultdict ++from collections.abc import MutableSequence +--- a/third_party/python/pipenv/pipenv/vendor/jinja2/sandbox.py ++++ b/third_party/python/pipenv/pipenv/vendor/jinja2/sandbox.py +@@ -82,1 +82,1 @@ +-from collections import MutableSet, MutableMapping, MutableSequence ++from collections.abc import MutableSet, MutableMapping, MutableSequence diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/FixVirtualEnv.diff 0ad-0.0.26/libraries/source/spidermonkey/FixVirtualEnv.diff --- 0ad-0.0.25b/libraries/source/spidermonkey/FixVirtualEnv.diff 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/FixVirtualEnv.diff 2022-09-23 20:36:41.000000000 +0000 @@ -0,0 +1,20 @@ +--- a/python/mozbuild/mozbuild/virtualenv.py ++++ b/python/mozbuild/mozbuild/virtualenv.py +@@ -235,7 +235,7 @@ + if os.path.islink(venv_python): + os.remove(venv_python) + +- args = [python, self.virtualenv_script_path, ++ args = [python, "-m" "virtualenv", + # Without this, virtualenv.py may attempt to contact the outside + # world and search for or download a newer version of pip, + # setuptools, or wheel. This is bad for security, reproducibility, +@@ -438,7 +438,7 @@ + handle_package(package) + + sitecustomize = os.path.join( +- os.path.dirname(os.__file__), 'sitecustomize.py') ++ os.path.dirname(sys.executable), 'sitecustomize.py') + with open(sitecustomize, 'w') as f: + f.write( + '# Importing mach_bootstrap has the side effect of\n' diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/FixVirtualenvForPython310.diff 0ad-0.0.26/libraries/source/spidermonkey/FixVirtualenvForPython310.diff --- 0ad-0.0.25b/libraries/source/spidermonkey/FixVirtualenvForPython310.diff 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/FixVirtualenvForPython310.diff 2022-09-23 20:36:41.000000000 +0000 @@ -0,0 +1,15 @@ +--- a/third_party/python/virtualenv/virtualenv.py ++++ b/third_party/python/virtualenv/virtualenv.py +@@ -1804,7 +1804,11 @@ + pass + else: + # noinspection PyProtectedMember +- if sysconfig._get_default_scheme() == "posix_local": ++ try: # Python >= 3.10 ++ default_scheme = sysconfig.get_default_scheme() ++ except: # Python < 3.10 ++ default_scheme = sysconfig._get_default_scheme() ++ if default_scheme == "posix_local": + local_path = os.path.join(home_dir, "local") + if not os.path.exists(local_path): + os.mkdir(local_path) diff -Nru 0ad-0.0.25b/libraries/source/spidermonkey/patch.sh 0ad-0.0.26/libraries/source/spidermonkey/patch.sh --- 0ad-0.0.25b/libraries/source/spidermonkey/patch.sh 2021-08-25 14:44:51.000000000 +0000 +++ 0ad-0.0.26/libraries/source/spidermonkey/patch.sh 2022-09-23 20:36:41.000000000 +0000 @@ -2,6 +2,33 @@ # Apply patches if needed # This script gets called from build.sh. +# SM78 fails to create virtual envs on macs with python > 3.7 +# Unfortunately, 3.7 is mostly unavailable on ARM macs. +# Therefore, replace the custom script with a more up-to-date version from pip +# if python is detected to be newer than 3.7. +if [ "$(uname -s)" = "Darwin" ]; +then + PYTHON_MINOR_VERSION="$(python3 -c 'import sys; print(sys.version_info.minor)')" + if [ "$PYTHON_MINOR_VERSION" -gt 7 ]; + then + # SM actually uses features from the full-fledged virtualenv package + # and not just venv, so install it to be safe. + # Install it locally to not pollute anything. + # Install specifically a version that's know to work. + pip3 install --upgrade -t virtualenv 'virtualenv==20.13.1' + export PYTHONPATH="$(pwd)/virtualenv:$PYTHONPATH" + patch -p1 < ../FixVirtualEnv.diff + fi +else + # In python 3.10 `sysconfig._get_default_scheme()` was renamed to + # `sysconfig.get_default_scheme()`. This breaks the version of + # `virtualenv` bundled with the spidermonkey source code. + # + # It is assumed that the updated version fetched for macOS systems + # above does not have this problem. + patch -p1 < ../FixVirtualenvForPython310.diff +fi + # Mozglue symbols need to be linked against static builds. # https://bugzilla.mozilla.org/show_bug.cgi?id=1588340 patch -p1 < ../FixMozglue.diff @@ -34,6 +61,11 @@ # so this patches it to an arbitrarily high Mac OS 11 patch -p1 < ../FixMacBuild.diff +# In python 3.3, the Collections' Abstract Base Classes were moved from `collections` to +# `collections.abc`, and aliases were set up for backwards compatibility. +# In python 3.10, these aliases were removed, requiring all code that used them to update. +patch -p1 < ../FixPythonCollectionABC.diff + # Fix FP access breaking compilation on RPI3+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1526653 # https://bugzilla.mozilla.org/show_bug.cgi?id=1536491 diff -Nru 0ad-0.0.25b/libraries/source/valgrind/include/callgrind.h 0ad-0.0.26/libraries/source/valgrind/include/callgrind.h --- 0ad-0.0.25b/libraries/source/valgrind/include/callgrind.h 2021-08-25 14:44:38.000000000 +0000 +++ 0ad-0.0.26/libraries/source/valgrind/include/callgrind.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ - -/* - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (callgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of callgrind, a valgrind tool for cache simulation - and call tree tracing. - - Copyright (C) 2003-2012 Josef Weidendorfer. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (callgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - -#ifndef __CALLGRIND_H -#define __CALLGRIND_H - -#include "valgrind.h" - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. - - The identification ('C','T') for Callgrind has historical - reasons: it was called "Calltree" before. Besides, ('C','G') would - clash with cachegrind. - */ - -typedef - enum { - VG_USERREQ__DUMP_STATS = VG_USERREQ_TOOL_BASE('C','T'), - VG_USERREQ__ZERO_STATS, - VG_USERREQ__TOGGLE_COLLECT, - VG_USERREQ__DUMP_STATS_AT, - VG_USERREQ__START_INSTRUMENTATION, - VG_USERREQ__STOP_INSTRUMENTATION - } Vg_CallgrindClientRequest; - -/* Dump current state of cost centers, and zero them afterwards */ -#define CALLGRIND_DUMP_STATS \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DUMP_STATS, \ - 0, 0, 0, 0, 0) - -/* Dump current state of cost centers, and zero them afterwards. - The argument is appended to a string stating the reason which triggered - the dump. This string is written as a description field into the - profile data dump. */ -#define CALLGRIND_DUMP_STATS_AT(pos_str) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DUMP_STATS_AT, \ - pos_str, 0, 0, 0, 0) - -/* Zero cost centers */ -#define CALLGRIND_ZERO_STATS \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ZERO_STATS, \ - 0, 0, 0, 0, 0) - -/* Toggles collection state. - The collection state specifies whether the happening of events - should be noted or if they are to be ignored. Events are noted - by increment of counters in a cost center */ -#define CALLGRIND_TOGGLE_COLLECT \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__TOGGLE_COLLECT, \ - 0, 0, 0, 0, 0) - -/* Start full callgrind instrumentation if not already switched on. - When cache simulation is done, it will flush the simulated cache; - this will lead to an artifical cache warmup phase afterwards with - cache misses which would not have happened in reality. */ -#define CALLGRIND_START_INSTRUMENTATION \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__START_INSTRUMENTATION, \ - 0, 0, 0, 0, 0) - -/* Stop full callgrind instrumentation if not already switched off. - This flushes Valgrinds translation cache, and does no additional - instrumentation afterwards, which effectivly will run at the same - speed as the "none" tool (ie. at minimal slowdown). - Use this to bypass Callgrind aggregation for uninteresting code parts. - To start Callgrind in this mode to ignore the setup phase, use - the option "--instr-atstart=no". */ -#define CALLGRIND_STOP_INSTRUMENTATION \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STOP_INSTRUMENTATION, \ - 0, 0, 0, 0, 0) - -#endif /* __CALLGRIND_H */ diff -Nru 0ad-0.0.25b/libraries/source/valgrind/include/memcheck.h 0ad-0.0.26/libraries/source/valgrind/include/memcheck.h --- 0ad-0.0.25b/libraries/source/valgrind/include/memcheck.h 2021-08-25 14:44:38.000000000 +0000 +++ 0ad-0.0.26/libraries/source/valgrind/include/memcheck.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,287 +0,0 @@ - -/* - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (memcheck.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of MemCheck, a heavyweight Valgrind tool for - detecting memory errors. - - Copyright (C) 2000-2012 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (memcheck.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -#ifndef __MEMCHECK_H -#define __MEMCHECK_H - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query memory permissions - inside your own programs. - - See comment near the top of valgrind.h on how to use them. -*/ - -#include "valgrind.h" - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. */ -typedef - enum { - VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), - VG_USERREQ__MAKE_MEM_UNDEFINED, - VG_USERREQ__MAKE_MEM_DEFINED, - VG_USERREQ__DISCARD, - VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, - VG_USERREQ__CHECK_MEM_IS_DEFINED, - VG_USERREQ__DO_LEAK_CHECK, - VG_USERREQ__COUNT_LEAKS, - - VG_USERREQ__GET_VBITS, - VG_USERREQ__SET_VBITS, - - VG_USERREQ__CREATE_BLOCK, - - VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, - - /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */ - VG_USERREQ__COUNT_LEAK_BLOCKS, - - /* This is just for memcheck's internal use - don't use it */ - _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR - = VG_USERREQ_TOOL_BASE('M','C') + 256 - } Vg_MemCheckClientRequest; - - - -/* Client-code macros to manipulate the state of memory. */ - -/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_NOACCESS, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Similarly, mark memory at _qzz_addr as addressable but undefined - for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_UNDEFINED, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Similarly, mark memory at _qzz_addr as addressable and defined - for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_DEFINED, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is - not altered: bytes which are addressable are marked as defined, - but those which are not addressable are left unchanged. */ -#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Create a block-description handle. The description is an ascii - string which is included in any messages pertaining to addresses - within the specified memory range. Has no other effect on the - properties of the memory range. */ -#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CREATE_BLOCK, \ - (_qzz_addr), (_qzz_len), (_qzz_desc), \ - 0, 0) - -/* Discard a block-description-handle. Returns 1 for an - invalid handle, 0 for a valid handle. */ -#define VALGRIND_DISCARD(_qzz_blkindex) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__DISCARD, \ - 0, (_qzz_blkindex), 0, 0, 0) - - -/* Client-code macros to check the state of memory. */ - -/* Check that memory at _qzz_addr is addressable for _qzz_len bytes. - If suitable addressibility is not established, Valgrind prints an - error message and returns the address of the first offending byte. - Otherwise it returns zero. */ -#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Check that memory at _qzz_addr is addressable and defined for - _qzz_len bytes. If suitable addressibility and definedness are not - established, Valgrind prints an error message and returns the - address of the first offending byte. Otherwise it returns zero. */ -#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__CHECK_MEM_IS_DEFINED, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Use this macro to force the definedness and addressibility of an - lvalue to be checked. If suitable addressibility and definedness - are not established, Valgrind prints an error message and returns - the address of the first offending byte. Otherwise it returns - zero. */ -#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \ - VALGRIND_CHECK_MEM_IS_DEFINED( \ - (volatile unsigned char *)&(__lvalue), \ - (unsigned long)(sizeof (__lvalue))) - - -/* Do a full memory leak check (like --leak-check=full) mid-execution. */ -#define VALGRIND_DO_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 0, 0, 0, 0, 0) - -/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for - which there was an increase in leaked bytes or leaked nr of blocks - since the previous leak search. */ -#define VALGRIND_DO_ADDED_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 0, 1, 0, 0, 0) - -/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with - increased or decreased leaked bytes/blocks since previous leak - search. */ -#define VALGRIND_DO_CHANGED_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 0, 2, 0, 0, 0) - -/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */ -#define VALGRIND_DO_QUICK_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 1, 0, 0, 0, 0) - -/* Return number of leaked, dubious, reachable and suppressed bytes found by - all previous leak checks. They must be lvalues. */ -#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \ - /* For safety on 64-bit platforms we assign the results to private - unsigned long variables, then assign these to the lvalues the user - specified, which works no matter what type 'leaked', 'dubious', etc - are. We also initialise '_qzz_leaked', etc because - VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as - defined. */ \ - { \ - unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ - unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ - VALGRIND_DO_CLIENT_REQUEST_STMT( \ - VG_USERREQ__COUNT_LEAKS, \ - &_qzz_leaked, &_qzz_dubious, \ - &_qzz_reachable, &_qzz_suppressed, 0); \ - leaked = _qzz_leaked; \ - dubious = _qzz_dubious; \ - reachable = _qzz_reachable; \ - suppressed = _qzz_suppressed; \ - } - -/* Return number of leaked, dubious, reachable and suppressed bytes found by - all previous leak checks. They must be lvalues. */ -#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \ - /* For safety on 64-bit platforms we assign the results to private - unsigned long variables, then assign these to the lvalues the user - specified, which works no matter what type 'leaked', 'dubious', etc - are. We also initialise '_qzz_leaked', etc because - VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as - defined. */ \ - { \ - unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ - unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ - VALGRIND_DO_CLIENT_REQUEST_STMT( \ - VG_USERREQ__COUNT_LEAK_BLOCKS, \ - &_qzz_leaked, &_qzz_dubious, \ - &_qzz_reachable, &_qzz_suppressed, 0); \ - leaked = _qzz_leaked; \ - dubious = _qzz_dubious; \ - reachable = _qzz_reachable; \ - suppressed = _qzz_suppressed; \ - } - - -/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it - into the provided zzvbits array. Return values: - 0 if not running on valgrind - 1 success - 2 [previously indicated unaligned arrays; these are now allowed] - 3 if any parts of zzsrc/zzvbits are not addressable. - The metadata is not copied in cases 0, 2 or 3 so it should be - impossible to segfault your system by using this call. -*/ -#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__GET_VBITS, \ - (const char*)(zza), \ - (char*)(zzvbits), \ - (zznbytes), 0, 0) - -/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it - from the provided zzvbits array. Return values: - 0 if not running on valgrind - 1 success - 2 [previously indicated unaligned arrays; these are now allowed] - 3 if any parts of zza/zzvbits are not addressable. - The metadata is not copied in cases 0, 2 or 3 so it should be - impossible to segfault your system by using this call. -*/ -#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__SET_VBITS, \ - (const char*)(zza), \ - (const char*)(zzvbits), \ - (zznbytes), 0, 0 ) - -#endif - diff -Nru 0ad-0.0.25b/libraries/source/valgrind/include/valgrind.h 0ad-0.0.26/libraries/source/valgrind/include/valgrind.h --- 0ad-0.0.25b/libraries/source/valgrind/include/valgrind.h 2021-08-25 14:44:38.000000000 +0000 +++ 0ad-0.0.26/libraries/source/valgrind/include/valgrind.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,4840 +0,0 @@ -/* -*- c -*- - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (valgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of Valgrind, a dynamic binary instrumentation - framework. - - Copyright (C) 2000-2012 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (valgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query Valgrind's - execution inside your own programs. - - The resulting executables will still run without Valgrind, just a - little bit more slowly than they otherwise would, but otherwise - unchanged. When not running on valgrind, each client request - consumes very few (eg. 7) instructions, so the resulting performance - loss is negligible unless you plan to execute client requests - millions of times per second. Nevertheless, if that is still a - problem, you can compile with the NVALGRIND symbol defined (gcc - -DNVALGRIND) so that client requests are not even compiled in. */ - -#ifndef __VALGRIND_H -#define __VALGRIND_H - - -/* ------------------------------------------------------------------ */ -/* VERSION NUMBER OF VALGRIND */ -/* ------------------------------------------------------------------ */ - -/* Specify Valgrind's version number, so that user code can - conditionally compile based on our version number. Note that these - were introduced at version 3.6 and so do not exist in version 3.5 - or earlier. The recommended way to use them to check for "version - X.Y or later" is (eg) - -#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ - && (__VALGRIND_MAJOR__ > 3 \ - || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) -*/ -#define __VALGRIND_MAJOR__ 3 -#define __VALGRIND_MINOR__ 8 - - -#include - -/* Nb: this file might be included in a file compiled with -ansi. So - we can't use C++ style "//" comments nor the "asm" keyword (instead - use "__asm__"). */ - -/* Derive some tags indicating what the target platform is. Note - that in this file we're using the compiler's CPP symbols for - identifying architectures, which are different to the ones we use - within the rest of Valgrind. Note, __powerpc__ is active for both - 32 and 64-bit PPC, whereas __powerpc64__ is only active for the - latter (on Linux, that is). - - Misc note: how to find out what's predefined in gcc by default: - gcc -Wp,-dM somefile.c -*/ -#undef PLAT_x86_darwin -#undef PLAT_amd64_darwin -#undef PLAT_x86_win32 -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64_linux -#undef PLAT_arm_linux -#undef PLAT_s390x_linux -#undef PLAT_mips32_linux - - -#if defined(__APPLE__) && defined(__i386__) -# define PLAT_x86_darwin 1 -#elif defined(__APPLE__) && defined(__x86_64__) -# define PLAT_amd64_darwin 1 -#elif defined(__MINGW32__) || defined(__CYGWIN32__) \ - || (defined(_WIN32) && defined(_M_IX86)) -# define PLAT_x86_win32 1 -#elif defined(__linux__) && defined(__i386__) -# define PLAT_x86_linux 1 -#elif defined(__linux__) && defined(__x86_64__) -# define PLAT_amd64_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) -# define PLAT_ppc32_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) -# define PLAT_ppc64_linux 1 -#elif defined(__linux__) && defined(__arm__) -# define PLAT_arm_linux 1 -#elif defined(__linux__) && defined(__s390__) && defined(__s390x__) -# define PLAT_s390x_linux 1 -#elif defined(__linux__) && defined(__mips__) -# define PLAT_mips32_linux 1 -#else -/* If we're not compiling for our target platform, don't generate - any inline asms. */ -# if !defined(NVALGRIND) -# define NVALGRIND 1 -# endif -#endif - - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ -/* in here of use to end-users -- skip to the next section. */ -/* ------------------------------------------------------------------ */ - -/* - * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client - * request. Accepts both pointers and integers as arguments. - * - * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind - * client request that does not return a value. - - * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind - * client request and whose value equals the client request result. Accepts - * both pointers and integers as arguments. Note that such calls are not - * necessarily pure functions -- they may have side effects. - */ - -#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ - _zzq_request, _zzq_arg1, _zzq_arg2, \ - _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ - (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ - (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) - -#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ - _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ - (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) - -#if defined(NVALGRIND) - -/* Define NVALGRIND to completely remove the Valgrind magic sequence - from the compiled code (analogous to NDEBUG's effects on - assert()) */ -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - (_zzq_default) - -#else /* ! NVALGRIND */ - -/* The following defines the magic code sequences which the JITter - spots and handles magically. Don't look too closely at them as - they will rot your brain. - - The assembly code sequences for all architectures is in this one - file. This is because this file must be stand-alone, and we don't - want to have multiple files. - - For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default - value gets put in the return slot, so that everything works when - this is executed not under Valgrind. Args are passed in a memory - block, and so there's no intrinsic limit to the number that could - be passed, but it's currently five. - - The macro args are: - _zzq_rlval result lvalue - _zzq_default default value (result returned when running on real CPU) - _zzq_request request code - _zzq_arg1..5 request params - - The other two macros are used to support function wrapping, and are - a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the - guest's NRADDR pseudo-register and whatever other information is - needed to safely run the call original from the wrapper: on - ppc64-linux, the R2 value at the divert point is also needed. This - information is abstracted into a user-visible type, OrigFn. - - VALGRIND_CALL_NOREDIR_* behaves the same as the following on the - guest, but guarantees that the branch instruction will not be - redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: - branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a - complete inline asm, since it needs to be combined with more magic - inline asm stuff to be useful. -*/ - -/* ------------------------- x86-{linux,darwin} ---------------- */ - -#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ - || (defined(PLAT_x86_win32) && defined(__GNUC__)) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "roll $3, %%edi ; roll $13, %%edi\n\t" \ - "roll $29, %%edi ; roll $19, %%edi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EDX = client_request ( %EAX ) */ \ - "xchgl %%ebx,%%ebx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - "xchgl %%ecx,%%ecx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%EAX */ \ - "xchgl %%edx,%%edx\n\t" -#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */ - -/* ------------------------- x86-Win32 ------------------------- */ - -#if defined(PLAT_x86_win32) && !defined(__GNUC__) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#if defined(_MSC_VER) - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - __asm rol edi, 3 __asm rol edi, 13 \ - __asm rol edi, 29 __asm rol edi, 19 - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ - (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ - (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ - (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) - -static __inline uintptr_t -valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, - uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, - uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, - uintptr_t _zzq_arg5) -{ - volatile uintptr_t _zzq_args[6]; - volatile unsigned int _zzq_result; - _zzq_args[0] = (uintptr_t)(_zzq_request); - _zzq_args[1] = (uintptr_t)(_zzq_arg1); - _zzq_args[2] = (uintptr_t)(_zzq_arg2); - _zzq_args[3] = (uintptr_t)(_zzq_arg3); - _zzq_args[4] = (uintptr_t)(_zzq_arg4); - _zzq_args[5] = (uintptr_t)(_zzq_arg5); - __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default - __SPECIAL_INSTRUCTION_PREAMBLE - /* %EDX = client_request ( %EAX ) */ - __asm xchg ebx,ebx - __asm mov _zzq_result, edx - } - return _zzq_result; -} - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - __asm xchg ecx,ecx \ - __asm mov __addr, eax \ - } \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX ERROR - -#else -#error Unsupported compiler. -#endif - -#endif /* PLAT_x86_win32 */ - -/* ------------------------ amd64-{linux,darwin} --------------- */ - -#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ - "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned long long int _zzq_args[6]; \ - volatile unsigned long long int _zzq_result; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RDX = client_request ( %RAX ) */ \ - "xchgq %%rbx,%%rbx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RAX = guest_NRADDR */ \ - "xchgq %%rcx,%%rcx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_RAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%RAX */ \ - "xchgq %%rdx,%%rdx\n\t" -#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ - "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned int _zzq_args[6]; \ - unsigned int _zzq_result; \ - unsigned int* _zzq_ptr; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64_linux) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - unsigned long long int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ - "rotldi 0,0,61 ; rotldi 0,0,51\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned long long int _zzq_args[6]; \ - unsigned long long int _zzq_result; \ - unsigned long long int* _zzq_ptr; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#endif /* PLAT_ppc64_linux */ - -/* ------------------------- arm-linux ------------------------- */ - -#if defined(PLAT_arm_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ - "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("mov r3, %1\n\t" /*default*/ \ - "mov r4, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* R3 = client_request ( R4 ) */ \ - "orr r10, r10, r10\n\t" \ - "mov %0, r3" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "cc","memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* R3 = guest_NRADDR */ \ - "orr r11, r11, r11\n\t" \ - "mov %0, r3" \ - : "=r" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R4 */ \ - "orr r12, r12, r12\n\t" - -#endif /* PLAT_arm_linux */ - -/* ------------------------ s390x-linux ------------------------ */ - -#if defined(PLAT_s390x_linux) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - } - OrigFn; - -/* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific - * code. This detection is implemented in platform specific toIR.c - * (e.g. VEX/priv/guest_s390_decoder.c). - */ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "lr 15,15\n\t" \ - "lr 1,1\n\t" \ - "lr 2,2\n\t" \ - "lr 3,3\n\t" - -#define __CLIENT_REQUEST_CODE "lr 2,2\n\t" -#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" -#define __CALL_NO_REDIR_CODE "lr 4,4\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({volatile unsigned long long int _zzq_args[6]; \ - volatile unsigned long long int _zzq_result; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - __asm__ volatile(/* r2 = args */ \ - "lgr 2,%1\n\t" \ - /* r3 = default */ \ - "lgr 3,%2\n\t" \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - __CLIENT_REQUEST_CODE \ - /* results = r3 */ \ - "lgr %0, 3\n\t" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "2", "3", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - __GET_NR_CONTEXT_CODE \ - "lgr %0, 3\n\t" \ - : "=a" (__addr) \ - : \ - : "cc", "3", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_R1 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - __CALL_NO_REDIR_CODE - -#endif /* PLAT_s390x_linux */ - -/* ------------------------- mips32-linux ---------------- */ - -#if defined(PLAT_mips32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -/* .word 0x342 - * .word 0x742 - * .word 0xC2 - * .word 0x4C2*/ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "srl $0, $0, 13\n\t" \ - "srl $0, $0, 29\n\t" \ - "srl $0, $0, 3\n\t" \ - "srl $0, $0, 19\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("move $11, %1\n\t" /*default*/ \ - "move $12, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* T3 = client_request ( T4 ) */ \ - "or $13, $13, $13\n\t" \ - "move %0, $11\n\t" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "cc","memory", "t3", "t4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %t9 = guest_NRADDR */ \ - "or $14, $14, $14\n\t" \ - "move %0, $11" /*result*/ \ - : "=r" (__addr) \ - : \ - : "cc", "memory" , "t3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_T9 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%t9 */ \ - "or $15, $15, $15\n\t" -#endif /* PLAT_mips32_linux */ - -/* Insert assembly code for other platforms here... */ - -#endif /* NVALGRIND */ - - -/* ------------------------------------------------------------------ */ -/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ -/* ugly. It's the least-worst tradeoff I can think of. */ -/* ------------------------------------------------------------------ */ - -/* This section defines magic (a.k.a appalling-hack) macros for doing - guaranteed-no-redirection macros, so as to get from function - wrappers to the functions they are wrapping. The whole point is to - construct standard call sequences, but to do the call itself with a - special no-redirect call pseudo-instruction that the JIT - understands and handles specially. This section is long and - repetitious, and I can't see a way to make it shorter. - - The naming scheme is as follows: - - CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} - - 'W' stands for "word" and 'v' for "void". Hence there are - different macros for calling arity 0, 1, 2, 3, 4, etc, functions, - and for each, the possibility of returning a word-typed result, or - no result. -*/ - -/* Use these to write the name of your wrapper. NOTE: duplicates - VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts - the default behaviour equivalance class tag "0000" into the name. - See pub_tool_redir.h for details -- normally you don't need to - think about this, though. */ - -/* Use an extra level of macroisation so as to ensure the soname/fnname - args are fully macro-expanded before pasting them together. */ -#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd - -#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ - VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) - -#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ - VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) - -/* Use this macro from within a wrapper function to collect the - context (address and possibly other info) of the original function. - Once you have that you can then use it in one of the CALL_FN_ - macros. The type of the argument _lval is OrigFn. */ -#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) - -/* Also provide end-user facilities for function replacement, rather - than wrapping. A replacement function differs from a wrapper in - that it has no way to get hold of the original function being - called, and hence no way to call onwards to it. In a replacement - function, VALGRIND_GET_ORIG_FN always returns zero. */ - -#define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ - VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) - -#define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ - VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) - -/* Derivatives of the main macros below, for calling functions - returning void. */ - -#define CALL_FN_v_v(fnptr) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_v(_junk,fnptr); } while (0) - -#define CALL_FN_v_W(fnptr, arg1) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_W(_junk,fnptr,arg1); } while (0) - -#define CALL_FN_v_WW(fnptr, arg1,arg2) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) - -#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) - -#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) - -#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) - -#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) - -#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) - -/* ------------------------- x86-{linux,darwin} ---------------- */ - -#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) - -/* These regs are trashed by the hidden call. No need to mention eax - as gcc can already see that, plus causes gcc to bomb. */ -#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "movl %%esp,%%edi\n\t" \ - "andl $0xfffffff0,%%esp\n\t" -#define VALGRIND_RESTORE_STACK \ - "movl %%edi,%%esp\n\t" - -/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 48(%%eax)\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_x86_linux || PLAT_x86_darwin */ - -/* ------------------------ amd64-{linux,darwin} --------------- */ - -#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) - -/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ - "rdi", "r8", "r9", "r10", "r11" - -/* This is all pretty complex. It's so as to make stack unwinding - work reliably. See bug 243270. The basic problem is the sub and - add of 128 of %rsp in all of the following macros. If gcc believes - the CFA is in %rsp, then unwinding may fail, because what's at the - CFA is not what gcc "expected" when it constructs the CFIs for the - places where the macros are instantiated. - - But we can't just add a CFI annotation to increase the CFA offset - by 128, to match the sub of 128 from %rsp, because we don't know - whether gcc has chosen %rsp as the CFA at that point, or whether it - has chosen some other register (eg, %rbp). In the latter case, - adding a CFI annotation to change the CFA offset is simply wrong. - - So the solution is to get hold of the CFA using - __builtin_dwarf_cfa(), put it in a known register, and add a - CFI annotation to say what the register is. We choose %rbp for - this (perhaps perversely), because: - - (1) %rbp is already subject to unwinding. If a new register was - chosen then the unwinder would have to unwind it in all stack - traces, which is expensive, and - - (2) %rbp is already subject to precise exception updates in the - JIT. If a new register was chosen, we'd have to have precise - exceptions for it too, which reduces performance of the - generated code. - - However .. one extra complication. We can't just whack the result - of __builtin_dwarf_cfa() into %rbp and then add %rbp to the - list of trashed registers at the end of the inline assembly - fragments; gcc won't allow %rbp to appear in that list. Hence - instead we need to stash %rbp in %r15 for the duration of the asm, - and say that %r15 is trashed instead. gcc seems happy to go with - that. - - Oh .. and this all needs to be conditionalised so that it is - unchanged from before this commit, when compiled with older gccs - that don't support __builtin_dwarf_cfa. Furthermore, since - this header file is freestanding, it has to be independent of - config.h, and so the following conditionalisation cannot depend on - configure time checks. - - Although it's not clear from - 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', - this expression excludes Darwin. - .cfi directives in Darwin assembly appear to be completely - different and I haven't investigated how they work. - - For even more entertainment value, note we have to use the - completely undocumented __builtin_dwarf_cfa(), which appears to - really compute the CFA, whereas __builtin_frame_address(0) claims - to but actually doesn't. See - https://bugs.kde.org/show_bug.cgi?id=243270#c47 -*/ -#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) -# define __FRAME_POINTER \ - ,"r"(__builtin_dwarf_cfa()) -# define VALGRIND_CFI_PROLOGUE \ - "movq %%rbp, %%r15\n\t" \ - "movq %2, %%rbp\n\t" \ - ".cfi_remember_state\n\t" \ - ".cfi_def_cfa rbp, 0\n\t" -# define VALGRIND_CFI_EPILOGUE \ - "movq %%r15, %%rbp\n\t" \ - ".cfi_restore_state\n\t" -#else -# define __FRAME_POINTER -# define VALGRIND_CFI_PROLOGUE -# define VALGRIND_CFI_EPILOGUE -#endif - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "movq %%rsp,%%r14\n\t" \ - "andq $0xfffffffffffffff0,%%rsp\n\t" -#define VALGRIND_RESTORE_STACK \ - "movq %%r14,%%rsp\n\t" - -/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned - long) == 8. */ - -/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ - macros. In order not to trash the stack redzone, we need to drop - %rsp by 128 before the hidden call, and restore afterwards. The - nastyness is that it is only by luck that the stack still appears - to be unwindable during the hidden call - since then the behaviour - of any routine using this macro does not match what the CFI data - says. Sigh. - - Why is this important? Imagine that a wrapper has a stack - allocated local, and passes to the hidden call, a pointer to it. - Because gcc does not know about the hidden call, it may allocate - that local in the redzone. Unfortunately the hidden call may then - trash it before it comes to use it. So we must step clear of the - redzone, for the duration of the hidden call, to make it safe. - - Probably the same problem afflicts the other redzone-style ABIs too - (ppc64-linux); but for those, the stack is - self describing (none of this CFI nonsense) so at least messing - with the stack pointer doesn't give a danger of non-unwindable - stack. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 96(%%rax)\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -/* This is useful for finding out about the on-stack stuff: - - extern int f9 ( int,int,int,int,int,int,int,int,int ); - extern int f10 ( int,int,int,int,int,int,int,int,int,int ); - extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); - extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); - - int g9 ( void ) { - return f9(11,22,33,44,55,66,77,88,99); - } - int g10 ( void ) { - return f10(11,22,33,44,55,66,77,88,99,110); - } - int g11 ( void ) { - return f11(11,22,33,44,55,66,77,88,99,110,121); - } - int g12 ( void ) { - return f12(11,22,33,44,55,66,77,88,99,110,121,132); - } -*/ - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rlwinm 1,1,0,0,27\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc32-linux, - sizeof(unsigned long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg12 */ \ - "lwz 3,48(11)\n\t" \ - "stw 3,20(1)\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64_linux) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rldicr 1,1,0,59\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned - long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg12 */ \ - "ld 3,96(11)\n\t" \ - "std 3,136(1)\n\t" \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc64_linux */ - -/* ------------------------- arm-linux ------------------------- */ - -#if defined(PLAT_arm_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -/* This is a bit tricky. We store the original stack pointer in r10 - as it is callee-saves. gcc doesn't allow the use of r11 for some - reason. Also, we can't directly "bic" the stack pointer in thumb - mode since r13 isn't an allowed register number in that context. - So use r4 as a temporary, since that is about to get trashed - anyway, just after each use of this macro. Side effect is we need - to be very careful about any future changes, since - VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ -#define VALGRIND_ALIGN_STACK \ - "mov r10, sp\n\t" \ - "mov r4, sp\n\t" \ - "bic r4, r4, #7\n\t" \ - "mov sp, r4\n\t" -#define VALGRIND_RESTORE_STACK \ - "mov sp, r10\n\t" - -/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "push {r0} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "push {r0, r1} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "push {r0, r1, r2} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "push {r0, r1, r2, r3} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #40] \n\t" \ - "push {r0} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #40] \n\t" \ - "ldr r1, [%1, #44] \n\t" \ - "push {r0, r1} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #40] \n\t" \ - "ldr r1, [%1, #44] \n\t" \ - "ldr r2, [%1, #48] \n\t" \ - "push {r0, r1, r2} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_arm_linux */ - -/* ------------------------- s390x-linux ------------------------- */ - -#if defined(PLAT_s390x_linux) - -/* Similar workaround as amd64 (see above), but we use r11 as frame - pointer and save the old r11 in r7. r11 might be used for - argvec, therefore we copy argvec in r1 since r1 is clobbered - after the call anyway. */ -#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) -# define __FRAME_POINTER \ - ,"d"(__builtin_dwarf_cfa()) -# define VALGRIND_CFI_PROLOGUE \ - ".cfi_remember_state\n\t" \ - "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ - "lgr 7,11\n\t" \ - "lgr 11,%2\n\t" \ - ".cfi_def_cfa r11, 0\n\t" -# define VALGRIND_CFI_EPILOGUE \ - "lgr 11, 7\n\t" \ - ".cfi_restore_state\n\t" -#else -# define __FRAME_POINTER -# define VALGRIND_CFI_PROLOGUE \ - "lgr 1,%1\n\t" -# define VALGRIND_CFI_EPILOGUE -#endif - -/* Nb: On s390 the stack pointer is properly aligned *at all times* - according to the s390 GCC maintainer. (The ABI specification is not - precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and - VALGRIND_RESTORE_STACK are not defined here. */ - -/* These regs are trashed by the hidden call. Note that we overwrite - r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the - function a proper return address. All others are ABI defined call - clobbers. */ -#define __CALLER_SAVED_REGS "0","1","2","3","4","5","14", \ - "f0","f1","f2","f3","f4","f5","f6","f7" - -/* Nb: Although r11 is modified in the asm snippets below (inside - VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for - two reasons: - (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not - modified - (2) GCC will complain that r11 cannot appear inside a clobber section, - when compiled with -O -fno-omit-frame-pointer - */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 1, 0(1)\n\t" /* target->r1 */ \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -/* The call abi has the arguments in r2-r6 and stack */ -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1, arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-168\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,168\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-176\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,176\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-184\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,184\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-192\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,192\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-200\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,200\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10, arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-208\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,208\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-216\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "mvc 208(8,15), 96(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,216\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - - -#endif /* PLAT_s390x_linux */ - -/* ------------------------- mips-linux ------------------------- */ - -#if defined(PLAT_mips32_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ -"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ -"$25", "$31" - -/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16\n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" /* arg1*/ \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 24\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 24 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 32\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "nop\n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 32 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 32\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 32 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 40\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 40 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 40\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 40 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 48\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 40(%1) \n\t" \ - "sw $a0, 36($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 48 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 48\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 40(%1) \n\t" \ - "sw $a0, 36($sp) \n\t" \ - "lw $a0, 44(%1) \n\t" \ - "sw $a0, 40($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 48 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 56\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 40(%1) \n\t" \ - "sw $a0, 36($sp) \n\t" \ - "lw $a0, 44(%1) \n\t" \ - "sw $a0, 40($sp) \n\t" \ - "lw $a0, 48(%1) \n\t" \ - "sw $a0, 44($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 56 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_mips32_linux */ - - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ -/* */ -/* ------------------------------------------------------------------ */ - -/* Some request codes. There are many more of these, but most are not - exposed to end-user view. These are the public ones, all of the - form 0x1000 + small_number. - - Core ones are in the range 0x00000000--0x0000ffff. The non-public - ones start at 0x2000. -*/ - -/* These macros are used by tools -- they must be public, but don't - embed them into other programs. */ -#define VG_USERREQ_TOOL_BASE(a,b) \ - ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) -#define VG_IS_TOOL_USERREQ(a, b, v) \ - (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. */ -typedef - enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, - VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, - - /* These allow any function to be called from the simulated - CPU but run on the real CPU. Nb: the first arg passed to - the function is always the ThreadId of the running - thread! So CLIENT_CALL0 actually requires a 1 arg - function, etc. */ - VG_USERREQ__CLIENT_CALL0 = 0x1101, - VG_USERREQ__CLIENT_CALL1 = 0x1102, - VG_USERREQ__CLIENT_CALL2 = 0x1103, - VG_USERREQ__CLIENT_CALL3 = 0x1104, - - /* Can be useful in regression testing suites -- eg. can - send Valgrind's output to /dev/null and still count - errors. */ - VG_USERREQ__COUNT_ERRORS = 0x1201, - - /* Allows a string (gdb monitor command) to be passed to the tool - Used for interaction with vgdb/gdb */ - VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, - - /* These are useful and can be interpreted by any tool that - tracks malloc() et al, by using vg_replace_malloc.c. */ - VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, - VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, - VG_USERREQ__FREELIKE_BLOCK = 0x1302, - /* Memory pool support. */ - VG_USERREQ__CREATE_MEMPOOL = 0x1303, - VG_USERREQ__DESTROY_MEMPOOL = 0x1304, - VG_USERREQ__MEMPOOL_ALLOC = 0x1305, - VG_USERREQ__MEMPOOL_FREE = 0x1306, - VG_USERREQ__MEMPOOL_TRIM = 0x1307, - VG_USERREQ__MOVE_MEMPOOL = 0x1308, - VG_USERREQ__MEMPOOL_CHANGE = 0x1309, - VG_USERREQ__MEMPOOL_EXISTS = 0x130a, - - /* Allow printfs to valgrind log. */ - /* The first two pass the va_list argument by value, which - assumes it is the same size as or smaller than a UWord, - which generally isn't the case. Hence are deprecated. - The second two pass the vargs by reference and so are - immune to this problem. */ - /* both :: char* fmt, va_list vargs (DEPRECATED) */ - VG_USERREQ__PRINTF = 0x1401, - VG_USERREQ__PRINTF_BACKTRACE = 0x1402, - /* both :: char* fmt, va_list* vargs */ - VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, - - /* Stack support. */ - VG_USERREQ__STACK_REGISTER = 0x1501, - VG_USERREQ__STACK_DEREGISTER = 0x1502, - VG_USERREQ__STACK_CHANGE = 0x1503, - - /* Wine support */ - VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, - - /* Querying of debug info. */ - VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, - - /* Disable/enable error reporting level. Takes a single - Word arg which is the delta to this thread's error - disablement indicator. Hence 1 disables or further - disables errors, and -1 moves back towards enablement. - Other values are not allowed. */ - VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801 - } Vg_ClientRequest; - -#if !defined(__GNUC__) -# define __extension__ /* */ -#endif - - -/* Returns the number of Valgrinds this code is running under. That - is, 0 if running natively, 1 if running under Valgrind, 2 if - running under Valgrind which is running under another Valgrind, - etc. */ -#define RUNNING_ON_VALGRIND \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ - VG_USERREQ__RUNNING_ON_VALGRIND, \ - 0, 0, 0, 0, 0) \ - - -/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + - _qzz_len - 1]. Useful if you are debugging a JITter or some such, - since it provides a way to make sure valgrind will retranslate the - invalidated area. Returns no value. */ -#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ - _qzz_addr, _qzz_len, 0, 0, 0) - - -/* These requests are for getting Valgrind itself to print something. - Possibly with a backtrace. This is a really ugly hack. The return value - is the number of characters printed, excluding the "**** " part at the - start and the backtrace (if present). */ - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) -/* Modern GCC will optimize the static routine out if unused, - and unused attribute will shut down warnings about it. */ -static int VALGRIND_PRINTF(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -#endif -static int -#if defined(_MSC_VER) -__inline -#endif -VALGRIND_PRINTF(const char *format, ...) -{ -#if defined(NVALGRIND) - return 0; -#else /* NVALGRIND */ -#if defined(_MSC_VER) - uintptr_t _qzz_res; -#else - unsigned long _qzz_res; -#endif - va_list vargs; - va_start(vargs, format); -#if defined(_MSC_VER) - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_VALIST_BY_REF, - (uintptr_t)format, - (uintptr_t)&vargs, - 0, 0, 0); -#else - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_VALIST_BY_REF, - (unsigned long)format, - (unsigned long)&vargs, - 0, 0, 0); -#endif - va_end(vargs); - return (int)_qzz_res; -#endif /* NVALGRIND */ -} - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) -static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -#endif -static int -#if defined(_MSC_VER) -__inline -#endif -VALGRIND_PRINTF_BACKTRACE(const char *format, ...) -{ -#if defined(NVALGRIND) - return 0; -#else /* NVALGRIND */ -#if defined(_MSC_VER) - uintptr_t _qzz_res; -#else - unsigned long _qzz_res; -#endif - va_list vargs; - va_start(vargs, format); -#if defined(_MSC_VER) - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, - (uintptr_t)format, - (uintptr_t)&vargs, - 0, 0, 0); -#else - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, - (unsigned long)format, - (unsigned long)&vargs, - 0, 0, 0); -#endif - va_end(vargs); - return (int)_qzz_res; -#endif /* NVALGRIND */ -} - - -/* These requests allow control to move from the simulated CPU to the - real CPU, calling an arbitary function. - - Note that the current ThreadId is inserted as the first argument. - So this call: - - VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) - - requires f to have this signature: - - Word f(Word tid, Word arg1, Word arg2) - - where "Word" is a word-sized type. - - Note that these client requests are not entirely reliable. For example, - if you call a function with them that subsequently calls printf(), - there's a high chance Valgrind will crash. Generally, your prospects of - these working are made higher if the called function does not refer to - any global variables, and does not refer to any libc or other functions - (printf et al). Any kind of entanglement with libc or dynamic linking is - likely to have a bad outcome, for tricky reasons which we've grappled - with a lot in the past. -*/ -#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL0, \ - _qyy_fn, \ - 0, 0, 0, 0) - -#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL1, \ - _qyy_fn, \ - _qyy_arg1, 0, 0, 0) - -#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL2, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, 0, 0) - -#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL3, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, \ - _qyy_arg3, 0) - - -/* Counts the number of errors that have been recorded by a tool. Nb: - the tool must record the errors with VG_(maybe_record_error)() or - VG_(unique_error)() for them to be counted. */ -#define VALGRIND_COUNT_ERRORS \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - 0 /* default return */, \ - VG_USERREQ__COUNT_ERRORS, \ - 0, 0, 0, 0, 0) - -/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing - when heap blocks are allocated in order to give accurate results. This - happens automatically for the standard allocator functions such as - malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, - delete[], etc. - - But if your program uses a custom allocator, this doesn't automatically - happen, and Valgrind will not do as well. For example, if you allocate - superblocks with mmap() and then allocates chunks of the superblocks, all - Valgrind's observations will be at the mmap() level and it won't know that - the chunks should be considered separate entities. In Memcheck's case, - that means you probably won't get heap block overrun detection (because - there won't be redzones marked as unaddressable) and you definitely won't - get any leak detection. - - The following client requests allow a custom allocator to be annotated so - that it can be handled accurately by Valgrind. - - VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated - by a malloc()-like function. For Memcheck (an illustrative case), this - does two things: - - - It records that the block has been allocated. This means any addresses - within the block mentioned in error messages will be - identified as belonging to the block. It also means that if the block - isn't freed it will be detected by the leak checker. - - - It marks the block as being addressable and undefined (if 'is_zeroed' is - not set), or addressable and defined (if 'is_zeroed' is set). This - controls how accesses to the block by the program are handled. - - 'addr' is the start of the usable block (ie. after any - redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator - can apply redzones -- these are blocks of padding at the start and end of - each block. Adding redzones is recommended as it makes it much more likely - Valgrind will spot block overruns. `is_zeroed' indicates if the memory is - zeroed (or filled with another predictable value), as is the case for - calloc(). - - VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a - heap block -- that will be used by the client program -- is allocated. - It's best to put it at the outermost level of the allocator if possible; - for example, if you have a function my_alloc() which calls - internal_alloc(), and the client request is put inside internal_alloc(), - stack traces relating to the heap block will contain entries for both - my_alloc() and internal_alloc(), which is probably not what you want. - - For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out - custom blocks from within a heap block, B, that has been allocated with - malloc/calloc/new/etc, then block B will be *ignored* during leak-checking - -- the custom blocks will take precedence. - - VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For - Memcheck, it does two things: - - - It records that the block has been deallocated. This assumes that the - block was annotated as having been allocated via - VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - - - It marks the block as being unaddressable. - - VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a - heap block is deallocated. - - VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For - Memcheck, it does four things: - - - It records that the size of a block has been changed. This assumes that - the block was annotated as having been allocated via - VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - - - If the block shrunk, it marks the freed memory as being unaddressable. - - - If the block grew, it marks the new area as undefined and defines a red - zone past the end of the new block. - - - The V-bits of the overlap between the old and the new block are preserved. - - VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block - and before deallocation of the old block. - - In many cases, these three client requests will not be enough to get your - allocator working well with Memcheck. More specifically, if your allocator - writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call - will be necessary to mark the memory as addressable just before the zeroing - occurs, otherwise you'll get a lot of invalid write errors. For example, - you'll need to do this if your allocator recycles freed blocks, but it - zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). - Alternatively, if your allocator reuses freed blocks for allocator-internal - data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. - - Really, what's happening is a blurring of the lines between the client - program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the - memory should be considered unaddressable to the client program, but the - allocator knows more than the rest of the client program and so may be able - to safely access it. Extra client requests are necessary for Valgrind to - understand the distinction between the allocator and the rest of the - program. - - Ignored if addr == 0. -*/ -#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ - addr, sizeB, rzB, is_zeroed, 0) - -/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. - Ignored if addr == 0. -*/ -#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ - addr, oldSizeB, newSizeB, rzB, 0) - -/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. - Ignored if addr == 0. -*/ -#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ - addr, rzB, 0, 0, 0) - -/* Create a memory pool. */ -#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ - pool, rzB, is_zeroed, 0, 0) - -/* Destroy a memory pool. */ -#define VALGRIND_DESTROY_MEMPOOL(pool) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ - pool, 0, 0, 0, 0) - -/* Associate a piece of memory with a memory pool. */ -#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ - pool, addr, size, 0, 0) - -/* Disassociate a piece of memory from a memory pool. */ -#define VALGRIND_MEMPOOL_FREE(pool, addr) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ - pool, addr, 0, 0, 0) - -/* Disassociate any pieces outside a particular range. */ -#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ - pool, addr, size, 0, 0) - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ - poolA, poolB, 0, 0, 0) - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ - pool, addrA, addrB, size, 0) - -/* Return 1 if a mempool exists, else 0. */ -#define VALGRIND_MEMPOOL_EXISTS(pool) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__MEMPOOL_EXISTS, \ - pool, 0, 0, 0, 0) - -/* Mark a piece of memory as being a stack. Returns a stack id. */ -#define VALGRIND_STACK_REGISTER(start, end) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__STACK_REGISTER, \ - start, end, 0, 0, 0) - -/* Unmark the piece of memory associated with a stack id as being a - stack. */ -#define VALGRIND_STACK_DEREGISTER(id) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ - id, 0, 0, 0, 0) - -/* Change the start and end address of the stack id. */ -#define VALGRIND_STACK_CHANGE(id, start, end) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ - id, start, end, 0, 0) - -/* Load PDB debug info for Wine PE image_map. */ -#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ - fd, ptr, total_size, delta, 0) - -/* Map a code address to a source file name and line number. buf64 - must point to a 64-byte buffer in the caller's address space. The - result will be dumped in there and is guaranteed to be zero - terminated. If no info is found, the first byte is set to zero. */ -#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__MAP_IP_TO_SRCLOC, \ - addr, buf64, 0, 0, 0) - -/* Disable error reporting for this thread. Behaves in a stack like - way, so you can safely call this multiple times provided that - VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times - to re-enable reporting. The first call of this macro disables - reporting. Subsequent calls have no effect except to increase the - number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable - reporting. Child threads do not inherit this setting from their - parents -- they are always created with reporting enabled. */ -#define VALGRIND_DISABLE_ERROR_REPORTING \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ - 1, 0, 0, 0, 0) - -/* Re-enable error reporting, as per comments on - VALGRIND_DISABLE_ERROR_REPORTING. */ -#define VALGRIND_ENABLE_ERROR_REPORTING \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ - -1, 0, 0, 0, 0) - -#undef PLAT_x86_darwin -#undef PLAT_amd64_darwin -#undef PLAT_x86_win32 -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64_linux -#undef PLAT_arm_linux -#undef PLAT_s390x_linux -#undef PLAT_mips32_linux - -#endif /* __VALGRIND_H */ diff -Nru 0ad-0.0.25b/source/collada/CommonConvert.h 0ad-0.0.26/source/collada/CommonConvert.h --- 0ad-0.0.25b/source/collada/CommonConvert.h 2021-07-27 21:57:05.000000000 +0000 +++ 0ad-0.0.26/source/collada/CommonConvert.h 2022-08-21 12:45:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,7 +27,6 @@ class FCDSceneNode; class FCDSkinController; class FMMatrix44; -class FUStatus; class Skeleton; diff -Nru 0ad-0.0.25b/source/collada/PSAConvert.cpp 0ad-0.0.26/source/collada/PSAConvert.cpp --- 0ad-0.0.25b/source/collada/PSAConvert.cpp 2021-07-27 21:57:05.000000000 +0000 +++ 0ad-0.0.26/source/collada/PSAConvert.cpp 2022-08-21 12:45:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2021 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,9 @@ REQUIRE(frameCount > 0, "animation must have frames"); // (TODO: sort out the timing/looping problems) - size_t boneCount = skeleton.GetBoneCount(); + const size_t boneCount = skeleton.GetBoneCount(); + if (boneCount > 64) + Log(LOG_ERROR, "Skeleton has too many bones %zu/64", boneCount); std::vector boneTransforms; @@ -99,7 +101,7 @@ float time = timeStart + frameLength * frame; BoneTransform boneDefault = { { 0, 0, 0 }, { 0, 0, 0, 1 } }; - std::vector frameBoneTransforms (boneCount, boneDefault); + std::vector frameBoneTransforms(boneCount, boneDefault); // Move the model into the new animated pose // (We can't tell exactly which nodes should be animated, so diff -Nru 0ad-0.0.25b/source/graphics/CameraController.cpp 0ad-0.0.26/source/graphics/CameraController.cpp --- 0ad-0.0.25b/source/graphics/CameraController.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/CameraController.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,6 +36,7 @@ #include "ps/TouchInput.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpPosition.h" @@ -57,6 +58,7 @@ // Dummy values (these will be filled in by the config file) m_ViewScrollSpeed(0), m_ViewScrollSpeedModifier(1), + m_ViewScrollMouseDetectDistance(3), m_ViewRotateXSpeed(0), m_ViewRotateXMin(0), m_ViewRotateXMax(0), @@ -103,6 +105,7 @@ { CFG_GET_VAL("view.scroll.speed", m_ViewScrollSpeed); CFG_GET_VAL("view.scroll.speed.modifier", m_ViewScrollSpeedModifier); + CFG_GET_VAL("view.scroll.mouse.detectdistance", m_ViewScrollMouseDetectDistance); CFG_GET_VAL("view.rotate.x.speed", m_ViewRotateXSpeed); CFG_GET_VAL("view.rotate.x.min", m_ViewRotateXMin); CFG_GET_VAL("view.rotate.x.max", m_ViewRotateXMax); @@ -181,16 +184,16 @@ moveForward += m_ViewDragSpeed * -mouse_dy; } - if (g_mouse_active) + if (g_mouse_active && m_ViewScrollMouseDetectDistance > 0) { - if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres) + if (g_mouse_x >= g_xres - m_ViewScrollMouseDetectDistance && g_mouse_x < g_xres) moveRightward += m_ViewScrollSpeed * deltaRealTime; - else if (g_mouse_x <= 3 && g_mouse_x >= 0) + else if (g_mouse_x < m_ViewScrollMouseDetectDistance && g_mouse_x >= 0) moveRightward -= m_ViewScrollSpeed * deltaRealTime; - if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres) + if (g_mouse_y >= g_yres - m_ViewScrollMouseDetectDistance && g_mouse_y < g_yres) moveForward -= m_ViewScrollSpeed * deltaRealTime; - else if (g_mouse_y <= 3 && g_mouse_y >= 0) + else if (g_mouse_y < m_ViewScrollMouseDetectDistance && g_mouse_y >= 0) moveForward += m_ViewScrollSpeed * deltaRealTime; } @@ -578,7 +581,7 @@ const float ground = std::max( g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel(nearPoint.X, nearPoint.Z), - g_Renderer.GetWaterManager()->m_WaterHeight); + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight); // filter ground levels for smooth camera movement const float filtered_near_ground = g_Game->GetWorld()->GetTerrain()->GetFilteredGroundLevel(nearPoint.X, nearPoint.Z, near_radius); @@ -587,7 +590,7 @@ // filtered maximum visible ground level in view const float filtered_ground = std::max( std::max(filtered_near_ground, filtered_pivot_ground), - g_Renderer.GetWaterManager()->m_WaterHeight); + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight); // target camera height above pivot point const float pivot_height = -forwards.Y * (m_Zoom.GetSmoothedValue() - m_ViewNear); diff -Nru 0ad-0.0.25b/source/graphics/CameraController.h 0ad-0.0.26/source/graphics/CameraController.h --- 0ad-0.0.25b/source/graphics/CameraController.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/CameraController.h 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -88,6 +88,8 @@ // Settings float m_ViewScrollSpeed; float m_ViewScrollSpeedModifier; + // How close the mouse pointer should be to a view edge to move the camera. + int m_ViewScrollMouseDetectDistance; float m_ViewRotateXSpeed; float m_ViewRotateXMin; float m_ViewRotateXMax; diff -Nru 0ad-0.0.25b/source/graphics/Camera.cpp 0ad-0.0.26/source/graphics/Camera.cpp --- 0ad-0.0.25b/source/graphics/Camera.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Camera.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,24 +15,19 @@ * along with 0 A.D. If not, see . */ -/* - * CCamera holds a view and a projection matrix. It also has a frustum - * which can be used to cull objects for rendering. - */ - #include "precompiled.h" #include "Camera.h" #include "graphics/HFTracer.h" #include "graphics/Terrain.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "maths/Vector2D.h" #include "maths/Vector4D.h" #include "ps/Game.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" CCamera::CCamera() @@ -276,7 +271,7 @@ CPlane plane; plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal - CVector3D(0.f, g_Renderer.GetWaterManager()->m_WaterHeight, 0.f)); // passes through water plane + CVector3D(0.f, g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight, 0.f)); // passes through water plane bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint ); @@ -354,7 +349,7 @@ CPlane plane; plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal - CVector3D(0.f, g_Renderer.GetWaterManager()->m_WaterHeight, 0.f)); // passes through water plane + CVector3D(0.f, g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight, 0.f)); // passes through water plane bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint ); @@ -451,7 +446,8 @@ { orientation.Normalize(); up.Normalize(); - CVector3D s = orientation.Cross(up); + const CVector3D s = orientation.Cross(up); + up = s.Cross(orientation); m_Orientation._11 = -s.X; m_Orientation._12 = up.X; m_Orientation._13 = orientation.X; m_Orientation._14 = camera.X; m_Orientation._21 = -s.Y; m_Orientation._22 = up.Y; m_Orientation._23 = orientation.Y; m_Orientation._24 = camera.Y; diff -Nru 0ad-0.0.25b/source/graphics/Canvas2D.cpp 0ad-0.0.26/source/graphics/Canvas2D.cpp --- 0ad-0.0.25b/source/graphics/Canvas2D.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Canvas2D.cpp 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,13 +35,26 @@ { // Array of 2D elements unrolled into 1D array. -using PlaneArray2D = std::array; +using PlaneArray2D = std::array; -inline void DrawTextureImpl(const CShaderProgramPtr& shader, CTexturePtr texture, - const PlaneArray2D& vertices, PlaneArray2D uvs, - const CColor& multiply, const CColor& add, const float grayscaleFactor) +struct SBindingSlots { - shader->BindTexture(str_tex, texture); + int32_t transform; + int32_t colorAdd; + int32_t colorMul; + int32_t grayscaleFactor; + int32_t tex; +}; + +inline void DrawTextureImpl( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CTexturePtr& texture, const PlaneArray2D& vertices, PlaneArray2D uvs, + const CColor& multiply, const CColor& add, const float grayscaleFactor, + const SBindingSlots& bindingSlots) +{ + texture->UploadBackendTextureIfNeeded(deviceCommandContext); + deviceCommandContext->SetTexture( + bindingSlots.tex, texture->GetBackendTexture()); for (size_t idx = 0; idx < uvs.size(); idx += 2) { if (texture->GetWidth() > 0.0f) @@ -50,16 +63,25 @@ uvs[idx + 1] /= texture->GetHeight(); } - shader->Uniform(str_transform, GetDefaultGuiMatrix()); - shader->Uniform(str_colorAdd, add); - shader->Uniform(str_colorMul, multiply); - shader->Uniform(str_grayscaleFactor, grayscaleFactor); - shader->VertexPointer(2, GL_FLOAT, 0, vertices.data()); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, uvs.data()); - shader->AssertPointersBound(); + deviceCommandContext->SetUniform(bindingSlots.colorAdd, add.AsFloatArray()); + deviceCommandContext->SetUniform(bindingSlots.colorMul, multiply.AsFloatArray()); + deviceCommandContext->SetUniform(bindingSlots.grayscaleFactor, grayscaleFactor); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); + deviceCommandContext->SetVertexBufferData( + 1, uvs.data(), uvs.size() * sizeof(uvs[0])); - if (!g_Renderer.DoSkipSubmit()) - glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 2); + deviceCommandContext->Draw(0, vertices.size() / 2); } } // anonymous namespace @@ -67,19 +89,34 @@ class CCanvas2D::Impl { public: + Impl(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) + : DeviceCommandContext(deviceCommandContext) + { + } + void BindTechIfNeeded() { if (Tech) return; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - CShaderDefines defines; - Tech = g_Renderer.GetShaderManager().LoadEffect( - str_canvas2d, g_Renderer.GetSystemShaderDefines(), defines); + Tech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d, defines); + // The canvas technique must be loaded because we can't render UI without it. ENSURE(Tech); - Tech->BeginPass(); + DeviceCommandContext->SetGraphicsPipelineState( + Tech->GetGraphicsPipelineStateDesc()); + DeviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = Tech->GetShader(); + + BindingSlots.transform = shader->GetBindingSlot(str_transform); + BindingSlots.colorAdd = shader->GetBindingSlot(str_colorAdd); + BindingSlots.colorMul = shader->GetBindingSlot(str_colorMul); + BindingSlots.grayscaleFactor = shader->GetBindingSlot(str_grayscaleFactor); + BindingSlots.tex = shader->GetBindingSlot(str_tex); + + const CMatrix3D transform = GetDefaultGuiMatrix(); + DeviceCommandContext->SetUniform( + BindingSlots.transform, transform.AsFloatArray()); } void UnbindTech() @@ -87,16 +124,21 @@ if (!Tech) return; - Tech->EndPass(); + DeviceCommandContext->EndPass(); Tech.reset(); - - glDisable(GL_BLEND); } + Renderer::Backend::IDeviceCommandContext* DeviceCommandContext = nullptr; CShaderTechniquePtr Tech; + + // We assume that the shader can't be destroyed while it's bound. So these + // bindings remain valid while the shader is alive. + SBindingSlots BindingSlots; }; -CCanvas2D::CCanvas2D() : m(std::make_unique()) +CCanvas2D::CCanvas2D( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) + : m(std::make_unique(deviceCommandContext)) { } @@ -108,55 +150,185 @@ void CCanvas2D::DrawLine(const std::vector& points, const float width, const CColor& color) { + if (points.empty()) + return; + + // We could reuse the terrain line building, but it uses 3D space instead of + // 2D. So it can be less optimal for a canvas. + + // Adding a single pixel line with alpha gradient to reduce the aliasing + // effect. + const float halfWidth = width * 0.5f + 1.0f; + + struct PointIndex + { + size_t index; + float length; + CVector2D normal; + }; + // Normal for the last index is undefined. + std::vector pointsIndices; + pointsIndices.reserve(points.size()); + pointsIndices.emplace_back(PointIndex{0, 0.0f, CVector2D()}); + for (size_t index = 0; index < points.size();) + { + size_t nextIndex = index + 1; + CVector2D direction; + float length = 0.0f; + while (nextIndex < points.size()) + { + direction = points[nextIndex] - points[pointsIndices.back().index]; + length = direction.Length(); + if (length >= halfWidth * 2.0f) + { + direction /= length; + break; + } + ++nextIndex; + } + if (nextIndex == points.size()) + break; + pointsIndices.back().length = length; + pointsIndices.back().normal = CVector2D(-direction.Y, direction.X); + pointsIndices.emplace_back(PointIndex{nextIndex, 0.0f, CVector2D()}); + index = nextIndex; + } + + if (pointsIndices.size() <= 1) + return; + + std::vector> vertices; + std::vector> uvs; + std::vector indices; + const size_t reserveSize = 2 * pointsIndices.size() - 1; + vertices.reserve(reserveSize); + uvs.reserve(reserveSize); + indices.reserve(reserveSize * 12); + + auto addVertices = [&vertices, &uvs, &indices, &halfWidth](const CVector2D& p1, const CVector2D& p2) + { + if (!vertices.empty()) + { + const u16 lastVertexIndex = static_cast(vertices.size() * 3 - 1); + ENSURE(lastVertexIndex >= 2); + // First vertical half of the segment. + indices.emplace_back(lastVertexIndex - 2); + indices.emplace_back(lastVertexIndex - 1); + indices.emplace_back(lastVertexIndex + 2); + indices.emplace_back(lastVertexIndex - 2); + indices.emplace_back(lastVertexIndex + 2); + indices.emplace_back(lastVertexIndex + 1); + // Second vertical half of the segment. + indices.emplace_back(lastVertexIndex - 1); + indices.emplace_back(lastVertexIndex); + indices.emplace_back(lastVertexIndex + 3); + indices.emplace_back(lastVertexIndex - 1); + indices.emplace_back(lastVertexIndex + 3); + indices.emplace_back(lastVertexIndex + 2); + } + vertices.emplace_back(std::array{p1, (p1 + p2) / 2.0f, p2}); + uvs.emplace_back(std::array{ + CVector2D(0.0f, 0.0f), + CVector2D(std::max(1.0f, halfWidth - 1.0f), 0.0f), + CVector2D(0.0f, 0.0f)}); + }; + + addVertices( + points[pointsIndices.front().index] - pointsIndices.front().normal * halfWidth, + points[pointsIndices.front().index] + pointsIndices.front().normal * halfWidth); + // For each pair of adjacent segments we need to add smooth transition. + for (size_t index = 0; index + 2 < pointsIndices.size(); ++index) + { + const PointIndex& pointIndex = pointsIndices[index]; + const PointIndex& nextPointIndex = pointsIndices[index + 1]; + // Angle between adjacent segments. + const float cosAlpha = pointIndex.normal.Dot(nextPointIndex.normal); + constexpr float EPS = 1e-3f; + // Use a simple segment if adjacent segments are almost codirectional. + if (cosAlpha > 1.0f - EPS) + { + addVertices( + points[pointIndex.index] - pointIndex.normal * halfWidth, + points[pointIndex.index] + pointIndex.normal * halfWidth); + } + else + { + addVertices( + points[nextPointIndex.index] - pointIndex.normal * halfWidth, + points[nextPointIndex.index] + pointIndex.normal * halfWidth); + // Average normal between adjacent segments. We might want to rotate it but + // for now we assume that it's enough for current line widths. + const CVector2D normal = cosAlpha < -1.0f + EPS + ? CVector2D(pointIndex.normal.Y, -pointIndex.normal.X) + : ((pointIndex.normal + nextPointIndex.normal) / 2.0f).Normalized(); + addVertices( + points[nextPointIndex.index] - normal * halfWidth, + points[nextPointIndex.index] + normal * halfWidth); + addVertices( + points[nextPointIndex.index] - nextPointIndex.normal * halfWidth, + points[nextPointIndex.index] + nextPointIndex.normal * halfWidth); + } + // We use 16-bit indices, it means that we can't use more than 64K vertices. + const size_t requiredFreeSpace = 3 * 4; + if (vertices.size() * 3 + requiredFreeSpace >= 65536) + break; + } + addVertices( + points[pointsIndices.back().index] - pointsIndices[pointsIndices.size() - 2].normal * halfWidth, + points[pointsIndices.back().index] + pointsIndices[pointsIndices.size() - 2].normal * halfWidth); + m->BindTechIfNeeded(); - std::vector vertices; - std::vector uvs(points.size() * 2, 0.0f); - vertices.reserve(points.size() * 2); - for (const CVector2D& point : points) - { - vertices.emplace_back(point.X); - vertices.emplace_back(point.Y); - } - - CShaderProgramPtr shader = m->Tech->GetShader(); - shader->BindTexture(str_tex, g_Renderer.GetTextureManager().GetTransparentTexture()); - shader->Uniform(str_transform, GetDefaultGuiMatrix()); - shader->Uniform(str_colorAdd, color); - shader->Uniform(str_colorMul, CColor(0.0f, 0.0f, 0.0f, 0.0f)); - shader->Uniform(str_grayscaleFactor, 0.0f); - shader->VertexPointer(2, GL_FLOAT, 0, vertices.data()); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, uvs.data()); - shader->AssertPointersBound(); - -#if !CONFIG2_GLES - glEnable(GL_LINE_SMOOTH); -#endif - glLineWidth(width); - if (!g_Renderer.DoSkipSubmit()) - glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 2); - glLineWidth(1.0f); -#if !CONFIG2_GLES - glDisable(GL_LINE_SMOOTH); -#endif + m->DeviceCommandContext->SetTexture( + m->BindingSlots.tex, + g_Renderer.GetTextureManager().GetAlphaGradientTexture()->GetBackendTexture()); + const CColor colorAdd(0.0f, 0.0f, 0.0f, 0.0f); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.colorAdd, colorAdd.AsFloatArray()); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.colorMul, color.AsFloatArray()); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.grayscaleFactor, 0.0f); + + m->DeviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + m->DeviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + m->DeviceCommandContext->SetVertexBufferData(0, vertices.data(), vertices.size() * sizeof(vertices[0])); + m->DeviceCommandContext->SetVertexBufferData(1, uvs.data(), uvs.size() * sizeof(uvs[0])); + + m->DeviceCommandContext->SetIndexBufferData(indices.data(), indices.size() * sizeof(indices[0])); + m->DeviceCommandContext->DrawIndexed(0, indices.size(), 0); } void CCanvas2D::DrawRect(const CRect& rect, const CColor& color) { - const PlaneArray2D uvs = { - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + const PlaneArray2D uvs + { + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - const PlaneArray2D vertices = { + const PlaneArray2D vertices = + { rect.left, rect.bottom, rect.right, rect.bottom, rect.right, rect.top, + rect.left, rect.bottom, + rect.right, rect.top, rect.left, rect.top }; m->BindTechIfNeeded(); DrawTextureImpl( - m->Tech->GetShader(), g_Renderer.GetTextureManager().GetTransparentTexture(), - vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color, 0.0f); + m->DeviceCommandContext, + g_Renderer.GetTextureManager().GetTransparentTexture(), + vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color, 0.0f, + m->BindingSlots); } void CCanvas2D::DrawTexture(CTexturePtr texture, const CRect& destination) @@ -170,31 +342,39 @@ CTexturePtr texture, const CRect& destination, const CRect& source, const CColor& multiply, const CColor& add, const float grayscaleFactor) { - const PlaneArray2D uvs = { + const PlaneArray2D uvs = + { source.left, source.bottom, source.right, source.bottom, source.right, source.top, + source.left, source.bottom, + source.right, source.top, source.left, source.top }; - const PlaneArray2D vertices = { + const PlaneArray2D vertices = + { destination.left, destination.bottom, destination.right, destination.bottom, destination.right, destination.top, + destination.left, destination.bottom, + destination.right, destination.top, destination.left, destination.top }; m->BindTechIfNeeded(); - DrawTextureImpl(m->Tech->GetShader(), texture, vertices, uvs, multiply, add, grayscaleFactor); + DrawTextureImpl( + m->DeviceCommandContext, texture, vertices, uvs, + multiply, add, grayscaleFactor, m->BindingSlots); } void CCanvas2D::DrawText(CTextRenderer& textRenderer) { m->BindTechIfNeeded(); - CShaderProgramPtr shader = m->Tech->GetShader(); - shader->Uniform(str_grayscaleFactor, 0.0f); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.grayscaleFactor, 0.0f); - textRenderer.Render(shader, GetDefaultGuiMatrix()); + textRenderer.Render(m->DeviceCommandContext, m->Tech->GetShader(), GetDefaultGuiMatrix()); } void CCanvas2D::Flush() diff -Nru 0ad-0.0.25b/source/graphics/Canvas2D.h 0ad-0.0.26/source/graphics/Canvas2D.h --- 0ad-0.0.25b/source/graphics/Canvas2D.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Canvas2D.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,7 +20,9 @@ #include "graphics/Texture.h" #include "maths/Vector2D.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include #include class CRect; @@ -33,7 +35,7 @@ class CCanvas2D { public: - CCanvas2D(); + CCanvas2D(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); ~CCanvas2D(); CCanvas2D(const CCanvas2D&) = delete; diff -Nru 0ad-0.0.25b/source/graphics/CinemaManager.cpp 0ad-0.0.26/source/graphics/CinemaManager.cpp --- 0ad-0.0.25b/source/graphics/CinemaManager.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/CinemaManager.cpp 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,15 +17,11 @@ #include "precompiled.h" -#include -#include - #include "graphics/CinemaManager.h" #include "graphics/Camera.h" #include "graphics/Color.h" #include "graphics/GameView.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "maths/Quaternion.h" #include "maths/Vector3D.h" @@ -37,6 +33,8 @@ #include "ps/GameSetup/Config.h" #include "ps/Hotkey.h" #include "ps/World.h" +#include "renderer/DebugRenderer.h" +#include "renderer/Renderer.h" #include "simulation2/components/ICmpCinemaManager.h" #include "simulation2/components/ICmpOverlayRenderer.h" #include "simulation2/components/ICmpRangeManager.h" @@ -46,9 +44,6 @@ #include "simulation2/MessageTypes.h" #include "simulation2/system/ComponentManager.h" #include "simulation2/Simulation2.h" -#include "renderer/DebugRenderer.h" -#include "renderer/Renderer.h" - CCinemaManager::CCinemaManager() : m_DrawPaths(false) @@ -77,9 +72,6 @@ if (!cmpCinemaManager) return; - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - for (const std::pair& p : cmpCinemaManager->GetPaths()) { DrawSpline(p.second, CColor(0.2f, 0.2f, 1.f, 0.9f), 128); @@ -91,9 +83,6 @@ DrawSpline(p.second.GetTargetSpline(), CColor(1.f, 0.3f, 0.4f, 0.9f), 128); DrawNodes(p.second.GetTargetSpline(), CColor(1.f, 0.1f, 0.f, 1.f)); } - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); } void CCinemaManager::DrawSpline(const RNSpline& spline, const CColor& splineColor, int smoothness) const @@ -111,7 +100,7 @@ const float time = start * i / spline.MaxDistance.ToFloat(); line.emplace_back(spline.GetPosition(time)); } - g_Renderer.GetDebugRenderer().DrawLine(line, splineColor, 0.2f); + g_Renderer.GetDebugRenderer().DrawLine(line, splineColor, 0.2f, false); // Height indicator if (g_Game && g_Game->GetWorld() && g_Game->GetWorld()->GetTerrain()) @@ -121,7 +110,7 @@ const float time = start * i / spline.MaxDistance.ToFloat(); const CVector3D tmp = spline.GetPosition(time); const float groundY = g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel(tmp.X, tmp.Z); - g_Renderer.GetDebugRenderer().DrawLine(tmp, CVector3D(tmp.X, groundY, tmp.Z), splineColor, 0.1f); + g_Renderer.GetDebugRenderer().DrawLine(tmp, CVector3D(tmp.X, groundY, tmp.Z), splineColor, 0.1f, false); } } } diff -Nru 0ad-0.0.25b/source/graphics/ColladaManager.cpp 0ad-0.0.26/source/graphics/ColladaManager.cpp --- 0ad-0.0.25b/source/graphics/ColladaManager.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ColladaManager.cpp 2022-08-21 12:45:25.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,7 +22,6 @@ #include #include "graphics/ModelDef.h" -#include "lib/fnv_hash.h" #include "maths/MD5.h" #include "ps/CacheLoader.h" #include "ps/CLogger.h" diff -Nru 0ad-0.0.25b/source/graphics/ColladaManager.h 0ad-0.0.26/source/graphics/ColladaManager.h --- 0ad-0.0.25b/source/graphics/ColladaManager.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ColladaManager.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,9 +20,7 @@ #include "lib/file/vfs/vfs.h" -class CStr8; class CColladaManagerImpl; -class MD5; class CColladaManager { diff -Nru 0ad-0.0.25b/source/graphics/Color.cpp 0ad-0.0.26/source/graphics/Color.cpp --- 0ad-0.0.25b/source/graphics/Color.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Color.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -83,8 +83,9 @@ ConvertRGBColorTo4ub = ConvertRGBColorTo4ubSSE; return; } -#endif +#elif defined(ARCH_X86_64) debug_printf("No SSE available. Slow fallback routines will be used.\n"); +#endif } /** diff -Nru 0ad-0.0.25b/source/graphics/Color.h 0ad-0.0.26/source/graphics/Color.h --- 0ad-0.0.25b/source/graphics/Color.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Color.h 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,8 @@ #include "graphics/SColor.h" #include "maths/Vector3D.h" #include "maths/Vector4D.h" +#include "ps/containers/Span.h" +#include "ps/CStrForward.h" // Simple defines for 3 and 4 component floating point colors - just map to // corresponding vector types. @@ -37,8 +39,6 @@ */ extern void ColorActivateFastImpl(); -class CStr8; - struct CColor { CColor() : r(-1.f), g(-1.f), b(-1.f), a(1.f) {} @@ -66,8 +66,20 @@ return !(*this == color); } - // For passing to glColor[34]fv: - const float* FloatArray() const { return &r; } + // For passing to uniform as vec3/vec4. + PS::span AsFloatArray() const + { + // Additional check to prevent a weird compiler has a different + // alignement for an array and a class members. + static_assert( + sizeof(CColor) == sizeof(float) * 4u && + offsetof(CColor, r) == 0 && + offsetof(CColor, g) == sizeof(float) && + offsetof(CColor, b) == sizeof(float) * 2u && + offsetof(CColor, a) == sizeof(float) * 3u, + "CColor should be properly layouted to use AsFloatArray"); + return PS::span(&r, 4); + } // For passing to CRenderer: SColor4ub AsSColor4ub() const diff -Nru 0ad-0.0.25b/source/graphics/Decal.cpp 0ad-0.0.26/source/graphics/Decal.cpp --- 0ad-0.0.25b/source/graphics/Decal.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Decal.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -112,5 +112,4 @@ void CModelDecal::RemoveShadows() { m_Decal.m_Material.AddShaderDefine(str_DISABLE_RECEIVE_SHADOWS, str_1); - m_Decal.m_Material.RecomputeCombinedShaderDefines(); } diff -Nru 0ad-0.0.25b/source/graphics/Decal.h 0ad-0.0.26/source/graphics/Decal.h --- 0ad-0.0.25b/source/graphics/Decal.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Decal.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -63,11 +63,6 @@ virtual CModelAbstract* Clone() const; - virtual void SetDirtyRec(int dirtyflags) - { - SetDirty(dirtyflags); - } - virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1); virtual void CalcBounds(); diff -Nru 0ad-0.0.25b/source/graphics/Font.cpp 0ad-0.0.26/source/graphics/Font.cpp --- 0ad-0.0.25b/source/graphics/Font.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Font.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -63,6 +63,8 @@ width = 0; height = m_Height; + // Compute the width as the width of the longest line. + int lineWidth = 0; for (const wchar_t* c = string; *c != '\0'; c++) { const GlyphData* g = m_Glyphs.get(*c); @@ -71,6 +73,14 @@ g = m_Glyphs.get(0xFFFD); // Use the missing glyph symbol if (g) - width += g->xadvance; // Add the character's advance distance + lineWidth += g->xadvance; // Add the character's advance distance + + if (*c == L'\n') + { + height += m_LineSpacing; + width = std::max(width, lineWidth); + lineWidth = 0; + } } + width = std::max(width, lineWidth); } diff -Nru 0ad-0.0.25b/source/graphics/Font.h 0ad-0.0.26/source/graphics/Font.h --- 0ad-0.0.25b/source/graphics/Font.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Font.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,17 +19,12 @@ #define INCLUDED_FONT #include "graphics/Texture.h" -#include "lib/res/handle.h" - -struct UnifontGlyphData; /** * Storage for a bitmap font. Loaded by CFontManager. */ class CFont { - friend class CFontManager; - CFont() {} public: struct GlyphData { @@ -82,6 +77,10 @@ CTexturePtr GetTexture() const { return m_Texture; } private: + friend class CFontManager; + + CFont() = default; + CTexturePtr m_Texture; bool m_HasRGB; // true if RGBA, false if ALPHA diff -Nru 0ad-0.0.25b/source/graphics/FontManager.cpp 0ad-0.0.26/source/graphics/FontManager.cpp --- 0ad-0.0.25b/source/graphics/FontManager.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/FontManager.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ #include "ps/Filesystem.h" #include "renderer/Renderer.h" -#include +#include std::shared_ptr CFontManager::LoadFont(CStrIntern fontName) { @@ -55,80 +55,93 @@ const VfsPath path(L"fonts/"); // Read font definition file into a stringstream - std::shared_ptr buf; + std::shared_ptr buffer; size_t size; const VfsPath fntName(fontName.string() + ".fnt"); - if (g_VFS->LoadFile(path / fntName, buf, size) < 0) + if (g_VFS->LoadFile(path / fntName, buffer, size) < 0) { LOGERROR("Failed to open font file %s", (path / fntName).string8()); return false; } - std::istringstream FNTStream(std::string((const char*)buf.get(), size)); + std::istringstream fontStream( + std::string(reinterpret_cast(buffer.get()), size)); - int Version; - FNTStream >> Version; - if (Version != 101) // Make sure this is from a recent version of the font builder + int version; + fontStream >> version; + // Make sure this is from a recent version of the font builder. + if (version != 101) { LOGERROR("Font %s has invalid version", fontName.c_str()); - return 0; + return false; } - int TextureWidth, TextureHeight; - FNTStream >> TextureWidth >> TextureHeight; + int textureWidth, textureHeight; + fontStream >> textureWidth >> textureHeight; - std::string Format; - FNTStream >> Format; - if (Format == "rgba") + std::string format; + fontStream >> format; + if (format == "rgba") font->m_HasRGB = true; - else if (Format == "a") + else if (format == "a") font->m_HasRGB = false; else - debug_warn(L"Invalid .fnt format string"); + { + LOGWARNING("Invalid .fnt format string"); + return false; + } - int NumGlyphs; - FNTStream >> NumGlyphs; + int mumberOfGlyphs; + fontStream >> mumberOfGlyphs; - FNTStream >> font->m_LineSpacing; - FNTStream >> font->m_Height; + fontStream >> font->m_LineSpacing; + fontStream >> font->m_Height; - font->m_BoundsX0 = FLT_MAX; - font->m_BoundsY0 = FLT_MAX; - font->m_BoundsX1 = -FLT_MAX; - font->m_BoundsY1 = -FLT_MAX; + font->m_BoundsX0 = std::numeric_limits::max(); + font->m_BoundsY0 = std::numeric_limits::max(); + font->m_BoundsX1 = -std::numeric_limits::max(); + font->m_BoundsY1 = -std::numeric_limits::max(); - for (int i = 0; i < NumGlyphs; ++i) + for (int i = 0; i < mumberOfGlyphs; ++i) { - int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance; - FNTStream >> Codepoint>>TextureX>>TextureY>>Width>>Height>>OffsetX>>OffsetY>>Advance; + int codepoint, textureX, textureY, width, height, offsetX, offsetY, advance; + fontStream >> codepoint + >> textureX >> textureY >> width >> height + >> offsetX >> offsetY >> advance; - if (Codepoint < 0 || Codepoint > 0xFFFF) + if (codepoint < 0 || codepoint > 0xFFFF) { - LOGWARNING("Font %s has invalid codepoint 0x%x", fontName.c_str(), Codepoint); + LOGWARNING("Font %s has invalid codepoint 0x%x", fontName.c_str(), codepoint); continue; } - float u = (float)TextureX / (float)TextureWidth; - float v = (float)TextureY / (float)TextureHeight; - float w = (float)Width / (float)TextureWidth; - float h = (float)Height / (float)TextureHeight; - - CFont::GlyphData g = { u, -v, u+w, -v+h, (i16)OffsetX, (i16)-OffsetY, (i16)(OffsetX+Width), (i16)(-OffsetY+Height), (i16)Advance }; - font->m_Glyphs.set((u16)Codepoint, g); - - font->m_BoundsX0 = std::min(font->m_BoundsX0, (float)g.x0); - font->m_BoundsY0 = std::min(font->m_BoundsY0, (float)g.y0); - font->m_BoundsX1 = std::max(font->m_BoundsX1, (float)g.x1); - font->m_BoundsY1 = std::max(font->m_BoundsY1, (float)g.y1); + const float u = static_cast(textureX) / textureWidth; + const float v = static_cast(textureY) / textureHeight; + const float w = static_cast(width) / textureWidth; + const float h = static_cast(height) / textureHeight; + + CFont::GlyphData g = + { + u, -v, u + w, -v + h, + static_cast(offsetX), static_cast(-offsetY), + static_cast(offsetX + width), static_cast(-offsetY + height), + static_cast(advance) + }; + font->m_Glyphs.set(static_cast(codepoint), g); + + font->m_BoundsX0 = std::min(font->m_BoundsX0, static_cast(g.x0)); + font->m_BoundsY0 = std::min(font->m_BoundsY0, static_cast(g.y0)); + font->m_BoundsX1 = std::max(font->m_BoundsX1, static_cast(g.x1)); + font->m_BoundsY1 = std::max(font->m_BoundsY1, static_cast(g.y1)); } - ENSURE(font->m_Height); // Ensure the height has been found (which should always happen if the font includes an 'I') + // Ensure the height has been found (which should always happen if the font includes an 'I'). + ENSURE(font->m_Height); // Load glyph texture - const VfsPath imgName(fontName.string() + ".png"); - CTextureProperties textureProps(path / imgName); - textureProps.SetFilter(GL_LINEAR); - if (!font->m_HasRGB) - textureProps.SetFormatOverride(GL_ALPHA); + const VfsPath imageName(fontName.string() + ".png"); + CTextureProperties textureProps(path / imageName, + font->m_HasRGB ? Renderer::Backend::Format::R8G8B8A8_UNORM : Renderer::Backend::Format::A8_UNORM); + textureProps.SetIgnoreQuality(true); font->m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); return true; diff -Nru 0ad-0.0.25b/source/graphics/GameView.cpp 0ad-0.0.26/source/graphics/GameView.cpp --- 0ad-0.0.25b/source/graphics/GameView.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/GameView.cpp 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -55,6 +55,7 @@ #include "ps/TouchInput.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpPosition.h" @@ -122,12 +123,6 @@ */ bool Culling; - /** - * Cache global lighting environment. This is used to check whether the - * environment has changed during the last frame, so that vertex data can be updated etc. - */ - CLightEnv CachedLightEnv; - CCinemaManager CinemaManager; /** @@ -167,7 +162,7 @@ m(new CGameViewImpl(pGame)) { m->CullCamera = m->ViewCamera; - g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera); + g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera); } CGameView::~CGameView() @@ -224,7 +219,6 @@ RegMemFun(this, &CGameView::Initialize, L"CGameView init", 1); RegMemFun(g_TexMan.GetSingletonPtr(), &CTerrainTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 60); - RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadAlphaMaps, L"LoadAlphaMaps", 5); } void CGameView::BeginFrame() @@ -234,16 +228,14 @@ // Set up cull camera m->CullCamera = m->ViewCamera; } - g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera); - - CheckLightEnv(); + g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera); m->Game->CachePlayerColors(); } void CGameView::Render() { - g_Renderer.RenderScene(*this); + g_Renderer.GetSceneRenderer().RenderScene(g_Renderer.GetDeviceCommandContext(), *this); } /////////////////////////////////////////////////////////// @@ -255,7 +247,7 @@ PROFILE3("submit terrain"); CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain(); - float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f; + float waterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight + 0.001f; const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide(); // find out which patches will be drawn @@ -279,32 +271,10 @@ m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling); } - -void CGameView::CheckLightEnv() -{ - if (m->CachedLightEnv == g_LightEnv) - return; - - m->CachedLightEnv = g_LightEnv; - CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain(); - - if (!pTerrain) - return; - - PROFILE("update light env"); - pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR); - - const std::vector& units = m->Game->GetWorld()->GetUnitManager().GetUnits(); - for (size_t i = 0; i < units.size(); ++i) - units[i]->GetModel().SetDirtyRec(RENDERDATA_UPDATE_COLOR); -} - - void CGameView::UnloadResources() { g_TexMan.UnloadTerrainTextures(); - g_Renderer.UnloadAlphaMaps(); - g_Renderer.GetWaterManager()->UnloadWaterTextures(); + g_Renderer.GetSceneRenderer().GetWaterManager().UnloadWaterTextures(); } void CGameView::Update(const float deltaRealTime) @@ -389,30 +359,31 @@ case SDL_HOTKEYPRESS: { std::string hotkey = static_cast(ev->ev.user.data1); + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); if (hotkey == "wireframe") { if (g_XmppClient && g_rankedGame == true) break; - else if (g_Renderer.GetModelRenderMode() == SOLID) + else if (sceneRenderer.GetModelRenderMode() == SOLID) { - g_Renderer.SetTerrainRenderMode(EDGED_FACES); - g_Renderer.SetWaterRenderMode(EDGED_FACES); - g_Renderer.SetModelRenderMode(EDGED_FACES); - g_Renderer.SetOverlayRenderMode(EDGED_FACES); + sceneRenderer.SetTerrainRenderMode(EDGED_FACES); + sceneRenderer.SetWaterRenderMode(EDGED_FACES); + sceneRenderer.SetModelRenderMode(EDGED_FACES); + sceneRenderer.SetOverlayRenderMode(EDGED_FACES); } - else if (g_Renderer.GetModelRenderMode() == EDGED_FACES) + else if (sceneRenderer.GetModelRenderMode() == EDGED_FACES) { - g_Renderer.SetTerrainRenderMode(WIREFRAME); - g_Renderer.SetWaterRenderMode(WIREFRAME); - g_Renderer.SetModelRenderMode(WIREFRAME); - g_Renderer.SetOverlayRenderMode(WIREFRAME); + sceneRenderer.SetTerrainRenderMode(WIREFRAME); + sceneRenderer.SetWaterRenderMode(WIREFRAME); + sceneRenderer.SetModelRenderMode(WIREFRAME); + sceneRenderer.SetOverlayRenderMode(WIREFRAME); } else { - g_Renderer.SetTerrainRenderMode(SOLID); - g_Renderer.SetWaterRenderMode(SOLID); - g_Renderer.SetModelRenderMode(SOLID); - g_Renderer.SetOverlayRenderMode(SOLID); + sceneRenderer.SetTerrainRenderMode(SOLID); + sceneRenderer.SetWaterRenderMode(SOLID); + sceneRenderer.SetModelRenderMode(SOLID); + sceneRenderer.SetOverlayRenderMode(SOLID); } return IN_HANDLED; } diff -Nru 0ad-0.0.25b/source/graphics/GameView.h 0ad-0.0.26/source/graphics/GameView.h --- 0ad-0.0.25b/source/graphics/GameView.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/GameView.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -92,9 +92,6 @@ // Unloads all graphics resources loaded by RegisterInit. void UnloadResources(); - // Checks whether lighting environment has changed and update vertex data if necessary. - void CheckLightEnv(); - CGameViewImpl* m; }; diff -Nru 0ad-0.0.25b/source/graphics/LOSTexture.cpp 0ad-0.0.26/source/graphics/LOSTexture.cpp --- 0ad-0.0.25b/source/graphics/LOSTexture.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/LOSTexture.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,10 +22,13 @@ #include "graphics/ShaderManager.h" #include "lib/bits.h" #include "lib/config2.h" +#include "lib/timer.h" +#include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" #include "ps/Game.h" #include "ps/Profile.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/TimeManager.h" @@ -53,16 +56,14 @@ // Keep it in relation to the number of impassable tiles in MAP_EDGE_TILES. static const size_t g_BlurSize = 7; -// Alignment (in bytes) of the pixel data passed into glTexSubImage2D. +// Alignment (in bytes) of the pixel data passed into texture uploading. // This must be a multiple of GL_UNPACK_ALIGNMENT, which ought to be 1 (since // that's what we set it to) but in some weird cases appears to have a different // value. (See Trac #2594). Multiples of 4 are possibly good for performance anyway. static const size_t g_SubTextureAlignment = 4; CLOSTexture::CLOSTexture(CSimulation2& simulation) - : m_Simulation(simulation), m_Dirty(true), m_ShaderInitialized(false), - m_Texture(0), m_TextureSmooth1(0), m_TextureSmooth2(0), m_smoothFbo(0), - m_MapSize(0), m_TextureSize(0), whichTex(true) + : m_Simulation(simulation) { if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS()) CreateShader(); @@ -70,6 +71,9 @@ CLOSTexture::~CLOSTexture() { + m_SmoothFramebuffers[0].reset(); + m_SmoothFramebuffers[1].reset(); + if (m_Texture) DeleteTexture(); } @@ -77,10 +81,8 @@ // Create the LOS texture engine. Should be ran only once. bool CLOSTexture::CreateShader() { - m_smoothShader = g_Renderer.GetShaderManager().LoadEffect(str_los_interp); - CShaderProgramPtr shader = m_smoothShader->GetShader(); - - m_ShaderInitialized = m_smoothShader && shader; + m_SmoothTech = g_Renderer.GetShaderManager().LoadEffect(str_los_interp); + m_ShaderInitialized = m_SmoothTech && m_SmoothTech->GetShader(); if (!m_ShaderInitialized) { @@ -89,23 +91,14 @@ return false; } - pglGenFramebuffersEXT(1, &m_smoothFbo); return true; } void CLOSTexture::DeleteTexture() { - glDeleteTextures(1, &m_Texture); - - if (m_TextureSmooth1) - glDeleteTextures(1, &m_TextureSmooth1); - - if (m_TextureSmooth2) - glDeleteTextures(1, &m_TextureSmooth2); - - m_Texture = 0; - m_TextureSmooth1 = 0; - m_TextureSmooth2 = 0; + m_Texture.reset(); + m_SmoothTextures[0].reset(); + m_SmoothTextures[1].reset(); } void CLOSTexture::MakeDirty() @@ -113,75 +106,71 @@ m_Dirty = true; } -void CLOSTexture::BindTexture(int unit) -{ - if (m_Dirty) - { - RecomputeTexture(unit); - m_Dirty = false; - } - - g_Renderer.BindTexture(unit, m_Texture); -} - -GLuint CLOSTexture::GetTextureSmooth() +Renderer::Backend::ITexture* CLOSTexture::GetTextureSmooth() { if (CRenderer::IsInitialised() && !g_RenderingOptions.GetSmoothLOS()) return GetTexture(); else - return whichTex ? m_TextureSmooth1 : m_TextureSmooth2; + return m_SmoothTextures[m_WhichTexture].get(); } -void CLOSTexture::InterpolateLOS() +void CLOSTexture::InterpolateLOS(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - if (CRenderer::IsInitialised() && !g_RenderingOptions.GetSmoothLOS()) - return; - - if (!m_ShaderInitialized) + const bool skipSmoothLOS = CRenderer::IsInitialised() && !g_RenderingOptions.GetSmoothLOS(); + if (!skipSmoothLOS && !m_ShaderInitialized) { if (!CreateShader()) return; - // RecomputeTexture(0) will not cause the ConstructTexture to run. + // RecomputeTexture will not cause the ConstructTexture to run. // Force the textures to be created. DeleteTexture(); - ConstructTexture(0); + ConstructTexture(deviceCommandContext); m_Dirty = true; } if (m_Dirty) { - RecomputeTexture(0); + RecomputeTexture(deviceCommandContext); + // We need to subtract the frame time because without it we have the + // same output images for the current and previous frames. + m_LastTextureRecomputeTime = timer_Time() - g_Renderer.GetTimeManager().GetFrameDelta(); + m_WhichTexture = 1u - m_WhichTexture; m_Dirty = false; } - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_smoothFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, - whichTex ? m_TextureSmooth2 : m_TextureSmooth1, 0); - - GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("LOS framebuffer object incomplete: 0x%04X", status); - } - - m_smoothShader->BeginPass(); - CShaderProgramPtr shader = m_smoothShader->GetShader(); - - glDisable(GL_BLEND); - - shader->Bind(); + if (skipSmoothLOS) + return; - shader->BindTexture(str_losTex1, m_Texture); - shader->BindTexture(str_losTex2, whichTex ? m_TextureSmooth1 : m_TextureSmooth2); + GPU_SCOPED_LABEL(deviceCommandContext, "Render LOS texture"); + deviceCommandContext->SetFramebuffer(m_SmoothFramebuffers[m_WhichTexture].get()); - shader->Uniform(str_delta, (float)g_Renderer.GetTimeManager().GetFrameDelta() * 4.0f, 0.0f, 0.0f, 0.0f); + deviceCommandContext->SetGraphicsPipelineState( + m_SmoothTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = m_SmoothTech->GetShader(); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex1), m_Texture.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex2), m_SmoothTextures[1u - m_WhichTexture].get()); + + const float delta = Clamp( + (timer_Time() - m_LastTextureRecomputeTime) * 2.0f, 0.0f, 1.0f); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_delta), delta); const SViewPort oldVp = g_Renderer.GetViewport(); - const SViewPort vp = { 0, 0, m_TextureSize, m_TextureSize }; + const SViewPort vp = + { + 0, 0, + static_cast(m_Texture->GetWidth()), + static_cast(m_Texture->GetHeight()) + }; g_Renderer.SetViewport(vp); - float quadVerts[] = { + float quadVerts[] = + { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, @@ -190,7 +179,8 @@ 1.0f, -1.0f, 1.0f, 1.0f }; - float quadTex[] = { + float quadTex[] = + { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -199,33 +189,36 @@ 1.0f, 0.0f, 1.0f, 1.0f }; - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); - g_Renderer.SetViewport(oldVp); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); - shader->Unbind(); - m_smoothShader->EndPass(); + deviceCommandContext->Draw(0, 6); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); + g_Renderer.SetViewport(oldVp); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->EndPass(); - whichTex = !whichTex; + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } -GLuint CLOSTexture::GetTexture() +Renderer::Backend::ITexture* CLOSTexture::GetTexture() { - if (m_Dirty) - { - RecomputeTexture(0); - m_Dirty = false; - } - - return m_Texture; + ENSURE(!m_Dirty); + return m_Texture.get(); } const CMatrix3D& CLOSTexture::GetTextureMatrix() @@ -234,13 +227,13 @@ return m_TextureMatrix; } -const CMatrix3D* CLOSTexture::GetMinimapTextureMatrix() +const CMatrix3D& CLOSTexture::GetMinimapTextureMatrix() { ENSURE(!m_Dirty); - return &m_MinimapTextureMatrix; + return m_MinimapTextureMatrix; } -void CLOSTexture::ConstructTexture(int unit) +void CLOSTexture::ConstructTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY); if (!cmpRangeManager) @@ -248,43 +241,62 @@ m_MapSize = cmpRangeManager->GetVerticesPerSide(); - m_TextureSize = (GLsizei)round_up_to_pow2(round_up((size_t)m_MapSize + g_BlurSize - 1, g_SubTextureAlignment)); + const size_t textureSize = round_up_to_pow2(round_up((size_t)m_MapSize + g_BlurSize - 1, g_SubTextureAlignment)); - glGenTextures(1, &m_Texture); + Renderer::Backend::IDevice* backendDevice = deviceCommandContext->GetDevice(); + + const Renderer::Backend::Sampler::Desc defaultSamplerDesc = + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + + if (backendDevice->IsFramebufferFormatSupported(Renderer::Backend::Format::R8_UNORM)) + { + m_TextureFormat = Renderer::Backend::Format::R8_UNORM; + m_TextureFormatStride = 1; + } + else + { + m_TextureFormat = Renderer::Backend::Format::R8G8B8A8_UNORM; + m_TextureFormatStride = 4; + } + + m_Texture = backendDevice->CreateTexture2D("LOSTexture", + m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); // Initialise texture with SoD color, for the areas we don't - // overwrite with glTexSubImage2D later - u8* texData = new u8[m_TextureSize * m_TextureSize * 4]; - memset(texData, 0x00, m_TextureSize * m_TextureSize * 4); + // overwrite with uploading later. + const size_t textureDataSize = textureSize * textureSize * m_TextureFormatStride; + std::unique_ptr texData = std::make_unique(textureDataSize); + memset(texData.get(), 0x00, textureDataSize); if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS()) { - glGenTextures(1, &m_TextureSmooth1); - glGenTextures(1, &m_TextureSmooth2); + m_SmoothTextures[0] = backendDevice->CreateTexture2D("LOSSmoothTexture0", + m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); + m_SmoothTextures[1] = backendDevice->CreateTexture2D("LOSSmoothTexture1", + m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); + + m_SmoothFramebuffers[0] = backendDevice->CreateFramebuffer( + "LOSSmoothFramebuffer0", m_SmoothTextures[0].get(), nullptr); + m_SmoothFramebuffers[1] = backendDevice->CreateFramebuffer( + "LOSSmoothFramebuffer1", m_SmoothTextures[1].get(), nullptr); + if (!m_SmoothFramebuffers[0] || !m_SmoothFramebuffers[1]) + { + LOGERROR("Failed to create LOS framebuffers"); + g_RenderingOptions.SetSmoothLOS(false); + } + + deviceCommandContext->UploadTexture( + m_SmoothTextures[0].get(), m_TextureFormat, texData.get(), textureDataSize); + deviceCommandContext->UploadTexture( + m_SmoothTextures[1].get(), m_TextureFormat, texData.get(), textureDataSize); + } - g_Renderer.BindTexture(unit, m_TextureSmooth1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData); - 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_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - g_Renderer.BindTexture(unit, m_TextureSmooth2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData); - 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_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - g_Renderer.BindTexture(unit, m_Texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData); - 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_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + deviceCommandContext->UploadTexture( + m_Texture.get(), m_TextureFormat, texData.get(), textureDataSize); - delete[] texData; + texData.reset(); { // Texture matrix: We want to map @@ -293,8 +305,8 @@ // world pos ((mapsize-1)*cellsize, y, (mapsize-1)*cellsize) (i.e. last vertex) // onto texcoord ((mapsize-0.5) / texsize, (mapsize-0.5) / texsize) (i.e. middle of last texel) - float s = (m_MapSize-1) / (float)(m_TextureSize * (m_MapSize-1) * LOS_TILE_SIZE); - float t = 0.5f / m_TextureSize; + float s = (m_MapSize-1) / static_cast(textureSize * (m_MapSize-1) * LOS_TILE_SIZE); + float t = 0.5f / textureSize; m_TextureMatrix.SetZero(); m_TextureMatrix._11 = s; m_TextureMatrix._23 = s; @@ -306,7 +318,7 @@ { // Minimap matrix: We want to map UV (0,0)-(1,1) onto (0,0)-(mapsize/texsize, mapsize/texsize) - float s = m_MapSize / (float)m_TextureSize; + float s = m_MapSize / (float)textureSize; m_MinimapTextureMatrix.SetZero(); m_MinimapTextureMatrix._11 = s; m_MinimapTextureMatrix._22 = s; @@ -314,7 +326,7 @@ } } -void CLOSTexture::RecomputeTexture(int unit) +void CLOSTexture::RecomputeTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { // If the map was resized, delete and regenerate the texture if (m_Texture) @@ -327,34 +339,55 @@ bool recreated = false; if (!m_Texture) { - ConstructTexture(unit); + ConstructTexture(deviceCommandContext); recreated = true; } PROFILE("recompute LOS texture"); - std::vector losData; - size_t pitch; - losData.resize(GetBitmapSize(m_MapSize, m_MapSize, &pitch)); - CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY); if (!cmpRangeManager) return; - CLosQuerier los(cmpRangeManager->GetLosQuerier(g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer())); + size_t pitch; + const size_t dataSize = GetBitmapSize(m_MapSize, m_MapSize, &pitch); + ENSURE(pitch * m_MapSize <= dataSize); + std::unique_ptr losData = std::make_unique( + dataSize * m_TextureFormatStride); + + CLosQuerier los(cmpRangeManager->GetLosQuerier(m_Simulation.GetSimContext().GetCurrentDisplayedPlayer())); GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize, pitch); + // GenerateBitmap writes data tightly packed and we need to offset it to fit + // into the texture format properly. + const size_t textureDataPitch = pitch * m_TextureFormatStride; + if (m_TextureFormatStride > 1) + { + // We skip the last byte because it will be first in our order and we + // don't need to move it. + for (size_t index = 0; index + 1 < dataSize; ++index) + { + const size_t oldAddress = dataSize - 1 - index; + const size_t newAddress = oldAddress * m_TextureFormatStride; + losData[newAddress] = losData[oldAddress]; + losData[oldAddress] = 0; + } + } + if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS() && recreated) { - g_Renderer.BindTexture(unit, m_TextureSmooth1); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pitch, m_MapSize, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]); - g_Renderer.BindTexture(unit, m_TextureSmooth2); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pitch, m_MapSize, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]); + deviceCommandContext->UploadTextureRegion( + m_SmoothTextures[0].get(), m_TextureFormat, losData.get(), + textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize); + deviceCommandContext->UploadTextureRegion( + m_SmoothTextures[1].get(), m_TextureFormat, losData.get(), + textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize); } - g_Renderer.BindTexture(unit, m_Texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pitch, m_MapSize, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]); + deviceCommandContext->UploadTextureRegion( + m_Texture.get(), m_TextureFormat, losData.get(), + textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize); } size_t CLOSTexture::GetBitmapSize(size_t w, size_t h, size_t* pitch) diff -Nru 0ad-0.0.25b/source/graphics/LOSTexture.h 0ad-0.0.26/source/graphics/LOSTexture.h --- 0ad-0.0.25b/source/graphics/LOSTexture.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/LOSTexture.h 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,10 +18,14 @@ #ifndef INCLUDED_LOSTEXTURE #define INCLUDED_LOSTEXTURE -#include "lib/ogl.h" - #include "graphics/ShaderTechniquePtr.h" #include "maths/Matrix3D.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/ITexture.h" + +#include class CLosQuerier; class CSimulation2; @@ -46,65 +50,67 @@ void MakeDirty(); /** - * Recomputes the LOS texture if necessary, and binds it to the requested - * texture unit. - * Also switches the current active texture unit, and enables texturing on it. - * The texture is in 8-bit ALPHA format. - */ - void BindTexture(int unit); - - /** * Recomputes the LOS texture if necessary, and returns the texture handle. * Also potentially switches the current active texture unit, and enables texturing on it. * The texture is in 8-bit ALPHA format. */ - GLuint GetTexture(); + Renderer::Backend::ITexture* GetTexture(); + Renderer::Backend::ITexture* GetTextureSmooth(); - void InterpolateLOS(); - GLuint GetTextureSmooth(); + void InterpolateLOS(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Returns a matrix to map (x,y,z) world coordinates onto (u,v) LOS texture - * coordinates, in the form expected by glLoadMatrixf. - * This must only be called after BindTexture. + * coordinates, in the form expected by a matrix uniform. + * This must only be called after InterpolateLOS. */ const CMatrix3D& GetTextureMatrix(); /** * Returns a matrix to map (0,0)-(1,1) texture coordinates onto LOS texture - * coordinates, in the form expected by glLoadMatrixf. - * This must only be called after BindTexture. + * coordinates, in the form expected by a matrix uniform. + * This must only be called after InterpolateLOS. */ - const CMatrix3D* GetMinimapTextureMatrix(); + const CMatrix3D& GetMinimapTextureMatrix(); private: void DeleteTexture(); bool CreateShader(); - void ConstructTexture(int unit); - void RecomputeTexture(int unit); + void ConstructTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + void RecomputeTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); size_t GetBitmapSize(size_t w, size_t h, size_t* pitch); void GenerateBitmap(const CLosQuerier& los, u8* losData, size_t w, size_t h, size_t pitch); CSimulation2& m_Simulation; - bool m_Dirty; - - bool m_ShaderInitialized; - - GLuint m_Texture; - GLuint m_TextureSmooth1, m_TextureSmooth2; + bool m_Dirty = true; - bool whichTex; + bool m_ShaderInitialized = false; - GLuint m_smoothFbo; - CShaderTechniquePtr m_smoothShader; + // We need to choose the smallest format. We always use the red channel but + // R8_UNORM might be unavailable on some platforms. So we fallback to + // R8G8B8A8_UNORM. + Renderer::Backend::Format m_TextureFormat = + Renderer::Backend::Format::UNDEFINED; + size_t m_TextureFormatStride = 0; + std::unique_ptr + m_Texture, m_SmoothTextures[2]; + + uint32_t m_WhichTexture = 0; + double m_LastTextureRecomputeTime = 0.0; + + // We update textures once a frame, so we change a Framebuffer once a frame. + // That allows us to use two ping-pong FBOs instead of checking completeness + // of Framebuffer each frame. + std::unique_ptr + m_SmoothFramebuffers[2]; + CShaderTechniquePtr m_SmoothTech; - size_t m_MapSize; // vertexes per side - GLsizei m_TextureSize; // texels per side + size_t m_MapSize = 0; // vertexes per side CMatrix3D m_TextureMatrix; CMatrix3D m_MinimapTextureMatrix; }; -#endif // INCLUDED_LOSTEXTURE \ No newline at end of file +#endif // INCLUDED_LOSTEXTURE diff -Nru 0ad-0.0.25b/source/graphics/MapGenerator.cpp 0ad-0.0.26/source/graphics/MapGenerator.cpp --- 0ad-0.0.25b/source/graphics/MapGenerator.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MapGenerator.cpp 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -170,7 +170,7 @@ m_MapGenRNG.seed(seed); // VFS - JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface); + JSI_VFS::RegisterScriptFunctions_ReadOnlySimulationMaps(*m_ScriptInterface); // Globalscripts may use VFS script functions m_ScriptInterface->LoadGlobalScripts(); diff -Nru 0ad-0.0.25b/source/graphics/MapReader.cpp 0ad-0.0.26/source/graphics/MapReader.cpp --- 0ad-0.0.25b/source/graphics/MapReader.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MapReader.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -247,9 +247,11 @@ CStr texturename; unpacker.UnpackString(texturename); - ENSURE(CTerrainTextureManager::IsInitialised()); // we need this for the terrain properties (even when graphics are disabled) - CTerrainTextureEntry* texentry = g_TexMan.FindTexture(texturename); - m_TerrainTextures.push_back(texentry); + if (CTerrainTextureManager::IsInitialised()) + { + CTerrainTextureEntry* texentry = g_TexMan.FindTexture(texturename); + m_TerrainTextures.push_back(texentry); + } cur_terrain_tex++; LDR_CHECK_TIMEOUT(cur_terrain_tex, num_terrain_tex); @@ -279,18 +281,21 @@ // initialise the terrain pTerrain->Initialize(m_PatchesPerSide, &m_Heightmap[0]); - // setup the textures on the minipatches - STileDesc* tileptr = &m_Tiles[0]; - for (ssize_t j=0; jGetPatch(i,j)->m_MiniPatches[m][k]; // can't fail + if (CTerrainTextureManager::IsInitialised()) + { + // setup the textures on the minipatches + STileDesc* tileptr = &m_Tiles[0]; + for (ssize_t j=0; jGetPatch(i,j)->m_MiniPatches[m][k]; // can't fail - mp.Tex = m_TerrainTextures[tileptr->m_Tex1Index]; - mp.Priority = tileptr->m_Priority; + mp.Tex = m_TerrainTextures[tileptr->m_Tex1Index]; + mp.Priority = tileptr->m_Priority; - tileptr++; + tileptr++; + } } } } @@ -558,8 +563,9 @@ m_MapReader.m_PatchesPerSide = patches; // Load the texture - ENSURE(CTerrainTextureManager::IsInitialised()); // we need this for the terrain properties (even when graphics are disabled) - CTerrainTextureEntry* texentry = g_TexMan.FindTexture(texture); + CTerrainTextureEntry* texentry = nullptr; + if (CTerrainTextureManager::IsInitialised()) + texentry = g_TexMan.FindTexture(texture); m_MapReader.pTerrain->Initialize(patches, NULL); @@ -1354,9 +1360,11 @@ while (cur_terrain_tex < num_terrain_tex) { - ENSURE(CTerrainTextureManager::IsInitialised()); // we need this for the terrain properties (even when graphics are disabled) - CTerrainTextureEntry* texentry = g_TexMan.FindTexture(textureNames[cur_terrain_tex]); - m_TerrainTextures.push_back(texentry); + if (CTerrainTextureManager::IsInitialised()) + { + CTerrainTextureEntry* texentry = g_TexMan.FindTexture(textureNames[cur_terrain_tex]); + m_TerrainTextures.push_back(texentry); + } cur_terrain_tex++; } diff -Nru 0ad-0.0.25b/source/graphics/MapReader.h 0ad-0.0.26/source/graphics/MapReader.h --- 0ad-0.0.25b/source/graphics/MapReader.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MapReader.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,13 +21,11 @@ #include "MapIO.h" #include "graphics/LightEnv.h" -#include "lib/res/handle.h" #include "ps/CStr.h" #include "ps/FileIo.h" #include "scriptinterface/ScriptTypes.h" #include "simulation2/system/Entity.h" -class CObjectEntry; class CTerrain; class WaterManager; class SkyManager; diff -Nru 0ad-0.0.25b/source/graphics/MapWriter.h 0ad-0.0.26/source/graphics/MapWriter.h --- 0ad-0.0.25b/source/graphics/MapWriter.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MapWriter.h 2022-08-21 12:45:23.000000000 +0000 @@ -30,13 +30,10 @@ class CCamera; class CCinemaManager; class CPostprocManager; -class CTriggerManager; class WaterManager; class SkyManager; class CSimulation2; struct MapTrigger; -struct MapTriggerGroup; -class XMLWriter_File; class CMapWriter : public CMapIO { diff -Nru 0ad-0.0.25b/source/graphics/Material.cpp 0ad-0.0.26/source/graphics/Material.cpp --- 0ad-0.0.25b/source/graphics/Material.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Material.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,13 +35,6 @@ void CMaterial::AddShaderDefine(CStrIntern key, CStrIntern value) { m_ShaderDefines.Add(key, value); - m_CombinedShaderDefines.clear(); -} - -void CMaterial::AddConditionalDefine(const char* defname, const char* defvalue, int type, std::vector &args) -{ - m_ConditionalDefines.Add(defname, defvalue, type, args); - m_CombinedShaderDefines.clear(); } void CMaterial::AddStaticUniform(const char* key, const CVector4D& value) @@ -66,31 +59,3 @@ CStrIntern string(samplerName); m_RequiredSamplers.push_back(string); } - - -// Set up m_CombinedShaderDefines so that index i contains m_ShaderDefines, plus -// the extra defines from m_ConditionalDefines[j] for all j where bit j is set in i. -// This lets GetShaderDefines() cheaply return the defines for any combination of conditions. -// -// (This might scale badly if we had a large number of conditional defines per material, -// but currently we don't expect to have many.) -void CMaterial::RecomputeCombinedShaderDefines() -{ - m_CombinedShaderDefines.clear(); - int size = m_ConditionalDefines.GetSize(); - - // Loop over all 2^n combinations of flags - for (int i = 0; i < (1 << size); i++) - { - CShaderDefines defs = m_ShaderDefines; - for (int j = 0; j < size; j++) - { - if (i & (1 << j)) - { - const CShaderConditionalDefines::CondDefine& def = m_ConditionalDefines.GetItem(j); - defs.Add(def.m_DefName, def.m_DefValue); - } - } - m_CombinedShaderDefines.push_back(defs); - } -} diff -Nru 0ad-0.0.25b/source/graphics/Material.h 0ad-0.0.26/source/graphics/Material.h --- 0ad-0.0.25b/source/graphics/Material.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Material.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -56,15 +56,7 @@ // Must call RecomputeCombinedShaderDefines after this, before rendering with this material void AddShaderDefine(CStrIntern key, CStrIntern value); - // conditionFlags is a bitmask representing which indexes of the - // GetConditionalDefines() list are currently matching. - // Use 0 if you don't care about conditional defines. - const CShaderDefines& GetShaderDefines(uint32_t conditionFlags) const { return m_CombinedShaderDefines.at(conditionFlags); } - - // Must call RecomputeCombinedShaderDefines after this, before rendering with this material - void AddConditionalDefine(const char* defname, const char* defvalue, int type, std::vector &args); - - const CShaderConditionalDefines& GetConditionalDefines() const { return m_ConditionalDefines; } + const CShaderDefines& GetShaderDefines() const { return m_ShaderDefines; } void AddStaticUniform(const char* key, const CVector4D& value); const CShaderUniforms& GetStaticUniforms() const { return m_StaticUniforms; } @@ -78,9 +70,6 @@ void AddRequiredSampler(const CStr& samplerName); const std::vector& GetRequiredSampler() const { return m_RequiredSamplers; } - // Must be called after all AddShaderDefine and AddConditionalDefine - void RecomputeCombinedShaderDefines(); - private: // This pointer is kept to make it easier for the fixed pipeline to @@ -92,12 +81,10 @@ CStrIntern m_ShaderEffect; CShaderDefines m_ShaderDefines; - CShaderConditionalDefines m_ConditionalDefines; - std::vector m_CombinedShaderDefines; CShaderUniforms m_StaticUniforms; CShaderRenderQueries m_RenderQueries; bool m_AlphaBlending; }; -#endif +#endif // INCLUDED_MATERIAL diff -Nru 0ad-0.0.25b/source/graphics/MaterialManager.cpp 0ad-0.0.26/source/graphics/MaterialManager.cpp --- 0ad-0.0.25b/source/graphics/MaterialManager.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MaterialManager.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ #include "MaterialManager.h" #include "graphics/PreprocessorWrapper.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" @@ -64,7 +63,6 @@ EL(uniform); EL(renderquery); EL(required_texture); - EL(conditional_define); AT(effect); AT(if); AT(define); @@ -72,15 +70,10 @@ AT(material); AT(name); AT(value); - AT(type); - AT(min); - AT(max); - AT(conf); #undef AT #undef EL CPreprocessorWrapper preprocessor; - preprocessor.AddDefine("CFG_FORCE_ALPHATEST", g_RenderingOptions.GetForceAlphaTest() ? "1" : "0"); CMaterial material; material.AddStaticUniform("qualityLevel", CVector4D(qualityLevel, 0, 0, 0)); @@ -119,59 +112,6 @@ { material.AddShaderDefine(CStrIntern(attrs.GetNamedItem(at_name)), CStrIntern(attrs.GetNamedItem(at_value))); } - else if (token == el_conditional_define) - { - std::vector args; - - CStr type = attrs.GetNamedItem(at_type).c_str(); - int typeID = -1; - - if (type == CStr("draw_range")) - { - typeID = DCOND_DISTANCE; - - float valmin = -1.0f; - float valmax = -1.0f; - - CStr conf = attrs.GetNamedItem(at_conf); - if (!conf.empty()) - { - CFG_GET_VAL("materialmgr." + conf + ".min", valmin); - CFG_GET_VAL("materialmgr." + conf + ".max", valmax); - } - else - { - CStr dmin = attrs.GetNamedItem(at_min); - if (!dmin.empty()) - valmin = attrs.GetNamedItem(at_min).ToFloat(); - - CStr dmax = attrs.GetNamedItem(at_max); - if (!dmax.empty()) - valmax = attrs.GetNamedItem(at_max).ToFloat(); - } - - args.push_back(valmin); - args.push_back(valmax); - - if (valmin >= 0.0f) - { - std::stringstream sstr; - sstr << valmin; - material.AddShaderDefine(CStrIntern(conf + "_MIN"), CStrIntern(sstr.str())); - } - - if (valmax >= 0.0f) - { - std::stringstream sstr; - sstr << valmax; - material.AddShaderDefine(CStrIntern(conf + "_MAX"), CStrIntern(sstr.str())); - } - } - - material.AddConditionalDefine(attrs.GetNamedItem(at_name).c_str(), - attrs.GetNamedItem(at_value).c_str(), - typeID, args); - } else if (token == el_uniform) { std::stringstream str(attrs.GetNamedItem(at_value)); @@ -191,8 +131,6 @@ } } - material.RecomputeCombinedShaderDefines(); - m_Materials[pathname] = material; return material; } diff -Nru 0ad-0.0.25b/source/graphics/MiniMapTexture.cpp 0ad-0.0.26/source/graphics/MiniMapTexture.cpp --- 0ad-0.0.25b/source/graphics/MiniMapTexture.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MiniMapTexture.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,19 +19,33 @@ #include "MiniMapTexture.h" +#include "graphics/GameView.h" +#include "graphics/LOSTexture.h" #include "graphics/MiniPatch.h" +#include "graphics/ShaderManager.h" +#include "graphics/ShaderProgramPtr.h" #include "graphics/Terrain.h" #include "graphics/TerrainTextureEntry.h" #include "graphics/TerrainTextureManager.h" #include "graphics/TerritoryTexture.h" +#include "graphics/TextureManager.h" #include "lib/bits.h" +#include "lib/hash.h" +#include "lib/timer.h" +#include "maths/MathUtil.h" +#include "maths/Vector2D.h" +#include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/Game.h" +#include "ps/Profile.h" +#include "ps/VideoMode.h" #include "ps/World.h" #include "ps/XML/Xeromyces.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "scriptinterface/Object.h" #include "simulation2/Simulation2.h" @@ -39,26 +53,235 @@ #include "simulation2/components/ICmpRangeManager.h" #include "simulation2/system/ParamNode.h" +#include +#include +#include + namespace { +// Set max drawn entities to 64K / 4 for now, which is more than enough. +// 4 is the number of vertices per entity. +// TODO: we should be cleverer about drawing them to reduce clutter, +// f.e. use instancing. +constexpr size_t MAX_ENTITIES_DRAWN = 65536 / 4; + +constexpr size_t MAX_ICON_COUNT = 256; +constexpr size_t MAX_UNIQUE_ICON_COUNT = 64; +constexpr size_t ICON_COMBINING_GRID_SIZE = 10; + +constexpr size_t FINAL_TEXTURE_SIZE = 512; + unsigned int ScaleColor(unsigned int color, float x) { unsigned int r = unsigned(float(color & 0xff) * x); - unsigned int g = unsigned(float((color>>8) & 0xff) * x); - unsigned int b = unsigned(float((color>>16) & 0xff) * x); - return (0xff000000 | b | g<<8 | r<<16); + unsigned int g = unsigned(float((color >> 8) & 0xff) * x); + unsigned int b = unsigned(float((color >> 16) & 0xff) * x); + return (0xff000000 | b | g << 8 | r << 16); +} + +void DrawTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + const float quadUVs[] = + { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f + }; + const float quadVertices[] = + { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + + 1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f + }; + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVertices, std::size(quadVertices) * sizeof(quadVertices[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadUVs, std::size(quadUVs) * sizeof(quadUVs[0])); + + deviceCommandContext->Draw(0, 6); +} + +struct MinimapUnitVertex +{ + // This struct is copyable for convenience and because to move is to copy for primitives. + u8 r, g, b, a; + CVector2D position; +}; + +// Adds a vertex to the passed VertexArray +inline void AddEntity(const MinimapUnitVertex& v, + VertexArrayIterator& attrColor, + VertexArrayIterator& attrPos, + const float entityRadius, + const bool useInstancing) +{ + if (useInstancing) + { + (*attrColor)[0] = v.r; + (*attrColor)[1] = v.g; + (*attrColor)[2] = v.b; + (*attrColor)[3] = v.a; + ++attrColor; + + (*attrPos)[0] = v.position.X; + (*attrPos)[1] = v.position.Y; + ++attrPos; + + return; + } + + const CVector2D offsets[4] = + { + {-entityRadius, 0.0f}, + {0.0f, -entityRadius}, + {entityRadius, 0.0f}, + {0.0f, entityRadius} + }; + + for (const CVector2D& offset : offsets) + { + (*attrColor)[0] = v.r; + (*attrColor)[1] = v.g; + (*attrColor)[2] = v.b; + (*attrColor)[3] = v.a; + ++attrColor; + + (*attrPos)[0] = v.position.X + offset.X; + (*attrPos)[1] = v.position.Y + offset.Y; + ++attrPos; + } } } // anonymous namespace +size_t CMiniMapTexture::CellIconKeyHash::operator()( + const CellIconKey& key) const +{ + size_t seed = 0; + hash_combine(seed, key.path); + hash_combine(seed, key.r); + hash_combine(seed, key.g); + hash_combine(seed, key.b); + return seed; +} + +bool CMiniMapTexture::CellIconKeyEqual::operator()( + const CellIconKey& lhs, const CellIconKey& rhs) const +{ + return + lhs.path == rhs.path && + lhs.r == rhs.r && + lhs.g == rhs.g && + lhs.b == rhs.b; +} + CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation) - : m_Simulation(simulation) + : m_Simulation(simulation), m_IndexArray(false), + m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX, true), + m_InstanceVertexArray(Renderer::Backend::IBuffer::Type::VERTEX, false) { // Register Relax NG validator. CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); m_ShallowPassageHeight = GetShallowPassageHeight(); + + double blinkDuration = 1.0; + // Tests won't have config initialised + if (CConfigDB::IsInitialised()) + { + CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration); + CFG_GET_VAL("gui.session.minimap.pingduration", m_PingDuration); + } + m_HalfBlinkDuration = blinkDuration / 2.0; + + m_AttributePos.format = Renderer::Backend::Format::R32G32_SFLOAT; + m_VertexArray.AddAttribute(&m_AttributePos); + + m_AttributeColor.format = Renderer::Backend::Format::R8G8B8A8_UNORM; + m_VertexArray.AddAttribute(&m_AttributeColor); + + m_VertexArray.SetNumberOfVertices(MAX_ENTITIES_DRAWN * 4); + m_VertexArray.Layout(); + + m_IndexArray.SetNumberOfVertices(MAX_ENTITIES_DRAWN * 6); + m_IndexArray.Layout(); + VertexArrayIterator index = m_IndexArray.GetIterator(); + for (size_t i = 0; i < m_IndexArray.GetNumberOfVertices(); ++i) + *index++ = 0; + m_IndexArray.Upload(); + + VertexArrayIterator attrPos = m_AttributePos.GetIterator(); + VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); + for (size_t i = 0; i < m_VertexArray.GetNumberOfVertices(); ++i) + { + (*attrColor)[0] = 0; + (*attrColor)[1] = 0; + (*attrColor)[2] = 0; + (*attrColor)[3] = 0; + ++attrColor; + + (*attrPos)[0] = -10000.0f; + (*attrPos)[1] = -10000.0f; + + ++attrPos; + } + m_VertexArray.Upload(); + + if (g_VideoMode.GetBackendDevice()->GetCapabilities().instancing) + { + m_UseInstancing = true; + + const size_t numberOfCircleSegments = 8; + + m_InstanceAttributePosition.format = Renderer::Backend::Format::R32G32_SFLOAT; + m_InstanceVertexArray.AddAttribute(&m_InstanceAttributePosition); + + m_InstanceVertexArray.SetNumberOfVertices(numberOfCircleSegments * 3); + m_InstanceVertexArray.Layout(); + + VertexArrayIterator attributePosition = + m_InstanceAttributePosition.GetIterator(); + for (size_t segment = 0; segment < numberOfCircleSegments; ++segment) + { + const float currentAngle = static_cast(segment) / numberOfCircleSegments * 2.0f * M_PI; + const float nextAngle = static_cast(segment + 1) / numberOfCircleSegments * 2.0f * M_PI; + + (*attributePosition)[0] = 0.0f; + (*attributePosition)[1] = 0.0f; + ++attributePosition; + + (*attributePosition)[0] = std::cos(currentAngle); + (*attributePosition)[1] = std::sin(currentAngle); + ++attributePosition; + + (*attributePosition)[0] = std::cos(nextAngle); + (*attributePosition)[1] = std::sin(nextAngle); + ++attributePosition; + } + + m_InstanceVertexArray.Upload(); + m_InstanceVertexArray.FreeBackingStore(); + } } CMiniMapTexture::~CMiniMapTexture() @@ -68,78 +291,89 @@ void CMiniMapTexture::Update(const float UNUSED(deltaRealTime)) { - if (m_WaterHeight != g_Renderer.GetWaterManager()->m_WaterHeight) - m_Dirty = true; + if (m_WaterHeight != g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight) + { + m_TerrainTextureDirty = true; + m_FinalTextureDirty = true; + } } -void CMiniMapTexture::Render() +void CMiniMapTexture::Render(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - if (!m_Dirty) - return; - const CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); if (!terrain) return; - CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY); - ENSURE(cmpRangeManager); - - m_MapSize = terrain->GetVerticesPerSide(); - m_TextureSize = static_cast(round_up_to_pow2(static_cast(m_MapSize))); - if (!m_TerrainTexture) - CreateTextures(); + CreateTextures(deviceCommandContext, terrain); - RebuildTerrainTexture(terrain); + if (m_TerrainTextureDirty) + RebuildTerrainTexture(deviceCommandContext, terrain); + + RenderFinalTexture(deviceCommandContext); } -void CMiniMapTexture::CreateTextures() +void CMiniMapTexture::CreateTextures( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CTerrain* terrain) { DestroyTextures(); + m_MapSize = terrain->GetVerticesPerSide(); + const size_t textureSize = round_up_to_pow2(static_cast(m_MapSize)); + + const Renderer::Backend::Sampler::Desc defaultSamplerDesc = + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + + Renderer::Backend::IDevice* backendDevice = deviceCommandContext->GetDevice(); + // Create terrain texture - glGenTextures(1, &m_TerrainTexture); - g_Renderer.BindTexture(0, m_TerrainTexture); + m_TerrainTexture = backendDevice->CreateTexture2D("MiniMapTerrainTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, textureSize, textureSize, defaultSamplerDesc); // Initialise texture with solid black, for the areas we don't - // overwrite with glTexSubImage2D later - u32* texData = new u32[m_TextureSize * m_TextureSize]; - for (ssize_t i = 0; i < m_TextureSize * m_TextureSize; ++i) + // overwrite with uploading later. + std::unique_ptr texData = std::make_unique(textureSize * textureSize); + for (size_t i = 0; i < textureSize * textureSize; ++i) texData[i] = 0xFF000000; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); - delete[] texData; - - m_TerrainData = new u32[(m_MapSize - 1) * (m_MapSize - 1)]; - 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_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + deviceCommandContext->UploadTexture( + m_TerrainTexture.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + texData.get(), textureSize * textureSize * 4); + texData.reset(); + + m_TerrainData = std::make_unique((m_MapSize - 1) * (m_MapSize - 1)); + + m_FinalTexture = backendDevice->CreateTexture2D("MiniMapFinalTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE, defaultSamplerDesc); + + m_FinalTextureFramebuffer = backendDevice->CreateFramebuffer("MiniMapFinalFramebuffer", + m_FinalTexture.get(), nullptr); + ENSURE(m_FinalTextureFramebuffer); } void CMiniMapTexture::DestroyTextures() { - if (m_TerrainTexture) - { - glDeleteTextures(1, &m_TerrainTexture); - m_TerrainTexture = 0; - } - - SAFE_ARRAY_DELETE(m_TerrainData); + m_TerrainTexture.reset(); + m_FinalTexture.reset(); + m_TerrainData.reset(); } -void CMiniMapTexture::RebuildTerrainTexture(const CTerrain* terrain) +void CMiniMapTexture::RebuildTerrainTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CTerrain* terrain) { const u32 x = 0; const u32 y = 0; const u32 width = m_MapSize - 1; const u32 height = m_MapSize - 1; - m_WaterHeight = g_Renderer.GetWaterManager()->m_WaterHeight; - m_Dirty = false; + m_WaterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight; + m_TerrainTextureDirty = false; for (u32 j = 0; j < height; ++j) { - u32* dataPtr = m_TerrainData + ((y + j) * width) + x; + u32* dataPtr = m_TerrainData.get() + ((y + j) * width) + x; for (u32 i = 0; i < width; ++i) { const float avgHeight = ( terrain->GetVertexGroundLevel((int)i, (int)j) @@ -173,8 +407,8 @@ { // If the texture can't be loaded yet, set the dirty flags // so we'll try regenerating the terrain texture again soon - if(!tex->GetTexture()->TryLoad()) - m_Dirty = true; + if (!tex->GetTexture()->TryLoad()) + m_TerrainTextureDirty = true; color = tex->GetBaseColor(); } @@ -186,9 +420,385 @@ } // Upload the texture - g_Renderer.BindTexture(0, m_TerrainTexture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, m_TerrainData); - g_Renderer.BindTexture(0, 0); + deviceCommandContext->UploadTextureRegion( + m_TerrainTexture.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + m_TerrainData.get(), width * height * 4, 0, 0, width, height); +} + +void CMiniMapTexture::RenderFinalTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + // only update 2x / second + // (note: since units only move a few pixels per second on the minimap, + // we can get away with infrequent updates; this is slow) + // TODO: Update all but camera at same speed as simulation + const double currentTime = timer_Time(); + const bool doUpdate = (currentTime - m_LastFinalTextureUpdate > 0.5) || m_FinalTextureDirty; + if (doUpdate) + m_LastFinalTextureUpdate = currentTime; + else + return; + m_FinalTextureDirty = false; + + PROFILE3("Render minimap texture"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render minimap texture"); + deviceCommandContext->SetFramebuffer(m_FinalTextureFramebuffer.get()); + + const SViewPort oldViewPort = g_Renderer.GetViewport(); + const SViewPort viewPort = { 0, 0, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE }; + g_Renderer.SetViewport(viewPort); + + CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY); + ENSURE(cmpRangeManager); + CLOSTexture& losTexture = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); + + const float invTileMapSize = 1.0f / static_cast(TERRAIN_TILE_SIZE * m_MapSize); + const float texCoordMax = m_TerrainTexture ? static_cast(m_MapSize - 1) / m_TerrainTexture->GetWidth() : 1.0f; + + Renderer::Backend::IShaderProgram* shader = nullptr; + CShaderTechniquePtr tech; + + CShaderDefines baseDefines; + baseDefines.Add(str_MINIMAP_BASE, str_1); + + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + tech->GetGraphicsPipelineStateDesc(); + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + shader = tech->GetShader(); + + if (m_TerrainTexture) + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), m_TerrainTexture.get()); + } + + CMatrix3D baseTransform; + baseTransform.SetIdentity(); + CMatrix3D baseTextureTransform; + baseTextureTransform.SetIdentity(); + + CMatrix3D terrainTransform; + terrainTransform.SetIdentity(); + terrainTransform.Scale(texCoordMax, texCoordMax, 1.0f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), terrainTransform.AsFloatArray()); + + if (m_TerrainTexture) + DrawTexture(deviceCommandContext); + deviceCommandContext->EndPass(); + + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + pipelineStateDesc.blendState.colorWriteMask = + Renderer::Backend::ColorWriteMask::RED | + Renderer::Backend::ColorWriteMask::GREEN | + Renderer::Backend::ColorWriteMask::BLUE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + // Draw territory boundaries + CTerritoryTexture& territoryTexture = + g_Renderer.GetSceneRenderer().GetScene().GetTerritoryTexture(); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), territoryTexture.GetTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), + territoryTexture.GetMinimapTextureMatrix().AsFloatArray()); + + DrawTexture(deviceCommandContext); + deviceCommandContext->EndPass(); + + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap_los, CShaderDefines()); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + shader = tech->GetShader(); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), losTexture.GetTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), + losTexture.GetMinimapTextureMatrix().AsFloatArray()); + + DrawTexture(deviceCommandContext); + + deviceCommandContext->EndPass(); + + // We might scale entities properly in the vertex shader but it requires + // additional space in the vertex buffer. So we assume that we don't need + // to change an entity size so often. + // Radius with instancing is lower because an entity has a more round shape. + const float entityRadius = static_cast(m_MapSize) / 128.0f * (m_UseInstancing ? 5.0 : 6.0f); + + if (doUpdate) + { + m_Icons.clear(); + m_IconsCache.clear(); + + CSimulation2::InterfaceList ents = m_Simulation.GetEntitiesWithInterface(IID_Minimap); + + VertexArrayIterator attrPos = m_AttributePos.GetIterator(); + VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); + + m_EntitiesDrawn = 0; + MinimapUnitVertex v; + std::vector pingingVertices; + pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); + + if (currentTime > m_NextBlinkTime) + { + m_BlinkState = !m_BlinkState; + m_NextBlinkTime = currentTime + m_HalfBlinkDuration; + } + + bool iconsEnabled = false; + CFG_GET_VAL("gui.session.minimap.icons.enabled", iconsEnabled); + float iconsOpacity = 1.0f; + CFG_GET_VAL("gui.session.minimap.icons.opacity", iconsOpacity); + float iconsSizeScale = 1.0f; + CFG_GET_VAL("gui.session.minimap.icons.sizescale", iconsSizeScale); + + bool iconsCountOverflow = false; + + entity_pos_t posX, posZ; + for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) + { + ICmpMinimap* cmpMinimap = static_cast(it->second); + if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) + { + LosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, m_Simulation.GetSimContext().GetCurrentDisplayedPlayer()); + if (vis != LosVisibility::HIDDEN) + { + v.a = 255; + v.position.X = posX.ToFloat(); + v.position.Y = posZ.ToFloat(); + + // Check minimap pinging to indicate something + if (m_BlinkState && cmpMinimap->CheckPing(currentTime, m_PingDuration)) + { + v.r = 255; // ping color is white + v.g = 255; + v.b = 255; + pingingVertices.push_back(v); + } + else + { + AddEntity(v, attrColor, attrPos, entityRadius, m_UseInstancing); + ++m_EntitiesDrawn; + } + + if (!iconsEnabled || !cmpMinimap->HasIcon()) + continue; + + const CellIconKey key{ + cmpMinimap->GetIconPath(), v.r, v.g, v.b}; + const u16 gridX = Clamp( + (v.position.X * invTileMapSize) * ICON_COMBINING_GRID_SIZE, 0, ICON_COMBINING_GRID_SIZE - 1); + const u16 gridY = Clamp( + (v.position.Y * invTileMapSize) * ICON_COMBINING_GRID_SIZE, 0, ICON_COMBINING_GRID_SIZE - 1); + CellIcon icon{ + gridX, gridY, cmpMinimap->GetIconSize() * iconsSizeScale * 0.5f, v.position}; + if (m_IconsCache.find(key) == m_IconsCache.end() && m_IconsCache.size() >= MAX_UNIQUE_ICON_COUNT) + { + iconsCountOverflow = true; + } + else + { + m_IconsCache[key].emplace_back(std::move(icon)); + } + } + } + } + + // We need to combine too close icons with the same path, we use a grid for + // that. But to save some allocations and space we store only the current + // row. + struct Cell + { + u32 count; + float maxHalfSize; + CVector2D averagePosition; + }; + std::array gridRow; + for (auto& [key, icons] : m_IconsCache) + { + CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture( + CTextureProperties(key.path)); + const CColor color(key.r / 255.0f, key.g / 255.0f, key.b / 255.0f, iconsOpacity); + + std::sort(icons.begin(), icons.end(), + [](const CellIcon& lhs, const CellIcon& rhs) -> bool + { + if (lhs.gridY != rhs.gridY) + return lhs.gridY < rhs.gridY; + return lhs.gridX < rhs.gridX; + }); + + for (auto beginIt = icons.begin(); beginIt != icons.end();) + { + auto endIt = std::next(beginIt); + while (endIt != icons.end() && beginIt->gridY == endIt->gridY) + ++endIt; + gridRow.fill({0, 0.0f, {}}); + for (; beginIt != endIt; ++beginIt) + { + Cell& cell = gridRow[beginIt->gridX]; + const float previousPositionWeight = static_cast(cell.count) / (cell.count + 1); + cell.averagePosition = cell.averagePosition * previousPositionWeight + beginIt->worldPosition / static_cast(cell.count + 1); + cell.maxHalfSize = std::max(cell.maxHalfSize, beginIt->halfSize); + ++cell.count; + } + for (const Cell& cell : gridRow) + { + if (cell.count == 0) + continue; + + if (m_Icons.size() < MAX_ICON_COUNT) + { + m_Icons.emplace_back(Icon{ + texture, color, cell.averagePosition, cell.maxHalfSize}); + } + else + iconsCountOverflow = true; + } + } + } + + if (iconsCountOverflow) + LOGWARNING("Too many minimap icons to draw."); + + // Add the pinged vertices at the end, so they are drawn on top + for (const MinimapUnitVertex& vertex : pingingVertices) + { + AddEntity(vertex, attrColor, attrPos, entityRadius, m_UseInstancing); + ++m_EntitiesDrawn; + } + + ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); + + if (!m_UseInstancing) + { + VertexArrayIterator index = m_IndexArray.GetIterator(); + for (size_t entityIndex = 0; entityIndex < m_EntitiesDrawn; ++entityIndex) + { + index[entityIndex * 6 + 0] = static_cast(entityIndex * 4 + 0); + index[entityIndex * 6 + 1] = static_cast(entityIndex * 4 + 1); + index[entityIndex * 6 + 2] = static_cast(entityIndex * 4 + 2); + index[entityIndex * 6 + 3] = static_cast(entityIndex * 4 + 0); + index[entityIndex * 6 + 4] = static_cast(entityIndex * 4 + 2); + index[entityIndex * 6 + 5] = static_cast(entityIndex * 4 + 3); + } + + m_IndexArray.Upload(); + } + + m_VertexArray.Upload(); + } + + m_VertexArray.PrepareForRendering(); + + if (m_EntitiesDrawn > 0) + { + CShaderDefines pointDefines; + pointDefines.Add(str_MINIMAP_POINT, str_1); + if (m_UseInstancing) + pointDefines.Add(str_USE_GPU_INSTANCING, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, pointDefines); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + shader = tech->GetShader(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + + CMatrix3D unitMatrix; + unitMatrix.SetIdentity(); + // Convert world space coordinates into [0, 2]. + const float unitScale = invTileMapSize; + unitMatrix.Scale(unitScale * 2.0f, unitScale * 2.0f, 1.0f); + // Offset the coordinates to [-1, 1]. + unitMatrix.Translate(CVector3D(-1.0f, -1.0f, 0.0f)); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), unitMatrix.AsFloatArray()); + + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = scissorRect.y = 1; + scissorRect.width = scissorRect.height = FINAL_TEXTURE_SIZE - 2; + deviceCommandContext->SetScissors(1, &scissorRect); + + m_VertexArray.UploadIfNeeded(deviceCommandContext); + + const uint32_t stride = m_VertexArray.GetStride(); + const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; + + if (m_UseInstancing) + { + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, + m_InstanceVertexArray.GetOffset() + m_InstanceAttributePosition.offset, + m_InstanceVertexArray.GetStride(), + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1); + + deviceCommandContext->SetVertexBuffer(0, m_InstanceVertexArray.GetBuffer()); + deviceCommandContext->SetVertexBuffer(1, m_VertexArray.GetBuffer()); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_width), entityRadius); + + deviceCommandContext->DrawInstanced(0, m_InstanceVertexArray.GetNumberOfVertices(), 0, m_EntitiesDrawn); + } + else + { + m_IndexArray.UploadIfNeeded(deviceCommandContext); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); + deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); + + deviceCommandContext->DrawIndexed(m_IndexArray.GetOffset(), m_EntitiesDrawn * 6, 0); + } + + g_Renderer.GetStats().m_DrawCalls++; + + deviceCommandContext->SetScissors(0, nullptr); + + deviceCommandContext->EndPass(); + } + + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + g_Renderer.SetViewport(oldViewPort); } // static diff -Nru 0ad-0.0.25b/source/graphics/MiniMapTexture.h 0ad-0.0.26/source/graphics/MiniMapTexture.h --- 0ad-0.0.25b/source/graphics/MiniMapTexture.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MiniMapTexture.h 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,17 @@ #ifndef INCLUDED_MINIMAPTEXTURE #define INCLUDED_MINIMAPTEXTURE -#include "lib/ogl.h" +#include "graphics/Color.h" +#include "graphics/Texture.h" +#include "maths/Vector2D.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/ITexture.h" +#include "renderer/VertexArray.h" + +#include +#include +#include +#include class CSimulation2; class CTerrain; @@ -38,41 +48,100 @@ /** * Redraws the texture if it's dirty. */ - void Render(); + void Render(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); - GLuint GetTerrainTexture() const { return m_TerrainTexture; } - - GLsizei GetTerrainTextureSize() const { return m_TextureSize; } + Renderer::Backend::ITexture* GetTexture() const { return m_FinalTexture.get(); } /** * @return The maximum height for unit passage in water. */ static float GetShallowPassageHeight(); + struct Icon + { + CTexturePtr texture; + CColor color; + CVector2D worldPosition; + float halfSize; + }; + // Returns icons for corresponding entities on the minimap texture. + const std::vector& GetIcons() { return m_Icons; } + private: - void CreateTextures(); + void CreateTextures( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CTerrain* terrain); void DestroyTextures(); - void RebuildTerrainTexture(const CTerrain* terrain); + void RebuildTerrainTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CTerrain* terrain); + void RenderFinalTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); CSimulation2& m_Simulation; - bool m_Dirty = true; + bool m_TerrainTextureDirty = true; + bool m_FinalTextureDirty = true; + double m_LastFinalTextureUpdate = 0.0; // minimap texture handles - GLuint m_TerrainTexture = 0; + std::unique_ptr + m_TerrainTexture, m_FinalTexture; + + std::unique_ptr + m_FinalTextureFramebuffer; // texture data - u32* m_TerrainData = nullptr; + std::unique_ptr m_TerrainData; // map size ssize_t m_MapSize = 0; - // texture size - GLsizei m_TextureSize = 0; - // Maximal water height to allow the passage of a unit (for underwater shallows). float m_ShallowPassageHeight = 0.0f; float m_WaterHeight = 0.0f; + + VertexIndexArray m_IndexArray; + VertexArray m_VertexArray; + VertexArray::Attribute m_AttributePos; + VertexArray::Attribute m_AttributeColor; + + bool m_UseInstancing = false; + // Vertex data if instancing is supported. + VertexArray m_InstanceVertexArray; + VertexArray::Attribute m_InstanceAttributePosition; + + size_t m_EntitiesDrawn = 0; + + double m_PingDuration = 25.0; + double m_HalfBlinkDuration = 0.0; + double m_NextBlinkTime = 0.0; + bool m_BlinkState = false; + + std::vector m_Icons; + // We store the map as a member to avoid redundant reallocations on each + // update. We use a grid approach to combine icons by distance. + struct CellIconKey + { + std::string path; + u8 r, g, b; + }; + struct CellIconKeyHash + { + size_t operator()(const CellIconKey& key) const; + }; + struct CellIconKeyEqual + { + bool operator()(const CellIconKey& lhs, const CellIconKey& rhs) const; + }; + struct CellIcon + { + // TODO: use CVector2DI. + u16 gridX, gridY; + float halfSize; + CVector2D worldPosition; + }; + std::unordered_map, CellIconKeyHash, CellIconKeyEqual> m_IconsCache; }; #endif // INCLUDED_MINIMAPTEXTURE diff -Nru 0ad-0.0.25b/source/graphics/MiniPatch.h 0ad-0.0.26/source/graphics/MiniPatch.h --- 0ad-0.0.25b/source/graphics/MiniPatch.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/MiniPatch.h 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,11 +22,8 @@ #ifndef INCLUDED_MINIPATCH #define INCLUDED_MINIPATCH -#include "lib/res/handle.h" - class CTerrainTextureEntry; -/////////////////////////////////////////////////////////////////////////////// // CMiniPatch: definition of a single terrain tile class CMiniPatch { @@ -43,5 +40,4 @@ int GetPriority() { return Priority; } }; - -#endif +#endif // INCLUDED_MINIPATCH diff -Nru 0ad-0.0.25b/source/graphics/ModelAbstract.h 0ad-0.0.26/source/graphics/ModelAbstract.h --- 0ad-0.0.25b/source/graphics/ModelAbstract.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ModelAbstract.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -89,9 +89,6 @@ // and this seems the easiest way to integrate with other code that wants // type-specific processing) - /// Calls SetDirty on this model and all child objects. - virtual void SetDirtyRec(int dirtyflags) = 0; - /// Returns world space bounds of this object and all child objects. virtual const CBoundingBoxAligned GetWorldBoundsRec() { return GetWorldBounds(); } // default implementation @@ -159,7 +156,7 @@ virtual player_id_t GetPlayerID() const { return m_PlayerID; } virtual void SetShadingColor(const CColor& color) { m_ShadingColor = color; } - virtual CColor GetShadingColor() const { return m_ShadingColor; } + virtual const CColor& GetShadingColor() const { return m_ShadingColor; } protected: void CalcSelectionBox(); diff -Nru 0ad-0.0.25b/source/graphics/Model.cpp 0ad-0.0.26/source/graphics/Model.cpp --- 0ad-0.0.25b/source/graphics/Model.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Model.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,41 +15,33 @@ * along with 0 A.D. If not, see . */ -/* - * Mesh object with texture and skinning information - */ - #include "precompiled.h" #include "Model.h" -#include "Decal.h" -#include "ModelDef.h" -#include "maths/Quaternion.h" +#include "graphics/Decal.h" +#include "graphics/MeshManager.h" +#include "graphics/ModelDef.h" +#include "graphics/ObjectEntry.h" +#include "graphics/SkeletonAnim.h" +#include "graphics/SkeletonAnimDef.h" #include "maths/BoundingBoxAligned.h" -#include "SkeletonAnim.h" -#include "SkeletonAnimDef.h" -#include "SkeletonAnimManager.h" -#include "MeshManager.h" -#include "ObjectEntry.h" -#include "lib/res/graphics/ogl_tex.h" -#include "lib/res/h_mgr.h" +#include "maths/Quaternion.h" #include "lib/sysdep/rtl.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" #include "ps/Profile.h" #include "renderer/RenderingOptions.h" -#include "simulation2/Simulation2.h" #include "simulation2/components/ICmpTerrain.h" #include "simulation2/components/ICmpWaterManager.h" +#include "simulation2/Simulation2.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Constructor -CModel::CModel(CSkeletonAnimManager& skeletonAnimManager, CSimulation2& simulation) +CModel::CModel(CSimulation2& simulation) : m_Flags(0), m_Anim(NULL), m_AnimTime(0), m_Simulation(simulation), - m_BoneMatrices(NULL), m_AmmoPropPoint(NULL), m_AmmoLoadedProp(0), - m_SkeletonAnimManager(skeletonAnimManager) + m_BoneMatrices(NULL), m_AmmoPropPoint(NULL), m_AmmoLoadedProp(0) { } @@ -205,43 +197,6 @@ } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// BuildAnimation: load raw animation frame animation from given file, and build a -// animation specific to this model -CSkeletonAnim* CModel::BuildAnimation(const VfsPath& pathname, const CStr& name, const CStr& ID, int frequency, float speed, float actionpos, float actionpos2, float soundpos) -{ - CSkeletonAnimDef* def = m_SkeletonAnimManager.GetAnimation(pathname); - if (!def) - return NULL; - - CSkeletonAnim* anim = new CSkeletonAnim(); - anim->m_Name = name; - anim->m_ID = ID; - anim->m_Frequency = frequency; - anim->m_AnimDef = def; - anim->m_Speed = speed; - - if (actionpos == -1.f) - anim->m_ActionPos = -1.f; - else - anim->m_ActionPos = actionpos * anim->m_AnimDef->GetDuration(); - - if (actionpos2 == -1.f) - anim->m_ActionPos2 = -1.f; - else - anim->m_ActionPos2 = actionpos2 * anim->m_AnimDef->GetDuration(); - - if (soundpos == -1.f) - anim->m_SoundPos = -1.f; - else - anim->m_SoundPos = soundpos * anim->m_AnimDef->GetDuration(); - - anim->m_ObjectBounds.SetEmpty(); - InvalidateBounds(); - - return anim; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Update: update this model to the given time, in msec void CModel::UpdateTo(float time) { @@ -539,7 +494,7 @@ // Clone: return a clone of this model CModelAbstract* CModel::Clone() const { - CModel* clone = new CModel(m_SkeletonAnimManager, m_Simulation); + CModel* clone = new CModel(m_Simulation); clone->m_ObjectBounds = m_ObjectBounds; clone->InitModel(m_pModelDef); clone->SetMaterial(m_Material); @@ -575,10 +530,7 @@ m_Flags |= flags; if (flags & MODELFLAG_IGNORE_LOS) - { m_Material.AddShaderDefine(str_IGNORE_LOS, str_1); - m_Material.RecomputeCombinedShaderDefines(); - } for (size_t i = 0; i < m_Props.size(); ++i) if (m_Props[i].m_Model->ToCModel()) @@ -590,7 +542,6 @@ m_Flags &= ~MODELFLAG_CASTSHADOWS; m_Material.AddShaderDefine(str_DISABLE_RECEIVE_SHADOWS, str_1); - m_Material.RecomputeCombinedShaderDefines(); for (size_t i = 0; i < m_Props.size(); ++i) { diff -Nru 0ad-0.0.25b/source/graphics/ModelDef.cpp 0ad-0.0.26/source/graphics/ModelDef.cpp --- 0ad-0.0.25b/source/graphics/ModelDef.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ModelDef.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,17 +15,14 @@ * along with 0 A.D. If not, see . */ -/* - * Defines a raw 3d model. - */ - #include "precompiled.h" #include "ModelDef.h" + #include "graphics/SkeletonAnimDef.h" #include "lib/sysdep/arch/x86_x64/simd.h" -#include "ps/FileIo.h" #include "maths/Vector4D.h" +#include "ps/FileIo.h" #if COMPILER_HAS_SSE # include @@ -203,10 +200,11 @@ const CMatrix3D& mtx = newPoseMatrices[blendIndices[j]]; // Loads matrix to xmm registers. - col0 = _mm_load_ps(mtx._data); - col1 = _mm_load_ps(mtx._data + 4); - col2 = _mm_load_ps(mtx._data + 8); - col3 = _mm_load_ps(mtx._data + 12); + const float* data = mtx.AsFloatArray().data(); + col0 = _mm_load_ps(data); + col1 = _mm_load_ps(data + 4); + col2 = _mm_load_ps(data + 8); + col3 = _mm_load_ps(data + 12); // Loads and computes vertex coordinates. vec0 = _mm_load1_ps(&vtx.m_Coords.X); // v0 = [x, x, x, x] @@ -338,7 +336,8 @@ mdef->m_NumUVsPerVertex = unpacker.UnpackSize(); } - mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices]; + mdef->m_pVertices = new SModelVertex[mdef->m_NumVertices]; + mdef->m_UVCoordinates.reserve(mdef->m_NumVertices * mdef->m_NumUVsPerVertex); for (size_t i = 0; i < mdef->m_NumVertices; ++i) { @@ -349,8 +348,7 @@ { float uv[2]; unpacker.UnpackRaw(&uv[0], 8); - mdef->m_pVertices[i].m_UVs.push_back(uv[0]); - mdef->m_pVertices[i].m_UVs.push_back(uv[1]); + mdef->m_UVCoordinates.emplace_back(uv[0], uv[1]); } unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Blend, sizeof(SVertexBlend)); diff -Nru 0ad-0.0.25b/source/graphics/ModelDef.h 0ad-0.0.26/source/graphics/ModelDef.h --- 0ad-0.0.25b/source/graphics/ModelDef.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ModelDef.h 2022-08-21 12:45:23.000000000 +0000 @@ -25,6 +25,7 @@ #include "maths/BoundingBoxAligned.h" #include "maths/Matrix3D.h" #include "maths/Quaternion.h" +#include "maths/Vector2D.h" #include "maths/Vector3D.h" #include "lib/file/vfs/vfs_path.h" #include "ps/CStr.h" @@ -33,6 +34,7 @@ #include #include #include +#include class CBoneState; class CSkeletonAnimDef; @@ -108,8 +110,6 @@ CVector3D m_Coords; // vertex normal CVector3D m_Norm; - // vertex UVs - std::vector m_UVs; // vertex blend data SVertexBlend m_Blend; }; @@ -173,6 +173,8 @@ // accessor: get number of UV sets size_t GetNumUVsPerVertex() const { return m_NumUVsPerVertex; } + const std::vector& GetUVCoordinates() const { return m_UVCoordinates; } + // accessor: get face data size_t GetNumFaces() const { return m_NumFaces; } SModelFace* GetFaces() const { return m_pFaces; } @@ -256,6 +258,7 @@ // vertex data size_t m_NumVertices; SModelVertex* m_pVertices; + std::vector m_UVCoordinates; size_t m_NumUVsPerVertex; // number of UV pairs per vertex // face data size_t m_NumFaces; diff -Nru 0ad-0.0.25b/source/graphics/ModelDummy.h 0ad-0.0.26/source/graphics/ModelDummy.h --- 0ad-0.0.25b/source/graphics/ModelDummy.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ModelDummy.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,7 +36,6 @@ virtual CModelDummy* ToCModelDummy() { return this; } virtual void CalcBounds() {}; - virtual void SetDirtyRec(int) {}; virtual void SetTerrainDirty(ssize_t, ssize_t, ssize_t, ssize_t) {} virtual void ValidatePosition() {}; virtual void InvalidatePosition() {}; diff -Nru 0ad-0.0.25b/source/graphics/Model.h 0ad-0.0.26/source/graphics/Model.h --- 0ad-0.0.25b/source/graphics/Model.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Model.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,7 +32,6 @@ class CObjectEntry; class CSkeletonAnim; class CSkeletonAnimDef; -class CSkeletonAnimManager; class CSimulation2; #define MODELFLAG_CASTSHADOWS (1<<0) @@ -77,7 +76,7 @@ public: // constructor - CModel(CSkeletonAnimManager& skeletonAnimManager, CSimulation2& simulation); + CModel(CSimulation2& simulation); // destructor ~CModel(); @@ -125,14 +124,6 @@ // TODO: replace with more generic shader define + flags setting void RemoveShadowsRec(); - // recurse down tree setting dirty bits - virtual void SetDirtyRec(int dirtyflags) { - SetDirty(dirtyflags); - for (size_t i=0;iSetDirtyRec(dirtyflags); - } - } - virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1) { for (size_t i = 0; i < m_Props.size(); ++i) @@ -196,21 +187,6 @@ } /** - * Load raw animation frame animation from given file, and build an - * animation specific to this model. - * @param pathname animation file to load - * @param name animation name (e.g. "idle") - * @param ID specific ID of the animation, to sync with props - * @param frequency influences the random choices - * @param speed animation speed as a factor of the default animation speed - * @param actionpos offset of 'action' event, in range [0, 1] - * @param actionpos2 offset of 'action2' event, in range [0, 1] - * @param sound offset of 'sound' event, in range [0, 1] - * @return new animation, or NULL on error - */ - CSkeletonAnim* BuildAnimation(const VfsPath& pathname, const CStr& name, const CStr& ID, int frequency, float speed, float actionpos, float actionpos2, float soundpos); - - /** * Add a prop to the model on the given point. */ void AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry, float minHeight = 0.f, float maxHeight = 0.f, bool selectable = true); @@ -298,9 +274,6 @@ * If m_AmmoPropPoint is not NULL, then the index in m_Props of the ammo prop */ size_t m_AmmoLoadedProp; - - // manager object which can load animations for us - CSkeletonAnimManager& m_SkeletonAnimManager; }; #endif diff -Nru 0ad-0.0.25b/source/graphics/ObjectBase.cpp 0ad-0.0.26/source/graphics/ObjectBase.cpp --- 0ad-0.0.25b/source/graphics/ObjectBase.cpp 2021-08-03 17:15:03.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ObjectBase.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -942,10 +942,10 @@ // Open up an external file to load. // Don't crash hard when failures happen, but log them and continue CXeromyces XeroActor; - if (XeroActor.Load(g_VFS, "art/actors/" + file, "actor") == PSRETURN_OK) + if (XeroActor.Load(g_VFS, VfsPath("art/actors/") / file, "actor") == PSRETURN_OK) { const XMBElement& root = XeroActor.GetRoot(); - if (root.GetNodeName() != el_actor) + if (root.GetNodeName() == XeroActor.GetElementID("qualitylevels")) { LOGERROR("Included actors cannot define quality levels (opening %s from file %s)", file, pathname.string8()); return false; diff -Nru 0ad-0.0.25b/source/graphics/ObjectBase.h 0ad-0.0.26/source/graphics/ObjectBase.h --- 0ad-0.0.25b/source/graphics/ObjectBase.h 2021-08-03 17:15:03.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ObjectBase.h 2022-08-21 12:45:23.000000000 +0000 @@ -23,10 +23,8 @@ #include "ps/CStrIntern.h" class CActorDef; -class CModel; class CObjectEntry; class CObjectManager; -class CSkeletonAnim; class CXeromyces; class XMBElement; diff -Nru 0ad-0.0.25b/source/graphics/ObjectEntry.cpp 0ad-0.0.26/source/graphics/ObjectEntry.cpp --- 0ad-0.0.25b/source/graphics/ObjectEntry.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ObjectEntry.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,12 +30,14 @@ #include "graphics/ObjectManager.h" #include "graphics/ParticleManager.h" #include "graphics/SkeletonAnim.h" +#include "graphics/SkeletonAnimManager.h" #include "graphics/TextureManager.h" #include "lib/rand.h" #include "ps/CLogger.h" #include "ps/Game.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "simulation2/Simulation2.h" #include @@ -47,9 +49,6 @@ CObjectEntry::~CObjectEntry() { - for (const std::pair& anim : m_Animations) - delete anim.second; - delete m_Model; } @@ -80,12 +79,12 @@ if (variation.decal.m_SizeX && variation.decal.m_SizeZ) { - CMaterial material = g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material); + CMaterial material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material); for (const CObjectBase::Samp& samp : m_Samplers) { CTextureProperties textureProps(samp.m_SamplerFile); - textureProps.SetWrap(GL_CLAMP_TO_BORDER); + textureProps.SetAddressMode(Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); // TODO: Should check which renderpath is selected and only preload the necessary textures. texture->Prefetch(); @@ -103,7 +102,7 @@ if (!variation.particles.empty()) { - m_Model = new CModelParticleEmitter(g_Renderer.GetParticleManager().LoadEmitterType(variation.particles)); + m_Model = new CModelParticleEmitter(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles)); return true; } @@ -129,10 +128,10 @@ } // delete old model, create new - CModel* model = new CModel(objectManager.GetSkeletonAnimManager(), m_Simulation); + CModel* model = new CModel(m_Simulation); delete m_Model; m_Model = model; - model->SetMaterial(g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material)); + model->SetMaterial(g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material)); model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a)); model->InitModel(modeldef); @@ -142,7 +141,7 @@ for (const CObjectBase::Samp& samp : m_Samplers) { CTextureProperties textureProps(samp.m_SamplerFile); - textureProps.SetWrap(GL_CLAMP_TO_EDGE); + textureProps.SetAddressMode(Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); // if we've loaded this model we're probably going to render it soon, so prefetch its texture. // All textures are prefetched even in the fixed pipeline, including the normal maps etc. @@ -168,7 +167,7 @@ if (it->second.m_FileName.empty()) continue; - CSkeletonAnim* anim = model->BuildAnimation( + std::unique_ptr anim = objectManager.GetSkeletonAnimManager().BuildAnimation( it->second.m_FileName, name, it->second.m_ID, @@ -178,13 +177,13 @@ it->second.m_ActionPos2, it->second.m_SoundPos); if (anim) - m_Animations.insert(std::make_pair(name, anim)); + m_Animations.emplace(name, std::move(anim)); } // ensure there's always an idle animation if (m_Animations.find("idle") == m_Animations.end()) { - CSkeletonAnim* anim = new CSkeletonAnim(); + std::unique_ptr anim = std::make_unique(); anim->m_Name = "idle"; anim->m_ID = ""; anim->m_AnimDef = NULL; @@ -193,10 +192,10 @@ anim->m_ActionPos = 0.f; anim->m_ActionPos2 = 0.f; anim->m_SoundPos = 0.f; - m_Animations.insert(std::make_pair("idle", anim)); + SkeletonAnimMap::const_iterator it = m_Animations.emplace("idle", std::move(anim)); // Ignore errors, since they're probably saying this is a non-animated model - model->SetAnimation(anim); + model->SetAnimation(it->second.get()); } else { @@ -301,7 +300,7 @@ for (SkeletonAnimMap::const_iterator it = lower; it != upper; ++it) { if (ID.empty() || it->second->m_ID == ID) - anims.push_back(it->second); + anims.push_back(it->second.get()); } if (anims.empty()) @@ -309,7 +308,7 @@ lower = m_Animations.lower_bound("idle"); upper = m_Animations.upper_bound("idle"); for (SkeletonAnimMap::const_iterator it = lower; it != upper; ++it) - anims.push_back(it->second); + anims.push_back(it->second.get()); } ENSURE(!anims.empty()); diff -Nru 0ad-0.0.25b/source/graphics/ObjectEntry.h 0ad-0.0.26/source/graphics/ObjectEntry.h --- 0ad-0.0.25b/source/graphics/ObjectEntry.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ObjectEntry.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,9 +23,9 @@ class CObjectBase; class CObjectManager; class CSimulation2; -struct SPropPoint; #include +#include #include #include @@ -84,7 +84,7 @@ CSimulation2& m_Simulation; - typedef std::multimap SkeletonAnimMap; + using SkeletonAnimMap = std::multimap>; SkeletonAnimMap m_Animations; // TODO: something more memory-efficient than storing loads of similar strings for each unit? }; diff -Nru 0ad-0.0.25b/source/graphics/Overlay.cpp 0ad-0.0.26/source/graphics/Overlay.cpp --- 0ad-0.0.25b/source/graphics/Overlay.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Overlay.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -43,12 +43,16 @@ void SOverlayTexturedLine::CreateOverlayTexture(const SOverlayDescriptor* overlayDescriptor) { CTextureProperties texturePropsBase(overlayDescriptor->m_LineTexture.c_str()); - texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsBase.SetMaxAnisotropy(4.f); + texturePropsBase.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsBase.SetAnisotropicFilter(true); CTextureProperties texturePropsMask(overlayDescriptor->m_LineTextureMask.c_str()); - texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsMask.SetMaxAnisotropy(4.f); + texturePropsMask.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsMask.SetAnisotropicFilter(true); m_AlwaysVisible = false; m_Closed = true; diff -Nru 0ad-0.0.25b/source/graphics/Overlay.h 0ad-0.0.26/source/graphics/Overlay.h --- 0ad-0.0.25b/source/graphics/Overlay.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Overlay.h 2022-08-21 12:45:25.000000000 +0000 @@ -27,7 +27,6 @@ #include class CFrustum; -class CTerrain; class CSimContext; class CTexturedLineRData; struct SOverlayDescriptor; diff -Nru 0ad-0.0.25b/source/graphics/ParticleEmitter.cpp 0ad-0.0.26/source/graphics/ParticleEmitter.cpp --- 0ad-0.0.25b/source/graphics/ParticleEmitter.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ParticleEmitter.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,14 +26,14 @@ #include "graphics/ShaderProgram.h" #include "graphics/TextureManager.h" #include "ps/CStrInternStatic.h" - #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) : m_Type(type), m_Active(true), m_NextParticleIdx(0), m_EmissionRoundingError(0.f), m_LastUpdateTime(type->m_Manager.GetCurrentTime()), - m_IndexArray(GL_STATIC_DRAW), - m_VertexArray(GL_DYNAMIC_DRAW), + m_IndexArray(false), + m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX, true), m_LastFrameNumber(-1) { // If we should start with particles fully emitted, pretend that we @@ -48,26 +48,22 @@ m_Particles.reserve(m_Type->m_MaxParticles); - m_AttributePos.type = GL_FLOAT; - m_AttributePos.elems = 3; + m_AttributePos.format = Renderer::Backend::Format::R32G32B32_SFLOAT; m_VertexArray.AddAttribute(&m_AttributePos); - m_AttributeAxis.type = GL_FLOAT; - m_AttributeAxis.elems = 2; + m_AttributeAxis.format = Renderer::Backend::Format::R32G32_SFLOAT; m_VertexArray.AddAttribute(&m_AttributeAxis); - m_AttributeUV.type = GL_FLOAT; - m_AttributeUV.elems = 2; + m_AttributeUV.format = Renderer::Backend::Format::R32G32_SFLOAT; m_VertexArray.AddAttribute(&m_AttributeUV); - m_AttributeColor.type = GL_UNSIGNED_BYTE; - m_AttributeColor.elems = 4; + m_AttributeColor.format = Renderer::Backend::Format::R8G8B8A8_UNORM; m_VertexArray.AddAttribute(&m_AttributeColor); - m_VertexArray.SetNumVertices(m_Type->m_MaxParticles * 4); + m_VertexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 4); m_VertexArray.Layout(); - m_IndexArray.SetNumVertices(m_Type->m_MaxParticles * 6); + m_IndexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 6); m_IndexArray.Layout(); VertexArrayIterator index = m_IndexArray.GetIterator(); for (u16 i = 0; i < m_Type->m_MaxParticles; ++i) @@ -154,7 +150,8 @@ // Special case: If the blending depends on the source color, not the source alpha, // then pre-multiply by the alpha. (This is kind of a hack.) - if (m_Type->m_BlendFuncDst == GL_ONE_MINUS_SRC_COLOR) + if (m_Type->m_BlendMode == CParticleEmitterType::BlendMode::OVERLAY || + m_Type->m_BlendMode == CParticleEmitterType::BlendMode::MULTIPLY) { color.R = (color.R * color.A) / 255; color.G = (color.G * color.A) / 255; @@ -177,45 +174,65 @@ m_VertexArray.PrepareForRendering(); } -void CParticleEmitter::Bind(const CShaderProgramPtr& shader) +void CParticleEmitter::Bind( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) { - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTextureSmooth()); - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); - shader->Uniform(str_sunColor, lightEnv.m_SunColor); - shader->Uniform(str_fogColor, lightEnv.m_FogColor); - shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); - - shader->BindTexture(str_baseTex, m_Type->m_Texture); - pglBlendEquationEXT(m_Type->m_BlendEquation); - glBlendFunc(m_Type->m_BlendFuncSrc, m_Type->m_BlendFuncDst); + m_Type->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); + + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); + + const CLightEnv& lightEnv = g_Renderer.GetSceneRenderer().GetLightEnv(); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunColor), lightEnv.m_SunColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogColor), lightEnv.m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogParams), lightEnv.m_FogFactor, lightEnv.m_FogMax); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), m_Type->m_Texture->GetBackendTexture()); } -void CParticleEmitter::RenderArray(const CShaderProgramPtr& shader) +void CParticleEmitter::RenderArray( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - // Some drivers apparently don't like count=0 in glDrawArrays here, - // so skip all drawing in that case if (m_Particles.empty()) return; - u8* indexBase = m_IndexArray.Bind(); - u8* base = m_VertexArray.Bind(); - - GLsizei stride = (GLsizei)m_VertexArray.GetStride(); + m_VertexArray.UploadIfNeeded(deviceCommandContext); + m_IndexArray.UploadIfNeeded(deviceCommandContext); - shader->VertexPointer(3, GL_FLOAT, stride, base + m_AttributePos.offset); + const uint32_t stride = m_VertexArray.GetStride(); + const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; - // Pass the sin/cos axis components as texcoords for no particular reason - // other than that they fit. (Maybe this should be glVertexAttrib* instead?) - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m_AttributeUV.offset); - shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, base + m_AttributeAxis.offset); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + m_AttributeUV.format, firstVertexOffset + m_AttributeUV.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + m_AttributeAxis.format, firstVertexOffset + m_AttributeAxis.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); + deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); + deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); - shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, (GLsizei)(m_Particles.size() * 6), GL_UNSIGNED_SHORT, indexBase); + deviceCommandContext->DrawIndexed(m_IndexArray.GetOffset(), m_Particles.size() * 6, 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_Particles += m_Particles.size(); diff -Nru 0ad-0.0.25b/source/graphics/ParticleEmitter.h 0ad-0.0.26/source/graphics/ParticleEmitter.h --- 0ad-0.0.25b/source/graphics/ParticleEmitter.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ParticleEmitter.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,8 @@ #include "graphics/ModelAbstract.h" #include "graphics/ParticleEmitterType.h" #include "maths/Quaternion.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/VertexArray.h" #include @@ -120,12 +122,15 @@ /** * Bind rendering state (textures and blend modes). */ - void Bind(const CShaderProgramPtr& shader); + void Bind( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader); /** * Draw the vertex array. */ - void RenderArray(const CShaderProgramPtr& shader); + void RenderArray( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Stop this emitter emitting new particles, and pass responsibility for rendering @@ -186,11 +191,6 @@ virtual CModelAbstract* Clone() const; - virtual void SetDirtyRec(int dirtyflags) - { - SetDirty(dirtyflags); - } - virtual void SetTerrainDirty(ssize_t UNUSED(i0), ssize_t UNUSED(j0), ssize_t UNUSED(i1), ssize_t UNUSED(j1)) { } diff -Nru 0ad-0.0.25b/source/graphics/ParticleEmitterType.cpp 0ad-0.0.26/source/graphics/ParticleEmitterType.cpp --- 0ad-0.0.25b/source/graphics/ParticleEmitterType.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ParticleEmitterType.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,7 +23,6 @@ #include "graphics/ParticleEmitter.h" #include "graphics/ParticleManager.h" #include "graphics/TextureManager.h" -#include "lib/rand.h" #include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" @@ -353,9 +352,7 @@ m_Variables[VAR_COLOR_R] = IParticleVarPtr(new CParticleVarConstant(1.f)); m_Variables[VAR_COLOR_G] = IParticleVarPtr(new CParticleVarConstant(1.f)); m_Variables[VAR_COLOR_B] = IParticleVarPtr(new CParticleVarConstant(1.f)); - m_BlendEquation = GL_FUNC_ADD; - m_BlendFuncSrc = GL_SRC_ALPHA; - m_BlendFuncDst = GL_ONE_MINUS_SRC_ALPHA; + m_BlendMode = BlendMode::ADD; m_StartFull = false; m_UseRelativeVelocity = false; m_Texture = g_Renderer.GetTextureManager().GetErrorTexture(); @@ -397,36 +394,21 @@ if (Child.GetNodeName() == el_texture) { CTextureProperties textureProps(Child.GetText().FromUTF8()); - textureProps.SetWrap(GL_CLAMP_TO_EDGE); + textureProps.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); } else if (Child.GetNodeName() == el_blend) { - CStr mode = Child.GetAttributes().GetNamedItem(at_mode); + const CStr mode = Child.GetAttributes().GetNamedItem(at_mode); if (mode == "add") - { - m_BlendEquation = GL_FUNC_ADD; - m_BlendFuncSrc = GL_SRC_ALPHA; - m_BlendFuncDst = GL_ONE; - } + m_BlendMode = BlendMode::ADD; else if (mode == "subtract") - { - m_BlendEquation = GL_FUNC_REVERSE_SUBTRACT; - m_BlendFuncSrc = GL_SRC_ALPHA; - m_BlendFuncDst = GL_ONE; - } + m_BlendMode = BlendMode::SUBTRACT; else if (mode == "over") - { - m_BlendEquation = GL_FUNC_ADD; - m_BlendFuncSrc = GL_SRC_ALPHA; - m_BlendFuncDst = GL_ONE_MINUS_SRC_ALPHA; - } + m_BlendMode = BlendMode::OVERLAY; else if (mode == "multiply") - { - m_BlendEquation = GL_FUNC_ADD; - m_BlendFuncSrc = GL_ZERO; - m_BlendFuncDst = GL_ONE_MINUS_SRC_COLOR; - } + m_BlendMode = BlendMode::MULTIPLY; } else if (Child.GetNodeName() == el_start_full) { diff -Nru 0ad-0.0.25b/source/graphics/ParticleEmitterType.h 0ad-0.0.26/source/graphics/ParticleEmitterType.h --- 0ad-0.0.25b/source/graphics/ParticleEmitterType.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ParticleEmitterType.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,10 +19,12 @@ #define INCLUDED_PARTICLEEMITTERTYPE #include "graphics/Texture.h" -#include "lib/ogl.h" #include "lib/file/vfs/vfs_path.h" #include "maths/BoundingBoxAligned.h" +#include +#include + class CVector3D; class CParticleEmitter; class CParticleManager; @@ -74,6 +76,14 @@ VAR__MAX }; + enum class BlendMode + { + ADD, + SUBTRACT, + OVERLAY, + MULTIPLY + }; + int GetVariableID(const std::string& name); bool LoadXML(const VfsPath& path); @@ -93,9 +103,7 @@ CTexturePtr m_Texture; - GLenum m_BlendEquation; - GLenum m_BlendFuncSrc; - GLenum m_BlendFuncDst; + BlendMode m_BlendMode = BlendMode::ADD; bool m_StartFull; bool m_UseRelativeVelocity; diff -Nru 0ad-0.0.25b/source/graphics/RenderableObject.h 0ad-0.0.26/source/graphics/RenderableObject.h --- 0ad-0.0.25b/source/graphics/RenderableObject.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/RenderableObject.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,7 +31,6 @@ // need updating #define RENDERDATA_UPDATE_VERTICES (1<<1) #define RENDERDATA_UPDATE_INDICES (1<<2) -#define RENDERDATA_UPDATE_COLOR (1<<4) /////////////////////////////////////////////////////////////////////////////// diff -Nru 0ad-0.0.25b/source/graphics/ShaderDefines.cpp 0ad-0.0.26/source/graphics/ShaderDefines.cpp --- 0ad-0.0.25b/source/graphics/ShaderDefines.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderDefines.cpp 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -89,7 +89,7 @@ // Sanity test: the items list is meant to be sorted by name. // This is a reasonable place to verify that, since this will be called once per distinct SItems. typedef ItemNameCmp Cmp; - ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate(Cmp())) == items.items.end()); + ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::not_fn(Cmp())) == items.items.end()); std::shared_ptr ptr = std::make_shared(items); s_InternedItems.insert(std::make_pair(items, ptr)); @@ -225,17 +225,15 @@ return CVector4D(); } -void CShaderUniforms::BindUniforms(const CShaderProgramPtr& shader) const -{ - const std::vector& items = m_Items->items; - for (size_t i = 0; i < items.size(); ++i) - { - CShaderProgram::Binding binding = shader->GetUniformBinding(items[i].first); - if (binding.Active()) - { - CVector4D v = items[i].second; - shader->Uniform(binding, v.X, v.Y, v.Z, v.W); - } +void CShaderUniforms::BindUniforms( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const +{ + for (const SItems::Item& item : m_Items->items) + { + const CVector4D& v = item.second; + deviceCommandContext->SetUniform( + shader->GetBindingSlot(item.first), v.AsFloatArray()); } } @@ -255,18 +253,6 @@ } } -void CShaderConditionalDefines::Add(const char* defname, const char* defvalue, int type, std::vector &args) -{ - CondDefine cd; - cd.m_DefName = CStrIntern(defname); - cd.m_DefValue = CStrIntern(defvalue); - cd.m_CondArgs = args; - cd.m_CondType = type; - - m_Defines.push_back(cd); -} - - // Explicit instantiations: template<> CShaderParams::InternedItems_t CShaderParams::s_InternedItems = CShaderParams::InternedItems_t(); diff -Nru 0ad-0.0.25b/source/graphics/ShaderDefines.h 0ad-0.0.26/source/graphics/ShaderDefines.h --- 0ad-0.0.25b/source/graphics/ShaderDefines.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderDefines.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,9 +18,10 @@ #ifndef INCLUDED_SHADERDEFINES #define INCLUDED_SHADERDEFINES -#include "graphics/ShaderProgramPtr.h" #include "ps/CStr.h" #include "ps/CStrIntern.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include #include @@ -178,7 +179,9 @@ /** * Bind the collection of uniforms onto the given shader. */ - void BindUniforms(const CShaderProgramPtr& shader) const; + void BindUniforms( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const; }; // Add here the types of queries we can make in the renderer @@ -206,29 +209,4 @@ std::vector m_Items; }; - -enum DEFINE_CONDITION_TYPES -{ - DCOND_DISTANCE -}; - -class CShaderConditionalDefines -{ -public: - struct CondDefine - { - CStrIntern m_DefName; - CStrIntern m_DefValue; - int m_CondType; - std::vector m_CondArgs; - }; - - void Add(const char* defname, const char* defvalue, int type, std::vector &args); - size_t GetSize() const { return m_Defines.size(); } - const CondDefine& GetItem(size_t i) const { return m_Defines[i]; } - -private: - std::vector m_Defines; -}; - #endif // INCLUDED_SHADERDEFINES diff -Nru 0ad-0.0.25b/source/graphics/ShaderManager.cpp 0ad-0.0.26/source/graphics/ShaderManager.cpp --- 0ad-0.0.25b/source/graphics/ShaderManager.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderManager.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,16 +30,20 @@ #include "ps/Filesystem.h" #include "ps/Profile.h" #include "ps/XML/Xeromyces.h" -#include "ps/XML/XMLWriter.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #define USE_SHADER_XML_VALIDATION 1 #if USE_SHADER_XML_VALIDATION -# include "ps/XML/RelaxNG.h" +#include "ps/XML/RelaxNG.h" +#include "ps/XML/XMLWriter.h" #endif +#include + TIMER_ADD_CLIENT(tc_ShaderValidation); CShaderManager::CShaderManager() @@ -62,310 +66,58 @@ UnregisterFileReloadFunc(ReloadChangedFileCB, this); } -CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const CShaderDefines& defines) +CShaderProgramPtr CShaderManager::LoadProgram(const CStr& name, const CShaderDefines& defines) { CacheKey key = { name, defines }; std::map::iterator it = m_ProgramCache.find(key); if (it != m_ProgramCache.end()) return it->second; - CShaderProgramPtr program; - if (!NewProgram(name, defines, program)) + CShaderProgramPtr program = CShaderProgram::Create(name, defines); + if (program) + { + for (const VfsPath& path : program->GetFileDependencies()) + AddProgramFileDependency(program, path); + } + else { LOGERROR("Failed to load shader '%s'", name); - program = CShaderProgramPtr(); } m_ProgramCache[key] = program; return program; } -static GLenum ParseAttribSemantics(const CStr& str) -{ - // Map known semantics onto the attribute locations documented by NVIDIA - if (str == "gl_Vertex") return 0; - if (str == "gl_Normal") return 2; - if (str == "gl_Color") return 3; - if (str == "gl_SecondaryColor") return 4; - if (str == "gl_FogCoord") return 5; - if (str == "gl_MultiTexCoord0") return 8; - if (str == "gl_MultiTexCoord1") return 9; - if (str == "gl_MultiTexCoord2") return 10; - if (str == "gl_MultiTexCoord3") return 11; - if (str == "gl_MultiTexCoord4") return 12; - if (str == "gl_MultiTexCoord5") return 13; - if (str == "gl_MultiTexCoord6") return 14; - if (str == "gl_MultiTexCoord7") return 15; - - // Define some arbitrary names for user-defined attribute locations - // that won't conflict with any standard semantics - if (str == "CustomAttribute0") return 1; - if (str == "CustomAttribute1") return 6; - if (str == "CustomAttribute2") return 7; - - debug_warn("Invalid attribute semantics"); - return 0; -} - -bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefines, CShaderProgramPtr& program) -{ - PROFILE2("loading shader"); - PROFILE2_ATTR("name: %s", name); - - VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml"; - - CXeromyces XeroFile; - PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); - if (ret != PSRETURN_OK) - return false; - -#if USE_SHADER_XML_VALIDATION - { - TIMER_ACCRUE(tc_ShaderValidation); - - // Serialize the XMB data and pass it to the validator - XMLWriter_File shaderFile; - shaderFile.SetPrettyPrint(false); - shaderFile.XMB(XeroFile); - bool ok = CXeromyces::ValidateEncoded("shader", name, shaderFile.GetOutput()); - if (!ok) - return false; - } -#endif - - // Define all the elements and attributes used in the XML file -#define EL(x) int el_##x = XeroFile.GetElementID(#x) -#define AT(x) int at_##x = XeroFile.GetAttributeID(#x) - EL(attrib); - EL(define); - EL(fragment); - EL(stream); - EL(uniform); - EL(vertex); - AT(file); - AT(if); - AT(loc); - AT(name); - AT(semantics); - AT(type); - AT(value); -#undef AT -#undef EL - - CPreprocessorWrapper preprocessor; - preprocessor.AddDefines(baseDefines); - - XMBElement Root = XeroFile.GetRoot(); - - const bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl"); - if (!isGLSL && g_RenderingOptions.GetPreferGLSL()) - LOGWARNING("CShaderManager::NewProgram: '%s': trying to load a non-GLSL program with enabled GLSL", name); - - VfsPath vertexFile; - VfsPath fragmentFile; - CShaderDefines defines = baseDefines; - std::map vertexUniforms; - std::map fragmentUniforms; - std::map vertexAttribs; - int streamFlags = 0; - - XERO_ITER_EL(Root, Child) - { - if (Child.GetNodeName() == el_define) - { - defines.Add(CStrIntern(Child.GetAttributes().GetNamedItem(at_name)), CStrIntern(Child.GetAttributes().GetNamedItem(at_value))); - } - else if (Child.GetNodeName() == el_vertex) - { - vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); - - XERO_ITER_EL(Child, Param) - { - XMBAttributeList Attrs = Param.GetAttributes(); - - CStr cond = Attrs.GetNamedItem(at_if); - if (!cond.empty() && !preprocessor.TestConditional(cond)) - continue; - - if (Param.GetNodeName() == el_uniform) - { - vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt(); - } - else if (Param.GetNodeName() == el_stream) - { - CStr StreamName = Attrs.GetNamedItem(at_name); - if (StreamName == "pos") - streamFlags |= STREAM_POS; - else if (StreamName == "normal") - streamFlags |= STREAM_NORMAL; - else if (StreamName == "color") - streamFlags |= STREAM_COLOR; - else if (StreamName == "uv0") - streamFlags |= STREAM_UV0; - else if (StreamName == "uv1") - streamFlags |= STREAM_UV1; - else if (StreamName == "uv2") - streamFlags |= STREAM_UV2; - else if (StreamName == "uv3") - streamFlags |= STREAM_UV3; - } - else if (Param.GetNodeName() == el_attrib) - { - int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics)); - vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc; - } - } - } - else if (Child.GetNodeName() == el_fragment) - { - fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); - - XERO_ITER_EL(Child, Param) - { - XMBAttributeList Attrs = Param.GetAttributes(); - - CStr cond = Attrs.GetNamedItem(at_if); - if (!cond.empty() && !preprocessor.TestConditional(cond)) - continue; - - if (Param.GetNodeName() == el_uniform) - { - // A somewhat incomplete listing, missing "shadow" and "rect" versions - // which are interpreted as 2D (NB: our shadowmaps may change - // type based on user config). - GLenum type = GL_TEXTURE_2D; - CStr t = Attrs.GetNamedItem(at_type); - if (t == "sampler1D") -#if CONFIG2_GLES - debug_warn(L"sampler1D not implemented on GLES"); -#else - type = GL_TEXTURE_1D; -#endif - else if (t == "sampler2D") - type = GL_TEXTURE_2D; - else if (t == "sampler3D") -#if CONFIG2_GLES - debug_warn(L"sampler3D not implemented on GLES"); -#else - type = GL_TEXTURE_3D; -#endif - else if (t == "samplerCube") - type = GL_TEXTURE_CUBE_MAP; - - fragmentUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = - std::make_pair(Attrs.GetNamedItem(at_loc).ToInt(), type); - } - } - } - } - - if (isGLSL) - program = CShaderProgramPtr(CShaderProgram::ConstructGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamFlags)); - else - program = CShaderProgramPtr(CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags)); - - program->Reload(); - -// m_HotloadFiles[xmlFilename].insert(program); // TODO: should reload somehow when the XML changes - for (const VfsPath& path : program->GetFileDependencies()) - AddProgramFileDependency(program, path); - - return true; -} - -static GLenum ParseComparisonFunc(const CStr& str) -{ - if (str == "never") - return GL_NEVER; - if (str == "always") - return GL_ALWAYS; - if (str == "less") - return GL_LESS; - if (str == "lequal") - return GL_LEQUAL; - if (str == "equal") - return GL_EQUAL; - if (str == "gequal") - return GL_GEQUAL; - if (str == "greater") - return GL_GREATER; - if (str == "notequal") - return GL_NOTEQUAL; - debug_warn("Invalid comparison func"); - return GL_ALWAYS; -} - -static GLenum ParseBlendFunc(const CStr& str) -{ - if (str == "zero") - return GL_ZERO; - if (str == "one") - return GL_ONE; - if (str == "src_color") - return GL_SRC_COLOR; - if (str == "one_minus_src_color") - return GL_ONE_MINUS_SRC_COLOR; - if (str == "dst_color") - return GL_DST_COLOR; - if (str == "one_minus_dst_color") - return GL_ONE_MINUS_DST_COLOR; - if (str == "src_alpha") - return GL_SRC_ALPHA; - if (str == "one_minus_src_alpha") - return GL_ONE_MINUS_SRC_ALPHA; - if (str == "dst_alpha") - return GL_DST_ALPHA; - if (str == "one_minus_dst_alpha") - return GL_ONE_MINUS_DST_ALPHA; - if (str == "constant_color") - return GL_CONSTANT_COLOR; - if (str == "one_minus_constant_color") - return GL_ONE_MINUS_CONSTANT_COLOR; - if (str == "constant_alpha") - return GL_CONSTANT_ALPHA; - if (str == "one_minus_constant_alpha") - return GL_ONE_MINUS_CONSTANT_ALPHA; - if (str == "src_alpha_saturate") - return GL_SRC_ALPHA_SATURATE; - debug_warn("Invalid blend func"); - return GL_ZERO; -} - size_t CShaderManager::EffectCacheKeyHash::operator()(const EffectCacheKey& key) const { size_t hash = 0; hash_combine(hash, key.name.GetHash()); - hash_combine(hash, key.defines1.GetHash()); - hash_combine(hash, key.defines2.GetHash()); + hash_combine(hash, key.defines.GetHash()); return hash; } bool CShaderManager::EffectCacheKey::operator==(const EffectCacheKey& b) const { - return (name == b.name && defines1 == b.defines1 && defines2 == b.defines2); + return name == b.name && defines == b.defines; } CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name) { - return LoadEffect(name, g_Renderer.GetSystemShaderDefines(), CShaderDefines()); + return LoadEffect(name, CShaderDefines()); } -CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDefines& defines1, const CShaderDefines& defines2) +CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDefines& defines) { // Return the cached effect, if there is one - EffectCacheKey key = { name, defines1, defines2 }; + EffectCacheKey key = { name, defines }; EffectCacheMap::iterator it = m_EffectCache.find(key); if (it != m_EffectCache.end()) return it->second; // First time we've seen this key, so construct a new effect: - - // Merge the two sets of defines, so NewEffect doesn't have to care about the split - CShaderDefines defines(defines1); - defines.SetMany(defines2); - - CShaderTechniquePtr tech(new CShaderTechnique()); - if (!NewEffect(name.c_str(), defines, tech)) + const VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name.string()) + L".xml"; + CShaderTechniquePtr tech(new CShaderTechnique(xmlFilename, defines)); + if (!LoadTechnique(tech)) { LOGERROR("Failed to load effect '%s'", name.c_str()); tech = CShaderTechniquePtr(); @@ -375,92 +127,99 @@ return tech; } -bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefines, CShaderTechniquePtr& tech) +bool CShaderManager::LoadTechnique(CShaderTechniquePtr& tech) { - PROFILE2("loading effect"); - PROFILE2_ATTR("name: %s", name); + PROFILE2("loading technique"); + PROFILE2_ATTR("name: %s", tech->GetPath().string8().c_str()); - // Shortcut syntax for effects that just contain a single shader - if (strncmp(name, "shader:", 7) == 0) - { - CShaderProgramPtr program = LoadProgram(name+7, baseDefines); - if (!program) - return false; - CShaderPass pass; - pass.SetShader(program); - tech->AddPass(pass); - return true; - } - - VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name) + L".xml"; + AddTechniqueFileDependency(tech, tech->GetPath()); CXeromyces XeroFile; - PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); + PSRETURN ret = XeroFile.Load(g_VFS, tech->GetPath()); if (ret != PSRETURN_OK) return false; + // By default we assume that we have techinques for every dummy shader. + if (g_VideoMode.GetBackend() == CVideoMode::Backend::DUMMY) + { + const Renderer::Backend::GraphicsPipelineStateDesc passPipelineStateDesc = + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); + tech->SetPasses({{passPipelineStateDesc, LoadProgram("dummy", tech->GetShaderDefines())}}); + return true; + } + // Define all the elements and attributes used in the XML file #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) - EL(alpha); EL(blend); + EL(color); + EL(cull); EL(define); EL(depth); EL(pass); + EL(polygon); EL(require); EL(sort_by_distance); + EL(stencil); + AT(compare); + AT(constant); AT(context); + AT(depth_fail); AT(dst); + AT(fail); + AT(front_face); AT(func); - AT(ref); + AT(mask); + AT(mask_read); + AT(mask_red); + AT(mask_green); + AT(mask_blue); + AT(mask_alpha); + AT(mode); + AT(name); + AT(op); + AT(pass); + AT(reference); AT(shader); AT(shaders); AT(src); - AT(mask); - AT(name); + AT(test); AT(value); #undef AT #undef EL - // Read some defines that influence how we pick techniques - bool hasARB = (baseDefines.GetInt("SYS_HAS_ARB") != 0); - bool hasGLSL = (baseDefines.GetInt("SYS_HAS_GLSL") != 0); - bool preferGLSL = (baseDefines.GetInt("SYS_PREFER_GLSL") != 0); - // Prepare the preprocessor for conditional tests CPreprocessorWrapper preprocessor; - preprocessor.AddDefines(baseDefines); + preprocessor.AddDefines(tech->GetShaderDefines()); XMBElement Root = XeroFile.GetRoot(); // Find all the techniques that we can use, and their preference - std::vector > usableTechs; + std::vector usableTechs; XERO_ITER_EL(Root, Technique) { - int preference = 0; bool isUsable = true; XERO_ITER_EL(Technique, Child) { XMBAttributeList Attrs = Child.GetAttributes(); + // TODO: require should be an attribute of the tech and not its child. if (Child.GetNodeName() == el_require) { if (Attrs.GetNamedItem(at_shaders) == "arb") { - if (!hasARB) + if (g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB || + !g_VideoMode.GetBackendDevice()->GetCapabilities().ARBShaders) + { isUsable = false; + } } else if (Attrs.GetNamedItem(at_shaders) == "glsl") { - if (!hasGLSL) + if (g_VideoMode.GetBackend() != CVideoMode::Backend::GL) isUsable = false; - - if (preferGLSL) - preference += 100; - else - preference -= 100; } else if (!Attrs.GetNamedItem(at_context).empty()) { @@ -472,7 +231,7 @@ } if (isUsable) - usableTechs.emplace_back(Technique, preference); + usableTechs.emplace_back(Technique); } if (usableTechs.empty()) @@ -481,15 +240,10 @@ return false; } - // Sort by preference, tie-break on order of specification - std::stable_sort(usableTechs.begin(), usableTechs.end(), - [](const std::pair& a, const std::pair& b) { - return b.second < a.second; - }); - - CShaderDefines techDefines = baseDefines; + tech->SetSortByDistance(false); - XERO_ITER_EL(usableTechs[0].first, Child) + CShaderDefines techDefines = tech->GetShaderDefines(); + XERO_ITER_EL(usableTechs[0], Child) { if (Child.GetNodeName() == el_define) { @@ -499,11 +253,20 @@ { tech->SetSortByDistance(true); } - else if (Child.GetNodeName() == el_pass) + } + // We don't want to have a shader context depending on the order of define and + // pass tags. + // TODO: we might want to implement that in a proper way via splitting passes + // and tags in different groups in XML. + std::vector techPasses; + XERO_ITER_EL(usableTechs[0], Child) + { + if (Child.GetNodeName() == el_pass) { CShaderDefines passDefines = techDefines; - CShaderPass pass; + Renderer::Backend::GraphicsPipelineStateDesc passPipelineStateDesc = + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); XERO_ITER_EL(Child, Element) { @@ -511,39 +274,151 @@ { passDefines.Add(CStrIntern(Element.GetAttributes().GetNamedItem(at_name)), CStrIntern(Element.GetAttributes().GetNamedItem(at_value))); } - else if (Element.GetNodeName() == el_alpha) - { - GLenum func = ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func)); - float ref = Element.GetAttributes().GetNamedItem(at_ref).ToFloat(); - pass.AlphaFunc(func, ref); - } else if (Element.GetNodeName() == el_blend) { - GLenum src = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_src)); - GLenum dst = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_dst)); - pass.BlendFunc(src, dst); + passPipelineStateDesc.blendState.enabled = true; + passPipelineStateDesc.blendState.srcColorBlendFactor = passPipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::ParseBlendFactor(Element.GetAttributes().GetNamedItem(at_src)); + passPipelineStateDesc.blendState.dstColorBlendFactor = passPipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::ParseBlendFactor(Element.GetAttributes().GetNamedItem(at_dst)); + if (!Element.GetAttributes().GetNamedItem(at_op).empty()) + { + passPipelineStateDesc.blendState.colorBlendOp = passPipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::ParseBlendOp(Element.GetAttributes().GetNamedItem(at_op)); + } + if (!Element.GetAttributes().GetNamedItem(at_constant).empty()) + { + if (!passPipelineStateDesc.blendState.constant.ParseString( + Element.GetAttributes().GetNamedItem(at_constant))) + { + LOGERROR("Failed to parse blend constant: %s", + Element.GetAttributes().GetNamedItem(at_constant).c_str()); + } + } + } + else if (Element.GetNodeName() == el_color) + { + passPipelineStateDesc.blendState.colorWriteMask = 0; + #define MASK_CHANNEL(ATTRIBUTE, VALUE) \ + if (Element.GetAttributes().GetNamedItem(ATTRIBUTE) == "TRUE") \ + passPipelineStateDesc.blendState.colorWriteMask |= Renderer::Backend::ColorWriteMask::VALUE + + MASK_CHANNEL(at_mask_red, RED); + MASK_CHANNEL(at_mask_green, GREEN); + MASK_CHANNEL(at_mask_blue, BLUE); + MASK_CHANNEL(at_mask_alpha, ALPHA); + #undef MASK_CHANNEL + } + else if (Element.GetNodeName() == el_cull) + { + if (!Element.GetAttributes().GetNamedItem(at_mode).empty()) + { + passPipelineStateDesc.rasterizationState.cullMode = + Renderer::Backend::ParseCullMode(Element.GetAttributes().GetNamedItem(at_mode)); + } + if (!Element.GetAttributes().GetNamedItem(at_front_face).empty()) + { + passPipelineStateDesc.rasterizationState.frontFace = + Renderer::Backend::ParseFrontFace(Element.GetAttributes().GetNamedItem(at_front_face)); + } } else if (Element.GetNodeName() == el_depth) { + if (!Element.GetAttributes().GetNamedItem(at_test).empty()) + { + passPipelineStateDesc.depthStencilState.depthTestEnabled = + Element.GetAttributes().GetNamedItem(at_test) == "TRUE"; + } + if (!Element.GetAttributes().GetNamedItem(at_func).empty()) - pass.DepthFunc(ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func))); + { + passPipelineStateDesc.depthStencilState.depthCompareOp = + Renderer::Backend::ParseCompareOp(Element.GetAttributes().GetNamedItem(at_func)); + } if (!Element.GetAttributes().GetNamedItem(at_mask).empty()) - pass.DepthMask(Element.GetAttributes().GetNamedItem(at_mask) == "true" ? 1 : 0); + { + passPipelineStateDesc.depthStencilState.depthWriteEnabled = + Element.GetAttributes().GetNamedItem(at_mask) == "true"; + } + } + else if (Element.GetNodeName() == el_polygon) + { + if (!Element.GetAttributes().GetNamedItem(at_mode).empty()) + { + passPipelineStateDesc.rasterizationState.polygonMode = + Renderer::Backend::ParsePolygonMode(Element.GetAttributes().GetNamedItem(at_mode)); + } + } + else if (Element.GetNodeName() == el_stencil) + { + if (!Element.GetAttributes().GetNamedItem(at_test).empty()) + { + passPipelineStateDesc.depthStencilState.stencilTestEnabled = + Element.GetAttributes().GetNamedItem(at_test) == "TRUE"; + } + + if (!Element.GetAttributes().GetNamedItem(at_reference).empty()) + { + passPipelineStateDesc.depthStencilState.stencilReference = + Element.GetAttributes().GetNamedItem(at_reference).ToULong(); + } + if (!Element.GetAttributes().GetNamedItem(at_mask_read).empty()) + { + passPipelineStateDesc.depthStencilState.stencilReadMask = + Element.GetAttributes().GetNamedItem(at_mask_read).ToULong(); + } + if (!Element.GetAttributes().GetNamedItem(at_mask).empty()) + { + passPipelineStateDesc.depthStencilState.stencilWriteMask = + Element.GetAttributes().GetNamedItem(at_mask).ToULong(); + } + + if (!Element.GetAttributes().GetNamedItem(at_compare).empty()) + { + passPipelineStateDesc.depthStencilState.stencilFrontFace.compareOp = + passPipelineStateDesc.depthStencilState.stencilBackFace.compareOp = + Renderer::Backend::ParseCompareOp(Element.GetAttributes().GetNamedItem(at_compare)); + } + if (!Element.GetAttributes().GetNamedItem(at_fail).empty()) + { + passPipelineStateDesc.depthStencilState.stencilFrontFace.failOp = + passPipelineStateDesc.depthStencilState.stencilBackFace.failOp = + Renderer::Backend::ParseStencilOp(Element.GetAttributes().GetNamedItem(at_fail)); + } + if (!Element.GetAttributes().GetNamedItem(at_pass).empty()) + { + passPipelineStateDesc.depthStencilState.stencilFrontFace.passOp = + passPipelineStateDesc.depthStencilState.stencilBackFace.passOp = + Renderer::Backend::ParseStencilOp(Element.GetAttributes().GetNamedItem(at_pass)); + } + if (!Element.GetAttributes().GetNamedItem(at_depth_fail).empty()) + { + passPipelineStateDesc.depthStencilState.stencilFrontFace.depthFailOp = + passPipelineStateDesc.depthStencilState.stencilBackFace.depthFailOp = + Renderer::Backend::ParseStencilOp(Element.GetAttributes().GetNamedItem(at_depth_fail)); + } } } - // Load the shader program after we've read all the possibly-relevant s - pass.SetShader(LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines)); - - tech->AddPass(pass); + // Load the shader program after we've read all the possibly-relevant s. + CShaderProgramPtr shaderProgram = + LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines); + if (shaderProgram) + { + for (const VfsPath& shaderProgramPath : shaderProgram->GetFileDependencies()) + AddTechniqueFileDependency(tech, shaderProgramPath); + techPasses.emplace_back(passPipelineStateDesc, shaderProgram); + } } } + tech->SetPasses(std::move(techPasses)); + return true; } -size_t CShaderManager::GetNumEffectsLoaded() +size_t CShaderManager::GetNumEffectsLoaded() const { return m_EffectCache.size(); } @@ -555,22 +430,39 @@ Status CShaderManager::ReloadChangedFile(const VfsPath& path) { - // Find all shaders using this file - HotloadFilesMap::iterator files = m_HotloadFiles.find(path); - if (files == m_HotloadFiles.end()) - return INFO::OK; - - // Reload all shaders using this file - for (const std::weak_ptr& ptr : files->second) - if (std::shared_ptr program = ptr.lock()) - program->Reload(); + // Find all shader programs using this file. + const auto programs = m_HotloadPrograms.find(path); + if (programs != m_HotloadPrograms.end()) + { + // Reload all shader programs using this file. + for (const std::weak_ptr& ptr : programs->second) + if (std::shared_ptr program = ptr.lock()) + program->Reload(); + } - // TODO: hotloading changes to shader XML files and effect XML files would be nice + // Find all shader techinques using this file. We need to reload them after + // shader programs. + const auto techniques = m_HotloadTechniques.find(path); + if (techniques != m_HotloadTechniques.end()) + { + // Reload all shader techinques using this file. + for (const std::weak_ptr& ptr : techniques->second) + if (std::shared_ptr technique = ptr.lock()) + { + if (!LoadTechnique(technique)) + LOGERROR("Failed to reload technique '%s'", technique->GetPath().string8().c_str()); + } + } return INFO::OK; } +void CShaderManager::AddTechniqueFileDependency(const CShaderTechniquePtr& technique, const VfsPath& path) +{ + m_HotloadTechniques[path].insert(technique); +} + void CShaderManager::AddProgramFileDependency(const CShaderProgramPtr& program, const VfsPath& path) { - m_HotloadFiles[path].insert(program); + m_HotloadPrograms[path].insert(program); } diff -Nru 0ad-0.0.25b/source/graphics/ShaderManager.h 0ad-0.0.26/source/graphics/ShaderManager.h --- 0ad-0.0.25b/source/graphics/ShaderManager.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderManager.h 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,21 +39,13 @@ ~CShaderManager(); /** - * Load a shader program. - * @param name name of shader XML specification (file is loaded from shaders/${name}.xml) - * @param defines key/value set of preprocessor definitions - * @return loaded program, or null pointer on error - */ - CShaderProgramPtr LoadProgram(const char* name, const CShaderDefines& defines); - - /** * Load a shader effect. * Effects can be implemented via many techniques; this returns the best usable technique. * @param name name of effect XML specification (file is loaded from shaders/effects/${name}.xml) - * @param defines1,defines2 key/value set of preprocessor definitions; defines2 has higher precedence + * @param defines key/value set of preprocessor definitions * @return loaded technique, or empty technique on error */ - CShaderTechniquePtr LoadEffect(CStrIntern name, const CShaderDefines& defines1, const CShaderDefines& defines2); + CShaderTechniquePtr LoadEffect(CStrIntern name, const CShaderDefines& defines); /** * Load a shader effect, with default system defines (from CRenderer::GetSystemShaderDefines). @@ -63,10 +55,9 @@ /** * Returns the number of shader effects that are currently loaded. */ - size_t GetNumEffectsLoaded(); + size_t GetNumEffectsLoaded() const; private: - struct CacheKey { std::string name; @@ -96,8 +87,7 @@ struct EffectCacheKey { CStrIntern name; - CShaderDefines defines1; - CShaderDefines defines2; + CShaderDefines defines; bool operator==(const EffectCacheKey& b) const; }; @@ -111,16 +101,32 @@ EffectCacheMap m_EffectCache; // Store the set of shaders that need to be reloaded when the given file is modified - using HotloadFilesMap = std::unordered_map, std::owner_less > > >; - HotloadFilesMap m_HotloadFiles; + template + using HotloadFilesMap = std::unordered_map< + VfsPath, + std::set, std::owner_less>>>; + HotloadFilesMap m_HotloadTechniques; + HotloadFilesMap m_HotloadPrograms; - bool NewProgram(const char* name, const CShaderDefines& defines, CShaderProgramPtr& program); - bool NewEffect(const char* name, const CShaderDefines& defines, CShaderTechniquePtr& tech); + /** + * Load a shader program. + * @param name name of shader XML specification (file is loaded from shaders/${name}.xml) + * @param defines key/value set of preprocessor definitions + * @return loaded program, or null pointer on error + */ + CShaderProgramPtr LoadProgram(const CStr& name, const CShaderDefines& defines); + + bool LoadTechnique(CShaderTechniquePtr& tech); static Status ReloadChangedFileCB(void* param, const VfsPath& path); Status ReloadChangedFile(const VfsPath& path); /** + * Associates the file with the technique to be reloaded if the file has changed. + */ + void AddTechniqueFileDependency(const CShaderTechniquePtr& technique, const VfsPath& path); + + /** * Associates the file with the program to be reloaded if the file has changed. */ void AddProgramFileDependency(const CShaderProgramPtr& program, const VfsPath& path); diff -Nru 0ad-0.0.25b/source/graphics/ShaderProgram.cpp 0ad-0.0.26/source/graphics/ShaderProgram.cpp --- 0ad-0.0.25b/source/graphics/ShaderProgram.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderProgram.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,925 +19,33 @@ #include "ShaderProgram.h" -#include "graphics/Color.h" -#include "graphics/PreprocessorWrapper.h" -#include "graphics/ShaderManager.h" -#include "graphics/TextureManager.h" -#include "lib/timer.h" -#include "lib/res/graphics/ogl_tex.h" -#include "maths/Matrix3D.h" -#include "maths/Vector3D.h" -#include "ps/CLogger.h" -#include "ps/Filesystem.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" -#if !CONFIG2_GLES - -class CShaderProgramARB : public CShaderProgram -{ -public: - CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags) : - CShaderProgram(streamflags), - m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), - m_Defines(defines), - m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes) - { - pglGenProgramsARB(1, &m_VertexProgram); - pglGenProgramsARB(1, &m_FragmentProgram); - } - - ~CShaderProgramARB() - { - Unload(); - - pglDeleteProgramsARB(1, &m_VertexProgram); - pglDeleteProgramsARB(1, &m_FragmentProgram); - } - - bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code) - { - ogl_WarnIfError(); - - pglBindProgramARB(target, program); - - ogl_WarnIfError(); - - pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str()); - - if (ogl_SquelchError(GL_INVALID_OPERATION)) - { - GLint errPos = 0; - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); - int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1; - char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); - LOGERROR("Failed to compile %s program '%s' (line %d):\n%s", targetName, file.string8(), errLine, errStr); - return false; - } - - pglBindProgramARB(target, 0); - - ogl_WarnIfError(); - - return true; - } - - void Reload() override - { - Unload(); - - CVFSFile vertexFile; - if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) - return; - - CVFSFile fragmentFile; - if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) - return; - - CPreprocessorWrapper preprocessor; - preprocessor.AddDefines(m_Defines); - - CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); - CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); - - if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode)) - return; - - if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode)) - return; - - m_IsValid = true; - } - - void Unload() - { - m_IsValid = false; - } - - void Bind() override - { - glEnable(GL_VERTEX_PROGRAM_ARB); - glEnable(GL_FRAGMENT_PROGRAM_ARB); - pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram); - pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram); - - BindClientStates(); - } - - void Unbind() override - { - glDisable(GL_VERTEX_PROGRAM_ARB); - glDisable(GL_FRAGMENT_PROGRAM_ARB); - pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); - pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); - - UnbindClientStates(); - - // TODO: should unbind textures, probably - } - - int GetUniformVertexIndex(CStrIntern id) - { - std::map::iterator it = m_VertexIndexes.find(id); - if (it == m_VertexIndexes.end()) - return -1; - return it->second; - } - - frag_index_pair_t GetUniformFragmentIndex(CStrIntern id) - { - std::map::iterator it = m_FragmentIndexes.find(id); - if (it == m_FragmentIndexes.end()) - return std::make_pair(-1, 0); - return it->second; - } - - Binding GetTextureBinding(texture_id_t id) override - { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index == -1) - return Binding(); - else - return Binding((int)fPair.second, index); - } - - void BindTexture(texture_id_t id, Handle tex) override - { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index != -1) - { - GLuint h; - ogl_tex_get_texture_id(tex, &h); - pglActiveTextureARB(GL_TEXTURE0+index); - glBindTexture(fPair.second, h); - } - } - - void BindTexture(texture_id_t id, GLuint tex) override - { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index != -1) - { - pglActiveTextureARB(GL_TEXTURE0+index); - glBindTexture(fPair.second, tex); - } - } - - void BindTexture(Binding id, Handle tex) override - { - int index = id.second; - if (index != -1) - ogl_tex_bind(tex, index); - } - - Binding GetUniformBinding(uniform_id_t id) override - { - return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id).first); - } - - void Uniform(Binding id, float v0, float v1, float v2, float v3) override - { - if (id.first != -1) - pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3); - - if (id.second != -1) - pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3); - } - - void Uniform(Binding id, const CMatrix3D& v) override - { - if (id.first != -1) - { - pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+0, v._11, v._12, v._13, v._14); - pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+1, v._21, v._22, v._23, v._24); - pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+2, v._31, v._32, v._33, v._34); - pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+3, v._41, v._42, v._43, v._44); - } - - if (id.second != -1) - { - pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+0, v._11, v._12, v._13, v._14); - pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+1, v._21, v._22, v._23, v._24); - pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+2, v._31, v._32, v._33, v._34); - pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+3, v._41, v._42, v._43, v._44); - } - } - - void Uniform(Binding id, size_t count, const CMatrix3D* v) override - { - ENSURE(count == 1); - Uniform(id, v[0]); - } - - void Uniform(Binding id, size_t count, const float* v) override - { - ENSURE(count == 4); - Uniform(id, v[0], v[1], v[2], v[3]); - } - - std::vector GetFileDependencies() const override - { - return {m_VertexFile, m_FragmentFile}; - } - -private: - VfsPath m_VertexFile; - VfsPath m_FragmentFile; - CShaderDefines m_Defines; - - GLuint m_VertexProgram; - GLuint m_FragmentProgram; - - std::map m_VertexIndexes; - - // pair contains - std::map m_FragmentIndexes; -}; - -#endif // #if !CONFIG2_GLES - -////////////////////////////////////////////////////////////////////////// - -TIMER_ADD_CLIENT(tc_ShaderGLSLCompile); -TIMER_ADD_CLIENT(tc_ShaderGLSLLink); - -class CShaderProgramGLSL : public CShaderProgram -{ -public: - CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags) : - CShaderProgram(streamflags), - m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), - m_Defines(defines), - m_VertexAttribs(vertexAttribs) - { - m_Program = 0; - m_VertexShader = pglCreateShaderObjectARB(GL_VERTEX_SHADER); - m_FragmentShader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER); - m_FileDependencies = {m_VertexFile, m_FragmentFile}; - } - - ~CShaderProgramGLSL() - { - Unload(); - - pglDeleteShader(m_VertexShader); - pglDeleteShader(m_FragmentShader); - } - - bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code) - { - TIMER_ACCRUE(tc_ShaderGLSLCompile); - - ogl_WarnIfError(); - - const char* code_string = code.c_str(); - GLint code_length = code.length(); - pglShaderSourceARB(shader, 1, &code_string, &code_length); - - pglCompileShaderARB(shader); - - GLint ok = 0; - pglGetShaderiv(shader, GL_COMPILE_STATUS, &ok); - - GLint length = 0; - pglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - - // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0 - // (http://code.google.com/p/android/issues/detail?id=9953) - if (!ok && length == 0) - length = 4096; - - if (length > 1) - { - char* infolog = new char[length]; - pglGetShaderInfoLog(shader, length, NULL, infolog); - - if (ok) - LOGMESSAGE("Info when compiling shader '%s':\n%s", file.string8(), infolog); - else - LOGERROR("Failed to compile shader '%s':\n%s", file.string8(), infolog); - - delete[] infolog; - } - - ogl_WarnIfError(); - - return (ok ? true : false); - } - - bool Link() - { - TIMER_ACCRUE(tc_ShaderGLSLLink); - - ENSURE(!m_Program); - m_Program = pglCreateProgramObjectARB(); - - pglAttachObjectARB(m_Program, m_VertexShader); - ogl_WarnIfError(); - pglAttachObjectARB(m_Program, m_FragmentShader); - ogl_WarnIfError(); - - // Set up the attribute bindings explicitly, since apparently drivers - // don't always pick the most efficient bindings automatically, - // and also this lets us hardcode indexes into VertexPointer etc - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) - pglBindAttribLocationARB(m_Program, it->second, it->first.c_str()); - - pglLinkProgramARB(m_Program); - - GLint ok = 0; - pglGetProgramiv(m_Program, GL_LINK_STATUS, &ok); - - GLint length = 0; - pglGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length); - - if (!ok && length == 0) - length = 4096; - - if (length > 1) - { - char* infolog = new char[length]; - pglGetProgramInfoLog(m_Program, length, NULL, infolog); - - if (ok) - LOGMESSAGE("Info when linking program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); - else - LOGERROR("Failed to link program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); - - delete[] infolog; - } - - ogl_WarnIfError(); - - if (!ok) - return false; - - m_Uniforms.clear(); - m_Samplers.clear(); - - Bind(); - - ogl_WarnIfError(); - - GLint numUniforms = 0; - pglGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); - ogl_WarnIfError(); - for (GLint i = 0; i < numUniforms; ++i) - { - char name[256] = {0}; - GLsizei nameLength = 0; - GLint size = 0; - GLenum type = 0; - pglGetActiveUniformARB(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name); - ogl_WarnIfError(); - - GLint loc = pglGetUniformLocationARB(m_Program, name); - - CStrIntern nameIntern(name); - m_Uniforms[nameIntern] = std::make_pair(loc, type); - - // Assign sampler uniforms to sequential texture units - if (type == GL_SAMPLER_2D - || type == GL_SAMPLER_CUBE -#if !CONFIG2_GLES - || type == GL_SAMPLER_2D_SHADOW -#endif - ) - { - int unit = (int)m_Samplers.size(); - m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); - m_Samplers[nameIntern].second = unit; - pglUniform1iARB(loc, unit); // link uniform to unit - ogl_WarnIfError(); - } - } - - // TODO: verify that we're not using more samplers than is supported - - Unbind(); - - ogl_WarnIfError(); - - return true; - } - - void Reload() override - { - Unload(); - - CVFSFile vertexFile; - if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) - return; - - CVFSFile fragmentFile; - if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) - return; - - std::vector newFileDependencies = {m_VertexFile, m_FragmentFile}; - - CPreprocessorWrapper preprocessor([&newFileDependencies](const CStr& includePath, CStr& out) -> bool { - const VfsPath includeFilePath(L"shaders/glsl/" + wstring_from_utf8(includePath)); - // Add dependencies anyway to reload the shader when the file is - // appeared. - newFileDependencies.push_back(includeFilePath); - CVFSFile includeFile; - if (includeFile.Load(g_VFS, includeFilePath) != PSRETURN_OK) - return false; - out = includeFile.GetAsString(); - return true; - }); - preprocessor.AddDefines(m_Defines); - -#if CONFIG2_GLES - // GLES defines the macro "GL_ES" in its GLSL preprocessor, - // but since we run our own preprocessor first, we need to explicitly - // define it here - preprocessor.AddDefine("GL_ES", "1"); -#endif - - CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); - CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); - - m_FileDependencies = std::move(newFileDependencies); - - if (vertexCode.empty()) - LOGERROR("Failed to preprocess vertex shader: '%s'", m_VertexFile.string8()); - if (fragmentCode.empty()) - LOGERROR("Failed to preprocess fragment shader: '%s'", m_FragmentFile.string8()); - -#if CONFIG2_GLES - // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00, - // and also to set default float precision for fragment shaders - vertexCode.Replace("#version 110\n", "#version 100\n"); - vertexCode.Replace("#version 110\r\n", "#version 100\n"); - vertexCode.Replace("#version 120\n", "#version 100\n"); - vertexCode.Replace("#version 120\r\n", "#version 100\n"); - fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n"); - fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n"); - fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n"); - fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n"); -#endif - - if (!Compile(m_VertexShader, m_VertexFile, vertexCode)) - return; - - if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode)) - return; - - if (!Link()) - return; - - m_IsValid = true; - } - - void Unload() - { - m_IsValid = false; - - if (m_Program) - pglDeleteProgram(m_Program); - m_Program = 0; - - // The shader objects can be reused and don't need to be deleted here - } - - void Bind() override - { - pglUseProgramObjectARB(m_Program); - - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) - pglEnableVertexAttribArrayARB(it->second); - } - - void Unbind() override - { - pglUseProgramObjectARB(0); - - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) - pglDisableVertexAttribArrayARB(it->second); - - // TODO: should unbind textures, probably - } - - Binding GetTextureBinding(texture_id_t id) override - { - std::map >::iterator it = m_Samplers.find(CStrIntern(id)); - if (it == m_Samplers.end()) - return Binding(); - else - return Binding((int)it->second.first, it->second.second); - } - - void BindTexture(texture_id_t id, Handle tex) override - { - std::map >::iterator it = m_Samplers.find(CStrIntern(id)); - if (it == m_Samplers.end()) - return; - - GLuint h; - ogl_tex_get_texture_id(tex, &h); - pglActiveTextureARB(GL_TEXTURE0 + it->second.second); - glBindTexture(it->second.first, h); - } - - void BindTexture(texture_id_t id, GLuint tex) override - { - std::map >::iterator it = m_Samplers.find(CStrIntern(id)); - if (it == m_Samplers.end()) - return; - - pglActiveTextureARB(GL_TEXTURE0 + it->second.second); - glBindTexture(it->second.first, tex); - } - - void BindTexture(Binding id, Handle tex) override - { - if (id.second == -1) - return; - - GLuint h; - ogl_tex_get_texture_id(tex, &h); - pglActiveTextureARB(GL_TEXTURE0 + id.second); - glBindTexture(id.first, h); - } - - Binding GetUniformBinding(uniform_id_t id) override - { - std::map >::iterator it = m_Uniforms.find(id); - if (it == m_Uniforms.end()) - return Binding(); - else - return Binding(it->second.first, (int)it->second.second); - } - - void Uniform(Binding id, float v0, float v1, float v2, float v3) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT) - pglUniform1fARB(id.first, v0); - else if (id.second == GL_FLOAT_VEC2) - pglUniform2fARB(id.first, v0, v1); - else if (id.second == GL_FLOAT_VEC3) - pglUniform3fARB(id.first, v0, v1, v2); - else if (id.second == GL_FLOAT_VEC4) - pglUniform4fARB(id.first, v0, v1, v2, v3); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)"); - } - } - - void Uniform(Binding id, const CMatrix3D& v) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT_MAT4) - pglUniformMatrix4fvARB(id.first, 1, GL_FALSE, &v._11); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); - } - } - - void Uniform(Binding id, size_t count, const CMatrix3D* v) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT_MAT4) - pglUniformMatrix4fvARB(id.first, count, GL_FALSE, &v->_11); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); - } - } - - void Uniform(Binding id, size_t count, const float* v) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT) - pglUniform1fvARB(id.first, count, v); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float)"); - } - } - - // Map the various fixed-function Pointer functions onto generic vertex attributes - // (matching the attribute indexes from ShaderManager's ParseAttribSemantics): - - void VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) override - { - pglVertexAttribPointerARB(0, size, type, GL_FALSE, stride, pointer); - m_ValidStreams |= STREAM_POS; - } - - void NormalPointer(GLenum type, GLsizei stride, const void* pointer) override - { - pglVertexAttribPointerARB(2, 3, type, (type == GL_FLOAT ? GL_FALSE : GL_TRUE), stride, pointer); - m_ValidStreams |= STREAM_NORMAL; - } - - void ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) override - { - pglVertexAttribPointerARB(3, size, type, (type == GL_FLOAT ? GL_FALSE : GL_TRUE), stride, pointer); - m_ValidStreams |= STREAM_COLOR; - } - - void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const void* pointer) override - { - pglVertexAttribPointerARB(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer); - m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); - } - - void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) override - { - std::map::iterator it = m_VertexAttribs.find(id); - if (it != m_VertexAttribs.end()) - { - pglVertexAttribPointerARB(it->second, size, type, normalized, stride, pointer); - } - } - - void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, const void* pointer) override - { - std::map::iterator it = m_VertexAttribs.find(id); - if (it != m_VertexAttribs.end()) - { -#if CONFIG2_GLES - debug_warn(L"glVertexAttribIPointer not supported on GLES"); -#else - pglVertexAttribIPointerEXT(it->second, size, type, stride, pointer); -#endif - } - } - - std::vector GetFileDependencies() const override - { - return m_FileDependencies; - } - -private: - VfsPath m_VertexFile; - VfsPath m_FragmentFile; - std::vector m_FileDependencies; - CShaderDefines m_Defines; - std::map m_VertexAttribs; - - GLhandleARB m_Program; - GLhandleARB m_VertexShader; - GLhandleARB m_FragmentShader; - - std::map > m_Uniforms; - std::map > m_Samplers; // texture target & unit chosen for each uniform sampler -}; - -////////////////////////////////////////////////////////////////////////// - -CShaderProgram::CShaderProgram(int streamflags) - : m_IsValid(false), m_StreamFlags(streamflags), m_ValidStreams(0) -{ -} - -#if CONFIG2_GLES -/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& UNUSED(defines), - const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes), - int UNUSED(streamflags)) -{ - LOGERROR("CShaderProgram::ConstructARB: '%s'+'%s': ARB shaders not supported on this device", - vertexFile.string8(), fragmentFile.string8()); - return NULL; -} -#else -/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags) +CShaderProgram::CShaderProgram(const CStr& name, const CShaderDefines& defines) + : m_Name(name), m_Defines(defines) { - return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags); } -#endif -/*static*/ CShaderProgram* CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags) +// static +CShaderProgramPtr CShaderProgram::Create(const CStr& name, const CShaderDefines& defines) { - return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags); + CShaderProgramPtr shaderProgram(new CShaderProgram(name, defines)); + shaderProgram->Reload(); + return shaderProgram->m_BackendShaderProgram ? shaderProgram : nullptr; } -bool CShaderProgram::IsValid() const +void CShaderProgram::Reload() { - return m_IsValid; + std::unique_ptr backendShaderProgram = + g_VideoMode.GetBackendDevice()->CreateShaderProgram(m_Name, m_Defines); + if (backendShaderProgram) + m_BackendShaderProgram = std::move(backendShaderProgram); } -int CShaderProgram::GetStreamFlags() const -{ - return m_StreamFlags; -} - -void CShaderProgram::BindTexture(texture_id_t id, CTexturePtr tex) -{ - BindTexture(id, tex->GetHandle()); -} - -void CShaderProgram::Uniform(Binding id, int v) -{ - Uniform(id, (float)v, (float)v, (float)v, (float)v); -} - -void CShaderProgram::Uniform(Binding id, float v) -{ - Uniform(id, v, v, v, v); -} - -void CShaderProgram::Uniform(Binding id, float v0, float v1) -{ - Uniform(id, v0, v1, 0.0f, 0.0f); -} - -void CShaderProgram::Uniform(Binding id, const CVector3D& v) -{ - Uniform(id, v.X, v.Y, v.Z, 0.0f); -} - -void CShaderProgram::Uniform(Binding id, const CColor& v) -{ - Uniform(id, v.r, v.g, v.b, v.a); -} - -void CShaderProgram::Uniform(uniform_id_t id, int v) -{ - Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v); -} - -void CShaderProgram::Uniform(uniform_id_t id, float v) -{ - Uniform(GetUniformBinding(id), v, v, v, v); -} - -void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1) -{ - Uniform(GetUniformBinding(id), v0, v1, 0.0f, 0.0f); -} - -void CShaderProgram::Uniform(uniform_id_t id, const CVector3D& v) -{ - Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f); -} - -void CShaderProgram::Uniform(uniform_id_t id, const CColor& v) -{ - Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a); -} - -void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1, float v2, float v3) -{ - Uniform(GetUniformBinding(id), v0, v1, v2, v3); -} - -void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v) -{ - Uniform(GetUniformBinding(id), v); -} - -void CShaderProgram::Uniform(uniform_id_t id, size_t count, const CMatrix3D* v) -{ - Uniform(GetUniformBinding(id), count, v); -} - -void CShaderProgram::Uniform(uniform_id_t id, size_t count, const float* v) -{ - Uniform(GetUniformBinding(id), count, v); -} - - -// These should all be overridden by CShaderProgramGLSL, and not used -// if a non-GLSL shader was loaded instead: - -void CShaderProgram::VertexAttribPointer(attrib_id_t UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type), - GLboolean UNUSED(normalized), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("Shader type doesn't support VertexAttribPointer"); -} - -void CShaderProgram::VertexAttribIPointer(attrib_id_t UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type), - GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("Shader type doesn't support VertexAttribIPointer"); -} - -#if CONFIG2_GLES - -// These should all be overridden by CShaderProgramGLSL -// (GLES doesn't support any other types of shader program): - -void CShaderProgram::VertexPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::VertexPointer should be overridden"); -} -void CShaderProgram::NormalPointer(GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::NormalPointer should be overridden"); -} -void CShaderProgram::ColorPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::ColorPointer should be overridden"); -} -void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::TexCoordPointer should be overridden"); -} - -#else - -// These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders -// both use the fixed-function vertex attribute pointers so we'll share their -// definitions here: - -void CShaderProgram::VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) -{ - glVertexPointer(size, type, stride, pointer); - m_ValidStreams |= STREAM_POS; -} - -void CShaderProgram::NormalPointer(GLenum type, GLsizei stride, const void* pointer) -{ - glNormalPointer(type, stride, pointer); - m_ValidStreams |= STREAM_NORMAL; -} - -void CShaderProgram::ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) -{ - glColorPointer(size, type, stride, pointer); - m_ValidStreams |= STREAM_COLOR; -} - -void CShaderProgram::TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const void* pointer) -{ - pglClientActiveTextureARB(texture); - glTexCoordPointer(size, type, stride, pointer); - pglClientActiveTextureARB(GL_TEXTURE0); - m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); -} - -void CShaderProgram::BindClientStates() -{ - ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1))); - - // Enable all the desired client states for non-GLSL rendering - - if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY); - if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY); - if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); - - if (m_StreamFlags & STREAM_UV0) - { - pglClientActiveTextureARB(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (m_StreamFlags & STREAM_UV1) - { - pglClientActiveTextureARB(GL_TEXTURE1); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - pglClientActiveTextureARB(GL_TEXTURE0); - } - - // Rendering code must subsequently call VertexPointer etc for all of the streams - // that were activated in this function, else AssertPointersBound will complain - // that some arrays were unspecified - m_ValidStreams = 0; -} - -void CShaderProgram::UnbindClientStates() -{ - if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY); - if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY); - if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); - - if (m_StreamFlags & STREAM_UV0) - { - pglClientActiveTextureARB(GL_TEXTURE0); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (m_StreamFlags & STREAM_UV1) - { - pglClientActiveTextureARB(GL_TEXTURE1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - pglClientActiveTextureARB(GL_TEXTURE0); - } -} - -#endif // !CONFIG2_GLES - -void CShaderProgram::AssertPointersBound() +std::vector CShaderProgram::GetFileDependencies() const { - ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); + if (m_BackendShaderProgram) + return m_BackendShaderProgram->GetFileDependencies(); + return {}; } diff -Nru 0ad-0.0.25b/source/graphics/ShaderProgram.h 0ad-0.0.26/source/graphics/ShaderProgram.h --- 0ad-0.0.25b/source/graphics/ShaderProgram.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderProgram.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,190 +18,39 @@ #ifndef INCLUDED_SHADERPROGRAM #define INCLUDED_SHADERPROGRAM +#include "graphics/ShaderDefines.h" #include "graphics/ShaderProgramPtr.h" -#include "graphics/Texture.h" -#include "lib/ogl.h" #include "lib/file/vfs/vfs_path.h" -#include "lib/res/handle.h" +#include "ps/CStr.h" +#include "renderer/backend/IShaderProgram.h" -#include #include -struct CColor; -class CMatrix3D; -class CVector3D; -class CShaderDefines; -class CStrIntern; - -// Vertex data stream flags -enum -{ - STREAM_POS = (1 << 0), - STREAM_NORMAL = (1 << 1), - STREAM_COLOR = (1 << 2), - STREAM_UV0 = (1 << 3), - STREAM_UV1 = (1 << 4), - STREAM_UV2 = (1 << 5), - STREAM_UV3 = (1 << 6), - STREAM_POSTOUV0 = (1 << 7), - STREAM_POSTOUV1 = (1 << 8), - STREAM_POSTOUV2 = (1 << 9), - STREAM_POSTOUV3 = (1 << 10) -}; - /** - * A compiled vertex+fragment shader program. - * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax) - * or GL_ARB_{vertex,fragment}_shader (GLSL), or may use hard-coded fixed-function - * multitexturing setup code; the difference is hidden from the caller. - * - * Texture/uniform IDs are typically strings, corresponding to the names defined in - * the shader .xml file. Alternatively (and more efficiently, if used very frequently), - * call GetTextureBinding/GetUniformBinding and pass its return value as the ID. - * Setting uniforms that the shader .xml doesn't support is harmless. - * - * For a high-level overview of shaders and materials, see - * http://trac.wildfiregames.com/wiki/MaterialSystem + * A wrapper for backend shader program to handle high-level operations like + * file reloading and handling errors on reload. */ class CShaderProgram { NONCOPYABLE(CShaderProgram); public: - typedef CStrIntern attrib_id_t; - typedef CStrIntern texture_id_t; - typedef CStrIntern uniform_id_t; - typedef std::pair frag_index_pair_t; - - /** - * Construct based on ARB vertex/fragment program files. - */ - static CShaderProgram* ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags); - - /** - * Construct based on GLSL vertex/fragment shader files. - */ - static CShaderProgram* ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags); - - /** - * Represents a uniform attribute or texture binding. - * For uniforms: - * - ARB shaders store vertex location in 'first', fragment location in 'second'. - * - GLSL shaders store uniform location in 'first', data type in 'second'. - * For textures, all store texture target (e.g. GL_TEXTURE_2D) in 'first', texture unit in 'second'. - * Non-existent bindings must store -1 in both. - */ - struct Binding - { - Binding(int a, int b) : first(a), second(b) { } - - Binding() : first(-1), second(-1) { } - - /** - * Returns whether this uniform attribute is active in the shader. - * If not then there's no point calling Uniform() to set its value. - */ - bool Active() const { return first != -1 || second != -1; } - - int first; - int second; - }; - - virtual ~CShaderProgram() { } - - virtual void Reload() = 0; - - /** - * Returns whether this shader was successfully loaded. - */ - bool IsValid() const; - - /** - * Binds the shader into the GL context. Call this before calling Uniform() - * or trying to render with it. - */ - virtual void Bind() = 0; - - /** - * Unbinds the shader from the GL context. Call this after rendering with it. - */ - virtual void Unbind() = 0; - - /** - * Returns bitset of STREAM_* value, indicating what vertex data streams the - * vertex shader needs (e.g. position, color, UV, ...). - */ - int GetStreamFlags() const; - - - virtual Binding GetTextureBinding(texture_id_t id) = 0; - - // Variants of texture binding: - void BindTexture(texture_id_t id, CTexturePtr tex); - virtual void BindTexture(texture_id_t id, Handle tex) = 0; - virtual void BindTexture(texture_id_t id, GLuint tex) = 0; - virtual void BindTexture(Binding id, Handle tex) = 0; - - - virtual Binding GetUniformBinding(uniform_id_t id) = 0; - - // Uniform-setting methods that subclasses must define: - virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) = 0; - virtual void Uniform(Binding id, const CMatrix3D& v) = 0; - virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) = 0; - virtual void Uniform(Binding id, size_t count, const float* v) = 0; - - // Convenient uniform-setting wrappers: - - void Uniform(Binding id, int v); - void Uniform(Binding id, float v); - void Uniform(Binding id, float v0, float v1); - void Uniform(Binding id, const CVector3D& v); - void Uniform(Binding id, const CColor& v); - - void Uniform(uniform_id_t id, int v); - void Uniform(uniform_id_t id, float v); - void Uniform(uniform_id_t id, float v0, float v1); - void Uniform(uniform_id_t id, const CVector3D& v); - void Uniform(uniform_id_t id, const CColor& v); - void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3); - void Uniform(uniform_id_t id, const CMatrix3D& v); - void Uniform(uniform_id_t id, size_t count, const CMatrix3D* v); - void Uniform(uniform_id_t id, size_t count, const float* v); - - // Vertex attribute pointers (equivalent to glVertexPointer etc): - - virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer); - virtual void NormalPointer(GLenum type, GLsizei stride, const void* pointer); - virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer); - virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const void* pointer); - virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); - virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, const void* pointer); - - /** - * Checks that all the required vertex attributes have been set. - * Call this before calling glDrawArrays/glDrawElements etc to avoid potential crashes. - */ - void AssertPointersBound(); + static CShaderProgramPtr Create(const CStr& name, const CShaderDefines& defines); - virtual std::vector GetFileDependencies() const = 0; + void Reload(); -protected: - CShaderProgram(int streamflags); + std::vector GetFileDependencies() const; + + Renderer::Backend::IShaderProgram* GetBackendShaderProgram() { return m_BackendShaderProgram.get(); } - bool m_IsValid; - int m_StreamFlags; + // TODO: add reloadable handles. + +protected: + CShaderProgram(const CStr& name, const CShaderDefines& defines); - // Non-GLSL client state handling: - void BindClientStates(); - void UnbindClientStates(); - int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind + CStr m_Name; + CShaderDefines m_Defines; + std::unique_ptr m_BackendShaderProgram; }; #endif // INCLUDED_SHADERPROGRAM diff -Nru 0ad-0.0.25b/source/graphics/ShaderTechnique.cpp 0ad-0.0.26/source/graphics/ShaderTechnique.cpp --- 0ad-0.0.25b/source/graphics/ShaderTechnique.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderTechnique.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,107 +21,22 @@ #include "graphics/ShaderProgram.h" -CShaderPass::CShaderPass() : - m_HasAlpha(false), m_HasBlend(false), m_HasColorMask(false), m_HasDepthMask(false), m_HasDepthFunc(false) +CShaderPass::CShaderPass( + const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, + const CShaderProgramPtr& shader) + : m_PipelineStateDesc(pipelineStateDesc), m_Shader(shader) { + m_PipelineStateDesc.shaderProgram = m_Shader->GetBackendShaderProgram(); } -void CShaderPass::Bind() -{ - m_Shader->Bind(); - -#if !CONFIG2_GLES - if (m_HasAlpha) - { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(m_AlphaFunc, m_AlphaRef); - } -#endif - // TODO: maybe emit some warning if GLSL shaders try to use alpha test; - // the test should be done inside the shader itself - - if (m_HasBlend) - { - glEnable(GL_BLEND); - glBlendFunc(m_BlendSrc, m_BlendDst); - } - - if (m_HasColorMask) - glColorMask(m_ColorMaskR, m_ColorMaskG, m_ColorMaskB, m_ColorMaskA); - - if (m_HasDepthMask) - glDepthMask(m_DepthMask); - - if (m_HasDepthFunc) - glDepthFunc(m_DepthFunc); -} - -void CShaderPass::Unbind() -{ - m_Shader->Unbind(); - -#if !CONFIG2_GLES - if (m_HasAlpha) - glDisable(GL_ALPHA_TEST); -#endif - - if (m_HasBlend) - glDisable(GL_BLEND); - - if (m_HasColorMask) - glColorMask(1, 1, 1, 1); - - if (m_HasDepthMask) - glDepthMask(1); - - if (m_HasDepthFunc) - glDepthFunc(GL_LEQUAL); -} - -void CShaderPass::AlphaFunc(GLenum func, GLclampf ref) -{ - m_HasAlpha = true; - m_AlphaFunc = func; - m_AlphaRef = ref; -} - -void CShaderPass::BlendFunc(GLenum src, GLenum dst) -{ - m_HasBlend = true; - m_BlendSrc = src; - m_BlendDst = dst; -} - -void CShaderPass::ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) -{ - m_HasColorMask = true; - m_ColorMaskR = r; - m_ColorMaskG = g; - m_ColorMaskB = b; - m_ColorMaskA = a; -} - -void CShaderPass::DepthMask(GLboolean mask) -{ - m_HasDepthMask = true; - m_DepthMask = mask; -} - -void CShaderPass::DepthFunc(GLenum func) -{ - m_HasDepthFunc = true; - m_DepthFunc = func; -} - - -CShaderTechnique::CShaderTechnique() - : m_SortByDistance(false) +CShaderTechnique::CShaderTechnique(const VfsPath& path, const CShaderDefines& defines) + : m_Path(path), m_Defines(defines) { } -void CShaderTechnique::AddPass(const CShaderPass& pass) +void CShaderTechnique::SetPasses(std::vector&& passes) { - m_Passes.push_back(pass); + m_Passes = std::move(passes); } int CShaderTechnique::GetNumPasses() const @@ -129,22 +44,17 @@ return m_Passes.size(); } -void CShaderTechnique::BeginPass(int pass) +Renderer::Backend::IShaderProgram* CShaderTechnique::GetShader(int pass) const { ENSURE(0 <= pass && pass < (int)m_Passes.size()); - m_Passes[pass].Bind(); -} - -void CShaderTechnique::EndPass(int pass) -{ - ENSURE(0 <= pass && pass < (int)m_Passes.size()); - m_Passes[pass].Unbind(); + return m_Passes[pass].GetShader(); } -const CShaderProgramPtr& CShaderTechnique::GetShader(int pass) const +const Renderer::Backend::GraphicsPipelineStateDesc& +CShaderTechnique::GetGraphicsPipelineStateDesc(int pass) const { - ENSURE(0 <= pass && pass < (int)m_Passes.size()); - return m_Passes[pass].GetShader(); + ENSURE(0 <= pass && pass < static_cast(m_Passes.size())); + return m_Passes[pass].GetPipelineStateDesc(); } bool CShaderTechnique::GetSortByDistance() const @@ -156,9 +66,3 @@ { m_SortByDistance = enable; } - -void CShaderTechnique::Reset() -{ - m_SortByDistance = false; - m_Passes.clear(); -} diff -Nru 0ad-0.0.25b/source/graphics/ShaderTechnique.h 0ad-0.0.26/source/graphics/ShaderTechnique.h --- 0ad-0.0.25b/source/graphics/ShaderTechnique.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/ShaderTechnique.h 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,9 +18,11 @@ #ifndef INCLUDED_SHADERTECHNIQUE #define INCLUDED_SHADERTECHNIQUE -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderDefines.h" +#include "graphics/ShaderProgram.h" #include "graphics/ShaderTechniquePtr.h" -#include "lib/ogl.h" +#include "lib/file/vfs/vfs_path.h" +#include "renderer/backend/PipelineState.h" #include @@ -31,54 +33,17 @@ class CShaderPass { public: - CShaderPass(); + CShaderPass(const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, const CShaderProgramPtr& shader); - /** - * Set the shader program used for rendering with this pass. - */ - void SetShader(const CShaderProgramPtr& shader) { m_Shader = shader; } - - // Add various bits of GL state to the pass: - void AlphaFunc(GLenum func, GLclampf ref); - void BlendFunc(GLenum src, GLenum dst); - void ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a); - void DepthMask(GLboolean mask); - void DepthFunc(GLenum func); - - /** - * Set up all the GL state that was previously specified on this pass. - */ - void Bind(); + Renderer::Backend::IShaderProgram* GetShader() const { return m_Shader->GetBackendShaderProgram(); } - /** - * Reset the GL state to the default. - */ - void Unbind(); - - const CShaderProgramPtr& GetShader() const { return m_Shader; } + const Renderer::Backend::GraphicsPipelineStateDesc& + GetPipelineStateDesc() const { return m_PipelineStateDesc; } private: CShaderProgramPtr m_Shader; - bool m_HasAlpha; - GLenum m_AlphaFunc; - GLclampf m_AlphaRef; - - bool m_HasBlend; - GLenum m_BlendSrc; - GLenum m_BlendDst; - - bool m_HasColorMask; - GLboolean m_ColorMaskR; - GLboolean m_ColorMaskG; - GLboolean m_ColorMaskB; - GLboolean m_ColorMaskA; - - bool m_HasDepthMask; - GLboolean m_DepthMask; - - bool m_HasDepthFunc; - GLenum m_DepthFunc; + Renderer::Backend::GraphicsPipelineStateDesc m_PipelineStateDesc{}; }; /** @@ -88,14 +53,16 @@ class CShaderTechnique { public: - CShaderTechnique(); - void AddPass(const CShaderPass& pass); + CShaderTechnique(const VfsPath& path, const CShaderDefines& defines); + + void SetPasses(std::vector&& passes); int GetNumPasses() const; - void BeginPass(int pass = 0); - void EndPass(int pass = 0); - const CShaderProgramPtr& GetShader(int pass = 0) const; + Renderer::Backend::IShaderProgram* GetShader(int pass = 0) const; + + const Renderer::Backend::GraphicsPipelineStateDesc& + GetGraphicsPipelineStateDesc(int pass = 0) const; /** * Whether this technique uses alpha blending that requires objects to be @@ -105,12 +72,18 @@ void SetSortByDistance(bool enable); - void Reset(); + const VfsPath& GetPath() { return m_Path; } + + const CShaderDefines& GetShaderDefines() { return m_Defines; } private: std::vector m_Passes; - bool m_SortByDistance; + bool m_SortByDistance = false; + + // We need additional data to reload the technique. + VfsPath m_Path; + CShaderDefines m_Defines; }; #endif // INCLUDED_SHADERTECHNIQUE diff -Nru 0ad-0.0.25b/source/graphics/SkeletonAnimManager.cpp 0ad-0.0.26/source/graphics/SkeletonAnimManager.cpp --- 0ad-0.0.25b/source/graphics/SkeletonAnimManager.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/SkeletonAnimManager.cpp 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,8 +25,10 @@ #include "graphics/ColladaManager.h" #include "graphics/Model.h" +#include "graphics/SkeletonAnim.h" #include "graphics/SkeletonAnimDef.h" #include "ps/CLogger.h" +#include "ps/CStr.h" #include "ps/FileIo.h" /////////////////////////////////////////////////////////////////////////////// @@ -79,3 +81,40 @@ // Add to map, NULL if failed to load - we won't try loading it again return m_Animations.insert_or_assign(name, std::move(def)).first->second.get(); } + +/** + * BuildAnimation: load raw animation frame animation from given file, and build a + * animation specific to this model + */ +std::unique_ptr CSkeletonAnimManager::BuildAnimation(const VfsPath& pathname, const CStr8& name, const CStr8& ID, int frequency, float speed, float actionpos, float actionpos2, float soundpos) +{ + CSkeletonAnimDef* def = GetAnimation(pathname); + if (!def) + return nullptr; + + std::unique_ptr anim = std::make_unique(); + anim->m_Name = name; + anim->m_ID = ID; + anim->m_Frequency = frequency; + anim->m_AnimDef = def; + anim->m_Speed = speed; + + if (actionpos == -1.f) + anim->m_ActionPos = -1.f; + else + anim->m_ActionPos = actionpos * anim->m_AnimDef->GetDuration(); + + if (actionpos2 == -1.f) + anim->m_ActionPos2 = -1.f; + else + anim->m_ActionPos2 = actionpos2 * anim->m_AnimDef->GetDuration(); + + if (soundpos == -1.f) + anim->m_SoundPos = -1.f; + else + anim->m_SoundPos = soundpos * anim->m_AnimDef->GetDuration(); + + anim->m_ObjectBounds.SetEmpty(); + + return anim; +} diff -Nru 0ad-0.0.25b/source/graphics/SkeletonAnimManager.h 0ad-0.0.26/source/graphics/SkeletonAnimManager.h --- 0ad-0.0.25b/source/graphics/SkeletonAnimManager.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/SkeletonAnimManager.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,6 +29,7 @@ class CColladaManager; class CSkeletonAnimDef; +class CSkeletonAnim; class CStr8; /////////////////////////////////////////////////////////////////////////////// @@ -46,6 +47,21 @@ // refer to valid animation file CSkeletonAnimDef* GetAnimation(const VfsPath& pathname); + /** + * Load raw animation frame animation from given file, and build an + * animation specific to this model. + * @param pathname animation file to load + * @param name animation name (e.g. "idle") + * @param ID specific ID of the animation, to sync with props + * @param frequency influences the random choices + * @param speed animation speed as a factor of the default animation speed + * @param actionpos offset of 'action' event, in range [0, 1] + * @param actionpos2 offset of 'action2' event, in range [0, 1] + * @param sound offset of 'sound' event, in range [0, 1] + * @return new animation, or NULL on error + */ + std::unique_ptr BuildAnimation(const VfsPath& pathname, const CStr8& name, const CStr8& ID, int frequency, float speed, float actionpos, float actionpos2, float soundpos); + private: // map of all known animations. Value is NULL if it failed to load. std::unordered_map> m_Animations; diff -Nru 0ad-0.0.25b/source/graphics/Terrain.cpp 0ad-0.0.26/source/graphics/Terrain.cpp --- 0ad-0.0.25b/source/graphics/Terrain.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Terrain.cpp 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,29 +15,23 @@ * along with 0 A.D. If not, see . */ -/* - * Describes ground via heightmap and array of CPatch. - */ - #include "precompiled.h" -#include "lib/res/graphics/ogl_tex.h" -#include "lib/sysdep/cpu.h" - -#include "renderer/Renderer.h" +#include "graphics/Terrain.h" -#include "TerrainProperties.h" -#include "TerrainTextureEntry.h" -#include "TerrainTextureManager.h" - -#include -#include "Terrain.h" -#include "Patch.h" +#include "graphics/Patch.h" +#include "graphics/TerrainProperties.h" +#include "graphics/TerrainTextureEntry.h" +#include "graphics/TerrainTextureManager.h" +#include "lib/sysdep/cpu.h" #include "maths/FixedVector3D.h" #include "maths/MathUtil.h" #include "ps/CLogger.h" +#include "renderer/Renderer.h" #include "simulation2/helpers/Pathfinding.h" +#include + /////////////////////////////////////////////////////////////////////////////// // CTerrain constructor CTerrain::CTerrain() @@ -102,17 +96,6 @@ } /////////////////////////////////////////////////////////////////////////////// - -CStr8 CTerrain::GetMovementClass(ssize_t i, ssize_t j) const -{ - CMiniPatch* tile = GetTile(i, j); - if (tile && tile->GetTextureEntry()) - return tile->GetTextureEntry()->GetProperties().GetMovementClass(); - - return "default"; -} - -/////////////////////////////////////////////////////////////////////////////// // CalcPosition: calculate the world space position of the vertex at (i,j) // If i,j is off the map, it acts as if the edges of the terrain are extended // outwards to infinity diff -Nru 0ad-0.0.25b/source/graphics/Terrain.h 0ad-0.0.26/source/graphics/Terrain.h --- 0ad-0.0.25b/source/graphics/Terrain.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Terrain.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,11 +26,11 @@ #include "graphics/SColor.h" #include "maths/Fixed.h" #include "maths/Vector3D.h" +#include "ps/CStr.h" class CPatch; class CMiniPatch; class CFixedVector3D; -class CStr8; class CBoundingBoxAligned; /////////////////////////////////////////////////////////////////////////////// @@ -79,8 +79,6 @@ && (z >= GetMinZ()) && (z < GetMaxZ())); } - CStr8 GetMovementClass(ssize_t i, ssize_t j) const; - float GetVertexGroundLevel(ssize_t i, ssize_t j) const; fixed GetVertexGroundLevelFixed(ssize_t i, ssize_t j) const; float GetExactGroundLevel(float x, float z) const; diff -Nru 0ad-0.0.25b/source/graphics/TerrainProperties.cpp 0ad-0.0.26/source/graphics/TerrainProperties.cpp --- 0ad-0.0.25b/source/graphics/TerrainProperties.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerrainProperties.cpp 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,8 +35,7 @@ m_BaseColor(0), m_HasBaseColor(false), m_TextureAngle((float)M_PI / 4.f), - m_TextureSize(32.f), - m_MovementClass("default") + m_TextureSize(32.f) { if (m_pParent) m_Groups = m_pParent->m_Groups; @@ -95,7 +94,6 @@ // Terrain Attribs ATTR(mmap); ATTR(groups); - ATTR(movementclass); ATTR(angle); ATTR(size); #undef ELMT @@ -136,10 +134,6 @@ { m_TextureSize = attr.Value.ToFloat(); } - else if (attr.Name == attr_movementclass) - { - m_MovementClass = attr.Value; - } } } diff -Nru 0ad-0.0.25b/source/graphics/TerrainProperties.h 0ad-0.0.26/source/graphics/TerrainProperties.h --- 0ad-0.0.25b/source/graphics/TerrainProperties.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerrainProperties.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -55,8 +55,6 @@ u32 m_BaseColor; bool m_HasBaseColor; - CStr m_MovementClass; - // Orientation of texture (in radians) (default pi/4 = 45 degrees) float m_TextureAngle; @@ -103,11 +101,6 @@ return m_TextureSize; } - CStr GetMovementClass() const - { - return m_MovementClass; - } - const GroupVector &GetGroups() const { return m_Groups; diff -Nru 0ad-0.0.25b/source/graphics/TerrainTextureEntry.cpp 0ad-0.0.26/source/graphics/TerrainTextureEntry.cpp --- 0ad-0.0.25b/source/graphics/TerrainTextureEntry.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerrainTextureEntry.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,22 +19,18 @@ #include "TerrainTextureEntry.h" +#include "graphics/MaterialManager.h" +#include "graphics/Terrain.h" +#include "graphics/TerrainProperties.h" +#include "graphics/TerrainTextureManager.h" +#include "graphics/TextureManager.h" #include "lib/utf8.h" -#include "lib/ogl.h" -#include "lib/allocators/shared_ptr.h" -#include "lib/file/io/io.h" -#include "lib/res/graphics/ogl_tex.h" - #include "ps/CLogger.h" +#include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/XML/Xeromyces.h" - -#include "graphics/MaterialManager.h" -#include "graphics/Terrain.h" -#include "graphics/TerrainTextureManager.h" -#include "graphics/TerrainProperties.h" -#include "graphics/Texture.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include @@ -66,7 +62,6 @@ #undef AT #undef EL - XMBElement root = XeroFile.GetRoot(); if (root.GetNodeName() != el_terrain) @@ -75,12 +70,10 @@ return; } - std::vector > samplers; VfsPath alphamap("standard"); m_Tag = utf8_from_wstring(path.Basename().string()); - XERO_ITER_EL(root, child) { int child_name = child.GetNodeName(); @@ -101,6 +94,8 @@ name = relativePath.Value; } samplers.emplace_back(name, terrainTexturePath); + if (name == str_baseTex.string()) + m_DiffuseTexturePath = terrainTexturePath; } } @@ -108,7 +103,7 @@ { VfsPath mat = VfsPath("art/materials") / child.GetText().FromUTF8(); if (CRenderer::IsInitialised()) - m_Material = g_Renderer.GetMaterialManager().LoadMaterial(mat); + m_Material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(mat); } else if (child_name == el_alphamap) { @@ -126,16 +121,11 @@ } } - for (size_t i = 0; i < samplers.size(); ++i) { CTextureProperties texture(samplers[i].second); - texture.SetWrap(GL_REPEAT); - - // TODO: anisotropy should probably be user-configurable, but we want it to be - // at least 2 for terrain else the ground looks very blurry when you tilt the - // camera upwards - texture.SetMaxAnisotropy(2.0f); + texture.SetAddressMode(Renderer::Backend::Sampler::AddressMode::REPEAT); + texture.SetAnisotropicFilter(true); if (CRenderer::IsInitialised()) { @@ -145,7 +135,7 @@ } if (CRenderer::IsInitialised()) - LoadAlphaMaps(alphamap); + m_TerrainAlpha = g_TexMan.LoadAlphaMap(alphamap); float texAngle = 0.f; float texSize = 1.f; @@ -194,173 +184,3 @@ m_BaseColorValid = true; } } - -const float* CTerrainTextureEntry::GetTextureMatrix() const -{ - return &m_TextureMatrix._11; -} - -// LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and -// calculate the coordinate of each alphamap within this packed texture -void CTerrainTextureEntry::LoadAlphaMaps(VfsPath &amtype) -{ - std::wstring key = L"(alpha map composite" + amtype.string() + L")"; - - CTerrainTextureManager::TerrainAlphaMap::iterator it = g_TexMan.m_TerrainAlphas.find(amtype); - - if (it != g_TexMan.m_TerrainAlphas.end()) - { - m_TerrainAlpha = it; - return; - } - - g_TexMan.m_TerrainAlphas[amtype] = TerrainAlpha(); - it = g_TexMan.m_TerrainAlphas.find(amtype); - - TerrainAlpha &result = it->second; - - // - // load all textures and store Handle in array - // - Handle textures[NUM_ALPHA_MAPS] = {0}; - VfsPath path(L"art/textures/terrain/alphamaps"); - path = path / amtype; - - const wchar_t* fnames[NUM_ALPHA_MAPS] = { - L"blendcircle.png", - L"blendlshape.png", - L"blendedge.png", - L"blendedgecorner.png", - L"blendedgetwocorners.png", - L"blendfourcorners.png", - L"blendtwooppositecorners.png", - L"blendlshapecorner.png", - L"blendtwocorners.png", - L"blendcorner.png", - L"blendtwoedges.png", - L"blendthreecorners.png", - L"blendushape.png", - L"blendbad.png" - }; - size_t base = 0; // texture width/height (see below) - // for convenience, we require all alpha maps to be of the same BPP - // (avoids another ogl_tex_get_size call, and doesn't hurt) - size_t bpp = 0; - for(size_t i=0;i data; - AllocateAligned(data, total_w*total_h, maxSectorSize); - // for each tile on row - for (size_t i = 0; i < NUM_ALPHA_MAPS; i++) - { - // get src of copy - u8* src = 0; - ignore_result(ogl_tex_get_data(textures[i], &src)); - - size_t srcstep = bpp/8; - - // get destination of copy - u8* dst = data.get() + (i*tile_w); - - // for each row of image - for (size_t j = 0; j < base; j++) - { - // duplicate first pixel - *dst++ = *src; - *dst++ = *src; - - // copy a row - for (size_t k = 0; k < base; k++) - { - *dst++ = *src; - src += srcstep; - } - - // duplicate last pixel - *dst++ = *(src-srcstep); - *dst++ = *(src-srcstep); - - // advance write pointer for next row - dst += total_w-tile_w; - } - - result.m_AlphaMapCoords[i].u0 = float(i*tile_w+2) / float(total_w); - result.m_AlphaMapCoords[i].u1 = float((i+1)*tile_w-2) / float(total_w); - result.m_AlphaMapCoords[i].v0 = 0.0f; - result.m_AlphaMapCoords[i].v1 = 1.0f; - } - - for (size_t i = 0; i < NUM_ALPHA_MAPS; i++) - ignore_result(ogl_tex_free(textures[i])); - - // upload the composite texture - Tex t; - ignore_result(t.wrap(total_w, total_h, 8, TEX_GREY, data, 0)); - - // uncomment the following to save a png of the generated texture - // in the public/ directory, for debugging - /*VfsPath filename("blendtex.png"); - - DynArray da; - RETURN_STATUS_IF_ERR(tex_encode(&t, filename.Extension(), &da)); - - // write to disk - //Status ret = INFO::OK; - { - std::shared_ptr file = DummySharedPtr(da.base); - const ssize_t bytes_written = g_VFS->CreateFile(filename, file, da.pos); - if(bytes_written > 0) - ENSURE(bytes_written == (ssize_t)da.pos); - //else - // ret = (Status)bytes_written; - } - - ignore_result(da_free(&da));*/ - - Handle hCompositeAlphaMap = ogl_tex_wrap(&t, g_VFS, key); - ignore_result(ogl_tex_set_filter(hCompositeAlphaMap, GL_LINEAR)); - ignore_result(ogl_tex_set_wrap (hCompositeAlphaMap, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE)); - ogl_tex_upload(hCompositeAlphaMap, GL_ALPHA, 0, 0); - result.m_hCompositeAlphaMap = hCompositeAlphaMap; - - m_TerrainAlpha = it; -} diff -Nru 0ad-0.0.25b/source/graphics/TerrainTextureEntry.h 0ad-0.0.26/source/graphics/TerrainTextureEntry.h --- 0ad-0.0.25b/source/graphics/TerrainTextureEntry.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerrainTextureEntry.h 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,54 +18,22 @@ #ifndef INCLUDED_TERRAINTEXTUREENTRY #define INCLUDED_TERRAINTEXTUREENTRY -#include "TerrainTextureManager.h" -#include "TextureManager.h" -#include "Material.h" - -#include "lib/res/handle.h" +#include "graphics/Material.h" +#include "graphics/TerrainTextureManager.h" +#include "graphics/Texture.h" #include "lib/file/vfs/vfs_path.h" #include "maths/Matrix3D.h" #include "ps/CStr.h" #include -class XMBElement; -class CXeromyces; - -////////////////////////////////////////////////////////////////////////////////////////////////////////// // CTerrainTextureEntry: class wrapping a terrain texture object; contains various other required // elements - color of minimap, terrain "group" it belongs to, etc class CTerrainTextureEntry { public: - typedef std::vector GroupVector; - -private: - // Tag = file name stripped of path and extension (grass_dark_1) - CStr m_Tag; - - // The property sheet used by this texture - CTerrainPropertiesPtr m_pProperties; - - CMaterial m_Material; - - CMatrix3D m_TextureMatrix; - - // BGRA color of topmost mipmap level, for coloring minimap, or a color - // specified by the terrain properties - u32 m_BaseColor; - // ..Valid is true if the base color has been cached - bool m_BaseColorValid; - - // All terrain type groups we're a member of - GroupVector m_Groups; - - // calculate the root color of the texture, used for coloring minimap - void BuildBaseColor(); - - void LoadAlphaMaps(VfsPath &amtype); + using GroupVector = std::vector; -public: // Most of the texture's data is delay-loaded, so after the constructor has // been called, the texture entry is ready to be used. CTerrainTextureEntry(CTerrainPropertiesPtr props, const VfsPath& path); @@ -82,7 +50,12 @@ // Returns a matrix of the form [c 0 -s 0; -s 0 -c 0; 0 0 0 0; 0 0 0 1] // mapping world-space (x,y,z,1) coordinates onto (u,v,0,1) texcoords - const float* GetTextureMatrix() const; + const CMatrix3D& GetTextureMatrix() const { return m_TextureMatrix; } + + // Used in Atlas to retrieve a texture for previews. Can't use textures + // directly because they're required on CPU side. Another solution is to + // retrieve path from diffuse texture from material. + const VfsPath& GetDiffuseTexturePath() const { return m_DiffuseTexturePath; } // Get mipmap color in BGRA format u32 GetBaseColor() @@ -91,8 +64,32 @@ return m_BaseColor; } - //TerrainAlpha *m_TerrainAlpha; CTerrainTextureManager::TerrainAlphaMap::iterator m_TerrainAlpha; + +private: + // Tag = file name stripped of path and extension (grass_dark_1) + CStr m_Tag; + + VfsPath m_DiffuseTexturePath; + + // The property sheet used by this texture + CTerrainPropertiesPtr m_pProperties; + + CMaterial m_Material; + + CMatrix3D m_TextureMatrix; + + // BGRA color of topmost mipmap level, for coloring minimap, or a color + // specified by the terrain properties + u32 m_BaseColor; + // ..Valid is true if the base color has been cached + bool m_BaseColorValid; + + // All terrain type groups we're a member of + GroupVector m_Groups; + + // calculate the root color of the texture, used for coloring minimap + void BuildBaseColor(); }; #endif diff -Nru 0ad-0.0.25b/source/graphics/TerrainTextureManager.cpp 0ad-0.0.26/source/graphics/TerrainTextureManager.cpp --- 0ad-0.0.25b/source/graphics/TerrainTextureManager.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerrainTextureManager.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,23 +17,25 @@ #include "precompiled.h" -#include -#include - #include "TerrainTextureManager.h" -#include "TerrainTextureEntry.h" -#include "TerrainProperties.h" -#include "lib/res/graphics/ogl_tex.h" -#include "lib/ogl.h" +#include "graphics/TerrainTextureEntry.h" +#include "graphics/TerrainProperties.h" +#include "graphics/TextureManager.h" +#include "lib/allocators/shared_ptr.h" +#include "lib/bits.h" +#include "lib/tex/tex.h" #include "lib/timer.h" - #include "ps/CLogger.h" #include "ps/Filesystem.h" +#include "ps/VideoMode.h" #include "ps/XML/Xeromyces.h" +#include "renderer/backend/IDevice.h" +#include "renderer/Renderer.h" +#include #include - +#include CTerrainTextureManager::CTerrainTextureManager() : m_LastGroupIndex(0) @@ -51,10 +53,7 @@ UnloadTerrainTextures(); for (std::pair& ta : m_TerrainAlphas) - { - ogl_tex_free(ta.second.m_hCompositeAlphaMap); - ta.second.m_hCompositeAlphaMap = 0; - } + ta.second.m_CompositeAlphaMap.reset(); } void CTerrainTextureManager::UnloadTerrainTextures() @@ -141,6 +140,190 @@ return m_TerrainGroups[name] = new CTerrainGroup(name, ++m_LastGroupIndex); } +// LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and +// calculate the coordinate of each alphamap within this packed texture. +CTerrainTextureManager::TerrainAlphaMap::iterator +CTerrainTextureManager::LoadAlphaMap(const VfsPath& alphaMapType) +{ + const std::wstring key = L"(alpha map composite" + alphaMapType.string() + L")"; + + CTerrainTextureManager::TerrainAlphaMap::iterator it = m_TerrainAlphas.find(alphaMapType); + + if (it != g_TexMan.m_TerrainAlphas.end()) + return it; + + m_TerrainAlphas[alphaMapType] = TerrainAlpha(); + it = m_TerrainAlphas.find(alphaMapType); + + TerrainAlpha& result = it->second; + + // + // load all textures and store Handle in array + // + Tex textures[NUM_ALPHA_MAPS] = {}; + const VfsPath path = VfsPath("art/textures/terrain/alphamaps") / alphaMapType; + + const wchar_t* fnames[NUM_ALPHA_MAPS] = + { + L"blendcircle.png", + L"blendlshape.png", + L"blendedge.png", + L"blendedgecorner.png", + L"blendedgetwocorners.png", + L"blendfourcorners.png", + L"blendtwooppositecorners.png", + L"blendlshapecorner.png", + L"blendtwocorners.png", + L"blendcorner.png", + L"blendtwoedges.png", + L"blendthreecorners.png", + L"blendushape.png", + L"blendbad.png" + }; + size_t base = 0; // texture width/height (see below) + // For convenience, we require all alpha maps to be of the same BPP. + size_t bpp = 0; + for (size_t i = 0; i < NUM_ALPHA_MAPS; ++i) + { + // note: these individual textures can be discarded afterwards; + // we cache the composite. + std::shared_ptr fileData; + size_t fileSize; + if (g_VFS->LoadFile(path / fnames[i], fileData, fileSize) != INFO::OK || + textures[i].decode(fileData, fileSize) != INFO::OK) + { + m_TerrainAlphas.erase(it); + LOGERROR("Failed to load alphamap: %s", alphaMapType.string8()); + + const VfsPath standard("standard"); + if (path != standard) + return LoadAlphaMap(standard); + return m_TerrainAlphas.end(); + } + + // Get its size and make sure they are all equal. + // (the packing algo assumes this). + if (textures[i].m_Width != textures[i].m_Height) + DEBUG_DISPLAY_ERROR(L"Alpha maps are not square"); + // .. first iteration: establish size + if (i == 0) + { + base = textures[i].m_Width; + bpp = textures[i].m_Bpp; + } + // .. not first: make sure texture size matches + else if (base != textures[i].m_Width || bpp != textures[i].m_Bpp) + DEBUG_DISPLAY_ERROR(L"Alpha maps are not identically sized (including pixel depth)"); + } + + // + // copy each alpha map (tile) into one buffer, arrayed horizontally. + // + const size_t tileWidth = 2 + base + 2; // 2 pixel border (avoids bilinear filtering artifacts) + const size_t totalWidth = round_up_to_pow2(tileWidth * NUM_ALPHA_MAPS); + const size_t totalHeight = base; ENSURE(is_pow2(totalHeight)); + std::shared_ptr data; + AllocateAligned(data, totalWidth * totalHeight, maxSectorSize); + // for each tile on row + for (size_t i = 0; i < NUM_ALPHA_MAPS; ++i) + { + // get src of copy + u8* src = textures[i].get_data(); + ENSURE(src); + + const size_t srcStep = bpp / 8; + + // get destination of copy + u8* dst = data.get() + (i * tileWidth); + + // for each row of image + for (size_t j = 0; j < base; ++j) + { + // duplicate first pixel + *dst++ = *src; + *dst++ = *src; + + // copy a row + for (size_t k = 0; k < base; ++k) + { + *dst++ = *src; + src += srcStep; + } + + // duplicate last pixel + *dst++ = *(src - srcStep); + *dst++ = *(src - srcStep); + + // advance write pointer for next row + dst += totalWidth - tileWidth; + } + + result.m_AlphaMapCoords[i].u0 = static_cast(i * tileWidth + 2) / totalWidth; + result.m_AlphaMapCoords[i].u1 = static_cast((i + 1) * tileWidth - 2) / totalWidth; + result.m_AlphaMapCoords[i].v0 = 0.0f; + result.m_AlphaMapCoords[i].v1 = 1.0f; + } + + for (size_t i = 0; i < NUM_ALPHA_MAPS; ++i) + textures[i].free(); + + // Enable the following to save a png of the generated texture + // in the public/ directory, for debugging. +#if 0 + Tex t; + ignore_result(t.wrap(totalWidth, totalHeight, 8, TEX_GREY, data, 0)); + + const VfsPath filename("blendtex.png"); + + DynArray da; + RETURN_STATUS_IF_ERR(tex_encode(&t, filename.Extension(), &da)); + + // write to disk + //Status ret = INFO::OK; + { + std::shared_ptr file = DummySharedPtr(da.base); + const ssize_t bytes_written = g_VFS->CreateFile(filename, file, da.pos); + if (bytes_written > 0) + ENSURE(bytes_written == (ssize_t)da.pos); + //else + // ret = (Status)bytes_written; + } + + ignore_result(da_free(&da)); +#endif + + result.m_CompositeAlphaMap = g_VideoMode.GetBackendDevice()->CreateTexture2D("CompositeAlphaMap", + Renderer::Backend::Format::A8_UNORM, totalWidth, totalHeight, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); + + result.m_CompositeDataToUpload = std::move(data); + + m_AlphaMapsToUpload.emplace_back(it); + + return it; +} + +void CTerrainTextureManager::UploadResourcesIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + for (const CTerrainTextureManager::TerrainAlphaMap::iterator& it : m_AlphaMapsToUpload) + { + TerrainAlpha& alphaMap = it->second; + if (!alphaMap.m_CompositeDataToUpload) + continue; + // Upload the composite texture. + Renderer::Backend::ITexture* texture = alphaMap.m_CompositeAlphaMap.get(); + deviceCommandContext->UploadTexture( + texture, Renderer::Backend::Format::A8_UNORM, alphaMap.m_CompositeDataToUpload.get(), + texture->GetWidth() * texture->GetHeight()); + alphaMap.m_CompositeDataToUpload.reset(); + } + + m_AlphaMapsToUpload.clear(); +} + void CTerrainGroup::AddTerrain(CTerrainTextureEntry* pTerrain) { m_Terrains.push_back(pTerrain); diff -Nru 0ad-0.0.25b/source/graphics/TerrainTextureManager.h 0ad-0.0.26/source/graphics/TerrainTextureManager.h --- 0ad-0.0.25b/source/graphics/TerrainTextureManager.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerrainTextureManager.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,23 +18,21 @@ #ifndef INCLUDED_TERRAINTEXTUREMANAGER #define INCLUDED_TERRAINTEXTUREMANAGER -#include -#include -#include - -#include "lib/res/graphics/ogl_tex.h" -#include "lib/res/handle.h" #include "lib/file/vfs/vfs_path.h" #include "ps/CStr.h" #include "ps/Singleton.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/ITexture.h" + +#include +#include +#include // access to sole CTerrainTextureManager object #define g_TexMan CTerrainTextureManager::GetSingleton() #define NUM_ALPHA_MAPS 14 -class XMBElement; -class CXeromyces; class CTerrainTextureEntry; class CTerrainProperties; @@ -73,11 +71,14 @@ struct TerrainAlpha { - // ogl_tex handle of composite alpha map (all the alpha maps packed into one texture) - Handle m_hCompositeAlphaMap; - // coordinates of each (untransformed) alpha map within the packed texture - struct { - float u0,u1,v0,v1; + // Composite alpha map (all the alpha maps packed into one texture). + std::unique_ptr m_CompositeAlphaMap; + // Data is used to separate file loading and uploading to GPU. + std::shared_ptr m_CompositeDataToUpload; + // Coordinates of each (untransformed) alpha map within the packed texture. + struct + { + float u0, u1, v0, v1; } m_AlphaMapCoords[NUM_ALPHA_MAPS]; }; @@ -89,21 +90,9 @@ friend class CTerrainTextureEntry; public: - typedef std::map TerrainGroupMap; - typedef std::map TerrainAlphaMap; - -private: - // All texture entries created by this class, for easy freeing now that - // textures may be in several STextureType's - std::vector m_TextureEntries; + using TerrainGroupMap = std::map; + using TerrainAlphaMap = std::map; - TerrainGroupMap m_TerrainGroups; - - TerrainAlphaMap m_TerrainAlphas; - - size_t m_LastGroupIndex; - -public: // constructor, destructor CTerrainTextureManager(); ~CTerrainTextureManager(); @@ -129,7 +118,25 @@ const TerrainGroupMap& GetGroups() const { return m_TerrainGroups; } -}; + CTerrainTextureManager::TerrainAlphaMap::iterator LoadAlphaMap(const VfsPath& alphaMapType); + + void UploadResourcesIfNeeded(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + +private: + // All texture entries created by this class, for easy freeing now that + // textures may be in several STextureType's + std::vector m_TextureEntries; + + TerrainGroupMap m_TerrainGroups; + + TerrainAlphaMap m_TerrainAlphas; + + size_t m_LastGroupIndex; + + // A way to separate file loading and uploading to GPU to not stall uploading. + // Once we get a properly threaded loading we might optimize that. + std::vector m_AlphaMapsToUpload; +}; -#endif +#endif // INCLUDED_TERRAINTEXTUREMANAGER diff -Nru 0ad-0.0.25b/source/graphics/TerritoryTexture.cpp 0ad-0.0.26/source/graphics/TerritoryTexture.cpp --- 0ad-0.0.25b/source/graphics/TerritoryTexture.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerritoryTexture.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,8 @@ #include "graphics/Terrain.h" #include "lib/bits.h" #include "ps/Profile.h" +#include "renderer/backend/IDevice.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/Renderer.h" #include "simulation2/Simulation2.h" #include "simulation2/helpers/Grid.h" @@ -35,20 +37,18 @@ // TODO: There's a lot of duplication with CLOSTexture - might be nice to refactor a bit CTerritoryTexture::CTerritoryTexture(CSimulation2& simulation) : - m_Simulation(simulation), m_DirtyID(0), m_Texture(0), m_MapSize(0), m_TextureSize(0) + m_Simulation(simulation), m_DirtyID(0), m_MapSize(0) { } CTerritoryTexture::~CTerritoryTexture() { - if (m_Texture) - DeleteTexture(); + DeleteTexture(); } void CTerritoryTexture::DeleteTexture() { - glDeleteTextures(1, &m_Texture); - m_Texture = 0; + m_Texture.reset(); } bool CTerritoryTexture::UpdateDirty() @@ -57,35 +57,25 @@ return cmpTerritoryManager && cmpTerritoryManager->NeedUpdateTexture(&m_DirtyID); } -void CTerritoryTexture::BindTexture(int unit) +Renderer::Backend::ITexture* CTerritoryTexture::GetTexture() { - if (UpdateDirty()) - RecomputeTexture(unit); - - g_Renderer.BindTexture(unit, m_Texture); -} - -GLuint CTerritoryTexture::GetTexture() -{ - if (UpdateDirty()) - RecomputeTexture(0); - - return m_Texture; + ENSURE(!UpdateDirty()); + return m_Texture.get(); } -const float* CTerritoryTexture::GetTextureMatrix() +const CMatrix3D& CTerritoryTexture::GetTextureMatrix() { ENSURE(!UpdateDirty()); - return &m_TextureMatrix._11; + return m_TextureMatrix; } -const CMatrix3D* CTerritoryTexture::GetMinimapTextureMatrix() +const CMatrix3D& CTerritoryTexture::GetMinimapTextureMatrix() { ENSURE(!UpdateDirty()); - return &m_MinimapTextureMatrix; + return m_MinimapTextureMatrix; } -void CTerritoryTexture::ConstructTexture(int unit) +void CTerritoryTexture::ConstructTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { CmpPtr cmpTerrain(m_Simulation, SYSTEM_ENTITY); if (!cmpTerrain) @@ -94,22 +84,22 @@ // Convert size from terrain tiles to territory tiles m_MapSize = cmpTerrain->GetMapSize() * Pathfinding::NAVCELL_SIZE_INT / ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE; - m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); + const uint32_t textureSize = round_up_to_pow2(static_cast(m_MapSize)); - glGenTextures(1, &m_Texture); - g_Renderer.BindTexture(unit, m_Texture); + m_Texture = deviceCommandContext->GetDevice()->CreateTexture2D("TerritoryTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, textureSize, textureSize, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); // Initialise texture with transparency, for the areas we don't - // overwrite with glTexSubImage2D later - u8* texData = new u8[m_TextureSize * m_TextureSize * 4]; - memset(texData, 0x00, m_TextureSize * m_TextureSize * 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); - delete[] texData; - - 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_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // overwrite with uploading later. + std::unique_ptr texData = std::make_unique(textureSize * textureSize * 4); + memset(texData.get(), 0x00, textureSize * textureSize * 4); + deviceCommandContext->UploadTexture( + m_Texture.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + texData.get(), textureSize * textureSize * 4); + texData.reset(); { // Texture matrix: We want to map @@ -118,7 +108,7 @@ // world pos (mapsize*cellsize, y, mapsize*cellsize) (i.e. top-right of last tile) // onto texcoord (mapsize / texsize, mapsize / texsize) (i.e. top-right of last texel) - float s = 1.f / (float)(m_TextureSize * TERRAIN_TILE_SIZE); + float s = 1.f / static_cast(textureSize * TERRAIN_TILE_SIZE); float t = 0.f; m_TextureMatrix.SetZero(); m_TextureMatrix._11 = s; @@ -131,7 +121,7 @@ { // Minimap matrix: We want to map UV (0,0)-(1,1) onto (0,0)-(mapsize/texsize, mapsize/texsize) - float s = m_MapSize / (float)m_TextureSize; + float s = m_MapSize / static_cast(textureSize); m_MinimapTextureMatrix.SetZero(); m_MinimapTextureMatrix._11 = s; m_MinimapTextureMatrix._22 = s; @@ -139,7 +129,7 @@ } } -void CTerritoryTexture::RecomputeTexture(int unit) +void CTerritoryTexture::RecomputeTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { // If the map was resized, delete and regenerate the texture if (m_Texture) @@ -150,7 +140,7 @@ } if (!m_Texture) - ConstructTexture(unit); + ConstructTexture(deviceCommandContext); PROFILE("recompute territory texture"); @@ -158,11 +148,12 @@ if (!cmpTerritoryManager) return; - std::vector bitmap(m_MapSize * m_MapSize * 4); - GenerateBitmap(cmpTerritoryManager->GetTerritoryGrid(), &bitmap[0], m_MapSize, m_MapSize); + std::unique_ptr bitmap = std::make_unique(m_MapSize * m_MapSize * 4); + GenerateBitmap(cmpTerritoryManager->GetTerritoryGrid(), bitmap.get(), m_MapSize, m_MapSize); - g_Renderer.BindTexture(unit, m_Texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize, m_MapSize, GL_RGBA, GL_UNSIGNED_BYTE, &bitmap[0]); + deviceCommandContext->UploadTextureRegion( + m_Texture.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, bitmap.get(), m_MapSize * m_MapSize * 4, + 0, 0, m_MapSize, m_MapSize); } void CTerritoryTexture::GenerateBitmap(const Grid& territories, u8* bitmap, ssize_t w, ssize_t h) @@ -254,3 +245,9 @@ if (bitmap[(j*w+i)*4 + 3] == alphaMax) bitmap[(j*w+i)*4 + 3] = 0; } + +void CTerritoryTexture::UpdateIfNeeded(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + if (UpdateDirty()) + RecomputeTexture(deviceCommandContext); +} diff -Nru 0ad-0.0.25b/source/graphics/TerritoryTexture.h 0ad-0.0.26/source/graphics/TerritoryTexture.h --- 0ad-0.0.25b/source/graphics/TerritoryTexture.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TerritoryTexture.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,9 +15,9 @@ * along with 0 A.D. If not, see . */ -#include "lib/ogl.h" - #include "maths/Matrix3D.h" +#include "renderer/backend/ITexture.h" +#include "renderer/backend/IDeviceCommandContext.h" class CSimulation2; template @@ -36,33 +36,31 @@ ~CTerritoryTexture(); /** - * Recomputes the territory texture if necessary, and binds it to the requested - * texture unit. - * Also switches the current active texture unit, and enables texturing on it. - * The texture is in 32-bit BGRA format. - */ - void BindTexture(int unit); - - /** * Recomputes the territory texture if necessary, and returns the texture handle. * Also potentially switches the current active texture unit, and enables texturing on it. * The texture is in 32-bit BGRA format. */ - GLuint GetTexture(); + Renderer::Backend::ITexture* GetTexture(); /** * Returns a matrix to map (x,y,z) world coordinates onto (u,v) texture - * coordinates, in the form expected by glLoadMatrixf. - * This must only be called after BindTexture. + * coordinates, in the form expected by a matrix uniform. + * This must only be called after UpdateIfNeeded. */ - const float* GetTextureMatrix(); + const CMatrix3D& GetTextureMatrix(); /** * Returns a matrix to map (0,0)-(1,1) texture coordinates onto texture - * coordinates, in the form expected by glLoadMatrixf. - * This must only be called after BindTexture. + * coordinates, in the form expected by a matrix uniform. + * This must only be called after UpdateIfNeeded. + */ + const CMatrix3D& GetMinimapTextureMatrix(); + + /** + * Updates the texture if needed (territory was changed or the texture + * wasn't created). */ - const CMatrix3D* GetMinimapTextureMatrix(); + void UpdateIfNeeded(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); private: /** @@ -71,8 +69,8 @@ bool UpdateDirty(); void DeleteTexture(); - void ConstructTexture(int unit); - void RecomputeTexture(int unit); + void ConstructTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + void RecomputeTexture(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); void GenerateBitmap(const Grid& territories, u8* bitmap, ssize_t w, ssize_t h); @@ -80,10 +78,9 @@ size_t m_DirtyID; - GLuint m_Texture; + std::unique_ptr m_Texture; ssize_t m_MapSize; // tiles per side - GLsizei m_TextureSize; // texels per side CMatrix3D m_TextureMatrix; CMatrix3D m_MinimapTextureMatrix; diff -Nru 0ad-0.0.25b/source/graphics/tests/test_TextureConverter.h 0ad-0.0.26/source/graphics/tests/test_TextureConverter.h --- 0ad-0.0.25b/source/graphics/tests/test_TextureConverter.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/graphics/tests/test_TextureConverter.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ #include "graphics/TextureConverter.h" #include "lib/file/vfs/vfs.h" -#include "lib/res/h_mgr.h" #include "lib/tex/tex.h" #include "ps/XML/Xeromyces.h" @@ -86,11 +85,19 @@ TS_ASSERT_DIFFERS(texdata[0*4], texdata[8*4]); TS_ASSERT_EQUALS(texdata[8*4], texdata[16*4]); TS_ASSERT_DIFFERS(texdata[16*4], texdata[24*4]); + } + + void test_not_pot() + { + // CTextureConverter prints to logs in case of an error. + TestLogger logger; -// for (size_t i = 0; i < tex.dataSize; ++i) -// { -// if (i % 4 == 0) printf("\n"); -// printf("%02x ", texdata[i]); -// } + const VfsPath path = L"art/textures/b/npot.png"; + + CTextureConverter converter(m_VFS, false); + CTextureConverter::Settings settings = + converter.ComputeSettings(L"", std::vector()); + TS_ASSERT(!converter.ConvertTexture(CTexturePtr(), path, L"cache/npot.png", settings)); + TS_ASSERT(logger.GetOutput().find("be power of two") != std::string::npos); } }; diff -Nru 0ad-0.0.25b/source/graphics/tests/test_TextureManager.h 0ad-0.0.26/source/graphics/tests/test_TextureManager.h --- 0ad-0.0.25b/source/graphics/tests/test_TextureManager.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/tests/test_TextureManager.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,44 +20,47 @@ #include "graphics/TextureManager.h" #include "lib/external_libraries/libsdl.h" #include "lib/file/vfs/vfs.h" -#include "lib/res/h_mgr.h" #include "lib/tex/tex.h" -#include "lib/ogl.h" +#include "ps/ConfigDB.h" #include "ps/XML/Xeromyces.h" +#include "renderer/backend/dummy/Device.h" class TestTextureManager : public CxxTest::TestSuite { PIVFS m_VFS; + std::unique_ptr m_Device; public: void setUp() { + CConfigDB::Initialise(); + DeleteDirectory(DataDir()/"_testcache"); // clean up in case the last test run failed m_VFS = CreateVfs(); TS_ASSERT_OK(m_VFS->Mount(L"", DataDir() / "mods" / "_test.tex" / "", VFS_MOUNT_MUST_EXIST)); TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); - h_mgr_init(); - CXeromyces::Startup(); + + m_Device = std::make_unique(); } void tearDown() { CXeromyces::Terminate(); - h_mgr_shutdown(); - m_VFS.reset(); DeleteDirectory(DataDir()/"_testcache"); + + CConfigDB::Shutdown(); } void test_load_basic() { { - CTextureManager texman(m_VFS, false, true); + CTextureManager texman(m_VFS, false, m_Device.get()); CTexturePtr t1 = texman.CreateTexture(CTextureProperties(L"art/textures/a/demo.png")); @@ -88,7 +91,7 @@ // New texture manager - should use the cached file { - CTextureManager texman(m_VFS, false, true); + CTextureManager texman(m_VFS, false, m_Device.get()); CTexturePtr t1 = texman.CreateTexture(CTextureProperties(L"art/textures/a/demo.png")); @@ -100,7 +103,7 @@ void test_load_formats() { - CTextureManager texman(m_VFS, false, true); + CTextureManager texman(m_VFS, false, m_Device.get()); CTexturePtr t1 = texman.CreateTexture(CTextureProperties(L"art/textures/a/demo.tga")); CTexturePtr t2 = texman.CreateTexture(CTextureProperties(L"art/textures/a/demo-abgr.dds")); CTexturePtr t3 = texman.CreateTexture(CTextureProperties(L"art/textures/a/demo-dxt1.dds")); diff -Nru 0ad-0.0.25b/source/graphics/TextRenderer.cpp 0ad-0.0.26/source/graphics/TextRenderer.cpp --- 0ad-0.0.25b/source/graphics/TextRenderer.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TextRenderer.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,7 +22,7 @@ #include "graphics/Font.h" #include "graphics/FontManager.h" #include "graphics/ShaderProgram.h" -#include "lib/ogl.h" +#include "graphics/TextureManager.h" #include "maths/Matrix3D.h" #include "ps/CStrIntern.h" #include "ps/CStrInternStatic.h" @@ -201,7 +201,9 @@ } }; -void CTextRenderer::Render(const CShaderProgramPtr& shader, const CMatrix3D& transform) +void CTextRenderer::Render( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, const CMatrix3D& transform) { std::vector indexes; std::vector vertexes; @@ -222,6 +224,13 @@ ++it; } + const int32_t texBindingSlot = shader->GetBindingSlot(str_tex); + const int32_t transformBindingSlot = shader->GetBindingSlot(str_transform); + const int32_t colorAddBindingSlot = shader->GetBindingSlot(str_colorAdd); + const int32_t colorMulBindingSlot = shader->GetBindingSlot(str_colorMul); + + bool transformChanged = false; + CTexture* lastTexture = nullptr; for (std::list::iterator it = m_Batches.begin(); it != m_Batches.end(); ++it) { @@ -232,34 +241,54 @@ if (lastTexture != batch.font->GetTexture().get()) { lastTexture = batch.font->GetTexture().get(); - shader->BindTexture(str_tex, batch.font->GetTexture()); + lastTexture->UploadBackendTextureIfNeeded(deviceCommandContext); + deviceCommandContext->SetTexture(texBindingSlot, lastTexture->GetBackendTexture()); } - CMatrix3D translation; - translation.SetTranslation(batch.translate.X, batch.translate.Y, 0.0f); - shader->Uniform(str_transform, transform * translation); + if (batch.translate.X != 0.0f || batch.translate.Y != 0.0f) + { + CMatrix3D localTransform; + localTransform.SetTranslation(batch.translate.X, batch.translate.Y, 0.0f); + localTransform = transform * localTransform; + deviceCommandContext->SetUniform(transformBindingSlot, localTransform.AsFloatArray()); + transformChanged = true; + } // ALPHA-only textures will have .rgb sampled as 0, so we need to // replace it with white (but not affect RGBA textures) if (batch.font->HasRGB()) - shader->Uniform(str_colorAdd, CColor(0.0f, 0.0f, 0.0f, 0.0f)); + deviceCommandContext->SetUniform(colorAddBindingSlot, 0.0f, 0.0f, 0.0f, 0.0f); else - shader->Uniform(str_colorAdd, CColor(batch.color.r, batch.color.g, batch.color.b, 0.0f)); + deviceCommandContext->SetUniform(colorAddBindingSlot, batch.color.r, batch.color.g, batch.color.b, 0.0f); - shader->Uniform(str_colorMul, batch.color); + deviceCommandContext->SetUniform(colorMulBindingSlot, batch.color.AsFloatArray()); vertexes.resize(std::min(MAX_CHAR_COUNT_PER_BATCH, batch.chars) * 4); indexes.resize(std::min(MAX_CHAR_COUNT_PER_BATCH, batch.chars) * 6); size_t idx = 0; - auto flush = [&idx, &vertexes, &indexes, &shader]() -> void { + auto flush = [deviceCommandContext, &idx, &vertexes, &indexes]() -> void + { if (idx == 0) return; - shader->VertexPointer(2, GL_SHORT, sizeof(t2f_v2i), &vertexes[0].x); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(t2f_v2i), &vertexes[0].u); - glDrawElements(GL_TRIANGLES, idx * 6, GL_UNSIGNED_SHORT, &indexes[0]); + const uint32_t stride = sizeof(t2f_v2i); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R16G16_SINT, offsetof(t2f_v2i, x), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, offsetof(t2f_v2i, u), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBufferData( + 0, vertexes.data(), vertexes.size() * sizeof(vertexes[0])); + deviceCommandContext->SetIndexBufferData(indexes.data(), indexes.size() * sizeof(indexes[0])); + + deviceCommandContext->DrawIndexed(0, idx * 6, 0); idx = 0; }; @@ -316,4 +345,7 @@ } m_Batches.clear(); + + if (transformChanged) + deviceCommandContext->SetUniform(transformBindingSlot, transform.AsFloatArray()); } diff -Nru 0ad-0.0.25b/source/graphics/TextRenderer.h 0ad-0.0.26/source/graphics/TextRenderer.h --- 0ad-0.0.25b/source/graphics/TextRenderer.h 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TextRenderer.h 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,10 +19,11 @@ #define INCLUDED_TEXTRENDERER #include "graphics/Color.h" -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" #include "maths/Rect.h" #include "maths/Vector2D.h" #include "ps/CStrIntern.h" +#include "renderer/backend/IDeviceCommandContext.h" #include @@ -45,7 +46,7 @@ /** * Set clipping rectangle, in pre-transform coordinates (i.e. text is clipped against * this rect based purely on the x,y values passed into Put()). Text fully outside the - * clipping rectangle may not be rendered. Should be used in conjunction with glScissor + * clipping rectangle may not be rendered. Should be used in conjunction with SetScissors * for precise clipping - this is just an optimisation. */ void SetClippingRect(const CRect& rect); @@ -102,7 +103,9 @@ /** * Render all of the previously printed text calls. */ - void Render(const CShaderProgramPtr& shader, const CMatrix3D& transform); + void Render( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, const CMatrix3D& transform); private: friend struct SBatchCompare; diff -Nru 0ad-0.0.25b/source/graphics/TextureConverter.cpp 0ad-0.0.26/source/graphics/TextureConverter.cpp --- 0ad-0.0.25b/source/graphics/TextureConverter.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TextureConverter.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,15 +19,17 @@ #include "TextureConverter.h" -#include "lib/regex.h" -#include "lib/timer.h" #include "lib/allocators/shared_ptr.h" +#include "lib/bits.h" +#include "lib/regex.h" #include "lib/tex/tex.h" +#include "lib/timer.h" #include "maths/MD5.h" #include "ps/CLogger.h" #include "ps/CStr.h" #include "ps/Profiler2.h" #include "ps/Threading.h" +#include "ps/Util.h" #include "ps/XML/Xeromyces.h" #if CONFIG2_NVTT @@ -341,9 +343,17 @@ } Tex tex; - if (tex.decode(file, fileSize) < 0) + const Status decodeStatus = tex.decode(file, fileSize); + if (decodeStatus != INFO::OK) + { + LOGERROR("Failed to decode texture \"%s\" %s", src.string8(), GetStatusAsString(decodeStatus).c_str()); + return false; + } + + if (!is_pow2(tex.m_Width) || !is_pow2(tex.m_Height)) { - LOGERROR("Failed to decode texture \"%s\"", src.string8()); + LOGERROR("Texture to convert \"%s\" should have width and height be power of two: %zux%zu", + src.string8(), tex.m_Width, tex.m_Height); return false; } diff -Nru 0ad-0.0.25b/source/graphics/TextureManager.cpp 0ad-0.0.26/source/graphics/TextureManager.cpp --- 0ad-0.0.25b/source/graphics/TextureManager.cpp 2021-07-27 21:56:54.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TextureManager.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,91 +22,301 @@ #include "graphics/Color.h" #include "graphics/TextureConverter.h" #include "lib/allocators/shared_ptr.h" +#include "lib/bits.h" #include "lib/file/vfs/vfs_tree.h" #include "lib/hash.h" -#include "lib/res/graphics/ogl_tex.h" -#include "lib/res/h_mgr.h" #include "lib/timer.h" +#include "maths/MathUtil.h" #include "maths/MD5.h" #include "ps/CacheLoader.h" #include "ps/CLogger.h" +#include "ps/ConfigDB.h" #include "ps/Filesystem.h" #include "ps/Profile.h" +#include "ps/Util.h" +#include "renderer/backend/IDevice.h" +#include "renderer/Renderer.h" +#include #include #include #include +#include #include #include -class SingleColorTexture +namespace +{ + +Renderer::Backend::Format ChooseFormatAndTransformTextureDataIfNeeded(Tex& textureData, const bool hasS3TC) +{ + const bool alpha = (textureData.m_Flags & TEX_ALPHA) != 0; + const bool grey = (textureData.m_Flags & TEX_GREY) != 0; + const size_t dxt = textureData.m_Flags & TEX_DXT; + + // Some backends don't support BGR as an internal format (like GLES). + // TODO: add a check that the format is internally supported. + if ((textureData.m_Flags & TEX_BGR) != 0) + { + LOGWARNING("Using slow path to convert BGR texture."); + textureData.transform_to(textureData.m_Flags & ~TEX_BGR); + } + + if (dxt) + { + if (hasS3TC) + { + switch (dxt) + { + case DXT1A: + return Renderer::Backend::Format::BC1_RGBA_UNORM; + case 1: + return Renderer::Backend::Format::BC1_RGB_UNORM; + case 3: + return Renderer::Backend::Format::BC2_UNORM; + case 5: + return Renderer::Backend::Format::BC3_UNORM; + default: + LOGERROR("Unknown DXT compression."); + return Renderer::Backend::Format::UNDEFINED; + } + } + else + textureData.transform_to(textureData.m_Flags & ~TEX_DXT); + } + + switch (textureData.m_Bpp) + { + case 8: + ENSURE(grey); + return Renderer::Backend::Format::L8_UNORM; + case 24: + ENSURE(!alpha); + return Renderer::Backend::Format::R8G8B8_UNORM; + case 32: + ENSURE(alpha); + return Renderer::Backend::Format::R8G8B8A8_UNORM; + default: + LOGERROR("Unsupported BPP: %zu", textureData.m_Bpp); + } + + return Renderer::Backend::Format::UNDEFINED; +} + +} // anonymous namespace + +class CPredefinedTexture { public: - SingleColorTexture(const CColor& color, PIVFS vfs, const VfsPath& pathPlaceholder, const bool disableGL, CTextureManagerImpl* textureManager) - : m_Handle(0) + const CTexturePtr& GetTexture() { - if (disableGL) - return; + return m_Texture; + } - const SColor4ub color32 = color.AsSColor4ub(); - // Construct 1x1 32-bit texture - std::shared_ptr data(new u8[4], ArrayDeleter()); - data.get()[0] = color32.R; - data.get()[1] = color32.G; - data.get()[2] = color32.B; - data.get()[3] = color32.A; - - Tex t; - ignore_result(t.wrap(1, 1, 32, TEX_ALPHA, data, 0)); - - m_Handle = ogl_tex_wrap(&t, vfs, pathPlaceholder); - ignore_result(ogl_tex_set_filter(m_Handle, GL_LINEAR)); - if (!disableGL) - ignore_result(ogl_tex_upload(m_Handle)); - - CTextureProperties props(pathPlaceholder); - m_Texture = CTexturePtr(new CTexture(m_Handle, props, textureManager)); - m_Texture->m_State = CTexture::LOADED; + void CreateTexture( + std::unique_ptr backendTexture, + CTextureManagerImpl* textureManager) + { + Renderer::Backend::ITexture* fallback = backendTexture.get(); + CTextureProperties props(VfsPath{}); + m_Texture = CTexturePtr(new CTexture( + std::move(backendTexture), fallback, props, textureManager)); + m_Texture->m_State = CTexture::UPLOADED; m_Texture->m_Self = m_Texture; } - ~SingleColorTexture() +private: + CTexturePtr m_Texture; +}; + +class CSingleColorTexture final : public CPredefinedTexture +{ +public: + CSingleColorTexture(const CColor& color, Renderer::Backend::IDevice* device, + CTextureManagerImpl* textureManager) + : m_Color(color) + { + std::stringstream textureName; + textureName << "SingleColorTexture ("; + textureName << "R:" << m_Color.r << ", "; + textureName << "G:" << m_Color.g << ", "; + textureName << "B:" << m_Color.b << ", "; + textureName << "A:" << m_Color.a << ")"; + + std::unique_ptr backendTexture = + device->CreateTexture2D( + textureName.str().c_str(), + Renderer::Backend::Format::R8G8B8A8_UNORM, + 1, 1, Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::REPEAT)); + CreateTexture(std::move(backendTexture), textureManager); + } + + void Upload(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - ignore_result(ogl_tex_free(m_Handle)); + if (!GetTexture() || !GetTexture()->GetBackendTexture()) + return; + + const SColor4ub color32 = m_Color.AsSColor4ub(); + // Construct 1x1 32-bit texture + const u8 data[4] = + { + color32.R, + color32.G, + color32.B, + color32.A + }; + deviceCommandContext->UploadTexture(GetTexture()->GetBackendTexture(), + Renderer::Backend::Format::R8G8B8A8_UNORM, data, std::size(data)); } - CTexturePtr GetTexture() +private: + CColor m_Color; +}; + +class CSingleColorTextureCube final : public CPredefinedTexture +{ +public: + CSingleColorTextureCube(const CColor& color, Renderer::Backend::IDevice* device, + CTextureManagerImpl* textureManager) + : m_Color(color) + { + std::stringstream textureName; + textureName << "SingleColorTextureCube ("; + textureName << "R:" << m_Color.r << ", "; + textureName << "G:" << m_Color.g << ", "; + textureName << "B:" << m_Color.b << ", "; + textureName << "A:" << m_Color.a << ")"; + + std::unique_ptr backendTexture = + device->CreateTexture( + textureName.str().c_str(), Renderer::Backend::ITexture::Type::TEXTURE_CUBE, + Renderer::Backend::Format::R8G8B8A8_UNORM, + 1, 1, Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1); + CreateTexture(std::move(backendTexture), textureManager); + } + + void Upload(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - return m_Texture; + if (!GetTexture() || !GetTexture()->GetBackendTexture()) + return; + + const SColor4ub color32 = m_Color.AsSColor4ub(); + // Construct 1x1 32-bit texture + const u8 data[4] = + { + color32.R, + color32.G, + color32.B, + color32.A + }; + + for (size_t face = 0; face < 6; ++face) + { + deviceCommandContext->UploadTexture( + GetTexture()->GetBackendTexture(), Renderer::Backend::Format::R8G8B8A8_UNORM, + data, std::size(data), 0, face); + } } - Handle GetHandle() +private: + CColor m_Color; +}; + +class CGradientTexture final : public CPredefinedTexture +{ +public: + static const uint32_t WIDTH = 256; + static const uint32_t NUMBER_OF_LEVELS = 9; + + CGradientTexture(const CColor& colorFrom, const CColor& colorTo, + Renderer::Backend::IDevice* device, CTextureManagerImpl* textureManager) + : m_ColorFrom(colorFrom), m_ColorTo(colorTo) + { + std::stringstream textureName; + textureName << "GradientTexture"; + textureName << " From ("; + textureName << "R:" << m_ColorFrom.r << ", "; + textureName << "G:" << m_ColorFrom.g << ", "; + textureName << "B:" << m_ColorFrom.b << ", "; + textureName << "A:" << m_ColorFrom.a << ")"; + textureName << " To ("; + textureName << "R:" << m_ColorTo.r << ","; + textureName << "G:" << m_ColorTo.g << ","; + textureName << "B:" << m_ColorTo.b << ","; + textureName << "A:" << m_ColorTo.a << ")"; + + std::unique_ptr backendTexture = + device->CreateTexture2D( + textureName.str().c_str(), + Renderer::Backend::Format::R8G8B8A8_UNORM, + WIDTH, 1, Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), + NUMBER_OF_LEVELS); + CreateTexture(std::move(backendTexture), textureManager); + } + + void Upload(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - return m_Handle; + if (!GetTexture() || !GetTexture()->GetBackendTexture()) + return; + + std::array, WIDTH> data; + for (uint32_t x = 0; x < WIDTH; ++x) + { + const float t = static_cast(x) / (WIDTH - 1); + const CColor color( + Interpolate(m_ColorFrom.r, m_ColorTo.r, t), + Interpolate(m_ColorFrom.g, m_ColorTo.g, t), + Interpolate(m_ColorFrom.b, m_ColorTo.b, t), + Interpolate(m_ColorFrom.a, m_ColorTo.a, t)); + const SColor4ub color32 = color.AsSColor4ub(); + data[x][0] = color32.R; + data[x][1] = color32.G; + data[x][2] = color32.B; + data[x][3] = color32.A; + } + for (uint32_t level = 0; level < NUMBER_OF_LEVELS; ++level) + { + deviceCommandContext->UploadTexture(GetTexture()->GetBackendTexture(), + Renderer::Backend::Format::R8G8B8A8_UNORM, data.data(), (WIDTH >> level) * data[0].size(), level); + // Prepare data for the next level. + const uint32_t nextLevelWidth = (WIDTH >> (level + 1)); + if (nextLevelWidth > 0) + { + for (uint32_t x = 0; x < nextLevelWidth; ++x) + data[x] = data[(x << 1)]; + // Border values should be the same. + data[nextLevelWidth - 1] = data[(WIDTH >> level) - 1]; + } + } } private: - Handle m_Handle; - CTexturePtr m_Texture; + CColor m_ColorFrom, m_ColorTo; }; struct TPhash { - std::size_t operator()(CTextureProperties const& a) const + std::size_t operator()(const CTextureProperties& textureProperties) const { std::size_t seed = 0; - hash_combine(seed, m_PathHash(a.m_Path)); - hash_combine(seed, a.m_Filter); - hash_combine(seed, a.m_WrapS); - hash_combine(seed, a.m_WrapT); - hash_combine(seed, a.m_Aniso); - hash_combine(seed, a.m_Format); + hash_combine(seed, m_PathHash(textureProperties.m_Path)); + hash_combine(seed, textureProperties.m_AddressModeU); + hash_combine(seed, textureProperties.m_AddressModeV); + hash_combine(seed, textureProperties.m_AnisotropicFilterEnabled); + hash_combine(seed, textureProperties.m_FormatOverride); + hash_combine(seed, textureProperties.m_IgnoreQuality); return seed; } - std::size_t operator()(CTexturePtr const& a) const + std::size_t operator()(const CTexturePtr& texture) const { - return (*this)(a->m_Properties); + return this->operator()(texture->m_Properties); } private: @@ -115,15 +325,20 @@ struct TPequal_to { - bool operator()(CTextureProperties const& a, CTextureProperties const& b) const + bool operator()(const CTextureProperties& lhs, const CTextureProperties& rhs) const { - return a.m_Path == b.m_Path && a.m_Filter == b.m_Filter - && a.m_WrapS == b.m_WrapS && a.m_WrapT == b.m_WrapT - && a.m_Aniso == b.m_Aniso && a.m_Format == b.m_Format; + return + lhs.m_Path == rhs.m_Path && + lhs.m_AddressModeU == rhs.m_AddressModeU && + lhs.m_AddressModeV == rhs.m_AddressModeV && + lhs.m_AnisotropicFilterEnabled == rhs.m_AnisotropicFilterEnabled && + lhs.m_FormatOverride == rhs.m_FormatOverride && + lhs.m_IgnoreQuality == rhs.m_IgnoreQuality; } - bool operator()(CTexturePtr const& a, CTexturePtr const& b) const + + bool operator()(const CTexturePtr& lhs, const CTexturePtr& rhs) const { - return (*this)(a->m_Properties, b->m_Properties); + return this->operator()(lhs->m_Properties, rhs->m_Properties); } }; @@ -131,66 +346,65 @@ { friend class CTexture; public: - CTextureManagerImpl(PIVFS vfs, bool highQuality, bool disableGL) : - m_VFS(vfs), m_CacheLoader(vfs, L".dds"), m_DisableGL(disableGL), - m_TextureConverter(vfs, highQuality), m_DefaultHandle(0), - m_ErrorTexture(CColor(1.0f, 0.0f, 1.0f, 1.0f), vfs, L"(error texture)", disableGL, this), - m_WhiteTexture(CColor(1.0f, 1.0f, 1.0f, 1.0f), vfs, L"(white texture)", disableGL, this), - m_TransparentTexture(CColor(0.0f, 0.0f, 0.0f, 0.0f), vfs, L"(transparent texture)", disableGL, this) - { - // Initialise some textures that will always be available, - // without needing to load any files - - // Default placeholder texture (grey) - if (!m_DisableGL) - { - // Construct 1x1 24-bit texture - std::shared_ptr data(new u8[3], ArrayDeleter()); - data.get()[0] = 64; - data.get()[1] = 64; - data.get()[2] = 64; - Tex t; - ignore_result(t.wrap(1, 1, 24, 0, data, 0)); - - m_DefaultHandle = ogl_tex_wrap(&t, m_VFS, L"(default texture)"); - ignore_result(ogl_tex_set_filter(m_DefaultHandle, GL_LINEAR)); - if (!m_DisableGL) - ignore_result(ogl_tex_upload(m_DefaultHandle)); - } - + CTextureManagerImpl(PIVFS vfs, bool highQuality, Renderer::Backend::IDevice* device) : + m_VFS(vfs), m_CacheLoader(vfs, L".dds"), m_Device(device), + m_TextureConverter(vfs, highQuality), + m_DefaultTexture(CColor(0.25f, 0.25f, 0.25f, 1.0f), device, this), + m_ErrorTexture(CColor(1.0f, 0.0f, 1.0f, 1.0f), device, this), + m_WhiteTexture(CColor(1.0f, 1.0f, 1.0f, 1.0f), device, this), + m_TransparentTexture(CColor(0.0f, 0.0f, 0.0f, 0.0f), device, this), + m_AlphaGradientTexture( + CColor(1.0f, 1.0f, 1.0f, 0.0f), CColor(1.0f, 1.0f, 1.0f, 1.0f), device, this), + m_BlackTextureCube(CColor(0.0f, 0.0f, 0.0f, 1.0f), device, this) + { // Allow hotloading of textures RegisterFileReloadFunc(ReloadChangedFileCB, this); + + m_HasS3TC = + m_Device->IsTextureFormatSupported(Renderer::Backend::Format::BC1_RGB_UNORM) && + m_Device->IsTextureFormatSupported(Renderer::Backend::Format::BC1_RGBA_UNORM) && + m_Device->IsTextureFormatSupported(Renderer::Backend::Format::BC2_UNORM) && + m_Device->IsTextureFormatSupported(Renderer::Backend::Format::BC3_UNORM); } ~CTextureManagerImpl() { UnregisterFileReloadFunc(ReloadChangedFileCB, this); - - ignore_result(ogl_tex_free(m_DefaultHandle)); } - CTexturePtr GetErrorTexture() + const CTexturePtr& GetErrorTexture() { return m_ErrorTexture.GetTexture(); } - CTexturePtr GetWhiteTexture() + const CTexturePtr& GetWhiteTexture() { return m_WhiteTexture.GetTexture(); } - CTexturePtr GetTransparentTexture() + const CTexturePtr& GetTransparentTexture() { return m_TransparentTexture.GetTexture(); } + const CTexturePtr& GetAlphaGradientTexture() + { + return m_AlphaGradientTexture.GetTexture(); + } + + const CTexturePtr& GetBlackTextureCube() + { + return m_BlackTextureCube.GetTexture(); + } + /** * See CTextureManager::CreateTexture */ CTexturePtr CreateTexture(const CTextureProperties& props) { // Construct a new default texture with the given properties to use as the search key - CTexturePtr texture(new CTexture(m_DefaultHandle, props, this)); + CTexturePtr texture(new CTexture( + nullptr, m_DefaultTexture.GetTexture()->GetBackendTexture(), props, this)); // Try to find an existing texture with the given properties TextureCache::iterator it = m_TextureCache.find(texture); @@ -205,72 +419,151 @@ return texture; } + CTexturePtr WrapBackendTexture( + std::unique_ptr backendTexture) + { + ENSURE(backendTexture); + Renderer::Backend::ITexture* fallback = backendTexture.get(); + + CTextureProperties props(VfsPath{}); + CTexturePtr texture(new CTexture( + std::move(backendTexture), fallback, props, this)); + texture->m_State = CTexture::UPLOADED; + texture->m_Self = texture; + return texture; + } + /** * Load the given file into the texture object and upload it to OpenGL. * Assumes the file already exists. */ void LoadTexture(const CTexturePtr& texture, const VfsPath& path) { - if (m_DisableGL) - return; - PROFILE2("load texture"); PROFILE2_ATTR("name: %ls", path.string().c_str()); - Handle h = ogl_tex_load(m_VFS, path, RES_UNIQUE); - if (h <= 0) + std::shared_ptr fileData; + size_t fileSize; + const Status loadStatus = m_VFS->LoadFile(path, fileData, fileSize); + if (loadStatus != INFO::OK) { - LOGERROR("Texture failed to load; \"%s\"", texture->m_Properties.m_Path.string8()); + LOGERROR("Texture failed to load; \"%s\" %s", + texture->m_Properties.m_Path.string8(), GetStatusAsString(loadStatus).c_str()); + texture->ResetBackendTexture( + nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture()); + texture->m_TextureData.reset(); + return; + } - // Replace with error texture to make it obvious - texture->SetHandle(m_ErrorTexture.GetHandle()); + texture->m_TextureData = std::make_unique(); + Tex& textureData = *texture->m_TextureData; + const Status decodeStatus = textureData.decode(fileData, fileSize); + if (decodeStatus != INFO::OK) + { + LOGERROR("Texture failed to decode; \"%s\" %s", + texture->m_Properties.m_Path.string8(), GetStatusAsString(decodeStatus).c_str()); + texture->ResetBackendTexture( + nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture()); + texture->m_TextureData.reset(); return; } - // Get some flags for later use - size_t flags = 0; - ignore_result(ogl_tex_get_format(h, &flags, NULL)); + if (!is_pow2(textureData.m_Width) || !is_pow2(textureData.m_Height)) + { + LOGERROR("Texture should have width and height be power of two; \"%s\" %zux%zu", + texture->m_Properties.m_Path.string8(), textureData.m_Width, textureData.m_Height); + texture->ResetBackendTexture( + nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture()); + texture->m_TextureData.reset(); + return; + } // Initialise base color from the texture - ignore_result(ogl_tex_get_average_color(h, &texture->m_BaseColor)); - - // Set GL upload properties - ignore_result(ogl_tex_set_wrap(h, texture->m_Properties.m_WrapS, texture->m_Properties.m_WrapT)); - ignore_result(ogl_tex_set_anisotropy(h, texture->m_Properties.m_Aniso)); + texture->m_BaseColor = textureData.get_average_color(); - // Prevent ogl_tex automatically generating mipmaps (which is slow and unwanted), - // by avoiding mipmapped filters unless the source texture already has mipmaps - GLint filter = texture->m_Properties.m_Filter; - if (!(flags & TEX_MIPMAPS)) + Renderer::Backend::Format format = Renderer::Backend::Format::UNDEFINED; + if (texture->m_Properties.m_FormatOverride != Renderer::Backend::Format::UNDEFINED) { - switch (filter) + format = texture->m_Properties.m_FormatOverride; + // TODO: it'd be good to remove the override hack and provide information + // via XML. + ENSURE((textureData.m_Flags & TEX_DXT) == 0); + if (format == Renderer::Backend::Format::A8_UNORM) { - case GL_NEAREST_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - filter = GL_NEAREST; - break; - case GL_LINEAR_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_LINEAR: - filter = GL_LINEAR; - break; + ENSURE(textureData.m_Bpp == 8 && (textureData.m_Flags & TEX_GREY)); } + else if (format == Renderer::Backend::Format::R8G8B8A8_UNORM) + { + ENSURE(textureData.m_Bpp == 32 && (textureData.m_Flags & TEX_ALPHA)); + } + else + debug_warn("Unsupported format override."); + } + else + { + format = ChooseFormatAndTransformTextureDataIfNeeded(textureData, m_HasS3TC); } - ignore_result(ogl_tex_set_filter(h, filter)); - // Upload to GL - if (!m_DisableGL && ogl_tex_upload(h, texture->m_Properties.m_Format) < 0) + if (format == Renderer::Backend::Format::UNDEFINED) { - LOGERROR("Texture failed to upload: \"%s\"", texture->m_Properties.m_Path.string8()); + LOGERROR("Texture failed to choose format; \"%s\"", texture->m_Properties.m_Path.string8()); + texture->ResetBackendTexture( + nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture()); + texture->m_TextureData.reset(); + return; + } - ogl_tex_free(h); + const uint32_t width = texture->m_TextureData->m_Width; + const uint32_t height = texture->m_TextureData->m_Height ; + const uint32_t MIPLevelCount = texture->m_TextureData->GetMIPLevels().size(); + texture->m_BaseLevelOffset = 0; + + Renderer::Backend::Sampler::Desc defaultSamplerDesc = + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::REPEAT); + + defaultSamplerDesc.addressModeU = texture->m_Properties.m_AddressModeU; + defaultSamplerDesc.addressModeV = texture->m_Properties.m_AddressModeV; + if (texture->m_Properties.m_AnisotropicFilterEnabled && m_Device->GetCapabilities().anisotropicFiltering) + { + int maxAnisotropy = 1; + CFG_GET_VAL("textures.maxanisotropy", maxAnisotropy); + const int allowedValues[] = {2, 4, 8, 16}; + if (std::find(std::begin(allowedValues), std::end(allowedValues), maxAnisotropy) != std::end(allowedValues)) + { + defaultSamplerDesc.anisotropyEnabled = true; + defaultSamplerDesc.maxAnisotropy = maxAnisotropy; + } + } - // Replace with error texture to make it obvious - texture->SetHandle(m_ErrorTexture.GetHandle()); - return; + if (!texture->m_Properties.m_IgnoreQuality) + { + int quality = 2; + CFG_GET_VAL("textures.quality", quality); + if (quality == 1) + { + if (MIPLevelCount > 1 && std::min(width, height) > 8) + texture->m_BaseLevelOffset += 1; + } + else if (quality == 0) + { + if (MIPLevelCount > 2 && std::min(width, height) > 16) + texture->m_BaseLevelOffset += 2; + while (std::min(width >> texture->m_BaseLevelOffset, height >> texture->m_BaseLevelOffset) > 256 && + MIPLevelCount > texture->m_BaseLevelOffset + 1) + { + texture->m_BaseLevelOffset += 1; + } + defaultSamplerDesc.mipFilter = Renderer::Backend::Sampler::Filter::NEAREST; + defaultSamplerDesc.anisotropyEnabled = false; + } } - // Let the texture object take ownership of this handle - texture->SetHandle(h, true); + texture->m_BackendTexture = m_Device->CreateTexture2D( + texture->m_Properties.m_Path.string8().c_str(), + format, (width >> texture->m_BaseLevelOffset), (height >> texture->m_BaseLevelOffset), + defaultSamplerDesc, MIPLevelCount - texture->m_BaseLevelOffset); } /** @@ -320,7 +613,8 @@ // No source file or archive cache was found, so we can't load the // real texture at all - return the error texture instead LOGERROR("CCacheLoader failed to find archived or source file for: \"%s\"", texture->m_Properties.m_Path.string8()); - texture->SetHandle(m_ErrorTexture.GetHandle()); + texture->ResetBackendTexture( + nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture()); return true; } } @@ -331,7 +625,7 @@ */ void ConvertTexture(const CTexturePtr& texture) { - VfsPath sourcePath = texture->m_Properties.m_Path; + const VfsPath sourcePath = texture->m_Properties.m_Path; PROFILE2("convert texture"); PROFILE2_ATTR("name: %ls", sourcePath.string().c_str()); @@ -339,9 +633,7 @@ MD5 hash; u32 version; PrepareCacheKey(texture, hash, version); - VfsPath looseCachePath = m_CacheLoader.LooseCachePath(sourcePath, hash, version); - -// LOGWARNING("Converting texture \"%s\"", srcPath.c_str()); + const VfsPath looseCachePath = m_CacheLoader.LooseCachePath(sourcePath, hash, version); CTextureConverter::Settings settings = GetConverterSettings(texture); @@ -393,7 +685,8 @@ else { LOGERROR("Texture failed to convert: \"%s\"", texture->m_Properties.m_Path.string8()); - texture->SetHandle(m_ErrorTexture.GetHandle()); + texture->ResetBackendTexture( + nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture()); } texture->m_State = CTexture::LOADED; return true; @@ -455,6 +748,23 @@ return false; } + bool MakeUploadProgress( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) + { + if (!m_PredefinedTexturesUploaded) + { + m_DefaultTexture.Upload(deviceCommandContext); + m_ErrorTexture.Upload(deviceCommandContext); + m_WhiteTexture.Upload(deviceCommandContext); + m_TransparentTexture.Upload(deviceCommandContext); + m_AlphaGradientTexture.Upload(deviceCommandContext); + m_BlackTextureCube.Upload(deviceCommandContext); + m_PredefinedTexturesUploaded = true; + return true; + } + return false; + } + /** * Compute the conversion settings that apply to a given texture, by combining * the textures.xml files from its directory and all parent directories @@ -516,12 +826,14 @@ if (files != m_HotloadFiles.end()) { // Flag all textures using this file as needing reloading - for (std::set >::iterator it = files->second.begin(); it != files->second.end(); ++it) + for (std::set>::iterator it = files->second.begin(); it != files->second.end(); ++it) { if (std::shared_ptr texture = it->lock()) { texture->m_State = CTexture::UNLOADED; - texture->SetHandle(m_DefaultHandle); + texture->ResetBackendTexture( + nullptr, m_DefaultTexture.GetTexture()->GetBackendTexture()); + texture->m_TextureData.reset(); } } } @@ -529,6 +841,17 @@ return INFO::OK; } + void ReloadAllTextures() + { + for (const CTexturePtr& texture : m_TextureCache) + { + texture->m_State = CTexture::UNLOADED; + texture->ResetBackendTexture( + nullptr, m_DefaultTexture.GetTexture()->GetBackendTexture()); + texture->m_TextureData.reset(); + } + } + size_t GetBytesUploaded() const { size_t size = 0; @@ -537,16 +860,24 @@ return size; } + void OnQualityChanged() + { + ReloadAllTextures(); + } + private: PIVFS m_VFS; CCacheLoader m_CacheLoader; - bool m_DisableGL; + Renderer::Backend::IDevice* m_Device = nullptr; CTextureConverter m_TextureConverter; - Handle m_DefaultHandle; - SingleColorTexture m_ErrorTexture; - SingleColorTexture m_WhiteTexture; - SingleColorTexture m_TransparentTexture; + CSingleColorTexture m_DefaultTexture; + CSingleColorTexture m_ErrorTexture; + CSingleColorTexture m_WhiteTexture; + CSingleColorTexture m_TransparentTexture; + CGradientTexture m_AlphaGradientTexture; + CSingleColorTextureCube m_BlackTextureCube; + bool m_PredefinedTexturesUploaded = false; // Cache of all loaded textures using TextureCache = @@ -557,44 +888,68 @@ // Store the set of textures that need to be reloaded when the given file // (a source file or settings.xml) is modified using HotloadFilesMap = - std::unordered_map, std::owner_less > > >; + std::unordered_map, std::owner_less>>>; HotloadFilesMap m_HotloadFiles; // Cache for the conversion settings files using SettingsFilesMap = std::unordered_map>; SettingsFilesMap m_SettingsFiles; + + bool m_HasS3TC = false; }; -CTexture::CTexture(Handle handle, const CTextureProperties& props, CTextureManagerImpl* textureManager) : - m_Handle(handle), m_BaseColor(0), m_State(UNLOADED), m_Properties(props), m_TextureManager(textureManager) +CTexture::CTexture( + std::unique_ptr texture, + Renderer::Backend::ITexture* fallback, + const CTextureProperties& props, CTextureManagerImpl* textureManager) : + m_BackendTexture(std::move(texture)), m_FallbackBackendTexture(fallback), + m_BaseColor(0), m_State(UNLOADED), m_Properties(props), + m_TextureManager(textureManager) { - // Add a reference to the handle (it might be shared by multiple CTextures - // so we can't take ownership of it) - if (m_Handle) - h_add_ref(m_Handle); } -CTexture::~CTexture() +CTexture::~CTexture() = default; + +void CTexture::UploadBackendTextureIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - if (m_Handle) - ogl_tex_free(m_Handle); + if (IsUploaded()) + return; + + if (!IsLoaded()) + TryLoad(); + + if (!IsLoaded()) + return; + else if (!m_TextureData || !m_BackendTexture) + { + ResetBackendTexture(nullptr, m_TextureManager->GetErrorTexture()->GetBackendTexture()); + m_State = UPLOADED; + return; + } + + m_UploadedSize = 0; + for (uint32_t textureDataLevel = m_BaseLevelOffset, level = 0; textureDataLevel < m_TextureData->GetMIPLevels().size(); ++textureDataLevel) + { + const Tex::MIPLevel& levelData = m_TextureData->GetMIPLevels()[textureDataLevel]; + deviceCommandContext->UploadTexture(m_BackendTexture.get(), m_BackendTexture->GetFormat(), + levelData.data, levelData.dataSize, level++); + m_UploadedSize += levelData.dataSize; + } + m_TextureData.reset(); + + m_State = UPLOADED; } -void CTexture::Bind(size_t unit) +Renderer::Backend::ITexture* CTexture::GetBackendTexture() { - ogl_tex_bind(GetHandle(), unit); + return m_BackendTexture && IsUploaded() ? m_BackendTexture.get() : m_FallbackBackendTexture; } -Handle CTexture::GetHandle() +const Renderer::Backend::ITexture* CTexture::GetBackendTexture() const { - // TODO: TryLoad might call ogl_tex_upload which enables GL_TEXTURE_2D - // on texture unit 0, regardless of 'unit', which callers might - // not be expecting. Ideally that wouldn't happen. - - TryLoad(); - - return m_Handle; + return m_BackendTexture && IsUploaded() ? m_BackendTexture.get() : m_FallbackBackendTexture; } bool CTexture::TryLoad() @@ -612,7 +967,7 @@ } } - return (m_State == LOADED); + return IsLoaded() || IsUploaded(); } void CTexture::Prefetch() @@ -626,42 +981,33 @@ } } -bool CTexture::IsLoaded() -{ - return (m_State == LOADED); -} - -void CTexture::SetHandle(Handle handle, bool takeOwnership) +void CTexture::ResetBackendTexture( + std::unique_ptr backendTexture, + Renderer::Backend::ITexture* fallbackBackendTexture) { - if (handle == m_Handle) - return; - - if (!takeOwnership) - h_add_ref(handle); - - ogl_tex_free(m_Handle); - m_Handle = handle; + m_BackendTexture = std::move(backendTexture); + m_FallbackBackendTexture = fallbackBackendTexture; } size_t CTexture::GetWidth() const { - size_t w = 0; - ignore_result(ogl_tex_get_size(m_Handle, &w, 0, 0)); - return w; + return GetBackendTexture()->GetWidth(); } size_t CTexture::GetHeight() const { - size_t h = 0; - ignore_result(ogl_tex_get_size(m_Handle, 0, &h, 0)); - return h; + return GetBackendTexture()->GetHeight(); } bool CTexture::HasAlpha() const { - size_t flags = 0; - ignore_result(ogl_tex_get_format(m_Handle, &flags, 0)); - return (flags & TEX_ALPHA) != 0; + const Renderer::Backend::Format format = GetBackendTexture()->GetFormat(); + return + format == Renderer::Backend::Format::A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::BC1_RGBA_UNORM || + format == Renderer::Backend::Format::BC2_UNORM || + format == Renderer::Backend::Format::BC3_UNORM; } u32 CTexture::GetBaseColor() const @@ -671,16 +1017,13 @@ size_t CTexture::GetUploadedSize() const { - size_t size = 0; - ignore_result(ogl_tex_get_uploaded_size(m_Handle, &size)); - return size; + return m_UploadedSize; } - // CTextureManager: forward all calls to impl: -CTextureManager::CTextureManager(PIVFS vfs, bool highQuality, bool disableGL) : - m(new CTextureManagerImpl(vfs, highQuality, disableGL)) +CTextureManager::CTextureManager(PIVFS vfs, bool highQuality, Renderer::Backend::IDevice* device) : + m(new CTextureManagerImpl(vfs, highQuality, device)) { } @@ -694,31 +1037,53 @@ return m->CreateTexture(props); } +CTexturePtr CTextureManager::WrapBackendTexture( + std::unique_ptr backendTexture) +{ + return m->WrapBackendTexture(std::move(backendTexture)); +} + bool CTextureManager::TextureExists(const VfsPath& path) const { return m->TextureExists(path); } -CTexturePtr CTextureManager::GetErrorTexture() +const CTexturePtr& CTextureManager::GetErrorTexture() { return m->GetErrorTexture(); } -CTexturePtr CTextureManager::GetWhiteTexture() +const CTexturePtr& CTextureManager::GetWhiteTexture() { return m->GetWhiteTexture(); } -CTexturePtr CTextureManager::GetTransparentTexture() +const CTexturePtr& CTextureManager::GetTransparentTexture() { return m->GetTransparentTexture(); } +const CTexturePtr& CTextureManager::GetAlphaGradientTexture() +{ + return m->GetAlphaGradientTexture(); +} + +const CTexturePtr& CTextureManager::GetBlackTextureCube() +{ + return m->GetBlackTextureCube(); +} + bool CTextureManager::MakeProgress() { return m->MakeProgress(); } +bool CTextureManager::MakeUploadProgress( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + return m->MakeUploadProgress(deviceCommandContext); +} + bool CTextureManager::GenerateCachedTexture(const VfsPath& path, VfsPath& outputPath) { return m->GenerateCachedTexture(path, outputPath); @@ -728,3 +1093,8 @@ { return m->GetBytesUploaded(); } + +void CTextureManager::OnQualityChanged() +{ + m->OnQualityChanged(); +} diff -Nru 0ad-0.0.25b/source/graphics/TextureManager.h 0ad-0.0.26/source/graphics/TextureManager.h --- 0ad-0.0.25b/source/graphics/TextureManager.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/graphics/TextureManager.h 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,8 +20,10 @@ #include "graphics/Texture.h" #include "lib/file/vfs/vfs.h" -#include "lib/ogl.h" -#include "lib/res/handle.h" +#include "lib/tex/tex.h" +#include "renderer/backend/IDevice.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/ITexture.h" #include @@ -57,7 +59,7 @@ * These will be loaded in the background, when there are no higher-priority textures * to load. * - * The same texture file can be safely loaded multiple times with different GL parameters + * The same texture file can be safely loaded multiple times with different backend parameters * (but this should be avoided whenever possible, as it wastes VRAM). * * For release packages, DDS files can be precached by appending ".dds" to their name, @@ -76,33 +78,48 @@ * Construct texture manager. vfs must be the VFS instance used for all textures * loaded from this object. * highQuality is slower and intended for batch-conversion modes. - * disableGL is intended for tests, and will disable all GL uploads. */ - CTextureManager(PIVFS vfs, bool highQuality, bool disableGL); + CTextureManager(PIVFS vfs, bool highQuality, Renderer::Backend::IDevice* device); ~CTextureManager(); /** - * Create a texture with the given GL properties. + * Create a texture with the given properties. * The texture data will not be loaded immediately. */ CTexturePtr CreateTexture(const CTextureProperties& props); /** + * Wraps a backend texture. + */ + CTexturePtr WrapBackendTexture( + std::unique_ptr backendTexture); + + /** * Returns a magenta texture. Use this for highlighting errors * (e.g. missing terrain textures). */ - CTexturePtr GetErrorTexture(); + const CTexturePtr& GetErrorTexture(); /** * Returns a single color RGBA texture with CColor(1.0f, 1.0f, 1.0f, 1.0f). */ - CTexturePtr GetWhiteTexture(); + const CTexturePtr& GetWhiteTexture(); /** * Returns a single color RGBA texture with CColor(0.0f, 0.0f, 0.0f, 0.0f). */ - CTexturePtr GetTransparentTexture(); + const CTexturePtr& GetTransparentTexture(); + + /** + * Returns a white RGBA texture with alpha gradient. + */ + const CTexturePtr& GetAlphaGradientTexture(); + + /** + * Returns a single color RGBA texture cube with CColor(0.0f, 0.0f, 0.0f, 1.0f). + */ + const CTexturePtr& GetBlackTextureCube(); /** * Work on asynchronous texture loading operations, if any. @@ -113,6 +130,12 @@ bool MakeProgress(); /** + * Work on asynchronous texture uploading operations, if any. + * Returns true if it did any work. Mostly the same as MakeProgress. + */ + bool MakeUploadProgress(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + + /** * Synchronously converts and compresses and saves the texture, * and returns the output path (minus a "cache/" prefix). This * is intended for pre-caching textures in release archives. @@ -131,6 +154,11 @@ */ size_t GetBytesUploaded() const; + /** + * Should be called on any quality or anisotropic change. + */ + void OnQualityChanged(); + private: CTextureManagerImpl* m; }; @@ -150,38 +178,41 @@ /** * Use the given texture name, and default GL parameters. */ - explicit CTextureProperties(const VfsPath& path) : - m_Path(path), m_Filter(GL_LINEAR_MIPMAP_LINEAR), - m_WrapS(GL_REPEAT), m_WrapT(GL_REPEAT), m_Aniso(1.0f), m_Format(0) + explicit CTextureProperties(const VfsPath& path) + : m_Path(path) { } - /** - * Set min/mag filter mode (typically GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST, etc). - */ - void SetFilter(GLint filter) { m_Filter = filter; } - - /** - * Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc). - */ - void SetWrap(GLint wrap) { m_WrapS = wrap; m_WrapT = wrap; } + CTextureProperties( + const VfsPath& path, const Renderer::Backend::Format formatOverride) + : m_Path(path), m_FormatOverride(formatOverride) + { + } /** - * Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc), - * separately for S and T. + * Set sampler address mode. */ - void SetWrap(GLint wrap_s, GLint wrap_t) { m_WrapS = wrap_s; m_WrapT = wrap_t; } + void SetAddressMode(const Renderer::Backend::Sampler::AddressMode addressMode) + { + m_AddressModeU = m_AddressModeV = addressMode; + } /** - * Set maximum anisotropy value. Must be >= 1.0. Should be a power of 2. + * Set sampler address mode separately for different coordinates. */ - void SetMaxAnisotropy(float aniso) { m_Aniso = aniso; } + void SetAddressMode( + const Renderer::Backend::Sampler::AddressMode addressModeU, + const Renderer::Backend::Sampler::AddressMode addressModeV) + { + m_AddressModeU = addressModeU; + m_AddressModeV = addressModeV; + } /** - * Set GL texture upload format, to override the default. - * Typically GL_ALPHA or GL_LUMINANCE for 8-bit textures. + * The value of max anisotropy is set by options. Though it might make sense + * to add an override. */ - void SetFormatOverride(GLenum format) { m_Format = format; } + void SetAnisotropicFilter(const bool enabled) { m_AnisotropicFilterEnabled = enabled; } // TODO: rather than this static definition of texture properties // (especially anisotropy), maybe we want something that can be more @@ -200,14 +231,20 @@ // // or something a bit like that. + void SetIgnoreQuality(bool ignore) { m_IgnoreQuality = ignore; } + private: // Must update TPhash, TPequal_to when changing these fields VfsPath m_Path; - GLint m_Filter; - GLint m_WrapS; - GLint m_WrapT; - float m_Aniso; - GLenum m_Format; + + Renderer::Backend::Sampler::AddressMode m_AddressModeU = + Renderer::Backend::Sampler::AddressMode::REPEAT; + Renderer::Backend::Sampler::AddressMode m_AddressModeV = + Renderer::Backend::Sampler::AddressMode::REPEAT; + bool m_AnisotropicFilterEnabled = false; + Renderer::Backend::Format m_FormatOverride = + Renderer::Backend::Format::UNDEFINED; + bool m_IgnoreQuality = false; }; /** @@ -218,19 +255,8 @@ */ class CTexture { - friend class CTextureManagerImpl; - friend class SingleColorTexture; - friend struct TextureCacheCmp; - friend struct TPequal_to; - friend struct TPhash; - - // Only the texture manager can create these - explicit CTexture(Handle handle, const CTextureProperties& props, CTextureManagerImpl* textureManager); - NONCOPYABLE(CTexture); - public: - ~CTexture(); /** @@ -261,29 +287,37 @@ size_t GetUploadedSize() const; /** - * Bind the texture to the given GL texture unit. + * Uploads a texture data to a backend texture if successfully loaded. * If the texture data hasn't been loaded yet, this may wait a short while to * load it. If loading takes too long then it will return sooner and the data will * be loaded in a background thread, so this does not guarantee the texture really - * will be loaded. + * will be uploaded. */ - void Bind(size_t unit = 0); + void UploadBackendTextureIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** - * Returns a ogl_tex handle, for later binding. See comments from Bind(). + * Returns a backend texture if successfully uploaded, else fallback. */ - Handle GetHandle(); + Renderer::Backend::ITexture* GetBackendTexture(); + const Renderer::Backend::ITexture* GetBackendTexture() const; /** - * Attempt to load the texture data quickly, as with Bind(). - * Returns whether the texture data is currently loaded. + * Attempt to load the texture data quickly, as with + * GetUploadedBackendTextureIfNeeded(). Returns whether the texture data is + * currently loaded (but not uploaded). */ bool TryLoad(); /** * Returns whether the texture data is currently loaded. */ - bool IsLoaded(); + bool IsLoaded() const { return m_State == LOADED; } + + /** + * Returns whether the texture data is currently uploaded. + */ + bool IsUploaded() const { return m_State == UPLOADED; } /** * Activate the prefetching optimisation for this texture. @@ -294,25 +328,42 @@ void Prefetch(); private: - /** - * Replace the Handle stored by this object. - * If takeOwnership is true, it will not increment the Handle's reference count. - */ - void SetHandle(Handle handle, bool takeOwnership = false); + friend class CTextureManagerImpl; + friend class CPredefinedTexture; + friend struct TextureCacheCmp; + friend struct TPequal_to; + friend struct TPhash; + + // Only the texture manager can create these + explicit CTexture( + std::unique_ptr texture, + Renderer::Backend::ITexture* fallback, + const CTextureProperties& props, CTextureManagerImpl* textureManager); + + void ResetBackendTexture( + std::unique_ptr backendTexture, + Renderer::Backend::ITexture* fallbackBackendTexture); const CTextureProperties m_Properties; - Handle m_Handle; + std::unique_ptr m_BackendTexture; + // It's possible to m_FallbackBackendTexture references m_BackendTexture. + Renderer::Backend::ITexture* m_FallbackBackendTexture = nullptr; u32 m_BaseColor; + std::unique_ptr m_TextureData; + size_t m_UploadedSize = 0; + uint32_t m_BaseLevelOffset = 0; - enum { + enum + { UNLOADED, // loading has not started PREFETCH_NEEDS_LOADING, // was prefetched; currently waiting to try loading from cache PREFETCH_NEEDS_CONVERTING, // was prefetched; currently waiting to be sent to the texture converter PREFETCH_IS_CONVERTING, // was prefetched; currently being processed by the texture converter HIGH_NEEDS_CONVERTING, // high-priority; currently waiting to be sent to the texture converter HIGH_IS_CONVERTING, // high-priority; currently being processed by the texture converter - LOADED // loading has completed (successfully or not) + LOADED, // loading texture data has completed (successfully or not) + UPLOADED // uploading to backend has completed (successfully or not) } m_State; CTextureManagerImpl* m_TextureManager; diff -Nru 0ad-0.0.25b/source/graphics/Unit.h 0ad-0.0.26/source/graphics/Unit.h --- 0ad-0.0.25b/source/graphics/Unit.h 2021-08-03 17:15:03.000000000 +0000 +++ 0ad-0.0.26/source/graphics/Unit.h 2022-08-21 12:45:23.000000000 +0000 @@ -28,7 +28,6 @@ class CModelAbstract; class CObjectEntry; class CObjectManager; -class CSkeletonAnim; class CUnitAnimation; diff -Nru 0ad-0.0.25b/source/graphics/UnitManager.cpp 0ad-0.0.26/source/graphics/UnitManager.cpp --- 0ad-0.0.25b/source/graphics/UnitManager.cpp 2021-08-03 17:15:03.000000000 +0000 +++ 0ad-0.0.26/source/graphics/UnitManager.cpp 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -97,3 +97,11 @@ AddUnit(unit); return unit; } + +void CUnitManager::MakeTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1, int dirtyFlags) +{ + if (!(dirtyFlags & RENDERDATA_UPDATE_VERTICES)) + return; + for (CUnit* unit : m_Units) + unit->GetModel().SetTerrainDirty(i0, j0, i1, j1); +} diff -Nru 0ad-0.0.25b/source/graphics/UnitManager.h 0ad-0.0.26/source/graphics/UnitManager.h --- 0ad-0.0.25b/source/graphics/UnitManager.h 2021-08-03 17:15:03.000000000 +0000 +++ 0ad-0.0.26/source/graphics/UnitManager.h 2022-08-21 12:45:23.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,14 +22,13 @@ #ifndef INCLUDED_UNITMANAGER #define INCLUDED_UNITMANAGER +#include "ps/CStrForward.h" + #include #include class CUnit; -class CVector3D; class CObjectManager; -class CStr8; -class CStrW; /////////////////////////////////////////////////////////////////////////////// // CUnitManager: simple container class holding all units within the world @@ -57,6 +56,12 @@ void SetObjectManager(CObjectManager& objectManager) { m_ObjectManager = &objectManager; } + /** + * Mark a specific region of the terrain as dirty. + * Coordinates are in terrain tiles, lower inclusive, upper exclusive. + */ + void MakeTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1, int dirtyFlags); + private: // list of all known units std::vector m_Units; diff -Nru 0ad-0.0.25b/source/gui/CGUI.cpp 0ad-0.0.26/source/gui/CGUI.cpp --- 0ad-0.0.25b/source/gui/CGUI.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/CGUI.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -42,6 +42,7 @@ #include "ps/Hotkey.h" #include "ps/Profile.h" #include "ps/Pyrogenesis.h" +#include "ps/VideoMode.h" #include "ps/XML/Xeromyces.h" #include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" @@ -154,7 +155,7 @@ // Yes the mouse position is stored as float to avoid // constant conversions when operating in a // float-based environment. - m_MousePos = CVector2D((float)ev->ev.motion.x / g_GuiScale, (float)ev->ev.motion.y / g_GuiScale); + m_MousePos = CVector2D((float)ev->ev.motion.x / g_VideoMode.GetScale(), (float)ev->ev.motion.y / g_VideoMode.GetScale()); SGUIMessage msg(GUIM_MOUSE_MOTION); m_BaseObject->RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::HandleMessage, msg); @@ -179,7 +180,7 @@ CVector2D oldMousePos = m_MousePos; if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP) { - m_MousePos = CVector2D((float)ev->ev.button.x / g_GuiScale, (float)ev->ev.button.y / g_GuiScale); + m_MousePos = CVector2D((float)ev->ev.button.x / g_VideoMode.GetScale(), (float)ev->ev.button.y / g_VideoMode.GetScale()); } // Allow the focused object to pre-empt regular GUI events. @@ -324,7 +325,7 @@ object->ScriptEvent(eventName, paramData); } -void CGUI::Draw() +void CGUI::Draw(CCanvas2D& canvas) { using Arena = Allocators::DynamicArena<128 * KiB>; using ObjectListAllocator = ProxyAllocator; @@ -341,7 +342,6 @@ return visibleObject1.index < visibleObject2.index; }); - CCanvas2D canvas; for (const VisibleObject& visibleObject : visibleObjects) visibleObject.object->Draw(canvas); } @@ -420,7 +420,16 @@ CSize2D CGUI::GetWindowSize() const { - return CSize2D{static_cast(g_xres) / g_GuiScale, static_cast(g_yres) / g_GuiScale}; + return CSize2D{static_cast(g_xres) / g_VideoMode.GetScale(), static_cast(g_yres) / g_VideoMode.GetScale() }; +} + +void CGUI::SendFocusMessage(EGUIMessageType msgType) +{ + if (m_FocusedObject) + { + SGUIMessage msg(msgType); + m_FocusedObject->HandleMessage(msg); + } } void CGUI::SetFocusedObject(IGUIObject* pObject) @@ -534,6 +543,7 @@ CXeromyces xeroFile; if (xeroFile.Load(g_VFS, Filename, "gui") != PSRETURN_OK) + // The error has already been reported by CXeromyces return; XMBElement node = xeroFile.GetRoot(); @@ -1081,11 +1091,11 @@ else if (attr_name == "wrap_mode") { if (attr_value == L"repeat") - image->m_WrapMode = GL_REPEAT; + image->m_AddressMode = Renderer::Backend::Sampler::AddressMode::REPEAT; else if (attr_value == L"mirrored_repeat") - image->m_WrapMode = GL_MIRRORED_REPEAT; + image->m_AddressMode = Renderer::Backend::Sampler::AddressMode::MIRRORED_REPEAT; else if (attr_value == L"clamp_to_edge") - image->m_WrapMode = GL_CLAMP_TO_EDGE; + image->m_AddressMode = Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE; else LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name, utf8_from_wstring(attr_value)); } diff -Nru 0ad-0.0.25b/source/gui/CGUI.h 0ad-0.0.26/source/gui/CGUI.h --- 0ad-0.0.25b/source/gui/CGUI.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/CGUI.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "gui/GUITooltip.h" #include "gui/SettingTypes/CGUIColor.h" #include "gui/SGUIIcon.h" +#include "gui/SGUIMessage.h" #include "gui/SGUIStyle.h" #include "lib/input.h" #include "maths/Rect.h" @@ -97,7 +98,7 @@ /** * Displays the whole GUI */ - void Draw(); + void Draw(CCanvas2D& canvas); /** * Draw GUI Sprite @@ -288,6 +289,11 @@ void SetFocusedObject(IGUIObject* pObject); /** + * Alert the focussed object of this GUIPage that the focus of the page has changed. + */ + void SendFocusMessage(EGUIMessageType msg); + + /** * Reads a string value and modifies the given value of type T if successful. * Does not change the value upon conversion failure. * diff -Nru 0ad-0.0.25b/source/gui/CGUISprite.h 0ad-0.0.26/source/gui/CGUISprite.h --- 0ad-0.0.25b/source/gui/CGUISprite.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/CGUISprite.h 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,9 +26,9 @@ #include "gui/GUIRenderer.h" #include "gui/SettingTypes/CGUISize.h" #include "gui/SettingTypes/CGUIColor.h" -#include "lib/ogl.h" #include "lib/file/vfs/vfs_path.h" #include "ps/CStr.h" +#include "renderer/backend/Sampler.h" #include #include @@ -55,7 +55,7 @@ SGUIImage() : m_FixedHAspectRatio(0.f), m_RoundCoordinates(true), - m_WrapMode(GL_REPEAT), + m_AddressMode(Renderer::Backend::Sampler::AddressMode::REPEAT), m_Effects(), m_Size(CGUISize::Full()), m_TextureSize(CGUISize::Full()) @@ -89,9 +89,9 @@ bool m_RoundCoordinates; /** - * Texture wrapping mode (GL_REPEAT, GL_CLAMP_TO_EDGE, etc) + * Texture address mode (REPEAT, CLAMP_TO_EDGE, etc). */ - GLint m_WrapMode; + Renderer::Backend::Sampler::AddressMode m_AddressMode; // Visual effects (e.g. color modulation) std::shared_ptr m_Effects; diff -Nru 0ad-0.0.25b/source/gui/CGUIText.cpp 0ad-0.0.26/source/gui/CGUIText.cpp --- 0ad-0.0.25b/source/gui/CGUIText.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/CGUIText.cpp 2022-09-23 19:16:47.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,125 +26,140 @@ #include "gui/ObjectBases/IGUIObject.h" #include "gui/SettingTypes/CGUIString.h" #include "ps/CStrInternStatic.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/Renderer.h" #include extern int g_xres, g_yres; -extern float g_GuiScale; // TODO Gee: CRect => CPoint ? void SGenerateTextImage::SetupSpriteCall( - const bool Left, CGUIText::SSpriteCall& SpriteCall, const float width, const float y, - const CSize2D& Size, const CStr& TextureName, const float BufferZone) + const bool left, CGUIText::SSpriteCall& spriteCall, const float width, const float y, + const CSize2D& size, const CStr& textureName, const float bufferZone) { // TODO Gee: Temp hardcoded values - SpriteCall.m_Area.top = y + BufferZone; - SpriteCall.m_Area.bottom = y + BufferZone + Size.Height; + spriteCall.m_Area.top = y + bufferZone; + spriteCall.m_Area.bottom = y + bufferZone + size.Height; - if (Left) + if (left) { - SpriteCall.m_Area.left = BufferZone; - SpriteCall.m_Area.right = Size.Width + BufferZone; + spriteCall.m_Area.left = bufferZone; + spriteCall.m_Area.right = size.Width + bufferZone; } else { - SpriteCall.m_Area.left = width-BufferZone - Size.Width; - SpriteCall.m_Area.right = width-BufferZone; + spriteCall.m_Area.left = width - bufferZone - size.Width; + spriteCall.m_Area.right = width - bufferZone; } - SpriteCall.m_Sprite = TextureName; + spriteCall.m_Sprite = textureName; - m_YFrom = SpriteCall.m_Area.top - BufferZone; - m_YTo = SpriteCall.m_Area.bottom + BufferZone; - m_Indentation = Size.Width + BufferZone * 2; + m_YFrom = spriteCall.m_Area.top - bufferZone; + m_YTo = spriteCall.m_Area.bottom + bufferZone; + m_Indentation = size.Width + bufferZone * 2; } -CGUIText::CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& FontW, const float Width, const float BufferZone, const EAlign align, const IGUIObject* pObject) +CGUIText::CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& fontW, const float width, const float bufferZone, const EAlign align, const IGUIObject* pObject) { if (string.m_Words.empty()) return; - CStrIntern Font(FontW.ToUTF8()); - float x = BufferZone, y = BufferZone; // drawing pointer + CStrIntern font(fontW.ToUTF8()); + float y = bufferZone; // drawing pointer + float lineWidth = 0.f; int from = 0; - bool FirstLine = true; // Necessary because text in the first line is shorter + bool firstLine = true; // Necessary because text in the first line is shorter // (it doesn't count the line spacing) // Images on the left or the right side. - SGenerateTextImages Images; - int pos_last_img = -1; // Position in the string where last img (either left or right) were encountered. + SGenerateTextImages images; + int posLastImage = -1; // Position in the string where last img (either left or right) were encountered. // in order to avoid duplicate processing. - // Go through string word by word + // The calculated width of each word includes the space between the current + // word and the next. When we're wrapping, we need subtract the width of the + // space after the last word on the line before the wrap. + CFontMetrics currentFont(font); + float spaceWidth = currentFont.GetCharacterWidth(L' '); + + // Go through string word by word. + // a word is defined as [start, end[ in string.m_Words so we skip the last item. for (int i = 0; i < static_cast(string.m_Words.size()) - 1; ++i) { // Pre-process each line one time, so we know which floating images // will be added for that line. - // Generated stuff is stored in Feedback. - CGUIString::SFeedback Feedback; + // Generated stuff is stored in feedback. + CGUIString::SFeedback feedback; // Preliminary line height, used for word-wrapping with floating images. - float prelim_line_height = 0.f; + float prelimLineHeight = 0.f; // Width and height of all text calls generated. - string.GenerateTextCall(pGUI, Feedback, Font, string.m_Words[i], string.m_Words[i+1], FirstLine); + string.GenerateTextCall(pGUI, feedback, font, string.m_Words[i], string.m_Words[i+1], firstLine); - SetupSpriteCalls(pGUI, Feedback.m_Images, y, Width, BufferZone, i, pos_last_img, Images); + SetupSpriteCalls(pGUI, feedback.m_Images, y, width, bufferZone, i, posLastImage, images); - pos_last_img = std::max(pos_last_img, i); + posLastImage = std::max(posLastImage, i); - x += Feedback.m_Size.Width; - prelim_line_height = std::max(prelim_line_height, Feedback.m_Size.Height); + lineWidth += feedback.m_Size.Width; - // If Width is 0, then there's no word-wrapping, disable NewLine. - if (((Width != 0 && (x > Width - BufferZone || Feedback.m_NewLine)) || i == static_cast(string.m_Words.size()) - 2) && - ProcessLine(pGUI, string, Font, pObject, Images, align, prelim_line_height, Width, BufferZone, FirstLine, x, y, i, from)) - return; + prelimLineHeight = std::max(prelimLineHeight, feedback.m_Size.Height); + + float spaceCorrection = feedback.m_EndsWithSpace ? spaceWidth : 0.f; + + // If width is 0, then there's no word-wrapping, disable NewLine. + if ((width != 0 && from != i && (lineWidth - spaceCorrection + 2 * bufferZone > width || feedback.m_NewLine)) || i == static_cast(string.m_Words.size()) - 2) + { + if (ProcessLine(pGUI, string, font, pObject, images, align, prelimLineHeight, width, bufferZone, firstLine, y, i, from)) + return; + lineWidth = 0.f; + } } } // Loop through our images queues, to see if images have been added. void CGUIText::SetupSpriteCalls( const CGUI& pGUI, - const std::array, 2>& FeedbackImages, + const std::array, 2>& feedbackImages, const float y, - const float Width, - const float BufferZone, + const float width, + const float bufferZone, const int i, - const int pos_last_img, - SGenerateTextImages& Images) + const int posLastImage, + SGenerateTextImages& images) { // Check if this has already been processed. // Also, floating images are only applicable if Word-Wrapping is on - if (Width == 0 || i <= pos_last_img) + if (width == 0 || i <= posLastImage) return; // Loop left/right for (int j = 0; j < 2; ++j) - for (const CStr& imgname : FeedbackImages[j]) + for (const CStr& imgname : feedbackImages[j]) { - SSpriteCall SpriteCall; - SGenerateTextImage Image; + SSpriteCall spriteCall; + SGenerateTextImage image; // Y is if no other floating images is above, y. Else it is placed // after the last image, like a stack downwards. float _y; - if (!Images[j].empty()) - _y = std::max(y, Images[j].back().m_YTo); + if (!images[j].empty()) + _y = std::max(y, images[j].back().m_YTo); else _y = y; const SGUIIcon& icon = pGUI.GetIcon(imgname); - Image.SetupSpriteCall(j == CGUIString::SFeedback::Left, SpriteCall, Width, _y, icon.m_Size, icon.m_SpriteName, BufferZone); + image.SetupSpriteCall(j == CGUIString::SFeedback::Left, spriteCall, width, _y, icon.m_Size, icon.m_SpriteName, bufferZone); // Check if image is the lowest thing. - m_Size.Height = std::max(m_Size.Height, Image.m_YTo); + m_Size.Height = std::max(m_Size.Height, image.m_YTo); - Images[j].emplace_back(Image); - m_SpriteCalls.emplace_back(std::move(SpriteCall)); + images[j].emplace_back(image); + m_SpriteCalls.emplace_back(std::move(spriteCall)); } } @@ -158,101 +173,100 @@ void CGUIText::ComputeLineSize( const CGUI& pGUI, const CGUIString& string, - const CStrIntern& Font, - const bool FirstLine, - const float Width, - const float width_range_to, + const CStrIntern& font, + const bool firstLine, + const float width, + const float widthRangeFrom, + const float widthRangeTo, const int i, - const int temp_from, - float& x, - CSize2D& line_size) const + const int tempFrom, + CSize2D& lineSize) const { - for (int j = temp_from; j <= i; ++j) + // The calculated width of each word includes the space between the current + // word and the next. When we're wrapping, we need subtract the width of the + // space after the last word on the line before the wrap. + CFontMetrics currentFont(font); + float spaceWidth = currentFont.GetCharacterWidth(L' '); + + float spaceCorrection = 0.f; + + float x = widthRangeFrom; + for (int j = tempFrom; j <= i; ++j) { - // We don't want to use Feedback now, so we'll have to use another one. - CGUIString::SFeedback Feedback2; + // We don't want to use feedback now, so we'll have to use another one. + CGUIString::SFeedback feedback2; // Don't attach object, it'll suppress the errors // we want them to be reported in the final GenerateTextCall() // so that we don't get duplicates. - string.GenerateTextCall(pGUI, Feedback2, Font, string.m_Words[j], string.m_Words[j+1], FirstLine); + string.GenerateTextCall(pGUI, feedback2, font, string.m_Words[j], string.m_Words[j+1], firstLine); // Append X value. - x += Feedback2.m_Size.Width; + x += feedback2.m_Size.Width; - if (Width != 0 && x > width_range_to && j != temp_from && !Feedback2.m_NewLine) - { - // The calculated width of each word includes the space between the current - // word and the next. When we're wrapping, we need subtract the width of the - // space after the last word on the line before the wrap. - CFontMetrics currentFont(Font); - line_size.Width -= currentFont.GetCharacterWidth(*L" "); + const float currentSpaceCorrection = feedback2.m_EndsWithSpace ? spaceWidth : 0.0f; + + const bool isLineOverflow = x - currentSpaceCorrection > widthRangeTo; + if (width != 0 && isLineOverflow && j != tempFrom && !feedback2.m_NewLine) break; - } - // Let line_size.cy be the maximum m_Height we encounter. - line_size.Height = std::max(line_size.Height, Feedback2.m_Size.Height); + // Update after the line-break detection, because otherwise spaceCorrection above + // will refer to the wrapped word and not the last-word-before-the-line-break. + spaceCorrection = currentSpaceCorrection; + + // Let lineSize.cy be the maximum m_Height we encounter. + lineSize.Height = std::max(lineSize.Height, feedback2.m_Size.Height); // If the current word is an explicit new line ("\n"), // break now before adding the width of this character. // ("\n" doesn't have a glyph, thus is given the same width as // the "missing glyph" character by CFont::GetCharacterWidth().) - if (Width != 0 && Feedback2.m_NewLine) + if (width != 0 && feedback2.m_NewLine) break; - line_size.Width += Feedback2.m_Size.Width; + lineSize.Width += feedback2.m_Size.Width; } + // Remove the space if necessary. + lineSize.Width -= spaceCorrection; } bool CGUIText::ProcessLine( const CGUI& pGUI, const CGUIString& string, - const CStrIntern& Font, + const CStrIntern& font, const IGUIObject* pObject, - const SGenerateTextImages& Images, + const SGenerateTextImages& images, const EAlign align, - const float prelim_line_height, - const float Width, - const float BufferZone, - bool& FirstLine, - float& x, + const float prelimLineHeight, + const float width, + const float bufferZone, + bool& firstLine, float& y, int& i, int& from) { // Change 'from' to 'i', but first keep a copy of its value. - int temp_from = from; + int tempFrom = from; from = i; - float width_range_from = BufferZone; - float width_range_to = Width - BufferZone; - ComputeLineRange(Images, y, Width, prelim_line_height, width_range_from, width_range_to); - - // Reset X for the next loop - x = width_range_from; - - CSize2D line_size; - ComputeLineSize(pGUI, string, Font, FirstLine, Width, width_range_to, i, temp_from, x, line_size); + float widthRangeFrom = bufferZone; + float widthRangeTo = width - bufferZone; + ComputeLineRange(images, y, width, prelimLineHeight, widthRangeFrom, widthRangeTo); - // Reset x once more - x = width_range_from; + CSize2D lineSize; + ComputeLineSize(pGUI, string, font, firstLine, width, widthRangeFrom, widthRangeTo, i, tempFrom, lineSize); // Move down, because font drawing starts from the baseline - y += line_size.Height; - - const float dx = GetLineOffset(align, width_range_from, width_range_to, line_size); + y += lineSize.Height; // Do the real processing now - const bool done = AssembleCalls(pGUI, string, Font, pObject, FirstLine, Width, width_range_to, dx, y, temp_from, i, x, from); - - // Reset X - x = BufferZone; + const bool done = AssembleCalls(pGUI, string, font, pObject, firstLine, width, widthRangeTo, GetLineOffset(align, widthRangeFrom, widthRangeTo, lineSize), y, tempFrom, i, from); // Update dimensions - m_Size.Width = std::max(m_Size.Width, line_size.Width + BufferZone * 2); - m_Size.Height = std::max(m_Size.Height, y + BufferZone); + m_Size.Width = std::max(m_Size.Width, lineSize.Width + bufferZone * 2); + m_Size.Height = std::max(m_Size.Height, y + bufferZone); - FirstLine = false; + firstLine = false; // Now if we entered as from = i, then we want // i being one minus that, so that it will become @@ -264,7 +278,7 @@ } // Decide width of the line. We need to iterate our floating images. -// this won't be exact because we're assuming the line_size.cy +// this won't be exact because we're assuming the lineSize.cy // will be as our preliminary calculation said. But that may change, // although we'd have to add a couple of more loops to try straightening // this problem out, and it is very unlikely to happen noticeably if one @@ -272,34 +286,34 @@ // is still quite unlikely it will happen. // Loop through left and right side, from and to. void CGUIText::ComputeLineRange( - const SGenerateTextImages& Images, + const SGenerateTextImages& images, const float y, - const float Width, - const float prelim_line_height, - float& width_range_from, - float& width_range_to) const + const float width, + const float prelimLineHeight, + float& widthRangeFrom, + float& widthRangeTo) const { // Floating images are only applicable if word-wrapping is enabled. - if (Width == 0) + if (width == 0) return; for (int j = 0; j < 2; ++j) - for (const SGenerateTextImage& img : Images[j]) + for (const SGenerateTextImage& img : images[j]) { // We're working with two intervals here, the image's and the line height's. // let's find the union of these two. - float union_from, union_to; + float unionFrom, unionTo; - union_from = std::max(y, img.m_YFrom); - union_to = std::min(y + prelim_line_height, img.m_YTo); + unionFrom = std::max(y, img.m_YFrom); + unionTo = std::min(y + prelimLineHeight, img.m_YTo); // The union is not empty - if (union_to > union_from) + if (unionTo > unionFrom) { if (j == 0) - width_range_from = std::max(width_range_from, img.m_Indentation); + widthRangeFrom = std::max(widthRangeFrom, img.m_Indentation); else - width_range_to = std::min(width_range_to, Width - img.m_Indentation); + widthRangeTo = std::min(widthRangeTo, width - img.m_Indentation); } } } @@ -307,21 +321,20 @@ // compute offset based on what kind of alignment float CGUIText::GetLineOffset( const EAlign align, - const float width_range_from, - const float width_range_to, - const CSize2D& line_size) const + const float widthRangeFrom, + const float widthRangeTo, + const CSize2D& lineSize) const { switch (align) { case EAlign::LEFT: - // don't add an offset - return 0.f; + return widthRangeFrom; case EAlign::CENTER: - return ((width_range_to - width_range_from) - line_size.Width) / 2; + return (widthRangeTo + widthRangeFrom - lineSize.Width) / 2; case EAlign::RIGHT: - return width_range_to - line_size.Width; + return widthRangeTo - lineSize.Width; default: debug_warn(L"Broken EAlign in CGUIText()"); @@ -332,94 +345,101 @@ bool CGUIText::AssembleCalls( const CGUI& pGUI, const CGUIString& string, - const CStrIntern& Font, + const CStrIntern& font, const IGUIObject* pObject, - const bool FirstLine, - const float Width, - const float width_range_to, + const bool firstLine, + const float width, + const float widthRangeTo, const float dx, const float y, - const int temp_from, + const int tempFrom, const int i, - float& x, int& from) { bool done = false; + float x = dx; - for (int j = temp_from; j <= i; ++j) + for (int j = tempFrom; j <= i; ++j) { - // We don't want to use Feedback now, so we'll have to use another one. - CGUIString::SFeedback Feedback2; + // We don't want to use feedback now, so we'll have to use another one. + CGUIString::SFeedback feedback2; // Defaults - string.GenerateTextCall(pGUI, Feedback2, Font, string.m_Words[j], string.m_Words[j+1], FirstLine, pObject); + string.GenerateTextCall(pGUI, feedback2, font, string.m_Words[j], string.m_Words[j+1], firstLine, pObject); // Iterate all and set X/Y values // Since X values are not set, we need to make an internal // iteration with an increment that will append the internal - // x, that is what x_pointer is for. - float x_pointer = 0.f; + // x, that is what xPointer is for. + float xPointer = 0.f; - for (STextCall& tc : Feedback2.m_TextCalls) + for (STextCall& tc : feedback2.m_TextCalls) { - tc.m_Pos = CVector2D(dx + x + x_pointer, y); + tc.m_Pos = CVector2D(x + xPointer, y); - x_pointer += tc.m_Size.Width; + xPointer += tc.m_Size.Width; if (tc.m_pSpriteCall) tc.m_pSpriteCall->m_Area += tc.m_Pos - CSize2D(0, tc.m_pSpriteCall->m_Area.GetHeight()); } - // Append X value. - x += Feedback2.m_Size.Width; + x += feedback2.m_Size.Width; - // The first word overrides the width limit, what we - // do, in those cases, are just drawing that word even - // though it'll extend the object. - if (Width != 0) // only if word-wrapping is applicable + if (width != 0) // only if word-wrapping is applicable { - if (Feedback2.m_NewLine) + // Check if we need to wrap, using the same algorithm as ComputeLineSize + // This means we must ignore the 'space before the next word' for the purposes of wrapping. + CFontMetrics currentFont(font); + float spaceWidth = currentFont.GetCharacterWidth(L' '); + float spaceCorrection = feedback2.m_EndsWithSpace ? spaceWidth : 0.f; + + if (feedback2.m_NewLine) { from = j + 1; // Sprite call can exist within only a newline segment, // therefore we need this. - if (!Feedback2.m_SpriteCalls.empty()) + if (!feedback2.m_SpriteCalls.empty()) { - auto newEnd = std::remove_if(Feedback2.m_TextCalls.begin(), Feedback2.m_TextCalls.end(), [](const STextCall& call) { return !call.m_pSpriteCall; }); + auto newEnd = std::remove_if(feedback2.m_TextCalls.begin(), feedback2.m_TextCalls.end(), [](const STextCall& call) { return !call.m_pSpriteCall; }); m_TextCalls.insert( m_TextCalls.end(), - std::make_move_iterator(Feedback2.m_TextCalls.begin()), + std::make_move_iterator(feedback2.m_TextCalls.begin()), std::make_move_iterator(newEnd)); m_SpriteCalls.insert( m_SpriteCalls.end(), - std::make_move_iterator(Feedback2.m_SpriteCalls.begin()), - std::make_move_iterator(Feedback2.m_SpriteCalls.end())); + std::make_move_iterator(feedback2.m_SpriteCalls.begin()), + std::make_move_iterator(feedback2.m_SpriteCalls.end())); } break; } - else if (x > width_range_to && j == temp_from) + else if (x - spaceCorrection > widthRangeTo && j == tempFrom) { + // The first word overrides the width limit, what we do, + // in those cases, is just drawing that word even + // though it'll extend the object. + // Ergo: do not break, since we want it to be added to m_TextCalls. from = j+1; - // do not break, since we want it to be added to m_TextCalls + // To avoid doing redundant computations, set up j to exit the loop right away. + j = i + 1; } - else if (x > width_range_to) + else if (x - spaceCorrection > widthRangeTo) { from = j; break; } } - // Add the whole Feedback2.m_TextCalls to our m_TextCalls. + // Add the whole feedback2.m_TextCalls to our m_TextCalls. m_TextCalls.insert( m_TextCalls.end(), - std::make_move_iterator(Feedback2.m_TextCalls.begin()), - std::make_move_iterator(Feedback2.m_TextCalls.end())); + std::make_move_iterator(feedback2.m_TextCalls.begin()), + std::make_move_iterator(feedback2.m_TextCalls.end())); m_SpriteCalls.insert( m_SpriteCalls.end(), - std::make_move_iterator(Feedback2.m_SpriteCalls.begin()), - std::make_move_iterator(Feedback2.m_SpriteCalls.end())); + std::make_move_iterator(feedback2.m_SpriteCalls.begin()), + std::make_move_iterator(feedback2.m_SpriteCalls.end())); if (j == static_cast(string.m_Words.size()) - 2) done = true; @@ -430,7 +450,10 @@ void CGUIText::Draw(CGUI& pGUI, CCanvas2D& canvas, const CGUIColor& DefaultColor, const CVector2D& pos, CRect clipping) const { - bool isClipped = clipping != CRect(); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + + const bool isClipped = clipping != CRect(); if (isClipped) { // Make clipping rect as small as possible to prevent rounding errors @@ -439,12 +462,17 @@ clipping.left = std::ceil(clipping.left); clipping.right = std::floor(clipping.right); - glEnable(GL_SCISSOR_TEST); - glScissor( - std::ceil(clipping.left * g_GuiScale), - std::ceil(g_yres - clipping.bottom * g_GuiScale), - std::floor(clipping.GetWidth() * g_GuiScale), - std::floor(clipping.GetHeight() * g_GuiScale)); + if (clipping.GetWidth() <= 0.0f || clipping.GetHeight() <= 0.0f) + return; + + const float scale = g_VideoMode.GetScale(); + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = std::ceil(clipping.left * scale); + scissorRect.y = std::ceil(g_yres - clipping.bottom * scale); + scissorRect.width = std::floor(clipping.GetWidth() * scale); + scissorRect.height = std::floor(clipping.GetHeight() * scale); + // TODO: move scissors to CCanvas2D. + deviceCommandContext->SetScissors(1, &scissorRect); } CTextRenderer textRenderer; @@ -468,5 +496,5 @@ pGUI.DrawSprite(sc.m_Sprite, canvas, sc.m_Area + pos); if (isClipped) - glDisable(GL_SCISSOR_TEST); + deviceCommandContext->SetScissors(0, nullptr); } diff -Nru 0ad-0.0.25b/source/gui/CGUIText.h 0ad-0.0.26/source/gui/CGUIText.h --- 0ad-0.0.25b/source/gui/CGUIText.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/gui/CGUIText.h 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -155,16 +155,16 @@ * will be sent to the Renderer. Also, horizontal alignment * is taken into acount in this method but NOT vertical alignment. * - * @param Text Text to generate CGUIText object from - * @param Font Default font, notice both Default color and default font + * @param string Text to generate CGUIText object from. + * @param font Default font, notice both Default color and default font * can be changed by tags. - * @param Width Width, 0 if no word-wrapping. - * @param BufferZone space between text and edge, and space between text and images. - * @param Align Horizontal alignment (left / center / right). + * @param width Width, 0 if no word-wrapping. + * @param bufferZone Space between text and edge, and space between text and images. + * @param align Horizontal alignment (left / center / right). * @param pObject Optional parameter for error output. Used *only* if error parsing fails, * and we need to be able to output which object the error occurred in to aid the user. */ - CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& FontW, const float Width, const float BufferZone, const EAlign align, const IGUIObject* pObject); + CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& fontW, const float width, const float bufferZone, const EAlign align, const IGUIObject* pObject); /** * Draw this CGUIText object @@ -181,68 +181,66 @@ bool ProcessLine( const CGUI& pGUI, const CGUIString& string, - const CStrIntern& Font, + const CStrIntern& font, const IGUIObject* pObject, - const SGenerateTextImages& Images, + const SGenerateTextImages& images, const EAlign align, - const float prelim_line_height, - const float Width, - const float BufferZone, - bool& FirstLine, - float& x, + const float prelimLineHeight, + const float width, + const float bufferZone, + bool& firstLine, float& y, int& i, int& from); void SetupSpriteCalls( const CGUI& pGUI, - const std::array, 2>& FeedbackImages, + const std::array, 2>& feedbackImages, const float y, - const float Width, - const float BufferZone, + const float width, + const float bufferZone, const int i, - const int pos_last_img, - SGenerateTextImages& Images); + const int posLastImage, + SGenerateTextImages& images); float GetLineOffset( const EAlign align, - const float width_range_from, - const float width_range_to, - const CSize2D& line_size) const; + const float widthRangeFrom, + const float widthRangeTo, + const CSize2D& lineSize) const; void ComputeLineRange( - const SGenerateTextImages& Images, + const SGenerateTextImages& images, const float y, - const float Width, - const float prelim_line_height, - float& width_range_from, - float& width_range_to) const; + const float width, + const float prelimLineHeight, + float& widthRangeFrom, + float& widthRangeTo) const; void ComputeLineSize( const CGUI& pGUI, const CGUIString& string, - const CStrIntern& Font, - const bool FirstLine, - const float Width, - const float width_range_to, + const CStrIntern& font, + const bool firstLine, + const float width, + const float widthRangeFrom, + const float widthRangeTo, const int i, - const int temp_from, - float& x, - CSize2D& line_size) const; + const int tempFrom, + CSize2D& lineSize) const; bool AssembleCalls( const CGUI& pGUI, const CGUIString& string, - const CStrIntern& Font, + const CStrIntern& font, const IGUIObject* pObject, - const bool FirstLine, - const float Width, - const float width_range_to, + const bool firstLine, + const float width, + const float widthRangeTo, const float dx, const float y, - const int temp_from, + const int tempFrom, const int i, - float& x, int& from); /** @@ -275,8 +273,8 @@ float m_Indentation; void SetupSpriteCall( - const bool Left, CGUIText::SSpriteCall& SpriteCall, const float width, const float y, - const CSize2D& Size, const CStr& TextureName, const float BufferZone); + const bool left, CGUIText::SSpriteCall& spriteCall, const float width, const float y, + const CSize2D& size, const CStr& textureName, const float bufferZone); }; #endif // INCLUDED_GUITEXT diff -Nru 0ad-0.0.25b/source/gui/GUIManager.cpp 0ad-0.0.26/source/gui/GUIManager.cpp --- 0ad-0.0.25b/source/gui/GUIManager.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/GUIManager.cpp 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,16 +25,22 @@ #include "ps/Filesystem.h" #include "ps/GameSetup/Config.h" #include "ps/Profile.h" +#include "ps/VideoMode.h" #include "ps/XML/Xeromyces.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h" -CGUIManager* g_GUI = nullptr; +namespace +{ -const CStr CGUIManager::EventNameWindowResized = "WindowResized"; +const CStr EVENT_NAME_GAME_LOAD_PROGRESS = "GameLoadProgress"; +const CStr EVENT_NAME_WINDOW_RESIZED = "WindowResized"; +} // anonymous namespace + +CGUIManager* g_GUI = nullptr; // General TODOs: // @@ -97,7 +103,12 @@ initDataClone = Script::WriteStructuredClone(rq, initData); } - m_PageStack.clear(); + if (!m_PageStack.empty()) + { + // Make sure we unfocus anything on the current page. + m_PageStack.back().gui->SendFocusMessage(GUIM_LOST_FOCUS); + m_PageStack.clear(); + } PushPage(pageName, initDataClone, JS::UndefinedHandleValue); } @@ -106,8 +117,13 @@ { // Store the callback handler in the current GUI page before opening the new one if (!m_PageStack.empty() && !callbackFunction.isUndefined()) + { m_PageStack.back().SetCallbackFunction(*m_ScriptInterface, callbackFunction); + // Make sure we unfocus anything on the current page. + m_PageStack.back().gui->SendFocusMessage(GUIM_LOST_FOCUS); + } + // Push the page prior to loading its contents, because that may push // another GUI page on init which should be pushed on top of this new page. m_PageStack.emplace_back(pageName, initData); @@ -122,8 +138,14 @@ return; } + // Make sure we unfocus anything on the current page. + m_PageStack.back().gui->SendFocusMessage(GUIM_LOST_FOCUS); + m_PageStack.pop_back(); m_PageStack.back().PerformCallbackFunction(args); + + // We return to a page where some object might have been focused. + m_PageStack.back().gui->SendFocusMessage(GUIM_GOT_FOCUS); } CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const Script::StructuredClone initData) @@ -146,7 +168,7 @@ hotloadData = Script::WriteStructuredClone(rq, hotloadDataVal); } - g_CursorName = g_DefaultCursor; + g_VideoMode.ResetCursor(); inputs.clear(); gui.reset(new CGUI(scriptContext)); @@ -366,12 +388,12 @@ p.gui->TickObjects(); } -void CGUIManager::Draw() const +void CGUIManager::Draw(CCanvas2D& canvas) const { PROFILE3_GPU("gui"); for (const SGUIPage& p : m_PageStack) - p.gui->Draw(); + p.gui->Draw(canvas); } void CGUIManager::UpdateResolution() @@ -382,7 +404,7 @@ for (const SGUIPage& p : pageStack) { p.gui->UpdateResolution(); - p.gui->SendEventToAll(EventNameWindowResized); + p.gui->SendEventToAll(EVENT_NAME_WINDOW_RESIZED); } } @@ -400,6 +422,22 @@ return templateRoot; } +void CGUIManager::DisplayLoadProgress(int percent, const wchar_t* pending_task) +{ + const ScriptInterface& scriptInterface = *(GetActiveGUI()->GetScriptInterface()); + ScriptRequest rq(scriptInterface); + + JS::RootedValueVector paramData(rq.cx); + + ignore_result(paramData.append(JS::NumberValue(percent))); + + JS::RootedValue valPendingTask(rq.cx); + Script::ToJSVal(rq, &valPendingTask, pending_task); + ignore_result(paramData.append(valPendingTask)); + + SendEventToAll(EVENT_NAME_GAME_LOAD_PROGRESS, paramData); +} + // This returns a shared_ptr to make sure the CGUI doesn't get deallocated // while we're in the middle of calling a function on it (e.g. if a GUI script // calls SwitchPage) diff -Nru 0ad-0.0.25b/source/gui/GUIManager.h 0ad-0.0.26/source/gui/GUIManager.h --- 0ad-0.0.25b/source/gui/GUIManager.h 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/gui/GUIManager.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include #include +class CCanvas2D; class CGUI; /** @@ -106,7 +107,7 @@ /** * See CGUI::Draw; applies to @em all loaded pages. */ - void Draw() const; + void Draw(CCanvas2D& canvas) const; /** * See CGUI::UpdateResolution; applies to @em all loaded pages. @@ -123,6 +124,11 @@ */ const CParamNode& GetTemplate(const std::string& templateName); + /** + * Display progress / description in loading screen. + */ + void DisplayLoadProgress(int percent, const wchar_t* pending_task); + private: struct SGUIPage { @@ -161,8 +167,6 @@ std::shared_ptr callbackFunction; }; - const static CStr EventNameWindowResized; - std::shared_ptr top() const; std::shared_ptr m_ScriptContext; diff -Nru 0ad-0.0.25b/source/gui/GUIMatrix.cpp 0ad-0.0.26/source/gui/GUIMatrix.cpp --- 0ad-0.0.25b/source/gui/GUIMatrix.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/gui/GUIMatrix.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,16 +18,15 @@ #include "precompiled.h" #include "GUIMatrix.h" - #include "maths/Matrix3D.h" +#include "ps/VideoMode.h" extern int g_xres, g_yres; -extern float g_GuiScale; CMatrix3D GetDefaultGuiMatrix() { - float xres = g_xres / g_GuiScale; - float yres = g_yres / g_GuiScale; + float xres = g_xres / g_VideoMode.GetScale(); + float yres = g_yres / g_VideoMode.GetScale(); CMatrix3D m; m.SetIdentity(); diff -Nru 0ad-0.0.25b/source/gui/GUIRenderer.cpp 0ad-0.0.26/source/gui/GUIRenderer.cpp --- 0ad-0.0.25b/source/gui/GUIRenderer.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/GUIRenderer.cpp 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,9 +26,6 @@ #include "gui/GUIMatrix.h" #include "gui/SettingTypes/CGUIColor.h" #include "i18n/L10n.h" -#include "lib/ogl.h" -#include "lib/res/graphics/ogl_tex.h" -#include "lib/res/h_mgr.h" #include "lib/tex/tex.h" #include "lib/utf8.h" #include "ps/CLogger.h" @@ -205,7 +202,8 @@ if (!(*cit)->m_TextureName.empty()) { CTextureProperties textureProps(g_L10n.LocalizePath((*cit)->m_TextureName)); - textureProps.SetWrap((*cit)->m_WrapMode); + textureProps.SetAddressMode((*cit)->m_AddressMode); + textureProps.SetIgnoreQuality(true); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); hasTexture = true; @@ -324,9 +322,8 @@ // Iterate through each DrawCall, and execute whatever drawing code is being called for (DrawCalls::const_iterator cit = Calls.begin(); cit != Calls.end(); ++cit) { - // A hack to preload the handle to get a correct texture size. - GLuint h; - ogl_tex_get_texture_id(cit->m_Texture->GetHandle(), &h); + // A hack to get a correct backend texture size. + cit->m_Texture->UploadBackendTextureIfNeeded(g_Renderer.GetDeviceCommandContext()); CRect texCoords = cit->ComputeTexCoords().Scale( cit->m_Texture->GetWidth(), cit->m_Texture->GetHeight()); diff -Nru 0ad-0.0.25b/source/gui/GUIRenderer.h 0ad-0.0.26/source/gui/GUIRenderer.h --- 0ad-0.0.25b/source/gui/GUIRenderer.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/GUIRenderer.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,8 +21,8 @@ #include "graphics/Color.h" #include "graphics/ShaderTechniquePtr.h" #include "graphics/Texture.h" -#include "lib/res/handle.h" #include "maths/Rect.h" +#include "ps/CStrForward.h" #include "ps/CStrIntern.h" #include @@ -31,7 +31,6 @@ class CCanvas2D; class CGUI; class CGUISprite; -class CStr8; struct CGUIColor; struct SGUIImage; diff -Nru 0ad-0.0.25b/source/gui/ObjectBases/IGUIScrollBarOwner.h 0ad-0.0.26/source/gui/ObjectBases/IGUIScrollBarOwner.h --- 0ad-0.0.25b/source/gui/ObjectBases/IGUIScrollBarOwner.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectBases/IGUIScrollBarOwner.h 2022-08-21 12:45:36.000000000 +0000 @@ -18,11 +18,12 @@ #ifndef INCLUDED_IGUISCROLLBAROWNER #define INCLUDED_IGUISCROLLBAROWNER +#include "ps/CStrForward.h" + #include #include class CCanvas2D; -class CStr8; struct SGUIMessage; struct SGUIScrollBarStyle; class IGUIScrollBar; diff -Nru 0ad-0.0.25b/source/gui/ObjectBases/IGUITextOwner.h 0ad-0.0.26/source/gui/ObjectBases/IGUITextOwner.h --- 0ad-0.0.25b/source/gui/ObjectBases/IGUITextOwner.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectBases/IGUITextOwner.h 2022-08-21 12:45:37.000000000 +0000 @@ -33,6 +33,7 @@ #include "gui/CGUISetting.h" #include "gui/SettingTypes/EAlign.h" #include "maths/Rect.h" +#include "ps/CStrForward.h" #include @@ -43,7 +44,6 @@ class CGUIString; class IGUIObject; -class CStrW; class CVector2D; /** diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CChart.cpp 0ad-0.0.26/source/gui/ObjectTypes/CChart.cpp --- 0ad-0.0.25b/source/gui/ObjectTypes/CChart.cpp 2021-07-27 21:56:51.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CChart.cpp 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -103,12 +103,12 @@ } else { - canvas.DrawLine(linePoints, 1.1f, data.m_Color); + canvas.DrawLine(linePoints, 2.0f, data.m_Color); linePoints.clear(); } } if (!linePoints.empty()) - canvas.DrawLine(linePoints, 1.1f, data.m_Color); + canvas.DrawLine(linePoints, 2.0f, data.m_Color); } if (m_AxisWidth > 0) diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CHotkeyPicker.h 0ad-0.0.26/source/gui/ObjectTypes/CHotkeyPicker.h --- 0ad-0.0.25b/source/gui/ObjectTypes/CHotkeyPicker.h 2021-07-27 21:56:51.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CHotkeyPicker.h 2022-08-21 12:45:35.000000000 +0000 @@ -25,8 +25,6 @@ #include -class ScriptInterface; - /** * When in focus, returns all currently pressed keys. * After a set time without changes, it will trigger a "combination" event. diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CInput.cpp 0ad-0.0.26/source/gui/ObjectTypes/CInput.cpp --- 0ad-0.0.25b/source/gui/ObjectTypes/CInput.cpp 2021-07-27 21:56:51.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CInput.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,6 +31,8 @@ #include "ps/GameSetup/Config.h" #include "ps/Globals.h" #include "ps/Hotkey.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/Renderer.h" #include @@ -1187,7 +1189,7 @@ m_GeneratedPlaceholderTextValid = false; } -void CInput::Draw(CCanvas2D& canvas) +void CInput::DrawContent(CCanvas2D& canvas) { if (m_CursorBlinkRate > 0.0) { @@ -1217,35 +1219,6 @@ CFontMetrics font(font_name); - // We'll have to setup clipping manually, since we're doing the rendering manually. - CRect cliparea(m_CachedActualSize); - - // First we'll figure out the clipping area, which is the cached actual size - // substracted by an optional scrollbar - if (m_ScrollBar) - { - scroll = GetScrollBar(0).GetPos(); - - // substract scrollbar from cliparea - if (cliparea.right > GetScrollBar(0).GetOuterRect().left && - cliparea.right <= GetScrollBar(0).GetOuterRect().right) - cliparea.right = GetScrollBar(0).GetOuterRect().left; - - if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && - cliparea.left < GetScrollBar(0).GetOuterRect().right) - cliparea.left = GetScrollBar(0).GetOuterRect().right; - } - - if (cliparea != CRect()) - { - glEnable(GL_SCISSOR_TEST); - glScissor( - cliparea.left * g_GuiScale, - g_yres - cliparea.bottom * g_GuiScale, - cliparea.GetWidth() * g_GuiScale, - cliparea.GetHeight() * g_GuiScale); - } - // These are useful later. int VirtualFrom, VirtualTo; @@ -1269,7 +1242,7 @@ textRenderer.Translate( (float)(int)(m_CachedActualSize.left) + m_BufferZone, - (float)(int)(m_CachedActualSize.top+h) + m_BufferZone); + (float)(int)(m_CachedActualSize.top + h) + m_BufferZone); // U+FE33: PRESENTATION FORM FOR VERTICAL LOW LINE // (sort of like a | which is aligned to the left of most characters) @@ -1319,15 +1292,15 @@ bool done = false; for (std::list::const_iterator it = m_CharacterPositions.begin(); - it != m_CharacterPositions.end(); - ++it, buffered_y += ls, x_pointer = 0.f) + it != m_CharacterPositions.end(); + ++it, buffered_y += ls, x_pointer = 0.f) { if (m_MultiLine && buffered_y > m_CachedActualSize.GetHeight()) break; // We might as well use 'i' here to iterate, because we need it // (often compared against ints, so don't make it size_t) - for (int i = 0; i < (int)it->m_ListOfX.size()+2; ++i) + for (int i = 0; i < (int)it->m_ListOfX.size() + 2; ++i) { if (it->m_ListStart + i == virtualFrom) { @@ -1341,7 +1314,7 @@ box_x = x_pointer; } - const bool at_end = (i == (int)it->m_ListOfX.size()+1); + const bool at_end = (i == (int)it->m_ListOfX.size() + 1); if (drawing_box && (it->m_ListStart + i == virtualTo || at_end)) { @@ -1425,8 +1398,8 @@ bool using_selected_color = false; for (std::list::const_iterator it = m_CharacterPositions.begin(); - it != m_CharacterPositions.end(); - ++it, buffered_y += ls) + it != m_CharacterPositions.end(); + ++it, buffered_y += ls) { if (buffered_y + m_BufferZone >= -ls || !m_MultiLine) { @@ -1443,7 +1416,7 @@ // We might as well use 'i' here, because we need it // (often compared against ints, so don't make it size_t) - for (int i = 0; i < (int)it->m_ListOfX.size()+1; ++i) + for (int i = 0; i < (int)it->m_ListOfX.size() + 1; ++i) { if (!m_MultiLine && i < (int)it->m_ListOfX.size()) { @@ -1453,7 +1426,7 @@ if (i == 0) textRenderer.Translate(it->m_ListOfX[i], 0.f); else - textRenderer.Translate(it->m_ListOfX[i] - it->m_ListOfX[i-1], 0.f); + textRenderer.Translate(it->m_ListOfX[i] - it->m_ListOfX[i - 1], 0.f); continue; } @@ -1467,14 +1440,14 @@ } // selecting only one, then we need only to draw a cursor. - if (i != (int)it->m_ListOfX.size() && it->m_ListStart + i == m_iBufferPos && m_CursorVisState) + if (i != (int)it->m_ListOfX.size() && it->m_ListStart + i == m_iBufferPos && m_CursorVisState && !m_Readonly) textRenderer.Put(0.0f, 0.0f, L"_"); // Drawing selected area if (SelectingText() && - it->m_ListStart + i >= VirtualFrom && - it->m_ListStart + i < VirtualTo && - !using_selected_color) + it->m_ListStart + i >= VirtualFrom && + it->m_ListStart + i < VirtualTo && + !using_selected_color) { using_selected_color = true; textRenderer.SetCurrentColor(m_TextColorSelected); @@ -1490,14 +1463,14 @@ // check it's now outside a one-liner, then we'll break if (!m_MultiLine && i < (int)it->m_ListOfX.size() && - it->m_ListOfX[i] - m_HorizontalScroll > m_CachedActualSize.GetWidth() - m_BufferZone) + it->m_ListOfX[i] - m_HorizontalScroll > m_CachedActualSize.GetWidth() - m_BufferZone) break; } if (it->m_ListStart + (int)it->m_ListOfX.size() == m_iBufferPos) { textRenderer.SetCurrentColor(m_TextColor); - if (m_CursorVisState) + if (m_CursorVisState && !m_Readonly) textRenderer.PutAdvance(L"_"); if (using_selected_color) @@ -1511,9 +1484,49 @@ } canvas.DrawText(textRenderer); +} + +void CInput::Draw(CCanvas2D& canvas) +{ + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + + // We'll have to setup clipping manually, since we're doing the rendering manually. + CRect cliparea(m_CachedActualSize); + + // First we'll figure out the clipping area, which is the cached actual size + // substracted by an optional scrollbar + if (m_ScrollBar) + { + // substract scrollbar from cliparea + if (cliparea.right > GetScrollBar(0).GetOuterRect().left && + cliparea.right <= GetScrollBar(0).GetOuterRect().right) + cliparea.right = GetScrollBar(0).GetOuterRect().left; + + if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && + cliparea.left < GetScrollBar(0).GetOuterRect().right) + cliparea.left = GetScrollBar(0).GetOuterRect().right; + } + + const bool isClipped = cliparea != CRect(); + if (isClipped) + { + if (cliparea.GetWidth() <= 0.0f || cliparea.GetHeight() <= 0.0f) + return; + const float scale = g_VideoMode.GetScale(); + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = cliparea.left * scale; + scissorRect.y = g_yres - cliparea.bottom * scale; + scissorRect.width = cliparea.GetWidth() * scale; + scissorRect.height = cliparea.GetHeight() * scale; + // TODO: move scissors to CCanvas2D. + deviceCommandContext->SetScissors(1, &scissorRect); + } + + DrawContent(canvas); - if (cliparea != CRect()) - glDisable(GL_SCISSOR_TEST); + if (isClipped) + deviceCommandContext->SetScissors(0, nullptr); if (m_Caption->empty() && !m_PlaceholderText->GetRawString().empty()) DrawPlaceholderText(canvas, cliparea); diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CInput.h 0ad-0.0.26/source/gui/ObjectTypes/CInput.h --- 0ad-0.0.25b/source/gui/ObjectTypes/CInput.h 2021-07-27 21:56:51.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CInput.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -97,6 +97,8 @@ */ virtual void Draw(CCanvas2D& canvas); + void DrawContent(CCanvas2D& canvas); + /** * Calculate m_CharacterPosition * the main task for this function is to perfom word-wrapping diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CMiniMap.cpp 0ad-0.0.26/source/gui/ObjectTypes/CMiniMap.cpp --- 0ad-0.0.25b/source/gui/ObjectTypes/CMiniMap.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CMiniMap.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ #include "graphics/Canvas2D.h" #include "graphics/GameView.h" -#include "graphics/LOSTexture.h" #include "graphics/MiniMapTexture.h" #include "graphics/MiniPatch.h" #include "graphics/ShaderManager.h" @@ -29,14 +28,14 @@ #include "graphics/Terrain.h" #include "graphics/TerrainTextureEntry.h" #include "graphics/TerrainTextureManager.h" -#include "graphics/TerritoryTexture.h" +#include "graphics/TextureManager.h" #include "gui/CGUI.h" #include "gui/GUIManager.h" #include "gui/GUIMatrix.h" #include "lib/bits.h" #include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" #include "lib/timer.h" +#include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" @@ -47,6 +46,7 @@ #include "ps/World.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "scriptinterface/Object.h" #include "simulation2/Simulation2.h" @@ -59,15 +59,9 @@ #include #include -extern bool g_GameRestarted; - namespace { -// Set max drawn entities to UINT16_MAX for now, which is more than enough -// TODO: we should be cleverer about drawing them to reduce clutter -const u16 MAX_ENTITIES_DRAWN = 65535; - // Adds segments pieces lying inside the circle to lines. void CropPointsByCircle(const std::array& points, const CVector3D& center, const float radius, std::vector* lines) { @@ -99,15 +93,18 @@ } } -void DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float mapScale) +void DrawTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + float angle, float x, float y, float x2, float y2, float mapScale) { // Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m) // Scale square maps to fit in circular minimap area const float s = sin(angle) * mapScale; const float c = cos(angle) * mapScale; - const float m = coordMax / 2.f; + const float m = 0.5f; - float quadTex[] = { + float quadTex[] = + { m*(-c + s + 1.f), m*(-c + -s + 1.f), m*(c + s + 1.f), m*(-c + s + 1.f), m*(c + -s + 1.f), m*(c + s + 1.f), @@ -116,7 +113,8 @@ m*(-c + -s + 1.f), m*(c + -s + 1.f), m*(-c + s + 1.f), m*(-c + -s + 1.f) }; - float quadVerts[] = { + float quadVerts[] = + { x, y, 0.0f, x2, y, 0.0f, x2, y2, 0.0f, @@ -126,12 +124,21 @@ x, y, 0.0f }; - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(3, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); - if (!g_Renderer.DoSkipSubmit()) - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); } } // anonymous namespace @@ -140,62 +147,15 @@ CMiniMap::CMiniMap(CGUI& pGUI) : IGUIObject(pGUI), - m_MapSize(0), m_MapScale(1.f), - m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), m_Mask(this, "mask", false), - m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), + m_MapSize(0), m_MapScale(1.f), m_Mask(this, "mask", false), m_FlareTextureCount(this, "flare_texture_count", 0), m_FlareRenderSize(this, "flare_render_size", 0), m_FlareInterleave(this, "flare_interleave", false), m_FlareAnimationSpeed(this, "flare_animation_speed", 0.0f), - m_FlareLifetimeSeconds(this, "flare_lifetime_seconds", 0.0f) + m_FlareLifetimeSeconds(this, "flare_lifetime_seconds", 0.0f), + m_FlareStartFadeSeconds(this, "flare_start_fade_seconds", 0.0f), + m_FlareStopFadeSeconds(this, "flare_stop_fade_seconds", 0.0f) { m_Clicking = false; m_MouseHovering = false; - - m_AttributePos.type = GL_FLOAT; - m_AttributePos.elems = 2; - m_VertexArray.AddAttribute(&m_AttributePos); - - m_AttributeColor.type = GL_UNSIGNED_BYTE; - m_AttributeColor.elems = 4; - m_VertexArray.AddAttribute(&m_AttributeColor); - - m_VertexArray.SetNumVertices(MAX_ENTITIES_DRAWN); - m_VertexArray.Layout(); - - m_IndexArray.SetNumVertices(MAX_ENTITIES_DRAWN); - m_IndexArray.Layout(); - VertexArrayIterator index = m_IndexArray.GetIterator(); - for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) - *index++ = i; - m_IndexArray.Upload(); - m_IndexArray.FreeBackingStore(); - - VertexArrayIterator attrPos = m_AttributePos.GetIterator(); - VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); - for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) - { - (*attrColor)[0] = 0; - (*attrColor)[1] = 0; - (*attrColor)[2] = 0; - (*attrColor)[3] = 0; - ++attrColor; - - (*attrPos)[0] = -10000.0f; - (*attrPos)[1] = -10000.0f; - - ++attrPos; - - } - m_VertexArray.Upload(); - - double blinkDuration = 1.0; - - // Tests won't have config initialised - if (CConfigDB::IsInitialised()) - { - CFG_GET_VAL("gui.session.minimap.pingduration", m_PingDuration); - CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration); - } - m_HalfBlinkDuration = blinkDuration/2; } CMiniMap::~CMiniMap() = default; @@ -267,29 +227,24 @@ LOGERROR("Invalid value for flare texture count. Valid range is 0-99."); return; } - const CStr numberingFormat = "%02u"; + const CStr textureNumberingFormat = "art/textures/animated/minimap-flare/frame%02u.png"; m_FlareTextures.clear(); m_FlareTextures.reserve(m_FlareTextureCount); for (u32 i = 0; i < m_FlareTextureCount; ++i) { - CTextureProperties textureProps(L"art/textures/animated/minimap-flare/frame" + CStr(fmt::sprintf(numberingFormat, i)).FromUTF8() + L".png"); + CTextureProperties textureProps(fmt::sprintf(textureNumberingFormat, i).c_str()); + textureProps.SetIgnoreQuality(true); m_FlareTextures.emplace_back(g_Renderer.GetTextureManager().CreateTexture(textureProps)); } } bool CMiniMap::IsMouseOver() const { - // Get the mouse position. const CVector2D& mousePos = m_pGUI.GetMousePos(); - // Get the position of the center of the minimap. - CVector2D minimapCenter = CVector2D(m_CachedActualSize.left + m_CachedActualSize.GetWidth() / 2.0, m_CachedActualSize.bottom - m_CachedActualSize.GetHeight() / 2.0); // Take the magnitude of the difference of the mouse position and minimap center. - double distFromCenter = sqrt(pow((mousePos.X - minimapCenter.X), 2) + pow((mousePos.Y - minimapCenter.Y), 2)); + const float distanceFromCenter = (mousePos - m_CachedActualSize.CenterPoint()).Length(); // If the distance is less then the radius of the minimap (half the width) the mouse is over the minimap. - if (distFromCenter < m_CachedActualSize.GetWidth() / 2.0) - return true; - else - return false; + return distanceFromCenter < m_CachedActualSize.GetWidth() / 2.0; } void CMiniMap::GetMouseWorldCoordinates(float& x, float& z) const @@ -323,6 +278,24 @@ return -atan2(cameraIn.X, cameraIn.Z); } +CVector2D CMiniMap::WorldSpaceToMiniMapSpace(const CVector3D& worldPosition) const +{ + // Coordinates with 0,0 in the middle of the minimap and +-0.5 as max. + const float invTileMapSize = 1.0f / static_cast(TERRAIN_TILE_SIZE * m_MapSize); + const float relativeX = (worldPosition.X * invTileMapSize - 0.5) / m_MapScale; + const float relativeY = (worldPosition.Z * invTileMapSize - 0.5) / m_MapScale; + + // Rotate coordinates. + const float angle = GetAngle(); + const float rotatedX = cos(angle) * relativeX + sin(angle) * relativeY; + const float rotatedY = -sin(angle) * relativeX + cos(angle) * relativeY; + + // Calculate coordinates in GUI space. + return CVector2D( + m_CachedActualSize.left + (0.5f + rotatedX) * m_CachedActualSize.GetWidth(), + m_CachedActualSize.bottom - (0.5f + rotatedY) * m_CachedActualSize.GetHeight()); +} + bool CMiniMap::FireWorldClickEvent(int button, int UNUSED(clicks)) { ScriptRequest rq(g_GUI->GetActiveGUI()->GetScriptInterface()); @@ -345,123 +318,78 @@ // This sets up and draws the rectangle on the minimap // which represents the view of the camera in the world. -void CMiniMap::DrawViewRect(const CMatrix3D& transform) const +void CMiniMap::DrawViewRect(CCanvas2D& canvas) const { // Compute the camera frustum intersected with a fixed-height plane. // Use the water height as a fixed base height, which should be the lowest we can go - float h = g_Renderer.GetWaterManager()->m_WaterHeight; - const float width = m_CachedActualSize.GetWidth(); - const float height = m_CachedActualSize.GetHeight(); - const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize); + const float sampleHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight; const CCamera* camera = g_Game->GetView()->GetCamera(); const std::array hitPoints = { - camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h), - camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h), - camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h), - camera->GetWorldCoordinates(0, 0, h) + camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), sampleHeight), + camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), sampleHeight), + camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, sampleHeight), + camera->GetWorldCoordinates(0, 0, sampleHeight) }; - std::vector lines; + std::vector worldSpaceLines; // We need to prevent drawing view bounds out of the map. const float halfMapSize = static_cast((m_MapSize - 1) * TERRAIN_TILE_SIZE) * 0.5f; - CropPointsByCircle(hitPoints, CVector3D(halfMapSize, 0.0f, halfMapSize), halfMapSize * m_MapScale, &lines); - if (lines.empty()) + CropPointsByCircle(hitPoints, CVector3D(halfMapSize, 0.0f, halfMapSize), halfMapSize * m_MapScale, &worldSpaceLines); + if (worldSpaceLines.empty()) return; - std::vector vertices; - vertices.reserve(lines.size() * 2); - for (const CVector3D& point : lines) + for (size_t index = 0; index < worldSpaceLines.size() && index + 1 < worldSpaceLines.size(); index += 2) { - // Convert to minimap space. - vertices.emplace_back(width * point.X * invTileMapSize); - vertices.emplace_back(-(height * point.Z * invTileMapSize)); + const CVector2D from = WorldSpaceToMiniMapSpace(worldSpaceLines[index]); + const CVector2D to = WorldSpaceToMiniMapSpace(worldSpaceLines[index + 1]); + canvas.DrawLine({from, to}, 2.0f, CColor(1.0f, 0.3f, 0.3f, 1.0f)); } - - glLineWidth(2.0f); - - CShaderDefines lineDefines; - lineDefines.Add(str_MINIMAP_LINE, str_1); - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), lineDefines); - tech->BeginPass(); - CShaderProgramPtr shader = tech->GetShader(); - shader->Uniform(str_transform, transform); - shader->Uniform(str_color, 1.0f, 0.3f, 0.3f, 1.0f); - - shader->VertexPointer(2, GL_FLOAT, 0, vertices.data()); - shader->AssertPointersBound(); - - if (!g_Renderer.DoSkipSubmit()) - glDrawArrays(GL_LINES, 0, vertices.size() / 2); - - tech->EndPass(); - - glLineWidth(1.0f); } void CMiniMap::DrawFlare(CCanvas2D& canvas, const MapFlare& flare, double currentTime) const { - if (!m_FlareTextures.size()) + if (m_FlareTextures.empty()) return; - // Coordinates with 0,0 in the middle of the minimap and +-0.5 as max. - const float invTileMapSize = 1.0f / static_cast(TERRAIN_TILE_SIZE * m_MapSize); - const float relativeX = (flare.pos.X * invTileMapSize - 0.5) / m_MapScale; - const float relativeY = (flare.pos.Y * invTileMapSize - 0.5) / m_MapScale; + const CVector2D flareCenter = WorldSpaceToMiniMapSpace(CVector3D(flare.pos.X, 0.0f, flare.pos.Y)); - // Rotate coordinates. - const float angle = GetAngle(); - const float rotatedX = cos(angle) * relativeX + sin(angle) * relativeY; - const float rotatedY = -sin(angle) * relativeX + cos(angle) * relativeY; - // Calculate coordinates in gui space. - const float cx = m_CachedActualSize.left + (0.5f + rotatedX) * m_CachedActualSize.GetWidth(); - const float cy = m_CachedActualSize.bottom - (0.5f + rotatedY) * m_CachedActualSize.GetHeight(); + const CRect destination( + flareCenter.X - m_FlareRenderSize, flareCenter.Y - m_FlareRenderSize, + flareCenter.X + m_FlareRenderSize, flareCenter.Y + m_FlareRenderSize); - const CRect destination(cx-m_FlareRenderSize, cy-m_FlareRenderSize, cx+m_FlareRenderSize, cy+m_FlareRenderSize); + const double deltaTime = currentTime - flare.time; + const double remainingTime = m_FlareLifetimeSeconds - deltaTime; + const u32 flooredStep = floor(deltaTime * m_FlareAnimationSpeed); - const u32 flooredStep = floor((currentTime - flare.time) * m_FlareAnimationSpeed); + const float startFadeAlpha = m_FlareStartFadeSeconds > 0.0f ? deltaTime / m_FlareStartFadeSeconds : 1.0f; + const float stopFadeAlpha = m_FlareStopFadeSeconds > 0.0f ? remainingTime / m_FlareStopFadeSeconds : 1.0f; + const float alpha = Clamp(std::min( + SmoothStep(0.0f, 1.0f, startFadeAlpha), SmoothStep(0.0f, 1.0f, stopFadeAlpha)), + 0.0f, 1.0f); - CTexturePtr texture = m_FlareTextures[flooredStep % m_FlareTextures.size()]; - // TODO: Only draw inside the minimap circle. - canvas.DrawTexture(texture, destination, CRect(0, 0, texture->GetWidth(), texture->GetHeight()), flare.color, CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f); + DrawFlareFrame(canvas, flooredStep % m_FlareTextures.size(), destination, flare.color, alpha); - // Draw a second circle if the first has reached half of the animation + // Draw a second circle if the first has reached half of the animation. if (m_FlareInterleave && flooredStep >= m_FlareTextures.size() / 2) { - texture = m_FlareTextures[(flooredStep - m_FlareTextures.size() / 2) % m_FlareTextures.size()]; - // TODO: Only draw inside the minimap circle. - canvas.DrawTexture(texture, destination, CRect(0, 0, texture->GetWidth(), texture->GetHeight()), flare.color, CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f); + DrawFlareFrame(canvas, (flooredStep - m_FlareTextures.size() / 2) % m_FlareTextures.size(), + destination, flare.color, alpha); } } -struct MinimapUnitVertex +void CMiniMap::DrawFlareFrame(CCanvas2D& canvas, const u32 frameIndex, + const CRect& destination, const CColor& color, float alpha) const { - // This struct is copyable for convenience and because to move is to copy for primitives. - u8 r, g, b, a; - float x, y; -}; - -// Adds a vertex to the passed VertexArray -static void inline addVertex(const MinimapUnitVertex& v, - VertexArrayIterator& attrColor, - VertexArrayIterator& attrPos) -{ - (*attrColor)[0] = v.r; - (*attrColor)[1] = v.g; - (*attrColor)[2] = v.b; - (*attrColor)[3] = v.a; - ++attrColor; - - (*attrPos)[0] = v.x; - (*attrPos)[1] = v.y; - - ++attrPos; -} - -// TODO: render the minimap in a framebuffer and just draw the frambuffer texture -// most of the time, updating the framebuffer twice a frame. -// Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling -// (those operations cause a gpu sync, which slows down the way gpu works) + // TODO: Only draw inside the minimap circle. + CTexturePtr texture = m_FlareTextures[frameIndex % m_FlareTextures.size()]; + CColor finalColor = color; + finalColor.a *= alpha; + canvas.DrawTexture(texture, destination, + CRect(0, 0, texture->GetWidth(), texture->GetHeight()), finalColor, + CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f); +} + void CMiniMap::Draw(CCanvas2D& canvas) { PROFILE3("render minimap"); @@ -471,247 +399,89 @@ if (!g_Game || !g_Game->IsGameStarted()) return; + if (!m_Mask) + canvas.DrawRect(m_CachedActualSize, CColor(0.0f, 0.0f, 0.0f, 1.0f)); + canvas.Flush(); CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); - CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); - CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture(); - // Set our globals in case they hadn't been set before const CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); - ssize_t width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); - ssize_t height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = terrain->GetVerticesPerSide(); - GLsizei textureSize = miniMapTexture.GetTerrainTextureSize(); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); - // only update 2x / second - // (note: since units only move a few pixels per second on the minimap, - // we can get away with infrequent updates; this is slow) - // TODO: Update all but camera at same speed as simulation - static double last_time; - const double cur_time = timer_Time(); - const bool doUpdate = cur_time - last_time > 0.5; - if (doUpdate) - last_time = cur_time; - - const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; - const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; - const float texCoordMax = (float)(m_MapSize - 1) / (float)textureSize; - const float angle = GetAngle(); - const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); - - CShaderProgramPtr shader; - CShaderTechniquePtr tech; - - 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 - if (miniMapTexture.GetTerrainTexture()) - shader->BindTexture(str_baseTex, miniMapTexture.GetTerrainTexture()); - 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); - } - - if (miniMapTexture.GetTerrainTexture()) - DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, m_MapScale); - - 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); - - DrawTexture(shader, 1.0f, angle, x, y, x2, y2, m_MapScale); - tech->EndPass(); - - // Draw the LOS quad in black, using alpha values from the LOS texture - 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, m_MapScale); - tech->EndPass(); - } - - glDisable(GL_BLEND); - - PROFILE_START("minimap units and flares"); - - CShaderDefines pointDefines; - pointDefines.Add(str_MINIMAP_POINT, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines); - tech->BeginPass(); - shader = tech->GetShader(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_pointSize, 3.f); - - CMatrix3D unitMatrix; - unitMatrix.SetIdentity(); - // Center the minimap on the origin of the axis of rotation. - unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f); - // Rotate the map. - unitMatrix.RotateZ(angle); - // Scale square maps to fit. - unitMatrix.Scale(unitScale, unitScale, 1.f); - // Move the minimap back to it's starting position. - unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f); - // Move the minimap to it's final location. - unitMatrix.Translate(x, y, 0.0f); - // Apply the gui matrix. - unitMatrix *= GetDefaultGuiMatrix(); - // Load the transform into the shader. - shader->Uniform(str_transform, unitMatrix); - - const float sx = (float)width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); - const float sy = (float)height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); - - CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); - - if (doUpdate) + CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture(); + if (miniMapTexture.GetTexture()) { - VertexArrayIterator attrPos = m_AttributePos.GetIterator(); - VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); - - m_EntitiesDrawn = 0; - MinimapUnitVertex v; - std::vector pingingVertices; - pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); - - if (cur_time > m_NextBlinkTime) - { - m_BlinkState = !m_BlinkState; - m_NextBlinkTime = cur_time + m_HalfBlinkDuration; - } + CShaderDefines baseDefines; + baseDefines.Add(str_MINIMAP_BASE, str_1); - entity_pos_t posX, posZ; - for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) - { - ICmpMinimap* cmpMinimap = static_cast(it->second); - if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) - { - LosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer()); - if (vis != LosVisibility::HIDDEN) - { - v.a = 255; - v.x = posX.ToFloat() * sx; - v.y = -posZ.ToFloat() * sy; - - // Check minimap pinging to indicate something - if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration)) - { - v.r = 255; // ping color is white - v.g = 255; - v.b = 255; - pingingVertices.push_back(v); - } - else - { - addVertex(v, attrColor, attrPos); - ++m_EntitiesDrawn; - } - } - } - } - - // Add the pinged vertices at the end, so they are drawn on top - for (const MinimapUnitVertex& vertex : pingingVertices) - { - addVertex(vertex, attrColor, attrPos); - ++m_EntitiesDrawn; - } - - ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); - m_VertexArray.Upload(); - } - - m_VertexArray.PrepareForRendering(); - - if (m_EntitiesDrawn > 0) - { -#if !CONFIG2_GLES - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - - u8* indexBase = m_IndexArray.Bind(); - u8* base = m_VertexArray.Bind(); - const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); - - shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); - shader->AssertPointersBound(); - - if (!g_Renderer.DoSkipSubmit()) - glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); - - g_Renderer.GetStats().m_DrawCalls++; - CVertexBuffer::Unbind(); - -#if !CONFIG2_GLES - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + tech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), miniMapTexture.GetTexture()); + + const CMatrix3D baseTransform = GetDefaultGuiMatrix(); + CMatrix3D baseTextureTransform; + baseTextureTransform.SetIdentity(); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), baseTextureTransform.AsFloatArray()); + + const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; + const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; + const float angle = GetAngle(); + DrawTexture(deviceCommandContext, angle, x, y, x2, y2, m_MapScale); + + deviceCommandContext->EndPass(); + } + + for (const CMiniMapTexture::Icon& icon : miniMapTexture.GetIcons()) + { + const CVector2D center = WorldSpaceToMiniMapSpace( + CVector3D(icon.worldPosition.X, 0.0f, icon.worldPosition.Y)); + const CRect destination( + center.X - icon.halfSize, center.Y - icon.halfSize, + center.X + icon.halfSize, center.Y + icon.halfSize); + const CRect source(0, 0, icon.texture->GetWidth(), icon.texture->GetHeight()); + canvas.DrawTexture( + icon.texture, destination, source, + icon.color, CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f); } - tech->EndPass(); + PROFILE_START("minimap flares"); - DrawViewRect(unitMatrix); + DrawViewRect(canvas); - while (!m_MapFlares.empty() && m_FlareLifetimeSeconds + m_MapFlares.front().time < cur_time) + const double currentTime = timer_Time(); + while (!m_MapFlares.empty() && m_FlareLifetimeSeconds + m_MapFlares.front().time < currentTime) m_MapFlares.pop_front(); for (const MapFlare& flare : m_MapFlares) - DrawFlare(canvas, flare, cur_time); + DrawFlare(canvas, flare, currentTime); - PROFILE_END("minimap units and flares"); + PROFILE_END("minimap flares"); } bool CMiniMap::Flare(const CVector2D& pos, const CStr& colorStr) diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CMiniMap.h 0ad-0.0.26/source/gui/ObjectTypes/CMiniMap.h --- 0ad-0.0.25b/source/gui/ObjectTypes/CMiniMap.h 2021-07-27 21:56:51.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CMiniMap.h 2022-08-21 12:45:35.000000000 +0000 @@ -27,9 +27,7 @@ #include #include -class CCamera; class CMatrix3D; -class CTerrain; class CMiniMap : public IGUIObject { @@ -82,6 +80,8 @@ CGUISimpleSetting m_FlareInterleave; CGUISimpleSetting m_FlareAnimationSpeed; CGUISimpleSetting m_FlareLifetimeSeconds; + CGUISimpleSetting m_FlareStartFadeSeconds; + CGUISimpleSetting m_FlareStopFadeSeconds; // Whether to draw a black square around and under the minimap. CGUISimpleSetting m_Mask; @@ -94,25 +94,15 @@ void RecreateFlareTextures(); - void DrawViewRect(const CMatrix3D& transform) const; + void DrawViewRect(CCanvas2D& canvas) const; - void DrawFlare(CCanvas2D& canvas, const MapFlare& flare, double curentTime) const; + void DrawFlare(CCanvas2D& canvas, const MapFlare& flare, double currentTime) const; + void DrawFlareFrame(CCanvas2D& canvas, const u32 frameIndex, const CRect& destination, const CColor& color, float alpha) const; void GetMouseWorldCoordinates(float& x, float& z) const; float GetAngle() const; - - VertexIndexArray m_IndexArray; - VertexArray m_VertexArray; - VertexArray::Attribute m_AttributePos; - VertexArray::Attribute m_AttributeColor; - - size_t m_EntitiesDrawn; - - double m_PingDuration; - double m_HalfBlinkDuration; - double m_NextBlinkTime; - bool m_BlinkState; + CVector2D WorldSpaceToMiniMapSpace(const CVector3D& worldPosition) const; }; #endif // INCLUDED_MINIMAP diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CSlider.cpp 0ad-0.0.26/source/gui/ObjectTypes/CSlider.cpp --- 0ad-0.0.25b/source/gui/ObjectTypes/CSlider.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CSlider.cpp 2022-08-21 12:45:35.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,7 +31,9 @@ m_MaxValue(this, "max_value"), m_MinValue(this, "min_value"), m_Sprite(this, "sprite"), + m_SpriteDisabled(this, "sprite_disabled"), m_SpriteBar(this, "sprite_bar"), + m_SpriteBarDisabled(this, "sprite_bar_disabled"), m_Value(this, "value") { m_Value.Set(Clamp(m_Value, m_MinValue, m_MaxValue), false); @@ -104,11 +106,11 @@ void CSlider::Draw(CCanvas2D& canvas) { - CRect slider_line(m_CachedActualSize); - slider_line.left += m_ButtonSide / 2.0f; - slider_line.right -= m_ButtonSide / 2.0f; - m_pGUI.DrawSprite(m_SpriteBar, canvas, slider_line); - m_pGUI.DrawSprite(m_Sprite, canvas, GetButtonRect()); + CRect sliderLine(m_CachedActualSize); + sliderLine.left += m_ButtonSide / 2.0f; + sliderLine.right -= m_ButtonSide / 2.0f; + m_pGUI.DrawSprite(IsEnabled() ? m_SpriteBar : m_SpriteBarDisabled, canvas, sliderLine); + m_pGUI.DrawSprite(IsEnabled() ? m_Sprite : m_SpriteDisabled, canvas, GetButtonRect()); } void CSlider::UpdateValue() @@ -118,7 +120,11 @@ CRect CSlider::GetButtonRect() const { - float ratio = m_MaxValue > m_MinValue ? (m_Value - m_MinValue) / (m_MaxValue - m_MinValue) : 0.0f; + // Even if the value is incorrect it doesn't make sense to draw it outside + // of the element bounds. Because that value might be set intentionally in the + // config for debug purposes. + const float value = Clamp(m_Value, m_MinValue, m_MaxValue); + float ratio = m_MaxValue > m_MinValue ? (value - m_MinValue) / (m_MaxValue - m_MinValue) : 0.0f; float x = m_CachedActualSize.left + ratio * (m_CachedActualSize.GetWidth() - m_ButtonSide); float y = m_CachedActualSize.top + (m_CachedActualSize.GetHeight() - m_ButtonSide) / 2.0; return CRect(x, y, x + m_ButtonSide, y + m_ButtonSide); diff -Nru 0ad-0.0.25b/source/gui/ObjectTypes/CSlider.h 0ad-0.0.26/source/gui/ObjectTypes/CSlider.h --- 0ad-0.0.25b/source/gui/ObjectTypes/CSlider.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/ObjectTypes/CSlider.h 2022-08-21 12:45:35.000000000 +0000 @@ -64,8 +64,8 @@ CGUISimpleSetting m_ButtonSide; CGUISimpleSetting m_MinValue; CGUISimpleSetting m_MaxValue; - CGUISimpleSetting m_Sprite; - CGUISimpleSetting m_SpriteBar; + CGUISimpleSetting m_Sprite, m_SpriteDisabled; + CGUISimpleSetting m_SpriteBar, m_SpriteBarDisabled; CGUISimpleSetting m_Value; private: diff -Nru 0ad-0.0.25b/source/gui/Scripting/JSInterface_GUIManager.cpp 0ad-0.0.26/source/gui/Scripting/JSInterface_GUIManager.cpp --- 0ad-0.0.25b/source/gui/Scripting/JSInterface_GUIManager.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/Scripting/JSInterface_GUIManager.cpp 2022-08-21 12:45:36.000000000 +0000 @@ -23,6 +23,7 @@ #include "gui/GUIManager.h" #include "gui/ObjectBases/IGUIObject.h" #include "ps/GameSetup/Config.h" +#include "ps/VideoMode.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h" @@ -52,16 +53,14 @@ g_GUI->PopPage(Script::WriteStructuredClone(rq, args)); } -std::wstring SetCursor(const std::wstring& name) +void SetCursor(const std::wstring& name) { - std::wstring old = g_CursorName; - g_CursorName = name; - return old; + g_VideoMode.SetCursor(name); } void ResetCursor() { - g_CursorName = g_DefaultCursor; + g_VideoMode.ResetCursor(); } bool TemplateExists(const std::string& templateName) diff -Nru 0ad-0.0.25b/source/gui/Scripting/ScriptFunctions.cpp 0ad-0.0.26/source/gui/Scripting/ScriptFunctions.cpp --- 0ad-0.0.25b/source/gui/Scripting/ScriptFunctions.cpp 2021-07-27 21:56:53.000000000 +0000 +++ 0ad-0.0.26/source/gui/Scripting/ScriptFunctions.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -71,6 +71,6 @@ JSI_Simulation::RegisterScriptFunctions(rq); JSI_Sound::RegisterScriptFunctions(rq); JSI_UserReport::RegisterScriptFunctions(rq); - JSI_VFS::RegisterScriptFunctions_GUI(rq); + JSI_VFS::RegisterScriptFunctions_ReadWriteAnywhere(rq); JSI_VisualReplay::RegisterScriptFunctions(rq); } diff -Nru 0ad-0.0.25b/source/gui/SettingTypes/CGUIColor.h 0ad-0.0.26/source/gui/SettingTypes/CGUIColor.h --- 0ad-0.0.25b/source/gui/SettingTypes/CGUIColor.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/SettingTypes/CGUIColor.h 2022-08-21 12:45:35.000000000 +0000 @@ -19,9 +19,9 @@ #define INCLUDED_GUICOLOR #include "graphics/Color.h" +#include "ps/CStrForward.h" class CGUI; -class CStr8; /** * Same as the CColor class, but this one can also parse colors predefined in the GUI page (such as "yellow"). diff -Nru 0ad-0.0.25b/source/gui/SettingTypes/CGUISize.h 0ad-0.0.26/source/gui/SettingTypes/CGUISize.h --- 0ad-0.0.25b/source/gui/SettingTypes/CGUISize.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/SettingTypes/CGUISize.h 2022-08-21 12:45:35.000000000 +0000 @@ -19,10 +19,9 @@ #define INCLUDED_CGUISIZE #include "maths/Rect.h" +#include "ps/CStrForward.h" #include "scriptinterface/ScriptForward.h" -class CStr8; - /** * This class represents a rectangle relative to a parent rectangle * The value can be initialized from a string or JS object. diff -Nru 0ad-0.0.25b/source/gui/SettingTypes/CGUIString.cpp 0ad-0.0.26/source/gui/SettingTypes/CGUIString.cpp --- 0ad-0.0.25b/source/gui/SettingTypes/CGUIString.cpp 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/SettingTypes/CGUIString.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -206,18 +206,19 @@ } } - // Calculate the size of the font + // Calculate the size of the font. CSize2D size; int cx, cy; CFontMetrics font (TextCall.m_Font); font.CalculateStringSize(TextCall.m_String.c_str(), cx, cy); - // For anything other than the first line, the line spacing - // needs to be considered rather than just the height of the text - if (!FirstLine) - cy = font.GetLineSpacing(); - size.Width = (float)cx; - size.Height = (float)cy; + size.Width = static_cast(cx); + // For anything other than the first line, the line spacing + // needs to be considered rather than just the height of the text. + if (FirstLine) + size.Height = static_cast(font.GetHeight()); + else + size.Height = static_cast(font.GetLineSpacing()); // Append width, and make maximum height the height. Feedback.m_Size.Width += size.Width; @@ -228,6 +229,17 @@ if (!TextCall.m_String.empty() && TextCall.m_String[0] == '\n') Feedback.m_NewLine = true; + // Multiple empty spaces are treated as individual words (one per space), + // and for coherence we'll do the 'ignore space after the word' thing + // only if the word actually has some other text in it, so process this only if size >= 2 + else if (TextCall.m_String.size() >= 2) + { + const wchar_t lastChar = TextCall.m_String.back(); + // If the last word ends with a 'space', we'll ignore it when aligning, so mark it. + Feedback.m_EndsWithSpace = lastChar == ' ' || lastChar == 0x3000; + } + else + Feedback.m_EndsWithSpace = false; // Add text-chunk Feedback.m_TextCalls.emplace_back(std::move(TextCall)); diff -Nru 0ad-0.0.25b/source/gui/SettingTypes/CGUIString.h 0ad-0.0.26/source/gui/SettingTypes/CGUIString.h --- 0ad-0.0.25b/source/gui/SettingTypes/CGUIString.h 2021-07-27 21:56:52.000000000 +0000 +++ 0ad-0.0.26/source/gui/SettingTypes/CGUIString.h 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -156,6 +156,11 @@ * If the word inputted was a new line. */ bool m_NewLine; + + /** + * If the word inputted ends with a space that can be collapsed when aligning. + */ + bool m_EndsWithSpace; }; /** diff -Nru 0ad-0.0.25b/source/gui/tests/test_CGUIText.h 0ad-0.0.26/source/gui/tests/test_CGUIText.h --- 0ad-0.0.25b/source/gui/tests/test_CGUIText.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/gui/tests/test_CGUIText.h 2022-09-23 19:16:46.000000000 +0000 @@ -0,0 +1,365 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "lib/self_test.h" + +#include "graphics/FontManager.h" +#include "graphics/FontMetrics.h" +#include "gui/CGUI.h" +#include "gui/CGUIText.h" +#include "gui/SettingTypes/CGUIString.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "ps/Filesystem.h" +#include "ps/ProfileViewer.h" +#include "ps/VideoMode.h" +#include "renderer/Renderer.h" +#include "scriptinterface/ScriptInterface.h" + +#include +#include + +class TestCGUIText : public CxxTest::TestSuite +{ + CProfileViewer* m_Viewer = nullptr; + CRenderer* m_Renderer = nullptr; + +public: + void setUp() + { + g_VFS = CreateVfs(); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir() / "mods" / "_test.minimal" / "", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); + + CXeromyces::Startup(); + + // The renderer spews messages. + TestLogger logger; + + // We need to initialise the renderer to initialise the font manager. + // TODO: decouple this. + CConfigDB::Initialise(); + CConfigDB::Instance()->SetValueString(CFG_SYSTEM, "rendererbackend", "dummy"); + g_VideoMode.InitNonSDL(); + g_VideoMode.CreateBackendDevice(false); + m_Viewer = new CProfileViewer; + m_Renderer = new CRenderer; + } + + void tearDown() + { + delete m_Renderer; + delete m_Viewer; + g_VideoMode.Shutdown(); + CConfigDB::Shutdown(); + CXeromyces::Terminate(); + g_VFS.reset(); + DeleteDirectory(DataDir() / "_testcache"); + } + + void test_empty() + { + CGUI gui(g_ScriptContext); + CGUIText empty; + } + + void test_wrapping() + { + CGUI gui(g_ScriptContext); + + const CStrW font = L"console"; + // Make sure this matches the value of the file. + // TODO: load dynamically. + const float lineHeight = 12.f; + const float lineSpacing = 15.f; + + CGUIString string; + CGUIText text; + float width = 0.f; + float renderedWidth = 0.f; + float padding = 0.f; + EAlign align = EAlign::LEFT; + + // Thing to note: the space before the newline should collapse in right-alignment. + string.SetValue(L"Some long text that will wrap-around. \n New line."); + text = CGUIText(gui, string, font, width, padding, align, nullptr); + + // Width 0 means no wrapping, so we should be getting one render call & one line. + // TODO: is it wanted that \n doesn't wrap in that case? + // We have 11 calls: the 9 words (wrap-around is split in two), the space after the newline, and the newline itself. + TS_ASSERT_EQUALS(text.GetTextCalls().size(), 11); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight); + + width = 100.f; + padding = 2.0f; + align = EAlign::LEFT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + renderedWidth = text.GetSize().Width; + // We have 10 calls: the 9 words (wrap-around is split in two), the space after the newline. + TS_ASSERT_EQUALS(text.GetTextCalls().size(), 10); + TS_ASSERT_LESS_THAN(text.GetSize().Width, width); + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing * 4); + + align = EAlign::RIGHT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + TS_ASSERT_EQUALS(text.GetTextCalls().size(), 10); + TS_ASSERT_EQUALS(text.GetSize().Width, renderedWidth); // Should be the same width as the left-case. + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing * 4); + + width = 400.f; + padding = 3.0f; + align = EAlign::LEFT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + TS_ASSERT_EQUALS(text.GetTextCalls().size(), 10); + TS_ASSERT_LESS_THAN(text.GetSize().Width, width); + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing); + + width = 400.f; + padding = 5.0f; + align = EAlign::CENTER; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + renderedWidth = text.GetSize().Width; + TS_ASSERT_LESS_THAN(text.GetSize().Width, width); + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing); + + align = EAlign::RIGHT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + TS_ASSERT_EQUALS(text.GetSize().Width, renderedWidth); // Should be the same width as the center-case. + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing); + + align = EAlign::LEFT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + TS_ASSERT_EQUALS(text.GetSize().Width, renderedWidth); // Should be the same width as the center-case. + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing); + + width = 400.f; + padding = 100.0f; + align = EAlign::LEFT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + renderedWidth = text.GetSize().Width; + TS_ASSERT_LESS_THAN(text.GetSize().Width, width); + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing * 2); + + align = EAlign::RIGHT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + TS_ASSERT_EQUALS(text.GetSize().Width, renderedWidth); // Should be the same width as the left-case. + TS_ASSERT_EQUALS(text.GetSize().Height, padding * 2 + lineHeight + lineSpacing * 2); + } + + void test_layout_wrapping_center() + { + // The short word should be layouted the same as when there is no + // second word, because it's the only one word in the first line until + // the width is enough to fit both. So we need to check that for + // increasing width X positions of both words are also increasing until + // they fit into a single line. + // + // Width is too small for both: + // +--------------------+ + // | Shortword | + // | (Veryverylongword) | + // +--------------------+ + // + // Right before the big enough width: + // +---------------------------+ + // | Shortword | + // | (Veryverylongword) | + // +---------------------------+ + // + // Width is enough to fit both: + // +------------------------------+ + // | Shortword (Veryverylongword) | + // +------------------------------+ + // + + CGUI gui(g_ScriptContext); + const CStrW firstWord = L"Shortword"; + const CStrW secondWord = L"(Veryverylongword)"; + const CStrW text = firstWord + L" " + secondWord; + CGUIString string; + string.SetValue(text); + const CStrW font = L"console"; + CFontMetrics fontMetrics{CStrIntern(font.ToUTF8())}; + + int firstWordWidth = 0, firstWordHeight = 0; + fontMetrics.CalculateStringSize(firstWord.c_str(), firstWordWidth, firstWordHeight); + TS_ASSERT(firstWordWidth > 0); + int secondWordWidth = 0, secondWordHeight = 0; + fontMetrics.CalculateStringSize(secondWord.c_str(), secondWordWidth, secondWordHeight); + TS_ASSERT(secondWordWidth > 0); + TS_ASSERT(firstWordWidth < secondWordWidth); + const float spaceWidth = fontMetrics.GetCharacterWidth(L' '); + + const float lineHeight = fontMetrics.GetHeight(); + const float lineSpacing = fontMetrics.GetLineSpacing(); + + auto layoutText = [&gui, &string, &font, lineHeight, firstWordWidth](const float width) + { + const float padding = 0.0f; + const CGUIText text(gui, string, font, width, padding, EAlign::CENTER, nullptr); + + std::array positions; + TS_ASSERT_EQUALS(text.GetTextCalls().size(), positions.size()); + + // If the second word is on the next line then the first word should be + // centered alone. + if (text.GetTextCalls()[0].m_Pos.Y + lineHeight <= text.GetTextCalls()[1].m_Pos.Y) + { + const float expectedX = (width - firstWordWidth) / 2.0f; + TS_ASSERT_EQUALS(text.GetTextCalls()[0].m_Pos.X, expectedX); + } + + std::transform( + text.GetTextCalls().begin(), text.GetTextCalls().end(), positions.begin(), + [](const CGUIText::STextCall& textCall) { return textCall.m_Pos; }); + return positions; + }; + + const float testPadding = 2; + const float beginWidth = firstWordWidth - testPadding; + const float endWidth = firstWordWidth + spaceWidth + secondWordWidth + testPadding; + std::array previousPositions = layoutText(beginWidth); + TS_ASSERT_EQUALS(std::get<0>(previousPositions).Y, lineHeight); + TS_ASSERT_EQUALS(std::get<1>(previousPositions).Y, lineHeight + lineSpacing); + bool firstFit = false; + for (float width = beginWidth; width <= endWidth; width += 1.0f) + { + std::array positions = layoutText(width); + TS_ASSERT_EQUALS(std::get<0>(positions).Y, lineHeight); + if (std::get<0>(positions).X >= std::get<0>(previousPositions).X) + { + if (firstFit) + { + TS_ASSERT_EQUALS(std::get<0>(positions).Y, std::get<1>(positions).Y); + } + else + { + TS_ASSERT_EQUALS(std::get<1>(positions).Y, lineHeight + lineSpacing); + } + TS_ASSERT(std::get<1>(positions).X >= std::get<1>(previousPositions).X); + } + else + { + TS_ASSERT(!firstFit); + firstFit = true; + TS_ASSERT_EQUALS(std::get<0>(positions).Y, std::get<1>(positions).Y); + TS_ASSERT(std::get<0>(positions).X < std::get<1>(positions).X); + } + previousPositions = positions; + } + TS_ASSERT(firstFit); + } + + void test_overflow() + { + CGUI gui(g_ScriptContext); + + const CStrW font = L"console"; + // Make sure this matches the value of the file. + // TODO: load dynamically. + const float lineHeight = 12.f; + const float lineSpacing = 15.f; + + float renderedWidth = 0.f; + const float width = 200.f; + const float padding = 20.f; + + CGUIString string; + CGUIText text; + string.SetValue(L"wordthatisverylonganddefinitelywontfitinaline and other words"); + text = CGUIText(gui, string, font, width, padding, EAlign::LEFT, nullptr); + renderedWidth = text.GetSize().Width; + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 1 + padding * 2); + text = CGUIText(gui, string, font, width, padding, EAlign::CENTER, nullptr); + TS_ASSERT_EQUALS(renderedWidth, text.GetSize().Width); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 1 + padding * 2); + text = CGUIText(gui, string, font, width, padding, EAlign::RIGHT, nullptr); + TS_ASSERT_EQUALS(renderedWidth, text.GetSize().Width); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 1 + padding * 2); + + string.SetValue(L"other words and wordthatisverylonganddefinitelywontfitinaline"); + text = CGUIText(gui, string, font, width, padding, EAlign::LEFT, nullptr); + renderedWidth = text.GetSize().Width; + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 1 + padding * 2); + text = CGUIText(gui, string, font, width, padding, EAlign::CENTER, nullptr); + TS_ASSERT_EQUALS(renderedWidth, text.GetSize().Width); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 1 + padding * 2); + text = CGUIText(gui, string, font, width, padding, EAlign::RIGHT, nullptr); + TS_ASSERT_EQUALS(renderedWidth, text.GetSize().Width); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 1 + padding * 2); + + string.SetValue(L"wordthatisverylonganddefinitelywontfitinaline"); + text = CGUIText(gui, string, font, width, padding, EAlign::LEFT, nullptr); + renderedWidth = text.GetSize().Width; + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + padding * 2); + text = CGUIText(gui, string, font, width, padding, EAlign::CENTER, nullptr); + TS_ASSERT_EQUALS(renderedWidth, text.GetSize().Width); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + padding * 2); + text = CGUIText(gui, string, font, width, padding, EAlign::RIGHT, nullptr); + TS_ASSERT_EQUALS(renderedWidth, text.GetSize().Width); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + padding * 2); + } + + void test_regression_rP26522() + { + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir() / "mods" / "mod" / "", VFS_MOUNT_MUST_EXIST)); + + CGUI gui(g_ScriptContext); + + const CStrW font = L"sans-bold-13"; + CGUIString string; + CGUIText text; + + // rP26522 introduced a bug that triggered in rare cases with word-wrapping. + string.SetValue(L"90–120 min"); + text = CGUIText(gui, string, L"sans-bold-13", 53, 8.f, EAlign::LEFT, nullptr); + + TS_ASSERT_EQUALS(text.GetTextCalls().size(), 2); + TS_ASSERT_EQUALS(text.GetSize().Height, 14 + 9 + 8 * 2); + } + + void test_multiple_blank_spaces() + { + CGUI gui(g_ScriptContext); + + const CStrW font = L"console"; + // Make sure this matches the value of the file. + // TODO: load dynamically. + const float lineHeight = 12.f; + const float lineSpacing = 15.f; + + CGUIString string; + CGUIText text; + float width = 100.f; + float renderedWidth = 0.f; + float padding = 0.f; + EAlign align = EAlign::LEFT; + + string.SetValue(L" word another \n spaces \n \n word "); + text = CGUIText(gui, string, font, width, padding, align, nullptr); + + // Blank spaces are treated as a word. + TS_ASSERT_EQUALS(text.GetTextCalls().size(), 26); + TS_ASSERT_EQUALS(text.GetSize().Height, lineHeight + lineSpacing * 4); + TS_ASSERT_EQUALS(text.GetSize().Width, 89.f); + renderedWidth = text.GetSize().Width; + + align = EAlign::RIGHT; + text = CGUIText(gui, string, font, width, padding, align, nullptr); + TS_ASSERT_EQUALS(text.GetSize().Width, renderedWidth); + } +}; diff -Nru 0ad-0.0.25b/source/lib/allocators/dynarray.h 0ad-0.0.26/source/lib/allocators/dynarray.h --- 0ad-0.0.25b/source/lib/allocators/dynarray.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/allocators/dynarray.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -58,7 +58,7 @@ * (* rounded up to next page size multiple) * @return Status. **/ -LIB_API Status da_alloc(DynArray* da, size_t max_size); +Status da_alloc(DynArray* da, size_t max_size); /** * free all memory (address space + physical) that constitutes the @@ -69,7 +69,7 @@ * @param da DynArray* zeroed afterwards. * @return Status **/ -LIB_API Status da_free(DynArray* da); +Status da_free(DynArray* da); /** * expand or shrink the array: changes the amount of currently committed @@ -80,7 +80,7 @@ * pages are added/removed until this is met. * @return Status. **/ -LIB_API Status da_set_size(DynArray* da, size_t new_size); +Status da_set_size(DynArray* da, size_t new_size); /** * Make sure at least \ bytes starting at da->pos are committed and @@ -90,7 +90,7 @@ * @param size Minimum amount to guarantee [bytes] * @return Status **/ -LIB_API Status da_reserve(DynArray* da, size_t size); +Status da_reserve(DynArray* da, size_t size); /** * "write" to array, i.e. copy from the given buffer. @@ -102,6 +102,6 @@ * @param size [bytes] to copy * @return Status. **/ -LIB_API Status da_append(DynArray* da, const void* data_src, size_t size); +Status da_append(DynArray* da, const void* data_src, size_t size); #endif // #ifndef INCLUDED_ALLOCATORS_DYNARRAY diff -Nru 0ad-0.0.25b/source/lib/allocators/freelist.h 0ad-0.0.26/source/lib/allocators/freelist.h --- 0ad-0.0.25b/source/lib/allocators/freelist.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/allocators/freelist.h 2022-08-21 12:45:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 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 @@ // @return the address of a sentinel element, suitable for initializing // a freelist pointer. subsequent mem_freelist_Detach on that freelist // will return 0. -LIB_API void* mem_freelist_Sentinel(); +void* mem_freelist_Sentinel(); static inline void mem_freelist_AddToFront(void*& freelist, void* el) { diff -Nru 0ad-0.0.25b/source/lib/allocators/page_aligned.h 0ad-0.0.26/source/lib/allocators/page_aligned.h --- 0ad-0.0.25b/source/lib/allocators/page_aligned.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/allocators/page_aligned.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,11 +27,11 @@ // very thin wrapper on top of sys/mman.h that makes the intent more obvious // (its commit/decommit semantics are difficult to tell apart) -LIB_API Status mem_Reserve(size_t size, u8** pp); -LIB_API Status mem_Release(u8* p, size_t size); -LIB_API Status mem_Commit(u8* p, size_t size, int prot); -LIB_API Status mem_Decommit(u8* p, size_t size); -LIB_API Status mem_Protect(u8* p, size_t size, int prot); +Status mem_Reserve(size_t size, u8** pp); +Status mem_Release(u8* p, size_t size); +Status mem_Commit(u8* p, size_t size, int prot); +Status mem_Decommit(u8* p, size_t size); +Status mem_Protect(u8* p, size_t size, int prot); /** @@ -49,7 +49,7 @@ * @param unaligned_size minimum size [bytes] to allocate. * @return page-aligned and -padded memory or 0 on error / out of memory. **/ -LIB_API void* page_aligned_alloc(size_t unaligned_size); +void* page_aligned_alloc(size_t unaligned_size); /** * free a previously allocated page-aligned region. @@ -57,6 +57,6 @@ * @param p Exact value returned from page_aligned_alloc * @param unaligned_size Exact value passed to page_aligned_alloc **/ -LIB_API void page_aligned_free(void* p, size_t unaligned_size); +void page_aligned_free(void* p, size_t unaligned_size); #endif // #ifndef INCLUDED_ALLOCATORS_PAGE_ALIGNED diff -Nru 0ad-0.0.25b/source/lib/allocators/pool.h 0ad-0.0.26/source/lib/allocators/pool.h --- 0ad-0.0.25b/source/lib/allocators/pool.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/allocators/pool.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -95,7 +95,7 @@ void* freelist; }; -LIB_API void TestPool(); +void TestPool(); } // namespace Allocators @@ -146,7 +146,7 @@ * allow variable-sized allocations, but pool_free is then unusable. * @return Status **/ -LIB_API Status pool_create(Pool* p, size_t max_size, size_t el_size); +Status pool_create(Pool* p, size_t max_size, size_t el_size); /** * free all memory (address space + physical) that constitutes the @@ -160,7 +160,7 @@ * @param p Pool* * @return Status. **/ -LIB_API Status pool_destroy(Pool* p); +Status pool_destroy(Pool* p); /** * indicate whether a pointer was allocated from the given pool. @@ -171,7 +171,7 @@ * @param el * @return bool. **/ -LIB_API bool pool_contains(const Pool* p, void* el); +bool pool_contains(const Pool* p, void* el); /** * Dole out memory from the pool. @@ -182,7 +182,7 @@ * @return allocated memory, or 0 if the Pool would have to be expanded and * there isn't enough memory to do so. **/ -LIB_API void* pool_alloc(Pool* p, size_t size); +void* pool_alloc(Pool* p, size_t size); /** * Make a fixed-size element available for reuse in the given Pool. @@ -194,7 +194,7 @@ * @param p Pool* * @param el Element returned by pool_alloc. **/ -LIB_API void pool_free(Pool* p, void* el); +void pool_free(Pool* p, void* el); /** * "free" all user allocations that ensued from the given Pool. @@ -204,7 +204,7 @@ * * @param p Pool* **/ -LIB_API void pool_free_all(Pool* p); +void pool_free_all(Pool* p); /** * Return the number of bytes committed in the pool's backing array. @@ -215,6 +215,6 @@ * @param p Pool* * @return number of bytes **/ -LIB_API size_t pool_committed(Pool* p); +size_t pool_committed(Pool* p); #endif // #ifndef INCLUDED_ALLOCATORS_POOL diff -Nru 0ad-0.0.25b/source/lib/allocators/shared_ptr.h 0ad-0.0.26/source/lib/allocators/shared_ptr.h --- 0ad-0.0.25b/source/lib/allocators/shared_ptr.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/allocators/shared_ptr.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -50,7 +50,7 @@ }; // (note: uses CheckedArrayDeleter) -LIB_API std::shared_ptr Allocate(size_t size); +std::shared_ptr Allocate(size_t size); struct AlignedDeleter diff -Nru 0ad-0.0.25b/source/lib/app_hooks.cpp 0ad-0.0.26/source/lib/app_hooks.cpp --- 0ad-0.0.25b/source/lib/app_hooks.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/app_hooks.cpp 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -20,11 +20,8 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* - * hooks to allow customization / app-specific behavior. - */ - #include "precompiled.h" + #include "lib/app_hooks.h" #include "lib/sysdep/sysdep.h" @@ -35,11 +32,6 @@ // default implementations //----------------------------------------------------------------------------- -static void def_override_gl_upload_caps() -{ -} - - static const OsPath& def_get_log_dir() { static OsPath logDir; @@ -54,31 +46,6 @@ } -static const wchar_t* def_translate(const wchar_t* text) -{ - return text; -} - - -static void def_translate_free(const wchar_t* UNUSED(text)) -{ - // no-op - translate() doesn't own the pointer. -} - - -static void def_log(const wchar_t* text) -{ -#if ICC_VERSION -#pragma warning(push) -#pragma warning(disable:181) // "invalid printf conversion" - but wchar_t* and %ls are legit -#endif - printf("%ls", text); // must not use wprintf, since stdout on Unix is byte-oriented -#if ICC_VERSION -#pragma warning(pop) -#endif -} - - static ErrorReactionInternal def_display_error(const wchar_t* UNUSED(text), size_t UNUSED(flags)) { return ERI_NOT_IMPLEMENTED; @@ -95,12 +62,8 @@ // having to check whether their function pointer is valid. static AppHooks ah = { - def_override_gl_upload_caps, def_get_log_dir, def_bundle_logs, - def_translate, - def_translate_free, - def_log, def_display_error }; @@ -117,12 +80,8 @@ ENSURE(new_ah); #define OVERRIDE_IF_NONZERO(HOOKNAME) if(new_ah->HOOKNAME) ah.HOOKNAME = new_ah->HOOKNAME; - OVERRIDE_IF_NONZERO(override_gl_upload_caps) OVERRIDE_IF_NONZERO(get_log_dir) OVERRIDE_IF_NONZERO(bundle_logs) - OVERRIDE_IF_NONZERO(translate) - OVERRIDE_IF_NONZERO(translate_free) - OVERRIDE_IF_NONZERO(log) OVERRIDE_IF_NONZERO(display_error) #undef OVERRIDE_IF_NONZERO } @@ -143,12 +102,6 @@ // (boilerplate code; hides details of how to call the app hook) //----------------------------------------------------------------------------- -void ah_override_gl_upload_caps() -{ - if(ah.override_gl_upload_caps) - ah.override_gl_upload_caps(); -} - const OsPath& ah_get_log_dir() { return ah.get_log_dir(); @@ -159,21 +112,6 @@ ah.bundle_logs(f); } -const wchar_t* ah_translate(const wchar_t* text) -{ - return ah.translate(text); -} - -void ah_translate_free(const wchar_t* text) -{ - ah.translate_free(text); -} - -void ah_log(const wchar_t* text) -{ - ah.log(text); -} - ErrorReactionInternal ah_display_error(const wchar_t* text, size_t flags) { return ah.display_error(text, flags); diff -Nru 0ad-0.0.25b/source/lib/app_hooks.h 0ad-0.0.26/source/lib/app_hooks.h --- 0ad-0.0.25b/source/lib/app_hooks.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/app_hooks.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -97,19 +97,6 @@ // the details of how exactly to do this. /** - * override default decision on using OpenGL extensions relating to - * texture upload. - * - * this should call ogl_tex_override to disable/force their use if the - * current card/driver combo respectively crashes or - * supports it even though the extension isn't advertised. - * - * the default implementation works but is hardwired in code and therefore - * not expandable. - **/ -extern void ah_override_gl_upload_caps(); - -/** * return path to directory into which crash dumps should be written. * * must be callable at any time - in particular, before VFS init. @@ -132,34 +119,6 @@ extern void ah_bundle_logs(FILE* f); /** - * translate text to the current locale. - * - * @param text to translate. - * @return pointer to localized text; must be freed via translate_free. - * - * the default implementation just returns the pointer unchanged. - **/ -extern const wchar_t* ah_translate(const wchar_t* text); - -/** - * free text that was returned by translate. - * - * @param text to free. - * - * the default implementation does nothing. - **/ -extern void ah_translate_free(const wchar_t* text); - -/** - * write text to the app's log. - * - * @param text to write. - * - * the default implementation uses stdout. - **/ -extern void ah_log(const wchar_t* text); - -/** * display an error dialog, thus overriding sys_display_error. * * @param text error message. @@ -178,12 +137,8 @@ **/ struct AppHooks { - void (*override_gl_upload_caps)(); const OsPath& (*get_log_dir)(); void (*bundle_logs)(FILE* f); - const wchar_t* (*translate)(const wchar_t* text); - void (*translate_free)(const wchar_t* text); - void (*log)(const wchar_t* text); ErrorReactionInternal (*display_error)(const wchar_t* text, size_t flags); }; @@ -194,7 +149,7 @@ * override the previous function pointer value * (these default to the stub hooks which are functional but basic). **/ -LIB_API void app_hooks_update(AppHooks* ah); +void app_hooks_update(AppHooks* ah); /** * was the app hook changed via app_hooks_update from its default value? @@ -206,4 +161,4 @@ // name is identifier of the function pointer within AppHooks to test. #define AH_IS_DEFINED(name) app_hook_was_redefined(offsetof(AppHooks, name)) -#endif // #ifndef INCLUDED_APP_HOOKS +#endif // INCLUDED_APP_HOOKS diff -Nru 0ad-0.0.25b/source/lib/byte_order.h 0ad-0.0.26/source/lib/byte_order.h --- 0ad-0.0.25b/source/lib/byte_order.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/byte_order.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -93,38 +93,38 @@ #endif /// read a little-endian number from memory into native byte order. -LIB_API u16 read_le16(const void* p); -LIB_API u32 read_le32(const void* p); /// see read_le16 -LIB_API u64 read_le64(const void* p); /// see read_le16 +u16 read_le16(const void* p); +u32 read_le32(const void* p); /// see read_le16 +u64 read_le64(const void* p); /// see read_le16 /// read a big-endian number from memory into native byte order. -LIB_API u16 read_be16(const void* p); -LIB_API u32 read_be32(const void* p); /// see read_be16 -LIB_API u64 read_be64(const void* p); /// see read_be16 +u16 read_be16(const void* p); +u32 read_be32(const void* p); /// see read_be16 +u64 read_be64(const void* p); /// see read_be16 /// write a little-endian number to memory in native byte order. -LIB_API void write_le16(void* p, u16 x); -LIB_API void write_le32(void* p, u32 x); /// see write_le16 -LIB_API void write_le64(void* p, u64 x); /// see write_le16 +void write_le16(void* p, u16 x); +void write_le32(void* p, u32 x); /// see write_le16 +void write_le64(void* p, u64 x); /// see write_le16 /// write a big-endian number to memory in native byte order. -LIB_API void write_be16(void* p, u16 x); -LIB_API void write_be32(void* p, u32 x); /// see write_be16 -LIB_API void write_be64(void* p, u64 x); /// see write_be16 +void write_be16(void* p, u16 x); +void write_be32(void* p, u32 x); /// see write_be16 +void write_be64(void* p, u64 x); /// see write_be16 /** * zero-extend \ (truncated to 8) bytes of little-endian data to u64, * starting at address \ (need not be aligned). **/ -LIB_API u64 movzx_le64(const u8* p, size_t size); -LIB_API u64 movzx_be64(const u8* p, size_t size); +u64 movzx_le64(const u8* p, size_t size); +u64 movzx_be64(const u8* p, size_t size); /** * sign-extend \ (truncated to 8) bytes of little-endian data to i64, * starting at address \ (need not be aligned). **/ -LIB_API i64 movsx_le64(const u8* p, size_t size); -LIB_API i64 movsx_be64(const u8* p, size_t size); +i64 movsx_le64(const u8* p, size_t size); +i64 movsx_be64(const u8* p, size_t size); #if ICC_VERSION @@ -154,13 +154,13 @@ #endif #ifndef swap16 -LIB_API u16 swap16(const u16 x); +u16 swap16(const u16 x); #endif #ifndef swap32 -LIB_API u32 swap32(const u32 x); +u32 swap32(const u32 x); #endif #ifndef swap64 -LIB_API u64 swap64(const u64 x); +u64 swap64(const u64 x); #endif #endif // #ifndef INCLUDED_BYTE_ORDER diff -Nru 0ad-0.0.25b/source/lib/config2.h 0ad-0.0.26/source/lib/config2.h --- 0ad-0.0.25b/source/lib/config2.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/config2.h 2022-08-21 12:45:18.000000000 +0000 @@ -86,4 +86,9 @@ # define CONFIG2_MINIUPNPC 1 #endif +// default disable valgrind +#ifndef CONFIG2_VALGRIND +# define CONFIG2_VALGRIND 0 +#endif + #endif // #ifndef INCLUDED_CONFIG2 diff -Nru 0ad-0.0.25b/source/lib/debug.cpp 0ad-0.0.26/source/lib/debug.cpp --- 0ad-0.0.25b/source/lib/debug.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/debug.cpp 2022-08-21 12:45:18.000000000 +0000 @@ -339,7 +339,7 @@ // implemented via sys_display_msg; see documentation there. void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg) { - sys_display_msg(ah_translate(caption), ah_translate(msg)); + sys_display_msg(caption, msg); } @@ -429,8 +429,6 @@ return ER_CONTINUE; // fix up params - // .. translate - description = ah_translate(description); // .. caller supports a suppress flag; set the corresponding flag so that // the error display implementation enables the Suppress option. if(suppress) diff -Nru 0ad-0.0.25b/source/lib/debug.h 0ad-0.0.26/source/lib/debug.h --- 0ad-0.0.25b/source/lib/debug.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/debug.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 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,6 @@ #include "lib/alignment.h" #include "lib/code_annotation.h" #include "lib/code_generation.h" -#include "lib/lib_api.h" #include "lib/status.h" #include "lib/types.h" @@ -66,7 +65,7 @@ * * @param fmt Format string and varargs; see printf. **/ -LIB_API void debug_printf(const char* fmt, ...) PRINTF_ARGS(1); +void debug_printf(const char* fmt, ...) PRINTF_ARGS(1); /** @@ -75,7 +74,7 @@ * is unavailable because that function is much more capable. * implemented via sys_display_msg; see documentation there. **/ -LIB_API void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg); +void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg); /// flags to customize debug_DisplayError behavior enum DebugDisplayErrorFlags @@ -191,7 +190,7 @@ * provides the storage. values: see DEBUG_SUPPRESS above. * @return ErrorReaction (user's choice: continue running or stop?) **/ -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); +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_IMPL(description, flags)\ @@ -236,31 +235,31 @@ * in future, allow output with the given tag to proceed. * no effect if already added. **/ -LIB_API void debug_filter_add(const char* tag); +void debug_filter_add(const char* tag); /** * in future, discard output with the given tag. * no effect if not currently added. **/ -LIB_API void debug_filter_remove(const char* tag); +void debug_filter_remove(const char* tag); /** * clear all filter state; equivalent to debug_filter_remove for * each tag that was debug_filter_add-ed. **/ -LIB_API void debug_filter_clear(); +void debug_filter_clear(); /** * indicate if the given text would be printed. * useful for a series of debug_printfs - avoids needing to add a tag to * each of their format strings. **/ -LIB_API bool debug_filter_allows(const char* text); +bool debug_filter_allows(const char* text); /** * call debug_puts if debug_filter_allows allows the string. **/ -LIB_API void debug_puts_filtered(const char* text); +void debug_puts_filtered(const char* text); /** * write an error description and all logs into crashlog.txt @@ -272,7 +271,7 @@ * @return Status; ERR::REENTERED if reentered via recursion or * multithreading (not allowed since an infinite loop may result). **/ -LIB_API Status debug_WriteCrashlog(const char* text); +Status debug_WriteCrashlog(const char* text); //----------------------------------------------------------------------------- @@ -364,7 +363,7 @@ * @param func name of the function containing it * @return ErrorReaction (user's choice: continue running or stop?) **/ -LIB_API ErrorReaction debug_OnAssertionFailure(const wchar_t* assert_expr, atomic_bool* suppress, const wchar_t* file, int line, const char* func) ANALYZER_NORETURN; +ErrorReaction debug_OnAssertionFailure(const wchar_t* assert_expr, atomic_bool* suppress, const wchar_t* file, int line, const char* func) ANALYZER_NORETURN; /** * called when a DEBUG_WARN_ERR indicates an error occurred; @@ -376,7 +375,7 @@ * @param func name of the function containing it * @return ErrorReaction (user's choice: continue running or stop?) **/ -LIB_API ErrorReaction debug_OnError(Status err, atomic_bool* suppress, const wchar_t* file, int line, const char* func) ANALYZER_NORETURN; +ErrorReaction debug_OnError(Status err, atomic_bool* suppress, const wchar_t* file, int line, const char* func) ANALYZER_NORETURN; /** @@ -393,12 +392,12 @@ * note: only one concurrent skip request is allowed; call * debug_StopSkippingErrors before the next debug_SkipErrors. */ -LIB_API void debug_SkipErrors(Status err); +void debug_SkipErrors(Status err); /** * @return how many errors were skipped since the call to debug_SkipErrors() **/ -LIB_API size_t debug_StopSkippingErrors(); +size_t debug_StopSkippingErrors(); //----------------------------------------------------------------------------- @@ -455,7 +454,7 @@ * @return Status; INFO::OK iff any information was successfully * retrieved and stored. **/ -LIB_API Status debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line); +Status debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line); static const size_t DEBUG_CONTEXT_SIZE = 2048; // Win32 CONTEXT is currently 1232 bytes @@ -463,7 +462,7 @@ * @param context must point to an instance of the platform-specific type * (e.g. CONTEXT) or CACHE_ALIGNED storage of DEBUG_CONTEXT_SIZE bytes. **/ -LIB_API Status debug_CaptureContext(void* context); +Status debug_CaptureContext(void* context); /** @@ -486,7 +485,7 @@ * @return Status; ERR::REENTERED if reentered via recursion or * multithreading (not allowed since static data is used). **/ -LIB_API Status debug_DumpStack(wchar_t* buf, size_t maxChars, void* context, const wchar_t* lastFuncToSkip); +Status debug_DumpStack(wchar_t* buf, size_t maxChars, void* context, const wchar_t* lastFuncToSkip); //----------------------------------------------------------------------------- @@ -498,7 +497,7 @@ * this can be quite slow (~1 ms)! On Windows, it uses OutputDebugString * (entails context switch), otherwise stdout+fflush (waits for IO). **/ -LIB_API void debug_puts(const char* text); +void debug_puts(const char* text); /** * return the caller of a certain function on the call stack. @@ -509,7 +508,7 @@ * @param context, lastFuncToSkip - see debug_DumpStack * @return address of the caller **/ -LIB_API void* debug_GetCaller(void* context, const wchar_t* lastFuncToSkip); +void* debug_GetCaller(void* context, const wchar_t* lastFuncToSkip); /** * check if a pointer appears to be totally invalid. @@ -520,13 +519,13 @@ * @param p pointer * @return 1 if totally bogus, otherwise 0. **/ -LIB_API int debug_IsPointerBogus(const void* p); +int debug_IsPointerBogus(const void* p); /// does the given pointer appear to point to code? -LIB_API bool debug_IsCodePointer(void* p); +bool debug_IsCodePointer(void* p); /// does the given pointer appear to point to the stack? -LIB_API bool debug_IsStackPointer(void* p); +bool debug_IsStackPointer(void* p); /** @@ -535,7 +534,7 @@ * (threads are easier to keep apart when they are identified by * name rather than TID.) **/ -LIB_API void debug_SetThreadName(const char* name); +void debug_SetThreadName(const char* name); /** * build a string describing the given error. @@ -548,6 +547,6 @@ * @param line, func: exact position of the error. * @param context, lastFuncToSkip: see debug_DumpStack. **/ -LIB_API const wchar_t* debug_BuildErrorMessage(const wchar_t* description, const wchar_t* fn_only, int line, const char* func, void* context, const wchar_t* lastFuncToSkip); +const wchar_t* debug_BuildErrorMessage(const wchar_t* description, const wchar_t* fn_only, int line, const char* func, void* context, const wchar_t* lastFuncToSkip); #endif // #ifndef INCLUDED_DEBUG diff -Nru 0ad-0.0.25b/source/lib/external_libraries/glext_funcs.h 0ad-0.0.26/source/lib/external_libraries/glext_funcs.h --- 0ad-0.0.25b/source/lib/external_libraries/glext_funcs.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/external_libraries/glext_funcs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,436 +0,0 @@ -/* Copyright (C) 2021 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. - */ - -/* - * OpenGL extension function declarations (X macros). - */ - -#include "lib/config2.h" // CONFIG2_GLES - -#if CONFIG2_GLES -# include -#elif OS_MACOSX -# include -#else -# include -#endif - -#if OS_WIN -# include -#endif - -/* - -FUNC is used for functions that are only extensions. -FUNC2 is used for functions that have been promoted to core features. -FUNC3 is used for functions that have been promoted to core features -but have slightly changed semantics and need to be referred to by their -core name instead of extension name. - -The FUNC2/FUNC3 calls include the version of OpenGL in which the extension was promoted, -and the pre- and post-promotion names (e.g. "glBindBufferARB" vs "glBindBuffer"). - -If the GL driver is advertising a sufficiently high version, we load the promoted -name; otherwise we use the *ARB name. (The spec says: - "GL implementations of such later revisions should continue to export the name - strings of promoted extensions in the EXTENSIONS string, and continue to support - the ARB-affixed versions of functions and enumerants as a transition aid." -but some drivers might be stupid/buggy and fail to do that, so we don't just use -the ARB names unconditionally.) - -The names are made accessible to engine code only via the ARB name, to make it -obvious that care must be taken (i.e. by being certain that the extension is -actually supported). - -*/ - -#if CONFIG2_GLES - -// some functions that are extensions in GL are core functions in GLES, -// so we should use them without the function pointer indirection -#define pglActiveTextureARB glActiveTexture -#define pglBlendColorEXT glBlendColor -#define pglBlendEquationEXT glBlendEquation -#define pglClientActiveTextureARB glClientActiveTexture -#define pglCompressedTexImage2DARB glCompressedTexImage2D - -#define pglAttachObjectARB glAttachShader -#define pglBindAttribLocationARB glBindAttribLocation -#define pglCompileShaderARB glCompileShader -#define pglCreateProgramObjectARB glCreateProgram -#define pglCreateShaderObjectARB glCreateShader -#define pglDeleteProgram glDeleteProgram -#define pglDeleteShader glDeleteShader -#define pglDisableVertexAttribArrayARB glDisableVertexAttribArray -#define pglEnableVertexAttribArrayARB glEnableVertexAttribArray -#define pglGetActiveUniformARB glGetActiveUniform -#define pglGetProgramiv glGetProgramiv -#define pglGetProgramInfoLog glGetProgramInfoLog -#define pglGetShaderiv glGetShaderiv -#define pglGetShaderInfoLog glGetShaderInfoLog -#define pglGetUniformLocationARB glGetUniformLocation -#define pglLinkProgramARB glLinkProgram -#define pglShaderSourceARB glShaderSource -#define pglUniform1fARB glUniform1f -#define pglUniform2fARB glUniform2f -#define pglUniform3fARB glUniform3f -#define pglUniform4fARB glUniform4f -#define pglUniform1iARB glUniform1i -#define pglUniformMatrix4fvARB glUniformMatrix4fv -#define pglUseProgramObjectARB glUseProgram -#define pglVertexAttribPointerARB glVertexAttribPointer - -#define pglBindBufferARB glBindBuffer -#define pglBufferDataARB glBufferData -#define pglBufferSubDataARB glBufferSubData -#define pglDeleteBuffersARB glDeleteBuffers -#define pglGenBuffersARB glGenBuffers - -// Those EXT symbols don't exist in GLES 2.0, since it imported the ARB version instead. -#define pglBindFramebufferEXT glBindFramebuffer -#define pglCheckFramebufferStatusEXT glCheckFramebufferStatus -#define pglDeleteFramebuffersEXT glDeleteFramebuffers -#define pglFramebufferTexture2DEXT glFramebufferTexture2D -#define pglGenFramebuffersEXT glGenFramebuffers -#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING -#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE -#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER - -// Those should come from GLES 2.0 core, not from GL_EXT_draw_buffers. -#ifndef GL_COLOR_ATTACHMENT0_EXT -#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 -#define GL_COLOR_ATTACHMENT1_EXT GL_COLOR_ATTACHMENT1 -#endif -#ifndef GL_DEPTH_ATTACHMENT_EXT -#define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT -#endif - -// GL_OES_mapbuffer -FUNC(GLvoid*, glMapBufferOES, (GLenum target, GLenum access)) -FUNC(GLboolean, glUnmapBufferOES, (GLenum target)) -#define pglMapBufferARB pglMapBufferOES -#define pglUnmapBufferARB pglUnmapBufferOES -#define GL_WRITE_ONLY GL_WRITE_ONLY_OES - -// GL_OES_texture_border_clamp -#define GL_CLAMP_TO_BORDER GL_CLAMP_TO_EDGE - -// GL_OES_rgb8_rgba8 -#define GL_RGBA8 GL_RGBA8_OES - -// GL_OES_depth32 -#define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES - -typedef GLuint GLhandleARB; - -#else - -// We might not have multisample on macOS. -#ifndef GL_TEXTURE_2D_MULTISAMPLE -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#endif - -// were these defined as real functions in gl.h already? - -// GL_EXT_draw_range_elements / GL1.2: -FUNC2(void, glDrawRangeElementsEXT, glDrawRangeElements, "1.2", (GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoid*)) - -// GL_ARB_multitexture / GL1.3: -FUNC2(void, glMultiTexCoord2fARB, glMultiTexCoord2f, "1.3", (int, float, float)) -FUNC2(void, glMultiTexCoord3fARB, glMultiTexCoord3f, "1.3", (int, float, float, float)) -FUNC2(void, glActiveTextureARB, glActiveTexture, "1.3", (int)) -FUNC2(void, glClientActiveTextureARB, glClientActiveTexture, "1.3", (int)) - -// GL_EXT_blend_color / GL1.4 (optional in 1.2): -FUNC2(void, glBlendColorEXT, glBlendColor, "1.4", (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) - -// GL_EXT_blend_minmax / GL1.4 (optional in 1.2): -FUNC2(void, glBlendEquationEXT, glBlendEquation, "1.4", (GLenum mode)) - -// GL_ARB_vertex_buffer_object / GL1.5: -FUNC2(void, glBindBufferARB, glBindBuffer, "1.5", (int target, GLuint buffer)) -FUNC2(void, glDeleteBuffersARB, glDeleteBuffers, "1.5", (GLsizei n, const GLuint* buffers)) -FUNC2(void, glGenBuffersARB, glGenBuffers, "1.5", (GLsizei n, GLuint* buffers)) -FUNC2(bool, glIsBufferARB, glIsBuffer, "1.5", (GLuint buffer)) -FUNC2(void, glBufferDataARB, glBufferData, "1.5", (int target, GLsizeiptrARB size, const void* data, int usage)) -FUNC2(void, glBufferSubDataARB, glBufferSubData, "1.5", (int target, GLintptrARB offset, GLsizeiptrARB size, const void* data)) -FUNC2(void, glGetBufferSubDataARB, glGetBufferSubData, "1.5", (int target, GLintptrARB offset, GLsizeiptrARB size, void* data)) -FUNC2(void*, glMapBufferARB, glMapBuffer, "1.5", (int target, int access)) -FUNC2(bool, glUnmapBufferARB, glUnmapBuffer, "1.5", (int target)) -FUNC2(void, glGetBufferParameterivARB, glGetBufferParameteriv, "1.5", (int target, int pname, int* params)) -FUNC2(void, glGetBufferPointervARB, glGetBufferPointerv, "1.5", (int target, int pname, void** params)) - -// GL_ARB_texture_compression / GL1.3 -FUNC2(void, glCompressedTexImage3DARB, glCompressedTexImage3D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)) -FUNC2(void, glCompressedTexImage2DARB, glCompressedTexImage2D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)) -FUNC2(void, glCompressedTexImage1DARB, glCompressedTexImage1D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*)) -FUNC2(void, glCompressedTexSubImage3DARB, glCompressedTexSubImage3D, "1.3", (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)) -FUNC2(void, glCompressedTexSubImage2DARB, glCompressedTexSubImage2D, "1.3", (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)) -FUNC2(void, glCompressedTexSubImage1DARB, glCompressedTexSubImage1D, "1.3", (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*)) -FUNC2(void, glGetCompressedTexImageARB, glGetCompressedTexImage, "1.3", (GLenum, GLint, GLvoid*)) - -// GL_EXT_framebuffer_object -FUNC(GLboolean, glIsRenderbufferEXT, (GLuint renderbuffer)) -FUNC(void, glBindRenderbufferEXT, (GLenum target, GLuint renderbuffer)) -FUNC(void, glDeleteRenderbuffersEXT, (GLsizei n, const GLuint *renderbuffers)) -FUNC(void, glGenRenderbuffersEXT, (GLsizei n, GLuint *renderbuffers)) -FUNC(void, glRenderbufferStorageEXT, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) -FUNC(void, glGetRenderbufferParameterivEXT, (GLenum target, GLenum pname, GLint *params)) -FUNC(GLboolean, glIsFramebufferEXT, (GLuint framebuffer)) -FUNC(void, glBindFramebufferEXT, (GLenum target, GLuint framebuffer)) -FUNC(void, glDeleteFramebuffersEXT, (GLsizei n, const GLuint *framebuffers)) -FUNC(void, glGenFramebuffersEXT, (GLsizei n, GLuint *framebuffers)) -FUNC(GLenum, glCheckFramebufferStatusEXT, (GLenum target)) -FUNC(void, glFramebufferTexture1DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) -FUNC(void, glFramebufferTexture2DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) -FUNC(void, glFramebufferTexture3DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)) -FUNC(void, glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) -FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum attachment, GLenum pname, GLint *params)) -FUNC(void, glGenerateMipmapEXT, (GLenum target)) -FUNC(void, glBlitFramebufferEXT, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) -FUNC(void, glDrawBuffers, (GLsizei n, const GLenum *bufs)) - -// GL_ARB_vertex_program, GL_ARB_fragment_program -FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string)) -FUNC(void, glBindProgramARB, (GLenum target, GLuint program)) -FUNC(void, glDeleteProgramsARB, (GLsizei n, const GLuint *programs)) -FUNC(void, glGenProgramsARB, (GLsizei n, GLuint *programs)) -FUNC(void, glProgramEnvParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) -FUNC(void, glProgramEnvParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params)) -FUNC(void, glProgramEnvParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)) -FUNC(void, glProgramEnvParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params)) -FUNC(void, glProgramLocalParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) -FUNC(void, glProgramLocalParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params)) -FUNC(void, glProgramLocalParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)) -FUNC(void, glProgramLocalParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params)) -FUNC(void, glGetProgramEnvParameterdvARB, (GLenum target, GLuint index, GLdouble *params)) -FUNC(void, glGetProgramEnvParameterfvARB, (GLenum target, GLuint index, GLfloat *params)) -FUNC(void, glGetProgramLocalParameterdvARB, (GLenum target, GLuint index, GLdouble *params)) -FUNC(void, glGetProgramLocalParameterfvARB, (GLenum target, GLuint index, GLfloat *params)) -FUNC(void, glGetProgramivARB, (GLenum target, GLenum pname, GLint *params)) -FUNC(void, glGetProgramStringARB, (GLenum target, GLenum pname, GLvoid *string)) -FUNC(GLboolean, glIsProgramARB, (GLuint program)) - -// GL_ARB_shader_objects -// (NOTE: Many of these have "Object" in their ARB names, but "Program" or "Shader" in their core names. -// When both Program and Shader versions exist, we use FUNC3 here and the engine must call the specific -// core name instead of the generic ARB name.) -FUNC3(void, glDeleteObjectARB, glDeleteShader, "2.0", (GLhandleARB obj)) -FUNC3(void, glDeleteObjectARB, glDeleteProgram, "2.0", (GLhandleARB obj)) -// FUNC2(GLhandleARB, glGetHandleARB, glGetHandle, "2.0", (GLenum pname)) - // there is no analog to the ARB function in GL 2.0 (the functionality is probably moved into glGetIntegerv(GL_CURRENT_PROGRAM)) - // so we can't represent it in this FUNC2 system, so just pretend it doesn't exist -FUNC2(void, glDetachObjectARB, glDetachShader, "2.0", (GLhandleARB containerObj, GLhandleARB attachedObj)) -FUNC2(GLhandleARB, glCreateShaderObjectARB, glCreateShader, "2.0", (GLenum shaderType)) -FUNC2(void, glShaderSourceARB, glShaderSource, "2.0", (GLhandleARB shaderObj, GLsizei count, const char **string, const GLint *length)) -FUNC2(void, glCompileShaderARB, glCompileShader, "2.0", (GLhandleARB shaderObj)) -FUNC2(GLhandleARB, glCreateProgramObjectARB, glCreateProgram, "2.0", (void)) -FUNC2(void, glAttachObjectARB, glAttachShader, "2.0", (GLhandleARB containerObj, GLhandleARB obj)) -FUNC2(void, glLinkProgramARB, glLinkProgram, "2.0", (GLhandleARB programObj)) -FUNC2(void, glUseProgramObjectARB, glUseProgram, "2.0", (GLhandleARB programObj)) -FUNC2(void, glValidateProgramARB, glValidateProgram, "2.0", (GLhandleARB programObj)) -FUNC2(void, glUniform1fARB, glUniform1f, "2.0", (GLint location, GLfloat v0)) -FUNC2(void, glUniform2fARB, glUniform2f, "2.0", (GLint location, GLfloat v0, GLfloat v1)) -FUNC2(void, glUniform3fARB, glUniform3f, "2.0", (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)) -FUNC2(void, glUniform4fARB, glUniform4f, "2.0", (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)) -FUNC2(void, glUniform1iARB, glUniform1i, "2.0", (GLint location, GLint v0)) -FUNC2(void, glUniform2iARB, glUniform2i, "2.0", (GLint location, GLint v0, GLint v1)) -FUNC2(void, glUniform3iARB, glUniform3i, "2.0", (GLint location, GLint v0, GLint v1, GLint v2)) -FUNC2(void, glUniform4iARB, glUniform4i, "2.0", (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)) -FUNC2(void, glUniform1fvARB, glUniform1fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) -FUNC2(void, glUniform2fvARB, glUniform2fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) -FUNC2(void, glUniform3fvARB, glUniform3fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) -FUNC2(void, glUniform4fvARB, glUniform4fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) -FUNC2(void, glUniform1ivARB, glUniform1iv, "2.0", (GLint location, GLsizei count, const GLint *value)) -FUNC2(void, glUniform2ivARB, glUniform2iv, "2.0", (GLint location, GLsizei count, const GLint *value)) -FUNC2(void, glUniform3ivARB, glUniform3iv, "2.0", (GLint location, GLsizei count, const GLint *value)) -FUNC2(void, glUniform4ivARB, glUniform4iv, "2.0", (GLint location, GLsizei count, const GLint *value)) -FUNC2(void, glUniformMatrix2fvARB, glUniformMatrix2fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) -FUNC2(void, glUniformMatrix3fvARB, glUniformMatrix3fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) -FUNC2(void, glUniformMatrix4fvARB, glUniformMatrix4fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) -FUNC3(void, glGetObjectParameterfvARB, glGetProgramfv, "2.0", (GLhandleARB obj, GLenum pname, GLfloat *params)) -FUNC3(void, glGetObjectParameterfvARB, glGetShaderfv, "2.0", (GLhandleARB obj, GLenum pname, GLfloat *params)) -FUNC3(void, glGetObjectParameterivARB, glGetProgramiv, "2.0", (GLhandleARB obj, GLenum pname, GLint *params)) -FUNC3(void, glGetObjectParameterivARB, glGetShaderiv, "2.0", (GLhandleARB obj, GLenum pname, GLint *params)) -FUNC3(void, glGetInfoLogARB, glGetProgramInfoLog, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, char *infoLog)) -FUNC3(void, glGetInfoLogARB, glGetShaderInfoLog, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, char *infoLog)) -FUNC2(void, glGetAttachedObjectsARB, glGetAttachedShaders, "2.0", (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj)) -FUNC2(GLint, glGetUniformLocationARB, glGetUniformLocation, "2.0", (GLhandleARB programObj, const char *name)) -FUNC2(void, glGetActiveUniformARB, glGetActiveUniform, "2.0", (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, char *name)) -FUNC2(void, glGetUniformfvARB, glGetUniformfv, "2.0", (GLhandleARB programObj, GLint location, GLfloat *params)) -FUNC2(void, glGetUniformivARB, glGetUniformiv, "2.0", (GLhandleARB programObj, GLint location, GLint *params)) -FUNC2(void, glGetShaderSourceARB, glGetShaderSource, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source)) - -// GL_ARB_vertex_shader -FUNC2(void, glVertexAttrib1fARB, glVertexAttrib1f, "2.0", (GLuint index, GLfloat v0)) -FUNC2(void, glVertexAttrib1sARB, glVertexAttrib1s, "2.0", (GLuint index, GLshort v0)) -FUNC2(void, glVertexAttrib1dARB, glVertexAttrib1d, "2.0", (GLuint index, GLdouble v0)) -FUNC2(void, glVertexAttrib2fARB, glVertexAttrib2f, "2.0", (GLuint index, GLfloat v0, GLfloat v1)) -FUNC2(void, glVertexAttrib2sARB, glVertexAttrib2s, "2.0", (GLuint index, GLshort v0, GLshort v1)) -FUNC2(void, glVertexAttrib2dARB, glVertexAttrib2d, "2.0", (GLuint index, GLdouble v0, GLdouble v1)) -FUNC2(void, glVertexAttrib3fARB, glVertexAttrib3f, "2.0", (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2)) -FUNC2(void, glVertexAttrib3sARB, glVertexAttrib3s, "2.0", (GLuint index, GLshort v0, GLshort v1, GLshort v2)) -FUNC2(void, glVertexAttrib3dARB, glVertexAttrib3d, "2.0", (GLuint index, GLdouble v0, GLdouble v1, GLdouble v2)) -FUNC2(void, glVertexAttrib4fARB, glVertexAttrib4f, "2.0", (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)) -FUNC2(void, glVertexAttrib4sARB, glVertexAttrib4s, "2.0", (GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3)) -FUNC2(void, glVertexAttrib4dARB, glVertexAttrib4d, "2.0", (GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3)) -FUNC2(void, glVertexAttrib4NubARB, glVertexAttrib4Nub, "2.0", (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w)) -FUNC2(void, glVertexAttrib1fvARB, glVertexAttrib1fv, "2.0", (GLuint index, const GLfloat *v)) -FUNC2(void, glVertexAttrib1svARB, glVertexAttrib1sv, "2.0", (GLuint index, const GLshort *v)) -FUNC2(void, glVertexAttrib1dvARB, glVertexAttrib1dv, "2.0", (GLuint index, const GLdouble *v)) -FUNC2(void, glVertexAttrib2fvARB, glVertexAttrib2fv, "2.0", (GLuint index, const GLfloat *v)) -FUNC2(void, glVertexAttrib2svARB, glVertexAttrib2sv, "2.0", (GLuint index, const GLshort *v)) -FUNC2(void, glVertexAttrib2dvARB, glVertexAttrib2dv, "2.0", (GLuint index, const GLdouble *v)) -FUNC2(void, glVertexAttrib3fvARB, glVertexAttrib3fv, "2.0", (GLuint index, const GLfloat *v)) -FUNC2(void, glVertexAttrib3svARB, glVertexAttrib3sv, "2.0", (GLuint index, const GLshort *v)) -FUNC2(void, glVertexAttrib3dvARB, glVertexAttrib3dv, "2.0", (GLuint index, const GLdouble *v)) -FUNC2(void, glVertexAttrib4fvARB, glVertexAttrib4fv, "2.0", (GLuint index, const GLfloat *v)) -FUNC2(void, glVertexAttrib4svARB, glVertexAttrib4sv, "2.0", (GLuint index, const GLshort *v)) -FUNC2(void, glVertexAttrib4dvARB, glVertexAttrib4dv, "2.0", (GLuint index, const GLdouble *v)) -FUNC2(void, glVertexAttrib4ivARB, glVertexAttrib4iv, "2.0", (GLuint index, const GLint *v)) -FUNC2(void, glVertexAttrib4bvARB, glVertexAttrib4bv, "2.0", (GLuint index, const GLbyte *v)) -FUNC2(void, glVertexAttrib4ubvARB, glVertexAttrib4ubv, "2.0", (GLuint index, const GLubyte *v)) -FUNC2(void, glVertexAttrib4usvARB, glVertexAttrib4usv, "2.0", (GLuint index, const GLushort *v)) -FUNC2(void, glVertexAttrib4uivARB, glVertexAttrib4uiv, "2.0", (GLuint index, const GLuint *v)) -FUNC2(void, glVertexAttrib4NbvARB, glVertexAttrib4Nbv, "2.0", (GLuint index, const GLbyte *v)) -FUNC2(void, glVertexAttrib4NsvARB, glVertexAttrib4Nsv, "2.0", (GLuint index, const GLshort *v)) -FUNC2(void, glVertexAttrib4NivARB, glVertexAttrib4Niv, "2.0", (GLuint index, const GLint *v)) -FUNC2(void, glVertexAttrib4NubvARB, glVertexAttrib4Nubv, "2.0", (GLuint index, const GLubyte *v)) -FUNC2(void, glVertexAttrib4NusvARB, glVertexAttrib4Nusv, "2.0", (GLuint index, const GLushort *v)) -FUNC2(void, glVertexAttrib4NuivARB, glVertexAttrib4Nuiv, "2.0", (GLuint index, const GLuint *v)) -FUNC2(void, glVertexAttribPointerARB, glVertexAttribPointer, "2.0", (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer)) -FUNC2(void, glEnableVertexAttribArrayARB, glEnableVertexAttribArray, "2.0", (GLuint index)) -FUNC2(void, glDisableVertexAttribArrayARB, glDisableVertexAttribArray, "2.0", (GLuint index)) -FUNC2(void, glBindAttribLocationARB, glBindAttribLocation, "2.0", (GLhandleARB programObj, GLuint index, const char *name)) -FUNC2(void, glGetActiveAttribARB, glGetActiveAttrib, "2.0", (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, int *size, GLenum *type, char *name)) -FUNC2(GLint, glGetAttribLocationARB, glGetAttribLocation, "2.0", (GLhandleARB programObj, const char *name)) -FUNC2(void, glGetVertexAttribdvARB, glGetVertexAttribdv, "2.0", (GLuint index, GLenum pname, GLdouble *params)) -FUNC2(void, glGetVertexAttribfvARB, glGetVertexAttribfv, "2.0", (GLuint index, GLenum pname, GLfloat *params)) -FUNC2(void, glGetVertexAttribivARB, glGetVertexAttribiv, "2.0", (GLuint index, GLenum pname, GLint *params)) -FUNC2(void, glGetVertexAttribPointervARB, glGetVertexAttribPointerv, "2.0", (GLuint index, GLenum pname, void **pointer)) - -// GL_EXT_gpu_shader4 / GL3.0: -FUNC2(void, glVertexAttribI1iEXT, glVertexAttribI1i, "3.0", (GLuint index, GLint x)) -FUNC2(void, glVertexAttribI2iEXT, glVertexAttribI2i, "3.0", (GLuint index, GLint x, GLint y)) -FUNC2(void, glVertexAttribI3iEXT, glVertexAttribI3i, "3.0", (GLuint index, GLint x, GLint y, GLint z)) -FUNC2(void, glVertexAttribI4iEXT, glVertexAttribI4i, "3.0", (GLuint index, GLint x, GLint y, GLint z, GLint w)) -FUNC2(void, glVertexAttribI1uiEXT, glVertexAttribI1ui, "3.0", (GLuint index, GLuint x)) -FUNC2(void, glVertexAttribI2uiEXT, glVertexAttribI2ui, "3.0", (GLuint index, GLuint x, GLuint y)) -FUNC2(void, glVertexAttribI3uiEXT, glVertexAttribI3ui, "3.0", (GLuint index, GLuint x, GLuint y, GLuint z)) -FUNC2(void, glVertexAttribI4uiEXT, glVertexAttribI4ui, "3.0", (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)) -FUNC2(void, glVertexAttribI1ivEXT, glVertexAttribI1iv, "3.0", (GLuint index, const GLint *v)) -FUNC2(void, glVertexAttribI2ivEXT, glVertexAttribI2iv, "3.0", (GLuint index, const GLint *v)) -FUNC2(void, glVertexAttribI3ivEXT, glVertexAttribI3iv, "3.0", (GLuint index, const GLint *v)) -FUNC2(void, glVertexAttribI4ivEXT, glVertexAttribI4iv, "3.0", (GLuint index, const GLint *v)) -FUNC2(void, glVertexAttribI1uivEXT, glVertexAttribI1uiv, "3.0", (GLuint index, const GLuint *v)) -FUNC2(void, glVertexAttribI2uivEXT, glVertexAttribI2uiv, "3.0", (GLuint index, const GLuint *v)) -FUNC2(void, glVertexAttribI3uivEXT, glVertexAttribI3uiv, "3.0", (GLuint index, const GLuint *v)) -FUNC2(void, glVertexAttribI4uivEXT, glVertexAttribI4uiv, "3.0", (GLuint index, const GLuint *v)) -FUNC2(void, glVertexAttribI4bvEXT, glVertexAttribI4bv, "3.0", (GLuint index, const GLbyte *v)) -FUNC2(void, glVertexAttribI4svEXT, glVertexAttribI4sv, "3.0", (GLuint index, const GLshort *v)) -FUNC2(void, glVertexAttribI4ubvEXT, glVertexAttribI4ubv, "3.0", (GLuint index, const GLubyte *v)) -FUNC2(void, glVertexAttribI4usvEXT, glVertexAttribI4usv, "3.0", (GLuint index, const GLushort *v)) -FUNC2(void, glVertexAttribIPointerEXT, glVertexAttribIPointer, "3.0", (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)) -FUNC2(void, glGetVertexAttribIivEXT, glGetVertexAttribIiv, "3.0", (GLuint index, GLenum pname, GLint *params)) -FUNC2(void, glGetVertexAttribIuivEXT, glGetVertexAttribIuiv, "3.0", (GLuint index, GLenum pname, GLuint *params)) -FUNC2(void, glUniform1uiEXT, glUniform1ui, "3.0", (GLint location, GLuint v0)) -FUNC2(void, glUniform2uiEXT, glUniform2ui, "3.0", (GLint location, GLuint v0, GLuint v1)) -FUNC2(void, glUniform3uiEXT, glUniform3ui, "3.0", (GLint location, GLuint v0, GLuint v1, GLuint v2)) -FUNC2(void, glUniform4uiEXT, glUniform4ui, "3.0", (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)) -FUNC2(void, glUniform1uivEXT, glUniform1uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) -FUNC2(void, glUniform2uivEXT, glUniform2uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) -FUNC2(void, glUniform3uivEXT, glUniform3uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) -FUNC2(void, glUniform4uivEXT, glUniform4uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) -FUNC2(void, glGetUniformuivEXT, glGetUniformuiv, "3.0", (GLuint program, GLint location, GLuint *params)) -FUNC2(void, glBindFragDataLocationEXT, glBindFragDataLocation, "3.0", (GLuint program, GLuint colorNumber, const char *name)) -FUNC2(GLint, glGetFragDataLocationEXT, glGetFragDataLocation, "3.0", (GLuint program, const char *name)) - -// GL_ARB_occlusion_query / GL1.5: -FUNC2(void, glGenQueriesARB, glGenQueries, "1.5", (GLsizei n, GLuint *ids)) -FUNC2(void, glDeleteQueriesARB, glDeleteQueries, "1.5", (GLsizei n, const GLuint *ids)) -FUNC2(GLboolean, glIsQueryARB, glIsQuery, "1.5", (GLuint id)) -FUNC2(void, glBeginQueryARB, glBeginQuery, "1.5", (GLenum target, GLuint id)) -FUNC2(void, glEndQueryARB, glEndQuery, "1.5", (GLenum target)) -FUNC2(void, glGetQueryivARB, glGetQueryiv, "1.5", (GLenum target, GLenum pname, GLint *params)) -FUNC2(void, glGetQueryObjectivARB, glGetQueryObjectiv, "1.5", (GLuint id, GLenum pname, GLint *params)) -FUNC2(void, glGetQueryObjectuivARB, glGetQueryObjectuiv, "1.5", (GLuint id, GLenum pname, GLuint *params)) - -// GL_ARB_sync / GL3.2: -FUNC2(void, glGetInteger64v, glGetInteger64v, "3.2", (GLenum pname, GLint64 *params)) - -// GL_EXT_timer_query: -FUNC(void, glGetQueryObjecti64vEXT, (GLuint id, GLenum pname, GLint64 *params)) -FUNC(void, glGetQueryObjectui64vEXT, (GLuint id, GLenum pname, GLuint64 *params)) - -// GL_ARB_timer_query / GL3.3: -FUNC2(void, glQueryCounter, glQueryCounter, "3.3", (GLuint id, GLenum target)) -FUNC2(void, glGetQueryObjecti64v, glGetQueryObjecti64v, "3.3", (GLuint id, GLenum pname, GLint64 *params)) -FUNC2(void, glGetQueryObjectui64v, glGetQueryObjectui64v, "3.3", (GLuint id, GLenum pname, GLuint64 *params)) - -// GL_ARB_map_buffer_range / GL3.0: -FUNC2(void*, glMapBufferRange, glMapBufferRange, "3.0", (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)) -FUNC2(void, glFlushMappedBufferRange, glFlushMappedBufferRange, "3.0", (GLenum target, GLintptr offset, GLsizeiptr length)) - -// GL_ARB_texture_multisample / GL3.3: -FUNC2(void, glTexImage2DMultisample, glTexImage2DMultisample, "3.3", (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations)) - -// GL_GREMEDY_string_marker (from gDEBugger) -FUNC(int, glStringMarkerGREMEDY, (GLsizei len, const GLvoid *string)) - -// GL_INTEL_performance_queries (undocumented, may be unstable, use at own risk; -// see http://zaynar.co.uk/docs/gl-intel-performance-queries.html) -FUNC(void, glGetFirstPerfQueryIdINTEL, (GLuint *queryId)) -FUNC(void, glGetNextPerfQueryIdINTEL, (GLuint prevQueryId, GLuint *queryId)) -FUNC(void, glGetPerfQueryInfoINTEL, (GLuint queryId, GLuint nameMaxLength, char *name, GLuint *counterBufferSize, GLuint *numCounters, GLuint *maxQueries, GLuint *)) -FUNC(void, glGetPerfCounterInfoINTEL, (GLuint queryId, GLuint counterId, GLuint nameMaxLength, char *name, GLuint descMaxLength, char *desc, GLuint *offset, GLuint *size, GLuint *usage, GLuint *type, GLuint64 *)) -FUNC(void, glCreatePerfQueryINTEL, (GLuint queryId, GLuint *id)) -FUNC(void, glBeginPerfQueryINTEL, (GLuint id)) -FUNC(void, glEndPerfQueryINTEL, (GLuint id)) -FUNC(void, glDeletePerfQueryINTEL, (GLuint id)) -FUNC(void, glGetPerfQueryDataINTEL, (GLuint id, GLenum requestType, GLuint maxLength, char *buffer, GLuint *length)) - -#endif // #if CONFIG_GLES2 - - -#if OS_WIN -// WGL_EXT_swap_control -FUNC(int, wglSwapIntervalEXT, (int)) - -// WGL_ARB_pbuffer -FUNC(HPBUFFERARB, wglCreatePbufferARB, (HDC, int, int, int, const int*)) -FUNC(HDC, wglGetPbufferDCARB, (HPBUFFERARB)) -FUNC(int, wglReleasePbufferDCARB, (HPBUFFERARB, HDC)) -FUNC(int, wglDestroyPbufferARB, (HPBUFFERARB)) -FUNC(int, wglQueryPbufferARB, (HPBUFFERARB, int, int*)) - -// GL_ARB_pixel_format -FUNC(int, wglGetPixelFormatAttribivARB, (HDC, int, int, unsigned int, const int*, int*)) -FUNC(int, wglGetPixelFormatAttribfvARB, (HDC, int, int, unsigned int, const int*, float*)) -FUNC(int, wglChoosePixelFormatARB, (HDC, const int *, const float*, unsigned int, int*, unsigned int*)) -#endif // OS_WIN - - -// GLX_MESA_query_renderer -FUNC(int /*Bool*/, glXQueryRendererIntegerMESA, (void /*Display*/ *dpy, int screen, int renderer, int attribute, unsigned int *value)) -FUNC(int /*Bool*/, glXQueryCurrentRendererIntegerMESA, (int attribute, unsigned int *value)) -FUNC(const char *, glXQueryRendererStringMESA, (void /*Display*/ *dpy, int screen, int renderer, int attribute)) -FUNC(const char *, glXQueryCurrentRendererStringMESA, (int attribute)) diff -Nru 0ad-0.0.25b/source/lib/external_libraries/libsdl.cpp 0ad-0.0.26/source/lib/external_libraries/libsdl.cpp --- 0ad-0.0.25b/source/lib/external_libraries/libsdl.cpp 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/external_libraries/libsdl.cpp 2022-09-23 19:16:47.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -28,6 +28,35 @@ #include + +#if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES +void* GetX11Display(SDL_Window* window) +{ + SDL_SysWMinfo wminfo; + SDL_VERSION(&wminfo.version); + const int ret = SDL_GetWindowWMInfo(window, &wminfo); + if (ret && wminfo.subsystem == SDL_SYSWM_X11) + { + return reinterpret_cast(wminfo.info.x11.display); + } + return nullptr; +} +#endif + +#if defined(SDL_VIDEO_DRIVER_WAYLAND) && !CONFIG2_GLES +void* GetWaylandDisplay(SDL_Window* window) +{ + SDL_SysWMinfo wminfo; + SDL_VERSION(&wminfo.version); + const int ret = SDL_GetWindowWMInfo(window, &wminfo); + if (ret && wminfo.subsystem == SDL_SYSWM_WAYLAND) + { + return reinterpret_cast(wminfo.info.wl.display); + } + return nullptr; +} +#endif + const char* GetSDLSubsystem(SDL_Window* window) { SDL_SysWMinfo wminfo; @@ -87,6 +116,7 @@ #if SDL_VERSION_ATLEAST(2, 0, 12) case SDL_SYSWM_HAIKU: subsystem = "Haiku"; + break; #endif #if SDL_VERSION_ATLEAST(2, 0, 11) default: diff -Nru 0ad-0.0.25b/source/lib/external_libraries/libsdl.h 0ad-0.0.26/source/lib/external_libraries/libsdl.h --- 0ad-0.0.25b/source/lib/external_libraries/libsdl.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/external_libraries/libsdl.h 2022-09-23 19:16:47.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,6 +27,7 @@ #ifndef INCLUDED_SDL #define INCLUDED_SDL +#include "lib/config2.h" #include "lib/external_libraries/libsdl_fwd.h" # include "SDL.h" @@ -56,4 +57,12 @@ // Returns a windowing subsystem used for the window. const char* GetSDLSubsystem(SDL_Window* window); +#if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES +void* GetX11Display(SDL_Window* window); +#endif + +#if defined(SDL_VIDEO_DRIVER_WAYLAND) && !CONFIG2_GLES +void* GetWaylandDisplay(SDL_Window* window); +#endif + #endif // INCLUDED_SDL diff -Nru 0ad-0.0.25b/source/lib/external_libraries/opengles2_wrapper.h 0ad-0.0.26/source/lib/external_libraries/opengles2_wrapper.h --- 0ad-0.0.25b/source/lib/external_libraries/opengles2_wrapper.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/external_libraries/opengles2_wrapper.h 2022-08-21 12:45:11.000000000 +0000 @@ -0,0 +1,121 @@ +/* Copyright (C) 2022 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. + */ + +#ifndef INCLUDED_GLES2_WRAPPER +#define INCLUDED_GLES2_WRAPPER + +#include "lib/config2.h" // CONFIG2_GLES + +#if CONFIG2_GLES +#include + +#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING +#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE +#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER +#define GL_WRITE_ONLY GL_WRITE_ONLY_OES +#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 +#define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT + + // Functions + +#define glActiveTextureARB glActiveTexture +#define glBlendColorEXT glBlendColor +#define glBlendEquationEXT glBlendEquation +#define glCompressedTexImage2DARB glCompressedTexImage2D +#define glAttachObjectARB glAttachShader +#define glBindAttribLocationARB glBindAttribLocation +#define glCompileShaderARB glCompileShader +#define glCreateProgramObjectARB glCreateProgram +#define glCreateShaderObjectARB glCreateShader +#define glDisableVertexAttribArrayARB glDisableVertexAttribArray +#define glEnableVertexAttribArrayARB glEnableVertexAttribArray +#define glGetActiveUniformARB glGetActiveUniform +#define glGetUniformLocationARB glGetUniformLocation +#define glLinkProgramARB glLinkProgram +#define glShaderSourceARB glShaderSource +#define glUniform1fARB glUniform1f +#define glUniform2fARB glUniform2f +#define glUniform3fARB glUniform3f +#define glUniform4fARB glUniform4f +#define glUniform1iARB glUniform1i +#define glUniform1fvARB glUniform1fv +#define glUniformMatrix4fvARB glUniformMatrix4fv +#define glUseProgramObjectARB glUseProgram +#define glVertexAttribPointerARB glVertexAttribPointer +#define glBindBufferARB glBindBuffer +#define glBufferDataARB glBufferData +#define glBufferSubDataARB glBufferSubData +#define glDeleteBuffersARB glDeleteBuffers +#define glGenBuffersARB glGenBuffers +#define glBindFramebufferEXT glBindFramebuffer +#define glCheckFramebufferStatusEXT glCheckFramebufferStatus +#define glDeleteFramebuffersEXT glDeleteFramebuffers +#define glFramebufferTexture2DEXT glFramebufferTexture2D +#define glGenFramebuffersEXT glGenFramebuffers + +// Extensions + +// GL_OES_texture_border_clamp +#define GL_CLAMP_TO_BORDER GL_CLAMP_TO_BORDER_OES +#define GL_TEXTURE_BORDER_COLOR GL_TEXTURE_BORDER_COLOR_OES + +// GL_OES_rgb8_rgba8 +#define GL_RGBA8 GL_RGBA8_OES + +// GL_OES_mapbuffer +#define glMapBufferARB glMapBufferOES +#define glUnmapBufferARB glUnmapBufferOES + +// GL_OES_depth32 +#define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES + +// GL_KHR_debug +#define glDebugMessageCallback glDebugMessageCallbackKHR +#define glDebugMessageControl glDebugMessageControlKHR +#define glObjectLabel glObjectLabelKHR +#define glPopDebugGroup glPopDebugGroupKHR +#define glPushDebugGroup glPushDebugGroupKHR + +#define GL_DEBUG_OUTPUT GL_DEBUG_OUTPUT_KHR +#define GL_DEBUG_SEVERITY_HIGH GL_DEBUG_SEVERITY_HIGH_KHR +#define GL_DEBUG_SEVERITY_LOW GL_DEBUG_SEVERITY_LOW_KHR +#define GL_DEBUG_SEVERITY_MEDIUM GL_DEBUG_SEVERITY_MEDIUM_KHR +#define GL_DEBUG_SEVERITY_NOTIFICATION GL_DEBUG_SEVERITY_NOTIFICATION_KHR +#define GL_DEBUG_SOURCE_API GL_DEBUG_SOURCE_API_KHR +#define GL_DEBUG_SOURCE_APPLICATION GL_DEBUG_SOURCE_APPLICATION_KHR +#define GL_DEBUG_SOURCE_OTHER GL_DEBUG_SOURCE_OTHER_KHR +#define GL_DEBUG_SOURCE_SHADER_COMPILER GL_DEBUG_SOURCE_SHADER_COMPILER_KHR +#define GL_DEBUG_SOURCE_THIRD_PARTY GL_DEBUG_SOURCE_THIRD_PARTY_KHR +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR +#define GL_DEBUG_TYPE_ERROR GL_DEBUG_TYPE_ERROR_KHR +#define GL_DEBUG_TYPE_MARKER GL_DEBUG_TYPE_MARKER_KHR +#define GL_DEBUG_TYPE_OTHER GL_DEBUG_TYPE_OTHER_KHR +#define GL_DEBUG_TYPE_PERFORMANCE GL_DEBUG_TYPE_PERFORMANCE_KHR +#define GL_DEBUG_TYPE_POP_GROUP GL_DEBUG_TYPE_POP_GROUP_KHR +#define GL_DEBUG_TYPE_PORTABILITY GL_DEBUG_TYPE_PORTABILITY_KHR +#define GL_DEBUG_TYPE_PUSH_GROUP GL_DEBUG_TYPE_PUSH_GROUP_KHR +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR + +#endif // CONFIG2_GLES + +#endif // !INCLUDED_GLES2_WRAPPER diff -Nru 0ad-0.0.25b/source/lib/external_libraries/opengl.h 0ad-0.0.26/source/lib/external_libraries/opengl.h --- 0ad-0.0.25b/source/lib/external_libraries/opengl.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/external_libraries/opengl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/* Copyright (C) 2011 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. - */ - -/* - * bring in OpenGL header+library, with compatibility fixes - */ - -#ifndef INCLUDED_OPENGL -#define INCLUDED_OPENGL - -#include "lib/config2.h" // CONFIG2_GLES - -#if OS_WIN -// wgl.h is a private header and should only be included from here. -// if this isn't defined, it'll complain. -#define WGL_HEADER_NEEDED -#include "lib/sysdep/os/win/wgl.h" -#endif - -#if CONFIG2_GLES -# include -#elif OS_MACOSX || OS_MAC -# include -#else -# include -#endif - -// if gl.h provides real prototypes for 1.2 / 1.3 functions, -// exclude the corresponding function pointers in glext_funcs.h -#ifdef GL_VERSION_1_2 -#define REAL_GL_1_2 -#endif -#ifdef GL_VERSION_1_3 -#define REAL_GL_1_3 -#endif - -// this must come after GL/gl.h include, so we can't combine the -// including GL/glext.h. -#undef GL_GLEXT_PROTOTYPES - -#if CONFIG2_GLES -# include -#elif OS_MACOSX || OS_MAC -# include -#else -# include -# if OS_WIN -# include -# endif -#endif - -#endif // #ifndef INCLUDED_OPENGL diff -Nru 0ad-0.0.25b/source/lib/file/archive/archive_zip.h 0ad-0.0.26/source/lib/file/archive/archive_zip.h --- 0ad-0.0.25b/source/lib/file/archive/archive_zip.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/archive/archive_zip.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -32,11 +32,11 @@ /** * @return 0 if opening the archive failed (e.g. because an external program is holding on to it) **/ -LIB_API PIArchiveReader CreateArchiveReader_Zip(const OsPath& archivePathname); +PIArchiveReader CreateArchiveReader_Zip(const OsPath& archivePathname); /** * @return 0 if opening the archive failed (e.g. because an external program is holding on to it) **/ -LIB_API PIArchiveWriter CreateArchiveWriter_Zip(const OsPath& archivePathname, bool noDeflate); +PIArchiveWriter CreateArchiveWriter_Zip(const OsPath& archivePathname, bool noDeflate); #endif // #ifndef INCLUDED_ARCHIVE_ZIP diff -Nru 0ad-0.0.25b/source/lib/file/archive/disabled_tests/test_codec_zlib.h 0ad-0.0.26/source/lib/file/archive/disabled_tests/test_codec_zlib.h --- 0ad-0.0.25b/source/lib/file/archive/disabled_tests/test_codec_zlib.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/archive/disabled_tests/test_codec_zlib.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,6 +25,8 @@ #include "lib/self_test.h" #include "lib/res/file/archive/codec_zlib.h" +#include + class TestCodecZLib : public CxxTest::TestSuite { public: @@ -35,10 +37,12 @@ // generate random input udata // (limit values to 0..7 so that the udata will actually be compressible) + std::mt19937 engine(42); + std::uniform_int_distribution distribution(0x00, 0x07); const size_t usize = 10000; u8 udata[usize]; for(size_t i = 0; i < usize; i++) - udata[i] = rand() & 0x07; + udata[i] = distribution(engine); // compress u8* cdata; size_t csize; diff -Nru 0ad-0.0.25b/source/lib/file/archive/disabled_tests/test_compression.h 0ad-0.0.26/source/lib/file/archive/disabled_tests/test_compression.h --- 0ad-0.0.25b/source/lib/file/archive/disabled_tests/test_compression.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/archive/disabled_tests/test_compression.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,6 +25,8 @@ #include "lib/self_test.h" #include "lib/res/file/archive/compression.h" +#include + class TestCompression : public CxxTest::TestSuite { public: @@ -32,10 +34,12 @@ { // generate random input data // (limit values to 0..7 so that the data will actually be compressible) + std::mt19937 engine(42); + std::uniform_int_distribution distribution(0x00, 0x07); const size_t data_size = 10000; u8 data[data_size]; for(size_t i = 0; i < data_size; i++) - data[i] = rand() & 0x07; + data[i] = distribution(engine); u8* cdata; size_t csize; u8 udata[data_size]; diff -Nru 0ad-0.0.25b/source/lib/file/file.h 0ad-0.0.26/source/lib/file/file.h --- 0ad-0.0.25b/source/lib/file/file.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/file.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -39,8 +39,8 @@ // @param oflag: either O_RDONLY or O_WRONLY (in which case O_CREAT and // O_TRUNC are added), plus O_DIRECT if aio is desired // @return file descriptor or a negative Status -LIB_API Status FileOpen(const OsPath& pathname, int oflag); -LIB_API void FileClose(int& fd); +Status FileOpen(const OsPath& pathname, int oflag); +void FileClose(int& fd); class File { diff -Nru 0ad-0.0.25b/source/lib/file/file_system.cpp 0ad-0.0.26/source/lib/file/file_system.cpp --- 0ad-0.0.25b/source/lib/file/file_system.cpp 2021-08-22 18:37:29.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/file_system.cpp 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,15 +25,13 @@ */ #include "precompiled.h" -#include "lib/file/file_system.h" -#include -#include -#include +#include "lib/file/file_system.h" #include "lib/sysdep/filesystem.h" #include +#include bool DirectoryExists(const OsPath& path) { @@ -200,7 +198,7 @@ try { - fs::rename(path.string8(), newPath.string8()); + fs::rename(fs::path(path.string()), fs::path(newPath.string())); } catch (fs::filesystem_error& err) { @@ -220,9 +218,9 @@ try { if(override_if_exists) - fs::copy_file(path.string8(), newPath.string8(), boost::filesystem::copy_option::overwrite_if_exists); + fs::copy_file(fs::path(path.string()), fs::path(newPath.string()), boost::filesystem::copy_option::overwrite_if_exists); else - fs::copy_file(path.string8(), newPath.string8()); + fs::copy_file(fs::path(path.string()), fs::path(newPath.string())); } catch(fs::filesystem_error& err) { diff -Nru 0ad-0.0.25b/source/lib/file/file_system.h 0ad-0.0.26/source/lib/file/file_system.h --- 0ad-0.0.25b/source/lib/file/file_system.h 2021-08-22 18:37:29.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/file_system.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -32,10 +32,10 @@ #include -LIB_API bool DirectoryExists(const OsPath& path); -LIB_API bool FileExists(const OsPath& pathname); +bool DirectoryExists(const OsPath& path); +bool FileExists(const OsPath& pathname); -LIB_API u64 FileSize(const OsPath& pathname); +u64 FileSize(const OsPath& pathname); // (bundling size and mtime avoids a second expensive call to stat()) @@ -72,22 +72,22 @@ time_t mtime; }; -LIB_API Status GetFileInfo(const OsPath& pathname, CFileInfo* fileInfo); +Status GetFileInfo(const OsPath& pathname, CFileInfo* fileInfo); typedef std::vector CFileInfos; typedef std::vector DirectoryNames; -LIB_API Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames* subdirectoryNames); +Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames* subdirectoryNames); // same as boost::filesystem::create_directories, except that mkdir is invoked with // instead of 0755. // If the breakpoint is enabled, debug_break will be called if the directory didn't exist and couldn't be created. -LIB_API Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint = true); +Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint = true); -LIB_API Status DeleteDirectory(const OsPath& dirPath); +Status DeleteDirectory(const OsPath& dirPath); -LIB_API Status CopyFile(const OsPath& path, const OsPath& newPath, bool override_if_exists = false); +Status CopyFile(const OsPath& path, const OsPath& newPath, bool override_if_exists = false); -LIB_API Status RenameFile(const OsPath& path, const OsPath& newPath); +Status RenameFile(const OsPath& path, const OsPath& newPath); #endif // #ifndef INCLUDED_FILE_SYSTEM diff -Nru 0ad-0.0.25b/source/lib/file/io/io.h 0ad-0.0.26/source/lib/file/io/io.h --- 0ad-0.0.25b/source/lib/file/io/io.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/io/io.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -226,8 +226,8 @@ #pragma pack(pop) -LIB_API Status Issue(aiocb& cb, size_t queueDepth); -LIB_API Status WaitUntilComplete(aiocb& cb, size_t queueDepth); +Status Issue(aiocb& cb, size_t queueDepth); +Status WaitUntilComplete(aiocb& cb, size_t queueDepth); //----------------------------------------------------------------------------- diff -Nru 0ad-0.0.25b/source/lib/file/vfs/vfs.h 0ad-0.0.26/source/lib/file/vfs/vfs.h --- 0ad-0.0.25b/source/lib/file/vfs/vfs.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/file/vfs/vfs.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -225,6 +225,6 @@ * note: there is no limitation to a single instance, it may make sense * to create and destroy VFS instances during each unit test. **/ -LIB_API PIVFS CreateVfs(); +PIVFS CreateVfs(); #endif // #ifndef INCLUDED_VFS diff -Nru 0ad-0.0.25b/source/lib/fnv_hash.cpp 0ad-0.0.26/source/lib/fnv_hash.cpp --- 0ad-0.0.25b/source/lib/fnv_hash.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/fnv_hash.cpp 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -20,12 +20,9 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* - * Fowler/Noll/Vo string hash - */ - #include "precompiled.h" +#include "lib/fnv_hash.h" // FNV1-A hash - good for strings. // if len = 0 (default), treat buf as a C-string; @@ -62,7 +59,6 @@ return h; } - // FNV1-A hash - good for strings. // if len = 0 (default), treat buf as a C-string; // otherwise, hash bytes of buf. @@ -93,40 +89,6 @@ bytes_left--; } - } - - return h; -} - - -// special version for strings: first converts to lowercase -// (useful for comparing mixed-case filenames). -// note: still need , e.g. to support non-0-terminated strings -u32 fnv_lc_hash(const char* str, size_t len) -{ - u32 h = 0x811c9dc5u; - // give distinct values for different length 0 buffers. - // value taken from FNV; it has no special significance. - - // expected case: string - if(!len) - { - while(*str) - { - h ^= tolower(*str++); - h *= 0x01000193u; - } - } - else - { - size_t bytes_left = len; - while(bytes_left != 0) - { - h ^= tolower(*str++); - h *= 0x01000193u; - - bytes_left--; - } } return h; diff -Nru 0ad-0.0.25b/source/lib/fnv_hash.h 0ad-0.0.26/source/lib/fnv_hash.h --- 0ad-0.0.25b/source/lib/fnv_hash.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/fnv_hash.h 2022-08-21 12:45:19.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -46,10 +46,4 @@ /// 64-bit version of fnv_hash. extern u64 fnv_hash64(const void* buf, size_t len = 0); -/** - * special version of fnv_hash for strings: first converts to lowercase - * (useful for comparing mixed-case filenames) - **/ -extern u32 fnv_lc_hash(const char* str, size_t len = 0); - -#endif // #ifndef INCLUDED_FNV_HASH +#endif // INCLUDED_FNV_HASH diff -Nru 0ad-0.0.25b/source/lib/frequency_filter.h 0ad-0.0.26/source/lib/frequency_filter.h --- 0ad-0.0.25b/source/lib/frequency_filter.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/frequency_filter.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -40,6 +40,6 @@ typedef std::shared_ptr PIFrequencyFilter; // expectedFrequency is a guess that hopefully speeds up convergence -LIB_API PIFrequencyFilter CreateFrequencyFilter(double resolution, double expectedFrequency); +PIFrequencyFilter CreateFrequencyFilter(double resolution, double expectedFrequency); #endif // #ifndef INCLUDED_FREQUENCY_FILTER diff -Nru 0ad-0.0.25b/source/lib/lib_api.h 0ad-0.0.26/source/lib/lib_api.h --- 0ad-0.0.25b/source/lib/lib_api.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/lib_api.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* Copyright (C) 2021 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. - */ - -#ifndef INCLUDED_LIB_API -#define INCLUDED_LIB_API - -#include "lib/sysdep/compiler.h" - -// note: EXTERN_C cannot be used because std::shared_ptr is often returned -// by value, which requires C++ linkage. - -#ifdef LIB_STATIC_LINK -# define LIB_API -#else -# if MSC_VERSION -# ifdef LIB_BUILD -# define LIB_API __declspec(dllexport) -# else -# define LIB_API __declspec(dllimport) -# ifdef NDEBUG -# pragma comment(lib, "lowlevel.lib") -# else -# pragma comment(lib, "lowlevel_d.lib") -# endif -# endif -# elif GCC_VERSION -# ifdef LIB_BUILD -# define LIB_API __attribute__ ((visibility("default"))) -# else -# define LIB_API -# endif -# else -# error "Don't know how to define LIB_API for this compiler" -# endif -#endif - -#endif // #ifndef INCLUDED_LIB_API diff -Nru 0ad-0.0.25b/source/lib/module_init.h 0ad-0.0.26/source/lib/module_init.h --- 0ad-0.0.25b/source/lib/module_init.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/module_init.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -50,7 +50,7 @@ * note that callbacks typically reference static data and thus do not * require a function argument, but that can later be added if necessary. **/ -LIB_API Status ModuleInit(volatile ModuleInitState* initState, Status (*init)()); +Status ModuleInit(volatile ModuleInitState* initState, Status (*init)()); /** * calls a user-defined shutdown function if initState is "initialized". @@ -69,6 +69,6 @@ * cleanup is necessary (e.g. at exit before leak reporting) and * it is certain that the module is no longer in use. **/ -LIB_API Status ModuleShutdown(volatile ModuleInitState* initState, void (*shutdown)()); +Status ModuleShutdown(volatile ModuleInitState* initState, void (*shutdown)()); #endif // #ifndef INCLUDED_MODULE_INIT diff -Nru 0ad-0.0.25b/source/lib/ogl.cpp 0ad-0.0.26/source/lib/ogl.cpp --- 0ad-0.0.25b/source/lib/ogl.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/ogl.cpp 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -20,46 +20,50 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* - * OpenGL helper functions. - */ - #include "precompiled.h" + #include "lib/ogl.h" +#include "lib/code_annotation.h" +#include "lib/config2.h" +#include "lib/debug.h" +#include "lib/external_libraries/libsdl.h" +#include "ps/CLogger.h" + +#if !CONFIG2_GLES + +# if OS_WIN +# include +# elif !OS_MACOSX && !OS_MAC +# include +# if defined(SDL_VIDEO_DRIVER_X11) +# include +# endif +# if defined(SDL_VIDEO_DRIVER_WAYLAND) +# include +# endif +# endif + +#endif // !CONFIG2_GLES + #include #include #include -#include "lib/external_libraries/libsdl.h" -#include "lib/debug.h" -#include "lib/sysdep/gfx.h" -#include "lib/res/h_mgr.h" - -#if MSC_VERSION -#pragma comment(lib, "opengl32.lib") -#endif - //---------------------------------------------------------------------------- // extensions //---------------------------------------------------------------------------- -// define extension function pointers -extern "C" -{ -#define FUNC(ret, name, params) ret (GL_CALL_CONV *p##name) params; -#define FUNC2(ret, nameARB, nameCore, version, params) ret (GL_CALL_CONV *p##nameARB) params; -#define FUNC3(ret, nameARB, nameCore, version, params) ret (GL_CALL_CONV *p##nameCore) params; -#include "lib/external_libraries/glext_funcs.h" -#undef FUNC3 -#undef FUNC2 -#undef FUNC -} - +static const char* exts = nullptr; -static const char* exts = NULL; -static bool have_30, have_21, have_20, have_15, have_14, have_13, have_12; +static bool have_30 = false; +static bool have_21 = false; +static bool have_20 = false; +static bool have_15 = false; +static bool have_14 = false; +static bool have_13 = false; +static bool have_12 = false; // return a C string of unspecified length containing a space-separated @@ -213,35 +217,21 @@ } } +static int GLVersion; +#if OS_WIN +static int WGLVersion; +#elif !CONFIG2_GLES && !OS_MACOSX && !OS_MAC +#if defined(SDL_VIDEO_DRIVER_X11) +static int GLXVersion; +#endif +#if defined(SDL_VIDEO_DRIVER_WAYLAND) +static int EGLVersion; +#endif +#endif -// check if the OpenGL implementation is at least at . -// (format: "%d.%d" major minor) -bool ogl_HaveVersion(const char* desired_version) +bool ogl_HaveVersion(int major, int minor) { - int desired_major, desired_minor; - if(sscanf_s(desired_version, "%d.%d", &desired_major, &desired_minor) != 2) - { - DEBUG_WARN_ERR(ERR::LOGIC); // invalid version string - return false; - } - - // guaranteed to be of the form "major.minor[.release][ vendor-specific]" - // or "OpenGL ES major.minor[.release][ vendor-specific]". - // we won't distinguish GLES 2.0 from GL 2.0, but that's okay since - // they're close enough. - const char* version = (const char*)glGetString(GL_VERSION); - int major, minor; - if(!version || - (sscanf_s(version, "%d.%d", &major, &minor) != 2 && - sscanf_s(version, "OpenGL ES %d.%d", &major, &minor) != 2)) - { - DEBUG_WARN_ERR(ERR::LOGIC); // GL_VERSION invalid - return false; - } - - // note: don't just compare characters - major and minor may be >= 10. - return (major > desired_major) || - (major == desired_major && minor >= desired_minor); + return GLAD_MAKE_VERSION(major, minor) <= GLVersion; } @@ -299,25 +289,25 @@ #else -static void GL_CALL_CONV dummy_glDrawRangeElementsEXT(GLenum mode, GLuint, GLuint, GLsizei count, GLenum type, GLvoid* indices) +static void GLAD_API_PTR dummy_glDrawRangeElementsEXT(GLenum mode, GLuint, GLuint, GLsizei count, GLenum type, GLvoid* indices) { glDrawElements(mode, count, type, indices); } -static void GL_CALL_CONV dummy_glActiveTextureARB(int) +static void GLAD_API_PTR dummy_glActiveTextureARB(GLenum UNUSED(texture)) { } -static void GL_CALL_CONV dummy_glClientActiveTextureARB(int) +static void GLAD_API_PTR dummy_glClientActiveTextureARB(GLenum UNUSED(texture)) { } -static void GL_CALL_CONV dummy_glMultiTexCoord2fARB(int, float s, float t) +static void GLAD_API_PTR dummy_glMultiTexCoord2fARB(GLenum UNUSED(target), GLfloat s, GLfloat t) { glTexCoord2f(s, t); } -static void GL_CALL_CONV dummy_glMultiTexCoord3fARB(int, float s, float t, float r) +static void GLAD_API_PTR dummy_glMultiTexCoord3fARB(GLenum UNUSED(target), GLfloat s, GLfloat t, GLfloat r) { glTexCoord3f(s, t, r); } @@ -328,49 +318,20 @@ if(!ogl_HaveExtension("GL_EXT_draw_range_elements")) { - pglDrawRangeElementsEXT = &dummy_glDrawRangeElementsEXT; + glDrawRangeElementsEXT = reinterpret_cast(&dummy_glDrawRangeElementsEXT); } if(!ogl_HaveExtension("GL_ARB_multitexture")) { - pglActiveTextureARB = &dummy_glActiveTextureARB; - pglClientActiveTextureARB = &dummy_glClientActiveTextureARB; - pglMultiTexCoord2fARB = &dummy_glMultiTexCoord2fARB; - pglMultiTexCoord3fARB = &dummy_glMultiTexCoord3fARB; + glActiveTextureARB = reinterpret_cast(&dummy_glActiveTextureARB); + glClientActiveTextureARB = reinterpret_cast(&dummy_glClientActiveTextureARB); + glMultiTexCoord2fARB = reinterpret_cast(&dummy_glMultiTexCoord2fARB); + glMultiTexCoord3fARB = reinterpret_cast(&dummy_glMultiTexCoord3fARB); } } #endif // #if CONFIG2_GLES -static void importExtensionFunctions() -{ - // It should be safe to load the ARB function pointers even if the - // extension isn't advertised, since we won't actually use them without - // checking for the extension. - // (TODO: this calls ogl_HaveVersion far more times than is necessary - - // we should probably use the have_* variables instead) - // Note: the xorg-x11 implementation of glXGetProcAddress doesn't return NULL - // if the function is unsupported (i.e. the rare case of a driver not reporting - // its supported version correctly, see http://trac.wildfiregames.com/ticket/171) -#define FUNC(ret, name, params) p##name = (ret (GL_CALL_CONV*) params)SDL_GL_GetProcAddress(#name); -#define FUNC23(pname, ret, nameARB, nameCore, version, params) \ - pname = NULL; \ - if(ogl_HaveVersion(version)) \ - pname = (ret (GL_CALL_CONV*) params)SDL_GL_GetProcAddress(#nameCore); \ - if(!pname) /* use the ARB name if the driver lied about what version it supports */ \ - pname = (ret (GL_CALL_CONV*) params)SDL_GL_GetProcAddress(#nameARB); -#define FUNC2(ret, nameARB, nameCore, version, params) FUNC23(p##nameARB, ret, nameARB, nameCore, version, params) -#define FUNC3(ret, nameARB, nameCore, version, params) FUNC23(p##nameCore, ret, nameARB, nameCore, version, params) -#include "lib/external_libraries/glext_funcs.h" -#undef FUNC3 -#undef FUNC2 -#undef FUNC23 -#undef FUNC - - enableDummyFunctions(); -} - - //---------------------------------------------------------------------------- const char* ogl_GetErrorName(GLenum err) @@ -421,7 +382,6 @@ debug_printf("%s:%d: OpenGL error(s) occurred: %s (%04x)\n", file, line, ogl_GetErrorName(first_error), (unsigned int)first_error); } - // ignore and reset the specified error (as returned by glGetError). // any other errors that have occurred are reported as ogl_WarnIfError would. // @@ -466,30 +426,110 @@ // feature and limit detect //---------------------------------------------------------------------------- -GLint ogl_max_tex_size = -1; // [pixels] -GLint ogl_max_tex_units = -1; // limit on GL_TEXTUREn - -// call after each video mode change, since thereafter extension functions -// may have changed [address]. -void ogl_Init() +#if OS_WIN +bool ogl_Init(void* (load)(const char*), void* hdc) +#elif !CONFIG2_GLES && !OS_MACOSX && !OS_MAC +bool ogl_Init(void* (load)(const char*), void* display, int subsystem) +#else +bool ogl_Init(void* (load)(const char*)) +#endif { + GLADloadfunc loadFunc = reinterpret_cast(load); + if (!loadFunc) + return false; + +#define LOAD_ERROR(ERROR_STRING) \ + if (g_Logger) \ + LOGERROR(ERROR_STRING); \ + else \ + debug_printf(ERROR_STRING); \ + +#if !CONFIG2_GLES + GLVersion = gladLoadGL(loadFunc); + if (!GLVersion) + { + LOAD_ERROR("Failed to load OpenGL functions."); + return false; + } +# if OS_WIN + WGLVersion = gladLoadWGL(reinterpret_cast(hdc), loadFunc); + if (!WGLVersion) + { + LOAD_ERROR("Failed to load WGL functions."); + return false; + } +# elif !OS_MACOSX && !OS_MAC + const SDL_SYSWM_TYPE sysWMType = static_cast(subsystem); +# if defined(SDL_VIDEO_DRIVER_X11) + if (sysWMType == SDL_SYSWM_X11) + { + GLXVersion = gladLoadGLX(reinterpret_cast(display), DefaultScreen(display), loadFunc); + if (!GLXVersion) + { + LOAD_ERROR("Failed to load GLX functions."); + return false; + } + } +# endif +# if defined(SDL_VIDEO_DRIVER_WAYLAND) + if (sysWMType == SDL_SYSWM_WAYLAND) + { + // TODO: investiage do we need Wayland display to load EGL. + // Because without eglGetDisplay we can't get one. But the + // function is loaded inside gladLoadEGL. So maybe we need to + // call it twice. + EGLVersion = gladLoadEGL(nullptr, loadFunc); + if (!EGLVersion) + { + LOAD_ERROR("Failed to load EGL functions."); + return false; + } + } +# endif +# endif +#else + GLVersion = gladLoadGLES2(loadFunc); + if (!GLVersion) + { + LOAD_ERROR("Failed to load GLES2 functions."); + return false; + } +#endif +#undef LOAD_ERROR + // cache extension list and versions for oglHave*. // note: this is less about performance (since the above are not // time-critical) than centralizing the 'OpenGL is ready' check. - exts = (const char*)glGetString(GL_EXTENSIONS); + exts = reinterpret_cast(glGetString(GL_EXTENSIONS)); ENSURE(exts); // else: called before OpenGL is ready for use - have_12 = ogl_HaveVersion("1.2"); - have_13 = ogl_HaveVersion("1.3"); - have_14 = ogl_HaveVersion("1.4"); - have_15 = ogl_HaveVersion("1.5"); - have_20 = ogl_HaveVersion("2.0"); - have_21 = ogl_HaveVersion("2.1"); - have_30 = ogl_HaveVersion("3.0"); + have_12 = ogl_HaveVersion(1, 2); + have_13 = ogl_HaveVersion(1, 3); + have_14 = ogl_HaveVersion(1, 4); + have_15 = ogl_HaveVersion(1, 5); + have_20 = ogl_HaveVersion(2, 0); + have_21 = ogl_HaveVersion(2, 1); + have_30 = ogl_HaveVersion(3, 0); - importExtensionFunctions(); + enableDummyFunctions(); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &ogl_max_tex_size); -#if !CONFIG2_GLES - glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ogl_max_tex_units); + return true; +} + + +void ogl_SetVsyncEnabled(bool enabled) +{ + const int interval = enabled ? 1 : 0; +#if !CONFIG2_GLES && OS_WIN + if (ogl_HaveExtension("WGL_EXT_swap_control")) + wglSwapIntervalEXT(interval); +#elif !CONFIG2_GLES && !OS_MACOSX && !OS_MAC +#if defined(SDL_VIDEO_DRIVER_X11) + if (GLXVersion && ogl_HaveExtension("GLX_SGI_swap_control")) + glXSwapIntervalSGI(interval); +#else + UNUSED2(interval); +#endif +#else + UNUSED2(interval); #endif } diff -Nru 0ad-0.0.25b/source/lib/ogl.h 0ad-0.0.26/source/lib/ogl.h --- 0ad-0.0.25b/source/lib/ogl.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/ogl.h 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,25 +27,42 @@ #ifndef INCLUDED_OGL #define INCLUDED_OGL -#include "lib/external_libraries/opengl.h" +#include "lib/config2.h" // CONFIG2_GLES +#include "lib/sysdep/os.h" // OS_WIN +#if CONFIG2_GLES +# include "external_libraries/opengles2_wrapper.h" +#else +# include +#endif + /** * initialization: import extension function pointers and do feature detect. - * call before using any other function, and after each video mode change. + * call before using any other function. * fails if OpenGL not ready for use. + * TODO: move loading functionality to GL backend. **/ -extern void ogl_Init(); +#if OS_WIN +extern bool ogl_Init(void* (load)(const char*), void* hdc); +#elif !OS_MACOSX && !OS_MAC && !CONFIG2_GLES +extern bool ogl_Init(void* (load)(const char*), void* display, int subsystem); +#else +extern bool ogl_Init(void* (load)(const char*)); +#endif +/** + * Change vsync state. + **/ +extern void ogl_SetVsyncEnabled(bool enabled); //----------------------------------------------------------------------------- // extensions /** - * check if an extension is supported by the OpenGL implementation. - * - * takes subsequently added core support for some extensions into account - * (in case drivers forget to advertise extensions). + * Check whether the given OpenGL extension is supported. + * NOTE: this does not check whether the extensions is *loaded*. + * for that, check whether GLAD_ is not null. * * @param ext extension string; exact case. * @return bool. @@ -55,12 +72,8 @@ /** * make sure the OpenGL implementation version matches or is newer than * the given version. - * - * @param version version string; format: ("%d.%d", major, minor). - * example: "1.2". - **/ -extern bool ogl_HaveVersion(const char* version); - + */ +extern bool ogl_HaveVersion(int major, int minor); /** * check if a list of extensions are all supported (as determined by * ogl_HaveExtension). @@ -83,59 +96,6 @@ **/ extern const char* ogl_ExtensionString(); -// The game wants to use some extension constants that aren't provided by -// glext.h on some old systems. -// Manually define all the necessary ones that are missing from -// GL_GLEXT_VERSION 39 (Mesa 7.0) since that's probably an old enough baseline: -#ifndef GL_VERSION_3_0 -# define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -# define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#endif -#ifndef GL_EXT_transform_feedback -# define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A -# define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B -# define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 -#endif -#ifndef GL_ARB_geometry_shader4 -# define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 -# define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD -# define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE -# define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF -# define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 -# define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 -#endif -#ifndef GL_ARB_timer_query -# define GL_TIME_ELAPSED 0x88BF -# define GL_TIMESTAMP 0x8E28 -#endif -#ifndef GL_ARB_framebuffer_object -# define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#endif -// Also need some more for OS X 10.5: -#ifndef GL_EXT_texture_array -# define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF -#endif -// Also need some types not in old glext.h: -#ifndef GL_ARB_sync - typedef int64_t GLint64; - typedef uint64_t GLuint64; -#endif - -// declare extension function pointers -#if OS_WIN -# define GL_CALL_CONV __stdcall -#else -# define GL_CALL_CONV -#endif -#define FUNC(ret, name, params) EXTERN_C ret (GL_CALL_CONV *p##name) params; -#define FUNC2(ret, nameARB, nameCore, version, params) EXTERN_C ret (GL_CALL_CONV *p##nameARB) params; -#define FUNC3(ret, nameARB, nameCore, version, params) EXTERN_C ret (GL_CALL_CONV *p##nameCore) params; -#include "lib/external_libraries/glext_funcs.h" -#undef FUNC3 -#undef FUNC2 -#undef FUNC -// leave GL_CALL_CONV defined for ogl.cpp - //----------------------------------------------------------------------------- // errors @@ -184,11 +144,4 @@ **/ extern bool ogl_SquelchError(GLenum err_to_ignore); - -//----------------------------------------------------------------------------- -// implementation limits / feature detect - -extern GLint ogl_max_tex_size; /// [pixels] -extern GLint ogl_max_tex_units; /// limit on GL_TEXTUREn - -#endif // #ifndef INCLUDED_OGL +#endif // INCLUDED_OGL diff -Nru 0ad-0.0.25b/source/lib/path.h 0ad-0.0.26/source/lib/path.h --- 0ad-0.0.25b/source/lib/path.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/path.h 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -37,10 +37,14 @@ #ifndef INCLUDED_PATH #define INCLUDED_PATH +#include "lib/sysdep/os.h" #include "lib/utf8.h" #include #include +#if OS_WIN +#include +#endif #include namespace ERR @@ -57,7 +61,7 @@ * @param s1, s2 comparand strings * @return bool **/ -LIB_API bool path_is_subpath(const wchar_t* s1, const wchar_t* s2); +bool path_is_subpath(const wchar_t* s1, const wchar_t* s2); /** * Get the path component of a path. @@ -66,7 +70,7 @@ * @param path Input path. * @return pointer to path component within \. **/ -LIB_API const wchar_t* path_name_only(const wchar_t* path); +const wchar_t* path_name_only(const wchar_t* path); // NB: there is a need for 'generic' paths (e.g. for Trace entry / archive pathnames). @@ -126,6 +130,19 @@ return path.empty(); } + // TODO: This macro should be removed later when macOS supports std::filesystem. + // Currently it does in more recent SDKs, but it also causes a slowdown on + // OpenGL. See #6193. +#if OS_WIN + /** + * @returns a STL version of the path. + */ + std::filesystem::path fileSystemPath() const + { + return std::filesystem::path(path); + } +#endif + const String& string() const { return path; diff -Nru 0ad-0.0.25b/source/lib/pch/pch_boost.h 0ad-0.0.26/source/lib/pch/pch_boost.h --- 0ad-0.0.25b/source/lib/pch/pch_boost.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/pch/pch_boost.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,14 +29,6 @@ # define BOOST_HAS_STDINT_H #endif -// Boost -// .. if this package isn't going to be statically linked, we're better off -// using Boost via DLL. (otherwise, we would have to ensure the exact same -// compiler is used, which is a pain because MSC8, MSC9 and ICC 10 are in use) -#ifndef LIB_STATIC_LINK -# define BOOST_ALL_DYN_LINK -#endif - // don't compile get_system_category() etc, since we don't use them and they // sometimes cause problems when linking. // But Filesystem <= 1.43 requires boost::system::posix, so only disable if newer diff -Nru 0ad-0.0.25b/source/lib/precompiled.h 0ad-0.0.26/source/lib/precompiled.h --- 0ad-0.0.25b/source/lib/precompiled.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/precompiled.h 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -69,7 +69,6 @@ #include "lib/sysdep/arch.h" #include "lib/sysdep/os.h" #include "lib/sysdep/stl.h" -#include "lib/lib_api.h" #include "lib/types.h" #include "lib/debug.h" #include "lib/lib.h" diff -Nru 0ad-0.0.25b/source/lib/rand.h 0ad-0.0.26/source/lib/rand.h --- 0ad-0.0.25b/source/lib/rand.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/rand.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -32,6 +32,7 @@ * avoids several common pitfalls; see discussion at * http://www.azillionmonkeys.com/qed/random.html **/ -LIB_API size_t rand(size_t min_inclusive, size_t max_exclusive); +// TODO: replace the function by STL distributions. +size_t rand(size_t min_inclusive, size_t max_exclusive); #endif // #ifndef INCLUDED_RAND diff -Nru 0ad-0.0.25b/source/lib/res/graphics/cursor.cpp 0ad-0.0.26/source/lib/res/graphics/cursor.cpp --- 0ad-0.0.25b/source/lib/res/graphics/cursor.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/graphics/cursor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,356 +0,0 @@ -/* 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 - * "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. - */ - -/* - * mouse cursors (either via OpenGL texture or hardware) - */ - -#include "precompiled.h" -#include "cursor.h" - -#include -#include -#include - -#include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" -#include "lib/res/h_mgr.h" -#include "ogl_tex.h" - -class SDLCursor -{ - SDL_Surface* surface; - SDL_Cursor* cursor; - -public: - Status create(const PIVFS& vfs, const VfsPath& pathname, int hotspotx_, int hotspoty_, double scale) - { - std::shared_ptr file; size_t fileSize; - RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize)); - - Tex t; - RETURN_STATUS_IF_ERR(t.decode(file, fileSize)); - - // convert to required BGRA format. - const size_t flags = (t.m_Flags | TEX_BGR) & ~TEX_DXT; - RETURN_STATUS_IF_ERR(t.transform_to(flags)); - void* bgra_img = t.get_data(); - if(!bgra_img) - WARN_RETURN(ERR::FAIL); - - surface = SDL_CreateRGBSurfaceFrom(bgra_img, (int)t.m_Width, (int)t.m_Height, 32, (int)t.m_Width*4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); - if(!surface) - return ERR::FAIL; - if(scale != 1.0) - { - SDL_Surface* scaled_surface = SDL_CreateRGBSurface(0, surface->w * scale, surface->h * scale, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); - if(!scaled_surface) - return ERR::FAIL; - if(SDL_BlitScaled(surface, NULL, scaled_surface, NULL)) - return ERR::FAIL; - SDL_FreeSurface(surface); - surface = scaled_surface; - } - cursor = SDL_CreateColorCursor(surface, hotspotx_, hotspoty_); - if(!cursor) - return ERR::FAIL; - - return INFO::OK; - } - - void set() - { - SDL_SetCursor(cursor); - } - - void destroy() - { - SDL_FreeCursor(cursor); - SDL_FreeSurface(surface); - } -}; - -// no init is necessary because this is stored in struct Cursor, which -// is 0-initialized by h_mgr. -class GLCursor -{ - Handle ht; - - GLint w, h; - int hotspotx, hotspoty; - -public: - Status create(const PIVFS& vfs, const VfsPath& pathname, int hotspotx_, int hotspoty_, double scale) - { - ht = ogl_tex_load(vfs, pathname); - RETURN_STATUS_IF_ERR(ht); - - size_t width, height; - (void)ogl_tex_get_size(ht, &width, &height, 0); - w = (GLint)(width * scale); - h = (GLint)(height * scale); - - hotspotx = hotspotx_; hotspoty = hotspoty_; - - (void)ogl_tex_set_filter(ht, GL_NEAREST); - (void)ogl_tex_upload(ht); - return INFO::OK; - } - - void destroy() - { - // note: we're stored in a resource => ht is initially 0 => - // this is safe, no need for an is_valid flag - (void)ogl_tex_free(ht); - } - - void draw(int x, int y) const - { -#if CONFIG2_GLES - UNUSED2(x); UNUSED2(y); -#warning TODO: implement cursors for GLES -#else - (void)ogl_tex_bind(ht); - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - - glBegin(GL_QUADS); - glTexCoord2i(1, 0); glVertex2i( x-hotspotx+w, y+hotspoty ); - glTexCoord2i(0, 0); glVertex2i( x-hotspotx, y+hotspoty ); - glTexCoord2i(0, 1); glVertex2i( x-hotspotx, y+hotspoty-h ); - glTexCoord2i(1, 1); glVertex2i( x-hotspotx+w, y+hotspoty-h ); - glEnd(); - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); -#endif - } - - Status validate() const - { - const GLint A = 128; // no cursor is expected to get this big - if(w > A || h > A || hotspotx > A || hotspoty > A) - WARN_RETURN(ERR::_1); - if(ht < 0) - WARN_RETURN(ERR::_2); - return INFO::OK; - } -}; - -enum CursorKind -{ - CK_Default, - CK_SDL, - CK_OpenGL -}; - -struct Cursor -{ - double scale; - - // require kind == CK_OpenGL after reload - bool forceGL; - - CursorKind kind; - - // valid iff kind == CK_SDL - SDLCursor sdl_cursor; - - // valid iff kind == CK_OpenGL - GLCursor gl_cursor; -}; - -H_TYPE_DEFINE(Cursor); - -static void Cursor_init(Cursor* c, va_list args) -{ - c->scale = va_arg(args, double); - c->forceGL = (va_arg(args, int) != 0); -} - -static void Cursor_dtor(Cursor* c) -{ - switch(c->kind) - { - case CK_Default: - break; // nothing to do - - case CK_SDL: - c->sdl_cursor.destroy(); - break; - - case CK_OpenGL: - c->gl_cursor.destroy(); - break; - - default: - DEBUG_WARN_ERR(ERR::LOGIC); - break; - } -} - -static Status Cursor_reload(Cursor* c, const PIVFS& vfs, const VfsPath& name, Handle) -{ - const VfsPath pathname(VfsPath(L"art/textures/cursors") / name); - - // read pixel offset of the cursor's hotspot [the bit of it that's - // drawn at (g_mouse_x,g_mouse_y)] from file. - int hotspotx = 0, hotspoty = 0; - { - const VfsPath pathnameHotspot = pathname.ChangeExtension(L".txt"); - std::shared_ptr buf; size_t size; - RETURN_STATUS_IF_ERR(vfs->LoadFile(pathnameHotspot, buf, size)); - std::wstringstream s(std::wstring((const wchar_t*)buf.get(), size)); - s >> hotspotx >> hotspoty; - } - - const VfsPath pathnameImage = pathname.ChangeExtension(L".png"); - - // try loading as SDL2 cursor - if(!c->forceGL && c->sdl_cursor.create(vfs, pathnameImage, hotspotx, hotspoty, c->scale) == INFO::OK) - c->kind = CK_SDL; - // fall back to GLCursor (system cursor code is disabled or failed) - else if(c->gl_cursor.create(vfs, pathnameImage, hotspotx, hotspoty, c->scale) == INFO::OK) - c->kind = CK_OpenGL; - // everything failed, leave cursor unchanged - else - c->kind = CK_Default; - - return INFO::OK; -} - -static Status Cursor_validate(const Cursor* c) -{ - switch(c->kind) - { - case CK_Default: - break; // nothing to do - - case CK_SDL: - break; // nothing to do - - case CK_OpenGL: - RETURN_STATUS_IF_ERR(c->gl_cursor.validate()); - break; - - default: - WARN_RETURN(ERR::_2); - break; - } - - return INFO::OK; -} - -static Status Cursor_to_string(const Cursor* c, wchar_t* buf) -{ - const wchar_t* type; - switch(c->kind) - { - case CK_Default: - type = L"default"; - break; - - case CK_SDL: - type = L"sdl"; - break; - - case CK_OpenGL: - type = L"gl"; - break; - - default: - DEBUG_WARN_ERR(ERR::LOGIC); - type = L"?"; - break; - } - - swprintf_s(buf, H_STRING_LEN, L"cursor (%ls)", type); - return INFO::OK; -} - - -// note: these standard resource interface functions are not exposed to the -// caller. all we need here is storage for the SDL_Cursor / GLCursor and -// a name -> data lookup mechanism, both provided by h_mgr. -// in other words, we continually create/free the cursor resource in -// cursor_draw and trust h_mgr's caching to absorb it. - -static Handle cursor_load(const PIVFS& vfs, const VfsPath& name, double scale, bool forceGL) -{ - return h_alloc(H_Cursor, vfs, name, 0, scale, (int)forceGL); -} - -void cursor_shutdown() -{ - h_mgr_free_type(H_Cursor); -} - -static Status cursor_free(Handle& h) -{ - return h_free(h, H_Cursor); -} - - -Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, double scale, bool forceGL) -{ - // hide the cursor - if(!name) - { - SDL_ShowCursor(SDL_DISABLE); - return INFO::OK; - } - - Handle hc = cursor_load(vfs, name, scale, forceGL); - // TODO: if forceGL changes at runtime after a cursor is first created, - // we might reuse a cached version of the cursor with the old forceGL flag - - RETURN_STATUS_IF_ERR(hc); // silently ignore failures - - H_DEREF(hc, Cursor, c); - - switch(c->kind) - { - case CK_Default: - break; - - case CK_SDL: - c->sdl_cursor.set(); - SDL_ShowCursor(SDL_ENABLE); - break; - - case CK_OpenGL: - c->gl_cursor.draw(x, y); - SDL_ShowCursor(SDL_DISABLE); - break; - - default: - DEBUG_WARN_ERR(ERR::LOGIC); - break; - } - - (void)cursor_free(hc); - return INFO::OK; -} diff -Nru 0ad-0.0.25b/source/lib/res/graphics/cursor.h 0ad-0.0.26/source/lib/res/graphics/cursor.h --- 0ad-0.0.25b/source/lib/res/graphics/cursor.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/graphics/cursor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* Copyright (C) 2017 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. - */ - -/* - * mouse cursors (either via OpenGL texture or hardware) - */ - -#ifndef INCLUDED_GRAPHICS_CURSOR -#define INCLUDED_GRAPHICS_CURSOR - -#include "lib/file/vfs/vfs.h" - -/** - * Draw the cursor on-screen. - * - * @param vfs - * @param name Base name of cursor or zero to hide the cursor. - * @param x,y Coordinates [pixels] (origin at lower left) - * (the origin is convenient for drawing via OpenGL, but requires the - * mouse Y coordinate to be subtracted from the client area height. - * Making the caller responsible for this avoids a dependency on - * the g_yres global variable.) - * @param scale Scale factor for drawing size the cursor. - * @param forceGL Require the OpenGL cursor implementation, not hardware cursor - * - * Uses a hardware mouse cursor where available, otherwise a - * portable OpenGL implementation. - **/ -extern Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, double scale, bool forceGL); - -/** - * Forcibly frees all cursor handles. - * - * Currently used just prior to SDL shutdown. - */ -void cursor_shutdown(); - -#endif // #ifndef INCLUDED_GRAPHICS_CURSOR diff -Nru 0ad-0.0.25b/source/lib/res/graphics/ogl_tex.cpp 0ad-0.0.26/source/lib/res/graphics/ogl_tex.cpp --- 0ad-0.0.25b/source/lib/res/graphics/ogl_tex.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/graphics/ogl_tex.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1140 +0,0 @@ -/* Copyright (C) 2019 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. - */ - -/* - * wrapper for all OpenGL texturing calls. provides caching, hotloading - * and lifetime management. - */ - -#include "precompiled.h" -#include "ogl_tex.h" - -#include - -#include "lib/app_hooks.h" -#include "lib/ogl.h" -#include "lib/bits.h" -#include "lib/sysdep/gfx.h" -#include "lib/tex/tex.h" - -#include "lib/res/h_mgr.h" -#include "lib/fnv_hash.h" - - -//---------------------------------------------------------------------------- -// OpenGL helper routines -//---------------------------------------------------------------------------- - -static bool filter_valid(GLint filter) -{ - switch(filter) - { - case GL_NEAREST: - case GL_LINEAR: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return true; - default: - return false; - } -} - - -static bool wrap_valid(GLint wrap) -{ - switch(wrap) - { -#if !CONFIG2_GLES - case GL_CLAMP: - case GL_CLAMP_TO_BORDER: -#endif - case GL_CLAMP_TO_EDGE: - case GL_REPEAT: - case GL_MIRRORED_REPEAT: - return true; - default: - return false; - } -} - - -static bool are_mipmaps_needed(size_t width, size_t height, GLint filter) -{ - // can't upload the entire texture; we're going to skip some - // levels until it no longer exceeds the OpenGL dimension limit. - if((GLint)width > ogl_max_tex_size || (GLint)height > ogl_max_tex_size) - return true; - - switch(filter) - { - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return true; - default: - return false; - } -} - - -static bool fmt_is_s3tc(GLenum fmt) -{ - switch(fmt) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - return true; - default: - return false; - } -} - - -// determine OpenGL texture format, given and Tex . -static GLint choose_fmt(size_t bpp, size_t flags) -{ - const bool alpha = (flags & TEX_ALPHA) != 0; - const bool bgr = (flags & TEX_BGR ) != 0; - const bool grey = (flags & TEX_GREY ) != 0; - const size_t dxt = flags & TEX_DXT; - - // S3TC - if(dxt != 0) - { - switch(dxt) - { - case DXT1A: - return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case 1: - return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - case 3: - return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - case 5: - return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - default: - DEBUG_WARN_ERR(ERR::LOGIC); // invalid DXT value - return 0; - } - } - - // uncompressed - switch(bpp) - { - case 8: - ENSURE(grey); - return GL_LUMINANCE; - case 16: - return GL_LUMINANCE_ALPHA; - case 24: - ENSURE(!alpha); -#if CONFIG2_GLES - // GLES never supports BGR - ENSURE(!bgr); - return GL_RGB; -#else - return bgr? GL_BGR : GL_RGB; -#endif - case 32: - ENSURE(alpha); - // GLES can support BGRA via GL_EXT_texture_format_BGRA8888 - // (TODO: can we rely on support for that extension?) - return bgr? GL_BGRA_EXT : GL_RGBA; - default: - DEBUG_WARN_ERR(ERR::LOGIC); // invalid bpp - return 0; - } - - UNREACHABLE; -} - - -//---------------------------------------------------------------------------- -// quality mechanism -//---------------------------------------------------------------------------- - -static GLint default_filter = GL_LINEAR; // one of the GL *minify* filters -static int default_q_flags = OGL_TEX_FULL_QUALITY; // OglTexQualityFlags - -static bool q_flags_valid(int q_flags) -{ - const size_t bits = OGL_TEX_FULL_QUALITY|OGL_TEX_HALF_BPP|OGL_TEX_HALF_RES; - // unrecognized bits are set - invalid - if((q_flags & ~bits) != 0) - return false; - // "full quality" but other reduction bits are set - invalid - if(q_flags & OGL_TEX_FULL_QUALITY && q_flags & ~OGL_TEX_FULL_QUALITY) - return false; - return true; -} - - -// change default settings - these affect performance vs. quality. -// may be overridden for individual textures via parameter to -// ogl_tex_upload or ogl_tex_set_filter, respectively. -// -// pass 0 to keep the current setting; defaults and legal values are: -// - q_flags: OGL_TEX_FULL_QUALITY; combination of OglTexQualityFlags -// - filter: GL_LINEAR; any valid OpenGL minification filter -void ogl_tex_set_defaults(int q_flags, GLint filter) -{ - if(q_flags) - { - ENSURE(q_flags_valid(q_flags)); - default_q_flags = q_flags; - } - - if(filter) - { - ENSURE(filter_valid(filter)); - default_filter = filter; - } -} - - -// choose an internal format for based on the given q_flags. -static GLint choose_int_fmt(GLenum fmt, int q_flags) -{ - // true => 4 bits per component; otherwise, 8 - const bool half_bpp = (q_flags & OGL_TEX_HALF_BPP) != 0; - - // early-out for S3TC textures: they don't need an internal format - // (because upload is via glCompressedTexImage2DARB), but we must avoid - // triggering the default case below. we might as well return a - // meaningful value (i.e. int_fmt = fmt). - if(fmt_is_s3tc(fmt)) - return fmt; - -#if CONFIG2_GLES - - UNUSED2(half_bpp); - - // GLES only supports internal format == external format - return fmt; - -#else - - switch(fmt) - { - // 8bpp - case GL_LUMINANCE: - return half_bpp? GL_LUMINANCE4 : GL_LUMINANCE8; - case GL_INTENSITY: - return half_bpp? GL_INTENSITY4 : GL_INTENSITY8; - case GL_ALPHA: - return half_bpp? GL_ALPHA4 : GL_ALPHA8; - - // 16bpp - case GL_LUMINANCE_ALPHA: - return half_bpp? GL_LUMINANCE4_ALPHA4 : GL_LUMINANCE8_ALPHA8; - - // 24bpp - case GL_RGB: - case GL_BGR: // note: BGR can't be used as internal format - return half_bpp? GL_RGB4 : GL_RGB8; - - // 32bpp - case GL_RGBA: - case GL_BGRA: // note: BGRA can't be used as internal format - return half_bpp? GL_RGBA4 : GL_RGBA8; - - default: - { - wchar_t buf[100]; - swprintf_s(buf, ARRAY_SIZE(buf), L"choose_int_fmt: fmt 0x%x isn't covered! please add it", fmt); - DEBUG_DISPLAY_ERROR(buf); - DEBUG_WARN_ERR(ERR::LOGIC); // given fmt isn't covered! please add it. - // fall back to a reasonable default - return half_bpp? GL_RGB4 : GL_RGB8; - } - } - - UNREACHABLE; - -#endif // #if CONFIG2_GLES -} - - -//---------------------------------------------------------------------------- -// texture state to allow seamless reload -//---------------------------------------------------------------------------- - -// see "Texture Parameters" in docs. - -// all GL state tied to the texture that must be reapplied after reload. -// (this mustn't get too big, as it's stored in the already sizeable OglTex) -struct OglTexState -{ - // glTexParameter - // note: there are more options, but they do not look to - // be important and will not be applied after a reload! - // in particular, LOD_BIAS isn't needed because that is set for - // the entire texturing unit via glTexEnv. - // .. texture filter - // note: this is the minification filter value; magnification filter - // is GL_NEAREST if it's GL_NEAREST, otherwise GL_LINEAR. - // we don't store mag_filter explicitly because it - // doesn't appear useful - either apps can tolerate LINEAR, or - // mipmaps aren't called for and filter could be NEAREST anyway). - GLint filter; - // .. wrap mode - GLint wrap_s; - GLint wrap_t; - // .. anisotropy - // note: ignored unless EXT_texture_filter_anisotropic is supported. - GLfloat anisotropy; -}; - - -// fill the given state object with default values. -static void state_set_to_defaults(OglTexState* ots) -{ - ots->filter = default_filter; - ots->wrap_s = GL_REPEAT; - ots->wrap_t = GL_REPEAT; - ots->anisotropy = 1.0f; -} - - -// send all state to OpenGL (actually the currently bound texture). -// called from ogl_tex_upload. -static void state_latch(OglTexState* ots) -{ - // filter - const GLint filter = ots->filter; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - const GLint mag_filter = (filter == GL_NEAREST)? GL_NEAREST : GL_LINEAR; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - - // wrap - const GLint wrap_s = ots->wrap_s; - const GLint wrap_t = ots->wrap_t; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); - // .. only CLAMP and REPEAT are guaranteed to be available. - // if we're using one of the others, we squelch the error that - // may have resulted if this GL implementation is old. -#if !CONFIG2_GLES - if((wrap_s != GL_CLAMP && wrap_s != GL_REPEAT) || (wrap_t != GL_CLAMP && wrap_t != GL_REPEAT)) - ogl_SquelchError(GL_INVALID_ENUM); -#endif - - // anisotropy - const GLfloat anisotropy = ots->anisotropy; - if (anisotropy != 1.0f && ogl_tex_has_anisotropy()) - { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); - } -} - - -//---------------------------------------------------------------------------- -// texture resource object -//---------------------------------------------------------------------------- - -// ideally we would split OglTex into data and state objects as in -// SndData / VSrc. this gives us the benefits of caching while still -// leaving each "instance" (state object, which owns a data reference) -// free to change its state. however, unlike in OpenAL, there is no state -// independent of the data object - all parameters are directly tied to the -// GL texture object. therefore, splitting them up is impossible. -// (we shouldn't even keep the texel data in memory since that's already -// covered by the FS cache). -// -// given that multiple "instances" share the state stored here, we conclude: -// - a refcount is necessary to prevent ogl_tex_upload from freeing -// as long as other instances are active. -// - concurrent use risks cross-talk (if the 2nd "instance" changes state and -// the first is reloaded, its state may change to that of the 2nd) -// -// as bad as it sounds, the latter issue isn't a problem: we do not expect -// multiple instances of the same texture where someone changes its filter. -// even if it is reloaded, the differing state is not critical. -// the alternative is even worse: disabling *all* caching/reuse would -// really hurt performance and h_mgr doesn't support only disallowing -// reuse of active objects (this would break the index lookup code, since -// multiple instances may then exist). - -// note: make sure these values fit inside OglTex.flags (only 16 bits) -enum OglTexFlags -{ - // "the texture is currently uploaded"; reset in dtor. - OT_IS_UPLOADED = 1, - - // "the enclosed Tex object is valid and holds a texture"; - // reset in dtor and after ogl_tex_upload's tex_free. - OT_TEX_VALID = 2, - //size_t tex_valid : 1; - - // "reload() should automatically re-upload the texture" (because - // it had been uploaded before the reload); never reset. - OT_NEED_AUTO_UPLOAD = 4, - - // (used for validating flags) - OT_ALL_FLAGS = OT_IS_UPLOADED|OT_TEX_VALID|OT_NEED_AUTO_UPLOAD -}; - -struct OglTex -{ - Tex t; - - // allocated by OglTex_reload; indicates the texture is currently uploaded. - GLuint id; - - // ogl_tex_upload calls choose_fmt to determine these from . - // however, its caller may override those values via parameters. - // note: these are stored here to allow retrieving via ogl_tex_get_format; - // they are only used within ogl_tex_upload. - GLenum fmt; - GLint int_fmt; - - OglTexState state; - - // OglTexQualityFlags - u8 q_flags; - - // to which Texture Mapping Unit was this bound? - u8 tmu; - - u16 flags; - - u32 uploaded_size; -}; - -H_TYPE_DEFINE(OglTex); - -static void OglTex_init(OglTex* ot, va_list args) -{ - Tex* wrapped_tex = va_arg(args, Tex*); - if(wrapped_tex) - { - ot->t = *wrapped_tex; - // indicate ot->t is now valid, thus skipping loading from file. - // note: ogl_tex_wrap prevents actual reloads from happening. - ot->flags |= OT_TEX_VALID; - } - - state_set_to_defaults(&ot->state); - ot->q_flags = default_q_flags; -} - -static void OglTex_dtor(OglTex* ot) -{ - if(ot->flags & OT_TEX_VALID) - { - ot->t.free(); - ot->flags &= ~OT_TEX_VALID; - } - - // note: do not check if OT_IS_UPLOADED is set, because we allocate - // OglTex.id without necessarily having done an upload. - glDeleteTextures(1, &ot->id); - ot->id = 0; - ot->flags &= ~OT_IS_UPLOADED; - ot->uploaded_size = 0; -} - -static Status OglTex_reload(OglTex* ot, const PIVFS& vfs, const VfsPath& pathname, Handle h) -{ - // we're reusing a freed but still in-memory OglTex object - if(ot->flags & OT_IS_UPLOADED) - return INFO::OK; - - // if we don't already have the texture in memory (*), load from file. - // * this happens if the texture is "wrapped". - if(!(ot->flags & OT_TEX_VALID)) - { - std::shared_ptr file; size_t fileSize; - RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize)); - if(ot->t.decode(file, fileSize) >= 0) - ot->flags |= OT_TEX_VALID; - } - - glGenTextures(1, &ot->id); - - // if it had already been uploaded before this reload, - // re-upload it (this also does state_latch). - if(ot->flags & OT_NEED_AUTO_UPLOAD) - (void)ogl_tex_upload(h); - - return INFO::OK; -} - -static Status OglTex_validate(const OglTex* ot) -{ - if(ot->flags & OT_TEX_VALID) - { - RETURN_STATUS_IF_ERR(ot->t.validate()); - - // width, height - // (note: this is done here because tex.cpp doesn't impose any - // restrictions on dimensions, while OpenGL does). - size_t w = ot->t.m_Width; - size_t h = ot->t.m_Height; - // .. == 0; texture file probably not loaded successfully. - if(w == 0 || h == 0) - WARN_RETURN(ERR::_11); - // .. not power-of-2. - // note: we can't work around this because both NV_texture_rectangle - // and subtexture require work for the client (changing tex coords). - // TODO: ARB_texture_non_power_of_two - if(!is_pow2(w) || !is_pow2(h)) - WARN_RETURN(ERR::_13); - - // no longer verify dimensions are less than ogl_max_tex_size, - // because we just use the higher mip levels in that case. - } - - // texture state - if(!filter_valid(ot->state.filter)) - WARN_RETURN(ERR::_14); - if(!wrap_valid(ot->state.wrap_s)) - WARN_RETURN(ERR::_15); - if(!wrap_valid(ot->state.wrap_t)) - WARN_RETURN(ERR::_16); - - // misc - if(!q_flags_valid(ot->q_flags)) - WARN_RETURN(ERR::_17); - if(ot->tmu >= 128) // unexpected that there will ever be this many - WARN_RETURN(ERR::_18); - if(ot->flags > OT_ALL_FLAGS) - WARN_RETURN(ERR::_19); - // .. note: don't check ot->fmt and ot->int_fmt - they aren't set - // until during ogl_tex_upload. - - return INFO::OK; -} - -static Status OglTex_to_string(const OglTex* ot, wchar_t* buf) -{ - swprintf_s(buf, H_STRING_LEN, L"OglTex id=%u flags=%x", ot->id, (unsigned int)ot->flags); - return INFO::OK; -} - - -// load and return a handle to the texture given in . -// for a list of supported formats, see tex.h's tex_load. -Handle ogl_tex_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags) -{ - Tex* wrapped_tex = 0; // we're loading from file - return h_alloc(H_OglTex, vfs, pathname, flags, wrapped_tex); -} - - -// return Handle to an existing object, if it has been loaded and -// is still in memory; otherwise, a negative error code. -Handle ogl_tex_find(const VfsPath& pathname) -{ - const uintptr_t key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); - return h_find(H_OglTex, key); -} - - -// make the given Tex object ready for use as an OpenGL texture -// and return a handle to it. this will be as if its contents -// had been loaded by ogl_tex_load. -// -// we need only add bookkeeping information and "wrap" it in -// a resource object (accessed via Handle), hence the name. -// -// isn't strictly needed but should describe the texture so that -// h_filename will return a meaningful comment for debug purposes. -// note: because we cannot guarantee that callers will pass distinct -// "filenames", caching is disabled for the created object. this avoids -// mistakenly reusing previous objects that share the same comment. -Handle ogl_tex_wrap(Tex* t, const PIVFS& vfs, const VfsPath& pathname, size_t flags) -{ - // this object may not be backed by a file ("may", because - // someone could do tex_load and then ogl_tex_wrap). - // if h_mgr asks for a reload, the dtor will be called but - // we won't be able to reconstruct it. therefore, disallow reloads. - // (they are improbable anyway since caller is supposed to pass a - // 'descriptive comment' instead of filename, but don't rely on that) - // also disable caching as explained above. - flags |= RES_DISALLOW_RELOAD|RES_NO_CACHE; - return h_alloc(H_OglTex, vfs, pathname, flags, t); -} - - -// free all resources associated with the texture and make further -// use of it impossible. (subject to refcount) -Status ogl_tex_free(Handle& ht) -{ - return h_free(ht, H_OglTex); -} - - -//---------------------------------------------------------------------------- -// state setters (see "Texture Parameters" in docs) -//---------------------------------------------------------------------------- - -// we require the below functions be called before uploading; this avoids -// potentially redundant glTexParameter calls (we'd otherwise need to always -// set defaults because we don't know if an override is forthcoming). - -// raise a debug warning if the texture has already been uploaded -// (except in the few cases where this is allowed; see below). -// this is so that you will notice incorrect usage - only one instance of a -// texture should be active at a time, because otherwise they vie for -// control of one shared OglTexState. -static void warn_if_uploaded(Handle ht, const OglTex* ot) -{ -#ifndef NDEBUG - // we do not require users of this module to remember if they've - // already uploaded a texture (inconvenient). since they also can't - // tell if the texture was newly loaded (due to h_alloc interface), - // we have to squelch this warning in 2 cases: - // - it's ogl_tex_loaded several times (i.e. refcount > 1) and the - // caller (typically a higher-level LoadTexture) is setting filter etc. - // - caller is using our Handle as a caching mechanism, and calls - // ogl_tex_set_* before every use of the texture. note: this - // need not fall under the above check, e.g. if freed but cached. - // workaround is that ogl_tex_set_* won't call us if the - // same state values are being set (harmless anyway). - intptr_t refs = h_get_refcnt(ht); - if(refs > 1) - return; // don't complain - - if(ot->flags & OT_IS_UPLOADED) - DEBUG_WARN_ERR(ERR::LOGIC); // ogl_tex_set_*: texture already uploaded and shouldn't be changed -#else - // (prevent warnings; the alternative of wrapping all call sites in - // #ifndef is worse) - UNUSED2(ht); - UNUSED2(ot); -#endif -} - - -// override default filter (as set above) for this texture. -// must be called before uploading (raises a warning if called afterwards). -// filter is as defined by OpenGL; it is applied for both minification and -// magnification (for rationale and details, see OglTexState) -Status ogl_tex_set_filter(Handle ht, GLint filter) -{ - H_DEREF(ht, OglTex, ot); - - if(!filter_valid(filter)) - WARN_RETURN(ERR::INVALID_PARAM); - - if(ot->state.filter != filter) - { - warn_if_uploaded(ht, ot); - ot->state.filter = filter; - } - return INFO::OK; -} - - -// override default wrap mode (GL_REPEAT) for this texture. -// must be called before uploading (raises a warning if called afterwards). -// wrap is as defined by OpenGL. -Status ogl_tex_set_wrap(Handle ht, GLint wrap_s, GLint wrap_t) -{ - H_DEREF(ht, OglTex, ot); - - if(!wrap_valid(wrap_s)) - WARN_RETURN(ERR::INVALID_PARAM); - - if(!wrap_valid(wrap_t)) - WARN_RETURN(ERR::INVALID_PARAM); - - if(ot->state.wrap_s != wrap_s || ot->state.wrap_t != wrap_t) - { - warn_if_uploaded(ht, ot); - ot->state.wrap_s = wrap_s; - ot->state.wrap_t = wrap_t; - } - return INFO::OK; -} - - -// override default anisotropy for this texture. -// must be called before uploading (raises a warning if called afterwards). -Status ogl_tex_set_anisotropy(Handle ht, GLfloat anisotropy) -{ - H_DEREF(ht, OglTex, ot); - - if(anisotropy < 1.0f) - WARN_RETURN(ERR::INVALID_PARAM); - - if(ot->state.anisotropy != anisotropy) - { - warn_if_uploaded(ht, ot); - ot->state.anisotropy = anisotropy; - } - return INFO::OK; -} - - -//---------------------------------------------------------------------------- -// upload -//---------------------------------------------------------------------------- - -// OpenGL has several features that are helpful for uploading but not -// available in all implementations. we check for their presence but -// provide for user override (in case they don't work on a card/driver -// combo we didn't test). - -// tristate; -1 is undecided -static int have_auto_mipmap_gen = -1; -static int have_s3tc = -1; -static int have_anistropy = -1; - -// override the default decision and force/disallow use of the -// given feature. should be called from ah_override_gl_upload_caps. -void ogl_tex_override(OglTexOverrides what, OglTexAllow allow) -{ - ENSURE(allow == OGL_TEX_ENABLE || allow == OGL_TEX_DISABLE); - const bool enable = (allow == OGL_TEX_ENABLE); - - switch(what) - { - case OGL_TEX_S3TC: - have_s3tc = enable; - break; - case OGL_TEX_AUTO_MIPMAP_GEN: - have_auto_mipmap_gen = enable; - break; - case OGL_TEX_ANISOTROPY: - have_anistropy = enable; - break; - default: - DEBUG_WARN_ERR(ERR::LOGIC); // invalid - break; - } -} - - -// detect caps (via OpenGL extension list) and give an app_hook the chance to -// override this (e.g. via list of card/driver combos on which S3TC breaks). -// called once from the first ogl_tex_upload. -static void detect_gl_upload_caps() -{ - // note: gfx_card will be empty if running in quickstart mode; - // in that case, we won't be able to check for known faulty cards. - - // detect features, but only change the variables if they were at - // "undecided" (if overrides were set before this, they must remain). - if(have_auto_mipmap_gen == -1) - { - have_auto_mipmap_gen = ogl_HaveExtension("GL_SGIS_generate_mipmap"); - } - if(have_s3tc == -1) - { -#if CONFIG2_GLES - // some GLES implementations have GL_EXT_texture_compression_dxt1 - // but that only supports DXT1 so we can't use it. - have_s3tc = ogl_HaveExtensions(0, "GL_EXT_texture_compression_s3tc", NULL) == 0; -#else - // note: we don't bother checking for GL_S3_s3tc - it is incompatible - // and irrelevant (was never widespread). - have_s3tc = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", NULL) == 0; -#endif - } - if(have_anistropy == -1) - { - have_anistropy = ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"); - } - - // allow app hook to make ogl_tex_override calls - if(AH_IS_DEFINED(override_gl_upload_caps)) - { - ah_override_gl_upload_caps(); - } - // no app hook defined - have our own crack at blacklisting some hardware. - else - { - const std::wstring cardName = gfx::CardName(); - // rationale: janwas's laptop's S3 card blows up if S3TC is used - // (oh, the irony). it'd be annoying to have to share this between all - // projects, hence this default implementation here. - if(cardName == L"S3 SuperSavage/IXC 1014") - ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE); - } -} - - -// take care of mipmaps. if they are called for by , either -// arrange for OpenGL to create them, or see to it that the Tex object -// contains them (if need be, creating them in software). -// sets *plevels_to_skip to influence upload behavior (depending on -// whether mipmaps are needed and the quality settings). -// returns 0 to indicate success; otherwise, caller must disable -// mipmapping by switching filter to e.g. GL_LINEAR. -static Status get_mipmaps(Tex* t, GLint filter, int q_flags, int* plevels_to_skip) -{ - // decisions: - // .. does filter call for uploading mipmaps? - const bool need_mipmaps = are_mipmaps_needed(t->m_Width, t->m_Height, filter); - // .. does the image data include mipmaps? (stored as separate - // images after the regular texels) - const bool includes_mipmaps = (t->m_Flags & TEX_MIPMAPS) != 0; - // .. is this texture in S3TC format? (more generally, "compressed") - const bool is_s3tc = (t->m_Flags & TEX_DXT) != 0; - - *plevels_to_skip = TEX_BASE_LEVEL_ONLY; - if(!need_mipmaps) - return INFO::OK; - - // image already contains pregenerated mipmaps; we need do nothing. - // this is the nicest case, because they are fastest to load - // (no extra processing needed) and typically filtered better than - // if automatically generated. - if(includes_mipmaps) - *plevels_to_skip = 0; // t contains mipmaps - // OpenGL supports automatic generation; we need only - // activate that and upload the base image. -#if !CONFIG2_GLES - else if(have_auto_mipmap_gen) - { - // note: we assume GL_GENERATE_MIPMAP and GL_GENERATE_MIPMAP_SGIS - // have the same values - it's heavily implied by the spec - // governing 'promoted' ARB extensions and just plain makes sense. - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - } -#endif - // image is S3TC-compressed and the previous 2 alternatives weren't - // available; we're going to cheat and just disable mipmapping. - // rationale: having tex_transform add mipmaps would be slow (since - // all<->all transforms aren't implemented, it'd have to decompress - // from S3TC first), and DDS images ought to include mipmaps! - else if(is_s3tc) - return ERR::FAIL; // NOWARN - // image is uncompressed and we're on an old OpenGL implementation; - // we will generate mipmaps in software. - else - { - RETURN_STATUS_IF_ERR(t->transform_to(t->m_Flags|TEX_MIPMAPS)); - *plevels_to_skip = 0; // t contains mipmaps - } - - // t contains mipmaps; we can apply our resolution reduction trick: - if(*plevels_to_skip == 0) - { - // if OpenGL's texture dimension limit is too small, use the - // higher mipmap levels. NB: the minimum guaranteed size is - // far too low, and menu background textures may be large. - GLint w = (GLint)t->m_Width, h = (GLint)t->m_Height; - while(w > ogl_max_tex_size || h > ogl_max_tex_size) - { - (*plevels_to_skip)++; - w /= 2; h /= 2; // doesn't matter if either dimension drops to 0 - } - - // this saves texture memory by skipping some of the lower - // (high-resolution) mip levels. - // - // note: we don't just use GL_TEXTURE_BASE_LEVEL because it would - // require uploading unused levels, which is wasteful. - // .. can be expanded to reduce to 1/4, 1/8 by encoding factor in q_flags. - if(q_flags & OGL_TEX_HALF_RES) - (*plevels_to_skip)++; - } - - return INFO::OK; -} - - -// tex_util_foreach_mipmap callbacks: upload the given level to OpenGL. - -struct UploadParams -{ - GLenum fmt; - GLint int_fmt; - u32* uploaded_size; -}; - -static void upload_level(size_t level, size_t level_w, size_t level_h, const u8* RESTRICT level_data, size_t level_data_size, void* RESTRICT cbData) -{ - const UploadParams* up = (const UploadParams*)cbData; - glTexImage2D(GL_TEXTURE_2D, (GLint)level, up->int_fmt, (GLsizei)level_w, (GLsizei)level_h, 0, up->fmt, GL_UNSIGNED_BYTE, level_data); - *up->uploaded_size += (u32)level_data_size; -} - -static void upload_compressed_level(size_t level, size_t level_w, size_t level_h, const u8* RESTRICT level_data, size_t level_data_size, void* RESTRICT cbData) -{ - const UploadParams* up = (const UploadParams*)cbData; - pglCompressedTexImage2DARB(GL_TEXTURE_2D, (GLint)level, up->fmt, (GLsizei)level_w, (GLsizei)level_h, 0, (GLsizei)level_data_size, level_data); - *up->uploaded_size += (u32)level_data_size; -} - -// upload the texture in the specified (internal) format. -// split out of ogl_tex_upload because it was too big. -// -// pre: is valid for OpenGL use; texture is bound. -static void upload_impl(Tex* t, GLenum fmt, GLint int_fmt, int levels_to_skip, u32* uploaded_size) -{ - const GLsizei w = (GLsizei)t->m_Width; - const GLsizei h = (GLsizei)t->m_Height; - const size_t bpp = t->m_Bpp; - const u8* data = (const u8*)t->get_data(); - const UploadParams up = { fmt, int_fmt, uploaded_size }; - - if(t->m_Flags & TEX_DXT) - tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 4, upload_compressed_level, (void*)&up); - else - tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 1, upload_level, (void*)&up); -} - - -// upload the texture to OpenGL. -// if not 0, parameters override the following: -// fmt_ovr : OpenGL format (e.g. GL_RGB) decided from bpp / Tex flags; -// q_flags_ovr : global default "quality vs. performance" flags; -// int_fmt_ovr : internal format (e.g. GL_RGB8) decided from fmt / q_flags. -// -// side effects: -// - enables texturing on TMU 0 and binds the texture to it; -// - frees the texel data! see ogl_tex_get_data. -Status ogl_tex_upload(const Handle ht, GLenum fmt_ovr, int q_flags_ovr, GLint int_fmt_ovr) -{ - ONCE(detect_gl_upload_caps()); - - H_DEREF(ht, OglTex, ot); - Tex* t = &ot->t; - ENSURE(q_flags_valid(q_flags_ovr)); - // we don't bother verifying *fmt_ovr - there are too many values - - // upload already happened; no work to do. - // (this also happens if a cached texture is "loaded") - if(ot->flags & OT_IS_UPLOADED) - return INFO::OK; - - if(ot->flags & OT_TEX_VALID) - { - // decompress S3TC if that's not supported by OpenGL. - if((t->m_Flags & TEX_DXT) && !have_s3tc) - (void)t->transform_to(t->m_Flags & ~TEX_DXT); - - // determine fmt and int_fmt, allowing for user override. - ot->fmt = choose_fmt(t->m_Bpp, t->m_Flags); - if(fmt_ovr) ot->fmt = fmt_ovr; - if(q_flags_ovr) ot->q_flags = q_flags_ovr; - ot->int_fmt = choose_int_fmt(ot->fmt, ot->q_flags); - if(int_fmt_ovr) ot->int_fmt = int_fmt_ovr; - - ot->uploaded_size = 0; - - // now actually send to OpenGL: - ogl_WarnIfError(); - { - // (note: we know ht is valid due to H_DEREF, but ogl_tex_bind can - // fail in debug builds if OglTex.id isn't a valid texture name) - RETURN_STATUS_IF_ERR(ogl_tex_bind(ht, ot->tmu)); - int levels_to_skip; - if(get_mipmaps(t, ot->state.filter, ot->q_flags, &levels_to_skip) < 0) - // error => disable mipmapping - ot->state.filter = GL_LINEAR; - // (note: if first time, applies our defaults/previous overrides; - // otherwise, replays all state changes) - state_latch(&ot->state); - upload_impl(t, ot->fmt, ot->int_fmt, levels_to_skip, &ot->uploaded_size); - } - ogl_WarnIfError(); - - ot->flags |= OT_IS_UPLOADED; - - // see rationale for at declaration of OglTex. - intptr_t refs = h_get_refcnt(ht); - if(refs == 1) - { - // note: we verify above that OT_TEX_VALID is set - ot->flags &= ~OT_TEX_VALID; - } - } - - ot->flags |= OT_NEED_AUTO_UPLOAD; - - return INFO::OK; -} - - -//---------------------------------------------------------------------------- -// getters -//---------------------------------------------------------------------------- - -// retrieve texture dimensions and bits per pixel. -// all params are optional and filled if non-NULL. -Status ogl_tex_get_size(Handle ht, size_t* w, size_t* h, size_t* bpp) -{ - H_DEREF(ht, OglTex, ot); - - if(w) - *w = ot->t.m_Width; - if(h) - *h = ot->t.m_Height; - if(bpp) - *bpp = ot->t.m_Bpp; - return INFO::OK; -} - - -// retrieve TexFlags and the corresponding OpenGL format. -// the latter is determined during ogl_tex_upload and is 0 before that. -// all params are optional and filled if non-NULL. -Status ogl_tex_get_format(Handle ht, size_t* flags, GLenum* fmt) -{ - H_DEREF(ht, OglTex, ot); - - if(flags) - *flags = ot->t.m_Flags; - if(fmt) - { - ENSURE(ot->flags & OT_IS_UPLOADED); - *fmt = ot->fmt; - } - return INFO::OK; -} - - -// retrieve pointer to texel data. -// -// note: this memory is freed after a successful ogl_tex_upload for -// this texture. after that, the pointer we retrieve is NULL but -// the function doesn't fail (negative return value) by design. -// if you still need to get at the data, add a reference before -// uploading it or read directly from OpenGL (discouraged). -Status ogl_tex_get_data(Handle ht, u8** p) -{ - H_DEREF(ht, OglTex, ot); - - *p = ot->t.get_data(); - return INFO::OK; -} - -Status ogl_tex_get_uploaded_size(Handle ht, size_t* size) -{ - H_DEREF(ht, OglTex, ot); - - *size = ot->uploaded_size; - return INFO::OK; -} - -// retrieve color of 1x1 mipmap level -extern Status ogl_tex_get_average_color(Handle ht, u32* p) -{ - H_DEREF(ht, OglTex, ot); - warn_if_uploaded(ht, ot); - - *p = ot->t.get_average_color(); - return INFO::OK; -} - -//---------------------------------------------------------------------------- -// misc API -//---------------------------------------------------------------------------- - -// bind the texture to the specified unit [number] in preparation for -// using it in rendering. if is 0, texturing is disabled instead. -// -// side effects: -// - changes the active texture unit; -// - (if return value is 0:) texturing was enabled/disabled on that unit. -// -// notes: -// - assumes multitexturing is available. -// - not necessary before calling ogl_tex_upload! -// - on error, the unit's texture state is unchanged; see implementation. -Status ogl_tex_bind(Handle ht, size_t unit) -{ - // note: there are many call sites of glActiveTextureARB, so caching - // those and ignoring redundant sets isn't feasible. - pglActiveTextureARB((int)(GL_TEXTURE0+unit)); - - // special case: disable texturing - if(ht == 0) - { -#if !CONFIG2_GLES - glDisable(GL_TEXTURE_2D); -#endif - return INFO::OK; - } - - // if this fails, the texture unit's state remains unchanged. - // we don't bother catching that and disabling texturing because a - // debug warning is raised anyway, and it's quite unlikely. - H_DEREF(ht, OglTex, ot); - ot->tmu = (u8)unit; - - // if 0, there's a problem in the OglTex reload/dtor logic. - // binding it results in whiteness, which can have many causes; - // we therefore complain so this one can be ruled out. - ENSURE(ot->id != 0); - -#if !CONFIG2_GLES - glEnable(GL_TEXTURE_2D); -#endif - glBindTexture(GL_TEXTURE_2D, ot->id); - return INFO::OK; -} - -Status ogl_tex_get_texture_id(Handle ht, GLuint* id) -{ - *id = 0; - H_DEREF(ht, OglTex, ot); - *id = ot->id; - return INFO::OK; -} - -// apply the specified transforms (as in tex_transform) to the image. -// must be called before uploading (raises a warning if called afterwards). -Status ogl_tex_transform(Handle ht, size_t transforms) -{ - H_DEREF(ht, OglTex, ot); - Status ret = ot->t.transform(transforms); - return ret; -} - - -// change the pixel format to that specified by . -// (note: this is equivalent to ogl_tex_transform(ht, ht_flags^new_flags). -Status ogl_tex_transform_to(Handle ht, size_t new_flags) -{ - H_DEREF(ht, OglTex, ot); - Status ret = ot->t.transform_to(new_flags); - return ret; -} - - -// return whether native S3TC support is available -bool ogl_tex_has_s3tc() -{ - // ogl_tex_upload must be called before this - ENSURE(have_s3tc != -1); - - return (have_s3tc != 0); -} - -// return whether anisotropic filtering support is available -bool ogl_tex_has_anisotropy() -{ - // ogl_tex_upload must be called before this - ENSURE(have_anistropy != -1); - - return (have_anistropy != 0); -} diff -Nru 0ad-0.0.25b/source/lib/res/graphics/ogl_tex.h 0ad-0.0.26/source/lib/res/graphics/ogl_tex.h --- 0ad-0.0.25b/source/lib/res/graphics/ogl_tex.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/graphics/ogl_tex.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,497 +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. - */ - -/* - * wrapper for all OpenGL texturing calls. provides caching, hotloading - * and lifetime management. - */ - -/* - -[KEEP IN SYNC WITH WIKI!] - -Introduction ------------- - -This module simplifies use of textures in OpenGL. An easy-to-use -load/upload/bind/free API is provided, which completely replaces -direct access to OpenGL's texturing calls. - -It basically wraps tex.cpp's texture info in a resource object -(see h_mgr.h) that maintains associated GL state and provides for -reference counting, caching, hotloading and safe access. -Additionally, the upload step provides for trading quality vs. speed -and works around older hardware/drivers. - - -Texture Parameters ------------------- - -OpenGL textures are conditioned on several parameters including -filter and wrap mode. These are typically set once when the texture is -created, but must survive reloads (1). To that end, all state (2) is -set via ogl_tex_set_* (instead of direct glTexParameter calls) and -re-applied after a reload. - -(1) the purpose of hotloading is to permit artists to see their changes - in-game without having to restart the map. reloads where the - texture looks different due to changed state are useless. - -(2) currently only filter and wrap mode. no other glTexParameter - settings are used ATM; if that changes, add to OglTexState. - - -Uploading to OpenGL -------------------- - -.. deserves some clarification. This entails calling glTexImage2D -(or its variants for mipmaps/compressed textures) and transfers -texture parameters and data from system memory to OpenGL -(and thereby usually video memory). - -In so doing, choices are made as to the texture's internal representation -(how it is stored in vmem) - in particular, the bit depth. -This can trade performance (more/less data to copy) for quality -(fidelity to original). - -We provide a mechanism that applies defaults to all uploads; -this allows a global "quality" setting that can boost performance on -older graphics cards without requiring anything else to be changed. -Textures with specific quality needs can override this via -ogl_tex_set_* or ogl_tex_upload parameters. - -Finally, provision is made for coping with hardware/drivers lacking support -for S3TC decompression or mipmap generation: that can be done in software, -if necessary. This avoids the need for alternate asset formats and -lowers hardware requirements. While such cards probably won't run -the app very well (due to their age and lack of other capabilities), -this does make possible developing/testing on older machines/laptops. - - -Caching and Texture Instances ------------------------------ - -Caching is both an advantage and drawback. When opening the same -texture twice without previously freeing it, a reference to the -first instance is returned. Therefore, be advised that concurrent use of the -same texture but with differing parameters (e.g. upload quality) followed by -a reload of the first instance will result in using the wrong parameters. -For background and rationale why this is acceptable, see struct OglTex. - - -Example Usage -------------- - -Note: to keep the examples simple, we leave out error handling by -ignoring all return values. Each function will still raise a warning -(assert) if it fails and passing e.g. invalid Handles will only cause -the next function to fail, but real apps should check and report errors. - -1) Basic usage: load texture from file. - - Handle hTexture = ogl_tex_load("filename.dds"); - (void)ogl_tex_upload(hTexture); - - [when rendering:] - (void)ogl_tex_bind(hTexture); - [.. do something with OpenGL that uses the currently bound texture] - - [at exit:] - * (done automatically, but this avoids it showing up as a leak) - (void)ogl_tex_free(hTexture); - - -2) Advanced usage: wrap existing texture data, override filter, - specify internal_format and use multitexturing. - - Tex t; - const size_t flags = 0; * image is plain RGB, default orientation - void* data = [pre-existing image] - (void)tex_wrap(w, h, 24, flags, data, &t); - Handle hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)"); - (void)ogl_tex_set_filter(hCompositeAlphaMap, GL_LINEAR); - (void)ogl_tex_upload(hCompositeAlphaMap, 0, 0, GL_INTENSITY); - * (your responsibility! tex_wrap attaches a reference but it is - * removed by ogl_tex_upload.) - free(data); - - [when rendering:] - (void)ogl_tex_bind(hCompositeAlphaMap, 1); - [.. do something with OpenGL that uses the currently bound texture] - - [at exit:] - * (done automatically, but this avoids it showing up as a leak) - (void)ogl_tex_free(hCompositeAlphaMap); - -*/ - -#ifndef INCLUDED_OGL_TEX -#define INCLUDED_OGL_TEX - -#include "lib/res/handle.h" -#include "lib/file/vfs/vfs.h" -#include "lib/ogl.h" -#include "lib/tex/tex.h" - - -// -// quality mechanism -// - -/** -* Quality flags for texture uploads. -* Specify any of them to override certain aspects of the default. -*/ -enum OglTexQualityFlags -{ - /** - * emphatically require full quality for this texture. - * (q_flags are invalid if this is set together with any other bit) - * rationale: the value 0 is used to indicate "use default flags" in - * ogl_tex_upload and ogl_tex_set_defaults, so this is the only - * way we can say "disregard default and do not reduce anything". - */ - OGL_TEX_FULL_QUALITY = 0x20, - - /** - * store the texture at half the normal bit depth - * (4 bits per pixel component, as opposed to 8). - * this increases performance on older graphics cards due to - * decreased size in vmem. it has no effect on - * compressed textures because they have a fixed internal format. - */ - OGL_TEX_HALF_BPP = 0x10, - - /** - * store the texture at half its original resolution. - * this increases performance on older graphics cards due to - * decreased size in vmem. - * this is useful for also reducing quality of compressed textures, - * which are not affected by OGL_TEX_HALF_BPP. - * currently only implemented for images that contain mipmaps - * (otherwise, we'd have to resample, which is slow). - * note: scaling down to 1/4, 1/8, .. is easily possible without - * extra work, so we leave some bits free for that. - */ - OGL_TEX_HALF_RES = 0x01 -}; - -/** -* Change default settings - these affect performance vs. quality. -* May be overridden for individual textures via parameter to -* ogl_tex_upload or ogl_tex_set_filter, respectively. -* -* @param q_flags quality flags. Pass 0 to keep the current setting -* (initially OGL_TEX_FULL_QUALITY), or any combination of -* OglTexQualityFlags. -* @param filter mag/minification filter. Pass 0 to keep the current setting -* (initially GL_LINEAR), or any valid OpenGL minification filter. -*/ -extern void ogl_tex_set_defaults(int q_flags, GLint filter); - - -// -// open/close -// - -/** -* Load and return a handle to the texture. -* -* @param vfs -* @param pathname -* @param flags h_alloc flags. -* @return Handle to texture or negative Status -* for a list of supported formats, see tex.h's tex_load. -*/ -extern Handle ogl_tex_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags = 0); - -/** -* Find and return an existing texture object, if it has already been -* loaded and is still in memory. -* -* @param pathname fn VFS filename of texture. -* @return Handle to texture or negative Status -*/ -extern Handle ogl_tex_find(const VfsPath& pathname); - -/** -* Make the Tex object ready for use as an OpenGL texture -* and return a handle to it. This will be as if its contents -* had been loaded by ogl_tex_load. -* -* @param t Texture object. -* @param vfs -* @param pathname filename or description of texture. not strictly needed, -* but would allow h_filename to return meaningful info for -* purposes of debugging. -* @param flags -* @return Handle to texture or negative Status -* -* note: because we cannot guarantee that callers will pass distinct -* "filenames", caching is disabled for the created object. this avoids -* mistakenly reusing previous objects that share the same comment. -* -* we need only add bookkeeping information and "wrap" it in -* a resource object (accessed via Handle), hence the name. -*/ -extern Handle ogl_tex_wrap(Tex* t, const PIVFS& vfs, const VfsPath& pathname, size_t flags = 0); - -/** -* Release this texture reference. When the count reaches zero, all of -* its associated resources are freed and further use made impossible. -* -* @param ht Texture handle. -* @return Status -*/ -extern Status ogl_tex_free(Handle& ht); - - -// -// set texture parameters -// - -// these must be called before uploading; this simplifies -// things and avoids calling glTexParameter twice. - -/** -* Override default filter (see {@link #ogl_tex_set_defaults}) for -* this texture. -* -* @param ht Texture handle -* @param filter OpenGL minification and magnification filter -* (rationale: see {@link OglTexState}) -* @return Status -* -* Must be called before uploading (raises a warning if called afterwards). -*/ -extern Status ogl_tex_set_filter(Handle ht, GLint filter); - -/** -* Override default wrap mode (GL_REPEAT) for this texture. -* -* @param ht Texture handle -* @param wrap_s OpenGL wrap mode for S coordinates -* @param wrap_t OpenGL wrap mode for T coordinates -* @return Status -* -* Must be called before uploading (raises a warning if called afterwards). -*/ -extern Status ogl_tex_set_wrap(Handle ht, GLint wrap_s, GLint wrap_t); - -/** -* Override default maximum anisotropic filtering for this texture. -* -* @param ht Texture handle -* @param anisotropy Anisotropy value (must not be less than 1.0; should -* usually be a power of two) -* @return Status -* -* Must be called before uploading (raises a warning if called afterwards). -*/ -extern Status ogl_tex_set_anisotropy(Handle ht, GLfloat anisotropy); - - -// -// upload -// - -enum OglTexOverrides -{ - OGL_TEX_S3TC, - OGL_TEX_AUTO_MIPMAP_GEN, - OGL_TEX_ANISOTROPY -}; - -enum OglTexAllow -{ - OGL_TEX_DISABLE, - OGL_TEX_ENABLE -}; - -/** -* Override the default decision and force/disallow use of the -* given feature. Typically called from ah_override_gl_upload_caps. -* -* @param what Feature to influence. -* @param allow Disable/enable flag. -*/ -extern void ogl_tex_override(OglTexOverrides what, OglTexAllow allow); - -/** -* Upload texture to OpenGL. -* -* @param ht Texture handle -* @param fmt_ovr optional override for OpenGL format (e.g. GL_RGB), -* which is decided from bpp / Tex flags -* @param q_flags_ovr optional override for global default -* OglTexQualityFlags -* @param int_fmt_ovr optional override for OpenGL internal format -* (e.g. GL_RGB8), which is decided from fmt / q_flags. -* @return Status. -* -* Side Effects: -* - enables texturing on TMU 0 and binds the texture to it; -* - frees the texel data! see ogl_tex_get_data. -*/ -extern Status ogl_tex_upload(const Handle ht, GLenum fmt_ovr = 0, int q_flags_ovr = 0, GLint int_fmt_ovr = 0); - - -// -// return information about the texture -// - -/** -* Retrieve dimensions and bit depth of the texture. -* -* @param ht Texture handle -* @param w optional; will be filled with width -* @param h optional; will be filled with height -* @param bpp optional; will be filled with bits per pixel -* @return Status -*/ -extern Status ogl_tex_get_size(Handle ht, size_t* w, size_t* h, size_t* bpp); - -/** -* Retrieve pixel format of the texture. -* -* @param ht Texture handle -* @param flags optional; will be filled with TexFlags -* @param fmt optional; will be filled with GL format -* (it is determined during ogl_tex_upload and 0 before then) -* @return Status -*/ -extern Status ogl_tex_get_format(Handle ht, size_t* flags, GLenum* fmt); - -/** -* Retrieve pixel data of the texture. -* -* @param ht Texture handle -* @param p will be filled with pointer to texels. -* @return Status -* -* Note: this memory is freed after a successful ogl_tex_upload for -* this texture. After that, the pointer we retrieve is NULL but -* the function doesn't fail (negative return value) by design. -* If you still need to get at the data, add a reference before -* uploading it or read directly from OpenGL (discouraged). -*/ -extern Status ogl_tex_get_data(Handle ht, u8** p); - -/** -* Retrieve number of bytes uploaded for the texture, including mipmaps. -* size will be 0 if the texture has not been uploaded yet. -* -* @param ht Texture handle -* @param size Will be filled with size in bytes -* @return Status -*/ -extern Status ogl_tex_get_uploaded_size(Handle ht, size_t* size); - -/** - * Retrieve ARGB value of 1x1 mipmap level of the texture, - * i.e. the average color of the whole texture. - * - * @param ht Texture handle - * @param p will be filled with ARGB value (or 0 if texture does not have mipmaps) - * @return Status - * - * Must be called before uploading (raises a warning if called afterwards). - */ -extern Status ogl_tex_get_average_color(Handle ht, u32* p); - - -// -// misc -// - -/** -* Bind texture to the specified unit in preparation for using it in -* rendering. -* -* @param ht Texture handle. If 0, texturing is disabled on this unit. -* @param unit Texture Mapping Unit number, typically 0 for the first. -* @return Status -* -* Side Effects: -* - changes the active texture unit; -* - (if successful) texturing was enabled/disabled on that unit. -* -* Notes: -* - assumes multitexturing is available. -* - not necessary before calling ogl_tex_upload! -* - on error, the unit's texture state is unchanged; see implementation. -*/ -extern Status ogl_tex_bind(Handle ht, size_t unit = 0); - -/** -* Return the GL handle of the loaded texture in *id, or 0 on failure. -*/ -extern Status ogl_tex_get_texture_id(Handle ht, GLuint* id); - -/** -* (partially) Transform pixel format of the texture. -* -* @param ht Texture handle. -* @param flags the TexFlags that are to be @em changed. -* @return Status -* @see tex_transform -* -* Must be called before uploading (raises a warning if called afterwards). -*/ -extern Status ogl_tex_transform(Handle ht, size_t flags); - -/** -* Transform pixel format of the texture. -* -* @param ht Texture handle. -* @param new_flags Flags desired new TexFlags indicating pixel format. -* @return Status -* @see tex_transform -* -* Must be called before uploading (raises a warning if called afterwards). -* -* Note: this is equivalent to ogl_tex_transform(ht, ht_flags^new_flags). -*/ -extern Status ogl_tex_transform_to(Handle ht, size_t new_flags); - -/** - * Return whether native S3TC texture compression support is available. - * If not, textures will be decompressed automatically, hurting performance. - * - * @return true if native S3TC supported. - * - * ogl_tex_upload must be called at least once before this. - */ -extern bool ogl_tex_has_s3tc(); - -/** - * Return whether anisotropic filtering support is available. - * (The anisotropy might still be disabled or overridden by the driver - * configuration.) - * - * @return true if anisotropic filtering supported. - * - * ogl_tex_upload must be called at least once before this. - */ -extern bool ogl_tex_has_anisotropy(); - -#endif // #ifndef INCLUDED_OGL_TEX diff -Nru 0ad-0.0.25b/source/lib/res/graphics/tests/test_tex.h 0ad-0.0.26/source/lib/res/graphics/tests/test_tex.h --- 0ad-0.0.25b/source/lib/res/graphics/tests/test_tex.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/graphics/tests/test_tex.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* Copyright (C) 2021 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 "lib/self_test.h" - -#include "lib/tex/tex.h" -#include "lib/tex/tex_codec.h" -#include "lib/allocators/shared_ptr.h" - -#include - -class TestTex : public CxxTest::TestSuite -{ -public: - // have mipmaps be created for a test image; check resulting size and pixels - void test_mipmap_create() - { - static u8 imgData[] = { 0x10,0x20,0x30, 0x40,0x60,0x80, 0xA0,0xA4,0xA8, 0xC0,0xC1,0xC2 }; - std::shared_ptr img = DummySharedPtr(imgData); - // assumes 2x2 box filter algorithm with rounding - static const u8 mipmap[] = { 0x6C,0x79,0x87 }; - Tex t; - TS_ASSERT_OK(t.wrap(2, 2, 24, 0, img, 0)); - TS_ASSERT_OK(t.transform_to(TEX_MIPMAPS)); - const u8* const out_img = t.get_data(); - TS_ASSERT_EQUALS((int)t.img_size(), 12+3); - TS_ASSERT_SAME_DATA(out_img, imgData, 12); - TS_ASSERT_SAME_DATA(out_img+12, mipmap, 3); - } - - void test_img_size() - { - std::shared_ptr img(new u8[100*100*4], ArrayDeleter()); - - Tex t; - TS_ASSERT_OK(t.wrap(100, 100, 32, TEX_ALPHA, img, 0)); - TS_ASSERT_EQUALS((int)t.img_size(), 40000); - - // DXT rounds up to 4x4 blocks; DXT1a is 4bpp - Tex t2; - TS_ASSERT_OK(t2.wrap(97, 97, 4, DXT1A, img, 0)); - TS_ASSERT_EQUALS((int)t2.img_size(), 5000); - } - - void test_s3tc_decode() - { - const size_t w = 4, h = 4, bpp = 4; - const size_t size = w*h/2; - std::shared_ptr img(new u8[size], ArrayDeleter()); - memcpy(img.get(), "\xFF\xFF\x00\x00\x00\xAA\xFF\x55", 8); // gradient from white to black - const u8 expected[] = - "\xFF\xFF\xFF" "\xFF\xFF\xFF" "\xFF\xFF\xFF" "\xFF\xFF\xFF" - "\xAA\xAA\xAA" "\xAA\xAA\xAA" "\xAA\xAA\xAA" "\xAA\xAA\xAA" - "\x55\x55\x55" "\x55\x55\x55" "\x55\x55\x55" "\x55\x55\x55" - "\x00\x00\x00" "\x00\x00\x00" "\x00\x00\x00" "\x00\x00\x00"; - - const size_t flags = TEX_DXT&1; - - // wrap in Tex - Tex t; - TS_ASSERT_OK(t.wrap(w, h, bpp, flags, img, 0)); - - // decompress S3TC - TS_ASSERT_OK(t.transform_to(0)); - - // compare img - TS_ASSERT_SAME_DATA(t.get_data(), expected, 48); - } -}; diff -Nru 0ad-0.0.25b/source/lib/res/handle.h 0ad-0.0.26/source/lib/res/handle.h --- 0ad-0.0.25b/source/lib/res/handle.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/handle.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +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. - */ - -/* - * forward declaration of Handle (reduces dependencies) - */ - -#ifndef INCLUDED_HANDLE -#define INCLUDED_HANDLE - -/** - * `handle' representing a reference to a resource (sound, texture, etc.) - * - * 0 is the (silently ignored) invalid handle value; < 0 is an error code. - * - * this is 64 bits because we want tags to remain unique. (tags are a - * counter that disambiguate several subsequent uses of the same - * resource array slot). 32-bit handles aren't enough because the index - * field requires at least 12 bits, thus leaving only about 512K possible - * tag values. - **/ -typedef i64 Handle; - -#endif // #ifndef INCLUDED_HANDLE diff -Nru 0ad-0.0.25b/source/lib/res/h_mgr.cpp 0ad-0.0.26/source/lib/res/h_mgr.cpp --- 0ad-0.0.25b/source/lib/res/h_mgr.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/h_mgr.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,789 +0,0 @@ -/* Copyright (C) 2019 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. - */ - -/* - * handle manager for resources. - */ - -#include "precompiled.h" -#include "h_mgr.h" - -#include - -#include // CHAR_BIT -#include -#include -#include // std::bad_alloc - -#include "lib/fnv_hash.h" -#include "lib/allocators/overrun_protector.h" -#include "lib/allocators/pool.h" -#include "lib/module_init.h" - -#include - -namespace ERR { -static const Status H_IDX_INVALID = -120000; // totally invalid -static const Status H_IDX_UNUSED = -120001; // beyond current cap -static const Status H_TAG_MISMATCH = -120003; -static const Status H_TYPE_MISMATCH = -120004; -static const Status H_ALREADY_FREED = -120005; -} -static const StatusDefinition hStatusDefinitions[] = { - { ERR::H_IDX_INVALID, L"Handle index completely out of bounds" }, - { ERR::H_IDX_UNUSED, L"Handle index exceeds high-water mark" }, - { ERR::H_TAG_MISMATCH, L"Handle tag mismatch (stale reference?)" }, - { ERR::H_TYPE_MISMATCH, L"Handle type mismatch" }, - { ERR::H_ALREADY_FREED, L"Handle already freed" } -}; -STATUS_ADD_DEFINITIONS(hStatusDefinitions); - - - -// rationale -// -// why fixed size control blocks, instead of just allocating dynamically? -// it is expected that resources be created and freed often. this way is -// much nicer to the memory manager. defining control blocks larger than -// the allotted space is caught by h_alloc (made possible by the vtbl builder -// storing control block size). it is also efficient to have all CBs in an -// more or less contiguous array (see below). -// -// why a manager, instead of a simple pool allocator? -// we need a central list of resources for freeing at exit, checking if a -// resource has already been loaded (for caching), and when reloading. -// may as well keep them in an array, rather than add a list and index. - - - -// -// handle -// - -// 0 = invalid handle value -// < 0 is an error code (we assume < 0 <==> MSB is set - -// true for 1s and 2s complement and sign-magnitude systems) - -// fields: -// (shift value = # bits between LSB and field LSB. -// may be larger than the field type - only shift Handle vars!) - -// - index (0-based) of control block in our array. -// (field width determines maximum currently open handles) -#define IDX_BITS 16 -static const u64 IDX_MASK = (1l << IDX_BITS) - 1; - -// - tag (1-based) ensures the handle references a certain resource instance. -// (field width determines maximum unambiguous resource allocs) -using Tag = i64; -#define TAG_BITS 48 - -// make sure both fields fit within a Handle variable -cassert(IDX_BITS + TAG_BITS <= sizeof(Handle)*CHAR_BIT); - - -// return the handle's index field (always non-negative). -// no error checking! -static inline size_t h_idx(const Handle h) -{ - return (size_t)(h & IDX_MASK) - 1; -} - -// build a handle from index and tag. -// can't fail. -static inline Handle handle(size_t idx, u64 tag) -{ - const size_t idxPlusOne = idx+1; - ENSURE(idxPlusOne <= IDX_MASK); - ENSURE((tag & IDX_MASK) == 0); - Handle h = tag | idxPlusOne; - ENSURE(h > 0); - return h; -} - - -// -// internal per-resource-instance data -// - -// chosen so that all current resource structs are covered. -static const size_t HDATA_USER_SIZE = 104; - - -struct HDATA -{ - // we only need the tag, because it is trivial to compute - // &HDATA from idx and vice versa. storing the entire handle - // avoids needing to extract the tag field. - Handle h; // NB: will be overwritten by pool_free - - uintptr_t key; - - intptr_t refs; - - // smaller bit fields combined into 1 - // .. if set, do not actually release the resource (i.e. call dtor) - // when the handle is h_free-d, regardless of the refcount. - // set by h_alloc; reset on exit and by housekeeping. - u32 keep_open : 1; - // .. HACK: prevent adding to h_find lookup index if flags & RES_UNIQUE - // (because those handles might have several instances open, - // which the index can't currently handle) - u32 unique : 1; - u32 disallow_reload : 1; - - H_Type type; - - // for statistics - size_t num_derefs; - - // storing PIVFS here is not a good idea since this often isn't - // `freed' due to caching (and there is no dtor), so - // the VFS reference count would never reach zero. - VfsPath pathname; - - u8 user[HDATA_USER_SIZE]; -}; - - -// max data array entries. compared to last_in_use => signed. -static const ssize_t hdata_cap = (1ul << IDX_BITS)/4; - -// pool of fixed-size elements allows O(1) alloc and free; -// there is a simple mapping between HDATA address and index. -static Pool hpool; - - -// error checking strategy: -// all handles passed in go through h_data(Handle, Type) - - -// get a (possibly new) array entry. -// -// fails if idx is out of bounds. -static Status h_data_from_idx(ssize_t idx, HDATA*& hd) -{ - // don't check if idx is beyond the current high-water mark, because - // we might be allocating a new entry. subsequent tag checks protect - // against using unallocated entries. - if(size_t(idx) >= size_t(hdata_cap)) // also detects negative idx - WARN_RETURN(ERR::H_IDX_INVALID); - - hd = (HDATA*)(hpool.da.base + idx*hpool.el_size); - hd->num_derefs++; - return INFO::OK; -} - -static ssize_t h_idx_from_data(HDATA* hd) -{ - if(!pool_contains(&hpool, hd)) - WARN_RETURN(ERR::INVALID_POINTER); - return (uintptr_t(hd) - uintptr_t(hpool.da.base))/hpool.el_size; -} - - -// get HDATA for the given handle. -// only uses (and checks) the index field. -// used by h_force_close (which must work regardless of tag). -static inline Status h_data_no_tag(const Handle h, HDATA*& hd) -{ - ssize_t idx = (ssize_t)h_idx(h); - RETURN_STATUS_IF_ERR(h_data_from_idx(idx, hd)); - // need to verify it's in range - h_data_from_idx can only verify that - // it's < maximum allowable index. - if(uintptr_t(hd) > uintptr_t(hpool.da.base)+hpool.da.pos) - WARN_RETURN(ERR::H_IDX_UNUSED); - return INFO::OK; -} - - -static bool ignoreDoubleFree = false; - -// get HDATA for the given handle. -// also verifies the tag field. -// used by functions callable for any handle type, e.g. h_filename. -static inline Status h_data_tag(Handle h, HDATA*& hd) -{ - RETURN_STATUS_IF_ERR(h_data_no_tag(h, hd)); - - if(hd->key == 0) // HDATA was wiped out and hd->h overwritten by pool_free - { - if(ignoreDoubleFree) - return ERR::H_ALREADY_FREED; // NOWARN (see ignoreDoubleFree) - else - WARN_RETURN(ERR::H_ALREADY_FREED); - } - - if(h != hd->h) - WARN_RETURN(ERR::H_TAG_MISMATCH); - - return INFO::OK; -} - - -// get HDATA for the given handle. -// also verifies the type. -// used by most functions accessing handle data. -static Status h_data_tag_type(const Handle h, const H_Type type, HDATA*& hd) -{ - RETURN_STATUS_IF_ERR(h_data_tag(h, hd)); - - // h_alloc makes sure type isn't 0, so no need to check that here. - if(hd->type != type) - { - debug_printf("h_mgr: expected type %s, got %s\n", utf8_from_wstring(hd->type->name).c_str(), utf8_from_wstring(type->name).c_str()); - WARN_RETURN(ERR::H_TYPE_MISMATCH); - } - - return INFO::OK; -} - - -//----------------------------------------------------------------------------- -// lookup data structure -//----------------------------------------------------------------------------- - -// speed up h_find (called every h_alloc) -// multimap, because we want to add handles of differing type but same key -// (e.g. a VFile and Tex object for the same underlying filename hash key) -// -// store index because it's smaller and Handle can easily be reconstructed -// -// -// note: there may be several RES_UNIQUE handles of the same type and key -// (e.g. sound files - several instances of a sound definition file). -// that wasn't foreseen here, so we'll just refrain from adding to the index. -// that means they won't be found via h_find - no biggie. - -using Key2Idx = std::unordered_multimap; -using It = Key2Idx::iterator; -static OverrunProtector key2idx_wrapper; - -enum KeyRemoveFlag { KEY_NOREMOVE, KEY_REMOVE }; - -static Handle key_find(uintptr_t key, H_Type type, KeyRemoveFlag remove_option = KEY_NOREMOVE) -{ - Key2Idx* key2idx = key2idx_wrapper.get(); - if(!key2idx) - WARN_RETURN(ERR::NO_MEM); - - // initial return value: "not found at all, or it's of the - // wrong type". the latter happens when called by h_alloc to - // check if e.g. a Tex object already exists; at that time, - // only the corresponding VFile exists. - Handle ret = -1; - - std::pair range = key2idx->equal_range(key); - for(It it = range.first; it != range.second; ++it) - { - ssize_t idx = it->second; - HDATA* hd; - if(h_data_from_idx(idx, hd) != INFO::OK) - continue; - if(hd->type != type || hd->key != key) - continue; - - // found a match - if(remove_option == KEY_REMOVE) - key2idx->erase(it); - ret = hd->h; - break; - } - - key2idx_wrapper.lock(); - return ret; -} - - -static void key_add(uintptr_t key, Handle h) -{ - Key2Idx* key2idx = key2idx_wrapper.get(); - if(!key2idx) - return; - - const ssize_t idx = h_idx(h); - // note: MSDN documentation of stdext::hash_multimap is incorrect; - // there is no overload of insert() that returns pair. - (void)key2idx->insert(std::make_pair(key, idx)); - - key2idx_wrapper.lock(); -} - - -static void key_remove(uintptr_t key, H_Type type) -{ - Handle ret = key_find(key, type, KEY_REMOVE); - ENSURE(ret > 0); -} - - -//---------------------------------------------------------------------------- -// h_alloc -//---------------------------------------------------------------------------- - -static void warn_if_invalid(HDATA* hd) -{ -#ifndef NDEBUG - H_VTbl* vtbl = hd->type; - - // validate HDATA - // currently nothing to do; is checked by h_alloc and - // the others have no invariants we could check. - - // have the resource validate its user_data - Status err = vtbl->validate(hd->user); - ENSURE(err == INFO::OK); - - // make sure empty space in control block isn't touched - // .. but only if we're not storing a filename there - const u8* start = hd->user + vtbl->user_size; - const u8* end = hd->user + HDATA_USER_SIZE; - for(const u8* p = start; p < end; p++) - ENSURE(*p == 0); // else: handle user data was overrun! -#else - UNUSED2(hd); -#endif -} - - -static Status type_validate(H_Type type) -{ - if(!type) - WARN_RETURN(ERR::INVALID_PARAM); - if(type->user_size > HDATA_USER_SIZE) - WARN_RETURN(ERR::LIMIT); - if(type->name == 0) - WARN_RETURN(ERR::INVALID_PARAM); - - return INFO::OK; -} - - -static Tag gen_tag() -{ - static Tag tag; - tag += (1ull << IDX_BITS); - // it's not easy to detect overflow, because compilers - // are allowed to assume it'll never happen. however, - // pow(2, 64-IDX_BITS) is "enough" anyway. - return tag; -} - - -static Handle reuse_existing_handle(uintptr_t key, H_Type type, size_t flags) -{ - if(flags & RES_NO_CACHE) - return 0; - - // object of specified key and type doesn't exist yet - Handle h = h_find(type, key); - if(h <= 0) - return 0; - - HDATA* hd; - RETURN_STATUS_IF_ERR(h_data_tag_type(h, type, hd)); // h_find means this won't fail - - hd->refs += 1; - - // we are reactivating a closed but cached handle. - // need to generate a new tag so that copies of the - // previous handle can no longer access the resource. - // (we don't need to reset the tag in h_free, because - // use before this fails due to refs > 0 check in h_user_data). - if(hd->refs == 1) - { - const Tag tag = gen_tag(); - h = handle(h_idx(h), tag); // can't fail - hd->h = h; - } - - return h; -} - - -static Status call_init_and_reload(Handle h, H_Type type, HDATA* hd, const PIVFS& vfs, const VfsPath& pathname, va_list* init_args) -{ - Status err = INFO::OK; - H_VTbl* vtbl = type; // exact same thing but for clarity - - // init - if(vtbl->init) - vtbl->init(hd->user, *init_args); - - // reload - if(vtbl->reload) - { - // catch exception to simplify reload funcs - let them use new() - try - { - err = vtbl->reload(hd->user, vfs, pathname, h); - if(err == INFO::OK) - warn_if_invalid(hd); - } - catch(std::bad_alloc&) - { - err = ERR::NO_MEM; - } - } - - return err; -} - - -static Handle alloc_new_handle(H_Type type, const PIVFS& vfs, const VfsPath& pathname, uintptr_t key, size_t flags, va_list* init_args) -{ - HDATA* hd = (HDATA*)pool_alloc(&hpool, 0); - if(!hd) - WARN_RETURN(ERR::NO_MEM); - new(&hd->pathname) VfsPath; - - ssize_t idx = h_idx_from_data(hd); - RETURN_STATUS_IF_ERR(idx); - - // (don't want to do this before the add-reference exit, - // so as not to waste tags for often allocated handles.) - const Tag tag = gen_tag(); - Handle h = handle(idx, tag); // can't fail. - - hd->h = h; - hd->key = key; - hd->type = type; - hd->refs = 1; - if(!(flags & RES_NO_CACHE)) - hd->keep_open = 1; - if(flags & RES_DISALLOW_RELOAD) - hd->disallow_reload = 1; - hd->unique = (flags & RES_UNIQUE) != 0; - hd->pathname = pathname; - - if(key && !hd->unique) - key_add(key, h); - - Status err = call_init_and_reload(h, type, hd, vfs, pathname, init_args); - if(err < 0) - goto fail; - - return h; - -fail: - // reload failed; free the handle - hd->keep_open = 0; // disallow caching (since contents are invalid) - (void)h_free(h, type); // (h_free already does WARN_IF_ERR) - - // note: since some uses will always fail (e.g. loading sounds if - // g_Quickstart), do not complain here. - return (Handle)err; -} - - -static std::recursive_mutex h_mutex; - -// any further params are passed to type's init routine -Handle h_alloc(H_Type type, const PIVFS& vfs, const VfsPath& pathname, size_t flags, ...) -{ - std::lock_guard lock(h_mutex); - - RETURN_STATUS_IF_ERR(type_validate(type)); - - const uintptr_t key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); - - // see if we can reuse an existing handle - Handle h = reuse_existing_handle(key, type, flags); - RETURN_STATUS_IF_ERR(h); - // .. successfully reused the handle; refcount increased - if(h > 0) - return h; - // .. need to allocate a new one: - va_list args; - va_start(args, flags); - h = alloc_new_handle(type, vfs, pathname, key, flags, &args); - va_end(args); - return h; // alloc_new_handle already does WARN_RETURN_STATUS_IF_ERR -} - - -//----------------------------------------------------------------------------- - -static void h_free_hd(HDATA* hd) -{ - if(hd->refs > 0) - hd->refs--; - - // still references open or caching requests it stays - do not release. - if(hd->refs > 0 || hd->keep_open) - return; - - // actually release the resource (call dtor, free control block). - - // h_alloc makes sure type != 0; if we get here, it still is - H_VTbl* vtbl = hd->type; - - // call its destructor - // note: H_TYPE_DEFINE currently always defines a dtor, but play it safe - if(vtbl->dtor) - vtbl->dtor(hd->user); - - if(hd->key && !hd->unique) - key_remove(hd->key, hd->type); - -#ifndef NDEBUG - // to_string is slow for some handles, so avoid calling it if unnecessary - if(debug_filter_allows("H_MGR|")) - { - wchar_t buf[H_STRING_LEN]; - if(vtbl->to_string(hd->user, buf) < 0) - wcscpy_s(buf, ARRAY_SIZE(buf), L"(error)"); - debug_printf("H_MGR| free %s %s accesses=%lu %s\n", utf8_from_wstring(hd->type->name).c_str(), hd->pathname.string8().c_str(), (unsigned long)hd->num_derefs, utf8_from_wstring(buf).c_str()); - } -#endif - - hd->pathname.~VfsPath(); // FIXME: ugly hack, but necessary to reclaim memory - memset(hd, 0, sizeof(*hd)); - pool_free(&hpool, hd); -} - - -Status h_free(Handle& h, H_Type type) -{ - std::lock_guard lock(h_mutex); - - // 0-initialized or an error code; don't complain because this - // happens often and is harmless. - if(h <= 0) - return INFO::OK; - - // wipe out the handle to prevent reuse but keep a copy for below. - const Handle h_copy = h; - h = 0; - - HDATA* hd; - RETURN_STATUS_IF_ERR(h_data_tag_type(h_copy, type, hd)); - - h_free_hd(hd); - return INFO::OK; -} - - -//---------------------------------------------------------------------------- -// remaining API - -void* h_user_data(const Handle h, const H_Type type) -{ - HDATA* hd; - if(h_data_tag_type(h, type, hd) != INFO::OK) - return 0; - - if(!hd->refs) - { - // note: resetting the tag is not enough (user might pass in its value) - DEBUG_WARN_ERR(ERR::LOGIC); // no references to resource (it's cached, but someone is accessing it directly) - return 0; - } - - warn_if_invalid(hd); - return hd->user; -} - - -VfsPath h_filename(const Handle h) -{ - // don't require type check: should be usable for any handle, - // even if the caller doesn't know its type. - HDATA* hd; - if(h_data_tag(h, hd) != INFO::OK) - return VfsPath(); - return hd->pathname; -} - - -// TODO: what if iterating through all handles is too slow? -Status h_reload(const PIVFS& vfs, const VfsPath& pathname) -{ - std::lock_guard lock(h_mutex); - - const u32 key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); - - // destroy (note: not free!) all handles backed by this file. - // do this before reloading any of them, because we don't specify reload - // order (the parent resource may be reloaded first, and load the child, - // whose original data would leak). - for(HDATA* hd = (HDATA*)hpool.da.base; hd < (HDATA*)(hpool.da.base + hpool.da.pos); hd = (HDATA*)(uintptr_t(hd)+hpool.el_size)) - { - if(hd->key == 0 || hd->key != key || hd->disallow_reload) - continue; - hd->type->dtor(hd->user); - } - - Status ret = INFO::OK; - - // now reload all affected handles - size_t i = 0; - for(HDATA* hd = (HDATA*)hpool.da.base; hd < (HDATA*)(hpool.da.base + hpool.da.pos); hd = (HDATA*)(uintptr_t(hd)+hpool.el_size), i++) - { - if(hd->key == 0 || hd->key != key || hd->disallow_reload) - continue; - - Status err = hd->type->reload(hd->user, vfs, hd->pathname, hd->h); - // don't stop if an error is encountered - try to reload them all. - if(err < 0) - { - h_free(hd->h, hd->type); - if(ret == 0) // don't overwrite first error - ret = err; - } - else - warn_if_invalid(hd); - } - - return ret; -} - - -Handle h_find(H_Type type, uintptr_t key) -{ - std::lock_guard lock(h_mutex); - return key_find(key, type); -} - - - -// force the resource to be freed immediately, even if cached. -// tag is not checked - this allows the first Handle returned -// (whose tag will change after being 'freed', but remaining in memory) -// to later close the object. -// this is used when reinitializing the sound engine - -// at that point, all (cached) OpenAL resources must be freed. -Status h_force_free(Handle h, H_Type type) -{ - std::lock_guard lock(h_mutex); - - // require valid index; ignore tag; type checked below. - HDATA* hd; - RETURN_STATUS_IF_ERR(h_data_no_tag(h, hd)); - if(hd->type != type) - WARN_RETURN(ERR::H_TYPE_MISMATCH); - hd->keep_open = 0; - hd->refs = 0; - h_free_hd(hd); - return INFO::OK; -} - - -// increment Handle 's reference count. -// only meant to be used for objects that free a Handle in their dtor, -// so that they are copy-equivalent and can be stored in a STL container. -// do not use this to implement refcounting on top of the Handle scheme, -// e.g. loading a Handle once and then passing it around. instead, have each -// user load the resource; refcounting is done under the hood. -void h_add_ref(Handle h) -{ - HDATA* hd; - if(h_data_tag(h, hd) != INFO::OK) - return; - - ENSURE(hd->refs); // if there are no refs, how did the caller manage to keep a Handle?! - hd->refs++; -} - - -// retrieve the internal reference count or a negative error code. -// background: since h_alloc has no way of indicating whether it -// allocated a new handle or reused an existing one, counting references -// within resource control blocks is impossible. since that is sometimes -// necessary (always wrapping objects in Handles is excessive), we -// provide access to the internal reference count. -intptr_t h_get_refcnt(Handle h) -{ - HDATA* hd; - RETURN_STATUS_IF_ERR(h_data_tag(h, hd)); - - ENSURE(hd->refs); // if there are no refs, how did the caller manage to keep a Handle?! - return hd->refs; -} - - -static ModuleInitState initState; - -static Status Init() -{ - RETURN_STATUS_IF_ERR(pool_create(&hpool, hdata_cap*sizeof(HDATA), sizeof(HDATA))); - return INFO::OK; -} - -static void Shutdown() -{ - debug_printf("H_MGR| shutdown. any handle frees after this are leaks!\n"); - // objects that store handles to other objects are destroyed before their - // children, so the subsequent forced destruction of the child here will - // raise a double-free warning unless we ignore it. (#860, #915, #920) - ignoreDoubleFree = true; - - std::lock_guard lock(h_mutex); - - // forcibly close all open handles - for(HDATA* hd = (HDATA*)hpool.da.base; hd < (HDATA*)(hpool.da.base + hpool.da.pos); hd = (HDATA*)(uintptr_t(hd)+hpool.el_size)) - { - // it's already been freed; don't free again so that this - // doesn't look like an error. - if(hd->key == 0) - continue; - - // disable caching; we need to release the resource now. - hd->keep_open = 0; - hd->refs = 0; - - h_free_hd(hd); - } - - pool_destroy(&hpool); -} - -void h_mgr_free_type(const H_Type type) -{ - ignoreDoubleFree = true; - - std::lock_guard lock(h_mutex); - - // forcibly close all open handles of the specified type - for(HDATA* hd = (HDATA*)hpool.da.base; hd < (HDATA*)(hpool.da.base + hpool.da.pos); hd = (HDATA*)(uintptr_t(hd)+hpool.el_size)) - { - // free if not previously freed and only free the proper type - if (hd->key == 0 || hd->type != type) - continue; - - // disable caching; we need to release the resource now. - hd->keep_open = 0; - hd->refs = 0; - - h_free_hd(hd); - } -} - -void h_mgr_init() -{ - ModuleInit(&initState, Init); -} - -void h_mgr_shutdown() -{ - ModuleShutdown(&initState, Shutdown); -} diff -Nru 0ad-0.0.25b/source/lib/res/h_mgr.h 0ad-0.0.26/source/lib/res/h_mgr.h --- 0ad-0.0.25b/source/lib/res/h_mgr.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/res/h_mgr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,432 +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. - */ - -/* - * handle manager for resources. - */ - -/* - -[KEEP IN SYNC WITH WIKI] - -introduction ------------- - -a resource is an instance of a specific type of game data (e.g. texture), -described by a control block (example fields: format, pointer to tex data). - -this module allocates storage for the control blocks, which are accessed -via handle. it also provides support for transparently reloading resources -from disk (allows in-game editing of data), and caches resource data. -finally, it frees all resources at exit, preventing leaks. - - -handles -------- - -handles are an indirection layer between client code and resources -(represented by their control blocks, which contains/points to its data). -they allow an important check not possible with a direct pointer: -guaranteeing the handle references a given resource /instance/. - -problem: code C1 allocates a resource, and receives a pointer p to its -control block. C1 passes p on to C2, and later frees it. -now other code allocates a resource, and happens to reuse the free slot -pointed to by p (also possible if simply allocating from the heap). -when C2 accesses p, the pointer is valid, but we cannot tell that -it is referring to a resource that had already been freed. big trouble. - -solution: each allocation receives a unique tag (a global counter that -is large enough to never overflow). Handles include this tag, as well -as a reference (array index) to the control block, which isn't directly -accessible. when dereferencing the handle, we check if the handle's tag -matches the copy stored in the control block. this protects against stale -handle reuse, double-free, and accidentally referencing other resources. - -type: each handle has an associated type. these must be checked to prevent -using textures as sounds, for example. with the manual vtbl scheme, -this type is actually a pointer to the resource object's vtbl, and is -set up via H_TYPE_DEFINE. this means that types are private to the module -that declared the handle; knowledge of the type ensures the caller -actually declared, and owns the resource. - - -guide to defining and using resources -------------------------------------- - -1) choose a name for the resource, used to represent all resources -of this type. we will call ours "Res1"; all below occurrences of this -must be replaced with the actual name (exact spelling). -why? the vtbl builder defines its functions as e.g. Res1_reload; -your actual definition must match. - -2) declare its control block: -struct Res1 -{ - void* data; // data loaded from file - size_t flags; // set when resource is created -}; - -Note that all control blocks are stored in fixed-size slots -(HDATA_USER_SIZE bytes), so squeezing the size of your data doesn't -help unless yours is the largest. - -3) build its vtbl: -H_TYPE_DEFINE(Res1); - -this defines the symbol H_Res1, which is used whenever the handle -manager needs its type. it is only accessible to this module -(file scope). note that it is actually a pointer to the vtbl. -this must come before uses of H_Res1, and after the CB definition; -there are no restrictions WRT functions, because the macro -forward-declares what it needs. - -4) implement all 'virtual' functions from the resource interface. -note that inheritance isn't really possible with this approach - -all functions must be defined, even if not needed. - --- - -init: -one-time init of the control block. called from h_alloc. -precondition: control block is initialized to 0. - -static void Type_init(Res1* r, va_list args) -{ - r->flags = va_arg(args, int); -} - -if the caller of h_alloc passed additional args, they are available -in args. if init references more args than were passed, big trouble. -however, this is a bug in your code, and cannot be triggered -maliciously. only your code knows the resource type, and it is the -only call site of h_alloc. -there is no provision for indicating failure. if one-time init fails -(rare, but one example might be failure to allocate memory that is -for the lifetime of the resource, instead of in reload), it will -have to set the control block state such that reload will fail. - --- - -reload: -does all initialization of the resource that requires its source file. -called after init; also after dtor every time the file is reloaded. - -static Status Type_reload(Res1* r, const VfsPath& pathname, Handle); -{ - // already loaded; done - if(r->data) - return 0; - - r->data = malloc(100); - if(!r->data) - WARN_RETURN(ERR::NO_MEM); - // (read contents of into r->data) - return 0; -} - -reload must abort if the control block data indicates the resource -has already been loaded! example: if texture's reload is called first, -it loads itself from file (triggering file.reload); afterwards, -file.reload will be called again. we can't avoid this, because the -handle manager doesn't know anything about dependencies -(here, texture -> file). -return value: 0 if successful (includes 'already loaded'), -negative error code otherwise. if this fails, the resource is freed -(=> dtor is called!). - -note that any subsequent changes to the resource state must be -stored in the control block and 'replayed' when reloading. -example: when uploading a texture, store the upload parameters -(filter, internal format); when reloading, upload again accordingly. - --- - -dtor: -frees all data allocated by init and reload. called after reload has -indicated failure, before reloading a resource, after h_free, -or at exit (if the resource is still extant). -except when reloading, the control block will be zeroed afterwards. - -static void Type_dtor(Res1* r); -{ - free(r->data); -} - -again no provision for reporting errors - there's no one to act on it -if called at exit. you can ENSURE or log the error, though. - -be careful to correctly handle the different cases in which this routine -can be called! some flags should persist across reloads (e.g. choices made -during resource init time that must remain valid), while everything else -*should be zeroed manually* (to behave correctly when reloading). -be advised that this interface may change; a "prepare for reload" method -or "compact/free extraneous resources" may be added. - --- - -validate: -makes sure the resource control block is in a valid state. returns 0 if -all is well, or a negative error code. -called automatically when the Handle is dereferenced or freed. - -static Status Type_validate(const Res1* r); -{ - const int permissible_flags = 0x01; - if(debug_IsPointerBogus(r->data)) - WARN_RETURN(ERR::_1); - if(r->flags & ~permissible_flags) - WARN_RETURN(ERR::_2); - return 0; -} - - -5) provide your layer on top of the handle manager: -Handle res1_load(const VfsPath& pathname, int my_flags) -{ - // passes my_flags to init - return h_alloc(H_Res1, pathname, 0, my_flags); -} - -Status res1_free(Handle& h) -{ - // control block is automatically zeroed after this. - return h_free(h, H_Res1); -} - -(this layer allows a res_load interface on top of all the loaders, -and is necessary because your module is the only one that knows H_Res1). - -6) done. the resource will be freed at exit (if not done already). - -here's how to access the control block, given a : -a) - H_DEREF(h, Res1, r); - -creates a variable r of type Res1*, which points to the control block -of the resource referenced by h. returns "invalid handle" -(a negative error code) on failure. -b) - Res1* r = h_user_data(h, H_Res1); - if(!r) - ; // bail - -useful if H_DEREF's error return (of type signed integer) isn't -acceptable. otherwise, prefer a) - this is pretty clunky, and -we could switch H_DEREF to throwing an exception on error. - -*/ - -#ifndef INCLUDED_H_MGR -#define INCLUDED_H_MGR - -// do not include from public header files! -// handle.h declares type Handle, and avoids making -// everything dependent on this (rather often updated) header. - - -#include // type init routines get va_list of args - -#ifndef INCLUDED_HANDLE -#include "handle.h" -#endif - -#include "lib/file/vfs/vfs.h" - -extern void h_mgr_init(); -extern void h_mgr_shutdown(); - - -// handle type (for 'type safety' - can't use a texture handle as a sound) - -// registering extension for each module is bad - some may use many -// (e.g. texture - many formats). -// handle manager shouldn't know about handle types - - -/* -///xxx advantage of manual vtbl: -no boilerplate init, h_alloc calls ctor directly, make sure it fits in the memory slot -vtbl contains sizeof resource data, and name! -but- has to handle variable params, a bit ugly -*/ - -// 'manual vtbl' type id -// handles have a type, to prevent using e.g. texture handles as a sound. -// -// alternatives: -// - enum of all handle types (smaller, have to pass all methods to h_alloc) -// - class (difficult to compare type, handle manager needs to know of all users) -// -// checked in h_alloc: -// - user_size must fit in what the handle manager provides -// - name must not be 0 -// -// init: user data is initially zeroed -// dtor: user data is zeroed afterwards -// reload: if this resource type is opened by another resource's reload, -// our reload routine MUST check if already opened! This is relevant when -// a file is reloaded: if e.g. a sound object opens a file, the handle -// manager calls the reload routines for the 2 handles in unspecified order. -// ensuring the order would require a tag field that can't overflow - -// not really guaranteed with 32-bit handles. it'd also be more work -// to sort the handles by creation time, or account for several layers of -// dependencies. -struct H_VTbl -{ - void (*init)(void* user, va_list); - Status (*reload)(void* user, const PIVFS& vfs, const VfsPath& pathname, Handle); - void (*dtor)(void* user); - Status (*validate)(const void* user); - Status (*to_string)(const void* user, wchar_t* buf); - size_t user_size; - const wchar_t* name; -}; - -typedef H_VTbl* H_Type; - -#define H_TYPE_DEFINE(type)\ - /* forward decls */\ - static void type##_init(type*, va_list);\ - static Status type##_reload(type*, const PIVFS&, const VfsPath&, Handle);\ - static void type##_dtor(type*);\ - static Status type##_validate(const type*);\ - static Status type##_to_string(const type*, wchar_t* buf);\ - static H_VTbl V_##type =\ - {\ - (void (*)(void*, va_list))type##_init,\ - (Status (*)(void*, const PIVFS&, const VfsPath&, Handle))type##_reload,\ - (void (*)(void*))type##_dtor,\ - (Status (*)(const void*))type##_validate,\ - (Status (*)(const void*, wchar_t*))type##_to_string,\ - sizeof(type), /* control block size */\ - WIDEN(#type) /* name */\ - };\ - static H_Type H_##type = &V_##type - - // note: we cast to void* pointers so the functions can be declared to - // take the control block pointers, instead of requiring a cast in each. - // the forward decls ensure the function signatures are correct. - - -// convenience macro for h_user_data: -// casts its return value to the control block type. -// use if H_DEREF's returning a negative error code isn't acceptable. -#define H_USER_DATA(h, type) (type*)h_user_data(h, H_##type) - -// even more convenient wrapper for h_user_data: -// declares a pointer (), assigns it H_USER_DATA, and has -// the user's function return a negative error code on failure. -// -// note: don't use STMT - var decl must be visible to "caller" -#define H_DEREF(h, type, var)\ - /* h already indicates an error - return immediately to pass back*/\ - /* that specific error, rather than only ERR::INVALID_HANDLE*/\ - if(h < 0)\ - WARN_RETURN((Status)h);\ - type* const var = H_USER_DATA(h, type);\ - if(!var)\ - WARN_RETURN(ERR::INVALID_HANDLE); - - -// all functions check the passed tag (part of the handle) and type against -// the internal values. if they differ, an error is returned. - - - - -// h_alloc flags -enum -{ - // alias for RES_TEMP scope. the handle will not be kept open. - RES_NO_CACHE = 0x01, - - // not cached, and will never reuse a previous instance - RES_UNIQUE = RES_NO_CACHE|0x10, - - // object is requesting it never be reloaded (e.g. because it's not - // backed by a file) - RES_DISALLOW_RELOAD = 0x20 -}; - -const size_t H_STRING_LEN = 256; - - - -// allocate a new handle. -// if key is 0, or a (key, type) handle doesn't exist, -// some free entry is used. -// otherwise, a handle to the existing object is returned, -// and HDATA.size != 0. -//// user_size is checked to make sure the user data fits in the handle data space. -// dtor is associated with type and called when the object is freed. -// handle data is initialized to 0; optionally, a pointer to it is returned. -extern Handle h_alloc(H_Type type, const PIVFS& vfs, const VfsPath& pathname, size_t flags = 0, ...); -extern Status h_free(Handle& h, H_Type type); - - -// Forcibly frees all handles of a specified type. -void h_mgr_free_type(const H_Type type); - - -// find and return a handle by key (typically filename hash) -// currently O(log n). -// -// HACK: currently can't find RES_UNIQUE handles, because there -// may be multiple instances of them, breaking the lookup data structure. -extern Handle h_find(H_Type type, uintptr_t key); - -// returns a void* pointer to the control block of the resource , -// or 0 on error (i.e. h is invalid or of the wrong type). -// prefer using H_DEREF or H_USER_DATA. -extern void* h_user_data(Handle h, H_Type type); - -extern VfsPath h_filename(Handle h); - - -extern Status h_reload(const PIVFS& vfs, const VfsPath& pathname); - -// force the resource to be freed immediately, even if cached. -// tag is not checked - this allows the first Handle returned -// (whose tag will change after being 'freed', but remaining in memory) -// to later close the object. -// this is used when reinitializing the sound engine - -// at that point, all (cached) OpenAL resources must be freed. -extern Status h_force_free(Handle h, H_Type type); - -// increment Handle 's reference count. -// only meant to be used for objects that free a Handle in their dtor, -// so that they are copy-equivalent and can be stored in a STL container. -// do not use this to implement refcounting on top of the Handle scheme, -// e.g. loading a Handle once and then passing it around. instead, have each -// user load the resource; refcounting is done under the hood. -extern void h_add_ref(Handle h); - -// retrieve the internal reference count or a negative error code. -// background: since h_alloc has no way of indicating whether it -// allocated a new handle or reused an existing one, counting references -// within resource control blocks is impossible. since that is sometimes -// necessary (always wrapping objects in Handles is excessive), we -// provide access to the internal reference count. -extern intptr_t h_get_refcnt(Handle h); - -#endif // #ifndef INCLUDED_H_MGR diff -Nru 0ad-0.0.25b/source/lib/status.h 0ad-0.0.26/source/lib/status.h --- 0ad-0.0.25b/source/lib/status.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/status.h 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -161,8 +161,6 @@ #ifndef INCLUDED_STATUS #define INCLUDED_STATUS -#include "lib/lib_api.h" - // an integral type allows defining error codes in separate headers, // but is not as type-safe as an enum. use Lint's 'strong type' checking // to catch errors such as Status Func() { return 1; }. @@ -206,7 +204,7 @@ * (this function must be callable as a static initializer; initializing * next avoids the need for a separate dummy variable) **/ -LIB_API StatusDefinitionBucket* StatusAddDefinitions(StatusDefinitionBucket* bucket); +StatusDefinitionBucket* StatusAddDefinitions(StatusDefinitionBucket* bucket); /** * add a module's array of StatusDefinition to the list. @@ -224,7 +222,7 @@ * @param max_chars size of buffer [characters] * @return buf (allows using this function in expressions) **/ -LIB_API wchar_t* StatusDescription(Status status, wchar_t* buf, size_t max_chars); +wchar_t* StatusDescription(Status status, wchar_t* buf, size_t max_chars); /** * @return the errno equivalent of a Status. diff -Nru 0ad-0.0.25b/source/lib/sysdep/arch/ia32/ia32.h 0ad-0.0.26/source/lib/sysdep/arch/ia32/ia32.h --- 0ad-0.0.25b/source/lib/sysdep/arch/ia32/ia32.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/arch/ia32/ia32.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -41,6 +41,6 @@ * * this function is used for walking the call stack. **/ -LIB_API Status ia32_GetCallTarget(void* ret_addr, void*& target); +Status ia32_GetCallTarget(void* ret_addr, void*& target); #endif // #ifndef INCLUDED_IA32 diff -Nru 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/apic.h 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/apic.h --- 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/apic.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/apic.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -33,20 +33,20 @@ * feasible. We also don't want to interfere with the OS's constant use of * the APIC registers. **/ -LIB_API ApicId GetApicId(); +ApicId GetApicId(); // if this returns false, apicId = contiguousId = processor. // otherwise, there are unspecified but bijective mappings between // apicId<->contiguousId and apicId<->processor. -LIB_API bool AreApicIdsReliable(); +bool AreApicIdsReliable(); // we may get the apicId of a processor we don't have access to. -LIB_API bool IsProcessorKnown(ApicId apicId); +bool IsProcessorKnown(ApicId apicId); -LIB_API size_t ProcessorFromApicId(ApicId apicId); -LIB_API size_t ContiguousIdFromApicId(ApicId apicId); +size_t ProcessorFromApicId(ApicId apicId); +size_t ContiguousIdFromApicId(ApicId apicId); -LIB_API ApicId ApicIdFromProcessor(size_t contiguousId); -LIB_API ApicId ApicIdFromContiguousId(size_t contiguousId); +ApicId ApicIdFromProcessor(size_t contiguousId); +ApicId ApicIdFromContiguousId(size_t contiguousId); #endif // #ifndef INCLUDED_X86_X64_APIC diff -Nru 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/tests/test_topology.h 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/tests/test_topology.h --- 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/tests/test_topology.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/tests/test_topology.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +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 "lib/self_test.h" - -#include "lib/sysdep/arch/x86_x64/topology.h" - -class TestTopology : public CxxTest::TestSuite -{ -public: - void test_run() - { - TS_ASSERT_LESS_THAN_EQUALS(1u, topology::NumPackages()); - TS_ASSERT_LESS_THAN_EQUALS(1u, topology::CoresPerPackage()); - TS_ASSERT_LESS_THAN_EQUALS(1u, topology::LogicalPerCore()); - } -}; diff -Nru 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/topology.cpp 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/topology.cpp --- 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/topology.cpp 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/topology.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,294 +0,0 @@ -/* 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 - * "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. - */ - -/* - * Detection of CPU topology - */ - -#include "precompiled.h" -#include "lib/sysdep/arch/x86_x64/topology.h" - -#include "lib/bits.h" -#include "lib/module_init.h" -#include "lib/sysdep/cpu.h" // ERR::CPU_FEATURE_MISSING -#include "lib/sysdep/os_cpu.h" -#include "lib/sysdep/numa.h" -#include "lib/sysdep/arch/x86_x64/x86_x64.h" -#include "lib/sysdep/arch/x86_x64/apic.h" - -#include -#include - -namespace topology { - -//--------------------------------------------------------------------------------------------------------------------- -// detect *maximum* number of cores/packages. -// note: some of them may be disabled by the OS or BIOS. -// note: Intel Appnote 485 assures us that they are uniform across packages. - -static size_t MaxCoresPerPackage() -{ - // assume single-core unless one of the following applies: - size_t maxCoresPerPackage = 1; - - x86_x64::CpuidRegs regs = { 0 }; - switch(x86_x64::Vendor()) - { - case x86_x64::VENDOR_INTEL: - regs.eax = 4; - regs.ecx = 0; - if(x86_x64::cpuid(®s)) - maxCoresPerPackage = bits(regs.eax, 26, 31)+1; - break; - - case x86_x64::VENDOR_AMD: - regs.eax = 0x80000008; - if(x86_x64::cpuid(®s)) - maxCoresPerPackage = bits(regs.ecx, 0, 7)+1; - break; - - default: - break; - } - - return maxCoresPerPackage; -} - - -static size_t MaxLogicalPerCore() -{ - struct IsHyperthreadingCapable - { - bool operator()() const - { - // definitely not - if(!x86_x64::Cap(x86_x64::CAP_HT)) - return false; - - // multi-core AMD systems falsely set the HT bit for reasons of - // compatibility. we'll just ignore it, because clearing it might - // confuse other callers. - if(x86_x64::Vendor() == x86_x64::VENDOR_AMD && x86_x64::Cap(x86_x64::CAP_AMD_CMP_LEGACY)) - return false; - - return true; - } - }; - if(IsHyperthreadingCapable()()) - { - x86_x64::CpuidRegs regs = { 0 }; - regs.eax = 1; - if(!x86_x64::cpuid(®s)) - DEBUG_WARN_ERR(ERR::CPU_FEATURE_MISSING); - const size_t logicalPerPackage = bits(regs.ebx, 16, 23); - const size_t maxCoresPerPackage = MaxCoresPerPackage(); - // cores ought to be uniform WRT # logical processors - ENSURE(logicalPerPackage % maxCoresPerPackage == 0); - const size_t maxLogicalPerCore = logicalPerPackage / maxCoresPerPackage; - return maxLogicalPerCore; - } - else - return 1; -} - -//--------------------------------------------------------------------------------------------------------------------- -// CPU topology interface - -// APIC IDs consist of variable-length bit fields indicating the logical, -// core, package and cache IDs. Vol3a says they aren't guaranteed to be -// contiguous, but that also applies to the individual fields. -// for example, quad-core E5630 CPUs report 4-bit core IDs 0, 1, 6, 7. -struct ApicField // POD -{ - size_t operator()(size_t bits) const - { - return (bits >> shift) & mask; - } - - size_t mask; // zero for zero-width fields - size_t shift; -}; - -struct CpuTopology // POD -{ - size_t numProcessors; // total reported by OS - - ApicField logical; - ApicField core; - ApicField package; - - // how many are actually enabled - size_t logicalPerCore; - size_t coresPerPackage; - size_t numPackages; -}; -static CpuTopology cpuTopology; -static ModuleInitState cpuInitState; - -static Status InitCpuTopology() -{ - cpuTopology.numProcessors = os_cpu_NumProcessors(); - - const size_t maxLogicalPerCore = MaxLogicalPerCore(); - const size_t maxCoresPerPackage = MaxCoresPerPackage(); - const size_t maxPackages = 256; // "enough" - - const size_t logicalWidth = ceil_log2(maxLogicalPerCore); - const size_t coreWidth = ceil_log2(maxCoresPerPackage); - const size_t packageWidth = ceil_log2(maxPackages); - - cpuTopology.logical.mask = bit_mask(logicalWidth); - cpuTopology.core.mask = bit_mask(coreWidth); - cpuTopology.package.mask = bit_mask(packageWidth); - - cpuTopology.logical.shift = 0; - cpuTopology.core.shift = logicalWidth; - cpuTopology.package.shift = logicalWidth + coreWidth; - - if(AreApicIdsReliable()) - { - struct NumUniqueValuesInField - { - size_t operator()(const ApicField& apicField) const - { - std::bitset values; - for(size_t processor = 0; processor < os_cpu_NumProcessors(); processor++) - { - const ApicId apicId = ApicIdFromProcessor(processor); - const size_t value = apicField(apicId); - values.set(value); - } - return values.count(); - } - }; - - cpuTopology.logicalPerCore = NumUniqueValuesInField()(cpuTopology.logical); - cpuTopology.coresPerPackage = NumUniqueValuesInField()(cpuTopology.core); - cpuTopology.numPackages = NumUniqueValuesInField()(cpuTopology.package); - } - else // processor lacks an xAPIC, or IDs are invalid - { - struct MinPackages - { - size_t operator()(size_t maxCoresPerPackage, size_t maxLogicalPerCore) const - { - const size_t numNodes = numa_NumNodes(); - const size_t logicalPerNode = PopulationCount(numa_ProcessorMaskFromNode(0)); - // NB: some cores or logical processors may be disabled. - const size_t maxLogicalPerPackage = maxCoresPerPackage*maxLogicalPerCore; - const size_t minPackagesPerNode = DivideRoundUp(logicalPerNode, maxLogicalPerPackage); - return minPackagesPerNode*numNodes; - } - }; - - // we can't differentiate between cores and logical processors. - // since the former are less likely to be disabled, we seek the - // maximum feasible number of cores and minimal number of packages: - const size_t minPackages = MinPackages()(maxCoresPerPackage, maxLogicalPerCore); - for(size_t numPackages = minPackages; numPackages <= cpuTopology.numProcessors; numPackages++) - { - if(cpuTopology.numProcessors % numPackages != 0) - continue; - const size_t logicalPerPackage = cpuTopology.numProcessors / numPackages; - const size_t minCoresPerPackage = DivideRoundUp(logicalPerPackage, maxLogicalPerCore); - for(size_t coresPerPackage = maxCoresPerPackage; coresPerPackage >= minCoresPerPackage; coresPerPackage--) - { - if(logicalPerPackage % coresPerPackage != 0) - continue; - const size_t logicalPerCore = logicalPerPackage / coresPerPackage; - if(logicalPerCore <= maxLogicalPerCore) - { - ENSURE(cpuTopology.numProcessors == numPackages*coresPerPackage*logicalPerCore); - cpuTopology.logicalPerCore = logicalPerCore; - cpuTopology.coresPerPackage = coresPerPackage; - cpuTopology.numPackages = numPackages; - - return INFO::OK; - } - } - } - - DEBUG_WARN_ERR(ERR::LOGIC); // didn't find a feasible topology - } - - return INFO::OK; -} - - -size_t NumPackages() -{ - ModuleInit(&cpuInitState, InitCpuTopology); - return cpuTopology.numPackages; -} - -size_t CoresPerPackage() -{ - ModuleInit(&cpuInitState, InitCpuTopology); - return cpuTopology.coresPerPackage; -} - -size_t LogicalPerCore() -{ - ModuleInit(&cpuInitState, InitCpuTopology); - return cpuTopology.logicalPerCore; -} - -size_t LogicalFromApicId(ApicId apicId) -{ - const size_t contiguousId = ContiguousIdFromApicId(apicId); - return contiguousId % cpuTopology.logicalPerCore; -} - -size_t CoreFromApicId(ApicId apicId) -{ - const size_t contiguousId = ContiguousIdFromApicId(apicId); - return (contiguousId / cpuTopology.logicalPerCore) % cpuTopology.coresPerPackage; -} - -size_t PackageFromApicId(ApicId apicId) -{ - const size_t contiguousId = ContiguousIdFromApicId(apicId); - return contiguousId / (cpuTopology.logicalPerCore * cpuTopology.coresPerPackage); -} - - -ApicId ApicIdFromIndices(size_t idxLogical, size_t idxCore, size_t idxPackage) -{ - ModuleInit(&cpuInitState, InitCpuTopology); - - size_t contiguousId = 0; - ENSURE(idxPackage < cpuTopology.numPackages); - contiguousId += idxPackage; - - contiguousId *= cpuTopology.coresPerPackage; - ENSURE(idxCore < cpuTopology.coresPerPackage); - contiguousId += idxCore; - - contiguousId *= cpuTopology.logicalPerCore; - ENSURE(idxLogical < cpuTopology.logicalPerCore); - contiguousId += idxLogical; - - ENSURE(contiguousId < cpuTopology.numProcessors); - return ApicIdFromContiguousId(contiguousId); -} - -} // namespace topology diff -Nru 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/topology.h 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/topology.h --- 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/topology.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/topology.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* 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 - * "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. - */ - -/* - * detection of CPU and cache topology. - * thread-safe, no explicit initialization is required. - */ - -#ifndef INCLUDED_X86_X64_TOPOLOGY -#define INCLUDED_X86_X64_TOPOLOGY - -#include "lib/sysdep/arch/x86_x64/apic.h" // ApicId - -namespace topology { - -//----------------------------------------------------------------------------- -// cpu - -// the CPU topology, i.e. how many packages, cores and logical processors are -// actually present and enabled, is useful for parameterizing parallel -// algorithms, especially on NUMA systems. -// -// note: OS abstractions usually only mention "processors", which could be -// any mix of the above. - -/** - * @return number of *enabled* CPU packages / sockets. - **/ -LIB_API size_t NumPackages(); - -/** - * @return number of *enabled* CPU cores per package. - * (2 on dual-core systems) - **/ -LIB_API size_t CoresPerPackage(); - -/** - * @return number of *enabled* logical processors (aka Hyperthreads) - * per core. (2 on P4 EE) - **/ -LIB_API size_t LogicalPerCore(); - -/** - * @return index of processor package/socket in [0, NumPackages()) - **/ -LIB_API size_t PackageFromApicId(ApicId apicId); - -/** - * @return index of processor core in [0, CoresPerPackage()) - **/ -LIB_API size_t CoreFromApicId(ApicId apicId); - -/** - * @return index of logical processor in [0, LogicalPerCore()) - **/ -LIB_API size_t LogicalFromApicId(ApicId apicId); - -/** - * @param idxPackage, idxCore, idxLogical return values of *FromApicId - * @return APIC ID (see note at AreApicIdsReliable) - **/ -LIB_API ApicId ApicIdFromIndices(size_t idxPackage, size_t idxCore, size_t idxLogical); - -} // namespace topology - -#endif // #ifndef INCLUDED_X86_X64_TOPOLOGY diff -Nru 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/x86_x64.h 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/x86_x64.h --- 0ad-0.0.25b/source/lib/sysdep/arch/x86_x64/x86_x64.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/arch/x86_x64/x86_x64.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,8 +27,6 @@ #ifndef INCLUDED_X86_X64 #define INCLUDED_X86_X64 -#include "lib/lib_api.h" - #if !ARCH_X86_X64 #error "including x86_x64.h without ARCH_X86_X64=1" #endif @@ -62,7 +60,7 @@ * and allows graceful expansion to functions that require further inputs. * @return true on success or false if the sub-function isn't supported. **/ -LIB_API bool cpuid(CpuidRegs* regs); +bool cpuid(CpuidRegs* regs); /** * CPU vendor. @@ -76,7 +74,7 @@ VENDOR_AMD }; -LIB_API Vendors Vendor(); +Vendors Vendor(); enum Models @@ -92,16 +90,16 @@ MODEL_SANDY_BRIDGE_2 = 0x2D, // (E5-26xx, E5-46xx) }; -LIB_API size_t Model(); +size_t Model(); -LIB_API size_t Family(); +size_t Family(); /** * @return the colloquial processor generation * (5 = Pentium, 6 = Pentium Pro/II/III / K6, 7 = Pentium4 / Athlon, 8 = Core / Opteron) **/ -LIB_API size_t Generation(); +size_t Generation(); /** @@ -141,9 +139,9 @@ /** * @return whether the CPU supports the indicated Cap / feature flag. **/ -LIB_API bool Cap(Caps cap); +bool Cap(Caps cap); -LIB_API void GetCapBits(u32* d0, u32* d1, u32* d2, u32* d3); +void GetCapBits(u32* d0, u32* d1, u32* d2, u32* d3); //----------------------------------------------------------------------------- @@ -161,13 +159,13 @@ #if MSC_VERSION static inline u64 rdtsc() { return __rdtsc(); } #else -LIB_API u64 rdtsc(); +u64 rdtsc(); #endif /** * trigger a breakpoint inside this function when it is called. **/ -LIB_API void DebugBreak(); +void DebugBreak(); /** * measure the CPU clock frequency via rdtsc and timer_Time. @@ -175,7 +173,7 @@ * this takes several milliseconds (i.e. much longer than * os_cpu_ClockFrequency) but delivers accurate measurements. **/ -LIB_API double ClockFrequency(); +double ClockFrequency(); } // namespace x86_x64 diff -Nru 0ad-0.0.25b/source/lib/sysdep/cpu.h 0ad-0.0.26/source/lib/sysdep/cpu.h --- 0ad-0.0.25b/source/lib/sysdep/cpu.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/cpu.h 2022-08-21 12:45:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -46,7 +46,7 @@ * @return string identifying the CPU (usually a cleaned-up version of the * brand string) **/ -LIB_API const char* cpu_IdentifierString(); +const char* cpu_IdentifierString(); //----------------------------------------------------------------------------- @@ -58,7 +58,7 @@ * * @return the previous value. **/ -LIB_API intptr_t cpu_AtomicAdd(volatile intptr_t* location, intptr_t increment); +intptr_t cpu_AtomicAdd(volatile intptr_t* location, intptr_t increment); /** * atomic "compare and swap". @@ -69,8 +69,8 @@ * @return false if the target word doesn't match the expected value, * otherwise true (also overwriting the contents of location) **/ -LIB_API bool cpu_CAS(volatile intptr_t* location, intptr_t expected, intptr_t newValue); -LIB_API bool cpu_CAS64(volatile i64* location, i64 expected, i64 newValue); +bool cpu_CAS(volatile intptr_t* location, intptr_t expected, intptr_t newValue); +bool cpu_CAS64(volatile i64* location, i64 expected, i64 newValue); /** * specialization of cpu_CAS for pointer types. this avoids error-prone @@ -83,7 +83,7 @@ } -LIB_API void cpu_Test(); +void cpu_Test(); /** * pause in spin-wait loops, as a performance optimisation. diff -Nru 0ad-0.0.25b/source/lib/sysdep/dir_watch.h 0ad-0.0.26/source/lib/sysdep/dir_watch.h --- 0ad-0.0.25b/source/lib/sysdep/dir_watch.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/dir_watch.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -52,7 +52,7 @@ * convenient to store PDirWatch there instead of creating a second * tree structure here. **/ -LIB_API Status dir_watch_Add(const OsPath& path, PDirWatch& dirWatch); +Status dir_watch_Add(const OsPath& path, PDirWatch& dirWatch); class DirWatchNotification { @@ -99,6 +99,6 @@ * typically want to receive change notifications at a single point, * rather than deal with the complexity of asynchronous notifications. **/ -LIB_API Status dir_watch_Poll(DirWatchNotifications& notifications); +Status dir_watch_Poll(DirWatchNotifications& notifications); #endif // #ifndef INCLUDED_DIR_WATCH diff -Nru 0ad-0.0.25b/source/lib/sysdep/filesystem.h 0ad-0.0.26/source/lib/sysdep/filesystem.h --- 0ad-0.0.25b/source/lib/sysdep/filesystem.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/filesystem.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -91,33 +91,26 @@ // however, ftruncate cannot be used since it is also subject to the // sector-alignment requirement. instead, the file must be closed and // this function called. -LIB_API int wtruncate(const OsPath& pathname, off_t length); +int wtruncate(const OsPath& pathname, off_t length); -LIB_API int wunlink(const OsPath& pathname); +int wunlink(const OsPath& pathname); -LIB_API int wrmdir(const OsPath& path); - - -// -// stdio.h -// - -LIB_API int wrename(const OsPath& pathnameOld, const OsPath& pathnameNew); +int wrmdir(const OsPath& path); // // stdlib.h // -LIB_API OsPath wrealpath(const OsPath& pathname); +OsPath wrealpath(const OsPath& pathname); // // sys/stat.h // -LIB_API int wstat(const OsPath& pathname, struct stat* buf); +int wstat(const OsPath& pathname, struct stat* buf); -LIB_API int wmkdir(const OsPath& path, mode_t mode); +int wmkdir(const OsPath& path, mode_t mode); #endif // #ifndef INCLUDED_SYSDEP_FILESYSTEM diff -Nru 0ad-0.0.25b/source/lib/sysdep/gfx.cpp 0ad-0.0.26/source/lib/sysdep/gfx.cpp --- 0ad-0.0.25b/source/lib/sysdep/gfx.cpp 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/gfx.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* 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 - * "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. - */ - -/* - * graphics card detection. - */ - -#include "precompiled.h" -#include "lib/sysdep/gfx.h" - -#include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" - -#if OS_WIN -# include "lib/sysdep/os/win/wgfx.h" -#endif - -#include - -namespace gfx { - -std::wstring CardName() -{ - // GL_VENDOR+GL_RENDERER are good enough here, so we don't use WMI to detect the cards. - // On top of that WMI can cause crashes with Nvidia Optimus and some netbooks - // see http://trac.wildfiregames.com/ticket/1952 - // http://trac.wildfiregames.com/ticket/1575 - wchar_t cardName[128]; - const char* vendor = (const char*)glGetString(GL_VENDOR); - const char* renderer = (const char*)glGetString(GL_RENDERER); - // (happens if called before ogl_Init or between glBegin and glEnd.) - if(!vendor || !renderer) - return L""; - swprintf_s(cardName, ARRAY_SIZE(cardName), L"%hs %hs", vendor, renderer); - - // remove crap from vendor names. (don't dare touch the model name - - // it's too risky, there are too many different strings) -#define SHORTEN(what, charsToKeep)\ - if(!wcsncmp(cardName, what, ARRAY_SIZE(what)-1))\ - memmove(cardName+charsToKeep, cardName+ARRAY_SIZE(what)-1, (wcslen(cardName)-(ARRAY_SIZE(what)-1)+1)*sizeof(wchar_t)); - SHORTEN(L"ATI Technologies Inc.", 3); - SHORTEN(L"NVIDIA Corporation", 6); - SHORTEN(L"S3 Graphics", 2); // returned by EnumDisplayDevices - SHORTEN(L"S3 Graphics, Incorporated", 2); // returned by GL_VENDOR -#undef SHORTEN - - return cardName; -} - - -std::wstring DriverInfo() -{ - std::wstring driverInfo; -#if OS_WIN - driverInfo = wgfx_DriverInfo(); - if(driverInfo.empty()) -#endif - { - const char* version = (const char*)glGetString(GL_VERSION); - if(version) - { - // add "OpenGL" to differentiate this from the real driver version - // (returned by platform-specific detect routines). - driverInfo = std::wstring(L"OpenGL ") + std::wstring(version, version+strlen(version)); - } - } - - if(driverInfo.empty()) - return L"(unknown)"; - return driverInfo; -} - -} // namespace gfx diff -Nru 0ad-0.0.25b/source/lib/sysdep/gfx.h 0ad-0.0.26/source/lib/sysdep/gfx.h --- 0ad-0.0.25b/source/lib/sysdep/gfx.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/gfx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* 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 - * "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. - */ - -/* - * graphics card detection. - */ - -#ifndef INCLUDED_GFX -#define INCLUDED_GFX - -namespace gfx { - -/** - * @return description of graphics card, -* or L"" if unknown. - **/ -LIB_API std::wstring CardName(); - -/** - * @return string describing the graphics driver and its version, - * or L"" if unknown. - **/ -LIB_API std::wstring DriverInfo(); - -} // namespace gfx - -#endif // #ifndef INCLUDED_GFX diff -Nru 0ad-0.0.25b/source/lib/sysdep/numa.h 0ad-0.0.26/source/lib/sysdep/numa.h --- 0ad-0.0.25b/source/lib/sysdep/numa.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/numa.h 2022-08-21 12:45:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,19 +29,19 @@ /** * @return number of NUMA "nodes" (i.e. groups of CPUs with local memory). **/ -LIB_API size_t numa_NumNodes(); +size_t numa_NumNodes(); /** * @param processor * @return node number (zero-based) to which \ belongs. **/ -LIB_API size_t numa_NodeFromProcessor(size_t processor); +size_t numa_NodeFromProcessor(size_t processor); /** * @param node * @return bit-mask of all processors constituting \. **/ -LIB_API uintptr_t numa_ProcessorMaskFromNode(size_t node); +uintptr_t numa_ProcessorMaskFromNode(size_t node); //----------------------------------------------------------------------------- @@ -52,7 +52,7 @@ * @param node * @return bytes of memory available for allocation on \. **/ -LIB_API size_t numa_AvailableMemory(size_t node); +size_t numa_AvailableMemory(size_t node); /** * @return the ratio between maximum and minimum times that one processor @@ -60,7 +60,7 @@ * in other words, this is the maximum slowdown for NUMA-oblivious * memory accesses. Microsoft guidelines require it to be <= 3. **/ -LIB_API double numa_Factor(); +double numa_Factor(); /** * @return an indication of whether memory pages are node-interleaved. @@ -69,6 +69,6 @@ * least-permission accounts. the default is to return false so as * not to cause callers to panic and trigger performance warnings. **/ -LIB_API bool numa_IsMemoryInterleaved(); +bool numa_IsMemoryInterleaved(); #endif // #ifndef INCLUDED_NUMA diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/bsd/bcpu.cpp 0ad-0.0.26/source/lib/sysdep/os/bsd/bcpu.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/bsd/bcpu.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/bsd/bcpu.cpp 2022-09-23 19:16:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,9 +25,12 @@ #include "lib/sysdep/os_cpu.h" #include "lib/alignment.h" #include "lib/bits.h" +#include "lib/config2.h" #include "lib/module_init.h" -#include "valgrind.h" +#if CONFIG2_VALGRIND +# include "valgrind.h" +#endif #include #include @@ -37,12 +40,14 @@ if(numProcessors == 0) { +#if CONFIG2_VALGRIND // Valgrind reports the number of real CPUs, but only emulates a single CPU. // That causes problems when we expect all those CPUs to be distinct, so // just pretend there's only one CPU if (RUNNING_ON_VALGRIND) numProcessors = 1; else +#endif { long res = sysconf(_SC_NPROCESSORS_CONF); ENSURE(res != -1); @@ -89,7 +94,7 @@ size_t len = sizeof(memorySize); // Argh, the API doesn't seem to be const-correct /*const*/ int mib[2] = { CTL_HW, HW_PHYSMEM }; - sysctl(mib, 2, &memorySize, &len, 0, 0); + sysctl(mib, 2, &memorySize, &len, nullptr, 0); memorySize /= MiB; return memorySize; } @@ -101,7 +106,7 @@ size_t len = sizeof(memoryAvailable); // Argh, the API doesn't seem to be const-correct /*const*/ int mib[2] = { CTL_HW, HW_USERMEM }; - sysctl(mib, 2, &memoryAvailable, &len, 0, 0); + sysctl(mib, 2, &memoryAvailable, &len, nullptr, 0); memoryAvailable /= MiB; return memoryAvailable; } diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/linux/lcpu.cpp 0ad-0.0.26/source/lib/sysdep/os/linux/lcpu.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/linux/lcpu.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/linux/lcpu.cpp 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,10 +25,11 @@ #include "lib/sysdep/os_cpu.h" #include "lib/alignment.h" #include "lib/bits.h" +#include "lib/config2.h" #include "lib/module_init.h" -#if OS_LINUX -#include "valgrind.h" +#if CONFIG2_VALGRIND +# include "valgrind.h" #endif @@ -38,12 +39,14 @@ if(numProcessors == 0) { +#if CONFIG2_VALGRIND // Valgrind reports the number of real CPUs, but only emulates a single CPU. // That causes problems when we expect all those CPUs to be distinct, so // just pretend there's only one CPU if (RUNNING_ON_VALGRIND) numProcessors = 1; else +#endif { long res = sysconf(_SC_NPROCESSORS_CONF); ENSURE(res != -1); diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/osx/ocpu.cpp 0ad-0.0.26/source/lib/sysdep/os/osx/ocpu.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/osx/ocpu.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/osx/ocpu.cpp 2022-09-23 19:16:47.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -81,8 +81,8 @@ size_t memorySize = 0; size_t len = sizeof(memorySize); // Argh, the API doesn't seem to be const-correct - /*const*/ int mib[2] = { CTL_HW, HW_PHYSMEM }; - sysctl(mib, 2, &memorySize, &len, 0, 0); + /*const*/ int mib[2] = { CTL_HW, HW_MEMSIZE }; + sysctl(mib, 2, &memorySize, &len, nullptr, 0); memorySize /= MiB; return memorySize; } @@ -94,7 +94,7 @@ size_t len = sizeof(memoryAvailable); // Argh, the API doesn't seem to be const-correct /*const*/ int mib[2] = { CTL_HW, HW_USERMEM }; - sysctl(mib, 2, &memoryAvailable, &len, 0, 0); + sysctl(mib, 2, &memoryAvailable, &len, nullptr, 0); memoryAvailable /= MiB; return memoryAvailable; } diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/osx/osx.cpp 0ad-0.0.26/source/lib/sysdep/os/osx/osx.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/osx/osx.cpp 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/osx/osx.cpp 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,7 +24,6 @@ #include "lib/lib.h" #include "lib/sysdep/sysdep.h" -#include "lib/sysdep/gfx.h" #include "lib/utf8.h" #include "osx_bundle.h" diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/acpi.h 0ad-0.0.26/source/lib/sysdep/os/win/acpi.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/acpi.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/acpi.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -101,11 +101,11 @@ * note: the first call may be slow, e.g. if a kernel-mode driver is * loaded. subsequent requests will be faster since tables are cached. **/ -LIB_API const AcpiTable* acpi_GetTable(const char* signature); +const AcpiTable* acpi_GetTable(const char* signature); /** * invalidates all pointers returned by acpi_GetTable. **/ -LIB_API void acpi_Shutdown(); +void acpi_Shutdown(); #endif // #ifndef INCLUDED_ACPI diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/manifest.cpp 0ad-0.0.26/source/lib/sysdep/os/win/manifest.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/win/manifest.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/manifest.cpp 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -33,7 +33,7 @@ ICC 10.1 IPO considers this string to be an input file, hence this is currently disabled there. */ -#if MSC_VERSION >= 1400 && !ICC_VERSION && defined(LIB_STATIC_LINK) +#if MSC_VERSION >= 1400 && !ICC_VERSION # if ARCH_IA32 # pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"") # elif ARCH_AMD64 diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wdbg.h 0ad-0.0.26/source/lib/sysdep/os/win/wdbg.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wdbg.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wdbg.h 2022-08-21 12:45:14.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -34,7 +34,7 @@ * this function does not allocate memory from the CRT heap, which makes it * safe to use from an allocation hook. **/ -LIB_API void wdbg_printf(const wchar_t* fmt, ...); +void wdbg_printf(const wchar_t* fmt, ...); /** * similar to ENSURE but safe to use during critical init or diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wdbg_heap.h 0ad-0.0.26/source/lib/sysdep/os/win/wdbg_heap.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wdbg_heap.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wdbg_heap.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -40,7 +40,7 @@ * enable or disable manual and automatic heap validity checking. * (enabled by default during critical_init.) **/ -LIB_API void wdbg_heap_Enable(bool); +void wdbg_heap_Enable(bool); /** * check heap integrity. @@ -48,12 +48,12 @@ * no effect if called between wdbg_heap_Enable(false) and the next * wdbg_heap_Enable(true). **/ -LIB_API void wdbg_heap_Validate(); +void wdbg_heap_Validate(); /** * @return the total number of alloc and realloc operations thus far. * used by the in-game profiler. **/ -LIB_API intptr_t wdbg_heap_NumberOfAllocations(); +intptr_t wdbg_heap_NumberOfAllocations(); #endif // #ifndef INCLUDED_WDBG_HEAP diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wdbg_sym.h 0ad-0.0.26/source/lib/sysdep/os/win/wdbg_sym.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wdbg_sym.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wdbg_sym.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -59,8 +59,8 @@ * stack trace (which is triggered by ENSURE et al. in app code) because * nested stack traces are ignored and only the error is displayed. **/ -LIB_API Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, CONTEXT& context, const wchar_t* lastFuncToSkip = 0); +Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, CONTEXT& context, const wchar_t* lastFuncToSkip = 0); -LIB_API void wdbg_sym_WriteMinidump(EXCEPTION_POINTERS* ep); +void wdbg_sym_WriteMinidump(EXCEPTION_POINTERS* ep); #endif // #ifndef INCLUDED_WDBG_SYM diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wgfx.cpp 0ad-0.0.26/source/lib/sysdep/os/win/wgfx.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/win/wgfx.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wgfx.cpp 2022-08-21 12:45:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,7 +27,6 @@ #include "precompiled.h" #include "lib/sysdep/os/win/wgfx.h" -#include "lib/sysdep/gfx.h" #include "lib/sysdep/os/win/wdll_ver.h" #include "lib/sysdep/os/win/wutil.h" diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wgl.h 0ad-0.0.26/source/lib/sysdep/os/win/wgl.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wgl.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wgl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +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 definitions required for GL/gl.h - */ - -// RAGE! Win32 OpenGL headers are full of crap we have to emulate -// (must not include windows.h) - -#ifndef WGL_HEADER_NEEDED -#error "wgl.h: why is this included from anywhere but ogl.h?" -#endif - - -#ifndef WINGDIAPI -#define WINGDIAPI __declspec(dllimport) -#endif -#ifndef CALLBACK -#define CALLBACK __stdcall -#endif -#ifndef APIENTRY -#define APIENTRY __stdcall -#endif -#ifndef WINAPI -#define WINAPI __stdcall -#endif - -#ifndef DECLARE_HANDLE -typedef void VOID; -typedef void* LPVOID; -typedef int BOOL; -typedef unsigned short USHORT; -typedef int INT; -typedef unsigned int UINT; -typedef long LONG; -typedef unsigned long DWORD; -typedef int INT32; -typedef __int64 INT64; -typedef float FLOAT; -typedef char CHAR; -typedef const char* LPCSTR; -typedef void* HANDLE; -typedef int (*PROC)(); -struct RECT -{ - LONG left; - LONG top; - LONG right; - LONG bottom; -}; -#define DECLARE_HANDLE(name) typedef HANDLE name -DECLARE_HANDLE(HDC); -DECLARE_HANDLE(HGLRC); -#endif - -// VC6 doesn't define wchar_t as built-in type -#ifndef _WCHAR_T_DEFINED -typedef unsigned short wchar_t; // for glu.h -#define _WCHAR_T_DEFINED -#endif - -WINGDIAPI BOOL WINAPI wglCopyContext(HGLRC, HGLRC, UINT); -WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); -WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC, int); -WINGDIAPI BOOL WINAPI wglDeleteContext(HGLRC); -WINGDIAPI HGLRC WINAPI wglGetCurrentContext(); -WINGDIAPI HDC WINAPI wglGetCurrentDC(); -WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); -WINGDIAPI BOOL WINAPI wglMakeCurrent(HDC, HGLRC); -WINGDIAPI BOOL WINAPI wglShareLists(HGLRC, HGLRC); -WINGDIAPI BOOL WINAPI wglUseFontBitmapsA(HDC, DWORD, DWORD, DWORD); -WINGDIAPI BOOL WINAPI wglUseFontBitmapsW(HDC, DWORD, DWORD, DWORD); diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/waio.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/waio.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/waio.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/waio.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -138,6 +138,6 @@ // this function sets the valid data length to avoid the synchronous zero-fill. // to avoid exposing the previous disk contents until the application // successfully writes to the file, deny sharing when opening the file. -LIB_API Status waio_Preallocate(int fd, off_t size); +Status waio_Preallocate(int fd, off_t size); #endif // #ifndef INCLUDED_WAIO diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wdlfcn.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wdlfcn.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wdlfcn.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wdlfcn.h 2022-08-21 12:45:14.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -34,9 +34,9 @@ #define RTLD_GLOBAL 0x04 // semantics are unsupported, so complain if set. #define RTLD_LOCAL 0x08 -LIB_API int dlclose(void* handle); -LIB_API char* dlerror(); -LIB_API void* dlopen(const char* so_name, int flags); -LIB_API void* dlsym(void* handle, const char* sym_name); +int dlclose(void* handle); +char* dlerror(); +void* dlopen(const char* so_name, int flags); +void* dlsym(void* handle, const char* sym_name); #endif // #ifndef INCLUDED_WDLFCN diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wfilesystem.cpp 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wfilesystem.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wfilesystem.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wfilesystem.cpp 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -303,12 +303,6 @@ } -int wrename(const OsPath& pathnameOld, const OsPath& pathnameNew) -{ - return _wrename(OsString(pathnameOld).c_str(), OsString(pathnameNew).c_str()); -} - - OsPath wrealpath(const OsPath& pathname) { wchar_t resolved[PATH_MAX]; diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wmman.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wmman.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wmman.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wmman.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -57,6 +57,6 @@ extern int mprotect(void* addr, size_t len, int prot); // convert POSIX PROT_* flags to their Win32 PAGE_* enumeration equivalents. -LIB_API unsigned MemoryProtectionFromPosix(int prot); +unsigned MemoryProtectionFromPosix(int prot); #endif // #ifndef INCLUDED_WMMAN diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wposix.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wposix.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wposix.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wposix.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -52,7 +52,7 @@ // // -LIB_API int setenv(const char* envname, const char* envval, int overwrite); +int setenv(const char* envname, const char* envval, int overwrite); // diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wpthread.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wpthread.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wpthread.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wpthread.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -57,45 +57,45 @@ typedef intptr_t pthread_once_t; // required for cpu_CAS #define PTHREAD_ONCE_INIT 0 // static pthread_once_t x = PTHREAD_ONCE_INIT; -LIB_API int pthread_once(pthread_once_t*, void (*init_routine)()); +int pthread_once(pthread_once_t*, void (*init_routine)()); // thread typedef uintptr_t pthread_t; -LIB_API int pthread_equal(pthread_t t1, pthread_t t2); -LIB_API pthread_t pthread_self(); -LIB_API int pthread_getschedparam(pthread_t thread, int* policy, struct sched_param* param); -LIB_API int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param); -LIB_API int pthread_create(pthread_t* thread, const void* attr, void* (*func)(void*), void* arg); -LIB_API int pthread_cancel(pthread_t thread); -LIB_API int pthread_join(pthread_t thread, void** value_ptr); +int pthread_equal(pthread_t t1, pthread_t t2); +pthread_t pthread_self(); +int pthread_getschedparam(pthread_t thread, int* policy, struct sched_param* param); +int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param); +int pthread_create(pthread_t* thread, const void* attr, void* (*func)(void*), void* arg); +int pthread_cancel(pthread_t thread); +int pthread_join(pthread_t thread, void** value_ptr); // mutex typedef void* pthread_mutexattr_t; -LIB_API int pthread_mutexattr_init(pthread_mutexattr_t* attr); -LIB_API int pthread_mutexattr_destroy(pthread_mutexattr_t* attr); +int pthread_mutexattr_init(pthread_mutexattr_t* attr); +int pthread_mutexattr_destroy(pthread_mutexattr_t* attr); enum { PTHREAD_MUTEX_RECURSIVE }; // the only one we support -LIB_API int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type); -LIB_API int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type); +int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type); +int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type); typedef void* pthread_mutex_t; // pointer to critical section -LIB_API pthread_mutex_t pthread_mutex_initializer(); +pthread_mutex_t pthread_mutex_initializer(); #define PTHREAD_MUTEX_INITIALIZER pthread_mutex_initializer() -LIB_API int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*); -LIB_API int pthread_mutex_destroy(pthread_mutex_t*); -LIB_API int pthread_mutex_lock(pthread_mutex_t*); -LIB_API int pthread_mutex_trylock(pthread_mutex_t*); -LIB_API int pthread_mutex_unlock(pthread_mutex_t*); -LIB_API int pthread_mutex_timedlock(pthread_mutex_t*, const struct timespec*); +int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*); +int pthread_mutex_destroy(pthread_mutex_t*); +int pthread_mutex_lock(pthread_mutex_t*); +int pthread_mutex_trylock(pthread_mutex_t*); +int pthread_mutex_unlock(pthread_mutex_t*); +int pthread_mutex_timedlock(pthread_mutex_t*, const struct timespec*); // thread-local storage typedef unsigned int pthread_key_t; -LIB_API int pthread_key_create(pthread_key_t*, void (*dtor)(void*)); -LIB_API int pthread_key_delete(pthread_key_t); -LIB_API void* pthread_getspecific(pthread_key_t); -LIB_API int pthread_setspecific(pthread_key_t, const void* value); +int pthread_key_create(pthread_key_t*, void (*dtor)(void*)); +int pthread_key_delete(pthread_key_t); +void* pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void* value); // @@ -106,14 +106,14 @@ #define SEM_FAILED 0 -LIB_API sem_t* sem_open(const char* name, int oflag, ...); -LIB_API int sem_close(sem_t* sem); -LIB_API int sem_unlink(const char* name); -LIB_API int sem_init(sem_t*, int pshared, unsigned value); -LIB_API int sem_destroy(sem_t*); -LIB_API int sem_post(sem_t*); -LIB_API int sem_wait(sem_t*); -LIB_API int sem_timedwait(sem_t*, const struct timespec*); +sem_t* sem_open(const char* name, int oflag, ...); +int sem_close(sem_t* sem); +int sem_unlink(const char* name); +int sem_init(sem_t*, int pshared, unsigned value); +int sem_destroy(sem_t*); +int sem_post(sem_t*); +int sem_wait(sem_t*); +int sem_timedwait(sem_t*, const struct timespec*); // wait until semaphore is locked or a message arrives. non-portable. @@ -130,6 +130,6 @@ // -1 otherwise. errno differentiates what happened: ETIMEDOUT if a // message arrived (this is to ease switching between message waiting and // periodic timeout), or an error indication. -LIB_API int sem_msgwait_np(sem_t* sem); +int sem_msgwait_np(sem_t* sem); #endif // #ifndef INCLUDED_WPTHREAD diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wtime.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wtime.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wtime.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wtime.h 2022-08-21 12:45:14.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -40,8 +40,8 @@ // // -LIB_API unsigned sleep(unsigned sec); -LIB_API int usleep(useconds_t us); +unsigned sleep(unsigned sec); +int usleep(useconds_t us); // @@ -50,6 +50,6 @@ extern int nanosleep(const struct timespec* rqtp, struct timespec* rmtp); -LIB_API char* strptime(const char* buf, const char* format, struct tm* timeptr); +char* strptime(const char* buf, const char* format, struct tm* timeptr); #endif // #ifndef INCLUDED_WTIME diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wutsname.cpp 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wutsname.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wutsname.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wutsname.cpp 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -47,7 +47,13 @@ // OS Implementation name if (osInfo.dwMajorVersion >= 10) { - stream << "Win" << osInfo.dwMajorVersion; + // Microsoft kept the 10.0.* version for Windows 11. + // https://stackoverflow.com/questions/69836878/detecting-windows-11-properly + // https://stackoverflow.com/questions/68510685/how-to-detect-windows-11-using-delphi-10-3-3/68517744#68517744 + if (osInfo.dwMajorVersion == 10 && osInfo.dwBuildNumber >= 22000) + stream << "Win11"; + else + stream << "Win" << osInfo.dwMajorVersion; } else stream << wversion_Family() << "\0"; diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wutsname.h 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wutsname.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wposix/wutsname.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wposix/wutsname.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -36,7 +36,7 @@ char machine[9]; // Name of the hardware type on which the system is running. }; -LIB_API int uname(struct utsname*); +int uname(struct utsname*); #endif // #ifndef INCLUDED_WUTSNAME diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wseh.cpp 0ad-0.0.26/source/lib/sysdep/os/win/wseh.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/win/wseh.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wseh.cpp 2022-09-23 19:16:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -277,7 +277,7 @@ const wchar_t* messageFormat = L"Much to our regret we must report the program has encountered an error.\r\n" L"\r\n" - L"Please let us know at http://trac.wildfiregames.com/ and attach the crashlog.txt and crashlog.dmp files.\r\n" + L"Please let us know at https://trac.wildfiregames.com/ and attach the crashlog.txt and crashlog.dmp files.\r\n" L"You may find paths to these files at https://trac.wildfiregames.com/wiki/GameDataPaths \r\n" L"\r\n" L"Details: unhandled exception (%ls)\r\n"; @@ -350,8 +350,6 @@ */ -#ifdef LIB_STATIC_LINK - #include "lib/utf8.h" EXTERN_C int wmainCRTStartup(); @@ -390,5 +388,3 @@ #endif return CallStartupWithinTryBlock(); } - -#endif diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wutil.cpp 0ad-0.0.26/source/lib/sysdep/os/win/wutil.cpp --- 0ad-0.0.25b/source/lib/sysdep/os/win/wutil.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wutil.cpp 2022-08-21 12:45:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -372,31 +372,11 @@ //----------------------------------------------------------------------------- // module handle -#ifndef LIB_STATIC_LINK - -#include "lib/sysdep/os/win/wdll_main.h" - -HMODULE wutil_LibModuleHandle() -{ - HMODULE hModule; - const DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; - const BOOL ok = GetModuleHandleEx(flags, (LPCWSTR)&wutil_LibModuleHandle, &hModule); - // (avoid ENSURE etc. because we're called from debug_DisplayError) - wdbg_assert(ok); - return hModule; -} - -#else - HMODULE wutil_LibModuleHandle() { return GetModuleHandle(0); } -#endif - - - //----------------------------------------------------------------------------- // find main window @@ -414,6 +394,11 @@ hAppWindow = wmInfo.info.win.window; } +void* wutil_GetAppHDC() +{ + return GetDC(hAppWindow); +} + void wutil_SetAppWindow(void* hwnd) { hAppWindow = reinterpret_cast(hwnd); diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wutil.h 0ad-0.0.26/source/lib/sysdep/os/win/wutil.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wutil.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wutil.h 2022-08-21 12:45:11.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -181,7 +181,7 @@ //----------------------------------------------------------------------------- -LIB_API Status wutil_SetPrivilege(const wchar_t* privilege, bool enable); +Status wutil_SetPrivilege(const wchar_t* privilege, bool enable); /** * @return module handle of lib code (that of the main EXE if diff -Nru 0ad-0.0.25b/source/lib/sysdep/os/win/wversion.h 0ad-0.0.26/source/lib/sysdep/os/win/wversion.h --- 0ad-0.0.25b/source/lib/sysdep/os/win/wversion.h 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os/win/wversion.h 2022-08-21 12:45:14.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -41,7 +41,7 @@ /** * @return one of the above WVERSION* values **/ -LIB_API size_t wversion_Number(); +size_t wversion_Number(); /** * @return short textual representation of the version diff -Nru 0ad-0.0.25b/source/lib/sysdep/os_cpu.h 0ad-0.0.26/source/lib/sysdep/os_cpu.h --- 0ad-0.0.25b/source/lib/sysdep/os_cpu.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/os_cpu.h 2022-08-21 12:45:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -54,7 +54,7 @@ * this process. * its population count is by definition equal to os_cpu_NumProcessors(). **/ -LIB_API uintptr_t os_cpu_ProcessorMask(); +uintptr_t os_cpu_ProcessorMask(); /** * @return the number of processors available to this process. @@ -62,7 +62,7 @@ * note: this function is necessary because POSIX sysconf _SC_NPROCESSORS_CONF * is not suppored on MacOSX, else we would use that. **/ -LIB_API size_t os_cpu_NumProcessors(); +size_t os_cpu_NumProcessors(); //----------------------------------------------------------------------------- @@ -72,36 +72,36 @@ * @return a rough estimate of the CPU clock frequency. * this is usually accurate to a few MHz and is faster than measurement loops. **/ -LIB_API double os_cpu_ClockFrequency(); +double os_cpu_ClockFrequency(); /** * @return the size [bytes] of a MMU page (4096 on most IA-32 systems) **/ -LIB_API size_t os_cpu_PageSize(); +size_t os_cpu_PageSize(); /** * @return the size [bytes] of a large MMU page (4 MiB on most IA-32 systems) * or zero if they are not supported. **/ -LIB_API size_t os_cpu_LargePageSize(); +size_t os_cpu_LargePageSize(); /** * @return the size [MB] of physical memory as reported by the OS; * no caching/validation is performed. **/ -LIB_API size_t os_cpu_QueryMemorySize(); +size_t os_cpu_QueryMemorySize(); /** * @return the size [MB] of physical memory; caches the result of * os_cpu_QueryMemorySize and overrides it with a more exact value * if SMBIOS information is available. **/ -LIB_API size_t os_cpu_MemorySize(); +size_t os_cpu_MemorySize(); /** * @return the current amount [MB] of available memory. **/ -LIB_API size_t os_cpu_MemoryAvailable(); +size_t os_cpu_MemoryAvailable(); //----------------------------------------------------------------------------- @@ -114,7 +114,7 @@ * (bit index i corresponds to processor i) * @return the previous mask **/ -LIB_API uintptr_t os_cpu_SetThreadAffinityMask(uintptr_t processorMask); +uintptr_t os_cpu_SetThreadAffinityMask(uintptr_t processorMask); class os_cpu_ScopedSetThreadAffinityMask { @@ -148,6 +148,6 @@ * order of processor ID. * fails if process affinity prevents running on all processors. **/ -LIB_API Status os_cpu_CallByEachCPU(OsCpuCallback cb, uintptr_t cbData); +Status os_cpu_CallByEachCPU(OsCpuCallback cb, uintptr_t cbData); #endif // #ifndef INCLUDED_OS_CPU diff -Nru 0ad-0.0.25b/source/lib/sysdep/rtl.h 0ad-0.0.26/source/lib/sysdep/rtl.h --- 0ad-0.0.25b/source/lib/sysdep/rtl.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/rtl.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ #ifndef INCLUDED_RTL #define INCLUDED_RTL -LIB_API void* rtl_AllocateAligned(size_t size, size_t alignment); -LIB_API void rtl_FreeAligned(void* alignedPointer); +void* rtl_AllocateAligned(size_t size, size_t alignment); +void rtl_FreeAligned(void* alignedPointer); #endif // #ifndef INCLUDED_RTL diff -Nru 0ad-0.0.25b/source/lib/sysdep/smbios.h 0ad-0.0.26/source/lib/sysdep/smbios.h --- 0ad-0.0.25b/source/lib/sysdep/smbios.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/smbios.h 2022-09-23 19:16:47.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -272,7 +272,7 @@ #define BaseboardFlags_ENUMERATORS\ ENUM(motherboard, 0x01)\ ENUM(requires_add_in, 0x02)\ - ENUM(removeable, 0x04)\ + ENUM(removable, 0x04)\ ENUM(replaceable, 0x08)\ ENUM(hot_swappable, 0x10) @@ -1219,13 +1219,13 @@ * thread-safe; return value should be cached (if possible) to avoid an * atomic comparison. **/ -LIB_API const Structures* GetStructures(); +const Structures* GetStructures(); /** * @return a string describing all structures (omitting fields with * meaningless or dummy values). **/ -LIB_API std::string StringizeStructures(const Structures*); +std::string StringizeStructures(const Structures*); } // namespace SMBIOS diff -Nru 0ad-0.0.25b/source/lib/sysdep/sysdep.h 0ad-0.0.26/source/lib/sysdep/sysdep.h --- 0ad-0.0.25b/source/lib/sysdep/sysdep.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/sysdep.h 2022-08-21 12:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -72,15 +72,14 @@ * (if so, it is safe to use debug_break; otherwise, that would * raise an exception) **/ -LIB_API bool sys_IsDebuggerPresent(); +bool sys_IsDebuggerPresent(); /** * @return a wide string conversion of the platform's encoding of main's argv. * - * (NB: wseh.cpp defines a wmain that converts argv to UTF-8 and calls main(), - * but only if LIB_STATIC_LINK) + * (NB: wseh.cpp defines a wmain that converts argv to UTF-8 and calls main()) **/ -LIB_API std::wstring sys_WideFromArgv(const char* argv_i); +std::wstring sys_WideFromArgv(const char* argv_i); /** * describe the current OS error state. @@ -111,7 +110,7 @@ * * this is useful for determining installation directory, e.g. for VFS. **/ -LIB_API OsPath sys_ExecutablePathname(); +OsPath sys_ExecutablePathname(); /** * Get the current user's login name. @@ -164,7 +163,7 @@ * this should only be used with small numbers of bytes, to avoid * hogging the system's entropy. **/ -LIB_API Status sys_generate_random_bytes(u8* buf, size_t count); +Status sys_generate_random_bytes(u8* buf, size_t count); /** * get the proxy address for accessing the given HTTP URL. @@ -173,12 +172,12 @@ * * @return INFO::OK on success; INFO::SKIPPED if no proxy found. **/ -LIB_API Status sys_get_proxy_config(const std::wstring& url, std::wstring& proxy); +Status sys_get_proxy_config(const std::wstring& url, std::wstring& proxy); /** * open a file like with fopen (but taking an OsPath argument). */ -LIB_API FILE* sys_OpenFile(const OsPath& pathname, const char* mode); +FILE* sys_OpenFile(const OsPath& pathname, const char* mode); /** * directory separation character diff -Nru 0ad-0.0.25b/source/lib/sysdep/vm.h 0ad-0.0.26/source/lib/sysdep/vm.h --- 0ad-0.0.25b/source/lib/sysdep/vm.h 2021-07-27 21:56:59.000000000 +0000 +++ 0ad-0.0.26/source/lib/sysdep/vm.h 2022-08-21 12:45:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -63,7 +63,7 @@ * (an error dialog will also be raised). * must be freed via ReleaseAddressSpace. **/ -LIB_API void* ReserveAddressSpace(size_t size, size_t commitSize = g_LargePageSize, PageType pageType = kDefault, int prot = PROT_READ|PROT_WRITE); +void* ReserveAddressSpace(size_t size, size_t commitSize = g_LargePageSize, PageType pageType = kDefault, int prot = PROT_READ|PROT_WRITE); /** * release address space and decommit any memory. @@ -72,7 +72,7 @@ * @param size is required by the POSIX implementation and * ignored on Windows. **/ -LIB_API void ReleaseAddressSpace(void* p, size_t size = 0); +void ReleaseAddressSpace(void* p, size_t size = 0); /** @@ -90,14 +90,14 @@ * * (this is surprisingly slow in XP, possibly due to PFN lock contention) **/ -LIB_API bool Commit(uintptr_t address, size_t size, PageType pageType = kDefault, int prot = PROT_READ|PROT_WRITE); +bool Commit(uintptr_t address, size_t size, PageType pageType = kDefault, int prot = PROT_READ|PROT_WRITE); /** * unmap physical memory. * * @return whether the operation succeeded. **/ -LIB_API bool Decommit(uintptr_t address, size_t size); +bool Decommit(uintptr_t address, size_t size); /** @@ -108,7 +108,7 @@ * @param prot memory protection flags: PROT_NONE or a combination of * PROT_READ, PROT_WRITE, PROT_EXEC. **/ -LIB_API bool Protect(uintptr_t address, size_t size, int prot); +bool Protect(uintptr_t address, size_t size, int prot); /** @@ -119,7 +119,7 @@ * @return zero-initialized memory aligned to the respective * page size. **/ -LIB_API void* Allocate(size_t size, PageType pageType = kDefault, int prot = PROT_READ|PROT_WRITE); +void* Allocate(size_t size, PageType pageType = kDefault, int prot = PROT_READ|PROT_WRITE); /** * decommit memory and release address space. @@ -131,23 +131,23 @@ * (this differs from ReleaseAddressSpace, which must account for * extra padding/alignment to largePageSize.) **/ -LIB_API void Free(void* p, size_t size = 0); +void Free(void* p, size_t size = 0); /** * install a handler that attempts to commit memory whenever a * read/write page fault is encountered. thread-safe. **/ -LIB_API void BeginOnDemandCommits(); +void BeginOnDemandCommits(); /** * decrements the reference count begun by BeginOnDemandCommit and * removes the page fault handler when it reaches 0. thread-safe. **/ -LIB_API void EndOnDemandCommits(); +void EndOnDemandCommits(); -LIB_API void DumpStatistics(); +void DumpStatistics(); } // namespace vm diff -Nru 0ad-0.0.25b/source/lib/tests/test_adts.h 0ad-0.0.26/source/lib/tests/test_adts.h --- 0ad-0.0.25b/source/lib/tests/test_adts.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tests/test_adts.h 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -23,7 +23,8 @@ #include "lib/self_test.h" #include "lib/adts/ring_buf.h" -#include "lib/rand.h" + +#include class TestRingbuf : public CxxTest::TestSuite { @@ -61,16 +62,19 @@ void test_randomized_insert_remove() { - srand(1); + std::mt19937 engine(42); + std::uniform_int_distribution distributionProbability(0, 9); + std::uniform_int_distribution distributionValue(0); + RingBuf buf; std::deque deq; for(size_t rep = 0; rep < 1000; rep++) { - size_t rnd_op = rand(0, 10); + const size_t rnd_op = distributionProbability(engine); // 70% - insert if(rnd_op >= 3) { - int item = rand(); + int item = distributionValue(engine); buf.push_back(item); deq.push_back(item); diff -Nru 0ad-0.0.25b/source/lib/tests/test_cache_adt.h 0ad-0.0.26/source/lib/tests/test_cache_adt.h --- 0ad-0.0.25b/source/lib/tests/test_cache_adt.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tests/test_cache_adt.h 2022-08-21 12:45:17.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -23,7 +23,8 @@ #include "lib/self_test.h" #include "lib/adts/cache_adt.h" -#include "lib/rand.h" + +#include class TestCache: public CxxTest::TestSuite { @@ -47,19 +48,21 @@ #define MEASURE(c, desc)\ {\ - srand(1);\ + std::mt19937 engine(42);\ + std::uniform_int_distribution distribution9(0, 9);\ + std::uniform_int_distribution distribution99(1, 99);\ int cnt = 1;\ TIMER_BEGIN(desc);\ for(int i = 0; i < 30000; i++)\ {\ /* 70% add (random objects) */\ - bool add = rand(1,10) < 7;\ + const bool add = distribution9(engine) < 7;\ if(add)\ {\ int key = cnt++;\ int val = cnt++;\ - size_t size = (size_t)rand(1,100);\ - size_t cost = (size_t)rand(1,100);\ + size_t size = distribution(engine);\ + size_t cost = distribution(engine);\ c.add(key, val, size, cost);\ }\ else\ @@ -88,22 +91,25 @@ // [PT: disabled because it's far too slow] void DISABLED_test_cache_policies() { - Cache c1; + std::mt19937 engine(42); + std::uniform_int_distribution distribution9(0, 9); + std::uniform_int_distribution distribution99(1, 99); + + Cache c1; Cache c2; - Cache c3; + Cache c3; - srand(1); int cnt = 1; for(int i = 0; i < 1000; i++) { // 70% add (random objects) - bool add = rand(1,10) < 7; + const bool add = distribution9(engine) < 7; if(add) { int key = cnt++; int val = cnt++; - size_t size = (size_t)rand(1,100); - size_t cost = (size_t)rand(1,100); + size_t size = distribution99(engine); + size_t cost = distribution99(engine); c1.add(key, val, size, cost); c2.add(key, val, size, cost); c3.add(key, val, size, cost); diff -Nru 0ad-0.0.25b/source/lib/tests/test_fnv_hash.h 0ad-0.0.26/source/lib/tests/test_fnv_hash.h --- 0ad-0.0.25b/source/lib/tests/test_fnv_hash.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tests/test_fnv_hash.h 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -32,12 +32,18 @@ TS_ASSERT_EQUALS(fnv_hash(""), 0x811C9DC5u); // verify initial value const u32 h1 = fnv_hash("abcdef"); TS_ASSERT_EQUALS(h1, 0xFF478A2A); // verify value for simple string - TS_ASSERT_EQUALS(fnv_hash ("abcdef", 6), h1); // same result if hashing buffer - TS_ASSERT_EQUALS(fnv_lc_hash("ABcDeF", 6), h1); // same result if case differs + TS_ASSERT_EQUALS(fnv_hash("abcdef", 6), h1); // same result if hashing buffer TS_ASSERT_EQUALS(fnv_hash64(""), 0xCBF29CE484222325ull); // verify initial value const u64 h2 = fnv_hash64("abcdef"); TS_ASSERT_EQUALS(h2, 0xD80BDA3FBE244A0Aull); // verify value for simple string TS_ASSERT_EQUALS(fnv_hash64("abcdef", 6), h2); // same result if hashing buffer } + + void test_collisions() + { + TS_ASSERT_EQUALS(fnv_hash("collisions", 10), fnv_hash("silage_formism", 14)); + TS_ASSERT_EQUALS(fnv_hash("2018-04-13 06:10", 16), fnv_hash("1984-05-01 06:20", 16)); + TS_ASSERT_EQUALS(fnv_hash("etude", 5), fnv_hash("nonassister", 11)); + } }; diff -Nru 0ad-0.0.25b/source/lib/tex/tests/test_tex.h 0ad-0.0.26/source/lib/tex/tests/test_tex.h --- 0ad-0.0.25b/source/lib/tex/tests/test_tex.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tex/tests/test_tex.h 2022-08-21 12:45:17.000000000 +0000 @@ -0,0 +1,88 @@ +/* Copyright (C) 2021 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 "lib/self_test.h" + +#include "lib/tex/tex.h" +#include "lib/tex/tex_codec.h" +#include "lib/allocators/shared_ptr.h" + +#include + +class TestTex : public CxxTest::TestSuite +{ +public: + // have mipmaps be created for a test image; check resulting size and pixels + void test_mipmap_create() + { + static u8 imgData[] = { 0x10,0x20,0x30, 0x40,0x60,0x80, 0xA0,0xA4,0xA8, 0xC0,0xC1,0xC2 }; + std::shared_ptr img = DummySharedPtr(imgData); + // assumes 2x2 box filter algorithm with rounding + static const u8 mipmap[] = { 0x6C,0x79,0x87 }; + Tex t; + TS_ASSERT_OK(t.wrap(2, 2, 24, 0, img, 0)); + TS_ASSERT_OK(t.transform_to(TEX_MIPMAPS)); + const u8* const out_img = t.get_data(); + TS_ASSERT_EQUALS((int)t.img_size(), 12+3); + TS_ASSERT_SAME_DATA(out_img, imgData, 12); + TS_ASSERT_SAME_DATA(out_img+12, mipmap, 3); + } + + void test_img_size() + { + std::shared_ptr img(new u8[100*100*4], ArrayDeleter()); + + Tex t; + TS_ASSERT_OK(t.wrap(100, 100, 32, TEX_ALPHA, img, 0)); + TS_ASSERT_EQUALS((int)t.img_size(), 40000); + + // DXT rounds up to 4x4 blocks; DXT1a is 4bpp + Tex t2; + TS_ASSERT_OK(t2.wrap(97, 97, 4, DXT1A, img, 0)); + TS_ASSERT_EQUALS((int)t2.img_size(), 5000); + } + + void test_s3tc_decode() + { + const size_t w = 4, h = 4, bpp = 4; + const size_t size = w*h/2; + std::shared_ptr img(new u8[size], ArrayDeleter()); + memcpy(img.get(), "\xFF\xFF\x00\x00\x00\xAA\xFF\x55", 8); // gradient from white to black + const u8 expected[] = + "\xFF\xFF\xFF" "\xFF\xFF\xFF" "\xFF\xFF\xFF" "\xFF\xFF\xFF" + "\xAA\xAA\xAA" "\xAA\xAA\xAA" "\xAA\xAA\xAA" "\xAA\xAA\xAA" + "\x55\x55\x55" "\x55\x55\x55" "\x55\x55\x55" "\x55\x55\x55" + "\x00\x00\x00" "\x00\x00\x00" "\x00\x00\x00" "\x00\x00\x00"; + + const size_t flags = TEX_DXT&1; + + // wrap in Tex + Tex t; + TS_ASSERT_OK(t.wrap(w, h, bpp, flags, img, 0)); + + // decompress S3TC + TS_ASSERT_OK(t.transform_to(0)); + + // compare img + TS_ASSERT_SAME_DATA(t.get_data(), expected, 48); + } +}; diff -Nru 0ad-0.0.25b/source/lib/tex/tex_codec.cpp 0ad-0.0.26/source/lib/tex/tex_codec.cpp --- 0ad-0.0.25b/source/lib/tex/tex_codec.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tex/tex_codec.cpp 2022-09-23 19:16:47.000000000 +0000 @@ -67,7 +67,7 @@ { // we guarantee at least 4 bytes for is_hdr to look at if(file_size < 4) - WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER); + return ERR::TEX_INCOMPLETE_HEADER; for(int i = 0; i < codecs_len; ++i) { @@ -78,7 +78,7 @@ } } - WARN_RETURN(ERR::TEX_UNKNOWN_FORMAT); + return ERR::TEX_UNKNOWN_FORMAT; } Status tex_codec_transform(Tex* t, size_t transforms) diff -Nru 0ad-0.0.25b/source/lib/tex/tex.cpp 0ad-0.0.26/source/lib/tex/tex.cpp --- 0ad-0.0.25b/source/lib/tex/tex.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tex/tex.cpp 2022-09-23 19:16:48.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -20,26 +20,23 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* - * support routines for 2d texture access/writing. - */ - #include "precompiled.h" -#include "tex.h" -#include -#include -#include +#include "tex.h" -#include "lib/timer.h" -#include "lib/bits.h" #include "lib/allocators/shared_ptr.h" +#include "lib/bits.h" #include "lib/sysdep/cpu.h" +#include "lib/tex/tex_codec.h" +#include "lib/timer.h" -#include "tex_codec.h" - +#include +#include +#include -static const StatusDefinition texStatusDefinitions[] = { +static const StatusDefinition texStatusDefinitions[] = +{ + { ERR::TEX_UNKNOWN_FORMAT, L"Unknown texture format" }, { ERR::TEX_FMT_INVALID, L"Invalid/unsupported texture format" }, { ERR::TEX_INVALID_COLOR_TYPE, L"Invalid color type" }, { ERR::TEX_NOT_8BIT_PRECISION, L"Not 8-bit channel precision" }, @@ -60,33 +57,32 @@ Status Tex::validate() const { if(m_Flags & TEX_UNDEFINED_FLAGS) - WARN_RETURN(ERR::_1); + return ERR::_1; - // pixel data (only check validity if the image is still in memory; - // ogl_tex frees the data after uploading to GL) + // pixel data (only check validity if the image is still in memory). if(m_Data) { // file size smaller than header+pixels. // possible causes: texture file header is invalid, // or file wasn't loaded completely. if(m_DataSize < m_Ofs + m_Width*m_Height*m_Bpp/8) - WARN_RETURN(ERR::_2); + return ERR::_2; } // bits per pixel // (we don't bother checking all values; a sanity check is enough) if(m_Bpp % 4 || m_Bpp > 32) - WARN_RETURN(ERR::_3); + return ERR::_3; // flags // .. DXT value const size_t dxt = m_Flags & TEX_DXT; if(dxt != 0 && dxt != 1 && dxt != DXT1A && dxt != 3 && dxt != 5) - WARN_RETURN(ERR::_4); + return ERR::_4; // .. orientation const size_t orientation = m_Flags & TEX_ORIENTATION; if(orientation == (TEX_BOTTOM_UP|TEX_TOP_DOWN)) - WARN_RETURN(ERR::_5); + return ERR::_5; return INFO::OK; } @@ -254,7 +250,7 @@ { // this code assumes the image is of POT dimension; we don't // go to the trouble of implementing image scaling because - // the only place this is used (ogl_tex_upload) requires POT anyway. + // the only place this is used (backend textures) requires POT anyway. if(!is_pow2(w) || !is_pow2(h)) WARN_RETURN(ERR::TEX_INVALID_SIZE); t->m_Flags |= TEX_MIPMAPS; // must come before tex_img_size! @@ -286,10 +282,7 @@ // somewhat optimized (loops are hoisted, cache associativity accounted for) static Status plain_transform(Tex* t, size_t transforms) { -TIMER_ACCRUE(tc_plain_transform); - - // (this is also called directly instead of through ogl_tex, so - // we need to validate) + TIMER_ACCRUE(tc_plain_transform); CHECK_TEX(t); // extract texture info @@ -479,12 +472,14 @@ return INFO::OK; Status ret = tex_codec_transform(this, remaining_transforms); + UpdateMIPLevels(); if(ret != INFO::OK) break; } // last chance RETURN_STATUS_IF_ERR(plain_transform(this, remaining_transforms)); + UpdateMIPLevels(); return INFO::OK; } @@ -601,6 +596,9 @@ m_Ofs = ofs; CHECK_TEX(this); + + UpdateMIPLevels(); + return INFO::OK; } @@ -614,9 +612,7 @@ m_Data.reset(); - // do not zero out the fields! that could lead to trouble since - // ogl_tex_upload followed by ogl_tex_free is legit, but would - // cause OglTex_validate to fail (since its Tex.w is == 0). + // TODO: refactor fields zeroing. } @@ -633,7 +629,7 @@ u8* p = m_Data.get(); if(!p) - return 0; + return nullptr; return p + m_Ofs; } @@ -724,10 +720,10 @@ // make sure the entire header is available const size_t min_hdr_size = c->hdr_size(0); if(DataSize < min_hdr_size) - WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER); + return ERR::TEX_INCOMPLETE_HEADER; const size_t hdr_size = c->hdr_size(Data.get()); if(DataSize < hdr_size) - WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER); + return ERR::TEX_INCOMPLETE_HEADER; m_Data = Data; m_DataSize = DataSize; @@ -737,14 +733,16 @@ // sanity checks if(!m_Width || !m_Height || m_Bpp > 32) - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; if(m_DataSize < m_Ofs + img_size()) - WARN_RETURN(ERR::TEX_INVALID_SIZE); + return ERR::TEX_INVALID_SIZE; flip_to_global_orientation(this); CHECK_TEX(this); + UpdateMIPLevels(); + return INFO::OK; } @@ -775,3 +773,39 @@ return INFO::OK; } + +void Tex::UpdateMIPLevels() +{ + m_MIPLevels.clear(); + + if (m_Flags & TEX_MIPMAPS) + { + // We add one because we need to account the smallest 1x1 level. + m_MIPLevels.reserve(ceil_log2(std::max(m_Width, m_Height)) + 1); + } + + u8* levelData = m_Data.get(); + levelData += m_Ofs; + + const u32 dataPadding = (m_Flags & TEX_DXT) != 0 ? 4 : 1; + u32 levelWidth = m_Width, levelHeight = m_Height; + for (u32 level = 0; ; ++level) + { + const u32 levelDataSize = round_up(levelWidth, dataPadding) * round_up(levelHeight, dataPadding) * m_Bpp / 8; + m_MIPLevels.emplace_back(); + m_MIPLevels.back().data = levelData; + m_MIPLevels.back().dataSize = levelDataSize; + m_MIPLevels.back().width = levelWidth; + m_MIPLevels.back().height = levelHeight; + + if (!(m_Flags & TEX_MIPMAPS)) + break; + + if (levelWidth == 1 && levelHeight == 1) + break; + + levelData += levelDataSize; + levelWidth = std::max(levelWidth / 2, 1); + levelHeight = std::max(levelHeight / 2, 1); + } +} diff -Nru 0ad-0.0.25b/source/lib/tex/tex_dds.cpp 0ad-0.0.26/source/lib/tex/tex_dds.cpp --- 0ad-0.0.25b/source/lib/tex/tex_dds.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tex/tex_dds.cpp 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -397,7 +397,7 @@ // check struct size if(read_le32(&pf->dwSize) != sizeof(DDS_PIXELFORMAT)) - WARN_RETURN(ERR::TEX_INVALID_SIZE); + return ERR::TEX_INVALID_SIZE; // determine type const size_t pf_flags = (size_t)read_le32(&pf->dwFlags); @@ -432,7 +432,7 @@ // DDS is storing images in a format that requires no processing, // we do not allow any weird orderings that require runtime work. // instead, the artists must export with the correct settings. - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; } RETURN_STATUS_IF_ERR(tex_validate_plain_format(bpp, (int)flags)); @@ -446,10 +446,10 @@ bpp = pf_bpp; if(pf_bpp != 8) - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; if(pf_a_mask != 0xFF) - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; flags |= TEX_GREY; RETURN_STATUS_IF_ERR(tex_validate_plain_format(bpp, (int)flags)); @@ -480,12 +480,12 @@ break; default: - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; } } // .. neither uncompressed nor compressed - invalid else - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; return INFO::OK; } @@ -499,7 +499,7 @@ { // check header size if(read_le32(&sd->dwSize) != sizeof(*sd)) - WARN_RETURN(ERR::CORRUPTED); + return ERR::CORRUPTED; // flags (indicate which fields are valid) const size_t sd_flags = (size_t)read_le32(&sd->dwFlags); @@ -507,7 +507,7 @@ // note: we can't guess dimensions - the image may not be square. const size_t sd_req_flags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT; if((sd_flags & sd_req_flags) != sd_req_flags) - WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER); + return ERR::TEX_INCOMPLETE_HEADER; // image dimensions h = (size_t)read_le32(&sd->dwHeight); @@ -537,7 +537,7 @@ if(sd_flags & DDSD_PITCH) { if(sd_pitch_or_size != Align<4>(pitch)) - DEBUG_WARN_ERR(ERR::CORRUPTED); + return ERR::CORRUPTED; } if(sd_flags & DDSD_LINEARSIZE) { @@ -545,7 +545,7 @@ // so allow values close to that as well const ssize_t totalSize = ssize_t(pitch*stored_h*1.333333f); if(sd_pitch_or_size != pitch*stored_h && std::abs(ssize_t(sd_pitch_or_size)-totalSize) > 64) - DEBUG_WARN_ERR(ERR::CORRUPTED); + return ERR::CORRUPTED; } // note: both flags set would be invalid; no need to check for that, // though, since one of the above tests would fail. @@ -559,7 +559,7 @@ // mipmap chain is incomplete // note: DDS includes the base level in its count, hence +1. if(mipmap_count != ceil_log2(std::max(w,h))+1) - WARN_RETURN(ERR::TEX_FMT_INVALID); + return ERR::TEX_FMT_INVALID; flags |= TEX_MIPMAPS; } } @@ -569,17 +569,19 @@ { const size_t depth = (size_t)read_le32(&sd->dwDepth); if(depth) - WARN_RETURN(ERR::NOT_SUPPORTED); + return ERR::NOT_SUPPORTED; } // check caps // .. this is supposed to be set, but don't bail if not (pointless) - ENSURE(sd->dwCaps & DDSCAPS_TEXTURE); + if (!(sd->dwCaps & DDSCAPS_TEXTURE)) + return ERR::CORRUPTED; // .. sanity check: warn if mipmap flag not set (don't bail if not // because we've already made the decision). const bool mipmap_cap = (sd->dwCaps & DDSCAPS_MIPMAP) != 0; const bool mipmap_flag = (flags & TEX_MIPMAPS) != 0; - ENSURE(mipmap_cap == mipmap_flag); + if (mipmap_cap != mipmap_flag) + return ERR::CORRUPTED; // note: we do not check for cubemaps and volume textures (not supported) // because the file may still have useful data we can read. diff -Nru 0ad-0.0.25b/source/lib/tex/tex.h 0ad-0.0.26/source/lib/tex/tex.h --- 0ad-0.0.25b/source/lib/tex/tex.h 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tex/tex.h 2022-09-23 19:16:48.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -104,11 +104,11 @@ #ifndef INCLUDED_TEX #define INCLUDED_TEX -#include "lib/res/handle.h" #include "lib/os_path.h" #include "lib/file/vfs/vfs_path.h" #include "lib/allocators/dynarray.h" +#include namespace ERR { @@ -202,12 +202,21 @@ }; /** - * stores all data describing an image. - * we try to minimize size, since this is stored in OglTex resources - * (which are big and pushing the h_mgr limit). + * Stores all data describing an image. + * TODO: rename to TextureData. **/ -struct Tex +class Tex { +public: + struct MIPLevel + { + // A pointer to the mip level image data (pixels). + u8* data; + u32 dataSize; + u32 width; + u32 height; + }; + /** * file buffer or image data. note: during the course of transforms * (which may occur when being loaded), this may be replaced with @@ -328,10 +337,12 @@ * return a pointer to the image data (pixels), taking into account any * header(s) that may come before it. * - * @return pointer to data returned by mem_get_ptr (holds reference)! + * @return pointer to the data. **/ u8* get_data(); + const std::vector& GetMIPLevels() const { return m_MIPLevels; } + /** * return the ARGB value of the 1x1 mipmap level of the texture. * @@ -348,6 +359,10 @@ **/ size_t img_size() const; +private: + void UpdateMIPLevels(); + + std::vector m_MIPLevels; }; diff -Nru 0ad-0.0.25b/source/lib/tex/tex_png.cpp 0ad-0.0.26/source/lib/tex/tex_png.cpp --- 0ad-0.0.25b/source/lib/tex/tex_png.cpp 2021-07-27 21:57:00.000000000 +0000 +++ 0ad-0.0.26/source/lib/tex/tex_png.cpp 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -271,7 +271,7 @@ // limitation: palette images aren't supported Status TexCodecPng::decode(u8* RESTRICT data, size_t size, Tex* RESTRICT t) const { -TIMER_ACCRUE(tc_png_decode); + TIMER_ACCRUE(tc_png_decode); png_infop info_ptr = 0; @@ -279,19 +279,19 @@ // warning handler to filter out useless messages png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, user_warning_fn); if(!png_ptr) - WARN_RETURN(ERR::FAIL); + return ERR::FAIL; info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, 0); - WARN_RETURN(ERR::NO_MEM); + return ERR::NO_MEM; } // setup error handling if(setjmp(png_jmpbuf(png_ptr))) { // libpng longjmps here after an error png_destroy_read_struct(&png_ptr, &info_ptr, 0); - WARN_RETURN(ERR::FAIL); + return ERR::FAIL; } MemoryStream stream(data, size); diff -Nru 0ad-0.0.25b/source/lib/timer.h 0ad-0.0.26/source/lib/timer.h --- 0ad-0.0.25b/source/lib/timer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/lib/timer.h 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -41,17 +41,17 @@ /** * timer_Time will subsequently return values relative to the current time. **/ -LIB_API void timer_Init(); +void timer_Init(); /** * @return high resolution (> 1 us) timestamp [s]. **/ -LIB_API double timer_Time(); +double timer_Time(); /** * @return resolution [s] of the timer. **/ -LIB_API double timer_Resolution(); +double timer_Resolution(); // (allow using XADD (faster than CMPXCHG) in 64-bit builds without casting) @@ -65,8 +65,8 @@ * internal helper functions for returning an easily readable * string (i.e. re-scaled to appropriate units) **/ -LIB_API std::string StringForSeconds(double seconds); -LIB_API std::string StringForCycles(Cycles cycles); +std::string StringForSeconds(double seconds); +std::string StringForCycles(Cycles cycles); //----------------------------------------------------------------------------- @@ -299,7 +299,7 @@ * - free() is not needed nor possible. * - description must remain valid until exit; a string literal is safest. **/ -LIB_API TimerClient* timer_AddClient(TimerClient* tc, const wchar_t* description); +TimerClient* timer_AddClient(TimerClient* tc, const wchar_t* description); /** * "allocate" a new TimerClient that will keep track of the total time @@ -343,7 +343,7 @@ * display all clients' totals; does not reset them. * typically called at exit. **/ -LIB_API void timer_DisplayClientTotals(); +void timer_DisplayClientTotals(); /// used by TIMER_ACCRUE diff -Nru 0ad-0.0.25b/source/lib/utf8.h 0ad-0.0.26/source/lib/utf8.h --- 0ad-0.0.25b/source/lib/utf8.h 2021-07-27 21:57:01.000000000 +0000 +++ 0ad-0.0.26/source/lib/utf8.h 2022-08-21 12:45:18.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -44,11 +44,11 @@ * otherwise, the function raises a warning dialog for every * error/warning. **/ -LIB_API std::wstring wstring_from_utf8(const std::string& s, Status* err = 0); +std::wstring wstring_from_utf8(const std::string& s, Status* err = 0); /** * opposite of wstring_from_utf8 **/ -LIB_API std::string utf8_from_wstring(const std::wstring& s, Status* err = 0); +std::string utf8_from_wstring(const std::wstring& s, Status* err = 0); #endif // #ifndef INCLUDED_UTF8 diff -Nru 0ad-0.0.25b/source/main.cpp 0ad-0.0.26/source/main.cpp --- 0ad-0.0.25b/source/main.cpp 2021-08-22 18:37:36.000000000 +0000 +++ 0ad-0.0.26/source/main.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,7 +36,6 @@ #include "lib/secure_crt.h" #include "lib/frequency_filter.h" #include "lib/input.h" -#include "lib/ogl.h" #include "lib/timer.h" #include "lib/external_libraries/libsdl.h" @@ -75,6 +74,7 @@ #include "graphics/GameView.h" #include "graphics/TextureManager.h" #include "gui/GUIManager.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" #include "rlinterface/RLInterface.h" #include "scriptinterface/ScriptContext.h" @@ -99,13 +99,28 @@ #define getpid _getpid // Use the non-deprecated function name #endif +#if OS_WIN +// We don't want to include Windows.h as it might mess up the rest +// of the file so we just define DWORD as done in Windef.h. +#ifndef DWORD +typedef unsigned long DWORD; +#endif // !DWORD +// Request the high performance GPU on Windows by default if no system override is specified. +// See: +// - https://github.com/supertuxkart/stk-code/pull/4693/commits/0a99c667ef513b2ce0f5755729a6e05df8aac48a +// - https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm +// - https://gpuopen.com/learn/amdpowerxpressrequesthighperformance/ +extern "C" +{ + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; +} +#endif + #include extern CStrW g_UniqueLogPostfix; -// Marks terrain as modified so the minimap can repaint (is there a cleaner way of handling this?) -bool g_GameRestarted = false; - // Determines the lifetime of the mainloop enum ShutdownType { @@ -162,12 +177,6 @@ case SDL_WINDOWEVENT: switch(ev->ev.window.event) { - case SDL_WINDOWEVENT_ENTER: - RenderCursor(true); - break; - case SDL_WINDOWEVENT_LEAVE: - RenderCursor(false); - break; case SDL_WINDOWEVENT_RESIZED: g_ResizedW = ev->ev.window.data1; g_ResizedH = ev->ev.window.data2; @@ -209,19 +218,12 @@ } else if (hotkey == "screenshot") { - WriteScreenshot(L".png"); + g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::DEFAULT); return IN_HANDLED; } else if (hotkey == "bigscreenshot") { - int tiles = 4, tileWidth = 256, tileHeight = 256; - CFG_GET_VAL("screenshot.tiles", tiles); - CFG_GET_VAL("screenshot.tilewidth", tileWidth); - CFG_GET_VAL("screenshot.tileheight", tileHeight); - if (tiles > 0 && tileWidth > 0 && tileHeight > 0) - WriteBigScreenshot(L".bmp", tiles, tileWidth, tileHeight); - else - LOGWARNING("Invalid big screenshot size: tiles=%d tileWidth=%d tileHeight=%d", tiles, tileWidth, tileHeight); + g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::BIG); return IN_HANDLED; } else if (hotkey == "togglefullscreen") @@ -278,7 +280,7 @@ CFG_GET_VAL(g_Game && g_Game->IsGameStarted() ? "adaptivefps.session" : "adaptivefps.menu", fpsLimit); // Keep in sync with options.json - if (fpsLimit < 20.0 || fpsLimit >= 100.0) + if (fpsLimit < 20.0 || fpsLimit >= 360.0) return; double wait = 1000.0 / fpsLimit - @@ -332,7 +334,7 @@ CancelLoad(CStr(e.what()).FromUTF8()); } - GUI_DisplayLoadProgress(progress_percent, description); + g_GUI->DisplayLoadProgress(progress_percent, description); return 0; } @@ -358,8 +360,6 @@ g_Profiler2.IncrementFrameNumber(); PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); - ogl_WarnIfError(); - // get elapsed time const double time = timer_Time(); g_frequencyFilter->Update(time); @@ -417,12 +417,8 @@ if (g_NetClient) g_NetClient->Poll(); - ogl_WarnIfError(); - g_GUI->TickObjects(); - ogl_WarnIfError(); - if (g_RLInterface) g_RLInterface->TryApplyMessage(); @@ -441,28 +437,14 @@ g_UserReporter.Update(); g_Console->Update(realTimeSinceLastFrame); - ogl_WarnIfError(); if (g_SoundManager) g_SoundManager->IdleTask(); - if (ShouldRender()) - { - Render(); - - { - PROFILE3("swap buffers"); - SDL_GL_SwapWindow(g_VideoMode.GetWindow()); - ogl_WarnIfError(); - } - - g_Renderer.OnSwapBuffers(); - } + g_Renderer.RenderFrame(true); g_Profiler.Frame(); - g_GameRestarted = false; - LimitFPS(); } @@ -473,10 +455,13 @@ g_Profiler2.IncrementFrameNumber(); PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); - static u32 turn = 0; - debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH); + if (g_NetClient) + g_NetClient->Poll(); - g_Game->GetSimulation2()->Update(DEFAULT_TURN_LENGTH); + static u32 turn = 0; + if (g_Game && g_Game->IsGameStarted() && g_Game->GetTurnManager()) + if (g_Game->GetTurnManager()->Update(DEFAULT_TURN_LENGTH, 1)) + debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH); g_Profiler.Frame(); @@ -523,7 +508,7 @@ return; } - if (args.Has("autostart-nonvisual") && args.Get("autostart").empty() && !args.Has("rl-interface")) + if (args.Has("autostart-nonvisual") && args.Get("autostart").empty() && !args.Has("rl-interface") && !args.Has("autostart-client")) { LOGERROR("-autostart-nonvisual cant be used alone. A map with -autostart=\"TYPEDIR/MAPNAME\" is needed."); return; @@ -679,8 +664,9 @@ if (isNonVisual) { - InitNonVisual(args); - if (isUsingRLInterface) + if (!InitNonVisual(args)) + g_Shutdown = ShutdownType::Quit; + else if (isUsingRLInterface) StartRLInterface(args); while (g_Shutdown == ShutdownType::None) diff -Nru 0ad-0.0.25b/source/maths/Fixed.h 0ad-0.0.26/source/maths/Fixed.h --- 0ad-0.0.25b/source/maths/Fixed.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/Fixed.h 2022-08-21 12:45:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,9 +20,7 @@ #include "lib/types.h" #include "maths/Sqrt.h" - -class CStr8; -class CStrW; +#include "ps/CStrForward.h" #ifndef NDEBUG #define USE_FIXED_OVERFLOW_CHECKS @@ -144,6 +142,12 @@ return CFixed(n << fract_bits); } + // TODO C++20: this won't be necessary when operator/(int) can be made constexpr. + static constexpr CFixed FromFraction(int n, int d) + { + return CFixed(static_cast(static_cast(n) << fract_bits) / d); + } + static constexpr CFixed FromFloat(float n) { if (!std::isfinite(n)) diff -Nru 0ad-0.0.25b/source/maths/MathUtil.h 0ad-0.0.26/source/maths/MathUtil.h --- 0ad-0.0.25b/source/maths/MathUtil.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/MathUtil.h 2022-08-21 12:45:41.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,13 +22,13 @@ #define RADTODEG(a) ((a) * (180.0f/(float)M_PI)) #define SQR(x) ((x) * (x)) -template +template inline T Interpolate(const T& a, const T& b, float t) { return a + (b - a) * t; } -template +template inline T Clamp(T value, T min, T max) { if (value <= min) @@ -38,13 +38,21 @@ return value; } -inline float sgn(float a) +template +inline T SmoothStep(T edge0, T edge1, T value) { - if (a > 0.0f) - return 1.0f; - if (a < 0.0f) - return -1.0f; - return 0.0f; + value = Clamp((value - edge0) / (edge1 - edge0), 0, 1); + return value * value * (3 - 2 * value); +} + +template +inline T Sign(const T value) +{ + if (value > T(0)) + return T(1); + if (value < T(0)) + return T(-1); + return T(0); } #endif // INCLUDED_MATHUTIL diff -Nru 0ad-0.0.25b/source/maths/Matrix3D.h 0ad-0.0.26/source/maths/Matrix3D.h --- 0ad-0.0.25b/source/maths/Matrix3D.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/Matrix3D.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,10 +25,10 @@ #include "maths/Vector3D.h" #include "maths/Vector4D.h" +#include "ps/containers/Span.h" class CQuaternion; -///////////////////////////////////////////////////////////////////////// // CMatrix3D: a 4x4 matrix class for common operations in 3D class CMatrix3D { @@ -37,8 +37,10 @@ // or via a flat or 2d array // NOTE: _xy means row x, column y in the mathematical notation of this matrix, so don't be // fooled by the way they're listed below - union { - struct { + union + { + struct + { float _11, _21, _31, _41; float _12, _22, _32, _42; float _13, _23, _33, _43; @@ -181,7 +183,7 @@ void SetIdentity(); // set this matrix to the zero matrix void SetZero(); - // set this matrix to the orthogonal projection matrix (as with glOrtho) + // set this matrix to the orthogonal projection matrix void SetOrtho(float left, float right, float bottom, float top, float near, float far); // set this matrix to the perspective projection matrix void SetPerspective(float fov, float aspect, float near, float far); @@ -320,6 +322,20 @@ // rotate a vector by the transpose of this matrix void RotateTransposed(const CVector3D& vector,CVector3D& result) const; CVector3D RotateTransposed(const CVector3D& vector) const; + + // Returns 16 element array of floats, e.g. for mat4 uniforms. + PS::span AsFloatArray() const + { + // Additional check to prevent a weird compiler has a different + // alignement for an array and a class members. + static_assert( + sizeof(CMatrix3D) == sizeof(float) * 16u && + offsetof(CMatrix3D, _data) == 0 && + offsetof(CMatrix3D, _11) == 0 && + offsetof(CMatrix3D, _44) == sizeof(float) * 15u, + "CMatrix3D should be properly layouted to use AsFloatArray"); + return PS::span(_data, 16); + } }; #endif // INCLUDED_MATRIX3D diff -Nru 0ad-0.0.25b/source/maths/Noise.cpp 0ad-0.0.26/source/maths/Noise.cpp --- 0ad-0.0.25b/source/maths/Noise.cpp 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/Noise.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/* Copyright (C) 2009 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* - * 2D and 3D seamless Perlin noise - */ - -// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html -// and http://mrl.nyu.edu/~perlin/paper445.pdf. -// Not optimized for speed yet. - -#include "precompiled.h" -#include "Noise.h" -#include -#include - -namespace -{ - /// Random number generator (Boost Mersenne Twister) - boost::mt19937 rng; - - /// Utility function for random numbers - float randFloat() { - return ((float)rng()) / 4294967296.0f; - } - - /// Utility function used in both noises as an ease curve - float easeCurve(float t) - { - return t*t*t*(t*(t*6-15)+10); - } -} - -Noise2D::Noise2D(int f) -{ - freq = f; - grads = new CVector2D*[freq]; - for(int i=0; i 1 || vec.LengthSquared() < 0.1); - vec.Normalize(); - grads[i][j][k] = CVector3D(vec.X, vec.Y, vec.Z); - } - } - } -} - -Noise3D::~ Noise3D() -{ - for(int i=0; i. - */ - -/* - * 2D and 3D seamless Perlin noise - */ - -// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html -// and http://mrl.nyu.edu/~perlin/paper445.pdf. -// Not optimized for speed yet. - -#ifndef INCLUDED_NOISE -#define INCLUDED_NOISE - -#include "Vector2D.h" -#include "Vector3D.h" -#include "MathUtil.h" - -class Noise2D -{ - NONCOPYABLE(Noise2D); - - /// Frequency in X and Y - int freq; - - /// freq*freq random gradient vectors in the unit cube - CVector2D** grads; -public: - Noise2D(int freq); - ~Noise2D(); - - /// Evaluate the noise function at a given point - float operator() (float x, float y); -}; - -class Noise3D -{ - NONCOPYABLE(Noise3D); - - /// Frequency in X and Y - int freq; - - /// Frequency in Z (vertical frequency) - int vfreq; - - /// freq*freq*vfreq random gradient vectors in the unit cube - CVector3D*** grads; -public: - Noise3D(int freq, int vfreq); - ~Noise3D(); - - /// Evaluate the noise function at a given point - float operator() (float x, float y, float z); -}; - -#endif diff -Nru 0ad-0.0.25b/source/maths/tests/test_Fixed.h 0ad-0.0.26/source/maths/tests/test_Fixed.h --- 0ad-0.0.25b/source/maths/tests/test_Fixed.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/tests/test_Fixed.h 2022-08-21 12:45:41.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,6 +17,11 @@ #include "lib/self_test.h" +#include "lib/sysdep/compiler.h" +#if MSC_VERSION +# pragma warning(push, 1) +# pragma warning(disable: 4724) +#endif #include "maths/Fixed.h" #include "maths/MathUtil.h" @@ -42,6 +47,14 @@ TS_ASSERT_EQUALS(a.ToInt_RoundToZero(), 123); } + void test_FromFraction() + { + TS_ASSERT_EQUALS(fixed::FromFraction(340, 10), fixed::FromInt(340) / 10); + TS_ASSERT_EQUALS(fixed::FromFraction(-5, 11), fixed::FromInt(-5) / 11); + TS_ASSERT_EQUALS(fixed::FromFraction(4, -3), fixed::FromInt(4) / -3); + TS_ASSERT_EQUALS(fixed::FromFraction(2, 3), fixed::FromInt(2) / 3); + } + void test_FromFloat() { fixed a = fixed::FromFloat(123.125f); @@ -219,6 +232,7 @@ TS_ASSERT_EQUALS((fixed::FromDouble(5.5) % fixed::FromInt(4)).ToDouble(), 1.5); TS_ASSERT_EQUALS((fixed::FromDouble(1.75) % fixed::FromDouble(0.5)).ToDouble(), 0.25); + TS_ASSERT_EQUALS((fixed::FromFloat(1.75) % fixed::FromFloat(0.5)).ToFloat(), 0.25f); } void test_Sqrt() @@ -320,3 +334,7 @@ TS_ASSERT_LESS_THAN(err, 0.00046); } }; + +#if MSC_VERSION +# pragma warning(pop) +#endif diff -Nru 0ad-0.0.25b/source/maths/tests/test_Matrix3d.h 0ad-0.0.26/source/maths/tests/test_Matrix3d.h --- 0ad-0.0.25b/source/maths/tests/test_Matrix3d.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/tests/test_Matrix3d.h 2022-08-21 12:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,23 +17,32 @@ #include "lib/self_test.h" -#include -#include #include "maths/Matrix3D.h" #include "maths/Quaternion.h" +#include +#include +#include + class TestMatrix : public CxxTest::TestSuite { + std::mt19937 m_Engine; + public: + void setUp() + { + m_Engine = std::mt19937(42); + } + void test_inverse() { CMatrix3D m; - srand(0); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); for (int i = 0; i < 4; ++i) { for (int j = 0; j < 16; ++j) { - m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX); + m._data[j] = -1.0f + 2.0f * distribution01(m_Engine); } CMatrix3D n; m.GetInverse(n); @@ -52,14 +61,14 @@ void test_quats() { - srand(0); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); for (int i = 0; i < 4; ++i) { CQuaternion q; q.FromEulerAngles( - -6.28f + 12.56f*(rand()/(float)RAND_MAX), - -6.28f + 12.56f*(rand()/(float)RAND_MAX), - -6.28f + 12.56f*(rand()/(float)RAND_MAX) + -6.28f + 12.56f * distribution01(m_Engine), + -6.28f + 12.56f * distribution01(m_Engine), + -6.28f + 12.56f * distribution01(m_Engine) ); CMatrix3D m; q.ToMatrix(m); @@ -83,11 +92,11 @@ void test_rotate() { - CMatrix3D m; - srand(0); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); + CMatrix3D m; for (int j = 0; j < 16; ++j) - m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX); + m._data[j] = -1.0f + 2.0f * distribution01(m_Engine); CMatrix3D r, a, b; @@ -124,8 +133,9 @@ void test_getRotation() { + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); + CMatrix3D m; - srand(0); m.SetZero(); TS_ASSERT_EQUALS(m.GetYRotation(), 0.f); @@ -135,7 +145,7 @@ for (int j = 0; j < 16; ++j) { - float a = 2*M_PI*rand()/(float)RAND_MAX - M_PI; + float a = 2 * M_PI * distribution01(m_Engine) - M_PI; m.SetYRotation(a); TS_ASSERT_DELTA(m.GetYRotation(), a, 0.001f); } @@ -143,11 +153,12 @@ void test_scale() { + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); + CMatrix3D m; - srand(0); for (int j = 0; j < 16; ++j) - m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX); + m._data[j] = -1.0f + 2.0f * distribution01(m_Engine); CMatrix3D s, a, b; diff -Nru 0ad-0.0.25b/source/maths/Vector3D.h 0ad-0.0.26/source/maths/Vector3D.h --- 0ad-0.0.25b/source/maths/Vector3D.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/Vector3D.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,8 @@ #ifndef INCLUDED_VECTOR3D #define INCLUDED_VECTOR3D +#include "ps/containers/Span.h" + class CFixedVector3D; class CVector3D @@ -120,8 +122,19 @@ void Normalize(); CVector3D Normalized() const; - // Returns 3 element array of floats, e.g. for glVertex3fv - const float* GetFloatArray() const { return &X; } + // Returns 3 element array of floats, e.g. for vec3 uniforms. + PS::span AsFloatArray() const + { + // Additional check to prevent a weird compiler has a different + // alignement for an array and a class members. + static_assert( + sizeof(CVector3D) == sizeof(float) * 3u && + offsetof(CVector3D, X) == 0 && + offsetof(CVector3D, Y) == sizeof(float) && + offsetof(CVector3D, Z) == sizeof(float) * 2u, + "Vector3D should be properly layouted to use AsFloatArray"); + return PS::span(&X, 3); + } }; extern float MaxComponent(const CVector3D& v); diff -Nru 0ad-0.0.25b/source/maths/Vector4D.h 0ad-0.0.26/source/maths/Vector4D.h --- 0ad-0.0.25b/source/maths/Vector4D.h 2021-07-27 21:57:04.000000000 +0000 +++ 0ad-0.0.26/source/maths/Vector4D.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,8 @@ #ifndef INCLUDED_VECTOR4D #define INCLUDED_VECTOR4D +#include "ps/containers/Span.h" + #include class CVector4D @@ -124,8 +126,20 @@ return X*a.X + Y*a.Y + Z*a.Z + W*a.W; } + // Returns 4 element array of floats, e.g. for vec4 uniforms. + PS::span AsFloatArray() const + { + // Additional check to prevent a weird compiler has a different + // alignement for an array and a class members. + static_assert( + sizeof(CVector4D) == sizeof(float) * 4u && + offsetof(CVector4D, X) == 0 && + offsetof(CVector4D, W) == sizeof(float) * 3u, + "CVector4D should be properly layouted to use AsFloatArray"); + return PS::span(&X, 4); + } float X, Y, Z, W; }; -#endif +#endif // INCLUDED_VECTOR4D diff -Nru 0ad-0.0.25b/source/network/NetClient.cpp 0ad-0.0.26/source/network/NetClient.cpp --- 0ad-0.0.25b/source/network/NetClient.cpp 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/network/NetClient.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -201,7 +201,8 @@ CNetClientSession* session = new CNetClientSession(*this); bool ok = session->Connect(m_ServerAddress, m_ServerPort, enetClient); SetAndOwnSession(session); - m_PollingThread = std::thread(Threading::HandleExceptions::Wrapper, m_Session); + if (ok) + m_PollingThread = std::thread(Threading::HandleExceptions::Wrapper, m_Session); return ok; } @@ -258,7 +259,7 @@ } CStr ip; - u16 port; + u16 port = 0; if (g_XmppClient && m_UseSTUN) { if (!StunClient::FindPublicIP(*enetClient, ip, port)) diff -Nru 0ad-0.0.25b/source/network/NetClient.h 0ad-0.0.26/source/network/NetClient.h --- 0ad-0.0.25b/source/network/NetClient.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/network/NetClient.h 2022-08-21 12:45:46.000000000 +0000 @@ -32,7 +32,6 @@ class CGame; class CNetClientSession; class CNetClientTurnManager; -class CNetServer; class ScriptInterface; typedef struct _ENetHost ENetHost; diff -Nru 0ad-0.0.25b/source/network/NetFileTransfer.h 0ad-0.0.26/source/network/NetFileTransfer.h --- 0ad-0.0.25b/source/network/NetFileTransfer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/network/NetFileTransfer.h 2022-08-21 12:45:46.000000000 +0000 @@ -25,8 +25,6 @@ class CFileTransferResponseMessage; class CFileTransferDataMessage; class CFileTransferAckMessage; -class CNetClientSession; -class CNetServerSession; class INetSession; // Assume this is sufficiently less than MTU that packets won't get diff -Nru 0ad-0.0.25b/source/network/NetServer.cpp 0ad-0.0.26/source/network/NetServer.cpp --- 0ad-0.0.25b/source/network/NetServer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/network/NetServer.cpp 2022-09-23 19:17:14.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -145,8 +145,7 @@ * See http://trac.wildfiregames.com/ticket/654 */ -CNetServerWorker::CNetServerWorker(bool useLobbyAuth, int autostartPlayers) : - m_AutostartPlayers(autostartPlayers), +CNetServerWorker::CNetServerWorker(bool useLobbyAuth) : m_LobbyAuth(useLobbyAuth), m_Shutdown(false), m_ScriptInterface(NULL), @@ -429,10 +428,6 @@ if (!RunStep()) break; - // Implement autostart mode - if (m_State == SERVER_STATE_PREGAME && (int)m_PlayerAssignments.size() == m_AutostartPlayers) - StartGame(Script::StringifyJSON(ScriptRequest(m_ScriptInterface), &m_InitAttributes)); - // Update profiler stats m_Stats->LatchHostState(m_Host); } @@ -1624,8 +1619,8 @@ -CNetServer::CNetServer(bool useLobbyAuth, int autostartPlayers) : - m_Worker(new CNetServerWorker(useLobbyAuth, autostartPlayers)), +CNetServer::CNetServer(bool useLobbyAuth) : + m_Worker(new CNetServerWorker(useLobbyAuth)), m_LobbyAuth(useLobbyAuth), m_UseSTUN(false), m_PublicIp(""), m_PublicPort(20595), m_Password() { } diff -Nru 0ad-0.0.25b/source/network/NetServer.h 0ad-0.0.26/source/network/NetServer.h --- 0ad-0.0.25b/source/network/NetServer.h 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/network/NetServer.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -110,10 +110,9 @@ public: /** * Construct a new network server. - * @param autostartPlayers - if positive then StartGame will be called automatically * once this many players are connected (intended for the command-line testing mode). */ - CNetServer(bool useLobbyAuth = false, int autostartPlayers = -1); + CNetServer(bool useLobbyAuth = false); ~CNetServer(); @@ -236,7 +235,7 @@ friend class CNetServer; friend class CNetFileReceiveTask_ServerRejoin; - CNetServerWorker(bool useLobbyAuth, int autostartPlayers); + CNetServerWorker(bool useLobbyAuth); ~CNetServerWorker(); bool CheckPassword(const std::string& password, const std::string& salt) const; @@ -350,8 +349,6 @@ */ JS::PersistentRootedValue m_InitAttributes; - int m_AutostartPlayers; - /** * Whether this match requires lobby authentication. */ diff -Nru 0ad-0.0.25b/source/network/scripting/JSInterface_Network.cpp 0ad-0.0.26/source/network/scripting/JSInterface_Network.cpp --- 0ad-0.0.25b/source/network/scripting/JSInterface_Network.cpp 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/network/scripting/JSInterface_Network.cpp 2022-09-23 19:17:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -62,7 +62,7 @@ return !!g_NetClient; } -void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u16 serverPort, bool useSTUN, const CStr& password) +void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u16 serverPort, bool useSTUN, const CStr& password, bool storeReplay) { ENSURE(!g_NetClient); ENSURE(!g_NetServer); @@ -100,7 +100,7 @@ std::string secret = ps_generate_guid(); g_NetServer->SetControllerSecret(secret); - g_Game = new CGame(true); + g_Game = new CGame(storeReplay); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(playerName); @@ -141,13 +141,13 @@ } } -void StartNetworkJoin(const ScriptRequest& rq, const CStrW& playerName, const CStr& serverAddress, u16 serverPort) +void StartNetworkJoin(const ScriptRequest& rq, const CStrW& playerName, const CStr& serverAddress, u16 serverPort, bool storeReplay) { ENSURE(!g_NetClient); ENSURE(!g_NetServer); ENSURE(!g_Game); - g_Game = new CGame(true); + g_Game = new CGame(storeReplay); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(playerName); g_NetClient->SetupServerData(serverAddress, serverPort, false); diff -Nru 0ad-0.0.25b/source/network/StunClient.h 0ad-0.0.26/source/network/StunClient.h --- 0ad-0.0.25b/source/network/StunClient.h 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/network/StunClient.h 2022-08-21 12:45:46.000000000 +0000 @@ -19,11 +19,11 @@ #ifndef STUNCLIENT_H #define STUNCLIENT_H +#include "ps/CStrForward.h" + #include typedef struct _ENetHost ENetHost; -class ScriptInterface; -class CStr8; namespace StunClient { diff -Nru 0ad-0.0.25b/source/network/tests/test_Net.h 0ad-0.0.26/source/network/tests/test_Net.h --- 0ad-0.0.25b/source/network/tests/test_Net.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/network/tests/test_Net.h 2022-08-21 12:45:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -44,11 +44,6 @@ TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); CXeromyces::Startup(); - // Need some stuff for terrain movement costs: - // (TODO: this ought to be independent of any graphics code) - new CTerrainTextureManager; - g_TexMan.LoadTerrainTextures(); - enet_initialize(); } @@ -56,8 +51,6 @@ { enet_deinitialize(); - delete &g_TexMan; - CXeromyces::Terminate(); g_VFS.reset(); DeleteDirectory(DataDir()/"_testcache"); diff -Nru 0ad-0.0.25b/source/ps/ArchiveBuilder.cpp 0ad-0.0.26/source/ps/ArchiveBuilder.cpp --- 0ad-0.0.25b/source/ps/ArchiveBuilder.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/ArchiveBuilder.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "lib/file/archive/archive_zip.h" #include "lib/file/vfs/vfs_util.h" #include "ps/XML/Xeromyces.h" +#include "renderer/backend/dummy/Device.h" #include @@ -76,7 +77,8 @@ // Use CTextureManager instead of CTextureConverter directly, // so it can deal with all the loading of settings.xml files - CTextureManager textureManager(m_VFS, true, true); + Renderer::Backend::Dummy::CDevice device; + CTextureManager textureManager(m_VFS, true, &device); CColladaManager colladaManager(m_VFS); diff -Nru 0ad-0.0.25b/source/ps/CConsole.cpp 0ad-0.0.26/source/ps/CConsole.cpp --- 0ad-0.0.25b/source/ps/CConsole.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/CConsole.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,12 +15,7 @@ * along with 0 A.D. If not, see . */ -/* - * Implements the in-game console with scripting support. - */ - #include "precompiled.h" -#include #include "CConsole.h" @@ -29,13 +24,10 @@ #include "graphics/TextRenderer.h" #include "gui/CGUI.h" #include "gui/GUIManager.h" -#include "gui/GUIMatrix.h" -#include "lib/ogl.h" +#include "lib/code_generation.h" #include "lib/timer.h" #include "lib/utf8.h" #include "maths/MathUtil.h" -#include "network/NetClient.h" -#include "network/NetServer.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" @@ -45,10 +37,12 @@ #include "ps/Hotkey.h" #include "ps/Profile.h" #include "ps/Pyrogenesis.h" +#include "ps/VideoMode.h" #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/JSON.h" #include +#include namespace { @@ -64,29 +58,28 @@ CConsole::CConsole() { - m_bToggle = false; - m_bVisible = false; + m_Toggle = false; + m_Visible = false; - m_fVisibleFrac = 0.0f; + m_VisibleFrac = 0.0f; - m_szBuffer = new wchar_t[CONSOLE_BUFFER_SIZE]; + m_Buffer = std::make_unique(CONSOLE_BUFFER_SIZE); FlushBuffer(); - m_iMsgHistPos = 1; - m_charsPerPage = 0; + m_MsgHistPos = 1; + m_CharsPerPage = 0; - m_prevTime = 0.0; - m_bCursorVisState = true; - m_cursorBlinkRate = 0.5; + m_PrevTime = 0.0; + m_CursorVisState = true; + m_CursorBlinkRate = 0.5; - InsertMessage("[ 0 A.D. Console v0.14 ]"); + m_QuitHotkeyWasShown = false; + + InsertMessage("[ 0 A.D. Console v0.15 ]"); InsertMessage(""); } -CConsole::~CConsole() -{ - delete[] m_szBuffer; -} +CConsole::~CConsole() = default; void CConsole::Init() { @@ -94,105 +87,123 @@ m_MaxHistoryLines = 200; CFG_GET_VAL("console.history.size", m_MaxHistoryLines); - m_sHistoryFile = L"config/console.txt"; + m_HistoryFile = L"config/console.txt"; LoadHistory(); UpdateScreenSize(g_xres, g_yres); // Calculate and store the line spacing const CFontMetrics font{CStrIntern(CONSOLE_FONT)}; - m_iFontHeight = font.GetLineSpacing(); - m_iFontWidth = font.GetCharacterWidth(L'C'); - m_charsPerPage = static_cast(g_xres / m_iFontWidth); + m_FontHeight = font.GetLineSpacing(); + m_FontWidth = font.GetCharacterWidth(L'C'); + m_CharsPerPage = static_cast(g_xres / m_FontWidth); // Offset by an arbitrary amount, to make it fit more nicely - m_iFontOffset = 7; + m_FontOffset = 7; - m_cursorBlinkRate = 0.5; - CFG_GET_VAL("gui.cursorblinkrate", m_cursorBlinkRate); + m_CursorBlinkRate = 0.5; + CFG_GET_VAL("gui.cursorblinkrate", m_CursorBlinkRate); } void CConsole::UpdateScreenSize(int w, int h) { - m_fX = 0; - m_fY = 0; + m_X = 0; + m_Y = 0; float height = h * 0.6f; - m_fWidth = w / g_GuiScale; - m_fHeight = height / g_GuiScale; + m_Width = w / g_VideoMode.GetScale(); + m_Height = height / g_VideoMode.GetScale(); +} + +void CConsole::ShowQuitHotkeys() +{ + if (m_QuitHotkeyWasShown) + return; + + std::string str; + for (const std::pair& key : g_HotkeyMap) + if (key.second.front().name == "console.toggle") + str += (str.empty() ? "Press " : " / ") + FindScancodeName(static_cast(key.first)); + + if (!str.empty()) + InsertMessage(str + " to quit."); + + m_QuitHotkeyWasShown = true; } void CConsole::ToggleVisible() { - m_bToggle = true; - m_bVisible = !m_bVisible; + m_Toggle = true; + m_Visible = !m_Visible; // TODO: this should be based on input focus, not visibility - if (m_bVisible) + if (m_Visible) + { + ShowQuitHotkeys(); SDL_StartTextInput(); - else - SDL_StopTextInput(); + return; + } + SDL_StopTextInput(); } void CConsole::SetVisible(bool visible) { - if (visible != m_bVisible) - m_bToggle = true; - m_bVisible = visible; + if (visible != m_Visible) + m_Toggle = true; + m_Visible = visible; if (visible) { - m_prevTime = 0.0; - m_bCursorVisState = false; + m_PrevTime = 0.0; + m_CursorVisState = false; } } void CConsole::FlushBuffer() { // Clear the buffer and set the cursor and length to 0 - memset(m_szBuffer, '\0', sizeof(wchar_t) * CONSOLE_BUFFER_SIZE); - m_iBufferPos = m_iBufferLength = 0; + memset(m_Buffer.get(), '\0', sizeof(wchar_t) * CONSOLE_BUFFER_SIZE); + m_BufferPos = m_BufferLength = 0; } void CConsole::Update(const float deltaRealTime) { - if(m_bToggle) + if (m_Toggle) { const float AnimateTime = .30f; const float Delta = deltaRealTime / AnimateTime; - if(m_bVisible) + if (m_Visible) { - m_fVisibleFrac += Delta; - if(m_fVisibleFrac > 1.0f) + m_VisibleFrac += Delta; + if (m_VisibleFrac > 1.0f) { - m_fVisibleFrac = 1.0f; - m_bToggle = false; + m_VisibleFrac = 1.0f; + m_Toggle = false; } } else { - m_fVisibleFrac -= Delta; - if(m_fVisibleFrac < 0.0f) + m_VisibleFrac -= Delta; + if (m_VisibleFrac < 0.0f) { - m_fVisibleFrac = 0.0f; - m_bToggle = false; + m_VisibleFrac = 0.0f; + m_Toggle = false; } } } } -void CConsole::Render() +void CConsole::Render(CCanvas2D& canvas) { - if (! (m_bVisible || m_bToggle) ) return; + if (!(m_Visible || m_Toggle)) + return; PROFILE3_GPU("console"); - CCanvas2D canvas; - DrawWindow(canvas); CTextRenderer textRenderer; textRenderer.SetCurrentFont(CStrIntern(CONSOLE_FONT)); // Animation: slide in from top of screen. - const float DeltaY = (1.0f - m_fVisibleFrac) * m_fHeight; - textRenderer.Translate(m_fX, m_fY - DeltaY); + const float deltaY = (1.0f - m_VisibleFrac) * m_Height; + textRenderer.Translate(m_X, m_Y - deltaY); DrawHistory(textRenderer); DrawBuffer(textRenderer); @@ -202,27 +213,28 @@ void CConsole::DrawWindow(CCanvas2D& canvas) { - std::vector points = { - CVector2D{m_fWidth, 0.0f}, + std::vector points = + { + CVector2D{m_Width, 0.0f}, CVector2D{1.0f, 0.0f}, - CVector2D{1.0f, m_fHeight - 1.0f}, - CVector2D{m_fWidth, m_fHeight - 1.0f}, - CVector2D{m_fWidth, 0.0f} + CVector2D{1.0f, m_Height - 1.0f}, + CVector2D{m_Width, m_Height - 1.0f}, + CVector2D{m_Width, 0.0f} }; for (CVector2D& point : points) - point += CVector2D{m_fX, m_fY - (1.0f - m_fVisibleFrac) * m_fHeight}; + point += CVector2D{m_X, m_Y - (1.0f - m_VisibleFrac) * m_Height}; canvas.DrawRect(CRect(points[1], points[3]), CColor(0.0f, 0.0f, 0.5f, 0.6f)); canvas.DrawLine(points, 1.0f, CColor(0.5f, 0.5f, 0.0f, 0.6f)); - if (m_fHeight > m_iFontHeight + 4) + if (m_Height > m_FontHeight + 4) { points = { - CVector2D{0.0f, m_fHeight - static_cast(m_iFontHeight) - 4.0f}, - CVector2D{m_fWidth, m_fHeight - static_cast(m_iFontHeight) - 4.0f} + CVector2D{0.0f, m_Height - static_cast(m_FontHeight) - 4.0f}, + CVector2D{m_Width, m_Height - static_cast(m_FontHeight) - 4.0f} }; for (CVector2D& point : points) - point += CVector2D{m_fX, m_fY - (1.0f - m_fVisibleFrac) * m_fHeight}; + point += CVector2D{m_X, m_Y - (1.0f - m_VisibleFrac) * m_Height}; canvas.DrawLine(points, 1.0f, CColor(0.5f, 0.5f, 0.0f, 0.6f)); } } @@ -231,19 +243,24 @@ { int i = 1; - std::deque::iterator Iter; //History iterator + std::deque::iterator it; //History iterator std::lock_guard lock(m_Mutex); // needed for safe access to m_deqMsgHistory textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 1.0f, 1.0f)); - for (Iter = m_deqMsgHistory.begin(); - Iter != m_deqMsgHistory.end() - && (((i - m_iMsgHistPos + 1) * m_iFontHeight) < m_fHeight); - ++Iter) - { - if (i >= m_iMsgHistPos) - textRenderer.Put(9.0f, m_fHeight - (float)m_iFontOffset - (float)m_iFontHeight * (i - m_iMsgHistPos + 1), Iter->c_str()); + for (it = m_MsgHistory.begin(); + it != m_MsgHistory.end() + && (((i - m_MsgHistPos + 1) * m_FontHeight) < m_Height); + ++it) + { + if (i >= m_MsgHistPos) + { + textRenderer.Put( + 9.0f, + m_Height - static_cast(m_FontOffset) - static_cast(m_FontHeight) * (i - m_MsgHistPos + 1), + it->c_str()); + } i++; } @@ -252,25 +269,25 @@ // Renders the buffer to the screen. void CConsole::DrawBuffer(CTextRenderer& textRenderer) { - if (m_fHeight < m_iFontHeight) + if (m_Height < m_FontHeight) return; const CVector2D savedTranslate = textRenderer.GetTranslate(); - textRenderer.Translate(2.0f, m_fHeight - (float)m_iFontOffset + 1.0f); + textRenderer.Translate(2.0f, m_Height - static_cast(m_FontOffset) + 1.0f); textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 1.0f)); textRenderer.PutAdvance(L"]"); textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 1.0f, 1.0f)); - if (m_iBufferPos == 0) + if (m_BufferPos == 0) DrawCursor(textRenderer); - for (int i = 0; i < m_iBufferLength; i++) + for (int i = 0; i < m_BufferLength; ++i) { - textRenderer.PrintfAdvance(L"%lc", m_szBuffer[i]); - if (m_iBufferPos-1 == i) + textRenderer.PrintfAdvance(L"%lc", m_Buffer[i]); + if (m_BufferPos - 1 == i) DrawCursor(textRenderer); } @@ -279,23 +296,23 @@ void CConsole::DrawCursor(CTextRenderer& textRenderer) { - if (m_cursorBlinkRate > 0.0) + if (m_CursorBlinkRate > 0.0) { // check if the cursor visibility state needs to be changed double currTime = timer_Time(); - if ((currTime - m_prevTime) >= m_cursorBlinkRate) + if ((currTime - m_PrevTime) >= m_CursorBlinkRate) { - m_bCursorVisState = !m_bCursorVisState; - m_prevTime = currTime; + m_CursorVisState = !m_CursorVisState; + m_PrevTime = currTime; } } else { // Should always be visible - m_bCursorVisState = true; + m_CursorVisState = true; } - if(m_bCursorVisState) + if(m_CursorVisState) { // Slightly translucent yellow textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 0.8f)); @@ -310,37 +327,37 @@ bool CConsole::IsEOB() const { - return m_iBufferPos == m_iBufferLength; + return m_BufferPos == m_BufferLength; } bool CConsole::IsBOB() const { - return m_iBufferPos == 0; + return m_BufferPos == 0; } bool CConsole::IsFull() const { - return m_iBufferLength == CONSOLE_BUFFER_SIZE; + return m_BufferLength == CONSOLE_BUFFER_SIZE; } bool CConsole::IsEmpty() const { - return m_iBufferLength == 0; + return m_BufferLength == 0; } //Inserts a character into the buffer. void CConsole::InsertChar(const int szChar, const wchar_t cooked) { - static int iHistoryPos = -1; + static int historyPos = -1; - if (!m_bVisible) return; + if (!m_Visible) return; switch (szChar) { case SDLK_RETURN: - iHistoryPos = -1; - m_iMsgHistPos = 1; - ProcessBuffer(m_szBuffer); + historyPos = -1; + m_MsgHistPos = 1; + ProcessBuffer(m_Buffer.get()); FlushBuffer(); return; @@ -351,42 +368,43 @@ case SDLK_BACKSPACE: if (IsEmpty() || IsBOB()) return; - if (m_iBufferPos == m_iBufferLength) - m_szBuffer[m_iBufferPos - 1] = '\0'; + if (m_BufferPos == m_BufferLength) + m_Buffer[m_BufferPos - 1] = '\0'; else { - for (int j = m_iBufferPos-1; j < m_iBufferLength-1; j++) - m_szBuffer[j] = m_szBuffer[j+1]; // move chars to left - m_szBuffer[m_iBufferLength-1] = '\0'; + for (int j = m_BufferPos-1; j < m_BufferLength - 1; ++j) + m_Buffer[j] = m_Buffer[j + 1]; // move chars to left + m_Buffer[m_BufferLength-1] = '\0'; } - m_iBufferPos--; - m_iBufferLength--; + m_BufferPos--; + m_BufferLength--; return; case SDLK_DELETE: - if (IsEmpty() || IsEOB()) return; + if (IsEmpty() || IsEOB()) + return; - if (m_iBufferPos == m_iBufferLength-1) + if (m_BufferPos == m_BufferLength - 1) { - m_szBuffer[m_iBufferPos] = '\0'; - m_iBufferLength--; + m_Buffer[m_BufferPos] = '\0'; + m_BufferLength--; } else { if (g_scancodes[SDL_SCANCODE_LCTRL] || g_scancodes[SDL_SCANCODE_RCTRL]) { // Make Ctrl-Delete delete up to end of line - m_szBuffer[m_iBufferPos] = '\0'; - m_iBufferLength = m_iBufferPos; + m_Buffer[m_BufferPos] = '\0'; + m_BufferLength = m_BufferPos; } else { // Delete just one char and move the others left - for(int j=m_iBufferPos; j lock(m_Mutex); // needed for safe access to m_deqMsgHistory - int linesShown = (int)m_fHeight/m_iFontHeight - 4; - m_iMsgHistPos = Clamp(static_cast(m_deqMsgHistory.size()) - linesShown, 1, static_cast(m_deqMsgHistory.size())); + const int linesShown = static_cast(m_Height / m_FontHeight) - 4; + m_MsgHistPos = Clamp(static_cast(m_MsgHistory.size()) - linesShown, 1, static_cast(m_MsgHistory.size())); } else { - m_iBufferPos = 0; + m_BufferPos = 0; } return; case SDLK_END: if (g_scancodes[SDL_SCANCODE_LCTRL] || g_scancodes[SDL_SCANCODE_RCTRL]) { - m_iMsgHistPos = 1; + m_MsgHistPos = 1; } else { - m_iBufferPos = m_iBufferLength; + m_BufferPos = m_BufferLength; } return; case SDLK_LEFT: - if (m_iBufferPos) m_iBufferPos--; + if (m_BufferPos) + m_BufferPos--; return; case SDLK_RIGHT: - if (m_iBufferPos != m_iBufferLength) m_iBufferPos++; + if (m_BufferPos != m_BufferLength) + m_BufferPos++; return; // BEGIN: Buffer History Lookup case SDLK_UP: - if (m_deqBufHistory.size() && iHistoryPos != (int)m_deqBufHistory.size() - 1) + if (m_BufHistory.size() && historyPos != static_cast(m_BufHistory.size()) - 1) { - iHistoryPos++; - SetBuffer(m_deqBufHistory.at(iHistoryPos).c_str()); - m_iBufferPos = m_iBufferLength; + historyPos++; + SetBuffer(m_BufHistory.at(historyPos).c_str()); + m_BufferPos = m_BufferLength; } return; case SDLK_DOWN: - if (m_deqBufHistory.size()) + if (m_BufHistory.size()) { - if (iHistoryPos > 0) + if (historyPos > 0) { - iHistoryPos--; - SetBuffer(m_deqBufHistory.at(iHistoryPos).c_str()); - m_iBufferPos = m_iBufferLength; + historyPos--; + SetBuffer(m_BufHistory.at(historyPos).c_str()); + m_BufferPos = m_BufferLength; } - else if (iHistoryPos == 0) + else if (historyPos == 0) { - iHistoryPos--; + historyPos--; FlushBuffer(); } } @@ -458,31 +478,33 @@ { std::lock_guard lock(m_Mutex); // needed for safe access to m_deqMsgHistory - if (m_iMsgHistPos != (int)m_deqMsgHistory.size()) m_iMsgHistPos++; + if (m_MsgHistPos != static_cast(m_MsgHistory.size())) + m_MsgHistPos++; return; } case SDLK_PAGEDOWN: - if (m_iMsgHistPos != 1) m_iMsgHistPos--; + if (m_MsgHistPos != 1) + m_MsgHistPos--; return; // END: Message History Lookup default: //Insert a character - if (IsFull()) return; - if (cooked == 0) return; + if (IsFull() || cooked == 0) + return; if (IsEOB()) //are we at the end of the buffer? - m_szBuffer[m_iBufferPos] = cooked; //cat char onto end + m_Buffer[m_BufferPos] = cooked; //cat char onto end else { //we need to insert int i; - for(i=m_iBufferLength; i>m_iBufferPos; i--) - m_szBuffer[i] = m_szBuffer[i-1]; // move chars to right - m_szBuffer[i] = cooked; + for (i = m_BufferLength; i > m_BufferPos; --i) + m_Buffer[i] = m_Buffer[i - 1]; // move chars to right + m_Buffer[i] = cooked; } - m_iBufferPos++; - m_iBufferLength++; + m_BufferPos++; + m_BufferLength++; return; } @@ -500,15 +522,15 @@ size_t distance; //make sure everything has been initialized - if ( m_charsPerPage != 0 ) + if (m_CharsPerPage != 0) { - while ( oldNewline+m_charsPerPage < wrapAround.length() ) + while (oldNewline + m_CharsPerPage < wrapAround.length()) { distance = wrapAround.find(newline, oldNewline) - oldNewline; - if ( distance > m_charsPerPage ) + if (distance > m_CharsPerPage) { - oldNewline += m_charsPerPage; - wrapAround.insert( oldNewline++, newline ); + oldNewline += m_CharsPerPage; + wrapAround.insert(oldNewline++, newline); } else oldNewline += distance+1; @@ -523,29 +545,29 @@ while ( (distance = wrapAround.find(newline, oldNewline)) != wrapAround.npos) { distance -= oldNewline; - m_deqMsgHistory.push_front(wrapAround.substr(oldNewline, distance)); + m_MsgHistory.push_front(wrapAround.substr(oldNewline, distance)); oldNewline += distance+1; } - m_deqMsgHistory.push_front(wrapAround.substr(oldNewline)); + m_MsgHistory.push_front(wrapAround.substr(oldNewline)); } } const wchar_t* CConsole::GetBuffer() { - m_szBuffer[m_iBufferLength] = 0; - return( m_szBuffer ); + m_Buffer[m_BufferLength] = 0; + return m_Buffer.get(); } void CConsole::SetBuffer(const wchar_t* szMessage) { - int oldBufferPos = m_iBufferPos; // remember since FlushBuffer will set it to 0 + int oldBufferPos = m_BufferPos; // remember since FlushBuffer will set it to 0 FlushBuffer(); - wcsncpy(m_szBuffer, szMessage, CONSOLE_BUFFER_SIZE); - m_szBuffer[CONSOLE_BUFFER_SIZE-1] = 0; - m_iBufferLength = static_cast(wcslen(m_szBuffer)); - m_iBufferPos = std::min(oldBufferPos, m_iBufferLength); + wcsncpy(m_Buffer.get(), szMessage, CONSOLE_BUFFER_SIZE); + m_Buffer[CONSOLE_BUFFER_SIZE-1] = 0; + m_BufferLength = static_cast(wcslen(m_Buffer.get())); + m_BufferPos = std::min(oldBufferPos, m_BufferLength); } void CConsole::ProcessBuffer(const wchar_t* szLine) @@ -555,7 +577,7 @@ ENSURE(wcslen(szLine) < CONSOLE_BUFFER_SIZE); - m_deqBufHistory.push_front(szLine); + m_BufHistory.push_front(szLine); SaveHistory(); // Do this each line for the moment; if a script causes // a crash it's a useful record. @@ -575,11 +597,11 @@ // just don't load anything in that case. // do this before LoadFile to avoid an error message if file not found. - if (!VfsFileExists(m_sHistoryFile)) + if (!VfsFileExists(m_HistoryFile)) return; std::shared_ptr buf; size_t buflen; - if (g_VFS->LoadFile(m_sHistoryFile, buf, buflen) < 0) + if (g_VFS->LoadFile(m_HistoryFile, buf, buflen) < 0) return; CStr bytes ((char*)buf.get(), buflen); @@ -592,29 +614,33 @@ if (pos != CStrW::npos) { if (pos > 0) - m_deqBufHistory.push_front(str.Left(str[pos-1] == '\r' ? pos - 1 : pos)); + m_BufHistory.push_front(str.Left(str[pos-1] == '\r' ? pos - 1 : pos)); str = str.substr(pos + 1); } else if (str.length() > 0) - m_deqBufHistory.push_front(str); + m_BufHistory.push_front(str); } } void CConsole::SaveHistory() { WriteBuffer buffer; - const int linesToSkip = (int)m_deqBufHistory.size() - m_MaxHistoryLines; - std::deque::reverse_iterator it = m_deqBufHistory.rbegin(); + const int linesToSkip = static_cast(m_BufHistory.size()) - m_MaxHistoryLines; + std::deque::reverse_iterator it = m_BufHistory.rbegin(); if(linesToSkip > 0) std::advance(it, linesToSkip); - for (; it != m_deqBufHistory.rend(); ++it) + for (; it != m_BufHistory.rend(); ++it) { CStr8 line = CStrW(*it).ToUTF8(); buffer.Append(line.data(), line.length()); static const char newline = '\n'; buffer.Append(&newline, 1); } - g_VFS->CreateFile(m_sHistoryFile, buffer.Data(), buffer.Size()); + + if (g_VFS->CreateFile(m_HistoryFile, buffer.Data(), buffer.Size()) == INFO::OK) + ONCE(debug_printf("FILES| Console command history written to '%s'\n", m_HistoryFile.string8().c_str())); + else + debug_printf("FILES| Failed to write console command history to '%s'\n", m_HistoryFile.string8().c_str()); } static bool isUnprintableChar(SDL_Keysym key) diff -Nru 0ad-0.0.25b/source/ps/CConsole.h 0ad-0.0.26/source/ps/CConsole.h --- 0ad-0.0.25b/source/ps/CConsole.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/CConsole.h 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,13 +22,12 @@ #ifndef INCLUDED_CCONSOLE #define INCLUDED_CCONSOLE -#include "graphics/ShaderProgramPtr.h" #include "lib/file/vfs/vfs_path.h" #include "lib/input.h" #include +#include #include -#include #include class CCanvas2D; @@ -61,7 +60,7 @@ */ void Update(const float deltaRealTime); - void Render(); + void Render(CCanvas2D& canvas); void InsertChar(const int szChar, const wchar_t cooked); @@ -73,44 +72,44 @@ const wchar_t* GetBuffer(); void FlushBuffer(); - bool IsActive() const { return m_bVisible; } + bool IsActive() const { return m_Visible; } private: // Lock for all state modified by InsertMessage std::mutex m_Mutex; - int m_iFontHeight; - int m_iFontWidth; - int m_iFontOffset; // distance to move up before drawing - size_t m_charsPerPage; - - float m_fX; - float m_fY; - - float m_fHeight; - float m_fWidth; + int m_FontHeight; + int m_FontWidth; + int m_FontOffset; // distance to move up before drawing + size_t m_CharsPerPage; + + float m_X; + float m_Y; + float m_Height; + float m_Width; // "position" in show/hide animation, how visible the console is (0..1). // allows implementing other animations than sliding, e.g. fading in/out. - float m_fVisibleFrac; + float m_VisibleFrac; - std::deque m_deqMsgHistory; // protected by m_Mutex - std::deque m_deqBufHistory; + std::deque m_MsgHistory; // protected by m_Mutex + std::deque m_BufHistory; - int m_iMsgHistPos; + int m_MsgHistPos; - wchar_t* m_szBuffer; - int m_iBufferPos; - int m_iBufferLength; + std::unique_ptr m_Buffer; + int m_BufferPos; + int m_BufferLength; - VfsPath m_sHistoryFile; + VfsPath m_HistoryFile; int m_MaxHistoryLines; - bool m_bVisible; // console is to be drawn - bool m_bToggle; // show/hide animation is currently active - double m_prevTime; // the previous time the cursor draw state changed (used for blinking cursor) - bool m_bCursorVisState; // if the cursor should be drawn or not - double m_cursorBlinkRate; // cursor blink rate in seconds, if greater than 0.0 + bool m_Visible; // console is to be drawn + bool m_Toggle; // show/hide animation is currently active + double m_PrevTime; // the previous time the cursor draw state changed (used for blinking cursor) + bool m_CursorVisState; // if the cursor should be drawn or not + bool m_QuitHotkeyWasShown; // show console.toggle hotkey values at first time + double m_CursorBlinkRate; // cursor blink rate in seconds, if greater than 0.0 void DrawWindow(CCanvas2D& canvas); void DrawHistory(CTextRenderer& textRenderer); @@ -128,6 +127,7 @@ void LoadHistory(); void SaveHistory(); + void ShowQuitHotkeys(); }; extern CConsole* g_Console; diff -Nru 0ad-0.0.25b/source/ps/CLogger.cpp 0ad-0.0.26/source/ps/CLogger.cpp --- 0ad-0.0.25b/source/ps/CLogger.cpp 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/CLogger.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -71,10 +71,11 @@ { OsPath mainlogPath(psLogDir() / (L"mainlog" + g_UniqueLogPostfix + L".html")); m_MainLog = new std::ofstream(OsString(mainlogPath).c_str(), std::ofstream::out | std::ofstream::trunc); - debug_printf("Writing the mainlog at %s\n", mainlogPath.string8().c_str()); + debug_printf("FILES| Main log written to '%s'\n", mainlogPath.string8().c_str()); OsPath interestinglogPath(psLogDir() / (L"interestinglog" + g_UniqueLogPostfix + L".html")); m_InterestingLog = new std::ofstream(OsString(interestinglogPath).c_str(), std::ofstream::out | std::ofstream::trunc); + debug_printf("FILES| Interesting log written to '%s'\n", interestinglogPath.string8().c_str()); m_OwnsStreams = true; m_UseDebugPrintf = true; @@ -202,7 +203,7 @@ PushRenderMessage(Warning, message); } -void CLogger::Render() +void CLogger::Render(CCanvas2D& canvas) { PROFILE3_GPU("logger"); @@ -254,7 +255,6 @@ textRenderer.Translate(0.0f, (float)lineSpacing); } - CCanvas2D canvas; canvas.DrawText(textRenderer); } diff -Nru 0ad-0.0.25b/source/ps/CLogger.h 0ad-0.0.26/source/ps/CLogger.h --- 0ad-0.0.25b/source/ps/CLogger.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/CLogger.h 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,11 +19,12 @@ #define INCLUDED_CLOGGER #include +#include #include #include #include -#include +class CCanvas2D; class CLogger; extern CLogger* g_Logger; @@ -69,7 +70,7 @@ void WriteWarning(const char* message); // Render recent log messages onto the screen - void Render(); + void Render(CCanvas2D& canvas); private: void Init(); diff -Nru 0ad-0.0.25b/source/ps/containers/Span.h 0ad-0.0.26/source/ps/containers/Span.h --- 0ad-0.0.25b/source/ps/containers/Span.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/ps/containers/Span.h 2022-09-23 19:16:55.000000000 +0000 @@ -0,0 +1,76 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_PS_SPAN +#define INCLUDED_PS_SPAN + +#include +#include +#include + +namespace PS +{ + +/** + * Simplifed version of std::span (C++20) as we don't support the original one + * yet. The naming intentionally follows the STL version to make the future + * replacement easier with less blame changing. + * It supports only very basic subset of std::span functionality. + * TODO: remove as soon as std::span become available. + */ +template +class span +{ +public: + using element_type = T; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using pointer = T*; + using reference = T&; + using iterator = pointer; + + constexpr span() + : m_Pointer(nullptr), m_Extent(0) {} + + constexpr span(iterator first, size_type extent) + : m_Pointer(first), m_Extent(extent) {} + + constexpr span(iterator first, iterator last) + : m_Pointer(first), m_Extent(static_cast(last - first)) {} + + constexpr span(const span& other) = default; + + constexpr span& operator=(const span& other) = default; + + ~span() = default; + + constexpr size_type size() const { return m_Extent; } + constexpr bool empty() const { return size() == 0; } + constexpr reference operator[](size_type index) const { return *(m_Pointer + index); } + constexpr pointer data() const { return m_Pointer; } + + constexpr iterator begin() const { return m_Pointer; } + constexpr iterator end() const { return m_Pointer + m_Extent; } + +private: + pointer m_Pointer; + size_type m_Extent; +}; + +} // namespace PS + +#endif // INCLUDED_PS_SPAN diff -Nru 0ad-0.0.25b/source/ps/CStr.cpp 0ad-0.0.26/source/ps/CStr.cpp --- 0ad-0.0.25b/source/ps/CStr.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/CStr.cpp 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,10 +15,6 @@ * along with 0 A.D. If not, see . */ -/** - * Description : Controls compilation of CStr class and - * : includes some function implementations. - **/ #include "precompiled.h" #ifndef CStr_CPP_FIRST @@ -30,8 +26,137 @@ #include "network/Serialization.h" #include +#include #include #include +#include + +namespace +{ + // Use a knowingly false expression, as we can't use + // static_assert(false, ...) directly, because it's an ill-formed program + // with a value (false) which doesn't depend on any input parameter. + // We don't use constexpr bool AlwaysFalse = false, because some compilers + // complain about an unused constant. + template + struct AlwaysFalse : std::false_type + {}; + + template + using tstringstream = std::basic_stringstream; + + template + bool istspace(const Char chr) + { + if constexpr (std::is_same_v) + return static_cast(std::isspace(chr)); + else + return static_cast(std::iswspace(chr)); + } + + template + Char totlower(const Char chr) + { + if constexpr (std::is_same_v) + return std::tolower(chr); + else + return std::towlower(chr); + } + + template + Char totupper(const Char chr) + { + if constexpr (std::is_same_v) + return std::toupper(chr); + else + return std::towupper(chr); + } + + template + u8* SerializeImpl(const StrBase& str, u8* buffer) + { + using Char = typename StrBase::value_type; + ENSURE(buffer); + if constexpr (std::is_same_v) + { + // CStr8 is always serialized to / from ASCII(or whatever 8 - bit codepage stored + // in the CStr). + size_t len = str.length(); + Serialize_int_4(buffer, (u32)len); + size_t i = 0; + for (i = 0; i < len; i++) + buffer[i] = str[i]; + return buffer + len; + } + else if constexpr (std::is_same_v) + { + // CStrW is always serialized to / from UTF - 16. + size_t len = str.length(); + size_t i = 0; + for (i = 0; i < len; i++) + { + const u16 bigEndian = to_be16(str[i]); + *(u16 *)(buffer + i * 2) = bigEndian; + } + *(u16 *)(buffer + i * 2) = 0; + return buffer + len * 2 + 2; + } + else + static_assert(AlwaysFalse::value, "Not implemented."); + } + + template + const u8* DeserializeImpl(const u8* buffer, const u8* bufferend, StrBase& str) + { + using Char = typename StrBase::value_type; + ENSURE(buffer); + ENSURE(bufferend); + if constexpr (std::is_same_v) + { + u32 len; + Deserialize_int_4(buffer, len); + if (buffer + len > bufferend) + return NULL; + str = StrBase(buffer, buffer + len); + return buffer + len; + } + else if constexpr (std::is_same_v) + { + const u16 *strend = (const u16 *)buffer; + while ((const u8 *)strend < bufferend && *strend) + strend++; + if ((const u8 *)strend >= bufferend) + return nullptr; + + str.resize(strend - (const u16 *)buffer); + const u16 *ptr = (const u16 *)buffer; + + typename StrBase::iterator it = str.begin(); + while (ptr < strend) + { + const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same + *(it++) = (Char)native; + } + + return (const u8 *)(strend + 1); + } + else + static_assert(AlwaysFalse::value, "Not implemented."); + } + + template + size_t GetSerializedLengthImpl(const StrBase& str) + { + using Char = typename StrBase::value_type; + if constexpr (std::is_same_v) + return str.length() + 4; + else if constexpr (std::is_same_v) + return str.length() * 2 + 2; + else + static_assert(AlwaysFalse::value, "Not implemented."); + } + +} // anonymous namespace #define UNIDOUBLER_HEADER "CStr.cpp" #include "UniDoubler.h" @@ -67,25 +192,11 @@ #include "CStr.h" -#include - -#ifdef _UNICODE - #define tstringstream wstringstream - #define _istspace iswspace - #define _totlower towlower - #define _totupper towupper -#else - #define tstringstream stringstream - #define _istspace isspace - #define _totlower tolower - #define _totupper toupper -#endif - -CStr CStr::Repeat(const CStr& String, size_t Reps) +CStr CStr::Repeat(const CStr& str, size_t reps) { CStr ret; - ret.reserve(String.length() * Reps); - while (Reps--) ret += String; + ret.reserve(str.length() * reps); + while (reps--) ret += str; return ret; } @@ -93,28 +204,28 @@ CStr CStr::FromInt(int n) { - std::tstringstream ss; + tstringstream ss; ss << n; return ss.str(); } CStr CStr::FromUInt(unsigned int n) { - std::tstringstream ss; + tstringstream ss; ss << n; return ss.str(); } CStr CStr::FromInt64(i64 n) { - std::tstringstream ss; + tstringstream ss; ss << n; return ss.str(); } CStr CStr::FromDouble(double n) { - std::tstringstream ss; + tstringstream ss; ss << n; return ss.str(); } @@ -124,7 +235,7 @@ int CStr::ToInt() const { int ret = 0; - std::tstringstream str(*this); + tstringstream str(*this); str >> ret; return ret; } @@ -132,7 +243,7 @@ unsigned int CStr::ToUInt() const { unsigned int ret = 0; - std::tstringstream str(*this); + tstringstream str(*this); str >> ret; return ret; } @@ -140,7 +251,7 @@ long CStr::ToLong() const { long ret = 0; - std::tstringstream str(*this); + tstringstream str(*this); str >> ret; return ret; } @@ -148,7 +259,7 @@ unsigned long CStr::ToULong() const { unsigned long ret = 0; - std::tstringstream str(*this); + tstringstream str(*this); str >> ret; return ret; } @@ -160,7 +271,7 @@ */ CStr ParseableAsNumber(CStr cleaned_copy) { - for (tchar& c : cleaned_copy) + for (CStr::Char& c : cleaned_copy) if (!std::isdigit(c) && c != '.' && c != '-' && c != '+') c = ' '; @@ -170,7 +281,7 @@ float CStr::ToFloat() const { float ret = 0; - std::tstringstream str(ParseableAsNumber(*this)); + tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } @@ -178,78 +289,75 @@ double CStr::ToDouble() const { double ret = 0; - std::tstringstream str(ParseableAsNumber(*this)); + tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } - // Search the string for another string -long CStr::Find(const CStr& Str) const +long CStr::Find(const CStr& str) const { - size_t Pos = find(Str, 0); + size_t pos = find(str, 0); - if (Pos != npos) - return (long)Pos; + if (pos != npos) + return static_cast(pos); return -1; } // Search the string for another string -long CStr::Find(const tchar chr) const +long CStr::Find(const Char chr) const { - size_t Pos = find(chr, 0); + size_t pos = find(chr, 0); - if (Pos != npos) - return (long)Pos; + if (pos != npos) + return static_cast(pos); return -1; } // Search the string for another string -long CStr::Find(const int start, const tchar chr) const +long CStr::Find(const int start, const Char chr) const { - size_t Pos = find(chr, start); + size_t pos = find(chr, start); - if (Pos != npos) - return (long)Pos; + if (pos != npos) + return static_cast(pos); return -1; } -long CStr::FindInsensitive(const int start, const tchar chr) const { return LowerCase().Find(start, _totlower(chr)); } -long CStr::FindInsensitive(const tchar chr) const { return LowerCase().Find(_totlower(chr)); } -long CStr::FindInsensitive(const CStr& Str) const { return LowerCase().Find(Str.LowerCase()); } +long CStr::FindInsensitive(const int start, const Char chr) const { return LowerCase().Find(start, totlower(chr)); } +long CStr::FindInsensitive(const Char chr) const { return LowerCase().Find(totlower(chr)); } +long CStr::FindInsensitive(const CStr& str) const { return LowerCase().Find(str.LowerCase()); } - -long CStr::ReverseFind(const CStr& Str) const +long CStr::ReverseFind(const CStr& str) const { - size_t Pos = rfind(Str, length() ); + size_t pos = rfind(str, length() ); - if (Pos != npos) - return (long)Pos; + if (pos != npos) + return static_cast(pos); return -1; - } // Lowercase and uppercase CStr CStr::LowerCase() const { - std::tstring NewString = *this; + StrBase newStr = *this; for (size_t i = 0; i < length(); i++) - NewString[i] = (tchar)_totlower((*this)[i]); + newStr[i] = (Char)totlower((*this)[i]); - return NewString; + return newStr; } CStr CStr::UpperCase() const { - std::tstring NewString = *this; + StrBase newStr = *this; for (size_t i = 0; i < length(); i++) - NewString[i] = (tchar)_totupper((*this)[i]); + newStr[i] = (Char)totupper((*this)[i]); - return NewString; + return newStr; } @@ -269,20 +377,20 @@ // Retrieve the substring following the last occurrence of Str // (or the whole string if it doesn't contain Str) -CStr CStr::AfterLast(const CStr& Str, size_t startPos) const +CStr CStr::AfterLast(const CStr& str, size_t startPos) const { - size_t pos = rfind(Str, startPos); + size_t pos = rfind(str, startPos); if (pos == npos) return *this; else - return substr(pos + Str.length()); + return substr(pos + str.length()); } // Retrieve the substring preceding the last occurrence of Str // (or the whole string if it doesn't contain Str) -CStr CStr::BeforeLast(const CStr& Str, size_t startPos) const +CStr CStr::BeforeLast(const CStr& str, size_t startPos) const { - size_t pos = rfind(Str, startPos); + size_t pos = rfind(str, startPos); if (pos == npos) return *this; else @@ -291,20 +399,20 @@ // Retrieve the substring following the first occurrence of Str // (or the whole string if it doesn't contain Str) -CStr CStr::AfterFirst(const CStr& Str, size_t startPos) const +CStr CStr::AfterFirst(const CStr& str, size_t startPos) const { - size_t pos = find(Str, startPos); + size_t pos = find(str, startPos); if (pos == npos) return *this; else - return substr(pos + Str.length()); + return substr(pos + str.length()); } // Retrieve the substring preceding the first occurrence of Str // (or the whole string if it doesn't contain Str) -CStr CStr::BeforeFirst(const CStr& Str, size_t startPos) const +CStr CStr::BeforeFirst(const CStr& str, size_t startPos) const { - size_t pos = find(Str, startPos); + size_t pos = find(str, startPos); if (pos == npos) return *this; else @@ -312,92 +420,91 @@ } // Remove all occurrences of some character or substring -void CStr::Remove(const CStr& Str) +void CStr::Remove(const CStr& str) { - size_t FoundAt = 0; - while (FoundAt != npos) + size_t foundAt = 0; + while (foundAt != npos) { - FoundAt = find(Str, 0); + foundAt = find(str, 0); - if (FoundAt != npos) - erase(FoundAt, Str.length()); + if (foundAt != npos) + erase(foundAt, str.length()); } } // Replace all occurrences of some substring by another -void CStr::Replace(const CStr& ToReplace, const CStr& ReplaceWith) +void CStr::Replace(const CStr& toReplace, const CStr& replaceWith) { - size_t Pos = 0; - - while (Pos != npos) + size_t pos = 0; + while (pos != npos) { - Pos = find(ToReplace, Pos); - if (Pos != npos) + pos = find(toReplace, pos); + if (pos != npos) { - erase(Pos, ToReplace.length()); - insert(Pos, ReplaceWith); - Pos += ReplaceWith.length(); + erase(pos, toReplace.length()); + insert(pos, replaceWith); + pos += replaceWith.length(); } } } std::string CStr::EscapeToPrintableASCII() const { - std::string NewString; + std::string newStr; for (size_t i = 0; i < length(); i++) { - tchar ch = (*this)[i]; + Char ch = (*this)[i]; - if (ch == '"') NewString += "\\\""; - else if (ch == '\\') NewString += "\\\\"; - else if (ch == '\b') NewString += "\\b"; - else if (ch == '\f') NewString += "\\f"; - else if (ch == '\n') NewString += "\\n"; - else if (ch == '\r') NewString += "\\r"; - else if (ch == '\t') NewString += "\\t"; + if (ch == '"') newStr += "\\\""; + else if (ch == '\\') newStr += "\\\\"; + else if (ch == '\b') newStr += "\\b"; + else if (ch == '\f') newStr += "\\f"; + else if (ch == '\n') newStr += "\\n"; + else if (ch == '\r') newStr += "\\r"; + else if (ch == '\t') newStr += "\\t"; else if (ch >= 32 && ch <= 126) - NewString += ch; + newStr += ch; else { std::stringstream ss; ss << "\\u" << std::hex << std::setfill('0') << std::setw(4) << (int)(unsigned char)ch; - NewString += ss.str(); + newStr += ss.str(); } } - return NewString; + return newStr; } // Returns a trimmed string, removes whitespace from the left/right/both -CStr CStr::Trim(PS_TRIM_MODE Mode) const +CStr CStr::Trim(PS_TRIM_MODE mode) const { - size_t Left = 0, Right = 0; + size_t left = 0, right = 0; - switch (Mode) + switch (mode) { case PS_TRIM_LEFT: { - for (Left = 0; Left < length(); Left++) - if (_istspace((*this)[Left]) == false) + for (left = 0; left < length(); left++) + if (istspace((*this)[left]) == false) break; // end found, trim 0 to Left-1 inclusive } break; case PS_TRIM_RIGHT: { - Right = length(); - while (Right--) - if (_istspace((*this)[Right]) == false) + right = length(); + while (right--) + if (istspace((*this)[right]) == false) break; // end found, trim len-1 to Right+1 inclusive } break; case PS_TRIM_BOTH: { - for (Left = 0; Left < length(); Left++) - if (_istspace((*this)[Left]) == false) + for (left = 0; left < length(); left++) + if (istspace((*this)[left]) == false) break; // end found, trim 0 to Left-1 inclusive - Right = length(); - while (Right--) - if (_istspace((*this)[Right]) == false) + right = length(); + while (right--) + if (istspace((*this)[right]) == false) break; // end found, trim len-1 to Right+1 inclusive } break; @@ -406,38 +513,38 @@ } - return substr(Left, Right-Left+1); + return substr(left, right - left + 1); } -CStr CStr::Pad(PS_TRIM_MODE Mode, size_t Length) const +CStr CStr::Pad(PS_TRIM_MODE mode, size_t len) const { - size_t Left = 0, Right = 0; + size_t left = 0, right = 0; - if (Length <= length()) + if (len <= length()) return *this; // From here: Length-length() >= 1 - switch (Mode) + switch (mode) { case PS_TRIM_LEFT: - Left = Length - length(); + left = len - length(); break; case PS_TRIM_RIGHT: - Right = Length - length(); + right = len - length(); break; case PS_TRIM_BOTH: - Left = (Length - length() + 1)/2; - Right = (Length - length() - 1)/2; // cannot be negative + left = (len - length() + 1) / 2; + right = (len - length() - 1) / 2; // cannot be negative break; default: debug_warn(L"CStr::Trim: invalid Mode"); } - return std::tstring(Left, _T(' ')) + *this + std::tstring(Right, _T(' ')); + return StrBase(left, ' ') + *this + StrBase(right, ' '); } size_t CStr::GetHashCode() const @@ -447,92 +554,19 @@ // the result was truncated down to 32 anyway. } -#ifdef _UNICODE -/* - CStrW is always serialized to/from UTF-16 -*/ - -u8* CStrW::Serialize(u8* buffer) const -{ - size_t len = length(); - size_t i = 0; - for (i = 0; i < len; i++) - { - const u16 bigEndian = to_be16((*this)[i]); - *(u16 *)(buffer + i*2) = bigEndian; - } - *(u16 *)(buffer + i*2) = 0; - return buffer + len*2 + 2; -} - -const u8* CStrW::Deserialize(const u8* buffer, const u8* bufferend) +u8* CStr::Serialize(u8* buffer) const { - ENSURE(buffer); - ENSURE(bufferend); - const u16 *strend = (const u16 *)buffer; - while ((const u8 *)strend < bufferend && *strend) strend++; - if ((const u8 *)strend >= bufferend) return NULL; - - resize(strend - (const u16 *)buffer); - const u16 *ptr = (const u16 *)buffer; - - std::wstring::iterator str = begin(); - while (ptr < strend) - { - const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same - *(str++) = (tchar)native; - } - - return (const u8 *)(strend+1); + return SerializeImpl(*this, buffer); } -size_t CStr::GetSerializedLength() const +const u8* CStr::Deserialize(const u8* buffer, const u8* bufferend) { - return size_t(length()*2 + 2); -} - -#else -/* - CStr8 is always serialized to/from ASCII (or whatever 8-bit codepage stored - in the CStr) -*/ - -u8* CStr8::Serialize(u8* buffer) const -{ - size_t len = length(); - Serialize_int_4(buffer, (u32)len); - size_t i = 0; - for (i = 0; i < len; i++) - buffer[i] = (*this)[i]; - return buffer + len; -} - -const u8* CStr8::Deserialize(const u8* buffer, const u8* bufferend) -{ - ENSURE(buffer); - ENSURE(bufferend); - u32 len; - Deserialize_int_4(buffer, len); - if (buffer + len > bufferend) - return NULL; - *this = std::string(buffer, buffer + len); - return buffer + len; + return DeserializeImpl(buffer, bufferend, *this); } size_t CStr::GetSerializedLength() const { - return length() + 4; + return GetSerializedLengthImpl(*this); } -#endif // _UNICODE - -// Clean up, to keep the second pass through unidoubler happy -#undef tstringstream -#undef _tstod -#undef _ttoi -#undef _ttol -#undef _istspace -#undef _totlower -#undef _totupper - #endif // CStr_CPP_FIRST diff -Nru 0ad-0.0.25b/source/ps/CStrForward.h 0ad-0.0.26/source/ps/CStrForward.h --- 0ad-0.0.25b/source/ps/CStrForward.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/ps/CStrForward.h 2022-08-21 12:45:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* Copyright (C) 2021 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CSTR_FORWARD +#define INCLUDED_CSTR_FORWARD + +class CStr8; +class CStrW; + +#endif // INCLUDED_CSTR_FORWARD diff -Nru 0ad-0.0.25b/source/ps/CStr.h 0ad-0.0.26/source/ps/CStr.h --- 0ad-0.0.25b/source/ps/CStr.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/CStr.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -50,43 +50,41 @@ #define CSTR_H_A #endif -#include -#include "ps/utf16string.h" +#include "ps/CStrForward.h" -class CStr8; -class CStrW; +#include /** * The base class of all strings **/ -class CStr: public std::tstring +class CStr : public std::tstring { public: - - // CONSTRUCTORS + using StrBase = std::tstring; + using Char = typename std::tstring::value_type; CStr() {} - CStr(const tchar* String) : std::tstring(String) {} - CStr(const tchar* String, size_t Length) : std::tstring(String, Length) {} - CStr(const std::tstring& String) : std::tstring(String) {} - template - CStr (InputIterator first, InputIterator last) : std::tstring(first, last) {} + CStr(const Char* str) : StrBase(str) {} + CStr(const Char* str, size_t len) : StrBase(str, len) {} + CStr(const StrBase& str) : StrBase(str) {} + template + CStr (InputIterator first, InputIterator last) : StrBase(first, last) {} /** * Repeat: Named constructor, to avoid overload overload. * - * @param const CStr & String reference to another CStr object to be repeated for initialization + * @param const CStr & str reference to another CStr object to be repeated for initialization * @param size_t Reps number of times to repeat the initialization * @return CStr new CStr object **/ - static CStr Repeat(const CStr& String, size_t Reps); + static CStr Repeat(const CStr& str, size_t reps); /** - * Construction from utf16strings. + * Construction from u16strings. * - * @param utf16string String utf16string to be used for initialization. + * @param u16string String u16string to be used for initialization. **/ - explicit CStr(const utf16string& String) : std::tstring(String.begin(), String.end()) {} + explicit CStr(const std::u16string& str) : StrBase(str.begin(), str.end()) {} // Conversion to/from UTF-8, encoded in a CStr8. // Invalid bytes/characters (e.g. broken UTF-8, and Unicode characters @@ -151,11 +149,11 @@ * Search the CStr for another string. * The search is case-sensitive. * - * @param const CStr & Str reference to the search string + * @param const CStr & str reference to the search string * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long Find(const CStr& Str) const; + long Find(const CStr& str) const; /** * Search the CStr for another string. * The search is case-sensitive. @@ -164,7 +162,7 @@ * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long Find(const tchar chr) const; + long Find(const Char chr) const; /** * Search the CStr for another string with starting offset. * The search is case-sensitive. @@ -174,17 +172,17 @@ * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long Find(const int start, const tchar chr) const; + long Find(const int start, const Char chr) const; /** * Search the CStr for another string. * The search is case-insensitive. * - * @param const CStr & Str reference to the search string + * @param const CStr & str reference to the search string * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long FindInsensitive(const CStr& Str) const; + long FindInsensitive(const CStr& str) const; /** * Search the CStr for another string. * The search is case-insensitive. @@ -193,7 +191,7 @@ * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long FindInsensitive(const tchar chr) const; + long FindInsensitive(const Char chr) const; /** * Search the CStr for another string with starting offset. * The search is case-insensitive. @@ -203,17 +201,17 @@ * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long FindInsensitive(const int start, const tchar chr) const; + long FindInsensitive(const int start, const Char chr) const; /** * Search the CStr for another string. * The search is case-sensitive. * - * @param const CStr & Str reference to the search string + * @param const CStr & str reference to the search string * @return long offset into the CStr of the last occurrence of the search string * -1 if the search string is not found **/ - long ReverseFind(const CStr& Str) const; + long ReverseFind(const CStr& str) const; /** * Make a copy of the CStr in lower-case. @@ -248,60 +246,60 @@ * Retrieve substring of the CStr after last occurrence of a string. * Return substring of the CStr after the last occurrence of the search string. * - * @param const CStr & Str reference to search string + * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring remaining after match * the CStr if no match is found **/ - CStr AfterLast(const CStr& Str, size_t startPos = npos) const; + CStr AfterLast(const CStr& str, size_t startPos = npos) const; /** * Retrieve substring of the CStr preceding last occurrence of a string. * Return substring of the CStr preceding the last occurrence of the search string. * - * @param const CStr & Str reference to search string + * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring preceding before match * the CStr if no match is found **/ - CStr BeforeLast(const CStr& Str, size_t startPos = npos) const; + CStr BeforeLast(const CStr& str, size_t startPos = npos) const; /** * Retrieve substring of the CStr after first occurrence of a string. * Return substring of the CStr after the first occurrence of the search string. * - * @param const CStr & Str reference to search string + * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring remaining after match * the CStr if no match is found **/ - CStr AfterFirst(const CStr& Str, size_t startPos = 0) const; + CStr AfterFirst(const CStr& str, size_t startPos = 0) const; /** * Retrieve substring of the CStr preceding first occurrence of a string. * Return substring of the CStr preceding the first occurrence of the search string. * - * @param const CStr & Str reference to search string + * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring preceding before match * the CStr if no match is found **/ - CStr BeforeFirst(const CStr& Str, size_t startPos = 0) const; + CStr BeforeFirst(const CStr& str, size_t startPos = 0) const; /** * Remove all occurrences of a string from the CStr. * - * @param const CStr & Str reference to search string to remove. + * @param const CStr & str reference to search string to remove. **/ - void Remove(const CStr& Str); + void Remove(const CStr& str); /** * Replace all occurrences of one string by another string in the CStr. * - * @param const CStr & StrToReplace reference to search string. - * @param const CStr & ReplaceWith reference to replace string. + * @param const CStr & strToReplace reference to search string. + * @param const CStr & replaceWith reference to replace string. **/ - void Replace(const CStr& StrToReplace, const CStr& ReplaceWith); + void Replace(const CStr& toReplace, const CStr& replaceWith); /** * Convert strings to printable ASCII characters with JSON-style escapes. @@ -314,7 +312,7 @@ * @param PS_TRIM_MODE Mode value from trim mode enumeration. * @return CStr copy of trimmed CStr. **/ - CStr Trim(PS_TRIM_MODE Mode) const; + CStr Trim(PS_TRIM_MODE mode) const; /** * Return a space padded copy of the CStr. @@ -323,10 +321,10 @@ * @param size_t Length number of pad spaces to add * @return CStr copy of padded CStr. **/ - CStr Pad(PS_TRIM_MODE Mode, size_t Length) const; + CStr Pad(PS_TRIM_MODE mode, size_t len) const; - // Conversion to utf16string - utf16string utf16() const { return utf16string(begin(), end()); } + // Conversion to u16string + std::u16string utf16() const { return std::u16string(begin(), end()); } // Calculates a hash of the string's contents size_t GetHashCode() const; @@ -351,4 +349,4 @@ }; } -#endif +#endif // INCLUDED_CSTR diff -Nru 0ad-0.0.25b/source/ps/CStrInternStatic.h 0ad-0.0.26/source/ps/CStrInternStatic.h --- 0ad-0.0.25b/source/ps/CStrInternStatic.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/CStrInternStatic.h 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -56,12 +56,19 @@ X(MODE_SILHOUETTEDISPLAY) X(MODE_SILHOUETTEOCCLUDER) X(MODE_WIREFRAME) +X(MODE_WIREFRAME_SOLID) +X(PASS_REFLECTIONS) +X(PASS_REFRACTIONS) +X(PASS_SHADOWS) +X(RENDER_DEBUG_MODE) +X(RENDER_DEBUG_MODE_AO) +X(RENDER_DEBUG_MODE_ALPHA) +X(RENDER_DEBUG_MODE_CUSTOM) +X(RENDER_DEBUG_MODE_NONE) X(SHADOWS_CASCADE_COUNT) -X(SYS_HAS_ARB) -X(SYS_HAS_GLSL) -X(SYS_PREFER_GLSL) X(USE_FANCY_EFFECTS) X(USE_FP_SHADOW) +X(USE_GPU_INSTANCING) X(USE_GPU_SKINNING) X(USE_INSTANCING) X(USE_NORMALS) @@ -102,6 +109,7 @@ X(debug_overlay) X(delta) X(depthTex) +X(dummy) X(foamTex) X(fogColor) X(fogParams) @@ -119,16 +127,20 @@ X(maskTex) X(maskTextureTransform) X(minimap) +X(minimap_los) X(modelViewMatrix) X(murkiness) X(normalMap) X(normalMap2) X(objectColor) +X(overlay_line) X(overlay_solid) -X(particle) +X(particle_add) +X(particle_multiply) +X(particle_overlay) X(particle_solid) +X(particle_subtract) X(playerColor) -X(pointSize) X(projInvTransform) X(qualityLevel) X(reflectionMap) @@ -143,21 +155,19 @@ X(shadingColor) X(shadowDistance) X(shadowDistances) -X2(shadowDistances_0, "shadowDistances[0]") X(shadowScale) X(shadowTex) X(shadowTransform) X(shadowTransforms) -X2(shadowTransforms_0, "shadowTransforms[0]") X(sharpness) X(skinBlendMatrices) -X2(skinBlendMatrices_0, "skinBlendMatrices[0]") X(skyBoxRot) X(skyCube) X(sky_simple) X(solid) X(sunColor) X(sunDir) +X(terrain_solid) X(tex) X(texSize) X(textureTransform) @@ -166,7 +176,9 @@ X(transform) X(translation) X(viewInvTransform) +X(water_high) X(water_simple) +X(water_waves) X(waterEffectsTex) X(waterTex) X(waveTex) diff -Nru 0ad-0.0.25b/source/ps/FileIo.h 0ad-0.0.26/source/ps/FileIo.h --- 0ad-0.0.25b/source/ps/FileIo.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/FileIo.h 2022-08-21 12:45:05.000000000 +0000 @@ -31,11 +31,9 @@ #define INCLUDED_FILEPACKER #include "lib/file/vfs/vfs_path.h" -#include "ps/Filesystem.h" // WriteBuffer - +#include "ps/CStrForward.h" #include "ps/Errors.h" - -class CStr8; +#include "ps/Filesystem.h" // WriteBuffer ERROR_GROUP(File); ERROR_TYPE(File, OpenFailed); diff -Nru 0ad-0.0.25b/source/ps/Filesystem.cpp 0ad-0.0.26/source/ps/Filesystem.cpp --- 0ad-0.0.25b/source/ps/Filesystem.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/Filesystem.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -16,16 +16,15 @@ */ #include "precompiled.h" + #include "Filesystem.h" +#include "lib/sysdep/dir_watch.h" +#include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/CStr.h" #include "ps/Profile.h" -#include "lib/res/h_mgr.h" // h_reload -#include "lib/sysdep/dir_watch.h" -#include "lib/utf8.h" - #include PIVFS g_VFS; @@ -93,8 +92,6 @@ for (size_t j = 0; j < g_ReloadFuncs.size(); ++j) g_ReloadFuncs[j].first(g_ReloadFuncs[j].second, pathname); - - RETURN_STATUS_IF_ERR(h_reload(g_VFS, pathname)); } } return INFO::OK; diff -Nru 0ad-0.0.25b/source/ps/Filesystem.h 0ad-0.0.26/source/ps/Filesystem.h --- 0ad-0.0.25b/source/ps/Filesystem.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/Filesystem.h 2022-08-21 12:45:08.000000000 +0000 @@ -21,11 +21,9 @@ #include "lib/file/file.h" #include "lib/file/io/write_buffer.h" #include "lib/file/vfs/vfs_util.h" - +#include "ps/CStrForward.h" #include "ps/Errors.h" -class CStr8; - extern PIVFS g_VFS; extern bool VfsFileExists(const VfsPath& pathname); diff -Nru 0ad-0.0.25b/source/ps/Future.h 0ad-0.0.26/source/ps/Future.h --- 0ad-0.0.25b/source/ps/Future.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/Future.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -77,7 +77,7 @@ { static constexpr bool VoidResult = std::is_same_v; public: - SharedState(std::function&& func) : m_Func(func) {} + SharedState(std::function&& func) : m_Func(std::move(func)) {} ~SharedState() { // For safety, wait on started task completion, but not on pending ones (auto-cancelled). @@ -175,11 +175,11 @@ using Status = FutureSharedStateDetail::Status; using SharedState = FutureSharedStateDetail::SharedState; public: - Future() {}; + Future() = default; Future(const Future& o) = delete; Future(Future&&) = default; Future& operator=(Future&&) = default; - ~Future() {} + ~Future() = default; /** * Make the future wait for the result of @a func. @@ -272,7 +272,7 @@ static constexpr bool VoidResult = std::is_same_v; public: PackagedTask() = delete; - PackagedTask(const std::shared_ptr::SharedState>& ss) : m_SharedState(ss) {} + PackagedTask(std::shared_ptr::SharedState> ss) : m_SharedState(std::move(ss)) {} void operator()() { diff -Nru 0ad-0.0.25b/source/ps/Game.cpp 0ad-0.0.26/source/ps/Game.cpp --- 0ad-0.0.25b/source/ps/Game.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/Game.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,6 +39,7 @@ #include "ps/World.h" #include "ps/GameSetup/GameSetup.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TimeManager.h" #include "renderer/WaterManager.h" #include "scriptinterface/FunctionWrapper.h" @@ -49,12 +50,10 @@ #include "simulation2/components/ICmpPlayerManager.h" #include "simulation2/system/ReplayTurnManager.h" #include "soundmanager/ISoundManager.h" - #include "tools/atlas/GameInterface/GameLoop.h" #include -extern bool g_GameRestarted; extern GameLoopState* g_AtlasGameLoop; /** @@ -263,7 +262,7 @@ m_World->RegisterInit(mapFile, *scriptInterface.GetContext(), settings, m_PlayerID); } if (m_GameView) - RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); + RegMemFun(&g_Renderer.GetSceneRenderer().GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); if (m_IsSavedGame) RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000); @@ -318,11 +317,11 @@ // all be invisible) Interpolate(0, 0); - m_GameStarted=true; + m_GameStarted = true; - // Render a frame to begin loading assets + // Preload resources to avoid blinking on a first game frame. if (CRenderer::IsInitialised()) - Render(); + g_Renderer.PreloadResourcesBeforeNextFrame(); if (g_NetClient) g_NetClient->LoadFinished(); @@ -344,8 +343,6 @@ if (CProfileManager::IsInitialised()) g_Profiler.StructuralReset(); - g_GameRestarted = true; - return 0; } @@ -450,8 +447,7 @@ } } - -CColor CGame::GetPlayerColor(player_id_t player) const +const CColor& CGame::GetPlayerColor(player_id_t player) const { if (player < 0 || player >= (int)m_PlayerColors.size()) return BrokenColor; diff -Nru 0ad-0.0.25b/source/ps/Game.h 0ad-0.0.26/source/ps/Game.h --- 0ad-0.0.25b/source/ps/Game.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/Game.h 2022-09-23 19:16:57.000000000 +0000 @@ -130,7 +130,7 @@ */ void CachePlayerColors(); - CColor GetPlayerColor(player_id_t player) const; + const CColor& GetPlayerColor(player_id_t player) const; /** * Get m_GameStarted. diff -Nru 0ad-0.0.25b/source/ps/GameSetup/Config.cpp 0ad-0.0.26/source/ps/GameSetup/Config.cpp --- 0ad-0.0.25b/source/ps/GameSetup/Config.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/GameSetup/Config.cpp 2022-08-21 12:45:01.000000000 +0000 @@ -26,15 +26,9 @@ #include "ps/GameSetup/CmdLineArgs.h" // (these variables are documented in the header.) - -const wchar_t g_DefaultCursor[] = L"default-arrow"; - -CStrW g_CursorName = g_DefaultCursor; - bool g_PauseOnFocusLoss = false; int g_xres, g_yres; -float g_GuiScale = 1.0f; bool g_Quickstart = false; bool g_DisableAudio = false; @@ -47,11 +41,8 @@ static void LoadGlobals() { CFG_GET_VAL("pauseonfocusloss", g_PauseOnFocusLoss); - - CFG_GET_VAL("gui.scale", g_GuiScale); } - static void ProcessCommandLineArgs(const CmdLineArgs& args) { // TODO: all these options (and the ones processed elsewhere) should diff -Nru 0ad-0.0.25b/source/ps/GameSetup/Config.h 0ad-0.0.26/source/ps/GameSetup/Config.h --- 0ad-0.0.25b/source/ps/GameSetup/Config.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/GameSetup/Config.h 2022-08-21 12:45:01.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,14 +24,10 @@ extern bool g_PauseOnFocusLoss; extern int g_xres, g_yres; -extern float g_GuiScale; extern bool g_Quickstart; extern bool g_DisableAudio; -extern CStrW g_CursorName; -extern const wchar_t g_DefaultCursor[]; - class CmdLineArgs; extern void CONFIG_Init(const CmdLineArgs& args); diff -Nru 0ad-0.0.25b/source/ps/GameSetup/GameSetup.cpp 0ad-0.0.26/source/ps/GameSetup/GameSetup.cpp --- 0ad-0.0.25b/source/ps/GameSetup/GameSetup.cpp 2021-08-22 18:37:36.000000000 +0000 +++ 0ad-0.0.26/source/ps/GameSetup/GameSetup.cpp 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,40 +17,33 @@ #include "precompiled.h" -#include "lib/app_hooks.h" -#include "lib/config2.h" -#include "lib/input.h" -#include "lib/ogl.h" -#include "lib/timer.h" -#include "lib/external_libraries/libsdl.h" -#include "lib/file/common/file_stats.h" -#include "lib/res/h_mgr.h" -#include "lib/res/graphics/cursor.h" +#include "ps/GameSetup/GameSetup.h" -#include "graphics/CinemaManager.h" -#include "graphics/Color.h" #include "graphics/GameView.h" -#include "graphics/LightEnv.h" #include "graphics/MapReader.h" -#include "graphics/ModelDef.h" -#include "graphics/MaterialManager.h" #include "graphics/TerrainTextureManager.h" #include "gui/CGUI.h" #include "gui/GUIManager.h" +#include "gui/Scripting/JSInterface_GUIManager.h" #include "i18n/L10n.h" -#include "maths/MathUtil.h" +#include "lib/app_hooks.h" +#include "lib/config2.h" +#include "lib/external_libraries/libsdl.h" +#include "lib/file/common/file_stats.h" +#include "lib/input.h" +#include "lib/timer.h" +#include "lobby/IXmppClient.h" #include "network/NetServer.h" #include "network/NetClient.h" #include "network/NetMessage.h" #include "network/NetMessages.h" - +#include "network/scripting/JSInterface_Network.h" #include "ps/CConsole.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/Filesystem.h" #include "ps/Game.h" #include "ps/GameSetup/Atlas.h" -#include "ps/GameSetup/GameSetup.h" #include "ps/GameSetup/Paths.h" #include "ps/GameSetup/Config.h" #include "ps/GameSetup/CmdLineArgs.h" @@ -67,28 +60,29 @@ #include "ps/Profiler2.h" #include "ps/Pyrogenesis.h" // psSetLogDir #include "ps/scripting/JSInterface_Console.h" +#include "ps/scripting/JSInterface_Game.h" +#include "ps/scripting/JSInterface_Main.h" +#include "ps/scripting/JSInterface_VFS.h" #include "ps/TouchInput.h" #include "ps/UserReport.h" #include "ps/Util.h" #include "ps/VideoMode.h" #include "ps/VisualReplay.h" #include "ps/World.h" - #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/VertexBufferManager.h" -#include "renderer/ModelRenderer.h" #include "scriptinterface/FunctionWrapper.h" +#include "scriptinterface/JSON.h" #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptStats.h" #include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptConversions.h" -#include "scriptinterface/JSON.h" #include "simulation2/Simulation2.h" -#include "lobby/IXmppClient.h" +#include "simulation2/scripting/JSInterface_Simulation.h" #include "soundmanager/scripting/JSInterface_Sound.h" #include "soundmanager/ISoundManager.h" #include "tools/atlas/GameInterface/GameLoop.h" -#include "tools/atlas/GameInterface/View.h" #if !(OS_WIN || OS_MACOSX || OS_ANDROID) // assume all other platforms use X11 for wxWidgets #define MUST_INIT_X11 1 @@ -111,245 +105,11 @@ ERROR_TYPE(System, VmodeFailed); ERROR_TYPE(System, RequiredExtensionsMissing); -bool g_DoRenderGui = true; -bool g_DoRenderLogger = true; -bool g_DoRenderCursor = true; - thread_local std::shared_ptr g_ScriptContext; -static const int SANE_TEX_QUALITY_DEFAULT = 5; // keep in sync with code - -static const CStr g_EventNameGameLoadProgress = "GameLoadProgress"; - bool g_InDevelopmentCopy; bool g_CheckedIfInDevelopmentCopy = false; -static void SetTextureQuality(int quality) -{ - int q_flags; - GLint filter; - -retry: - // keep this in sync with SANE_TEX_QUALITY_DEFAULT - switch(quality) - { - // worst quality - case 0: - q_flags = OGL_TEX_HALF_RES|OGL_TEX_HALF_BPP; - filter = GL_NEAREST; - break; - // [perf] add bilinear filtering - case 1: - q_flags = OGL_TEX_HALF_RES|OGL_TEX_HALF_BPP; - filter = GL_LINEAR; - break; - // [vmem] no longer reduce resolution - case 2: - q_flags = OGL_TEX_HALF_BPP; - filter = GL_LINEAR; - break; - // [vmem] add mipmaps - case 3: - q_flags = OGL_TEX_HALF_BPP; - filter = GL_NEAREST_MIPMAP_LINEAR; - break; - // [perf] better filtering - case 4: - q_flags = OGL_TEX_HALF_BPP; - filter = GL_LINEAR_MIPMAP_LINEAR; - break; - // [vmem] no longer reduce bpp - case SANE_TEX_QUALITY_DEFAULT: - q_flags = OGL_TEX_FULL_QUALITY; - filter = GL_LINEAR_MIPMAP_LINEAR; - break; - // [perf] add anisotropy - case 6: - // TODO: add anisotropic filtering - q_flags = OGL_TEX_FULL_QUALITY; - filter = GL_LINEAR_MIPMAP_LINEAR; - break; - // invalid - default: - debug_warn(L"SetTextureQuality: invalid quality"); - quality = SANE_TEX_QUALITY_DEFAULT; - // careful: recursion doesn't work and we don't want to duplicate - // the "sane" default values. - goto retry; - } - - ogl_tex_set_defaults(q_flags, filter); -} - - -//---------------------------------------------------------------------------- -// GUI integration -//---------------------------------------------------------------------------- - -// display progress / description in loading screen -void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task) -{ - const ScriptInterface& scriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); - ScriptRequest rq(scriptInterface); - - JS::RootedValueVector paramData(rq.cx); - - ignore_result(paramData.append(JS::NumberValue(percent))); - - JS::RootedValue valPendingTask(rq.cx); - Script::ToJSVal(rq, &valPendingTask, pending_task); - ignore_result(paramData.append(valPendingTask)); - - g_GUI->SendEventToAll(g_EventNameGameLoadProgress, paramData); -} - -bool ShouldRender() -{ - return !g_app_minimized && (g_app_has_focus || !g_VideoMode.IsInFullscreen()); -} - - -void Render() -{ - // Do not render if not focused while in fullscreen or minimised, - // as that triggers a difficult-to-reproduce crash on some graphic cards. - if (!ShouldRender()) - return; - - PROFILE3("render"); - - g_Profiler2.RecordGPUFrameStart(); - ogl_WarnIfError(); - - // prepare before starting the renderer frame - if (g_Game && g_Game->IsGameStarted()) - g_Game->GetView()->BeginFrame(); - - if (g_Game) - g_Renderer.SetSimulation(g_Game->GetSimulation2()); - - // start new frame - g_Renderer.BeginFrame(); - - ogl_WarnIfError(); - - if (g_Game && g_Game->IsGameStarted()) - { - g_Game->GetView()->Render(); - ogl_WarnIfError(); - } - - g_Renderer.RenderTextOverlays(); - - // If we're in Atlas game view, render special tools - if (g_AtlasGameLoop && g_AtlasGameLoop->view) - { - g_AtlasGameLoop->view->DrawCinemaPathTool(); - ogl_WarnIfError(); - } - - if (g_Game && g_Game->IsGameStarted()) - { - g_Game->GetView()->GetCinema()->Render(); - ogl_WarnIfError(); - } - - glDisable(GL_DEPTH_TEST); - - if (g_DoRenderGui) - { - // All GUI elements are drawn in Z order to render semi-transparent - // objects correctly. - g_GUI->Draw(); - ogl_WarnIfError(); - } - - // If we're in Atlas game view, render special overlays (e.g. editor bandbox). - if (g_AtlasGameLoop && g_AtlasGameLoop->view) - { - g_AtlasGameLoop->view->DrawOverlays(); - ogl_WarnIfError(); - } - - g_Console->Render(); - ogl_WarnIfError(); - - if (g_DoRenderLogger) - { - g_Logger->Render(); - ogl_WarnIfError(); - } - - // Profile information - g_ProfileViewer.RenderProfile(); - ogl_WarnIfError(); - - // Draw the cursor (or set the Windows cursor, on Windows) - if (g_DoRenderCursor) - { - PROFILE3_GPU("cursor"); - CStrW cursorName = g_CursorName; - if (cursorName.empty()) - { - cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, g_GuiScale, false); - } - else - { - bool forceGL = false; - CFG_GET_VAL("nohwcursor", forceGL); - -#if CONFIG2_GLES -#warning TODO: implement cursors for GLES -#else - // set up transform for GL cursor - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - CMatrix3D transform; - transform.SetOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f); - glLoadMatrixf(&transform._11); -#endif - -#if OS_ANDROID -#warning TODO: cursors for Android -#else - if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, g_GuiScale, forceGL) < 0) - LOGWARNING("Failed to draw cursor '%s'", utf8_from_wstring(cursorName)); -#endif - -#if CONFIG2_GLES -#warning TODO: implement cursors for GLES -#else - // restore transform - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -#endif - } - } - - glEnable(GL_DEPTH_TEST); - - g_Renderer.EndFrame(); - - PROFILE2_ATTR("draw calls: %d", (int)g_Renderer.GetStats().m_DrawCalls); - PROFILE2_ATTR("terrain tris: %d", (int)g_Renderer.GetStats().m_TerrainTris); - PROFILE2_ATTR("water tris: %d", (int)g_Renderer.GetStats().m_WaterTris); - PROFILE2_ATTR("model tris: %d", (int)g_Renderer.GetStats().m_ModelTris); - PROFILE2_ATTR("overlay tris: %d", (int)g_Renderer.GetStats().m_OverlayTris); - PROFILE2_ATTR("blend splats: %d", (int)g_Renderer.GetStats().m_BlendSplats); - PROFILE2_ATTR("particles: %d", (int)g_Renderer.GetStats().m_Particles); - - ogl_WarnIfError(); - - g_Profiler2.RecordGPUFrameEnd(); - ogl_WarnIfError(); -} - ErrorReactionInternal psDisplayError(const wchar_t* UNUSED(text), size_t UNUSED(flags)) { // If we're fullscreen, then sometimes (at least on some particular drivers on Linux) @@ -465,34 +225,6 @@ g_GUI->SwitchPage(gui_page, srcScriptInterface, initData); } -void InitPsAutostart(bool networked, JS::HandleValue attrs) -{ - // The GUI has not been initialized yet, so use the simulation scriptinterface for this variable - ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptRequest rq(scriptInterface); - - JS::RootedValue playerAssignments(rq.cx); - Script::CreateObject(rq, &playerAssignments); - - if (!networked) - { - JS::RootedValue localPlayer(rq.cx); - Script::CreateObject(rq, &localPlayer, "player", g_Game->GetPlayerID()); - Script::SetProperty(rq, playerAssignments, "local", localPlayer); - } - - JS::RootedValue sessionInitData(rq.cx); - - Script::CreateObject( - rq, - &sessionInitData, - "attribs", attrs, - "playerAssignments", playerAssignments); - - InitPs(true, L"page_loading.xml", &scriptInterface, sessionInitData); -} - - void InitInput() { g_Joystick.Initialise(); @@ -539,40 +271,6 @@ SAFE_DELETE(g_GUI); UnloadHotkeys(); - - // disable the special Windows cursor, or free textures for OGL cursors - cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y, 1.0, false); -} - - -static void InitRenderer() -{ - TIMER(L"InitRenderer"); - - // create renderer - new CRenderer; - - // create terrain related stuff - new CTerrainTextureManager; - - g_Renderer.Open(g_xres, g_yres); - - // Setup lighting environment. Since the Renderer accesses the - // lighting environment through a pointer, this has to be done before - // the first Frame. - g_Renderer.SetLightEnv(&g_LightEnv); - - // I haven't seen the camera affecting GUI rendering and such, but the - // viewport has to be updated according to the video mode - SViewPort vp; - vp.m_X = 0; - vp.m_Y = 0; - vp.m_Width = g_xres; - vp.m_Height = g_yres; - g_Renderer.SetViewport(vp); - ModelDefActivateFastImpl(); - ColorActivateFastImpl(); - ModelRenderer::Init(); } static void InitSDL() @@ -602,6 +300,14 @@ SDL_SetHint(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, "1"); #endif +#if SDL_VERSION_ATLEAST(2, 0, 14) && OS_WIN + // SDL2 >= 2.0.14 Before SDL 2.0.14, this defaulted to true. In 2.0.14 they switched to false + // breaking the behavior on Windows. + // https://github.com/libsdl-org/SDL/commit/1947ca7028ab165cc3e6cbdb0b4b7c4db68d1710 + // https://github.com/libsdl-org/SDL/issues/5033 + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1"); +#endif + #if OS_MACOSX // Some Mac mice only have one button, so they can't right-click // but SDL2 can emulate that with Ctrl+Click @@ -626,7 +332,7 @@ if (CRenderer::IsInitialised()) { ISoundManager::CloseGame(); - g_Renderer.ResetState(); + g_Renderer.GetSceneRenderer().ResetState(); } } @@ -645,10 +351,6 @@ ShutdownPs(); - TIMER_BEGIN(L"shutdown TexMan"); - delete &g_TexMan; - TIMER_END(L"shutdown TexMan"); - if (hasRenderer) { TIMER_BEGIN(L"shutdown Renderer"); @@ -661,9 +363,6 @@ g_Profiler2.ShutdownGPU(); - // Free cursors before shutting down SDL, as they may depend on SDL. - cursor_shutdown(); - TIMER_BEGIN(L"shutdown SDL"); ShutdownSDL(); TIMER_END(L"shutdown SDL"); @@ -699,10 +398,6 @@ g_VFS.reset(); - // this forcibly frees all open handles (thus preventing real leaks), - // and makes further access to h_mgr impossible. - h_mgr_shutdown(); - file_stats_dump(); TIMER_END(L"resource modules"); @@ -795,6 +490,7 @@ debug_SetThreadName("main"); // add all debug_printf "tags" that we are interested in: debug_filter_add("TIMER"); + debug_filter_add("FILES"); timer_Init(); @@ -828,8 +524,6 @@ bool Init(const CmdLineArgs& args, int flags) { - h_mgr_init(); - // Do this as soon as possible, because it chdirs // and will mess up the error reporting if anything // crashes before the working directory is set. @@ -947,17 +641,6 @@ RunHardwareDetection(); - if (g_AtlasGameLoop && g_AtlasGameLoop->view) - SetTextureQuality(SANE_TEX_QUALITY_DEFAULT); - else - { - int textureQuality = SANE_TEX_QUALITY_DEFAULT; - CFG_GET_VAL("texturequality", textureQuality); - SetTextureQuality(textureQuality); - } - - ogl_WarnIfError(); - // Optionally start profiler GPU timings automatically // (By default it's only enabled by a hotkey, for performance/compatibility) bool profilerGPUEnable = false; @@ -977,13 +660,9 @@ g_GUI = new CGUIManager(); - // (must come after SetVideoMode, since it calls ogl_Init) 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 - || !ogl_HaveExtension("GL_ARB_vertex_buffer_object") // VBO - || RenderPathEnum::FromString(renderPath) == FIXED) + if (RenderPathEnum::FromString(renderPath) == FIXED) { // It doesn't make sense to continue working here, because we're not // able to display anything. @@ -995,44 +674,13 @@ ); } - const char* missing = ogl_HaveExtensions(0, - "GL_ARB_multitexture", - "GL_EXT_draw_range_elements", - "GL_ARB_texture_env_combine", - "GL_ARB_texture_env_dot3", - NULL); - if(missing) - { - wchar_t buf[500]; - swprintf_s(buf, ARRAY_SIZE(buf), - L"The %hs extension doesn't appear to be available on your computer." - L" The game may still work, though - you are welcome to try at your own risk." - L" If not or it doesn't look right, upgrade your graphics card.", - missing - ); - DEBUG_DISPLAY_ERROR(buf); - // TODO: i18n - } - - if (!ogl_HaveExtension("GL_ARB_texture_env_crossbar")) - { - DEBUG_DISPLAY_ERROR( - L"The GL_ARB_texture_env_crossbar extension doesn't appear to be available on your computer." - L" Shadows are not available and overall graphics quality might suffer." - L" You are advised to try installing newer drivers and/or upgrade your graphics card."); - g_ConfigDB.SetValueBool(CFG_HWDETECT, "shadows", false); - } - - ogl_WarnIfError(); - g_RenderingOptions.ReadConfigAndSetupHooks(); - InitRenderer(); + // create renderer + new CRenderer; InitInput(); - ogl_WarnIfError(); - // TODO: Is this the best place for this? if (VfsDirectoryExists(L"maps/")) CXeromyces::AddValidator(g_VFS, "map", "maps/scenario.rng"); @@ -1068,28 +716,9 @@ } } -void InitNonVisual(const CmdLineArgs& args) -{ - // Need some stuff for terrain movement costs: - // (TODO: this ought to be independent of any graphics code) - new CTerrainTextureManager; - g_TexMan.LoadTerrainTextures(); - Autostart(args); -} - -void RenderGui(bool RenderingState) -{ - g_DoRenderGui = RenderingState; -} - -void RenderLogger(bool RenderingState) +bool InitNonVisual(const CmdLineArgs& args) { - g_DoRenderLogger = RenderingState; -} - -void RenderCursor(bool RenderingState) -{ - g_DoRenderCursor = RenderingState; + return Autostart(args); } /** @@ -1137,6 +766,34 @@ return mapElement.GetText(); } +// TODO: this essentially duplicates the CGUI logic to load directory or scripts. +// NB: this won't make sure to not double-load scripts, unlike the GUI. +void AutostartLoadScript(const ScriptInterface& scriptInterface, const VfsPath& path) +{ + if (path.IsDirectory()) + { + VfsPaths pathnames; + vfs::GetPathnames(g_VFS, path, L"*.js", pathnames); + for (const VfsPath& file : pathnames) + scriptInterface.LoadGlobalScriptFile(file); + } + else + scriptInterface.LoadGlobalScriptFile(path); +} + +// TODO: this essentially duplicates the CGUI function +CParamNode GetTemplate(const std::string& templateName) +{ + // This is very cheap to create so let's just do it every time. + CTemplateLoader templateLoader; + + const CParamNode& templateRoot = templateLoader.GetTemplateFileData(templateName).GetChild("Entity"); + if (!templateRoot.IsOk()) + LOGERROR("Invalid template found for '%s'", templateName.c_str()); + + return templateRoot; +} + /* * Command line options for autostart * (keep synchronized with binaries/system/readme.txt): @@ -1150,8 +807,8 @@ * -autostart-aiseed=AISEED sets the seed used for the AI random * generator (default 0, use -1 for random) * -autostart-player=NUMBER sets the playerID in non-networked games (default 1, use -1 for observer) - * -autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV - * (skirmish and random maps only) + * -autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV (skirmish and random maps only). + * Use random for a random civ. * -autostart-team=PLAYER:TEAM sets the team for PLAYER (e.g. 2:2). * -autostart-ceasefire=NUM sets a ceasefire duration NUM * (default 0 minutes) @@ -1182,9 +839,9 @@ * * Examples: * 1) "Bob" will host a 2 player game on the Arcadia map: - * -autostart="scenarios/Arcadia" -autostart-host -autostart-host-players=2 -autostart-playername="Bob" + * -autostart="scenarios/arcadia" -autostart-host -autostart-host-players=2 -autostart-playername="Bob" * "Alice" joins the match as player 2: - * -autostart="scenarios/Arcadia" -autostart-client=127.0.0.1 -autostart-playername="Alice" + * -autostart-client=127.0.0.1 -autostart-playername="Alice" * The players use the developer overlay to control players. * * 2) Load Alpine Lakes random map with random seed, 2 players (Athens and Britons), and player 2 is PetraBot: @@ -1195,16 +852,83 @@ */ bool Autostart(const CmdLineArgs& args) { - CStr autoStartName = args.Get("autostart"); - - if (autoStartName.empty()) + if (!args.Has("autostart-client") && !args.Has("autostart")) return false; - g_Game = new CGame(!args.Has("autostart-disable-replay")); + // Get optional playername. + CStrW userName = L"anonymous"; + if (args.Has("autostart-playername")) + userName = args.Get("autostart-playername").FromUTF8(); + + // Create some scriptinterface to store the js values for the settings. + ScriptInterface scriptInterface("Engine", "Game Setup", g_ScriptContext); - ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); ScriptRequest rq(scriptInterface); + // We use the javascript gameSettings to handle options, but that requires running JS. + // Since we don't want to use the full Gui manager, we load an entrypoint script + // that can run the priviledged "LoadScript" function, and then call the appropriate function. + ScriptFunction::Register<&AutostartLoadScript>(rq, "LoadScript"); + // Load the entire folder to allow mods to extend the entrypoint without copying the whole file. + AutostartLoadScript(scriptInterface, VfsPath(L"autostart/")); + + // Provide some required functions to the script. + if (args.Has("autostart-nonvisual")) + ScriptFunction::Register<&GetTemplate>(rq, "GetTemplate"); + else + { + JSI_GUIManager::RegisterScriptFunctions(rq); + // TODO: this loads pregame, which is hardcoded to exist by various code paths. That ought be changed. + InitPs(false, L"page_pregame.xml", g_GUI->GetScriptInterface().get(), JS::UndefinedHandleValue); + } + + JSI_Game::RegisterScriptFunctions(rq); + JSI_Main::RegisterScriptFunctions(rq); + JSI_Simulation::RegisterScriptFunctions(rq); + JSI_VFS::RegisterScriptFunctions_ReadWriteAnywhere(rq); + JSI_Network::RegisterScriptFunctions(rq); + + JS::RootedValue sessionInitData(rq.cx); + + if (args.Has("autostart-client")) + { + CStr ip = args.Get("autostart-client"); + if (ip.empty()) + ip = "127.0.0.1"; + + Script::CreateObject( + rq, + &sessionInitData, + "playerName", userName, + "ip", ip, + "port", PS_DEFAULT_PORT, + "storeReplay", !args.Has("autostart-disable-replay")); + + JS::RootedValue global(rq.cx, rq.globalValue()); + if (!ScriptFunction::CallVoid(rq, global, "autostartClient", sessionInitData, true)) + return false; + + bool shouldQuit = false; + while (!shouldQuit) + { + g_NetClient->Poll(); + ScriptFunction::Call(rq, global, "onTick", shouldQuit); + std::this_thread::sleep_for(std::chrono::microseconds(200)); + } + + if (args.Has("autostart-nonvisual")) + { + LDR_NonprogressiveLoad(); + g_Game->ReallyStartGame(); + } + return true; + } + + CStr autoStartName = args.Get("autostart"); + + if (autoStartName.empty()) + return false; + JS::RootedValue attrs(rq.cx); JS::RootedValue settings(rq.cx); JS::RootedValue playerData(rq.cx); @@ -1224,28 +948,6 @@ if (mapDirectory == L"random") { - // Random map definition will be loaded from JSON file, so we need to parse it - std::wstring scriptPath = L"maps/" + autoStartName.FromUTF8() + L".json"; - JS::RootedValue scriptData(rq.cx); - Script::ReadJSONFile(rq, scriptPath, &scriptData); - if (!scriptData.isUndefined() && Script::GetProperty(rq, scriptData, "settings", &settings)) - { - // JSON loaded ok - copy script name over to game attributes - std::wstring scriptFile; - if (!Script::GetProperty(rq, settings, "Script", scriptFile)) - { - LOGERROR("Autostart: random map '%s' data has no 'Script' property.", utf8_from_wstring(scriptPath)); - throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details."); - } - Script::SetProperty(rq, attrs, "script", scriptFile); // RMS filename - } - else - { - // Problem with JSON file - LOGERROR("Autostart: Error reading random map script '%s'", utf8_from_wstring(scriptPath)); - throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details."); - } - // Get optional map size argument (default 192) uint mapSize = 192; if (args.Has("autostart-size")) @@ -1277,23 +979,10 @@ } mapType = "random"; } - else if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes") - { - // Initialize general settings from the map data so some values - // (e.g. name of map) are always present, even when autostart is - // partially configured - CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml"); - Script::ParseJSON(rq, mapSettingsJSON, &settings); - - // Initialize the playerData array being modified by autostart - // with the real map data, so sensible values are present: - Script::GetProperty(rq, settings, "PlayerData", &playerData); - - if (mapDirectory == L"scenarios") - mapType = "scenario"; - else - mapType = "skirmish"; - } + else if (mapDirectory == L"scenarios") + mapType = "scenario"; + else if (mapDirectory == L"skirmishes") + mapType = "skirmish"; else { LOGERROR("Autostart: Unrecognized map type '%s'", utf8_from_wstring(mapDirectory)); @@ -1348,15 +1037,7 @@ // Instead of overwriting existing player data, modify the array JS::RootedValue currentPlayer(rq.cx); if (!Script::GetPropertyInt(rq, playerData, playerID-offset, ¤tPlayer) || currentPlayer.isUndefined()) - { - if (mapDirectory == L"skirmishes") - { - // playerID is certainly bigger than this map player number - LOGWARNING("Autostart: Invalid player %d in autostart-team option", playerID); - continue; - } Script::CreateObject(rq, ¤tPlayer); - } int teamID = civArgs[i].AfterFirst(":").ToInt() - 1; Script::SetProperty(rq, currentPlayer, "Team", teamID); @@ -1379,15 +1060,7 @@ // Instead of overwriting existing player data, modify the array JS::RootedValue currentPlayer(rq.cx); if (!Script::GetPropertyInt(rq, playerData, playerID-offset, ¤tPlayer) || currentPlayer.isUndefined()) - { - if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes") - { - // playerID is certainly bigger than this map player number - LOGWARNING("Autostart: Invalid player %d in autostart-ai option", playerID); - continue; - } Script::CreateObject(rq, ¤tPlayer); - } Script::SetProperty(rq, currentPlayer, "AI", aiArgs[i].AfterFirst(":")); Script::SetProperty(rq, currentPlayer, "AIDiff", 3); @@ -1406,15 +1079,7 @@ // Instead of overwriting existing player data, modify the array JS::RootedValue currentPlayer(rq.cx); if (!Script::GetPropertyInt(rq, playerData, playerID-offset, ¤tPlayer) || currentPlayer.isUndefined()) - { - if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes") - { - // playerID is certainly bigger than this map player number - LOGWARNING("Autostart: Invalid player %d in autostart-aidiff option", playerID); - continue; - } Script::CreateObject(rq, ¤tPlayer); - } Script::SetProperty(rq, currentPlayer, "AIDiff", civArgs[i].AfterFirst(":").ToInt()); Script::SetPropertyInt(rq, playerData, playerID-offset, currentPlayer); @@ -1433,15 +1098,7 @@ // Instead of overwriting existing player data, modify the array JS::RootedValue currentPlayer(rq.cx); if (!Script::GetPropertyInt(rq, playerData, playerID-offset, ¤tPlayer) || currentPlayer.isUndefined()) - { - if (mapDirectory == L"skirmishes") - { - // playerID is certainly bigger than this map player number - LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID); - continue; - } Script::CreateObject(rq, ¤tPlayer); - } Script::SetProperty(rq, currentPlayer, "Civ", civArgs[i].AfterFirst(":")); Script::SetPropertyInt(rq, playerData, playerID-offset, currentPlayer); @@ -1451,17 +1108,6 @@ LOGWARNING("Autostart: Option 'autostart-civ' is invalid for scenarios"); } - // Add player data to map settings - Script::SetProperty(rq, settings, "PlayerData", playerData); - - // Add map settings to game attributes - Script::SetProperty(rq, attrs, "settings", settings); - - // Get optional playername - CStrW userName = L"anonymous"; - if (args.Has("autostart-playername")) - userName = args.Get("autostart-playername").FromUTF8(); - // Add additional scripts to the TriggerScripts property std::vector triggerScriptsVector; JS::RootedValue triggerScripts(rq.cx); @@ -1478,6 +1124,9 @@ triggerScriptsVector.push_back(nonVisualScript.FromUTF8()); } + Script::ToJSVal(rq, &triggerScripts, triggerScriptsVector); + Script::SetProperty(rq, settings, "TriggerScripts", triggerScripts); + std::vector victoryConditions(1, "conquest"); if (args.Has("autostart-victory")) victoryConditions = args.GetMultiple("autostart-victory"); @@ -1487,31 +1136,6 @@ Script::SetProperty(rq, settings, "VictoryConditions", victoryConditions); - for (const CStr& victory : victoryConditions) - { - JS::RootedValue scriptData(rq.cx); - JS::RootedValue data(rq.cx); - JS::RootedValue victoryScripts(rq.cx); - - CStrW scriptPath = L"simulation/data/settings/victory_conditions/" + victory.FromUTF8() + L".json"; - Script::ReadJSONFile(rq, scriptPath, &scriptData); - if (!scriptData.isUndefined() && Script::GetProperty(rq, scriptData, "Data", &data) && !data.isUndefined() - && Script::GetProperty(rq, data, "Scripts", &victoryScripts) && !victoryScripts.isUndefined()) - { - std::vector victoryScriptsVector; - Script::FromJSVal(rq, victoryScripts, victoryScriptsVector); - triggerScriptsVector.insert(triggerScriptsVector.end(), victoryScriptsVector.begin(), victoryScriptsVector.end()); - } - else - { - LOGERROR("Autostart: Error reading victory script '%s'", utf8_from_wstring(scriptPath)); - throw PSERROR_Game_World_MapLoadFailed("Error reading victory script.\nCheck application log for details."); - } - } - - Script::ToJSVal(rq, &triggerScripts, triggerScriptsVector); - Script::SetProperty(rq, settings, "TriggerScripts", triggerScripts); - int wonderDuration = 10; if (args.Has("autostart-wonderduration")) wonderDuration = args.Get("autostart-wonderduration").ToInt(); @@ -1527,60 +1151,69 @@ relicCount = args.Get("autostart-reliccount").ToInt(); Script::SetProperty(rq, settings, "RelicCount", relicCount); + // Add player data to map settings. + Script::SetProperty(rq, settings, "PlayerData", playerData); + + // Add map settings to game attributes. + Script::SetProperty(rq, attrs, "settings", settings); + if (args.Has("autostart-host")) { - InitPsAutostart(true, attrs); - - size_t maxPlayers = 2; + int maxPlayers = 2; if (args.Has("autostart-host-players")) maxPlayers = args.Get("autostart-host-players").ToUInt(); - // Generate a secret to identify the host client. - std::string secret = ps_generate_guid(); - - g_NetServer = new CNetServer(false, maxPlayers); - g_NetServer->SetControllerSecret(secret); - g_NetServer->UpdateInitAttributes(&attrs, scriptInterface); - - bool ok = g_NetServer->SetupConnection(PS_DEFAULT_PORT); - ENSURE(ok); - - g_NetClient = new CNetClient(g_Game); - g_NetClient->SetUserName(userName); - g_NetClient->SetupServerData("127.0.0.1", PS_DEFAULT_PORT, false); - g_NetClient->SetControllerSecret(secret); - g_NetClient->SetupConnection(nullptr); + Script::CreateObject( + rq, + &sessionInitData, + "attribs", attrs, + "playerName", userName, + "port", PS_DEFAULT_PORT, + "maxPlayers", maxPlayers, + "storeReplay", !args.Has("autostart-disable-replay")); + + JS::RootedValue global(rq.cx, rq.globalValue()); + if (!ScriptFunction::CallVoid(rq, global, "autostartHost", sessionInitData, true)) + return false; + + // In MP host mode, we need to wait until clients have loaded. + bool shouldQuit = false; + while (!shouldQuit) + { + g_NetClient->Poll(); + ScriptFunction::Call(rq, global, "onTick", shouldQuit); + std::this_thread::sleep_for(std::chrono::microseconds(200)); + } } - else if (args.Has("autostart-client")) + else { - InitPsAutostart(true, attrs); - - g_NetClient = new CNetClient(g_Game); - g_NetClient->SetUserName(userName); + JS::RootedValue localPlayer(rq.cx); + Script::CreateObject( + rq, + &localPlayer, + "player", args.Has("autostart-player") ? args.Get("autostart-player").ToInt() : 1, + "name", userName); - CStr ip = args.Get("autostart-client"); - if (ip.empty()) - ip = "127.0.0.1"; + JS::RootedValue playerAssignments(rq.cx); + Script::CreateObject(rq, &playerAssignments); + Script::SetProperty(rq, playerAssignments, "local", localPlayer); - g_NetClient->SetupServerData(ip, PS_DEFAULT_PORT, false); - ENSURE(g_NetClient->SetupConnection(nullptr)); + Script::CreateObject( + rq, + &sessionInitData, + "attribs", attrs, + "playerAssignments", playerAssignments, + "storeReplay", !args.Has("autostart-disable-replay")); + + JS::RootedValue global(rq.cx, rq.globalValue()); + if (!ScriptFunction::CallVoid(rq, global, "autostartHost", sessionInitData, false)) + return false; } - else - { - g_Game->SetPlayerID(args.Has("autostart-player") ? args.Get("autostart-player").ToInt() : 1); - - g_Game->StartGame(&attrs, ""); - if (CRenderer::IsInitialised()) - { - InitPsAutostart(false, attrs); - } - else - { - // TODO: Non progressive load can fail - need a decent way to handle this - LDR_NonprogressiveLoad(); - ENSURE(g_Game->ReallyStartGame() == PSRETURN_OK); - } + if (args.Has("autostart-nonvisual")) + { + LDR_NonprogressiveLoad(); + g_Game->ReallyStartGame(); } return true; @@ -1599,7 +1232,21 @@ ScriptRequest rq(scriptInterface); JS::RootedValue attrs(rq.cx, g_Game->GetSimulation2()->GetInitAttributes()); - InitPsAutostart(false, attrs); + JS::RootedValue playerAssignments(rq.cx); + Script::CreateObject(rq, &playerAssignments); + JS::RootedValue localPlayer(rq.cx); + Script::CreateObject(rq, &localPlayer, "player", g_Game->GetPlayerID()); + Script::SetProperty(rq, playerAssignments, "local", localPlayer); + + JS::RootedValue sessionInitData(rq.cx); + + Script::CreateObject( + rq, + &sessionInitData, + "attribs", attrs, + "playerAssignments", playerAssignments); + + InitPs(true, L"page_loading.xml", &scriptInterface, sessionInitData); return true; } diff -Nru 0ad-0.0.25b/source/ps/GameSetup/GameSetup.h 0ad-0.0.26/source/ps/GameSetup/GameSetup.h --- 0ad-0.0.25b/source/ps/GameSetup/GameSetup.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/GameSetup/GameSetup.h 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,16 +18,12 @@ #ifndef INCLUDED_GAMESETUP #define INCLUDED_GAMESETUP -// -// GUI integration -// +#include "ps/CStr.h" -// display progress / description in loading screen -extern void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task); +#include -extern void Render(); - -extern bool ShouldRender(); +class CmdLineArgs; +class Paths; /** * initialize global modules that are be needed before Init. @@ -68,20 +64,6 @@ SHUTDOWN_FROM_CONFIG = 1 }; -/** - * enable/disable rendering of the GUI (intended mainly for screenshots) - */ -extern void RenderGui(bool RenderingState); -extern void RenderLogger(bool RenderingState); - -/** - * enable/disable rendering of the cursor - this does not hide cursor, but reverts to OS style - */ -extern void RenderCursor(bool RenderingState); - - -class CmdLineArgs; -class Paths; extern const std::vector& GetMods(const CmdLineArgs& args, int flags); /** @@ -97,7 +79,7 @@ extern bool Init(const CmdLineArgs& args, int flags); extern void InitInput(); extern void InitGraphics(const CmdLineArgs& args, int flags, const std::vector& installedMods = std::vector()); -extern void InitNonVisual(const CmdLineArgs& args); +extern bool InitNonVisual(const CmdLineArgs& args); extern void Shutdown(int flags); extern void CancelLoad(const CStrW& message); diff -Nru 0ad-0.0.25b/source/ps/GameSetup/HWDetect.cpp 0ad-0.0.26/source/ps/GameSetup/HWDetect.cpp --- 0ad-0.0.25b/source/ps/GameSetup/HWDetect.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/GameSetup/HWDetect.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,20 +17,14 @@ #include "precompiled.h" -#include "lib/ogl.h" #include "lib/svn_revision.h" #include "lib/timer.h" #include "lib/utf8.h" #include "lib/external_libraries/libsdl.h" -#include "lib/res/graphics/ogl_tex.h" #include "lib/posix/posix_utsname.h" #include "lib/sysdep/cpu.h" -#include "lib/sysdep/gfx.h" #include "lib/sysdep/numa.h" #include "lib/sysdep/os_cpu.h" -#if ARCH_X86_X64 -# include "lib/sysdep/arch/x86_x64/topology.h" -#endif #if CONFIG2_AUDIO #include "soundmanager/SoundManager.h" #endif @@ -43,49 +37,26 @@ #include "ps/scripting/JSInterface_Debug.h" #include "ps/UserReport.h" #include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/JSON.h" #include "scriptinterface/Object.h" #include "scriptinterface/ScriptInterface.h" +// FreeType headers might have an include order. +#include +#include + #if OS_LINUX #include #endif -// TODO: Support OpenGL platforms which don't use GLX as well. -#if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES -#include -#include - -// Define the GLX_MESA_query_renderer macros if built with -// an old Mesa (<10.0) that doesn't provide them -#ifndef GLX_MESA_query_renderer -#define GLX_MESA_query_renderer 1 -#define GLX_RENDERER_VENDOR_ID_MESA 0x8183 -#define GLX_RENDERER_DEVICE_ID_MESA 0x8184 -#define GLX_RENDERER_VERSION_MESA 0x8185 -#define GLX_RENDERER_ACCELERATED_MESA 0x8186 -#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 -#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 -#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 -#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A -#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B -#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C -#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D -#define GLX_RENDERER_ID_MESA 0x818E -#endif /* GLX_MESA_query_renderer */ - -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 8) -#include -#endif - +#include #include +#include static void ReportSDL(const ScriptRequest& rq, JS::HandleValue settings); -static void ReportVulkan(const ScriptRequest& rq, JS::HandleValue settings); -static void ReportGLLimits(const ScriptRequest& rq, JS::HandleValue settings); +static void ReportFreeType(const ScriptRequest& rq, JS::HandleValue settings); void SetDisableAudio(bool disabled) { @@ -154,8 +125,8 @@ Script::SetProperty(rq, settings, "build_gcc", (int)GCC_VERSION); Script::SetProperty(rq, settings, "build_clang", (int)CLANG_VERSION); - Script::SetProperty(rq, settings, "gfx_card", gfx::CardName()); - Script::SetProperty(rq, settings, "gfx_drv_ver", gfx::DriverInfo()); + Script::SetProperty(rq, settings, "gfx_card", g_VideoMode.GetBackendDevice()->GetName()); + Script::SetProperty(rq, settings, "gfx_drv_ver", g_VideoMode.GetBackendDevice()->GetDriverInformation()); #if CONFIG2_AUDIO if (g_SoundManager) { @@ -165,9 +136,13 @@ #endif ReportSDL(rq, settings); - ReportVulkan(rq, settings); + ReportFreeType(rq, settings); + + JS::RootedValue backendDeviceSettings(rq.cx); + Script::CreateObject(rq, &backendDeviceSettings); - ReportGLLimits(rq, settings); + g_VideoMode.GetBackendDevice()->Report(rq, backendDeviceSettings); + Script::SetProperty(rq, settings, "renderer_backend", backendDeviceSettings); Script::SetProperty(rq, settings, "video_desktop_xres", g_VideoMode.GetDesktopXRes()); Script::SetProperty(rq, settings, "video_desktop_yres", g_VideoMode.GetDesktopYRes()); @@ -197,11 +172,6 @@ Script::SetProperty(rq, settings, "cpu_pagesize", (u32)os_cpu_PageSize()); Script::SetProperty(rq, settings, "cpu_largepagesize", (u32)os_cpu_LargePageSize()); Script::SetProperty(rq, settings, "cpu_numprocs", (u32)os_cpu_NumProcessors()); -#if ARCH_X86_X64 - Script::SetProperty(rq, settings, "cpu_numpackages", (u32)topology::NumPackages()); - Script::SetProperty(rq, settings, "cpu_coresperpackage", (u32)topology::CoresPerPackage()); - Script::SetProperty(rq, settings, "cpu_logicalpercore", (u32)topology::LogicalPerCore()); -#endif Script::SetProperty(rq, settings, "numa_numnodes", (u32)numa_NumNodes()); Script::SetProperty(rq, settings, "numa_factor", numa_Factor()); @@ -225,8 +195,10 @@ Script::SetProperty(rq, settings, "timer_resolution", timer_Resolution()); + Script::SetProperty(rq, settings, "hardware_concurrency", std::thread::hardware_concurrency()); + // The version should be increased for every meaningful change. - const int reportVersion = 16; + const int reportVersion = 20; // Send the same data to the reporting system g_UserReporter.SubmitReport( @@ -256,415 +228,30 @@ // This is null in atlas (and further the call triggers an assertion). const char* backend = g_VideoMode.GetWindow() ? GetSDLSubsystem(g_VideoMode.GetWindow()) : "none"; Script::SetProperty(rq, settings, "sdl_video_backend", backend ? backend : "unknown"); + + Script::SetProperty(rq, settings, "sdl_display_count", SDL_GetNumVideoDisplays()); + + Script::SetProperty(rq, settings, "sdl_cpu_count", SDL_GetCPUCount()); + Script::SetProperty(rq, settings, "sdl_system_ram", SDL_GetSystemRAM()); } -static void ReportVulkan(const ScriptRequest& rq, JS::HandleValue settings) +static void ReportFreeType(const ScriptRequest& rq, JS::HandleValue settings) { - std::string vulkanSupport = "unsupported"; - // According to http://wiki.libsdl.org/SDL_Vulkan_LoadLibrary the following - // functionality is supported since SDL 2.0.8. -#if SDL_VERSION_ATLEAST(2, 0, 8) - if (!SDL_Vulkan_LoadLibrary(nullptr)) - { - void* vkGetInstanceProcAddr = SDL_Vulkan_GetVkGetInstanceProcAddr(); - if (vkGetInstanceProcAddr) - vulkanSupport = "supported"; - else - vulkanSupport = "noprocaddr"; - SDL_Vulkan_UnloadLibrary(); + FT_Library FTLibrary; + std::string FTSupport = "unsupported"; + if (!FT_Init_FreeType(&FTLibrary)) + { + FT_Int major, minor, patch; + FT_Library_Version(FTLibrary, &major, &minor, &patch); + FT_Done_FreeType(FTLibrary); + std::stringstream version; + version << major << "." << minor << "." << patch; + FTSupport = version.str(); } else { - vulkanSupport = "cantload"; + FTSupport = "cantload"; } -#endif - Script::SetProperty(rq, settings, "vulkan", vulkanSupport); + Script::SetProperty(rq, settings, "freetype", FTSupport); } -static void ReportGLLimits(const ScriptRequest& rq, JS::HandleValue settings) -{ - const char* errstr = "(error)"; - -#define INTEGER(id) do { \ - GLint i = -1; \ - glGetIntegerv(GL_##id, &i); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) \ - Script::SetProperty(rq, settings, "GL_" #id, errstr); \ - else \ - Script::SetProperty(rq, settings, "GL_" #id, i); \ - } while (false) - -#define INTEGER2(id) do { \ - GLint i[2] = { -1, -1 }; \ - glGetIntegerv(GL_##id, i); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) { \ - Script::SetProperty(rq, settings, "GL_" #id "[0]", errstr); \ - Script::SetProperty(rq, settings, "GL_" #id "[1]", errstr); \ - } else { \ - Script::SetProperty(rq, settings, "GL_" #id "[0]", i[0]); \ - Script::SetProperty(rq, settings, "GL_" #id "[1]", i[1]); \ - } \ - } while (false) - -#define FLOAT(id) do { \ - GLfloat f = std::numeric_limits::quiet_NaN(); \ - glGetFloatv(GL_##id, &f); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) \ - Script::SetProperty(rq, settings, "GL_" #id, errstr); \ - else \ - Script::SetProperty(rq, settings, "GL_" #id, f); \ - } while (false) - -#define FLOAT2(id) do { \ - GLfloat f[2] = { std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN() }; \ - glGetFloatv(GL_##id, f); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) { \ - Script::SetProperty(rq, settings, "GL_" #id "[0]", errstr); \ - Script::SetProperty(rq, settings, "GL_" #id "[1]", errstr); \ - } else { \ - Script::SetProperty(rq, settings, "GL_" #id "[0]", f[0]); \ - Script::SetProperty(rq, settings, "GL_" #id "[1]", f[1]); \ - } \ - } while (false) - -#define STRING(id) do { \ - const char* c = (const char*)glGetString(GL_##id); \ - if (!c) c = ""; \ - if (ogl_SquelchError(GL_INVALID_ENUM)) c = errstr; \ - Script::SetProperty(rq, settings, "GL_" #id, std::string(c)); \ - } while (false) - -#define QUERY(target, pname) do { \ - GLint i = -1; \ - pglGetQueryivARB(GL_##target, GL_##pname, &i); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) \ - Script::SetProperty(rq, settings, "GL_" #target ".GL_" #pname, errstr); \ - else \ - Script::SetProperty(rq, settings, "GL_" #target ".GL_" #pname, i); \ - } while (false) - -#define VERTEXPROGRAM(id) do { \ - GLint i = -1; \ - pglGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_##id, &i); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) \ - Script::SetProperty(rq, settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, errstr); \ - else \ - Script::SetProperty(rq, settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, i); \ - } while (false) - -#define FRAGMENTPROGRAM(id) do { \ - GLint i = -1; \ - pglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_##id, &i); \ - if (ogl_SquelchError(GL_INVALID_ENUM)) \ - Script::SetProperty(rq, settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, errstr); \ - else \ - Script::SetProperty(rq, settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, i); \ - } while (false) - -#define BOOL(id) INTEGER(id) - - ogl_WarnIfError(); - - // Core OpenGL 1.3: - // (We don't bother checking extension strings for anything older than 1.3; - // it'll just produce harmless warnings) - STRING(VERSION); - STRING(VENDOR); - STRING(RENDERER); - STRING(EXTENSIONS); - -#if !CONFIG2_GLES - INTEGER(MAX_CLIP_PLANES); -#endif - INTEGER(SUBPIXEL_BITS); -#if !CONFIG2_GLES - INTEGER(MAX_3D_TEXTURE_SIZE); -#endif - INTEGER(MAX_TEXTURE_SIZE); - INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE); - INTEGER2(MAX_VIEWPORT_DIMS); - -#if !CONFIG2_GLES - BOOL(RGBA_MODE); - BOOL(INDEX_MODE); - BOOL(DOUBLEBUFFER); - BOOL(STEREO); -#endif - - FLOAT2(ALIASED_POINT_SIZE_RANGE); - FLOAT2(ALIASED_LINE_WIDTH_RANGE); -#if !CONFIG2_GLES - INTEGER(MAX_ELEMENTS_INDICES); - INTEGER(MAX_ELEMENTS_VERTICES); - INTEGER(MAX_TEXTURE_UNITS); -#endif - INTEGER(SAMPLE_BUFFERS); - INTEGER(SAMPLES); - // TODO: compressed texture formats - INTEGER(RED_BITS); - INTEGER(GREEN_BITS); - INTEGER(BLUE_BITS); - INTEGER(ALPHA_BITS); -#if !CONFIG2_GLES - INTEGER(INDEX_BITS); -#endif - INTEGER(DEPTH_BITS); - INTEGER(STENCIL_BITS); - -#if !CONFIG2_GLES - - // Core OpenGL 2.0 (treated as extensions): - - if (ogl_HaveExtension("GL_EXT_texture_lod_bias")) - { - FLOAT(MAX_TEXTURE_LOD_BIAS_EXT); - } - - if (ogl_HaveExtension("GL_ARB_occlusion_query")) - { - QUERY(SAMPLES_PASSED, QUERY_COUNTER_BITS); - } - - if (ogl_HaveExtension("GL_ARB_shading_language_100")) - { - STRING(SHADING_LANGUAGE_VERSION_ARB); - } - - if (ogl_HaveExtension("GL_ARB_vertex_shader")) - { - INTEGER(MAX_VERTEX_ATTRIBS_ARB); - INTEGER(MAX_VERTEX_UNIFORM_COMPONENTS_ARB); - INTEGER(MAX_VARYING_FLOATS_ARB); - INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB); - INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB); - } - - if (ogl_HaveExtension("GL_ARB_fragment_shader")) - { - INTEGER(MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB); - } - - if (ogl_HaveExtension("GL_ARB_vertex_shader") || ogl_HaveExtension("GL_ARB_fragment_shader") || - ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program")) - { - INTEGER(MAX_TEXTURE_IMAGE_UNITS_ARB); - INTEGER(MAX_TEXTURE_COORDS_ARB); - } - - if (ogl_HaveExtension("GL_ARB_draw_buffers")) - { - INTEGER(MAX_DRAW_BUFFERS_ARB); - } - - // Core OpenGL 3.0: - - if (ogl_HaveExtension("GL_EXT_gpu_shader4")) - { - INTEGER(MIN_PROGRAM_TEXEL_OFFSET); // no _EXT version of these in glext.h - INTEGER(MAX_PROGRAM_TEXEL_OFFSET); - } - - if (ogl_HaveExtension("GL_EXT_framebuffer_object")) - { - INTEGER(MAX_COLOR_ATTACHMENTS_EXT); - INTEGER(MAX_RENDERBUFFER_SIZE_EXT); - } - - if (ogl_HaveExtension("GL_EXT_framebuffer_multisample")) - { - INTEGER(MAX_SAMPLES_EXT); - } - - if (ogl_HaveExtension("GL_EXT_texture_array")) - { - INTEGER(MAX_ARRAY_TEXTURE_LAYERS_EXT); - } - - if (ogl_HaveExtension("GL_EXT_transform_feedback")) - { - INTEGER(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT); - INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT); - INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT); - } - - - // Other interesting extensions: - - if (ogl_HaveExtension("GL_EXT_timer_query") || ogl_HaveExtension("GL_ARB_timer_query")) - { - QUERY(TIME_ELAPSED, QUERY_COUNTER_BITS); - } - - if (ogl_HaveExtension("GL_ARB_timer_query")) - { - QUERY(TIMESTAMP, QUERY_COUNTER_BITS); - } - - if (ogl_HaveExtension("GL_EXT_texture_filter_anisotropic")) - { - FLOAT(MAX_TEXTURE_MAX_ANISOTROPY_EXT); - } - - if (ogl_HaveExtension("GL_ARB_texture_rectangle")) - { - INTEGER(MAX_RECTANGLE_TEXTURE_SIZE_ARB); - } - - if (ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program")) - { - INTEGER(MAX_PROGRAM_MATRICES_ARB); - INTEGER(MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB); - } - - if (ogl_HaveExtension("GL_ARB_vertex_program")) - { - VERTEXPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB); - VERTEXPROGRAM(MAX_PROGRAM_PARAMETERS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_ATTRIBS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB); - - if (ogl_HaveExtension("GL_ARB_fragment_program")) - { - // The spec seems to say these should be supported, but - // Mesa complains about them so let's not bother - /* - VERTEXPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB); - VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB); - */ - } - } - - if (ogl_HaveExtension("GL_ARB_fragment_program")) - { - FRAGMENTPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_PARAMETERS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_ATTRIBS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB); - - if (ogl_HaveExtension("GL_ARB_vertex_program")) - { - // The spec seems to say these should be supported, but - // Intel drivers on Windows complain about them so let's not bother - /* - FRAGMENTPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB); - FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB); - */ - } - } - - if (ogl_HaveExtension("GL_ARB_geometry_shader4")) - { - INTEGER(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB); - INTEGER(MAX_GEOMETRY_OUTPUT_VERTICES_ARB); - INTEGER(MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB); - INTEGER(MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB); - INTEGER(MAX_GEOMETRY_VARYING_COMPONENTS_ARB); - INTEGER(MAX_VERTEX_VARYING_COMPONENTS_ARB); - } - -#else // CONFIG2_GLES - - // Core OpenGL ES 2.0: - - STRING(SHADING_LANGUAGE_VERSION); - INTEGER(MAX_VERTEX_ATTRIBS); - INTEGER(MAX_VERTEX_UNIFORM_VECTORS); - INTEGER(MAX_VARYING_VECTORS); - INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS); - INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS); - INTEGER(MAX_FRAGMENT_UNIFORM_VECTORS); - INTEGER(MAX_TEXTURE_IMAGE_UNITS); - INTEGER(MAX_RENDERBUFFER_SIZE); - -#endif // CONFIG2_GLES - - -// TODO: Support OpenGL platforms which don't use GLX as well. -#if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES - -#define GLXQCR_INTEGER(id) do { \ - unsigned int i = UINT_MAX; \ - if (pglXQueryCurrentRendererIntegerMESA(id, &i)) \ - Script::SetProperty(rq, settings, #id, i); \ - } while (false) - -#define GLXQCR_INTEGER2(id) do { \ - unsigned int i[2] = { UINT_MAX, UINT_MAX }; \ - if (pglXQueryCurrentRendererIntegerMESA(id, i)) { \ - Script::SetProperty(rq, settings, #id "[0]", i[0]); \ - Script::SetProperty(rq, settings, #id "[1]", i[1]); \ - } \ - } while (false) - -#define GLXQCR_INTEGER3(id) do { \ - unsigned int i[3] = { UINT_MAX, UINT_MAX, UINT_MAX }; \ - if (pglXQueryCurrentRendererIntegerMESA(id, i)) { \ - Script::SetProperty(rq, settings, #id "[0]", i[0]); \ - Script::SetProperty(rq, settings, #id "[1]", i[1]); \ - Script::SetProperty(rq, settings, #id "[2]", i[2]); \ - } \ - } while (false) - -#define GLXQCR_STRING(id) do { \ - const char* str = pglXQueryCurrentRendererStringMESA(id); \ - if (str) \ - Script::SetProperty(rq, settings, #id ".string", str); \ - } while (false) - - - SDL_SysWMinfo wminfo; - SDL_VERSION(&wminfo.version); - const int ret = SDL_GetWindowWMInfo(g_VideoMode.GetWindow(), &wminfo); - if (ret && wminfo.subsystem == SDL_SYSWM_X11) - { - Display* dpy = wminfo.info.x11.display; - int scrnum = DefaultScreen(dpy); - - const char* glxexts = glXQueryExtensionsString(dpy, scrnum); - - Script::SetProperty(rq, settings, "glx_extensions", glxexts); - - if (strstr(glxexts, "GLX_MESA_query_renderer") && pglXQueryCurrentRendererIntegerMESA && pglXQueryCurrentRendererStringMESA) - { - GLXQCR_INTEGER(GLX_RENDERER_VENDOR_ID_MESA); - GLXQCR_INTEGER(GLX_RENDERER_DEVICE_ID_MESA); - GLXQCR_INTEGER3(GLX_RENDERER_VERSION_MESA); - GLXQCR_INTEGER(GLX_RENDERER_ACCELERATED_MESA); - GLXQCR_INTEGER(GLX_RENDERER_VIDEO_MEMORY_MESA); - GLXQCR_INTEGER(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA); - GLXQCR_INTEGER(GLX_RENDERER_PREFERRED_PROFILE_MESA); - GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA); - GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA); - GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA); - GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA); - GLXQCR_STRING(GLX_RENDERER_VENDOR_ID_MESA); - GLXQCR_STRING(GLX_RENDERER_DEVICE_ID_MESA); - } - } -#endif // SDL_VIDEO_DRIVER_X11 - -} diff -Nru 0ad-0.0.25b/source/ps/GameSetup/HWDetect.h 0ad-0.0.26/source/ps/GameSetup/HWDetect.h --- 0ad-0.0.25b/source/ps/GameSetup/HWDetect.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/GameSetup/HWDetect.h 2022-08-21 12:45:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 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,7 @@ /** * Runs hardware-detection script to adjust default config settings * and/or emit warnings depending on the user's system configuration. - * This must only be called after ogl_Init. + * This must only be called after backend device creation. */ void RunHardwareDetection(); diff -Nru 0ad-0.0.25b/source/ps/GUID.h 0ad-0.0.26/source/ps/GUID.h --- 0ad-0.0.25b/source/ps/GUID.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/GUID.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ #ifndef INCLUDED_GUID #define INCLUDED_GUID -class CStr8; +#include "ps/CStr.h" CStr8 ps_generate_guid(void); diff -Nru 0ad-0.0.25b/source/ps/Hashing.h 0ad-0.0.26/source/ps/Hashing.h --- 0ad-0.0.25b/source/ps/Hashing.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/Hashing.h 2022-08-21 12:45:05.000000000 +0000 @@ -18,7 +18,7 @@ #ifndef INCLUDED_HASHING #define INCLUDED_HASHING -class CStr8; +#include "ps/CStr.h" /** * Hash a string in a cryptographically secure manner. diff -Nru 0ad-0.0.25b/source/ps/KeyName.cpp 0ad-0.0.26/source/ps/KeyName.cpp --- 0ad-0.0.25b/source/ps/KeyName.cpp 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/KeyName.cpp 2022-08-21 12:45:05.000000000 +0000 @@ -24,6 +24,7 @@ #include "lib/external_libraries/libsdl.h" #include "ps/CStr.h" +#include #include #include diff -Nru 0ad-0.0.25b/source/ps/KeyName.h 0ad-0.0.26/source/ps/KeyName.h --- 0ad-0.0.25b/source/ps/KeyName.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/KeyName.h 2022-08-21 12:45:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,8 +20,7 @@ // Need SDLK_* enum values. #include "lib/external_libraries/libsdl.h" - -class CStr8; +#include "ps/CStr.h" extern SDL_Scancode FindScancode(const CStr8& keyname); // Map a scancode to a locale-independent scancode name. diff -Nru 0ad-0.0.25b/source/ps/Mod.cpp 0ad-0.0.26/source/ps/Mod.cpp --- 0ad-0.0.25b/source/ps/Mod.cpp 2021-08-22 18:37:29.000000000 +0000 +++ 0ad-0.0.26/source/ps/Mod.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include "i18n/L10n.h" #include "lib/file/file_system.h" #include "lib/file/vfs/vfs.h" +#include "lib/sysdep/os.h" #include "lib/utf8.h" #include "ps/Filesystem.h" #include "ps/GameSetup/GameSetup.h" @@ -32,9 +33,16 @@ #include "scriptinterface/ScriptExceptions.h" #include "scriptinterface/ScriptInterface.h" +#if !OS_WIN +#include "lib/os_path.h" +#endif + #include #include #include +#if OS_WIN +#include +#endif #include #include #include @@ -48,11 +56,14 @@ bool LoadModJSON(const PIVFS& vfs, OsPath modsPath, OsPath mod, std::string& text) { +#if OS_WIN + const std::filesystem::path modJsonPath = (modsPath / mod / L"mod.json").fileSystemPath(); +#else + const std::string modJsonPath = OsString(modsPath / mod / L"mod.json"); +#endif // Attempt to open mod.json first. - std::ifstream modjson; - modjson.open((modsPath / mod / L"mod.json").string8()); - - if (!modjson.is_open()) + std::ifstream modjson(modJsonPath); + if (!modjson) { modjson.close(); @@ -69,8 +80,8 @@ text = modinfo.GetAsString(); // Attempt to write the mod.json file so we'll take the fast path next time. - std::ofstream out_mod_json((modsPath / mod / L"mod.json").string8()); - if (out_mod_json.good()) + std::ofstream out_mod_json(modJsonPath); + if (out_mod_json) { out_mod_json << text; out_mod_json.close(); @@ -293,7 +304,7 @@ } modNameVersions.emplace(it->m_Name, it->m_Version); - modDependencies.emplace(it->m_Name, it->m_Dependencies); + modDependencies.emplace(it->m_Pathname, it->m_Dependencies); } static const std::vector toCheck = { "<=", ">=", "=", "<", ">" }; @@ -324,17 +335,9 @@ //0.0.24 const CStr versionToCheck = dep.substr(pos + op.size()); const std::unordered_map::iterator it = modNameVersions.find(modToCheck); - if (it == modNameVersions.end()) - { + // Could not find the mod, or 0.0.25(0ad) , <=, 0.0.24(required version) + if (it == modNameVersions.end() || !CompareVersionStrings(it->second, op, versionToCheck)) incompatibleMods.push_back(mod); - continue; - } - // 0.0.25(0ad) , <=, 0.0.24(required version) - if (!CompareVersionStrings(it->second, op, versionToCheck)) - { - incompatibleMods.push_back(mod); - continue; - } break; } } diff -Nru 0ad-0.0.25b/source/ps/ModInstaller.cpp 0ad-0.0.26/source/ps/ModInstaller.cpp --- 0ad-0.0.25b/source/ps/ModInstaller.cpp 2021-08-22 18:37:29.000000000 +0000 +++ 0ad-0.0.26/source/ps/ModInstaller.cpp 2022-09-23 19:16:54.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,13 +21,21 @@ #include "lib/file/vfs/vfs_util.h" #include "lib/file/file_system.h" +#include "lib/sysdep/os.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/XML/Xeromyces.h" #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/JSON.h" +#if !OS_WIN +#include "lib/os_path.h" +#endif + #include +#if OS_WIN +#include +#endif CModInstaller::CModInstaller(const OsPath& modsdir, const OsPath& tempdir) : m_ModsDir(modsdir), m_TempDir(tempdir / "_modscache"), m_CacheDir("cache/") @@ -107,7 +115,12 @@ DeleteDirectory(modTemp.Parent()); - std::ofstream mod_json((modDir / "mod.json").string8()); +#if OS_WIN + const std::filesystem::path modJsonPath = (modDir / L"mod.json").fileSystemPath(); +#else + const std::string modJsonPath = OsString(modDir / L"mod.json"); +#endif + std::ofstream mod_json(modJsonPath); if (mod_json.good()) { mod_json << modinfo.GetAsString(); diff -Nru 0ad-0.0.25b/source/ps/ModInstaller.h 0ad-0.0.26/source/ps/ModInstaller.h --- 0ad-0.0.25b/source/ps/ModInstaller.h 2021-08-22 18:37:36.000000000 +0000 +++ 0ad-0.0.26/source/ps/ModInstaller.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include "CStr.h" #include "lib/file/vfs/vfs.h" +#include #include class ScriptContext; diff -Nru 0ad-0.0.25b/source/ps/ModIo.cpp 0ad-0.0.26/source/ps/ModIo.cpp --- 0ad-0.0.25b/source/ps/ModIo.cpp 2021-08-22 18:37:29.000000000 +0000 +++ 0ad-0.0.26/source/ps/ModIo.cpp 2022-08-21 12:45:05.000000000 +0000 @@ -853,7 +853,7 @@ return true; } - return false; + FAIL("Invalid signature."); #undef CLEANUP } diff -Nru 0ad-0.0.25b/source/ps/Profile.cpp 0ad-0.0.26/source/ps/Profile.cpp --- 0ad-0.0.25b/source/ps/Profile.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/Profile.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,18 +27,6 @@ #include "lib/timer.h" -#if OS_WIN && !defined(NDEBUG) -# define USE_CRT_SET_ALLOC_HOOK -#endif - -#if defined(__GLIBC__) && !defined(NDEBUG) -//# define USE_GLIBC_MALLOC_HOOK -# define USE_GLIBC_MALLOC_OVERRIDE -# include -# include -# include "lib/sysdep/cpu.h" -#endif - #include /////////////////////////////////////////////////////////////////////////////////////////////// @@ -81,10 +69,8 @@ columns.push_back(ProfileColumn("Name", 230)); columns.push_back(ProfileColumn("calls/frame", 80)); columns.push_back(ProfileColumn("msec/frame", 80)); - columns.push_back(ProfileColumn("mallocs/frame", 120)); columns.push_back(ProfileColumn("calls/turn", 80)); columns.push_back(ProfileColumn("msec/turn", 80)); - columns.push_back(ProfileColumn("mallocs/turn", 80)); } }; @@ -160,23 +146,17 @@ double unlogged_time_frame = node->GetFrameTime(); double unlogged_time_turn = node->GetTurnTime(); - double unlogged_mallocs_frame = node->GetFrameMallocs(); - double unlogged_mallocs_turn = node->GetTurnMallocs(); CProfileNode::const_profile_iterator it; for (it = node->GetChildren()->begin(); it != node->GetChildren()->end(); ++it) { unlogged_time_frame -= (*it)->GetFrameTime(); unlogged_time_turn -= (*it)->GetTurnTime(); - unlogged_mallocs_frame -= (*it)->GetFrameMallocs(); - unlogged_mallocs_turn -= (*it)->GetTurnMallocs(); } for (it = node->GetScriptChildren()->begin(); it != node->GetScriptChildren()->end(); ++it) { unlogged_time_frame -= (*it)->GetFrameTime(); unlogged_time_turn -= (*it)->GetTurnTime(); - unlogged_mallocs_frame -= (*it)->GetFrameMallocs(); - unlogged_mallocs_turn -= (*it)->GetTurnMallocs(); } // The root node can't easily count per-turn values (since Turn isn't called until @@ -184,17 +164,12 @@ if (!node->GetParent()) { unlogged_time_turn = 0.0; - unlogged_mallocs_turn = 0.0; } if (col == 2) sprintf_s(buf, ARRAY_SIZE(buf), "%.3f", unlogged_time_frame * 1000.0f); - else if (col == 3) - sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", unlogged_mallocs_frame); - else if (col == 5) + else if (col == 4) sprintf_s(buf, ARRAY_SIZE(buf), "%.3f", unlogged_time_turn * 1000.f); - else if (col == 6) - sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", unlogged_mallocs_turn); return CStr(buf); } @@ -212,17 +187,11 @@ sprintf_s(buf, ARRAY_SIZE(buf), "%.3f", child->GetFrameTime() * 1000.0f); break; case 3: - sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", child->GetFrameMallocs()); - break; - case 4: sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", child->GetTurnCalls()); break; - case 5: + case 4: sprintf_s(buf, ARRAY_SIZE(buf), "%.3f", child->GetTurnTime() * 1000.0f); break; - case 6: - sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", child->GetTurnMallocs()); - break; } return CStr(buf); } @@ -312,16 +281,6 @@ return average(time_per_turn); } -double CProfileNode::GetFrameMallocs() const -{ - return average(mallocs_per_frame); -} - -double CProfileNode::GetTurnMallocs() const -{ - return average(mallocs_per_turn); -} - const CProfileNode* CProfileNode::GetChild( const char* childName ) const { const_profile_iterator it; @@ -383,11 +342,6 @@ time_frame_current = 0.0; time_turn_current = 0.0; - mallocs_per_frame.clear(); - mallocs_per_turn.clear(); - mallocs_frame_current = 0; - mallocs_turn_current = 0; - profile_iterator it; for (it = children.begin(); it != children.end(); ++it) (*it)->Reset(); @@ -399,11 +353,9 @@ { calls_per_frame.push_back(calls_frame_current); time_per_frame.push_back(time_frame_current); - mallocs_per_frame.push_back(mallocs_frame_current); calls_frame_current = 0; time_frame_current = 0.0; - mallocs_frame_current = 0; profile_iterator it; for (it = children.begin(); it != children.end(); ++it) @@ -416,11 +368,9 @@ { calls_per_turn.push_back(calls_turn_current); time_per_turn.push_back(time_turn_current); - mallocs_per_turn.push_back(mallocs_turn_current); calls_turn_current = 0; time_turn_current = 0.0; - mallocs_turn_current = 0; profile_iterator it; for (it = children.begin(); it != children.end(); ++it) @@ -429,228 +379,6 @@ (*it)->Turn(); } -// TODO: these should probably only count allocations that occur in the thread being profiled -#if defined(USE_CRT_SET_ALLOC_HOOK) - -static long malloc_count = 0; -static _CRT_ALLOC_HOOK prev_hook; - -static int crt_alloc_hook(int allocType, void* userData, size_t size, int blockType, - long requestNumber, const unsigned char* filename, int lineNumber) -{ - if (allocType == _HOOK_ALLOC && Threading::IsMainThread()) - ++malloc_count; - - if (prev_hook) - return prev_hook(allocType, userData, size, blockType, requestNumber, filename, lineNumber); - else - return 1; -} - -static void alloc_hook_initialize() -{ - prev_hook = _CrtSetAllocHook(crt_alloc_hook); -} - -static long get_memory_alloc_count() -{ - return malloc_count; -} - -#elif defined(USE_GLIBC_MALLOC_HOOK) - -// Set up malloc hooks to count allocations - see -// http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html -static intptr_t malloc_count = 0; -static void *(*old_malloc_hook) (size_t, const void*); -static std::mutex alloc_hook_mutex; -static void *malloc_hook(size_t size, const void* UNUSED(caller)) -{ - // This doesn't really work across threads. The hooks are global variables, and - // we have to temporarily unhook in order to call the real malloc, and during that - // time period another thread may perform an unhooked (hence uncounted) allocation - // which we will miss. - - // Two threads may execute the hook simultaneously, so we need to do the - // temporary unhooking in a thread-safe way, so for simplicity we just use a mutex. - std::lock_guard lock(alloc_hook_mutex); - ++malloc_count; - __malloc_hook = old_malloc_hook; - void* result = malloc(size); - old_malloc_hook = __malloc_hook; - __malloc_hook = malloc_hook; - return result; -} - -static void alloc_hook_initialize() -{ - std::lock_guard lock(alloc_hook_mutex); - old_malloc_hook = __malloc_hook; - __malloc_hook = malloc_hook; - // (we don't want to bother hooking realloc and memalign, because if they allocate - // new memory then they'll be caught by the malloc hook anyway) -} -/* -It would be nice to do: - __attribute__ ((visibility ("default"))) void (*__malloc_initialize_hook)() = malloc_initialize_hook; -except that doesn't seem to work in practice, since something (?) resets the -hook to NULL some time while loading the game, after we've set it here - so -we just call malloc_initialize_hook once inside CProfileManager::Frame instead -and hope nobody deletes our hook after that. -*/ -static long get_memory_alloc_count() -{ - return malloc_count; -} - -#elif defined(USE_GLIBC_MALLOC_OVERRIDE) - -static intptr_t alloc_count = 0; - -// We override the malloc/realloc/calloc/free functions and then use dlsym to -// defer the actual allocation to the real libc implementation. -// The dlsym call will (in glibc 2.9/2.10) call calloc once (to allocate an error -// message structure), so we have a bootstrapping problem when trying to -// get the first called function via dlsym. So we kludge it by returning a statically-allocated -// buffer for the very first call to calloc after we've called dlsym. -// This is quite hacky but it seems to just about work in practice... - -// TODO: KNOWN ISSUE: Use after free and infinite recursion -// We assign the glibc free function to libc_free in our malloc/calloc function (with dlsym). -// We did that in the free function before, but had to change it to work around the first problem described below. -// It's not a good solution because some of the problems described here can reappear when the first -// call to malloc/calloc changes and enters the function with a different state. -// -// Dl* functions (dlsym, dlopen etc.) store an error message internally if something fails. -// Calling dlerror returns a pointer to this error message. Calling dlerror a second time or calling dlsym -// causes it to free the internal storage for this error message. -// This behaviour can cause two types of problems: -// -// 1. Infinite recursion due to free call -// Problem occurs if: We use any of the dl* functions in our free function and free gets called with an internal -// error message buffer allocated. -// What happens: Our call to the dl* function causes another free-call insdie glibc which calls our free function -// and can cause infinite recursion. -// -// 2. Use after free -// Problem occurs if: An external library (or any other function) calls a dl* function that stores an internal -// error string, then calls dlerror to receive the message and then calls any of our malloc/calloc/realloc/free fuctions. -// Our function uses one of the dl* functions too. After calling our function, it tries to use the error message pointer -// it got with dlerror before. -// What happens: Our call to the dl* function will free the storage of the message and the pointer in the external library -// becomes invalid. We get undefined behaviour if the extern library uses the error message pointer after that. - - -static bool alloc_bootstrapped = false; -static char alloc_bootstrap_buffer[32]; // sufficient for x86_64 -static bool alloc_has_called_dlsym = false; -static void (*libc_free)(void*) = NULL; -// (We'll only be running a single thread at this point so no need for locking these variables) - -//#define ALLOC_DEBUG - -void* malloc(size_t sz) -{ - cpu_AtomicAdd(&alloc_count, 1); - - static void *(*libc_malloc)(size_t); - if (libc_malloc == NULL) - { - alloc_has_called_dlsym = true; - libc_malloc = (void *(*)(size_t)) dlsym(RTLD_NEXT, "malloc"); - } - void* ret = libc_malloc(sz); -#ifdef ALLOC_DEBUG - printf("### malloc(%d) = %p\n", sz, ret); -#endif - - if (libc_free == NULL) - libc_free = (void (*)(void*)) dlsym(RTLD_NEXT, "free"); - - return ret; -} - -void* realloc(void* ptr, size_t sz) -{ - cpu_AtomicAdd(&alloc_count, 1); - - static void *(*libc_realloc)(void*, size_t); - if (libc_realloc == NULL) - { - alloc_has_called_dlsym = true; - libc_realloc = (void *(*)(void*, size_t)) dlsym(RTLD_NEXT, "realloc"); - } - void* ret = libc_realloc(ptr, sz); -#ifdef ALLOC_DEBUG - printf("### realloc(%p, %d) = %p\n", ptr, sz, ret); -#endif - return ret; -} - -void* calloc(size_t nm, size_t sz) -{ - cpu_AtomicAdd(&alloc_count, 1); - - static void *(*libc_calloc)(size_t, size_t); - if (libc_calloc == NULL) - { - if (alloc_has_called_dlsym && !alloc_bootstrapped) - { - ENSURE(nm*sz <= ARRAY_SIZE(alloc_bootstrap_buffer)); -#ifdef ALLOC_DEBUG - printf("### calloc-bs(%d, %d) = %p\n", nm, sz, alloc_bootstrap_buffer); -#endif - alloc_bootstrapped = true; - return alloc_bootstrap_buffer; - } - alloc_has_called_dlsym = true; - libc_calloc = (void *(*)(size_t, size_t)) dlsym(RTLD_NEXT, "calloc"); - } - void* ret = libc_calloc(nm, sz); -#ifdef ALLOC_DEBUG - printf("### calloc(%d, %d) = %p\n", nm, sz, ret); -#endif - - if (libc_free == NULL) - libc_free = (void (*)(void*)) dlsym(RTLD_NEXT, "free"); - - return ret; -} - -void free(void* ptr) -{ - // Might be triggered if free is called before any calloc/malloc calls or if the dlsym call inside - // our calloc/malloc function causes a free call. Read the known issue comment block a few lines above. - ENSURE (libc_free != NULL); - - libc_free(ptr); -#ifdef ALLOC_DEBUG - printf("### free(%p)\n", ptr); -#endif -} - -static void alloc_hook_initialize() -{ -} - -static long get_memory_alloc_count() -{ - return alloc_count; -} - -#else - -static void alloc_hook_initialize() -{ -} -static long get_memory_alloc_count() -{ - // TODO: don't show this column of data when we don't have sensible values - // to display. - return 0; -} -#endif - void CProfileNode::Call() { calls_frame_current++; @@ -658,7 +386,6 @@ if (recursion++ == 0) { start = timer_Time(); - start_mallocs = get_memory_alloc_count(); } } @@ -668,11 +395,8 @@ return false; double now = timer_Time(); - long allocs = get_memory_alloc_count(); time_frame_current += (now - start); time_turn_current += (now - start); - mallocs_frame_current += (allocs - start_mallocs); - mallocs_turn_current += (allocs - start_mallocs); return true; } @@ -714,10 +438,7 @@ void CProfileManager::Frame() { - ONCE(alloc_hook_initialize()); - root->time_frame_current += (timer_Time() - root->start); - root->mallocs_frame_current += (get_memory_alloc_count() - root->start_mallocs); root->Frame(); @@ -728,7 +449,6 @@ } root->start = timer_Time(); - root->start_mallocs = get_memory_alloc_count(); } void CProfileManager::Turn() diff -Nru 0ad-0.0.25b/source/ps/Profile.h 0ad-0.0.26/source/ps/Profile.h --- 0ad-0.0.25b/source/ps/Profile.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/Profile.h 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -62,8 +62,6 @@ double GetFrameTime() const; double GetTurnCalls() const; double GetTurnTime() const; - double GetFrameMallocs() const; - double GetTurnMallocs() const; const CProfileNode* GetChild( const char* name ) const; const CProfileNode* GetScriptChild( const char* name ) const; @@ -103,13 +101,7 @@ RingBuf time_per_frame; RingBuf time_per_turn; - long mallocs_frame_current; - long mallocs_turn_current; - RingBuf mallocs_per_frame; - RingBuf mallocs_per_turn; - double start; - long start_mallocs; int recursion; CProfileNode* parent; diff -Nru 0ad-0.0.25b/source/ps/Profiler2GPU.cpp 0ad-0.0.26/source/ps/Profiler2GPU.cpp --- 0ad-0.0.25b/source/ps/Profiler2GPU.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/Profiler2GPU.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,77 +25,16 @@ #include "Profiler2GPU.h" #include "lib/ogl.h" -#include "lib/allocators/shared_ptr.h" #include "ps/ConfigDB.h" #include "ps/Profiler2.h" +#include "ps/VideoMode.h" #include #include +#include #if !CONFIG2_GLES -class CProfiler2GPU_base -{ - NONCOPYABLE(CProfiler2GPU_base); - -protected: - CProfiler2GPU_base(CProfiler2& profiler, const char* name) : - m_Profiler(profiler), m_Storage(*new CProfiler2::ThreadStorage(profiler, name)) - { - m_Storage.RecordSyncMarker(m_Profiler.GetTime()); - m_Storage.Record(CProfiler2::ITEM_EVENT, m_Profiler.GetTime(), "thread start"); - - m_Profiler.AddThreadStorage(&m_Storage); - } - - ~CProfiler2GPU_base() - { - m_Profiler.RemoveThreadStorage(&m_Storage); - } - - CProfiler2& m_Profiler; - CProfiler2::ThreadStorage& m_Storage; -}; - -////////////////////////////////////////////////////////////////////////// - -// Base class for ARB_timer_query, EXT_timer_query -class CProfiler2GPU_timer_query : public CProfiler2GPU_base -{ -protected: - CProfiler2GPU_timer_query(CProfiler2& profiler, const char* name) : - CProfiler2GPU_base(profiler, name) - { - } - - ~CProfiler2GPU_timer_query() - { - if (!m_FreeQueries.empty()) - pglDeleteQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]); - ogl_WarnIfError(); - } - - // Returns a new GL query object (or a recycled old one) - GLuint NewQuery() - { - if (m_FreeQueries.empty()) - { - // Generate a batch of new queries - m_FreeQueries.resize(8); - pglGenQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]); - ogl_WarnIfError(); - } - - GLuint query = m_FreeQueries.back(); - m_FreeQueries.pop_back(); - return query; - } - - std::vector m_FreeQueries; // query objects that are allocated but not currently in used -}; - -////////////////////////////////////////////////////////////////////////// - /* * GL_ARB_timer_query supports sync and async queries for absolute GPU * timestamps, which lets us time regions of code relative to the CPU. @@ -105,8 +44,10 @@ * When all the queries for a frame have their results available, * we convert their GPU timestamps into CPU times and record the data. */ -class CProfiler2GPU_ARB_timer_query : public CProfiler2GPU_timer_query +class CProfiler2GPUARB { + NONCOPYABLE(CProfiler2GPUARB); + struct SEvent { const char* id; @@ -129,21 +70,34 @@ public: static bool IsSupported() { + if (g_VideoMode.GetBackend() != CVideoMode::Backend::GL) + return false; return ogl_HaveExtension("GL_ARB_timer_query"); } - CProfiler2GPU_ARB_timer_query(CProfiler2& profiler) : - CProfiler2GPU_timer_query(profiler, "gpu_arb") + CProfiler2GPUARB(CProfiler2& profiler) + : m_Profiler(profiler), m_Storage(*new CProfiler2::ThreadStorage(profiler, "gpu_arb")) { // TODO: maybe we should check QUERY_COUNTER_BITS to ensure it's // high enough (but apparently it might trigger GL errors on ATI) + + m_Storage.RecordSyncMarker(m_Profiler.GetTime()); + m_Storage.Record(CProfiler2::ITEM_EVENT, m_Profiler.GetTime(), "thread start"); + + m_Profiler.AddThreadStorage(&m_Storage); } - ~CProfiler2GPU_ARB_timer_query() + ~CProfiler2GPUARB() { // Pop frames to return queries to the free list while (!m_Frames.empty()) PopFrontFrame(); + + if (!m_FreeQueries.empty()) + glDeleteQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]); + ogl_WarnIfError(); + + m_Profiler.RemoveThreadStorage(&m_Storage); } void FrameStart() @@ -169,7 +123,7 @@ { PROFILE2("profile timestamp resync"); - pglGetInteger64v(GL_TIMESTAMP, &frame.syncTimestampStart); + glGetInteger64v(GL_TIMESTAMP, &frame.syncTimestampStart); ogl_WarnIfError(); frame.syncTimeStart = m_Profiler.GetTime(); @@ -203,7 +157,7 @@ event.query = NewQuery(); event.isEnter = isEnter; - pglQueryCounter(event.query, GL_TIMESTAMP); + glQueryCounter(event.query, GL_TIMESTAMP); ogl_WarnIfError(); frame.events.push_back(event); @@ -229,7 +183,7 @@ // Queries become available in order so we only need to check the last one GLint available = 0; - pglGetQueryObjectivARB(frame.events.back().query, GL_QUERY_RESULT_AVAILABLE, &available); + glGetQueryObjectivARB(frame.events.back().query, GL_QUERY_RESULT_AVAILABLE, &available); ogl_WarnIfError(); if (!available) break; @@ -239,7 +193,7 @@ for (size_t i = 0; i < frame.events.size(); ++i) { GLuint64 queryTimestamp = 0; - pglGetQueryObjectui64v(frame.events[i].query, GL_QUERY_RESULT, &queryTimestamp); + glGetQueryObjectui64v(frame.events[i].query, GL_QUERY_RESULT, &queryTimestamp); // (use the non-suffixed function here, as defined by GL_ARB_timer_query) ogl_WarnIfError(); @@ -272,602 +226,79 @@ m_FreeQueries.push_back(frame.events[i].query); m_Frames.pop_front(); } -}; - -////////////////////////////////////////////////////////////////////////// - -/* - * GL_EXT_timer_query only supports async queries for elapsed time, - * and only a single simultaneous query. - * We can't correctly convert it to absolute time, so we just pretend - * each GPU frame starts the same time as the CPU for that frame. - * We do a query for elapsed time between every adjacent enter/leave-region event. - * When all the queries for a frame have their results available, - * we sum the elapsed times to calculate when each event occurs within the - * frame, and record the data. - */ -class CProfiler2GPU_EXT_timer_query : public CProfiler2GPU_timer_query -{ - struct SEvent - { - const char* id; - GLuint query; // query for time elapsed from this event until the next, or 0 for final event - bool isEnter; // true if entering region; false if leaving - }; - - struct SFrame - { - u32 num; - double timeStart; // CPU time at frame start - std::vector events; - }; - - std::deque m_Frames; - -public: - static bool IsSupported() - { - return ogl_HaveExtension("GL_EXT_timer_query"); - } - - CProfiler2GPU_EXT_timer_query(CProfiler2& profiler) : - CProfiler2GPU_timer_query(profiler, "gpu_ext") - { - } - - ~CProfiler2GPU_EXT_timer_query() - { - // Pop frames to return queries to the free list - while (!m_Frames.empty()) - PopFrontFrame(); - } - - void FrameStart() - { - ProcessFrames(); - - SFrame frame; - frame.num = m_Profiler.GetFrameNumber(); - frame.timeStart = m_Profiler.GetTime(); - - m_Frames.push_back(frame); - - RegionEnter("frame"); - } - - void FrameEnd() - { - RegionLeave("frame"); - - pglEndQueryARB(GL_TIME_ELAPSED); - ogl_WarnIfError(); - } - - void RecordRegion(const char* id, bool isEnter) - { - ENSURE(!m_Frames.empty()); - SFrame& frame = m_Frames.back(); - - // Must call glEndQuery before calling glGenQueries (via NewQuery), - // for compatibility with the GL_EXT_timer_query spec (which says - // GL_INVALID_OPERATION if a query of any target is active; the ARB - // spec and OpenGL specs don't appear to say that, but the AMD drivers - // implement that error (see Trac #1033)) - - if (!frame.events.empty()) - { - pglEndQueryARB(GL_TIME_ELAPSED); - ogl_WarnIfError(); - } - - SEvent event; - event.id = id; - event.query = NewQuery(); - event.isEnter = isEnter; - - pglBeginQueryARB(GL_TIME_ELAPSED, event.query); - ogl_WarnIfError(); - - frame.events.push_back(event); - } - - void RegionEnter(const char* id) - { - RecordRegion(id, true); - } - void RegionLeave(const char* id) - { - RecordRegion(id, false); - } - -private: - void ProcessFrames() - { - while (!m_Frames.empty()) - { - SFrame& frame = m_Frames.front(); - - // Queries become available in order so we only need to check the last one - GLint available = 0; - pglGetQueryObjectivARB(frame.events.back().query, GL_QUERY_RESULT_AVAILABLE, &available); - ogl_WarnIfError(); - if (!available) - break; - - // The frame's queries are now available, so retrieve and record all their results: - - double t = frame.timeStart; - m_Storage.RecordFrameStart(t); - - for (size_t i = 0; i < frame.events.size(); ++i) - { - if (frame.events[i].isEnter) - m_Storage.Record(CProfiler2::ITEM_ENTER, t, frame.events[i].id); - else - m_Storage.RecordLeave(t); - - // Associate the frame number with the "frame" region - if (i == 0) - m_Storage.RecordAttributePrintf("%u", frame.num); - - // Advance by the elapsed time to the next event - GLuint64 queryElapsed = 0; - pglGetQueryObjectui64vEXT(frame.events[i].query, GL_QUERY_RESULT, &queryElapsed); - // (use the EXT-suffixed function here, as defined by GL_EXT_timer_query) - ogl_WarnIfError(); - t += (double)queryElapsed / 1e9; - } - - PopFrontFrame(); - } - } - - void PopFrontFrame() - { - ENSURE(!m_Frames.empty()); - SFrame& frame = m_Frames.front(); - for (size_t i = 0; i < frame.events.size(); ++i) - m_FreeQueries.push_back(frame.events[i].query); - m_Frames.pop_front(); - } -}; - -////////////////////////////////////////////////////////////////////////// - -/* - * GL_INTEL_performance_queries is not officially documented - * (see http://zaynar.co.uk/docs/gl-intel-performance-queries.html) - * but it's potentially useful so we'll support it anyway. - * It supports async queries giving elapsed time plus a load of other - * counters that we'd like to use, and supports many simultaneous queries - * (unlike GL_EXT_timer_query). - * There are multiple query types (typically 2), each with its own set of - * multiple counters. - * On each enter-region event, we start a new set of queries. - * On each leave-region event, we end the corresponding set of queries. - * We can't tell the offsets between the enter events of nested regions, - * so we pretend they all got entered at the same time. - */ -class CProfiler2GPU_INTEL_performance_queries : public CProfiler2GPU_base -{ - struct SEvent - { - const char* id; - bool isEnter; - std::vector queries; // if isEnter, one per SPerfQueryType; else empty - }; - - struct SFrame - { - u32 num; - double timeStart; // CPU time at frame start - std::vector events; - std::vector activeRegions; // stack of indexes into events - }; - - std::deque m_Frames; - - // Counters listed by the graphics driver for a particular query type - struct SPerfCounter - { - std::string name; - std::string desc; - GLuint offset; - GLuint size; - GLuint type; - }; - - // Query types listed by the graphics driver - struct SPerfQueryType - { - GLuint queryTypeId; - std::string name; - GLuint counterBufferSize; - std::vector counters; - - std::vector freeQueries; // query objects that are allocated but not currently in use - }; - - std::vector m_QueryTypes; - - #define INTEL_PERFQUERIES_NONBLOCK 0x83FA - #define INTEL_PERFQUERIES_BLOCK 0x83FB - #define INTEL_PERFQUERIES_TYPE_UNSIGNED_INT 0x9402 - #define INTEL_PERFQUERIES_TYPE_UNSIGNED_INT64 0x9403 - #define INTEL_PERFQUERIES_TYPE_FLOAT 0x9404 - #define INTEL_PERFQUERIES_TYPE_BOOL 0x9406 - -public: - static bool IsSupported() - { - return ogl_HaveExtension("GL_INTEL_performance_queries"); - } - - CProfiler2GPU_INTEL_performance_queries(CProfiler2& profiler) : - CProfiler2GPU_base(profiler, "gpu_intel") - { - LoadPerfCounters(); - } - - ~CProfiler2GPU_INTEL_performance_queries() - { - // Pop frames to return queries to the free list - while (!m_Frames.empty()) - PopFrontFrame(); - - for (size_t i = 0; i < m_QueryTypes.size(); ++i) - for (size_t j = 0; j < m_QueryTypes[i].freeQueries.size(); ++j) - pglDeletePerfQueryINTEL(m_QueryTypes[i].freeQueries[j]); - - ogl_WarnIfError(); - } - - void FrameStart() - { - ProcessFrames(); - - SFrame frame; - frame.num = m_Profiler.GetFrameNumber(); - frame.timeStart = m_Profiler.GetTime(); - - m_Frames.push_back(frame); - - RegionEnter("frame"); - } - - void FrameEnd() - { - RegionLeave("frame"); - } - - void RegionEnter(const char* id) - { - ENSURE(!m_Frames.empty()); - SFrame& frame = m_Frames.back(); - - SEvent event; - event.id = id; - event.isEnter = true; - - for (size_t i = 0; i < m_QueryTypes.size(); ++i) - { - GLuint local_id = NewQuery(i); - pglBeginPerfQueryINTEL(local_id); - ogl_WarnIfError(); - event.queries.push_back(local_id); - } - - frame.activeRegions.push_back(frame.events.size()); - - frame.events.push_back(event); - } - - void RegionLeave(const char* id) - { - ENSURE(!m_Frames.empty()); - SFrame& frame = m_Frames.back(); - - ENSURE(!frame.activeRegions.empty()); - SEvent& activeEvent = frame.events[frame.activeRegions.back()]; - - for (size_t i = 0; i < m_QueryTypes.size(); ++i) - { - pglEndPerfQueryINTEL(activeEvent.queries[i]); - ogl_WarnIfError(); - } - - frame.activeRegions.pop_back(); - - SEvent event; - event.id = id; - event.isEnter = false; - frame.events.push_back(event); - } - -private: - GLuint NewQuery(size_t queryIdx) + // Returns a new GL query object (or a recycled old one) + GLuint NewQuery() { - ENSURE(queryIdx < m_QueryTypes.size()); - - if (m_QueryTypes[queryIdx].freeQueries.empty()) + if (m_FreeQueries.empty()) { - GLuint id; - pglCreatePerfQueryINTEL(m_QueryTypes[queryIdx].queryTypeId, &id); + // Generate a batch of new queries + m_FreeQueries.resize(8); + glGenQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]); ogl_WarnIfError(); - return id; } - GLuint id = m_QueryTypes[queryIdx].freeQueries.back(); - m_QueryTypes[queryIdx].freeQueries.pop_back(); - return id; - } - - void ProcessFrames() - { - while (!m_Frames.empty()) - { - SFrame& frame = m_Frames.front(); - - // Queries don't become available in order, so check them all before - // trying to read the results from any - for (size_t j = 0; j < m_QueryTypes.size(); ++j) - { - size_t size = m_QueryTypes[j].counterBufferSize; - std::shared_ptr buf(new char[size], ArrayDeleter()); - - for (size_t i = 0; i < frame.events.size(); ++i) - { - if (!frame.events[i].isEnter) - continue; - - GLuint length = 0; - pglGetPerfQueryDataINTEL(frame.events[i].queries[j], INTEL_PERFQUERIES_NONBLOCK, size, buf.get(), &length); - ogl_WarnIfError(); - if (length == 0) - return; - } - } - - double lastTime = frame.timeStart; - std::stack endTimes; - - m_Storage.RecordFrameStart(frame.timeStart); - - for (size_t i = 0; i < frame.events.size(); ++i) - { - if (frame.events[i].isEnter) - { - m_Storage.Record(CProfiler2::ITEM_ENTER, lastTime, frame.events[i].id); - - if (i == 0) - m_Storage.RecordAttributePrintf("%u", frame.num); - - double elapsed = 0.0; - - for (size_t j = 0; j < m_QueryTypes.size(); ++j) - { - GLuint length; - char* buf = new char[m_QueryTypes[j].counterBufferSize]; - pglGetPerfQueryDataINTEL(frame.events[i].queries[j], INTEL_PERFQUERIES_BLOCK, m_QueryTypes[j].counterBufferSize, buf, &length); - ogl_WarnIfError(); - ENSURE(length == m_QueryTypes[j].counterBufferSize); - - m_Storage.RecordAttributePrintf("-- %s --", m_QueryTypes[j].name.c_str()); - - for (size_t k = 0; k < m_QueryTypes[j].counters.size(); ++k) - { - SPerfCounter& counter = m_QueryTypes[j].counters[k]; - - if (counter.type == INTEL_PERFQUERIES_TYPE_UNSIGNED_INT) - { - ENSURE(counter.size == 4); - GLuint value = 0; - memcpy(&value, buf + counter.offset, counter.size); - m_Storage.RecordAttributePrintf("%s: %u", counter.name.c_str(), value); - } - else if (counter.type == INTEL_PERFQUERIES_TYPE_UNSIGNED_INT64) - { - ENSURE(counter.size == 8); - GLuint64 value = 0; - memcpy(&value, buf + counter.offset, counter.size); - m_Storage.RecordAttributePrintf("%s: %.0f", counter.name.c_str(), (double)value); - - if (counter.name == "TotalTime") - elapsed = (double)value / 1e6; - } - else if (counter.type == INTEL_PERFQUERIES_TYPE_FLOAT) - { - ENSURE(counter.size == 4); - GLfloat value = 0; - memcpy(&value, buf + counter.offset, counter.size); - m_Storage.RecordAttributePrintf("%s: %f", counter.name.c_str(), value); - } - else if (counter.type == INTEL_PERFQUERIES_TYPE_BOOL) - { - ENSURE(counter.size == 4); - GLuint value = 0; - memcpy(&value, buf + counter.offset, counter.size); - ENSURE(value == 0 || value == 1); - m_Storage.RecordAttributePrintf("%s: %u", counter.name.c_str(), value); - } - else - { - //debug_warn(L"unrecognised Intel performance counter type"); - } - } - - delete[] buf; - } - - endTimes.push(lastTime + elapsed); - } - else - { - lastTime = endTimes.top(); - endTimes.pop(); - m_Storage.RecordLeave(lastTime); - } - } - - PopFrontFrame(); - } - } - - void PopFrontFrame() - { - ENSURE(!m_Frames.empty()); - SFrame& frame = m_Frames.front(); - for (size_t i = 0; i < frame.events.size(); ++i) - if (frame.events[i].isEnter) - for (size_t j = 0; j < m_QueryTypes.size(); ++j) - m_QueryTypes[j].freeQueries.push_back(frame.events[i].queries[j]); - m_Frames.pop_front(); + GLuint query = m_FreeQueries.back(); + m_FreeQueries.pop_back(); + return query; } - void LoadPerfCounters() - { - GLuint queryTypeId; - pglGetFirstPerfQueryIdINTEL(&queryTypeId); - ogl_WarnIfError(); - do - { - char queryName[256]; - GLuint counterBufferSize, numCounters, maxQueries, unknown; - pglGetPerfQueryInfoINTEL(queryTypeId, ARRAY_SIZE(queryName), queryName, &counterBufferSize, &numCounters, &maxQueries, &unknown); - ogl_WarnIfError(); - ENSURE(unknown == 1); - - SPerfQueryType query; - query.queryTypeId = queryTypeId; - query.name = queryName; - query.counterBufferSize = counterBufferSize; - - for (GLuint counterId = 1; counterId <= numCounters; ++counterId) - { - char counterName[256]; - char counterDesc[2048]; - GLuint counterOffset, counterSize, counterUsage, counterType; - GLuint64 unknown2; - pglGetPerfCounterInfoINTEL(queryTypeId, counterId, ARRAY_SIZE(counterName), counterName, ARRAY_SIZE(counterDesc), counterDesc, &counterOffset, &counterSize, &counterUsage, &counterType, &unknown2); - ogl_WarnIfError(); - ENSURE(unknown2 == 0 || unknown2 == 1); - - SPerfCounter counter; - counter.name = counterName; - counter.desc = counterDesc; - counter.offset = counterOffset; - counter.size = counterSize; - counter.type = counterType; - query.counters.push_back(counter); - } - - m_QueryTypes.push_back(query); - - pglGetNextPerfQueryIdINTEL(queryTypeId, &queryTypeId); - ogl_WarnIfError(); + CProfiler2& m_Profiler; + CProfiler2::ThreadStorage& m_Storage; - } while (queryTypeId); - } + std::vector m_FreeQueries; // query objects that are allocated but not currently in used }; -////////////////////////////////////////////////////////////////////////// - CProfiler2GPU::CProfiler2GPU(CProfiler2& profiler) : - m_Profiler(profiler), m_ProfilerARB(NULL), m_ProfilerEXT(NULL), m_ProfilerINTEL(NULL) + m_Profiler(profiler) { bool enabledARB = false; - bool enabledEXT = false; - bool enabledINTEL = false; CFG_GET_VAL("profiler2.gpu.arb.enable", enabledARB); - CFG_GET_VAL("profiler2.gpu.ext.enable", enabledEXT); - CFG_GET_VAL("profiler2.gpu.intel.enable", enabledINTEL); - // Only enable either ARB or EXT, not both, because they are redundant - // (EXT is only needed for compatibility with older systems), and because - // using both triggers GL_INVALID_OPERATION on AMD drivers (see comment - // in CProfiler2GPU_EXT_timer_query::RecordRegion) - if (enabledARB && CProfiler2GPU_ARB_timer_query::IsSupported()) - { - m_ProfilerARB = new CProfiler2GPU_ARB_timer_query(m_Profiler); - } - else if (enabledEXT && CProfiler2GPU_EXT_timer_query::IsSupported()) + if (enabledARB && CProfiler2GPUARB::IsSupported()) { - m_ProfilerEXT = new CProfiler2GPU_EXT_timer_query(m_Profiler); - } - - // The INTEL mode should be compatible with ARB/EXT (though no current - // drivers support both), and provides complementary data, so enable it - // when possible - if (enabledINTEL && CProfiler2GPU_INTEL_performance_queries::IsSupported()) - { - m_ProfilerINTEL = new CProfiler2GPU_INTEL_performance_queries(m_Profiler); + m_ProfilerARB = std::make_unique(m_Profiler); } } -CProfiler2GPU::~CProfiler2GPU() -{ - SAFE_DELETE(m_ProfilerARB); - SAFE_DELETE(m_ProfilerEXT); - SAFE_DELETE(m_ProfilerINTEL); -} +CProfiler2GPU::~CProfiler2GPU() = default; void CProfiler2GPU::FrameStart() { if (m_ProfilerARB) m_ProfilerARB->FrameStart(); - - if (m_ProfilerEXT) - m_ProfilerEXT->FrameStart(); - - if (m_ProfilerINTEL) - m_ProfilerINTEL->FrameStart(); } void CProfiler2GPU::FrameEnd() { if (m_ProfilerARB) m_ProfilerARB->FrameEnd(); - - if (m_ProfilerEXT) - m_ProfilerEXT->FrameEnd(); - - if (m_ProfilerINTEL) - m_ProfilerINTEL->FrameEnd(); } void CProfiler2GPU::RegionEnter(const char* id) { if (m_ProfilerARB) m_ProfilerARB->RegionEnter(id); - - if (m_ProfilerEXT) - m_ProfilerEXT->RegionEnter(id); - - if (m_ProfilerINTEL) - m_ProfilerINTEL->RegionEnter(id); } void CProfiler2GPU::RegionLeave(const char* id) { if (m_ProfilerARB) m_ProfilerARB->RegionLeave(id); - - if (m_ProfilerEXT) - m_ProfilerEXT->RegionLeave(id); - - if (m_ProfilerINTEL) - m_ProfilerINTEL->RegionLeave(id); } #else // CONFIG2_GLES -CProfiler2GPU::CProfiler2GPU(CProfiler2& profiler) : - m_Profiler(profiler), m_ProfilerARB(NULL), m_ProfilerEXT(NULL), m_ProfilerINTEL(NULL) +class CProfiler2GPUARB +{ +public: +}; + +CProfiler2GPU::CProfiler2GPU(CProfiler2& UNUSED(profiler)) { } -CProfiler2GPU::~CProfiler2GPU() { } +CProfiler2GPU::~CProfiler2GPU() = default; void CProfiler2GPU::FrameStart() { } void CProfiler2GPU::FrameEnd() { } diff -Nru 0ad-0.0.25b/source/ps/Profiler2GPU.h 0ad-0.0.26/source/ps/Profiler2GPU.h --- 0ad-0.0.25b/source/ps/Profiler2GPU.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/Profiler2GPU.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -20,10 +20,12 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "lib/config2.h" + +#include + class CProfiler2; -class CProfiler2GPU_ARB_timer_query; -class CProfiler2GPU_EXT_timer_query; -class CProfiler2GPU_INTEL_performance_queries; +class CProfiler2GPUARB; /** * Used by CProfiler2 for GPU profiling support. @@ -42,9 +44,9 @@ void RegionLeave(const char* id); private: +#if !CONFIG2_GLES CProfiler2& m_Profiler; +#endif - CProfiler2GPU_ARB_timer_query* m_ProfilerARB; - CProfiler2GPU_EXT_timer_query* m_ProfilerEXT; - CProfiler2GPU_INTEL_performance_queries* m_ProfilerINTEL; + std::unique_ptr m_ProfilerARB; }; diff -Nru 0ad-0.0.25b/source/ps/Profiler2.h 0ad-0.0.26/source/ps/Profiler2.h --- 0ad-0.0.25b/source/ps/Profiler2.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/Profiler2.h 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -95,7 +95,7 @@ class CProfiler2 { - friend class CProfiler2GPU_base; + friend class CProfiler2GPUARB; friend class CProfile2SpikeRegion; friend class CProfile2AggregatedRegion; public: diff -Nru 0ad-0.0.25b/source/ps/ProfileViewer.cpp 0ad-0.0.26/source/ps/ProfileViewer.cpp --- 0ad-0.0.25b/source/ps/ProfileViewer.cpp 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/ProfileViewer.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,11 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * Implementation of profile display (containing only display routines, - * the data model(s) are implemented elsewhere). - */ - #include "precompiled.h" #include "ProfileViewer.h" @@ -40,8 +35,8 @@ #include "scriptinterface/Object.h" #include -#include #include +#include struct CProfileViewerInternals { @@ -149,7 +144,7 @@ // Render -void CProfileViewer::RenderProfile() +void CProfileViewer::RenderProfile(CCanvas2D& canvas) { if (!m->profileVisible) return; @@ -170,8 +165,6 @@ CFontMetrics font(font_name); int lineSpacing = font.GetLineSpacing(); - CCanvas2D canvas; - // Render background. float estimateWidth = 50.0f; for (const ProfileColumn& column : columns) diff -Nru 0ad-0.0.25b/source/ps/ProfileViewer.h 0ad-0.0.26/source/ps/ProfileViewer.h --- 0ad-0.0.25b/source/ps/ProfileViewer.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/ProfileViewer.h 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include -class ScriptInterface; +class CCanvas2D; /** * Struct ProfileColumn: Describes one column of an AbstractProfileTable. @@ -140,7 +140,7 @@ * RenderProfile: Render the profile display using OpenGL if the user * has enabled it. */ - void RenderProfile(); + void RenderProfile(CCanvas2D& canvas); /** * Input: Filter and handle any input events that the profile display diff -Nru 0ad-0.0.25b/source/ps/Pyrogenesis.cpp 0ad-0.0.26/source/ps/Pyrogenesis.cpp --- 0ad-0.0.25b/source/ps/Pyrogenesis.cpp 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/Pyrogenesis.cpp 2022-08-21 12:45:08.000000000 +0000 @@ -24,7 +24,7 @@ #include "lib/sysdep/sysdep.h" #include "lib/svn_revision.h" -const char* engine_version = "0.0.25"; +const char* engine_version = "0.0.26"; const char* main_window_name = "0 A.D."; // convert contents of file from char to wchar_t and diff -Nru 0ad-0.0.25b/source/ps/Replay.cpp 0ad-0.0.26/source/ps/Replay.cpp --- 0ad-0.0.25b/source/ps/Replay.cpp 2021-08-22 18:37:29.000000000 +0000 +++ 0ad-0.0.26/source/ps/Replay.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,7 +22,6 @@ #include "graphics/TerrainTextureManager.h" #include "lib/timer.h" #include "lib/file/file_system.h" -#include "lib/res/h_mgr.h" #include "lib/tex/tex.h" #include "ps/CLogger.h" #include "ps/Game.h" @@ -83,7 +82,7 @@ Script::SetProperty(rq, attribs, "mods", mods); m_Directory = createDateIndexSubdirectory(VisualReplay::GetDirectoryPath()); - debug_printf("Writing replay to %s\n", m_Directory.string8().c_str()); + debug_printf("FILES| Replay written to '%s'\n", m_Directory.string8().c_str()); m_Stream = new std::ofstream(OsString(m_Directory / L"commands.txt").c_str(), std::ofstream::out | std::ofstream::trunc); *m_Stream << "start " << Script::StringifyJSON(rq, attribs, false) << "\n"; @@ -130,9 +129,15 @@ CreateDirectories(fileName.Parent(), 0700); std::ofstream stream (OsString(fileName).c_str(), std::ofstream::out | std::ofstream::trunc); - stream << Script::StringifyJSON(rq, &metadata, false); - stream.close(); - debug_printf("Saved replay metadata to %s\n", fileName.string8().c_str()); + if (stream) + { + stream << Script::StringifyJSON(rq, &metadata, false); + stream.close(); + debug_printf("FILES| Replay metadata written to '%s'\n", fileName.string8().c_str()); + } + else + debug_printf("FILES| Failed to write replay metadata to '%s'\n", fileName.string8().c_str()); + } OsPath CReplayLogger::GetDirectory() const @@ -248,14 +253,6 @@ if (ooslog) g_Game->GetSimulation2()->EnableOOSLog(); - // Need some stuff for terrain movement costs: - // (TODO: this ought to be independent of any graphics code) - new CTerrainTextureManager; - g_TexMan.LoadTerrainTextures(); - - // Initialise h_mgr so it doesn't crash when emitting sounds - h_mgr_init(); - ScriptRequest rq(g_Game->GetSimulation2()->GetScriptInterface()); JS::RootedValue attribs(rq.cx); ENSURE(Script::ParseJSON(rq, attribsStr, &attribs)); @@ -329,9 +326,6 @@ // it's already destructed. g_ScriptContext.reset(); - // Clean up - delete &g_TexMan; - delete &g_Profiler; delete &g_ProfileViewer; SAFE_DELETE(g_ScriptStatsTable); diff -Nru 0ad-0.0.25b/source/ps/SavedGame.h 0ad-0.0.26/source/ps/SavedGame.h --- 0ad-0.0.25b/source/ps/SavedGame.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/SavedGame.h 2022-08-21 12:45:05.000000000 +0000 @@ -22,7 +22,6 @@ #include "scriptinterface/StructuredClone.h" class CSimulation2; -class CGUIManager; /** * @file diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_ConfigDB.cpp 0ad-0.0.26/source/ps/scripting/JSInterface_ConfigDB.cpp --- 0ad-0.0.25b/source/ps/scripting/JSInterface_ConfigDB.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_ConfigDB.cpp 2022-08-21 12:45:02.000000000 +0000 @@ -21,6 +21,7 @@ #include "ps/ConfigDB.h" #include "ps/CLogger.h" +#include "ps/VideoMode.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptRequest.h" @@ -188,6 +189,16 @@ return true; } +void PauseOnFocusLoss(bool pause) +{ + g_PauseOnFocusLoss = pause; +} + +void SetGUIScale(float scale) +{ + g_VideoMode.Rescale(scale); +} + void RegisterScriptFunctions(const ScriptRequest& rq) { ScriptFunction::Register<&HasChanges>(rq, "ConfigDB_HasChanges"); @@ -201,5 +212,7 @@ ScriptFunction::Register<&CreateAndWriteValueToFile>(rq, "ConfigDB_CreateAndWriteValueToFile"); ScriptFunction::Register<&SetFile>(rq, "ConfigDB_SetFile"); ScriptFunction::Register<&Reload>(rq, "ConfigDB_Reload"); + ScriptFunction::Register<&PauseOnFocusLoss>(rq, "PauseOnFocusLoss"); + ScriptFunction::Register<&SetGUIScale>(rq, "SetGUIScale"); } } diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_ConfigDB.h 0ad-0.0.26/source/ps/scripting/JSInterface_ConfigDB.h --- 0ad-0.0.25b/source/ps/scripting/JSInterface_ConfigDB.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_ConfigDB.h 2022-08-21 12:45:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ #ifndef INCLUDED_JSI_CONFIGDB #define INCLUDED_JSI_CONFIGDB +extern bool g_PauseOnFocusLoss; class ScriptRequest; namespace JSI_ConfigDB diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_Game.cpp 0ad-0.0.26/source/ps/scripting/JSInterface_Game.cpp --- 0ad-0.0.25b/source/ps/scripting/JSInterface_Game.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_Game.cpp 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -41,13 +41,13 @@ return g_Game; } -void StartGame(const ScriptInterface& guiInterface, JS::HandleValue attribs, int playerID) +void StartGame(const ScriptInterface& guiInterface, JS::HandleValue attribs, int playerID, bool storeReplay) { ENSURE(!g_NetServer); ENSURE(!g_NetClient); ENSURE(!g_Game); - g_Game = new CGame(true); + g_Game = new CGame(storeReplay); // Convert from GUI script context to sim script context/ CSimulation2* sim = g_Game->GetSimulation2(); diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_Hotkey.cpp 0ad-0.0.26/source/ps/scripting/JSInterface_Hotkey.cpp --- 0ad-0.0.25b/source/ps/scripting/JSInterface_Hotkey.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_Hotkey.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -46,7 +46,7 @@ ret.setUndefined(); return; } - for (const std::pair& item : val) + for (const std::pair& item : val) { JS::RootedValue el(rq.cx); Script::ToJSVal(rq, &el, item.second); diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_Main.cpp 0ad-0.0.26/source/ps/scripting/JSInterface_Main.cpp --- 0ad-0.0.25b/source/ps/scripting/JSInterface_Main.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_Main.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include "graphics/MapReader.h" #include "lib/sysdep/sysdep.h" #include "lib/utf8.h" +#include "maths/Size2D.h" #include "maths/MD5.h" #include "ps/CStrIntern.h" #include "ps/GUID.h" @@ -97,14 +98,19 @@ return g_frequencyFilter->StableFrequency(); } -int GetTextWidth(const std::string& fontName, const std::wstring& text) +CSize2D GetTextSize(const std::string& fontName, const std::wstring& text) { int width = 0; int height = 0; CStrIntern _fontName(fontName); CFontMetrics fontMetrics(_fontName); fontMetrics.CalculateStringSize(text.c_str(), width, height); - return width; + return CSize2D(width, height); +} + +int GetTextWidth(const std::string& fontName, const std::wstring& text) +{ + return GetTextSize(fontName, text).Width; } std::string CalculateMD5(const std::string& input) @@ -129,6 +135,7 @@ ScriptFunction::Register<&GetMatchID>(rq, "GetMatchID"); ScriptFunction::Register<&LoadMapSettings>(rq, "LoadMapSettings"); ScriptFunction::Register<&GetFps>(rq, "GetFPS"); + ScriptFunction::Register<&GetTextSize>(rq, "GetTextSize"); ScriptFunction::Register<&GetTextWidth>(rq, "GetTextWidth"); ScriptFunction::Register<&CalculateMD5>(rq, "CalculateMD5"); } diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_VFS.cpp 0ad-0.0.26/source/ps/scripting/JSInterface_VFS.cpp --- 0ad-0.0.25b/source/ps/scripting/JSInterface_VFS.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_VFS.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -224,7 +224,14 @@ VfsPath path(filePath); WriteBuffer buf; buf.Append(str.c_str(), str.length()); - g_VFS->CreateFile(path, buf.Data(), buf.Size()); + if (g_VFS->CreateFile(path, buf.Data(), buf.Size()) == INFO::OK) + { + OsPath realPath; + g_VFS->GetRealPath(path, realPath, false); + debug_printf("FILES| JSON data written to '%s'\n", realPath.string8().c_str()); + } + else + debug_printf("FILES| Failed to write JSON data to '%s'\n", path.string8().c_str()); } bool DeleteCampaignSave(const CStrW& filePath) @@ -258,7 +265,7 @@ VFS_ScriptFunctions(Maps); #undef VFS_ScriptFunctions -void RegisterScriptFunctions_GUI(const ScriptRequest& rq) +void RegisterScriptFunctions_ReadWriteAnywhere(const ScriptRequest& rq) { ScriptFunction::Register<&Script_ListDirectoryFiles_GUI>(rq, "ListDirectoryFiles"); ScriptFunction::Register<&Script_FileExists_GUI>(rq, "FileExists"); @@ -271,14 +278,14 @@ ScriptFunction::Register<&DeleteCampaignSave>(rq, "DeleteCampaignSave"); } -void RegisterScriptFunctions_Simulation(const ScriptRequest& rq) +void RegisterScriptFunctions_ReadOnlySimulation(const ScriptRequest& rq) { ScriptFunction::Register<&Script_ListDirectoryFiles_Simulation>(rq, "ListDirectoryFiles"); ScriptFunction::Register<&Script_FileExists_Simulation>(rq, "FileExists"); ScriptFunction::Register<&Script_ReadJSONFile_Simulation>(rq, "ReadJSONFile"); } -void RegisterScriptFunctions_Maps(const ScriptRequest& rq) +void RegisterScriptFunctions_ReadOnlySimulationMaps(const ScriptRequest& rq) { ScriptFunction::Register<&Script_ListDirectoryFiles_Maps>(rq, "ListDirectoryFiles"); ScriptFunction::Register<&Script_FileExists_Maps>(rq, "FileExists"); diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_VFS.h 0ad-0.0.26/source/ps/scripting/JSInterface_VFS.h --- 0ad-0.0.25b/source/ps/scripting/JSInterface_VFS.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_VFS.h 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,9 +22,9 @@ namespace JSI_VFS { - void RegisterScriptFunctions_GUI(const ScriptRequest& rq); - void RegisterScriptFunctions_Simulation(const ScriptRequest& rq); - void RegisterScriptFunctions_Maps(const ScriptRequest& rq); + void RegisterScriptFunctions_ReadWriteAnywhere(const ScriptRequest& rq); + void RegisterScriptFunctions_ReadOnlySimulation(const ScriptRequest& rq); + void RegisterScriptFunctions_ReadOnlySimulationMaps(const ScriptRequest& rq); } #endif // INCLUDED_JSI_VFS diff -Nru 0ad-0.0.25b/source/ps/scripting/JSInterface_VisualReplay.cpp 0ad-0.0.26/source/ps/scripting/JSInterface_VisualReplay.cpp --- 0ad-0.0.25b/source/ps/scripting/JSInterface_VisualReplay.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/scripting/JSInterface_VisualReplay.cpp 2022-08-21 12:45:03.000000000 +0000 @@ -28,7 +28,8 @@ { CStrW GetReplayDirectoryName(const CStrW& directoryName) { - return OsPath(VisualReplay::GetDirectoryPath() / directoryName).string(); + // The string conversion is added to account for non-latin characters. + return wstring_from_utf8(OsPath(VisualReplay::GetDirectoryPath() / directoryName).string8()); } void RegisterScriptFunctions(const ScriptRequest& rq) diff -Nru 0ad-0.0.25b/source/ps/TaskManager.cpp 0ad-0.0.26/source/ps/TaskManager.cpp --- 0ad-0.0.25b/source/ps/TaskManager.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/TaskManager.cpp 2022-09-23 19:16:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,15 +36,26 @@ namespace Threading { + +namespace +{ /** * Minimum number of TaskManager workers. */ -static constexpr size_t MIN_THREADS = 3; +constexpr size_t MIN_WORKERS = 3; /** * Maximum number of TaskManager workers. */ -static constexpr size_t MAX_THREADS = 32; +constexpr size_t MAX_WORKERS = 32; + +size_t GetDefaultNumberOfWorkers() +{ + const size_t hardware_concurrency = std::thread::hardware_concurrency(); + return hardware_concurrency ? Clamp(hardware_concurrency - 1, MIN_WORKERS, MAX_WORKERS) : MIN_WORKERS; +} + +} // anonymous namespace std::unique_ptr g_TaskManager; @@ -155,18 +166,18 @@ mutable size_t m_RoundRobinIdx = 0; }; -TaskManager::TaskManager() : TaskManager(std::thread::hardware_concurrency() - 1) +TaskManager::TaskManager() : TaskManager(GetDefaultNumberOfWorkers()) { } TaskManager::TaskManager(size_t numberOfWorkers) { m = std::make_unique(*this); - numberOfWorkers = Clamp(numberOfWorkers, MIN_THREADS, MAX_THREADS); + numberOfWorkers = Clamp(numberOfWorkers, MIN_WORKERS, MAX_WORKERS); m->SetupWorkers(numberOfWorkers); } -TaskManager::~TaskManager() {} +TaskManager::~TaskManager() = default; TaskManager::Impl::Impl(TaskManager& backref) : m_TaskManager(backref) diff -Nru 0ad-0.0.25b/source/ps/TaskManager.h 0ad-0.0.26/source/ps/TaskManager.h --- 0ad-0.0.25b/source/ps/TaskManager.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/TaskManager.h 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -67,7 +67,7 @@ Future> PushTask(T&& func, TaskPriority priority = TaskPriority::NORMAL) { Future> ret; - DoPushTask(std::move(ret.Wrap(std::move(func))), priority); + DoPushTask(ret.Wrap(std::move(func)), priority); return ret; } diff -Nru 0ad-0.0.25b/source/ps/TemplateLoader.cpp 0ad-0.0.26/source/ps/TemplateLoader.cpp --- 0ad-0.0.25b/source/ps/TemplateLoader.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/TemplateLoader.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -105,6 +105,21 @@ return INFO::OK; } +static Status AddToTemplatesUnrestricted(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData) +{ + std::vector& templates = *(std::vector*)cbData; + + VfsPath pathstem = pathname.ChangeExtension(L""); + std::string name = pathstem.string8().substr(ARRAY_SIZE(TEMPLATE_ROOT)-1); + + // We want to ignore template_*.xml templates, since they may be incomplete. + if (name.substr(0, 9) == "template_") + return INFO::OK; + + templates.push_back(name); + return INFO::OK; +} + static Status AddActorToTemplates(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData) { std::vector& templates = *(std::vector*)cbData; @@ -143,6 +158,17 @@ return templates; } + +std::vector CTemplateLoader::FindTemplatesUnrestricted(const std::string& path, bool includeSubdirectories) const +{ + std::vector templates; + + size_t flags = includeSubdirectories ? vfs::DIR_RECURSIVE : 0; + + WARN_IF_ERR(vfs::ForEachFile(g_VFS, VfsPath(TEMPLATE_ROOT) / path, AddToTemplatesUnrestricted, (uintptr_t)&templates, L"*.xml", flags)); + + return templates; +} const CParamNode& CTemplateLoader::GetTemplateFileData(const std::string& templateName) { diff -Nru 0ad-0.0.25b/source/ps/TemplateLoader.h 0ad-0.0.26/source/ps/TemplateLoader.h --- 0ad-0.0.25b/source/ps/TemplateLoader.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/TemplateLoader.h 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -67,6 +67,12 @@ */ std::vector FindTemplates(const std::string& path, bool includeSubdirectories, ETemplatesType templatesType) const; + /** + * Returns a list of strings that could validly be passed as @c templateName to LoadTemplateFile. + * Not ignoring any special directories. + */ + std::vector FindTemplatesUnrestricted(const std::string& path, bool includeSubdirectories) const; + private: /** * (Re)loads the given template, regardless of whether it exists already, diff -Nru 0ad-0.0.25b/source/ps/tests/stub_impl_hack.h 0ad-0.0.26/source/ps/tests/stub_impl_hack.h --- 0ad-0.0.25b/source/ps/tests/stub_impl_hack.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/tests/stub_impl_hack.h 2022-08-21 12:45:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,8 +20,6 @@ // usually defined by main.cpp, used by engine's scripting/ScriptFunctions.cpp, // must be included here to placate linker. -bool g_GameRestarted; - bool IsQuitRequested() { return false; diff -Nru 0ad-0.0.25b/source/ps/tests/test_Mod.h 0ad-0.0.26/source/ps/tests/test_Mod.h --- 0ad-0.0.25b/source/ps/tests/test_Mod.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/tests/test_Mod.h 2022-08-21 12:45:04.000000000 +0000 @@ -128,6 +128,30 @@ mods.push_back("public"); mods.push_back("does_not_exist"); TS_ASSERT(!m_Mods.CheckForIncompatibleMods(mods).empty()); + + mods.clear(); + mods.push_back("good2"); + TS_ASSERT(m_Mods.CheckForIncompatibleMods(mods).size() == 1); + } + + void test_different_name_and_path() + { + ScriptInterface script("Test", "Test", g_ScriptContext); + + ScriptRequest rq(script); + JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx)); + + m_Mods.m_AvailableMods = { + Mod::ModData{ "public", "0ad", "0.0.25", {}, false, "" }, + Mod::ModData{ "wrong", "wrong_name", "0.10.0", { "0ad=0.0.24" }, false, ""} + }; + + std::vector mods; + + mods.clear(); + mods.push_back("public"); + mods.push_back("wrong"); + TS_ASSERT(!m_Mods.CheckForIncompatibleMods(mods).empty()); } void test_play_compatible() diff -Nru 0ad-0.0.25b/source/ps/tests/test_ModIo.h 0ad-0.0.26/source/ps/tests/test_ModIo.h --- 0ad-0.0.25b/source/ps/tests/test_ModIo.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/tests/test_ModIo.h 2022-08-21 12:45:04.000000000 +0000 @@ -209,17 +209,6 @@ if (sodium_base642bin((unsigned char*)&pk, sizeof pk, pk_str.c_str(), pk_str.size(), NULL, &bin_len, NULL, sodium_base64_VARIANT_ORIGINAL) != 0 || bin_len != sizeof pk) LOGERROR("failed to decode base64 public key"); - - // No invalid signature at all (silent failure) -#define TS_ASSERT_PARSE_SILENT_FAILURE(input) \ - { \ - TestLogger logger; \ - SigStruct sig; \ - std::string err; \ - TS_ASSERT(!ModIo::ParseSignature(input, sig, pk, err)); \ - TS_ASSERT(err.empty()); \ - } - #define TS_ASSERT_PARSE(input, expected_error) \ { \ TestLogger logger; \ @@ -229,7 +218,7 @@ TS_ASSERT_STR_EQUALS(err, expected_error); \ } - TS_ASSERT_PARSE_SILENT_FAILURE({}); + TS_ASSERT_PARSE({}, "Invalid (too short) sig."); TS_ASSERT_PARSE("", "Invalid (too short) sig."); @@ -242,8 +231,7 @@ TS_ASSERT_PARSE("untrusted comment: \nZm9vYmFyCg==\ntrusted comment: \n", "Failed to decode base64 sig."); TS_ASSERT_PARSE("untrusted comment: \nRWTA6VIoth2Q1HUg5bwwbCUZPcqbQ/reLXqxiaWARH5PNcwxX5vBv/mLPLgdxGsIrOyK90763+rCVTmjeYx5BDz8C0CIbGZTNQs=\ntrusted comment: \n", "Only hashed minisign signatures are supported."); - // Silent failure again this one has the wrong keynum - TS_ASSERT_PARSE_SILENT_FAILURE({"untrusted comment: \nRUTA5VIoth2Q1HUg5bwwbCUZPcqbQ/reLXqxiaWARH5PNcwxX5vBv/mLPLgdxGsIrOyK90763+rCVTmjeYx5BDz8C0CIbGZTNQs=\ntrusted comment: \n"}); + TS_ASSERT_PARSE({"untrusted comment: \nRUTA5VIoth2Q1HUg5bwwbCUZPcqbQ/reLXqxiaWARH5PNcwxX5vBv/mLPLgdxGsIrOyK90763+rCVTmjeYx5BDz8C0CIbGZTNQs=\ntrusted comment: \n"}, "Invalid signature."); TS_ASSERT_PARSE("untrusted comment: \nRUTA6VIoth2Q1HUg5bwwbCUZPcqbQ/reLXqxiaWARH5PNcwxX5vBv/mLPLgdxGsIrOyK90763+rCVTmjeYx5BDz8C0CIbGZTNQs=\ntrusted comment: \n", "Failed to decode base64 global_sig."); @@ -258,7 +246,6 @@ TS_ASSERT(err.empty()); } -#undef TS_ASSERT_PARSE_SILENT_FAILURE #undef TS_ASSERT_PARSE } }; diff -Nru 0ad-0.0.25b/source/ps/UniDoubler.h 0ad-0.0.26/source/ps/UniDoubler.h --- 0ad-0.0.25b/source/ps/UniDoubler.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/UniDoubler.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,8 +32,6 @@ #endif #define CStr CStrW #define tstring wstring -#define tchar wchar_t -#define _T(t) L ## t // Include the unidoubled file #include UNIDOUBLER_HEADER @@ -42,24 +40,16 @@ #undef _UNICODE #undef CStr #undef tstring -#undef tchar -#undef _T - // Now include the 8-bit version under the name CStr8 #define CStr CStr8 #define tstring string -#define tchar char -#define _T(t) t #include UNIDOUBLER_HEADER // Clean up the macros again, to minimise namespace pollution #undef CStr #undef tstring -#undef tchar -#undef _T - // To please the file that originally include CStr.h, make CStr an alias for CStr8: #define CStr CStr8 diff -Nru 0ad-0.0.25b/source/ps/UserReport.cpp 0ad-0.0.26/source/ps/UserReport.cpp --- 0ad-0.0.25b/source/ps/UserReport.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/UserReport.cpp 2022-09-23 19:16:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -616,12 +616,12 @@ std::ofstream stream(OsString(path), std::ofstream::trunc); if (stream) { - debug_printf("UserReport written to %s\n", path.string8().c_str()); + debug_printf("FILES| UserReport written to '%s'\n", path.string8().c_str()); stream << dataHumanReadable << std::endl; stream.close(); } else - debug_printf("Failed to write UserReport to %s\n", path.string8().c_str()); + debug_printf("FILES| Failed to write UserReport to '%s'\n", path.string8().c_str()); } // If not initialised, discard the report diff -Nru 0ad-0.0.25b/source/ps/utf16string.h 0ad-0.0.26/source/ps/utf16string.h --- 0ad-0.0.25b/source/ps/utf16string.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/utf16string.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* 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 - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* - A basic_string derivative that works with uint16_t as its underlying char - type. -*/ -#ifndef INCLUDED_UTF16STRING -#define INCLUDED_UTF16STRING - -// On Linux, wchar_t is 32-bit, so define a new version of it. -// We now use this code on Windows as well, because wchar_t is a -// native type and distinct from utf16_t. -#include -#include -#include -#include - - -typedef uint16_t utf16_t; - -// jw: this was originally defined in the std namespace, which is at -// least frowned upon if not illegal. giving it a new name and passing it -// as a template parameter is the "correct" and safe way. - -struct utf16_traits -{ - typedef utf16_t char_type; - typedef int int_type; - typedef std::streampos pos_type; - typedef std::streamoff off_type; - typedef std::mbstate_t state_type; - - static void assign(char_type& c1, const char_type& c2) - { c1 = c2; } - - static bool eq(const char_type& c1, const char_type& c2) - { return c1 == c2; } - - static bool lt(const char_type& c1, const char_type& c2) - { return c1 < c2; } - - static int compare(const char_type* s1, const char_type* s2, size_t n) - { - return memcmp(s1, s2, n*sizeof(char_type)); - } - - static size_t length(const char_type* s) - { - const char_type* end=s; - while (*end) end++; - return (size_t)(end-s); - } - - static const char_type* find(const char_type* s, size_t n, const char_type& a) - { - const char_type *end = s+n; - const char_type *res = std::find(s, end, a); - return (res != end)?res:NULL; - } - - static char_type* move(char_type* s1, const char_type* s2, size_t n) - { - return (char_type *)memmove(s1, s2, n*sizeof(char_type)); - } - - static char_type* copy(char_type* s1, const char_type* s2, size_t n) - { - return (char_type *)memcpy(s1, s2, n*sizeof(char_type)); - } - - static char_type* assign(char_type* s, size_t n, char_type a) - { - while (n--) - { - s[n]=a; - } - return s; - } - - static char_type to_char_type(const int_type& c) - { return (char_type)c; } - - static int_type to_int_type(const char_type& c) - { return (int_type)c; } - - static bool eq_int_type(const int_type& c1, const int_type& c2) - { return c1 == c2; } - - static int_type eof() - { return -1; } - - static int_type not_eof(const int_type& c) - { return (c == -1) ? 0 : c; } -}; - -typedef std::basic_string utf16string; -typedef std::basic_stringstream utf16stringstream; - -#endif diff -Nru 0ad-0.0.25b/source/ps/Util.cpp 0ad-0.0.26/source/ps/Util.cpp --- 0ad-0.0.25b/source/ps/Util.cpp 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/Util.cpp 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,34 +19,22 @@ #include "ps/Util.h" -#include "lib/posix/posix_utsname.h" -#include "lib/ogl.h" -#include "lib/timer.h" -#include "lib/bits.h" // round_up +#include "graphics/GameView.h" #include "lib/allocators/shared_ptr.h" -#include "lib/sysdep/sysdep.h" // sys_OpenFile -#include "lib/sysdep/gfx.h" +#include "lib/posix/posix_utsname.h" #include "lib/sysdep/cpu.h" #include "lib/sysdep/os_cpu.h" -#if ARCH_X86_X64 -#include "lib/sysdep/arch/x86_x64/topology.h" -#endif #include "lib/sysdep/smbios.h" +#include "lib/sysdep/sysdep.h" // sys_OpenFile #include "lib/tex/tex.h" - -#include "i18n/L10n.h" -#include "lib/utf8.h" - -#include "ps/GameSetup/Config.h" -#include "ps/GameSetup/GameSetup.h" -#include "ps/Game.h" +#include "lib/timer.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" +#include "ps/GameSetup/Config.h" +#include "ps/GameSetup/GameSetup.h" #include "ps/Pyrogenesis.h" #include "ps/VideoMode.h" -#include "renderer/Renderer.h" -#include "maths/MathUtil.h" -#include "graphics/GameView.h" +#include "renderer/backend/IDevice.h" #if CONFIG2_AUDIO #include "soundmanager/SoundManager.h" @@ -55,31 +43,6 @@ #include #include -extern CStrW g_CursorName; - -static std::string SplitExts(const char *exts) -{ - std::string str = exts; - std::string ret = ""; - size_t idx = str.find_first_of(" "); - while(idx != std::string::npos) - { - if(idx >= str.length() - 1) - { - ret += str; - break; - } - - ret += str.substr(0, idx); - ret += "\n"; - str = str.substr(idx + 1); - idx = str.find_first_of(" "); - } - - return ret; -} - - void WriteSystemInfo() { TIMER(L"write_sys_info"); @@ -108,9 +71,6 @@ // CPU fprintf(f, "CPU : %s, %s", un.machine, cpu_IdentifierString()); -#if ARCH_X86_X64 - fprintf(f, " (%dx%dx%d)", (int)topology::NumPackages(), (int)topology::CoresPerPackage(), (int)topology::LogicalPerCore()); -#endif double cpuClock = os_cpu_ClockFrequency(); // query OS (may fail) #if ARCH_X86_X64 if(cpuClock <= 0.0) @@ -130,10 +90,8 @@ fprintf(f, "Memory : %u MiB; %u MiB free\n", (unsigned)os_cpu_MemorySize(), (unsigned)os_cpu_MemoryAvailable()); // graphics - const std::wstring cardName = gfx::CardName(); - const std::wstring driverInfo = gfx::DriverInfo(); - fprintf(f, "Graphics Card : %ls\n", cardName.c_str()); - fprintf(f, "OpenGL Drivers : %s; %ls\n", glGetString(GL_VERSION), driverInfo.c_str()); + fprintf(f, "Video Card : %s\n", g_VideoMode.GetBackendDevice()->GetName().c_str()); + fprintf(f, "Video Driver : %s\n", g_VideoMode.GetBackendDevice()->GetDriverInformation().c_str()); fprintf(f, "Video Mode : %dx%d:%d\n", g_VideoMode.GetXRes(), g_VideoMode.GetYRes(), g_VideoMode.GetBPP()); #if CONFIG2_AUDIO @@ -151,9 +109,12 @@ #endif // OpenGL extensions (write them last, since it's a lot of text) - const char* exts = ogl_ExtensionString(); - if (!exts) exts = "{unknown}"; - fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str()); + fprintf(f, "\nBackend Extensions:\n"); + if (g_VideoMode.GetBackendDevice()->GetExtensions().empty()) + fprintf(f, "{unknown}\n"); + else + for (const std::string& extension : g_VideoMode.GetBackendDevice()->GetExtensions()) + fprintf(f, "%s\n", extension.c_str()); // System Management BIOS (even more text than OpenGL extensions) std::string smbios = SMBIOS::StringizeStructures(SMBIOS::GetStructures()); @@ -161,6 +122,8 @@ fclose(f); f = 0; + + debug_printf("FILES| Hardware details written to '%s'\n", pathname.string8().c_str()); } @@ -181,7 +144,10 @@ // TODO: load from language file } - +CStr GetStatusAsString(Status status) +{ + return utf8_from_wstring(ErrorString(status)); +} // write the specified texture to disk. // note: cannot be made const because the image may have to be @@ -238,214 +204,6 @@ return path; } -static size_t s_nextScreenshotNumber; - -// identifies the file format that is to be written -// (case-insensitive). examples: "bmp", "png", "jpg". -// BMP is good for quick output at the expense of large files. -void WriteScreenshot(const VfsPath& extension) -{ - // get next available numbered filename - // note: %04d -> always 4 digits, so sorting by filename works correctly. - const VfsPath basenameFormat(L"screenshots/screenshot%04d"); - const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension); - VfsPath filename; - vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename); - - const size_t w = (size_t)g_xres, h = (size_t)g_yres; - const size_t bpp = 24; - GLenum fmt = GL_RGB; - int flags = TEX_BOTTOM_UP; - // we want writing BMP to be as fast as possible, - // so read data from OpenGL in BMP format to obviate conversion. - if(extension == L".bmp") - { -#if !CONFIG2_GLES // GLES doesn't support BGR - fmt = GL_BGR; - flags |= TEX_BGR; -#endif - } - - // Hide log messages and re-render - RenderLogger(false); - Render(); - RenderLogger(true); - - const size_t img_size = w * h * bpp/8; - const size_t hdr_size = tex_hdr_size(filename); - std::shared_ptr buf; - AllocateAligned(buf, hdr_size+img_size, maxSectorSize); - GLvoid* img = buf.get() + hdr_size; - Tex t; - if(t.wrap(w, h, bpp, flags, buf, hdr_size) < 0) - return; - glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img); - - if (tex_write(&t, filename) == INFO::OK) - { - OsPath realPath; - g_VFS->GetRealPath(filename, realPath); - - LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8()); - - debug_printf( - CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(), - realPath.string8().c_str()); - } - else - LOGERROR("Error writing screenshot to '%s'", filename.string8()); -} - - - -// Similar to WriteScreenshot, but generates an image of size tileWidth*tiles x tileHeight*tiles. -void WriteBigScreenshot(const VfsPath& extension, int tiles, int tileWidth, int tileHeight) -{ - // If the game hasn't started yet then use WriteScreenshot to generate the image. - if (g_Game == nullptr) - { - WriteScreenshot(L".bmp"); - return; - } - - // get next available numbered filename - // note: %04d -> always 4 digits, so sorting by filename works correctly. - const VfsPath basenameFormat(L"screenshots/screenshot%04d"); - const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension); - VfsPath filename; - vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename); - - // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and - // hope the screen is actually large enough for that. - ENSURE(g_xres >= tileWidth && g_yres >= tileHeight); - - const int img_w = tileWidth * tiles, img_h = tileHeight * tiles; - const int bpp = 24; - GLenum fmt = GL_RGB; - int flags = TEX_BOTTOM_UP; - // we want writing BMP to be as fast as possible, - // so read data from OpenGL in BMP format to obviate conversion. - if(extension == L".bmp") - { -#if !CONFIG2_GLES // GLES doesn't support BGR - fmt = GL_BGR; - flags |= TEX_BGR; -#endif - } - - const size_t img_size = img_w * img_h * bpp/8; - const size_t tile_size = tileWidth * tileHeight * bpp/8; - const size_t hdr_size = tex_hdr_size(filename); - void* tile_data = malloc(tile_size); - if(!tile_data) - { - WARN_IF_ERR(ERR::NO_MEM); - return; - } - std::shared_ptr img_buf; - AllocateAligned(img_buf, hdr_size + img_size, maxSectorSize); - - Tex t; - GLvoid* img = img_buf.get() + hdr_size; - if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0) - { - free(tile_data); - return; - } - - ogl_WarnIfError(); - - CCamera oldCamera = *g_Game->GetView()->GetCamera(); - - // Resize various things so that the sizes and aspect ratios are correct - { - g_Renderer.Resize(tileWidth, tileHeight); - SViewPort vp = { 0, 0, tileWidth, tileHeight }; - g_Game->GetView()->SetViewport(vp); - } - -#if !CONFIG2_GLES - // Temporarily move everything onto the front buffer, so the user can - // see the exciting progress as it renders (and can tell when it's finished). - // (It doesn't just use SwapBuffers, because it doesn't know whether to - // call the SDL version or the Atlas version.) - GLint oldReadBuffer, oldDrawBuffer; - glGetIntegerv(GL_READ_BUFFER, &oldReadBuffer); - glGetIntegerv(GL_DRAW_BUFFER, &oldDrawBuffer); - glDrawBuffer(GL_FRONT); - glReadBuffer(GL_FRONT); -#endif - - // Hide the cursor - CStrW oldCursor = g_CursorName; - g_CursorName = L""; - - // Render each tile - CMatrix3D projection; - projection.SetIdentity(); - const float aspectRatio = 1.0f * tileWidth / tileHeight; - for (int tile_y = 0; tile_y < tiles; ++tile_y) - { - for (int tile_x = 0; tile_x < tiles; ++tile_x) - { - // Adjust the camera to render the appropriate region - if (oldCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) - { - projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tile_x, tile_y); - } - g_Game->GetView()->GetCamera()->SetProjection(projection); - - RenderLogger(false); - RenderGui(false); - Render(); - RenderGui(true); - RenderLogger(true); - - // Copy the tile pixels into the main image - glReadPixels(0, 0, tileWidth, tileHeight, fmt, GL_UNSIGNED_BYTE, tile_data); - for (int y = 0; y < tileHeight; ++y) - { - void* dest = static_cast(img) + ((tile_y * tileHeight + y) * img_w + (tile_x * tileWidth)) * bpp / 8; - void* src = static_cast(tile_data) + y * tileWidth * bpp / 8; - memcpy(dest, src, tileWidth * bpp / 8); - } - } - } - - // Restore the old cursor - g_CursorName = oldCursor; - -#if !CONFIG2_GLES - // Restore the buffer settings - glDrawBuffer(oldDrawBuffer); - glReadBuffer(oldReadBuffer); -#endif - - // Restore the viewport settings - { - g_Renderer.Resize(g_xres, g_yres); - SViewPort vp = { 0, 0, g_xres, g_yres }; - g_Game->GetView()->SetViewport(vp); - g_Game->GetView()->GetCamera()->SetProjectionFromCamera(oldCamera); - } - - if (tex_write(&t, filename) == INFO::OK) - { - OsPath realPath; - g_VFS->GetRealPath(filename, realPath); - - LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8()); - - debug_printf( - CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(), - realPath.string8().c_str()); - } - else - LOGERROR("Error writing screenshot to '%s'", filename.string8()); - - free(tile_data); -} - std::string Hexify(const std::string& s) { std::stringstream str; diff -Nru 0ad-0.0.25b/source/ps/Util.h 0ad-0.0.26/source/ps/Util.h --- 0ad-0.0.25b/source/ps/Util.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/Util.h 2022-09-23 19:16:57.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,19 +18,20 @@ #ifndef PS_UTIL_H #define PS_UTIL_H -#include "lib/os_path.h" #include "lib/file/vfs/vfs_path.h" +#include "lib/os_path.h" +#include "lib/status.h" +#include "ps/CStr.h" -struct Tex; +class Tex; void WriteSystemInfo(); const wchar_t* ErrorString(int err); -OsPath createDateIndexSubdirectory(const OsPath& parentDir); +CStr GetStatusAsString(Status status); -void WriteScreenshot(const VfsPath& extension); -void WriteBigScreenshot(const VfsPath& extension, int tiles = 4, int tileWidth = 640, int tileHeight = 480); +OsPath createDateIndexSubdirectory(const OsPath& parentDir); Status tex_write(Tex* t, const VfsPath& filename); diff -Nru 0ad-0.0.25b/source/ps/VideoMode.cpp 0ad-0.0.26/source/ps/VideoMode.cpp --- 0ad-0.0.25b/source/ps/VideoMode.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/VideoMode.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,8 +23,6 @@ #include "gui/GUIManager.h" #include "lib/config2.h" #include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" -#include "lib/sysdep/gfx.h" #include "lib/tex/tex.h" #include "ps/CConsole.h" #include "ps/CLogger.h" @@ -34,6 +32,8 @@ #include "ps/Game.h" #include "ps/GameSetup/Config.h" #include "ps/Pyrogenesis.h" +#include "renderer/backend/dummy/Device.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" namespace @@ -45,6 +45,8 @@ int DEFAULT_FULLSCREEN_W = 1024; int DEFAULT_FULLSCREEN_H = 768; +const wchar_t DEFAULT_CURSOR_NAME[] = L"default-arrow"; + } // anonymous namespace #if OS_WIN @@ -59,30 +61,203 @@ CVideoMode g_VideoMode; +class CVideoMode::CCursor +{ +public: + enum class CursorBackend + { + SDL, + SYSTEM + }; + + CCursor(); + ~CCursor(); + + void SetCursor(const CStrW& name); + void ResetCursor(); + +private: + CursorBackend m_CursorBackend = CursorBackend::SYSTEM; + SDL_Surface* m_CursorSurface = nullptr; + SDL_Cursor* m_Cursor = nullptr; + CStrW m_CursorName; +}; + +CVideoMode::CCursor::CCursor() +{ + std::string cursorBackend; + CFG_GET_VAL("cursorbackend", cursorBackend); + if (cursorBackend == "sdl") + m_CursorBackend = CursorBackend::SDL; + else + m_CursorBackend = CursorBackend::SYSTEM; + + ResetCursor(); +} + +CVideoMode::CCursor::~CCursor() +{ + if (m_Cursor) + SDL_FreeCursor(m_Cursor); + if (m_CursorSurface) + SDL_FreeSurface(m_CursorSurface); +} + +void CVideoMode::CCursor::SetCursor(const CStrW& name) +{ + if (m_CursorBackend == CursorBackend::SYSTEM || m_CursorName == name) + return; + m_CursorName = name; + + if (m_Cursor) + SDL_FreeCursor(m_Cursor); + if (m_CursorSurface) + SDL_FreeSurface(m_CursorSurface); + + if (name.empty()) + { + SDL_ShowCursor(SDL_DISABLE); + return; + } + + const VfsPath pathBaseName(VfsPath(L"art/textures/cursors") / name); + + // Read pixel offset of the cursor's hotspot [the bit of it that's + // drawn at (g_mouse_x,g_mouse_y)] from file. + int hotspotX = 0, hotspotY = 0; + { + const VfsPath pathHotspotName = pathBaseName.ChangeExtension(L".txt"); + std::shared_ptr buffer; + size_t size; + if (g_VFS->LoadFile(pathHotspotName, buffer, size) != INFO::OK) + { + LOGERROR("Can't load hotspot for cursor: %s", pathHotspotName.string8().c_str()); + return; + } + std::wstringstream s(std::wstring(reinterpret_cast(buffer.get()), size)); + s >> hotspotX >> hotspotY; + } + + const VfsPath pathImageName = pathBaseName.ChangeExtension(L".png"); + + std::shared_ptr file; + size_t fileSize; + if (g_VFS->LoadFile(pathImageName, file, fileSize) != INFO::OK) + { + LOGERROR("Can't load image for cursor: %s", pathImageName.string8().c_str()); + return; + } + + Tex t; + if (t.decode(file, fileSize) != INFO::OK) + { + LOGERROR("Can't decode image for cursor"); + return; + } + + // Convert to required BGRA format. + const size_t flags = (t.m_Flags | TEX_BGR) & ~TEX_DXT; + if (t.transform_to(flags) != INFO::OK) + { + LOGERROR("Can't transform image for cursor"); + return; + } + void* imageBGRA = t.get_data(); + if (!imageBGRA) + { + LOGERROR("Transformed image is empty for cursor"); + return; + } + + m_CursorSurface = SDL_CreateRGBSurfaceFrom(imageBGRA, + static_cast(t.m_Width), static_cast(t.m_Height), 32, + static_cast(t.m_Width * 4), + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + if (!m_CursorSurface) + { + LOGERROR("Can't create surface for cursor: %s", SDL_GetError()); + return; + } + const float scale = g_VideoMode.GetScale(); + if (scale != 1.0) + { + SDL_Surface* scaledSurface = SDL_CreateRGBSurface(0, + m_CursorSurface->w * scale, + m_CursorSurface->h * scale, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + if (!scaledSurface) + { + LOGERROR("Can't create scaled surface forcursor: %s", SDL_GetError()); + return; + } + if (SDL_BlitScaled(m_CursorSurface, nullptr, scaledSurface, nullptr)) + return; + SDL_FreeSurface(m_CursorSurface); + m_CursorSurface = scaledSurface; + } + m_Cursor = SDL_CreateColorCursor(m_CursorSurface, hotspotX, hotspotY); + if (!m_Cursor) + { + LOGERROR("Can't create cursor: %s", SDL_GetError()); + return; + } + + SDL_SetCursor(m_Cursor); +} + +void CVideoMode::CCursor::ResetCursor() +{ + SetCursor(DEFAULT_CURSOR_NAME); +} + CVideoMode::CVideoMode() : m_WindowedW(DEFAULT_WINDOW_W), m_WindowedH(DEFAULT_WINDOW_H), m_WindowedX(0), m_WindowedY(0) { } +CVideoMode::~CVideoMode() = default; + void CVideoMode::ReadConfig() { bool windowed = !m_ConfigFullscreen; CFG_GET_VAL("windowed", windowed); m_ConfigFullscreen = !windowed; + CFG_GET_VAL("gui.scale", m_Scale); + CFG_GET_VAL("xres", m_ConfigW); CFG_GET_VAL("yres", m_ConfigH); CFG_GET_VAL("bpp", m_ConfigBPP); CFG_GET_VAL("display", m_ConfigDisplay); CFG_GET_VAL("hidpi", m_ConfigEnableHiDPI); CFG_GET_VAL("vsync", m_ConfigVSync); + + CStr rendererBackend; + CFG_GET_VAL("rendererbackend", rendererBackend); + if (rendererBackend == "glarb") + m_Backend = Backend::GL_ARB; + else if (rendererBackend == "dummy") + m_Backend = Backend::DUMMY; + else + m_Backend = Backend::GL; } bool CVideoMode::SetVideoMode(int w, int h, int bpp, bool fullscreen) { Uint32 flags = 0; if (fullscreen) - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + { + bool borderlessFullscreen = true; + CFG_GET_VAL("borderless.fullscreen", borderlessFullscreen); + flags |= borderlessFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; + } + else + { + bool borderlessWindow = false; + CFG_GET_VAL("borderless.window", borderlessWindow); + if (borderlessWindow) + flags |= SDL_WINDOW_BORDERLESS; + } if (!m_Window) { @@ -124,11 +299,15 @@ return false; } - SDL_GLContext context = SDL_GL_CreateContext(m_Window); - if (!context) +#if OS_WIN + // We need to set the window for an error dialog. + wutil_SetAppWindow(m_Window); +#endif + + if (!CreateBackendDevice(true)) { - LOGERROR("SetVideoMode failed in SDL_GL_CreateContext: %dx%d:%d %d (\"%s\")", - w, h, bpp, fullscreen ? 1 : 0, SDL_GetError()); + LOGERROR("SetVideoMode failed in backend device creation: %dx%d:%d %d", + w, h, bpp, fullscreen ? 1 : 0); return false; } } @@ -168,11 +347,6 @@ else SDL_SetWindowGrab(m_Window, SDL_FALSE); -#if OS_WIN - // We need to set the window for an error dialog. - wutil_SetAppWindow(m_Window); -#endif - m_IsFullscreen = fullscreen; g_xres = m_CurrentW; @@ -230,16 +404,15 @@ int bpp = GetBestBPP(); + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); -#if CONFIG2_GLES - // Require GLES 2.0 - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); -#endif + bool debugContext = false; + CFG_GET_VAL("renderer.backend.debugcontext", debugContext); + if (debugContext) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); bool forceGLVersion = false; CFG_GET_VAL("forceglversion", forceGLVersion); @@ -271,6 +444,24 @@ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, forceGLMinorVersion); } } + else + { +#if CONFIG2_GLES + // Require GLES 2.0 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#else + // Some macOS and MESA drivers might not create a context even if they can + // with the core profile. So disable it for a while until we can guarantee + // its creation. +#if OS_WIN + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); +#endif + } if (!SetVideoMode(w, h, bpp, m_ConfigFullscreen)) { @@ -294,9 +485,6 @@ atexit(SDL_Quit); // End work around. - ogl_Init(); // required after each mode change - // (TODO: does that mean we need to call this when toggling fullscreen later?) - m_IsInitialised = true; if (!m_ConfigFullscreen) @@ -307,6 +495,8 @@ SetWindowIcon(); + m_Cursor = std::make_unique(); + return true; } @@ -325,13 +515,33 @@ { ENSURE(m_IsInitialised); + m_Cursor.reset(); + m_IsFullscreen = false; m_IsInitialised = false; + m_BackendDevice.reset(); if (m_Window) { SDL_DestroyWindow(m_Window); - m_Window = NULL; + m_Window = nullptr; + } +} + +bool CVideoMode::CreateBackendDevice(const bool createSDLContext) +{ + if (m_Backend == Backend::DUMMY) + { + m_BackendDevice = std::make_unique(); + return true; + } + m_BackendDevice = Renderer::Backend::GL::CDevice::Create(createSDLContext ? m_Window : nullptr, m_Backend == Backend::GL_ARB); + if (!m_BackendDevice && m_Backend == Backend::GL) + { + LOGERROR("Unable to create device for GL backend, switching to ARB.", static_cast(m_Backend)); + m_Backend = Backend::GL_ARB; + return CreateBackendDevice(createSDLContext); } + return !!m_BackendDevice; } bool CVideoMode::ResizeWindow(int w, int h) @@ -359,6 +569,18 @@ return true; } +void CVideoMode::Rescale(float scale) +{ + ENSURE(m_IsInitialised); + m_Scale = scale; + UpdateRenderer(m_CurrentW, m_CurrentH); +} + +float CVideoMode::GetScale() const +{ + return m_Scale; +} + bool CVideoMode::SetFullscreen(bool fullscreen) { // This might get called before initialisation by psDisplayError; @@ -563,3 +785,15 @@ SDL_SetWindowIcon(m_Window, iconSurface); SDL_FreeSurface(iconSurface); } + +void CVideoMode::SetCursor(const CStrW& name) +{ + if (m_Cursor) + m_Cursor->SetCursor(name); +} + +void CVideoMode::ResetCursor() +{ + if (m_Cursor) + m_Cursor->ResetCursor(); +} diff -Nru 0ad-0.0.25b/source/ps/VideoMode.h 0ad-0.0.26/source/ps/VideoMode.h --- 0ad-0.0.25b/source/ps/VideoMode.h 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/VideoMode.h 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,12 +18,32 @@ #ifndef INCLUDED_VIDEOMODE #define INCLUDED_VIDEOMODE +#include "ps/CStrForward.h" + +#include + typedef struct SDL_Window SDL_Window; +namespace Renderer +{ +namespace Backend +{ +class IDevice; +} +} + class CVideoMode { public: + enum class Backend + { + GL, + GL_ARB, + DUMMY + }; + CVideoMode(); + ~CVideoMode(); /** * Initialise the video mode, for use in an SDL-using application. @@ -42,11 +62,22 @@ void Shutdown(); /** + * Creates a backend device. Also we use wxWidgets in Atlas so we don't need + * to create one for that case. + */ + bool CreateBackendDevice(const bool createSDLContext); + + /** * Resize the SDL window and associated graphics stuff to the new size. */ bool ResizeWindow(int w, int h); /** + * Set scale and tell dependent compoenent to recompute sizes. + */ + void Rescale(float scale); + + /** * Switch to fullscreen or windowed mode. */ bool SetFullscreen(bool fullscreen); @@ -84,10 +115,19 @@ int GetDesktopBPP() const; int GetDesktopFreq() const; + float GetScale() const; + SDL_Window* GetWindow(); void SetWindowIcon(); + void SetCursor(const CStrW& name); + void ResetCursor(); + + Backend GetBackend() const { return m_Backend; } + + Renderer::Backend::IDevice* GetBackendDevice() { return m_BackendDevice.get(); } + private: void ReadConfig(); int GetBestBPP(); @@ -109,6 +149,8 @@ int m_PreferredBPP = 0; int m_PreferredFreq = 0; + float m_Scale = 1.0f; + // Config file settings (0 if unspecified) int m_ConfigW = 0; int m_ConfigH = 0; @@ -135,6 +177,12 @@ int m_CurrentW; int m_CurrentH; int m_CurrentBPP; + + class CCursor; + std::unique_ptr m_Cursor; + + Backend m_Backend = Backend::GL; + std::unique_ptr m_BackendDevice; }; extern CVideoMode g_VideoMode; diff -Nru 0ad-0.0.25b/source/ps/VisualReplay.cpp 0ad-0.0.26/source/ps/VisualReplay.cpp --- 0ad-0.0.25b/source/ps/VisualReplay.cpp 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/VisualReplay.cpp 2022-08-21 12:45:05.000000000 +0000 @@ -22,6 +22,7 @@ #include "lib/timer.h" #include "lib/utf8.h" #include "lib/allocators/shared_ptr.h" +#include "lib/file/file_system.h" #include "lib/external_libraries/libsdl.h" #include "network/NetClient.h" #include "network/NetServer.h" @@ -108,7 +109,7 @@ cacheStream.close(); wunlink(GetCacheFilePath()); - if (wrename(GetTempCacheFilePath(), GetCacheFilePath())) + if (RenameFile(GetTempCacheFilePath(), GetCacheFilePath())) LOGERROR("Could not store the replay cache"); } diff -Nru 0ad-0.0.25b/source/ps/VisualReplay.h 0ad-0.0.26/source/ps/VisualReplay.h --- 0ad-0.0.25b/source/ps/VisualReplay.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/VisualReplay.h 2022-08-21 12:45:08.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,12 +19,9 @@ #define INCLUDED_VISUAL_REPLAY #include "lib/os_path.h" +#include "ps/CStrForward.h" #include "scriptinterface/ScriptTypes.h" -class CSimulation2; -class CGUIManager; -class CStrW; - class ScriptInterface; /** diff -Nru 0ad-0.0.25b/source/ps/World.cpp 0ad-0.0.26/source/ps/World.cpp --- 0ad-0.0.25b/source/ps/World.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/World.cpp 2022-08-21 12:45:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,12 +15,6 @@ * along with 0 A.D. If not, see . */ -/** - * File : World.cpp - * Project : engine - * Description : Contains the CWorld Class implementation. - * - **/ #include "precompiled.h" #include "graphics/GameView.h" @@ -39,6 +33,7 @@ #include "ps/LoaderThunks.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "simulation2/Simulation2.h" /** @@ -76,8 +71,8 @@ { CTriggerManager* pTriggerManager = NULL; m_MapReader->LoadMap(mapfilename, cx, settings, m_Terrain, - CRenderer::IsInitialised() ? g_Renderer.GetWaterManager() : NULL, - CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetWaterManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetSkyManager() : NULL, &g_LightEnv, m_pGame->GetView(), m_pGame->GetView() ? m_pGame->GetView()->GetCinema() : NULL, pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL, @@ -99,8 +94,8 @@ // If scriptFile is empty, a blank map will be generated using settings (no RMS run) CTriggerManager* pTriggerManager = NULL; m_MapReader->LoadRandomMap(scriptFile, cx, settings, m_Terrain, - CRenderer::IsInitialised() ? g_Renderer.GetWaterManager() : NULL, - CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetWaterManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetSkyManager() : NULL, &g_LightEnv, m_pGame->GetView(), m_pGame->GetView() ? m_pGame->GetView()->GetCinema() : NULL, pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL, diff -Nru 0ad-0.0.25b/source/ps/World.h 0ad-0.0.26/source/ps/World.h --- 0ad-0.0.25b/source/ps/World.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/World.h 2022-08-21 12:45:08.000000000 +0000 @@ -24,6 +24,7 @@ #ifndef INCLUDED_WORLD #define INCLUDED_WORLD +#include "ps/CStrForward.h" #include "ps/Errors.h" #ifndef ERROR_GROUP_GAME_DEFINED @@ -36,7 +37,6 @@ class CGame; class CUnitManager; class CTerrain; -class CStrW; class CMapReader; class ScriptContext; diff -Nru 0ad-0.0.25b/source/ps/XMB/XMBData.h 0ad-0.0.26/source/ps/XMB/XMBData.h --- 0ad-0.0.25b/source/ps/XMB/XMBData.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/XMB/XMBData.h 2022-08-21 12:45:04.000000000 +0000 @@ -85,7 +85,6 @@ #include #include -class CXeromyces; class XMBStorage; class XMBElement; diff -Nru 0ad-0.0.25b/source/ps/XMB/XMBStorage.cpp 0ad-0.0.26/source/ps/XMB/XMBStorage.cpp --- 0ad-0.0.25b/source/ps/XMB/XMBStorage.cpp 2021-07-27 21:56:55.000000000 +0000 +++ 0ad-0.0.26/source/ps/XMB/XMBStorage.cpp 2022-09-23 19:16:55.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -129,7 +129,7 @@ void XMBStorageWriter::OutputNames(WriteBuffer& writeBuffer, const std::unordered_map& names) const { std::vector> orderedElements; - for (const std::pair& n : names) + for (const std::pair& n : names) orderedElements.emplace_back(n); std::sort(orderedElements.begin(), orderedElements.end(), [](const auto& a, const auto&b) { return a.second < b.second; }); for (const std::pair& n : orderedElements) @@ -181,7 +181,7 @@ data.Output(writeBuffer, value); // Output attributes - for (const std::pair attr : data.m_Attributes) + for (const std::pair attr : data.m_Attributes) { writeBuffer.Append(&attr.first, 4); u32 attrLen = u32(attr.second.size())+1; diff -Nru 0ad-0.0.25b/source/ps/XML/RelaxNG.h 0ad-0.0.26/source/ps/XML/RelaxNG.h --- 0ad-0.0.25b/source/ps/XML/RelaxNG.h 2021-07-27 21:56:56.000000000 +0000 +++ 0ad-0.0.26/source/ps/XML/RelaxNG.h 2022-08-21 12:45:04.000000000 +0000 @@ -26,8 +26,6 @@ typedef struct _xmlDoc xmlDoc; typedef xmlDoc *xmlDocPtr; -class IRelaxNGGrammar; - class RelaxNGValidator { public: diff -Nru 0ad-0.0.25b/source/ps/XML/Xeromyces.cpp 0ad-0.0.26/source/ps/XML/Xeromyces.cpp --- 0ad-0.0.25b/source/ps/XML/Xeromyces.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/ps/XML/Xeromyces.cpp 2022-08-21 12:45:04.000000000 +0000 @@ -126,14 +126,12 @@ if (ret == INFO::OK) { // Found a cached XMB - load it - if (m_Data.ReadFromFile(vfs, xmbPath)) - { - if(!Initialise(m_Data)) - return PSRETURN_Xeromyces_XMLParseError; + if (m_Data.ReadFromFile(vfs, xmbPath) && Initialise(m_Data)) return PSRETURN_OK; - } // If this fails then we'll continue and (re)create the loose cache - - // this failure legitimately happens due to partially-written XMB files. + // this failure legitimately happens due to partially-written XMB files or XMB version upgrades. + // NB: at this point xmbPath may point to an archived file, we want to write a loose cached version. + xmbPath = cacheLoader.LooseCachePath(filename, validatorGrammarHash, XMBStorage::XMBVersion); } else if (ret == INFO::SKIPPED) { diff -Nru 0ad-0.0.25b/source/renderer/backend/CompareOp.cpp 0ad-0.0.26/source/renderer/backend/CompareOp.cpp --- 0ad-0.0.25b/source/renderer/backend/CompareOp.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/CompareOp.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "CompareOp.h" + +namespace Renderer +{ + +namespace Backend +{ + +CompareOp ParseCompareOp(const CStr& str) +{ + // TODO: it might make sense to use upper case in XML for consistency. +#define CASE(NAME, VALUE) if (str == NAME) return CompareOp::VALUE + CASE("never", NEVER); + CASE("less", LESS); + CASE("equal", EQUAL); + CASE("lequal", LESS_OR_EQUAL); + CASE("greater", GREATER); + CASE("notequal", NOT_EQUAL); + CASE("gequal", GREATER_OR_EQUAL); + CASE("always", ALWAYS); +#undef CASE + debug_warn("Invalid compare op"); + return CompareOp::NEVER; +} + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/CompareOp.h 0ad-0.0.26/source/renderer/backend/CompareOp.h --- 0ad-0.0.25b/source/renderer/backend/CompareOp.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/CompareOp.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,57 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_COMPAREOP +#define INCLUDED_RENDERER_BACKEND_COMPAREOP + +#include "graphics/Color.h" + +class CStr; + +namespace Renderer +{ + +namespace Backend +{ + +enum class CompareOp +{ + // Never passes the comparison. + NEVER, + // Passes if the source value is less than the destination value. + LESS, + // Passes if the source depth value is equal to the destination value. + EQUAL, + // Passes if the source depth value is less than or equal to the destination value. + LESS_OR_EQUAL, + // Passes if the source depth value is greater than the destination value. + GREATER, + // Passes if the source depth value is not equal to the destination value. + NOT_EQUAL, + // Passes if the source depth value is greater than or equal to the destination value. + GREATER_OR_EQUAL, + // Always passes the comparison. + ALWAYS +}; + +CompareOp ParseCompareOp(const CStr& str); + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_COMPAREOP diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Buffer.cpp 0ad-0.0.26/source/renderer/backend/dummy/Buffer.cpp --- 0ad-0.0.25b/source/renderer/backend/dummy/Buffer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Buffer.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,58 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Buffer.h" + +#include "renderer/backend/dummy/Device.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +// static +std::unique_ptr CBuffer::Create( + CDevice* device, const Type type, const uint32_t size, const bool dynamic) +{ + std::unique_ptr buffer(new CBuffer()); + buffer->m_Device = device; + buffer->m_Type = type; + buffer->m_Size = size; + buffer->m_Dynamic = dynamic; + return buffer; +} + +CBuffer::CBuffer() = default; + +CBuffer::~CBuffer() = default; + +IDevice* CBuffer::GetDevice() +{ + return m_Device; +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Buffer.h 0ad-0.0.26/source/renderer/backend/dummy/Buffer.h --- 0ad-0.0.25b/source/renderer/backend/dummy/Buffer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Buffer.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,68 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_DUMMY_BUFFER +#define INCLUDED_RENDERER_BACKEND_DUMMY_BUFFER + +#include "renderer/backend/IBuffer.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDevice; + +class CBuffer : public IBuffer +{ +public: + ~CBuffer() override; + + IDevice* GetDevice() override; + + Type GetType() const override { return m_Type; } + uint32_t GetSize() const override { return m_Size; } + bool IsDynamic() const override { return m_Dynamic; } + +private: + friend class CDevice; + + static std::unique_ptr Create( + CDevice* device, const Type type, const uint32_t size, const bool dynamic); + + CBuffer(); + + CDevice* m_Device = nullptr; + + Type m_Type = Type::VERTEX; + uint32_t m_Size = 0; + bool m_Dynamic = false; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_DUMMY_BUFFER diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/DeviceCommandContext.cpp 0ad-0.0.26/source/renderer/backend/dummy/DeviceCommandContext.cpp --- 0ad-0.0.25b/source/renderer/backend/dummy/DeviceCommandContext.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/DeviceCommandContext.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,215 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "DeviceCommandContext.h" + +#include "renderer/backend/dummy/Buffer.h" +#include "renderer/backend/dummy/Device.h" +#include "renderer/backend/dummy/Framebuffer.h" +#include "renderer/backend/dummy/ShaderProgram.h" +#include "renderer/backend/dummy/Texture.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +// static +std::unique_ptr CDeviceCommandContext::Create(CDevice* device) +{ + std::unique_ptr deviceCommandContext(new CDeviceCommandContext()); + deviceCommandContext->m_Device = device; + return deviceCommandContext; +} + +CDeviceCommandContext::CDeviceCommandContext() = default; + +CDeviceCommandContext::~CDeviceCommandContext() = default; + +IDevice* CDeviceCommandContext::GetDevice() +{ + return m_Device; +} + +void CDeviceCommandContext::SetGraphicsPipelineState( + const GraphicsPipelineStateDesc&) +{ +} + +void CDeviceCommandContext::UploadTexture( + ITexture*, const Format, const void*, const size_t, + const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::UploadTextureRegion( + ITexture*, const Format, const void*, const size_t, + const uint32_t, const uint32_t, const uint32_t, const uint32_t, + const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::UploadBuffer(IBuffer*, const void*, const uint32_t) +{ +} + +void CDeviceCommandContext::UploadBuffer(IBuffer*, const UploadBufferFunction&) +{ +} + +void CDeviceCommandContext::UploadBufferRegion( + IBuffer*, const void*, const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::UploadBufferRegion( + IBuffer*, const uint32_t, const uint32_t, const UploadBufferFunction&) +{ +} + +void CDeviceCommandContext::BeginScopedLabel(const char*) +{ +} + +void CDeviceCommandContext::EndScopedLabel() +{ +} + +void CDeviceCommandContext::Flush() +{ +} + +void CDeviceCommandContext::BlitFramebuffer(IFramebuffer*, IFramebuffer*) +{ +} + +void CDeviceCommandContext::ClearFramebuffer() +{ +} + +void CDeviceCommandContext::ClearFramebuffer(const bool, const bool, const bool) +{ +} + +void CDeviceCommandContext::SetFramebuffer(IFramebuffer*) +{ +} + +void CDeviceCommandContext::ReadbackFramebufferSync( + const uint32_t, const uint32_t, const uint32_t, const uint32_t, void*) +{ +} + +void CDeviceCommandContext::SetScissors(const uint32_t, const Rect*) +{ +} + +void CDeviceCommandContext::SetViewports(const uint32_t, const Rect*) +{ +} + +void CDeviceCommandContext::SetVertexAttributeFormat( + const VertexAttributeStream, const Format, + const uint32_t, const uint32_t, const VertexAttributeRate, const uint32_t) +{ +} + +void CDeviceCommandContext::SetVertexBuffer(const uint32_t, IBuffer*) +{ +} + +void CDeviceCommandContext::SetVertexBufferData( + const uint32_t, const void*, const uint32_t) +{ +} + +void CDeviceCommandContext::SetIndexBuffer(IBuffer*) +{ +} + +void CDeviceCommandContext::SetIndexBufferData(const void*, const uint32_t) +{ +} + +void CDeviceCommandContext::BeginPass() +{ +} + +void CDeviceCommandContext::EndPass() +{ +} + +void CDeviceCommandContext::Draw(const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::DrawIndexed(const uint32_t, const uint32_t, const int32_t) +{ +} + +void CDeviceCommandContext::DrawInstanced( + const uint32_t, const uint32_t, const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::DrawIndexedInstanced( + const uint32_t, const uint32_t, const uint32_t, const uint32_t, const int32_t) +{ +} + +void CDeviceCommandContext::DrawIndexedInRange( + const uint32_t, const uint32_t, const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::SetTexture(const int32_t, ITexture*) +{ +} + +void CDeviceCommandContext::SetUniform(const int32_t, const float) +{ +} + +void CDeviceCommandContext::SetUniform(const int32_t, const float, const float) +{ +} + +void CDeviceCommandContext::SetUniform( + const int32_t, const float, const float, const float) +{ +} + +void CDeviceCommandContext::SetUniform( + const int32_t, const float, const float, const float, const float) +{ +} + +void CDeviceCommandContext::SetUniform(const int32_t, PS::span) +{ +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/DeviceCommandContext.h 0ad-0.0.26/source/renderer/backend/dummy/DeviceCommandContext.h --- 0ad-0.0.25b/source/renderer/backend/dummy/DeviceCommandContext.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/DeviceCommandContext.h 2022-09-23 19:17:03.000000000 +0000 @@ -0,0 +1,152 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_DUMMY_DEVICECOMMANDCONTEXT +#define INCLUDED_RENDERER_DUMMY_DEVICECOMMANDCONTEXT + +#include "renderer/backend/Format.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/PipelineState.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDevice; +class CBuffer; +class CFramebuffer; +class CShaderProgram; +class CTexture; + +class CDeviceCommandContext : public IDeviceCommandContext +{ +public: + ~CDeviceCommandContext(); + + IDevice* GetDevice() override; + + void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) override; + + void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override; + + void ClearFramebuffer() override; + void ClearFramebuffer(const bool color, const bool depth, const bool stencil) override; + void SetFramebuffer(IFramebuffer* framebuffer) override; + void ReadbackFramebufferSync( + const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, + void* data) override; + + void UploadTexture(ITexture* texture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t level = 0, const uint32_t layer = 0) override; + void UploadTextureRegion(ITexture* texture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t xOffset, const uint32_t yOffset, + const uint32_t width, const uint32_t height, + const uint32_t level = 0, const uint32_t layer = 0) override; + + using UploadBufferFunction = std::function; + void UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize) override; + void UploadBuffer(IBuffer* buffer, const UploadBufferFunction& uploadFunction) override; + void UploadBufferRegion( + IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize) override; + void UploadBufferRegion( + IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize, + const UploadBufferFunction& uploadFunction) override; + + void SetScissors(const uint32_t scissorCount, const Rect* scissors) override; + void SetViewports(const uint32_t viewportCount, const Rect* viewports) override; + + void SetVertexAttributeFormat( + const VertexAttributeStream stream, + const Format format, + const uint32_t offset, + const uint32_t stride, + const VertexAttributeRate rate, + const uint32_t bindingSlot) override; + void SetVertexBuffer(const uint32_t bindingSlot, IBuffer* buffer) override; + void SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) override; + + void SetIndexBuffer(IBuffer* buffer) override; + void SetIndexBufferData(const void* data, const uint32_t dataSize) override; + + void BeginPass() override; + void EndPass() override; + + void Draw(const uint32_t firstVertex, const uint32_t vertexCount) override; + void DrawIndexed( + const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) override; + void DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) override; + void DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) override; + void DrawIndexedInRange( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t start, const uint32_t end) override; + + void SetTexture(const int32_t bindingSlot, ITexture* texture) override; + + void SetUniform( + const int32_t bindingSlot, + const float value) override; + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) override; + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) override; + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) override; + void SetUniform( + const int32_t bindingSlot, PS::span values) override; + + void BeginScopedLabel(const char* name) override; + void EndScopedLabel() override; + + void Flush() override; + +private: + friend class CDevice; + + static std::unique_ptr Create(CDevice* device); + + CDeviceCommandContext(); + + CDevice* m_Device = nullptr; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_DUMMY_DEVICECOMMANDCONTEXT diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Device.cpp 0ad-0.0.26/source/renderer/backend/dummy/Device.cpp --- 0ad-0.0.25b/source/renderer/backend/dummy/Device.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Device.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,134 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Device.h" + +#include "renderer/backend/dummy/Buffer.h" +#include "renderer/backend/dummy/DeviceCommandContext.h" +#include "renderer/backend/dummy/Framebuffer.h" +#include "renderer/backend/dummy/ShaderProgram.h" +#include "renderer/backend/dummy/Texture.h" +#include "scriptinterface/JSON.h" +#include "scriptinterface/Object.h" +#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/ScriptRequest.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +CDevice::CDevice() +{ + m_Name = "Dummy"; + m_Version = "Unknown"; + m_DriverInformation = "Unknown"; + m_Extensions = {}; + + m_Backbuffer = CFramebuffer::Create(this); + + m_Capabilities.S3TC = true; + m_Capabilities.ARBShaders = false; + m_Capabilities.ARBShadersShadow = false; + m_Capabilities.computeShaders = true; + m_Capabilities.debugLabels = true; + m_Capabilities.debugScopedLabels = true; + m_Capabilities.multisampling = true; + m_Capabilities.anisotropicFiltering = true; + m_Capabilities.maxSampleCount = 4u; + m_Capabilities.maxAnisotropy = 16.0f; + m_Capabilities.maxTextureSize = 8192u; + m_Capabilities.instancing = true; +} + +CDevice::~CDevice() = default; + +void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings) +{ + Script::SetProperty(rq, settings, "name", "dummy"); +} + +std::unique_ptr CDevice::CreateCommandContext() +{ + return CDeviceCommandContext::Create(this); +} + +std::unique_ptr CDevice::CreateTexture(const char* UNUSED(name), const CTexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& UNUSED(defaultSamplerDesc), const uint32_t MIPLevelCount, const uint32_t UNUSED(sampleCount)) +{ + return CTexture::Create(this, type, format, width, height, MIPLevelCount); +} + +std::unique_ptr CDevice::CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) +{ + return CreateTexture(name, ITexture::Type::TEXTURE_2D, + format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount); +} + +std::unique_ptr CDevice::CreateFramebuffer( + const char*, ITexture*, ITexture*) +{ + return CFramebuffer::Create(this); +} + +std::unique_ptr CDevice::CreateFramebuffer( + const char*, ITexture*, ITexture*, const CColor&) +{ + return CFramebuffer::Create(this); +} + +std::unique_ptr CDevice::CreateBuffer( + const char*, const CBuffer::Type type, const uint32_t size, const bool dynamic) +{ + return CBuffer::Create(this, type, size, dynamic); +} + +std::unique_ptr CDevice::CreateShaderProgram( + const CStr&, const CShaderDefines&) +{ + return CShaderProgram::Create(this); +} + +void CDevice::Present() +{ + // We have nothing to present. +} + +bool CDevice::IsTextureFormatSupported(const Format UNUSED(format)) const +{ + return true; +} + +bool CDevice::IsFramebufferFormatSupported(const Format UNUSED(format)) const +{ + return true; +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Device.h 0ad-0.0.26/source/renderer/backend/dummy/Device.h --- 0ad-0.0.25b/source/renderer/backend/dummy/Device.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Device.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,101 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_DUMMY_DEVICE +#define INCLUDED_RENDERER_BACKEND_DUMMY_DEVICE + +#include "renderer/backend/IDevice.h" + +class CShaderDefines; + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDeviceCommandContext; + +class CDevice : public IDevice +{ +public: + CDevice(); + ~CDevice() override; + + const std::string& GetName() const override { return m_Name; } + const std::string& GetVersion() const override { return m_Version; } + const std::string& GetDriverInformation() const override { return m_DriverInformation; } + const std::vector& GetExtensions() const override { return m_Extensions; } + + void Report(const ScriptRequest& rq, JS::HandleValue settings) override; + + IFramebuffer* GetCurrentBackbuffer() override { return m_Backbuffer.get(); } + + std::unique_ptr CreateCommandContext() override; + + std::unique_ptr CreateTexture(const char* name, const ITexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) override; + + std::unique_ptr CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override; + + std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment) override; + + std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment, const CColor& clearColor) override; + + std::unique_ptr CreateBuffer( + const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) override; + + std::unique_ptr CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) override; + + void Present() override; + + bool IsTextureFormatSupported(const Format format) const override; + + bool IsFramebufferFormatSupported(const Format format) const override; + + const Capabilities& GetCapabilities() const override { return m_Capabilities; } + +protected: + + std::string m_Name; + std::string m_Version; + std::string m_DriverInformation; + std::vector m_Extensions; + + std::unique_ptr m_Backbuffer; + + Capabilities m_Capabilities{}; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_DUMMY_DEVICE diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Framebuffer.cpp 0ad-0.0.26/source/renderer/backend/dummy/Framebuffer.cpp --- 0ad-0.0.25b/source/renderer/backend/dummy/Framebuffer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Framebuffer.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,54 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Framebuffer.h" + +#include "renderer/backend/dummy/Device.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +CFramebuffer::CFramebuffer() = default; + +CFramebuffer::~CFramebuffer() = default; + +// static +std::unique_ptr CFramebuffer::Create(CDevice* device) +{ + std::unique_ptr framebuffer(new CFramebuffer()); + framebuffer->m_Device = device; + return framebuffer; +} + +IDevice* CFramebuffer::GetDevice() +{ + return m_Device; +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Framebuffer.h 0ad-0.0.26/source/renderer/backend/dummy/Framebuffer.h --- 0ad-0.0.25b/source/renderer/backend/dummy/Framebuffer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Framebuffer.h 2022-09-23 19:17:03.000000000 +0000 @@ -0,0 +1,63 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_DUMMY_FRAMEBUFFER +#define INCLUDED_RENDERER_BACKEND_DUMMY_FRAMEBUFFER + +#include "renderer/backend/IFramebuffer.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDevice; + +class CFramebuffer : public IFramebuffer +{ +public: + ~CFramebuffer() override; + + IDevice* GetDevice() override; + + const CColor& GetClearColor() const override { return m_ClearColor; } + +private: + friend class CDevice; + + static std::unique_ptr Create(CDevice* device); + + CFramebuffer(); + + CDevice* m_Device = nullptr; + + CColor m_ClearColor; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_DUMMY_FRAMEBUFFER diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/ShaderProgram.cpp 0ad-0.0.26/source/renderer/backend/dummy/ShaderProgram.cpp --- 0ad-0.0.25b/source/renderer/backend/dummy/ShaderProgram.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/ShaderProgram.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,64 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "ShaderProgram.h" + +#include "renderer/backend/dummy/Device.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +CShaderProgram::CShaderProgram() = default; + +CShaderProgram::~CShaderProgram() = default; + +// static +std::unique_ptr CShaderProgram::Create(CDevice* device) +{ + std::unique_ptr shaderProgram(new CShaderProgram()); + shaderProgram->m_Device = device; + return shaderProgram; +} + +IDevice* CShaderProgram::GetDevice() +{ + return m_Device; +} + +int32_t CShaderProgram::GetBindingSlot(const CStrIntern UNUSED(name)) const +{ + return -1; +} + +std::vector CShaderProgram::GetFileDependencies() const +{ + return {}; +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/ShaderProgram.h 0ad-0.0.26/source/renderer/backend/dummy/ShaderProgram.h --- 0ad-0.0.25b/source/renderer/backend/dummy/ShaderProgram.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/ShaderProgram.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,63 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_DUMMY_SHADERPROGRAM +#define INCLUDED_RENDERER_BACKEND_DUMMY_SHADERPROGRAM + +#include "renderer/backend/IShaderProgram.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDevice; + +class CShaderProgram : public IShaderProgram +{ +public: + ~CShaderProgram() override; + + IDevice* GetDevice() override; + + int32_t GetBindingSlot(const CStrIntern name) const override; + + std::vector GetFileDependencies() const override; + +protected: + friend class CDevice; + + CShaderProgram(); + + static std::unique_ptr Create(CDevice* device); + + CDevice* m_Device = nullptr; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_DUMMY_SHADERPROGRAM diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Texture.cpp 0ad-0.0.26/source/renderer/backend/dummy/Texture.cpp --- 0ad-0.0.25b/source/renderer/backend/dummy/Texture.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Texture.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,64 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Texture.h" + +#include "renderer/backend/dummy/Device.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +// static +std::unique_ptr CTexture::Create( + CDevice* device, const Type type, const Format format, + const uint32_t width, const uint32_t height, + const uint32_t MIPLevelCount) +{ + std::unique_ptr texture(new CTexture()); + + texture->m_Device = device; + texture->m_Format = format; + texture->m_Type = type; + texture->m_Width = width; + texture->m_Height = height; + texture->m_MIPLevelCount = MIPLevelCount; + + return texture; +} + +CTexture::CTexture() = default; + +CTexture::~CTexture() = default; + +IDevice* CTexture::GetDevice() +{ + return m_Device; +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/dummy/Texture.h 0ad-0.0.26/source/renderer/backend/dummy/Texture.h --- 0ad-0.0.25b/source/renderer/backend/dummy/Texture.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/dummy/Texture.h 2022-09-23 19:17:03.000000000 +0000 @@ -0,0 +1,74 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_DUMMY_TEXTURE +#define INCLUDED_RENDERER_BACKEND_DUMMY_TEXTURE + +#include "renderer/backend/ITexture.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDevice; + +class CTexture : public ITexture +{ +public: + ~CTexture() override; + + IDevice* GetDevice() override; + + Type GetType() const override { return m_Type; } + Format GetFormat() const override { return m_Format; } + + uint32_t GetWidth() const override { return m_Width; } + uint32_t GetHeight() const override { return m_Height; } + uint32_t GetMIPLevelCount() const override { return m_MIPLevelCount; } + +private: + friend class CDevice; + + CTexture(); + + static std::unique_ptr Create( + CDevice* device, const Type type, const Format format, + const uint32_t width, const uint32_t height, + const uint32_t MIPLevelCount); + + CDevice* m_Device = nullptr; + Type m_Type = Type::TEXTURE_2D; + Format m_Format = Format::UNDEFINED; + uint32_t m_Width = 0; + uint32_t m_Height = 0; + uint32_t m_MIPLevelCount = 0; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_DUMMY_TEXTURE diff -Nru 0ad-0.0.25b/source/renderer/backend/Format.h 0ad-0.0.26/source/renderer/backend/Format.h --- 0ad-0.0.25b/source/renderer/backend/Format.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/Format.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,69 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_FORMAT +#define INCLUDED_RENDERER_BACKEND_FORMAT + +namespace Renderer +{ + +namespace Backend +{ + +enum class Format +{ + UNDEFINED, + R8_UNORM, + R8G8_UNORM, + R8G8_UINT, + R8G8B8_UNORM, + R8G8B8A8_UNORM, + R8G8B8A8_UINT, + + // TODO: we need to drop legacy A8 and L8 formats as soon as we have proper + // channel swizzling. + A8_UNORM, + L8_UNORM, + + R16_UNORM, + R16_UINT, + R16_SINT, + R16G16_UNORM, + R16G16_UINT, + R16G16_SINT, + + R32_SFLOAT, + R32G32_SFLOAT, + R32G32B32_SFLOAT, + R32G32B32A32_SFLOAT, + + D16, + D24, + D24_S8, + D32, + + BC1_RGB_UNORM, + BC1_RGBA_UNORM, + BC2_UNORM, + BC3_UNORM +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_FORMAT diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Buffer.cpp 0ad-0.0.26/source/renderer/backend/gl/Buffer.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/Buffer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Buffer.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -0,0 +1,81 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Buffer.h" + +#include "lib/code_annotation.h" +#include "lib/config2.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/Texture.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +// static +std::unique_ptr CBuffer::Create( + CDevice* device, const char* name, + const Type type, const uint32_t size, const bool dynamic) +{ + std::unique_ptr buffer(new CBuffer()); + buffer->m_Device = device; + buffer->m_Type = type; + buffer->m_Size = size; + buffer->m_Dynamic = dynamic; + glGenBuffersARB(1, &buffer->m_Handle); + const GLenum target = type == Type::INDEX ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER; + glBindBufferARB(target, buffer->m_Handle); + glBufferDataARB(target, size, nullptr, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +#if !CONFIG2_GLES + if (buffer->m_Device->GetCapabilities().debugLabels) + { + glObjectLabel(GL_BUFFER, buffer->m_Handle, -1, name); + } +#else + UNUSED2(name); +#endif + glBindBufferARB(target, 0); + return buffer; +} + +CBuffer::CBuffer() = default; + +CBuffer::~CBuffer() +{ + if (m_Handle) + glDeleteBuffersARB(1, &m_Handle); +} + +IDevice* CBuffer::GetDevice() +{ + return m_Device; +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Buffer.h 0ad-0.0.26/source/renderer/backend/gl/Buffer.h --- 0ad-0.0.25b/source/renderer/backend/gl/Buffer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Buffer.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,74 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_BUFFER +#define INCLUDED_RENDERER_BACKEND_GL_BUFFER + +#include "lib/ogl.h" +#include "renderer/backend/IBuffer.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +class CBuffer final : public IBuffer +{ +public: + ~CBuffer() override; + + IDevice* GetDevice() override; + + Type GetType() const override { return m_Type; } + uint32_t GetSize() const override { return m_Size; } + bool IsDynamic() const override { return m_Dynamic; } + + GLuint GetHandle() { return m_Handle; } + +private: + friend class CDevice; + + static std::unique_ptr Create( + CDevice* device, const char* name, + const Type type, const uint32_t size, const bool dynamic); + + CBuffer(); + + CDevice* m_Device = nullptr; + Type m_Type = Type::VERTEX; + uint32_t m_Size = 0; + bool m_Dynamic = false; + + GLuint m_Handle = 0; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_BUFFER diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/DeviceCommandContext.cpp 0ad-0.0.26/source/renderer/backend/gl/DeviceCommandContext.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/DeviceCommandContext.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/DeviceCommandContext.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -0,0 +1,1192 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "DeviceCommandContext.h" + +#include "ps/CLogger.h" +#include "renderer/backend/gl/Buffer.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/Framebuffer.h" +#include "renderer/backend/gl/Mapping.h" +#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/gl/Texture.h" + +#include +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace +{ + +bool operator==(const StencilOpState& lhs, const StencilOpState& rhs) +{ + return + lhs.failOp == rhs.failOp && + lhs.passOp == rhs.passOp && + lhs.depthFailOp == rhs.depthFailOp && + lhs.compareOp == rhs.compareOp; +} +bool operator!=(const StencilOpState& lhs, const StencilOpState& rhs) +{ + return !operator==(lhs, rhs); +} + +bool operator==( + const CDeviceCommandContext::Rect& lhs, + const CDeviceCommandContext::Rect& rhs) +{ + return + lhs.x == rhs.x && lhs.y == rhs.y && + lhs.width == rhs.width && lhs.height == rhs.height; +} + +bool operator!=( + const CDeviceCommandContext::Rect& lhs, + const CDeviceCommandContext::Rect& rhs) +{ + return !operator==(lhs, rhs); +} + +void ApplyDepthMask(const bool depthWriteEnabled) +{ + glDepthMask(depthWriteEnabled ? GL_TRUE : GL_FALSE); +} + +void ApplyColorMask(const uint8_t colorWriteMask) +{ + glColorMask( + (colorWriteMask & ColorWriteMask::RED) != 0 ? GL_TRUE : GL_FALSE, + (colorWriteMask & ColorWriteMask::GREEN) != 0 ? GL_TRUE : GL_FALSE, + (colorWriteMask & ColorWriteMask::BLUE) != 0 ? GL_TRUE : GL_FALSE, + (colorWriteMask & ColorWriteMask::ALPHA) != 0 ? GL_TRUE : GL_FALSE); +} + +void ApplyStencilMask(const uint32_t stencilWriteMask) +{ + glStencilMask(stencilWriteMask); +} + +GLenum BufferTypeToGLTarget(const CBuffer::Type type) +{ + GLenum target = GL_ARRAY_BUFFER; + switch (type) + { + case CBuffer::Type::VERTEX: + target = GL_ARRAY_BUFFER; + break; + case CBuffer::Type::INDEX: + target = GL_ELEMENT_ARRAY_BUFFER; + break; + }; + return target; +} + +#if !CONFIG2_GLES +bool IsDepthTexture(const Format format) +{ + return + format == Format::D16 || format == Format::D24 || + format == Format::D32 || format == Format::D24_S8; +} +#endif // !CONFIG2_GLES + +void UploadDynamicBufferRegionImpl( + const GLenum target, const uint32_t bufferSize, + const uint32_t dataOffset, const uint32_t dataSize, + const CDeviceCommandContext::UploadBufferFunction& uploadFunction) +{ + ENSURE(dataOffset < dataSize); + // Tell the driver that it can reallocate the whole VBO + glBufferDataARB(target, bufferSize, nullptr, GL_DYNAMIC_DRAW); + ogl_WarnIfError(); + + while (true) + { + // (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used + // here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with + // current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do + // the explicit glBufferData.) + void* mappedData = glMapBufferARB(target, GL_WRITE_ONLY); + if (mappedData == nullptr) + { + // This shouldn't happen unless we run out of virtual address space + LOGERROR("glMapBuffer failed"); + break; + } + + uploadFunction(static_cast(mappedData) + dataOffset); + + if (glUnmapBufferARB(target) == GL_TRUE) + break; + + // Unmap might fail on e.g. resolution switches, so just try again + // and hope it will eventually succeed + LOGMESSAGE("glUnmapBuffer failed, trying again...\n"); + } +} + +} // anonymous namespace + +// static +std::unique_ptr CDeviceCommandContext::Create(CDevice* device) +{ + std::unique_ptr deviceCommandContext(new CDeviceCommandContext(device)); + deviceCommandContext->m_Framebuffer = static_cast(device->GetCurrentBackbuffer()); + deviceCommandContext->ResetStates(); + return deviceCommandContext; +} + +CDeviceCommandContext::CDeviceCommandContext(CDevice* device) + : m_Device(device) +{ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + for (BindUnit& unit : m_BoundTextures) + { + unit.target = GL_TEXTURE_2D; + unit.handle = 0; + } + for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) + { + m_VertexAttributeFormat[index].active = false; + m_VertexAttributeFormat[index].initialized = false; + m_VertexAttributeFormat[index].bindingSlot = 0; + } + + for (size_t index = 0; index < m_BoundBuffers.size(); ++index) + { + const CBuffer::Type type = static_cast(index); + const GLenum target = BufferTypeToGLTarget(type); + const GLuint handle = 0; + m_BoundBuffers[index].first = target; + m_BoundBuffers[index].second = handle; + } +} + +CDeviceCommandContext::~CDeviceCommandContext() = default; + +IDevice* CDeviceCommandContext::GetDevice() +{ + return m_Device; +} + +void CDeviceCommandContext::SetGraphicsPipelineState( + const GraphicsPipelineStateDesc& pipelineStateDesc) +{ + SetGraphicsPipelineStateImpl(pipelineStateDesc, false); +} + +void CDeviceCommandContext::UploadTexture( + ITexture* texture, const Format format, + const void* data, const size_t dataSize, + const uint32_t level, const uint32_t layer) +{ + UploadTextureRegion(texture, format, data, dataSize, + 0, 0, + std::max(1u, texture->GetWidth() >> level), + std::max(1u, texture->GetHeight() >> level), + level, layer); +} + +void CDeviceCommandContext::UploadTextureRegion( + ITexture* destinationTexture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t xOffset, const uint32_t yOffset, + const uint32_t width, const uint32_t height, + const uint32_t level, const uint32_t layer) +{ + ENSURE(destinationTexture); + CTexture* texture = destinationTexture->As(); + ENSURE(width > 0 && height > 0); + if (texture->GetType() == CTexture::Type::TEXTURE_2D) + { + ENSURE(layer == 0); + if (texture->GetFormat() == Format::R8G8B8A8_UNORM || + texture->GetFormat() == Format::R8G8B8_UNORM || +#if !CONFIG2_GLES + texture->GetFormat() == Format::R8_UNORM || +#endif + texture->GetFormat() == Format::A8_UNORM) + { + ENSURE(texture->GetFormat() == dataFormat); + size_t bytesPerPixel = 4; + GLenum pixelFormat = GL_RGBA; + switch (dataFormat) + { + case Format::R8G8B8A8_UNORM: + break; + case Format::R8G8B8_UNORM: + pixelFormat = GL_RGB; + bytesPerPixel = 3; + break; +#if !CONFIG2_GLES + case Format::R8_UNORM: + pixelFormat = GL_RED; + bytesPerPixel = 1; + break; +#endif + case Format::A8_UNORM: + pixelFormat = GL_ALPHA; + bytesPerPixel = 1; + break; + case Format::L8_UNORM: + pixelFormat = GL_LUMINANCE; + bytesPerPixel = 1; + break; + default: + debug_warn("Unexpected format."); + break; + } + ENSURE(dataSize == width * height * bytesPerPixel); + + ScopedBind scopedBind(this, GL_TEXTURE_2D, texture->GetHandle()); + glTexSubImage2D(GL_TEXTURE_2D, level, + xOffset, yOffset, width, height, + pixelFormat, GL_UNSIGNED_BYTE, data); + ogl_WarnIfError(); + } + else if ( + texture->GetFormat() == Format::BC1_RGB_UNORM || + texture->GetFormat() == Format::BC1_RGBA_UNORM || + texture->GetFormat() == Format::BC2_UNORM || + texture->GetFormat() == Format::BC3_UNORM) + { + ENSURE(xOffset == 0 && yOffset == 0); + ENSURE(texture->GetFormat() == dataFormat); + // TODO: add data size check. + + GLenum internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + switch (texture->GetFormat()) + { + case Format::BC1_RGBA_UNORM: + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case Format::BC2_UNORM: + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case Format::BC3_UNORM: + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + default: + break; + } + + ScopedBind scopedBind(this, GL_TEXTURE_2D, texture->GetHandle()); + glCompressedTexImage2DARB(GL_TEXTURE_2D, level, internalFormat, width, height, 0, dataSize, data); + ogl_WarnIfError(); + } + else + debug_warn("Unsupported format"); + } + else if (texture->GetType() == CTexture::Type::TEXTURE_CUBE) + { + if (texture->GetFormat() == Format::R8G8B8A8_UNORM) + { + ENSURE(texture->GetFormat() == dataFormat); + ENSURE(level == 0 && layer < 6); + ENSURE(xOffset == 0 && yOffset == 0 && texture->GetWidth() == width && texture->GetHeight() == height); + const size_t bpp = 4; + ENSURE(dataSize == width * height * bpp); + + // The order of layers should be the following: + // front, back, top, bottom, right, left + static const GLenum targets[6] = + { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + }; + + ScopedBind scopedBind(this, GL_TEXTURE_CUBE_MAP, texture->GetHandle()); + glTexImage2D(targets[layer], level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + ogl_WarnIfError(); + } + else + debug_warn("Unsupported format"); + } + else + debug_warn("Unsupported type"); +} + +void CDeviceCommandContext::UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize) +{ + UploadBufferRegion(buffer, data, dataSize, 0); +} + +void CDeviceCommandContext::UploadBuffer( + IBuffer* buffer, const UploadBufferFunction& uploadFunction) +{ + UploadBufferRegion(buffer, 0, buffer->GetSize(), uploadFunction); +} + +void CDeviceCommandContext::UploadBufferRegion( + IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize) +{ + ENSURE(data); + ENSURE(dataOffset + dataSize <= buffer->GetSize()); + const GLenum target = BufferTypeToGLTarget(buffer->GetType()); + ScopedBufferBind scopedBufferBind(this, buffer->As()); + if (buffer->IsDynamic()) + { + UploadDynamicBufferRegionImpl(target, buffer->GetSize(), dataOffset, dataSize, [data, dataSize](u8* mappedData) + { + std::memcpy(mappedData, data, dataSize); + }); + } + else + { + glBufferSubDataARB(target, dataOffset, dataSize, data); + ogl_WarnIfError(); + } +} + +void CDeviceCommandContext::UploadBufferRegion( + IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize, + const UploadBufferFunction& uploadFunction) +{ + ENSURE(dataOffset + dataSize <= buffer->GetSize()); + const GLenum target = BufferTypeToGLTarget(buffer->GetType()); + ScopedBufferBind scopedBufferBind(this, buffer->As()); + ENSURE(buffer->IsDynamic()); + UploadDynamicBufferRegionImpl(target, buffer->GetSize(), dataOffset, dataSize, uploadFunction); +} + +void CDeviceCommandContext::BeginScopedLabel(const char* name) +{ + if (!m_Device->GetCapabilities().debugScopedLabels) + return; + + ++m_ScopedLabelDepth; + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0x0AD, -1, name); +} + +void CDeviceCommandContext::EndScopedLabel() +{ + if (!m_Device->GetCapabilities().debugScopedLabels) + return; + + ENSURE(m_ScopedLabelDepth > 0); + --m_ScopedLabelDepth; + glPopDebugGroup(); +} + +void CDeviceCommandContext::BindTexture( + const uint32_t unit, const GLenum target, const GLuint handle) +{ + ENSURE(unit < m_BoundTextures.size()); +#if CONFIG2_GLES + ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); +#else + ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_2D_MULTISAMPLE); +#endif + if (m_ActiveTextureUnit != unit) + { + glActiveTexture(GL_TEXTURE0 + unit); + m_ActiveTextureUnit = unit; + } + if (m_BoundTextures[unit].target == target && m_BoundTextures[unit].handle == handle) + return; + if (m_BoundTextures[unit].target != target && m_BoundTextures[unit].target && m_BoundTextures[unit].handle) + glBindTexture(m_BoundTextures[unit].target, 0); + if (m_BoundTextures[unit].handle != handle) + glBindTexture(target, handle); + ogl_WarnIfError(); + m_BoundTextures[unit] = {target, handle}; +} + +void CDeviceCommandContext::BindBuffer(const IBuffer::Type type, CBuffer* buffer) +{ + ENSURE(!buffer || buffer->GetType() == type); + if (type == IBuffer::Type::VERTEX) + { + if (m_VertexBuffer == buffer) + return; + m_VertexBuffer = buffer; + } + else if (type == IBuffer::Type::INDEX) + { + if (!buffer) + m_IndexBuffer = nullptr; + m_IndexBufferData = nullptr; + } + const GLenum target = BufferTypeToGLTarget(type); + const GLuint handle = buffer ? buffer->GetHandle() : 0; + glBindBufferARB(target, handle); + ogl_WarnIfError(); + const size_t cacheIndex = static_cast(type); + ENSURE(cacheIndex < m_BoundBuffers.size()); + m_BoundBuffers[cacheIndex].second = handle; +} + +void CDeviceCommandContext::OnTextureDestroy(CTexture* texture) +{ + ENSURE(texture); + for (size_t index = 0; index < m_BoundTextures.size(); ++index) + if (m_BoundTextures[index].handle == texture->GetHandle()) + BindTexture(index, GL_TEXTURE_2D, 0); +} + +void CDeviceCommandContext::Flush() +{ + ENSURE(m_ScopedLabelDepth == 0); + + GPU_SCOPED_LABEL(this, "CDeviceCommandContext::Flush"); + + ResetStates(); + + m_IndexBuffer = nullptr; + m_IndexBufferData = nullptr; + + for (size_t unit = 0; unit < m_BoundTextures.size(); ++unit) + { + if (m_BoundTextures[unit].handle) + BindTexture(unit, GL_TEXTURE_2D, 0); + } + BindBuffer(CBuffer::Type::INDEX, nullptr); + BindBuffer(CBuffer::Type::VERTEX, nullptr); +} + +void CDeviceCommandContext::ResetStates() +{ + SetGraphicsPipelineStateImpl(MakeDefaultGraphicsPipelineStateDesc(), true); + SetScissors(0, nullptr); + SetFramebuffer(m_Device->GetCurrentBackbuffer()); +} + +void CDeviceCommandContext::SetGraphicsPipelineStateImpl( + const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force) +{ + ENSURE(!m_InsidePass); + + if (m_GraphicsPipelineStateDesc.shaderProgram != pipelineStateDesc.shaderProgram) + { + CShaderProgram* currentShaderProgram = nullptr; + if (m_GraphicsPipelineStateDesc.shaderProgram) + { + currentShaderProgram = + static_cast(m_GraphicsPipelineStateDesc.shaderProgram); + } + CShaderProgram* nextShaderProgram = nullptr; + if (pipelineStateDesc.shaderProgram) + { + nextShaderProgram = + static_cast(pipelineStateDesc.shaderProgram); + for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) + { + const VertexAttributeStream stream = static_cast(index); + m_VertexAttributeFormat[index].active = nextShaderProgram->IsStreamActive(stream); + m_VertexAttributeFormat[index].initialized = false; + m_VertexAttributeFormat[index].bindingSlot = std::numeric_limits::max(); + } + } + if (nextShaderProgram) + nextShaderProgram->Bind(currentShaderProgram); + else if (currentShaderProgram) + currentShaderProgram->Unbind(); + + m_ShaderProgram = nextShaderProgram; + } + + const DepthStencilStateDesc& currentDepthStencilStateDesc = m_GraphicsPipelineStateDesc.depthStencilState; + const DepthStencilStateDesc& nextDepthStencilStateDesc = pipelineStateDesc.depthStencilState; + if (force || currentDepthStencilStateDesc.depthTestEnabled != nextDepthStencilStateDesc.depthTestEnabled) + { + if (nextDepthStencilStateDesc.depthTestEnabled) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + } + if (force || currentDepthStencilStateDesc.depthCompareOp != nextDepthStencilStateDesc.depthCompareOp) + { + glDepthFunc(Mapping::FromCompareOp(nextDepthStencilStateDesc.depthCompareOp)); + } + if (force || currentDepthStencilStateDesc.depthWriteEnabled != nextDepthStencilStateDesc.depthWriteEnabled) + { + ApplyDepthMask(nextDepthStencilStateDesc.depthWriteEnabled); + } + + if (force || currentDepthStencilStateDesc.stencilTestEnabled != nextDepthStencilStateDesc.stencilTestEnabled) + { + if (nextDepthStencilStateDesc.stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + else + glDisable(GL_STENCIL_TEST); + } + if (force || + currentDepthStencilStateDesc.stencilFrontFace != nextDepthStencilStateDesc.stencilFrontFace || + currentDepthStencilStateDesc.stencilBackFace != nextDepthStencilStateDesc.stencilBackFace) + { + if (nextDepthStencilStateDesc.stencilFrontFace == nextDepthStencilStateDesc.stencilBackFace) + { + glStencilOp( + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.failOp), + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.depthFailOp), + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.passOp)); + } + else + { + if (force || currentDepthStencilStateDesc.stencilFrontFace != nextDepthStencilStateDesc.stencilFrontFace) + { + glStencilOpSeparate( + GL_FRONT, + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.failOp), + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.depthFailOp), + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.passOp)); + } + if (force || currentDepthStencilStateDesc.stencilBackFace != nextDepthStencilStateDesc.stencilBackFace) + { + glStencilOpSeparate( + GL_BACK, + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilBackFace.failOp), + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilBackFace.depthFailOp), + Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilBackFace.passOp)); + } + } + } + if (force || currentDepthStencilStateDesc.stencilWriteMask != nextDepthStencilStateDesc.stencilWriteMask) + { + ApplyStencilMask(nextDepthStencilStateDesc.stencilWriteMask); + } + if (force || + currentDepthStencilStateDesc.stencilReference != nextDepthStencilStateDesc.stencilReference || + currentDepthStencilStateDesc.stencilReadMask != nextDepthStencilStateDesc.stencilReadMask || + currentDepthStencilStateDesc.stencilFrontFace.compareOp != nextDepthStencilStateDesc.stencilFrontFace.compareOp || + currentDepthStencilStateDesc.stencilBackFace.compareOp != nextDepthStencilStateDesc.stencilBackFace.compareOp) + { + if (nextDepthStencilStateDesc.stencilFrontFace.compareOp == nextDepthStencilStateDesc.stencilBackFace.compareOp) + { + glStencilFunc( + Mapping::FromCompareOp(nextDepthStencilStateDesc.stencilFrontFace.compareOp), + nextDepthStencilStateDesc.stencilReference, + nextDepthStencilStateDesc.stencilReadMask); + } + else + { + glStencilFuncSeparate(GL_FRONT, + Mapping::FromCompareOp(nextDepthStencilStateDesc.stencilFrontFace.compareOp), + nextDepthStencilStateDesc.stencilReference, + nextDepthStencilStateDesc.stencilReadMask); + glStencilFuncSeparate(GL_BACK, + Mapping::FromCompareOp(nextDepthStencilStateDesc.stencilBackFace.compareOp), + nextDepthStencilStateDesc.stencilReference, + nextDepthStencilStateDesc.stencilReadMask); + } + } + + const BlendStateDesc& currentBlendStateDesc = m_GraphicsPipelineStateDesc.blendState; + const BlendStateDesc& nextBlendStateDesc = pipelineStateDesc.blendState; + if (force || currentBlendStateDesc.enabled != nextBlendStateDesc.enabled) + { + if (nextBlendStateDesc.enabled) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + } + if (force || + currentBlendStateDesc.srcColorBlendFactor != nextBlendStateDesc.srcColorBlendFactor || + currentBlendStateDesc.srcAlphaBlendFactor != nextBlendStateDesc.srcAlphaBlendFactor || + currentBlendStateDesc.dstColorBlendFactor != nextBlendStateDesc.dstColorBlendFactor || + currentBlendStateDesc.dstAlphaBlendFactor != nextBlendStateDesc.dstAlphaBlendFactor) + { + if (nextBlendStateDesc.srcColorBlendFactor == nextBlendStateDesc.srcAlphaBlendFactor && + nextBlendStateDesc.dstColorBlendFactor == nextBlendStateDesc.dstAlphaBlendFactor) + { + glBlendFunc( + Mapping::FromBlendFactor(nextBlendStateDesc.srcColorBlendFactor), + Mapping::FromBlendFactor(nextBlendStateDesc.dstColorBlendFactor)); + } + else + { + glBlendFuncSeparate( + Mapping::FromBlendFactor(nextBlendStateDesc.srcColorBlendFactor), + Mapping::FromBlendFactor(nextBlendStateDesc.dstColorBlendFactor), + Mapping::FromBlendFactor(nextBlendStateDesc.srcAlphaBlendFactor), + Mapping::FromBlendFactor(nextBlendStateDesc.dstAlphaBlendFactor)); + } + } + + if (force || + currentBlendStateDesc.colorBlendOp != nextBlendStateDesc.colorBlendOp || + currentBlendStateDesc.alphaBlendOp != nextBlendStateDesc.alphaBlendOp) + { + if (nextBlendStateDesc.colorBlendOp == nextBlendStateDesc.alphaBlendOp) + { + glBlendEquation(Mapping::FromBlendOp(nextBlendStateDesc.colorBlendOp)); + } + else + { + glBlendEquationSeparate( + Mapping::FromBlendOp(nextBlendStateDesc.colorBlendOp), + Mapping::FromBlendOp(nextBlendStateDesc.alphaBlendOp)); + } + } + + if (force || + currentBlendStateDesc.constant != nextBlendStateDesc.constant) + { + glBlendColor( + nextBlendStateDesc.constant.r, + nextBlendStateDesc.constant.g, + nextBlendStateDesc.constant.b, + nextBlendStateDesc.constant.a); + } + + if (force || + currentBlendStateDesc.colorWriteMask != nextBlendStateDesc.colorWriteMask) + { + ApplyColorMask(nextBlendStateDesc.colorWriteMask); + } + + const RasterizationStateDesc& currentRasterizationStateDesc = + m_GraphicsPipelineStateDesc.rasterizationState; + const RasterizationStateDesc& nextRasterizationStateDesc = + pipelineStateDesc.rasterizationState; + if (force || + currentRasterizationStateDesc.polygonMode != nextRasterizationStateDesc.polygonMode) + { +#if !CONFIG2_GLES + glPolygonMode( + GL_FRONT_AND_BACK, + nextRasterizationStateDesc.polygonMode == PolygonMode::LINE ? GL_LINE : GL_FILL); +#endif + } + + if (force || + currentRasterizationStateDesc.cullMode != nextRasterizationStateDesc.cullMode) + { + if (nextRasterizationStateDesc.cullMode == CullMode::NONE) + { + glDisable(GL_CULL_FACE); + } + else + { + if (force || currentRasterizationStateDesc.cullMode == CullMode::NONE) + glEnable(GL_CULL_FACE); + glCullFace(nextRasterizationStateDesc.cullMode == CullMode::FRONT ? GL_FRONT : GL_BACK); + } + } + + if (force || + currentRasterizationStateDesc.frontFace != nextRasterizationStateDesc.frontFace) + { + if (nextRasterizationStateDesc.frontFace == FrontFace::CLOCKWISE) + glFrontFace(GL_CW); + else + glFrontFace(GL_CCW); + } + +#if !CONFIG2_GLES + if (force || + currentRasterizationStateDesc.depthBiasEnabled != nextRasterizationStateDesc.depthBiasEnabled) + { + if (nextRasterizationStateDesc.depthBiasEnabled) + glEnable(GL_POLYGON_OFFSET_FILL); + else + glDisable(GL_POLYGON_OFFSET_FILL); + } + if (force || + currentRasterizationStateDesc.depthBiasConstantFactor != nextRasterizationStateDesc.depthBiasConstantFactor || + currentRasterizationStateDesc.depthBiasSlopeFactor != nextRasterizationStateDesc.depthBiasSlopeFactor) + { + glPolygonOffset( + nextRasterizationStateDesc.depthBiasSlopeFactor, + nextRasterizationStateDesc.depthBiasConstantFactor); + } +#endif + + ogl_WarnIfError(); + + m_GraphicsPipelineStateDesc = pipelineStateDesc; +} + +void CDeviceCommandContext::BlitFramebuffer( + IFramebuffer* dstFramebuffer, IFramebuffer* srcFramebuffer) +{ + CFramebuffer* destinationFramebuffer = dstFramebuffer->As(); + CFramebuffer* sourceFramebuffer = srcFramebuffer->As(); +#if CONFIG2_GLES + UNUSED2(destinationFramebuffer); + UNUSED2(sourceFramebuffer); + debug_warn("CDeviceCommandContext::BlitFramebuffer is not implemented for GLES"); +#else + // Source framebuffer should not be backbuffer. + ENSURE(sourceFramebuffer->GetHandle() != 0); + ENSURE(destinationFramebuffer != sourceFramebuffer); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, sourceFramebuffer->GetHandle()); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, destinationFramebuffer->GetHandle()); + // TODO: add more check for internal formats. And currently we don't support + // scaling inside blit. + glBlitFramebufferEXT( + 0, 0, sourceFramebuffer->GetWidth(), sourceFramebuffer->GetHeight(), + 0, 0, sourceFramebuffer->GetWidth(), sourceFramebuffer->GetHeight(), + (sourceFramebuffer->GetAttachmentMask() & destinationFramebuffer->GetAttachmentMask()), + GL_NEAREST); + ogl_WarnIfError(); +#endif +} + +void CDeviceCommandContext::ClearFramebuffer() +{ + ClearFramebuffer(true, true, true); +} + +void CDeviceCommandContext::ClearFramebuffer(const bool color, const bool depth, const bool stencil) +{ + const bool needsColor = color && (m_Framebuffer->GetAttachmentMask() & GL_COLOR_BUFFER_BIT) != 0; + const bool needsDepth = depth && (m_Framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT) != 0; + const bool needsStencil = stencil && (m_Framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT) != 0; + GLbitfield mask = 0; + if (needsColor) + { + ApplyColorMask(ColorWriteMask::RED | ColorWriteMask::GREEN | ColorWriteMask::BLUE | ColorWriteMask::ALPHA); + glClearColor( + m_Framebuffer->GetClearColor().r, + m_Framebuffer->GetClearColor().g, + m_Framebuffer->GetClearColor().b, + m_Framebuffer->GetClearColor().a); + mask |= GL_COLOR_BUFFER_BIT; + } + if (needsDepth) + { + ApplyDepthMask(true); + mask |= GL_DEPTH_BUFFER_BIT; + } + if (needsStencil) + { + ApplyStencilMask(std::numeric_limits::max()); + mask |= GL_STENCIL_BUFFER_BIT; + } + glClear(mask); + ogl_WarnIfError(); + if (needsColor) + ApplyColorMask(m_GraphicsPipelineStateDesc.blendState.colorWriteMask); + if (needsDepth) + ApplyDepthMask(m_GraphicsPipelineStateDesc.depthStencilState.depthWriteEnabled); + if (needsStencil) + ApplyStencilMask(m_GraphicsPipelineStateDesc.depthStencilState.stencilWriteMask); +} + +void CDeviceCommandContext::SetFramebuffer(IFramebuffer* framebuffer) +{ + ENSURE(framebuffer); + m_Framebuffer = framebuffer->As(); + ENSURE(m_Framebuffer->GetHandle() == 0 || (m_Framebuffer->GetWidth() > 0 && m_Framebuffer->GetHeight() > 0)); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_Framebuffer->GetHandle()); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::ReadbackFramebufferSync( + const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, + void* data) +{ + ENSURE(m_Framebuffer); + glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const Rect* scissors) +{ + ENSURE(scissorCount <= 1); + if (scissorCount == 0) + { + if (m_ScissorCount != scissorCount) + glDisable(GL_SCISSOR_TEST); + } + else + { + if (m_ScissorCount != scissorCount) + glEnable(GL_SCISSOR_TEST); + ENSURE(scissors); + if (m_ScissorCount != scissorCount || m_Scissors[0] != scissors[0]) + { + m_Scissors[0] = scissors[0]; + glScissor(m_Scissors[0].x, m_Scissors[0].y, m_Scissors[0].width, m_Scissors[0].height); + } + } + ogl_WarnIfError(); + m_ScissorCount = scissorCount; +} + +void CDeviceCommandContext::SetViewports(const uint32_t viewportCount, const Rect* viewports) +{ + ENSURE(viewportCount == 1); + glViewport(viewports[0].x, viewports[0].y, viewports[0].width, viewports[0].height); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::SetVertexAttributeFormat( + const VertexAttributeStream stream, + const Format format, + const uint32_t offset, + const uint32_t stride, + const VertexAttributeRate rate, + const uint32_t bindingSlot) +{ + const uint32_t index = static_cast(stream); + ENSURE(index < m_VertexAttributeFormat.size()); + ENSURE(bindingSlot < m_VertexAttributeFormat.size()); + if (!m_VertexAttributeFormat[index].active) + return; + m_VertexAttributeFormat[index].format = format; + m_VertexAttributeFormat[index].offset = offset; + m_VertexAttributeFormat[index].stride = stride; + m_VertexAttributeFormat[index].rate = rate; + m_VertexAttributeFormat[index].bindingSlot = bindingSlot; + + m_VertexAttributeFormat[index].initialized = true; +} + +void CDeviceCommandContext::SetVertexBuffer( + const uint32_t bindingSlot, IBuffer* buffer) +{ + ENSURE(buffer); + ENSURE(buffer->GetType() == IBuffer::Type::VERTEX); + ENSURE(m_ShaderProgram); + BindBuffer(buffer->GetType(), buffer->As()); + for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) + { + if (!m_VertexAttributeFormat[index].active || m_VertexAttributeFormat[index].bindingSlot != bindingSlot) + continue; + ENSURE(m_VertexAttributeFormat[index].initialized); + const VertexAttributeStream stream = static_cast(index); + m_ShaderProgram->VertexAttribPointer(stream, + m_VertexAttributeFormat[index].format, + m_VertexAttributeFormat[index].offset, + m_VertexAttributeFormat[index].stride, + m_VertexAttributeFormat[index].rate, + nullptr); + } +} + +void CDeviceCommandContext::SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) +{ + ENSURE(data); + ENSURE(m_ShaderProgram); + ENSURE(dataSize > 0); + BindBuffer(CBuffer::Type::VERTEX, nullptr); + for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) + { + if (!m_VertexAttributeFormat[index].active || m_VertexAttributeFormat[index].bindingSlot != bindingSlot) + continue; + ENSURE(m_VertexAttributeFormat[index].initialized); + const VertexAttributeStream stream = static_cast(index); + // We don't know how many vertices will be used in a draw command, so we + // assume at least one vertex. + ENSURE(dataSize >= m_VertexAttributeFormat[index].offset + m_VertexAttributeFormat[index].stride); + m_ShaderProgram->VertexAttribPointer(stream, + m_VertexAttributeFormat[index].format, + m_VertexAttributeFormat[index].offset, + m_VertexAttributeFormat[index].stride, + m_VertexAttributeFormat[index].rate, + data); + } +} + +void CDeviceCommandContext::SetIndexBuffer(IBuffer* buffer) +{ + ENSURE(buffer->GetType() == CBuffer::Type::INDEX); + m_IndexBuffer = buffer->As(); + m_IndexBufferData = nullptr; + BindBuffer(CBuffer::Type::INDEX, m_IndexBuffer); +} + +void CDeviceCommandContext::SetIndexBufferData(const void* data, const uint32_t dataSize) +{ + ENSURE(dataSize > 0); + if (m_IndexBuffer) + { + BindBuffer(CBuffer::Type::INDEX, nullptr); + m_IndexBuffer = nullptr; + } + m_IndexBufferData = data; +} + +void CDeviceCommandContext::BeginPass() +{ + ENSURE(!m_InsidePass); + m_InsidePass = true; +} + +void CDeviceCommandContext::EndPass() +{ + ENSURE(m_InsidePass); + m_InsidePass = false; +} + +void CDeviceCommandContext::Draw( + const uint32_t firstVertex, const uint32_t vertexCount) +{ + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + // Some drivers apparently don't like count = 0 in glDrawArrays here, so skip + // all drawing in that case. + if (vertexCount == 0) + return; + m_ShaderProgram->AssertPointersBound(); + glDrawArrays(GL_TRIANGLES, firstVertex, vertexCount); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::DrawIndexed( + const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) +{ + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + if (indexCount == 0) + return; + ENSURE(m_IndexBuffer || m_IndexBufferData); + ENSURE(vertexOffset == 0); + if (m_IndexBuffer) + { + ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize()); + } + m_ShaderProgram->AssertPointersBound(); + // Don't use glMultiDrawElements here since it doesn't have a significant + // performance impact and it suffers from various driver bugs (e.g. it breaks + // in Mesa 7.10 swrast with index VBOs). + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, + static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex))); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) +{ + ENSURE(m_Device->GetCapabilities().instancing); + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + if (vertexCount == 0 || instanceCount == 0) + return; + ENSURE(firstInstance == 0); + m_ShaderProgram->AssertPointersBound(); +#if CONFIG2_GLES + ENSURE(!m_Device->GetCapabilities().instancing); + UNUSED2(firstVertex); + UNUSED2(vertexCount); + UNUSED2(instanceCount); +#else + glDrawArraysInstancedARB(GL_TRIANGLES, firstVertex, vertexCount, instanceCount); +#endif + ogl_WarnIfError(); +} + +void CDeviceCommandContext::DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) +{ + ENSURE(m_Device->GetCapabilities().instancing); + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + ENSURE(m_IndexBuffer || m_IndexBufferData); + if (indexCount == 0) + return; + ENSURE(firstInstance == 0 && vertexOffset == 0); + if (m_IndexBuffer) + { + ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize()); + } + m_ShaderProgram->AssertPointersBound(); + // Don't use glMultiDrawElements here since it doesn't have a significant + // performance impact and it suffers from various driver bugs (e.g. it breaks + // in Mesa 7.10 swrast with index VBOs). +#if CONFIG2_GLES + ENSURE(!m_Device->GetCapabilities().instancing); + UNUSED2(indexCount); + UNUSED2(firstIndex); + UNUSED2(instanceCount); +#else + glDrawElementsInstancedARB(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, + static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)), + instanceCount); +#endif + ogl_WarnIfError(); +} + +void CDeviceCommandContext::DrawIndexedInRange( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t start, const uint32_t end) +{ + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + if (indexCount == 0) + return; + ENSURE(m_IndexBuffer || m_IndexBufferData); + const void* indices = + static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)); + m_ShaderProgram->AssertPointersBound(); + // Draw with DrawRangeElements where available, since it might be more + // efficient for slow hardware. +#if CONFIG2_GLES + UNUSED2(start); + UNUSED2(end); + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices); +#else + glDrawRangeElementsEXT(GL_TRIANGLES, start, end, indexCount, GL_UNSIGNED_SHORT, indices); +#endif + ogl_WarnIfError(); +} + +void CDeviceCommandContext::SetTexture(const int32_t bindingSlot, ITexture* texture) +{ + ENSURE(m_ShaderProgram); + ENSURE(texture); + const CShaderProgram::TextureUnit textureUnit = + m_ShaderProgram->GetTextureUnit(bindingSlot); + if (!textureUnit.type) + return; + + if (textureUnit.type != GL_SAMPLER_2D && +#if !CONFIG2_GLES + textureUnit.type != GL_SAMPLER_2D_SHADOW && +#endif + textureUnit.type != GL_SAMPLER_CUBE) + { + LOGERROR("CDeviceCommandContext::SetTexture: expected sampler at binding slot"); + return; + } + +#if !CONFIG2_GLES + if (textureUnit.type == GL_SAMPLER_2D_SHADOW) + { + if (!IsDepthTexture(texture->GetFormat())) + { + LOGERROR("CDeviceCommandContext::SetTexture: Invalid texture type (expected depth texture)"); + return; + } + } +#endif + + ENSURE(textureUnit.unit >= 0); + const uint32_t unit = textureUnit.unit; + if (unit >= m_BoundTextures.size()) + { + LOGERROR("CDeviceCommandContext::SetTexture: Invalid texture unit (too big)"); + return; + } + BindTexture(unit, textureUnit.target, texture->As()->GetHandle()); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float value) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, value); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ, valueW); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, PS::span values) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, values); +} + +CDeviceCommandContext::ScopedBind::ScopedBind( + CDeviceCommandContext* deviceCommandContext, + const GLenum target, const GLuint handle) + : m_DeviceCommandContext(deviceCommandContext), + m_OldBindUnit(deviceCommandContext->m_BoundTextures[deviceCommandContext->m_ActiveTextureUnit]), + m_ActiveTextureUnit(deviceCommandContext->m_ActiveTextureUnit) +{ + const uint32_t unit = m_DeviceCommandContext->m_BoundTextures.size() - 1; + m_DeviceCommandContext->BindTexture(unit, target, handle); +} + +CDeviceCommandContext::ScopedBind::~ScopedBind() +{ + m_DeviceCommandContext->BindTexture( + m_ActiveTextureUnit, m_OldBindUnit.target, m_OldBindUnit.handle); +} + +CDeviceCommandContext::ScopedBufferBind::ScopedBufferBind( + CDeviceCommandContext* deviceCommandContext, CBuffer* buffer) + : m_DeviceCommandContext(deviceCommandContext) +{ + ENSURE(buffer); + m_CacheIndex = static_cast(buffer->GetType()); + const GLenum target = BufferTypeToGLTarget(buffer->GetType()); + const GLuint handle = buffer->GetHandle(); + if (m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].first == target && + m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].second == handle) + { + // Use an invalid index as a sign that we don't need to restore the + // bound buffer. + m_CacheIndex = m_DeviceCommandContext->m_BoundBuffers.size(); + } + else + { + glBindBufferARB(target, handle); + } +} + +CDeviceCommandContext::ScopedBufferBind::~ScopedBufferBind() +{ + if (m_CacheIndex >= m_DeviceCommandContext->m_BoundBuffers.size()) + return; + glBindBufferARB( + m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].first, + m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].second); +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/DeviceCommandContext.h 0ad-0.0.26/source/renderer/backend/gl/DeviceCommandContext.h --- 0ad-0.0.25b/source/renderer/backend/gl/DeviceCommandContext.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/DeviceCommandContext.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,235 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_GL_DEVICECOMMANDCONTEXT +#define INCLUDED_RENDERER_GL_DEVICECOMMANDCONTEXT + +#include "lib/ogl.h" +#include "ps/containers/Span.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/gl/Buffer.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/PipelineState.h" + +#include +#include +#include +#include +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; +class CFramebuffer; +class CShaderProgram; +class CTexture; + +class CDeviceCommandContext final : public IDeviceCommandContext +{ +public: + ~CDeviceCommandContext(); + + IDevice* GetDevice() override; + + void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) override; + + void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override; + + void ClearFramebuffer() override; + void ClearFramebuffer(const bool color, const bool depth, const bool stencil) override; + void SetFramebuffer(IFramebuffer* framebuffer) override; + void ReadbackFramebufferSync( + const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, + void* data) override; + + void UploadTexture(ITexture* texture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t level = 0, const uint32_t layer = 0) override; + void UploadTextureRegion(ITexture* texture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t xOffset, const uint32_t yOffset, + const uint32_t width, const uint32_t height, + const uint32_t level = 0, const uint32_t layer = 0) override; + + using UploadBufferFunction = std::function; + void UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize) override; + void UploadBuffer(IBuffer* buffer, const UploadBufferFunction& uploadFunction) override; + void UploadBufferRegion( + IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize) override; + void UploadBufferRegion( + IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize, + const UploadBufferFunction& uploadFunction) override; + + void SetScissors(const uint32_t scissorCount, const Rect* scissors) override; + void SetViewports(const uint32_t viewportCount, const Rect* viewports) override; + + void SetVertexAttributeFormat( + const VertexAttributeStream stream, + const Format format, + const uint32_t offset, + const uint32_t stride, + const VertexAttributeRate rate, + const uint32_t bindingSlot) override; + void SetVertexBuffer(const uint32_t bindingSlot, IBuffer* buffer) override; + void SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) override; + + void SetIndexBuffer(IBuffer* buffer) override; + void SetIndexBufferData(const void* data, const uint32_t dataSize) override; + + void BeginPass() override; + void EndPass() override; + + void Draw(const uint32_t firstVertex, const uint32_t vertexCount) override; + void DrawIndexed( + const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) override; + void DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) override; + void DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) override; + void DrawIndexedInRange( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t start, const uint32_t end) override; + + void SetTexture(const int32_t bindingSlot, ITexture* texture) override; + + void SetUniform( + const int32_t bindingSlot, + const float value) override; + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) override; + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) override; + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) override; + void SetUniform( + const int32_t bindingSlot, PS::span values) override; + + void BeginScopedLabel(const char* name) override; + void EndScopedLabel() override; + + void Flush() override; + + // We need to know when to invalidate our texture bind cache. + void OnTextureDestroy(CTexture* texture); + +private: + friend class CDevice; + friend class CTexture; + + static std::unique_ptr Create(CDevice* device); + + CDeviceCommandContext(CDevice* device); + + void ResetStates(); + + void SetGraphicsPipelineStateImpl( + const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force); + + void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle); + void BindBuffer(const IBuffer::Type type, CBuffer* buffer); + + CDevice* m_Device = nullptr; + + GraphicsPipelineStateDesc m_GraphicsPipelineStateDesc{}; + CFramebuffer* m_Framebuffer = nullptr; + CShaderProgram* m_ShaderProgram = nullptr; + uint32_t m_ScissorCount = 0; + // GL2.1 doesn't support more than 1 scissor. + std::array m_Scissors; + + uint32_t m_ScopedLabelDepth = 0; + + CBuffer* m_VertexBuffer = nullptr; + CBuffer* m_IndexBuffer = nullptr; + const void* m_IndexBufferData = nullptr; + + bool m_InsidePass = false; + + uint32_t m_ActiveTextureUnit = 0; + struct BindUnit + { + GLenum target; + GLuint handle; + }; + std::array m_BoundTextures; + class ScopedBind + { + public: + ScopedBind(CDeviceCommandContext* deviceCommandContext, + const GLenum target, const GLuint handle); + + ~ScopedBind(); + private: + CDeviceCommandContext* m_DeviceCommandContext = nullptr; + BindUnit m_OldBindUnit; + uint32_t m_ActiveTextureUnit = 0; + }; + + using BoundBuffer = std::pair; + std::array m_BoundBuffers; + class ScopedBufferBind + { + public: + ScopedBufferBind( + CDeviceCommandContext* deviceCommandContext, CBuffer* buffer); + + ~ScopedBufferBind(); + private: + CDeviceCommandContext* m_DeviceCommandContext = nullptr; + size_t m_CacheIndex = 0; + }; + + struct VertexAttributeFormat + { + Format format; + uint32_t offset; + uint32_t stride; + VertexAttributeRate rate; + uint32_t bindingSlot; + + bool active; + bool initialized; + }; + std::array< + VertexAttributeFormat, + static_cast(VertexAttributeStream::UV7) + 1> m_VertexAttributeFormat; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_GL_DEVICECOMMANDCONTEXT diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Device.cpp 0ad-0.0.26/source/renderer/backend/gl/Device.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/Device.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Device.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -0,0 +1,999 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Device.h" + +#include "lib/external_libraries/libsdl.h" +#include "lib/ogl.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "ps/Profile.h" +#include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/Texture.h" +#include "scriptinterface/JSON.h" +#include "scriptinterface/Object.h" +#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/ScriptRequest.h" + +#if OS_WIN +#include "lib/sysdep/os/win/wgfx.h" + +// We can't include wutil directly because GL headers conflict with Windows +// until we use a proper GL loader. +extern void* wutil_GetAppHDC(); +#endif + +#include +#include +#include + +#if !CONFIG2_GLES && (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND)) + +#if defined(SDL_VIDEO_DRIVER_X11) +#include +#endif +#if defined(SDL_VIDEO_DRIVER_WAYLAND) +#include +#endif +#include + +#endif // !CONFIG2_GLES && (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND)) + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace +{ + +std::string GetNameImpl() +{ + // GL_VENDOR+GL_RENDERER are good enough here, so we don't use WMI to detect the cards. + // On top of that WMI can cause crashes with Nvidia Optimus and some netbooks + // see http://trac.wildfiregames.com/ticket/1952 + // http://trac.wildfiregames.com/ticket/1575 + char cardName[128]; + const char* vendor = reinterpret_cast(glGetString(GL_VENDOR)); + const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); + // Happens if called before GL initialization. + if (!vendor || !renderer) + return {}; + sprintf_s(cardName, std::size(cardName), "%s %s", vendor, renderer); + + // Remove crap from vendor names. (don't dare touch the model name - + // it's too risky, there are too many different strings). +#define SHORTEN(what, charsToKeep) \ + if (!strncmp(cardName, what, std::size(what) - 1)) \ + memmove(cardName + charsToKeep, cardName + std::size(what) - 1, (strlen(cardName) - (std::size(what) - 1) + 1) * sizeof(char)); + SHORTEN("ATI Technologies Inc.", 3); + SHORTEN("NVIDIA Corporation", 6); + SHORTEN("S3 Graphics", 2); // returned by EnumDisplayDevices + SHORTEN("S3 Graphics, Incorporated", 2); // returned by GL_VENDOR +#undef SHORTEN + + return cardName; +} + +std::string GetVersionImpl() +{ + return reinterpret_cast(glGetString(GL_VERSION)); +} + +std::string GetDriverInformationImpl() +{ + const std::string version = GetVersionImpl(); + + std::string driverInfo; +#if OS_WIN + driverInfo = CStrW(wgfx_DriverInfo()).ToUTF8(); + if (driverInfo.empty()) +#endif + { + if (!version.empty()) + { + // Add "OpenGL" to differentiate this from the real driver version + // (returned by platform-specific detect routines). + driverInfo = std::string("OpenGL ") + version; + } + } + + if (driverInfo.empty()) + return version; + return version + " " + driverInfo; +} + +std::vector GetExtensionsImpl() +{ + std::vector extensions; + const std::string exts = ogl_ExtensionString(); + boost::split(extensions, exts, boost::algorithm::is_space(), boost::token_compress_on); + std::sort(extensions.begin(), extensions.end()); + return extensions; +} + +void GLAD_API_PTR OnDebugMessage( + GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei UNUSED(length), const GLchar* message, const void* UNUSED(user_param)) +{ + std::string debugSource = "unknown"; + std::string debugType = "unknown"; + std::string debugSeverity = "unknown"; + + switch (source) + { + case GL_DEBUG_SOURCE_API: + debugSource = "the API"; + break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + debugSource = "the window system"; + break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + debugSource = "the shader compiler"; + break; + case GL_DEBUG_SOURCE_THIRD_PARTY: + debugSource = "a third party"; + break; + case GL_DEBUG_SOURCE_APPLICATION: + debugSource = "the application"; + break; + case GL_DEBUG_SOURCE_OTHER: + debugSource = "somewhere"; + break; + } + + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + debugType = "error"; + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + debugType = "deprecated behaviour"; + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + debugType = "undefined behaviour"; + break; + case GL_DEBUG_TYPE_PORTABILITY: + debugType = "portability"; + break; + case GL_DEBUG_TYPE_PERFORMANCE: + debugType = "performance"; + break; + case GL_DEBUG_TYPE_OTHER: + debugType = "other"; + break; + case GL_DEBUG_TYPE_MARKER: + debugType = "marker"; + break; + case GL_DEBUG_TYPE_PUSH_GROUP: + debugType = "push group"; + break; + case GL_DEBUG_TYPE_POP_GROUP: + debugType = "pop group"; + break; + } + + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + debugSeverity = "high"; + break; + case GL_DEBUG_SEVERITY_MEDIUM: + debugSeverity = "medium"; + break; + case GL_DEBUG_SEVERITY_LOW: + debugSeverity = "low"; + break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + debugSeverity = "notification"; + break; + } + + if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) + { + debug_printf( + "OpenGL | %s: %s source: %s id %u: %s\n", debugSeverity.c_str(), debugType.c_str(), debugSource.c_str(), id, message); + } + else + { + LOGWARNING( + "OpenGL | %s: %s source: %s id %u: %s\n", debugSeverity.c_str(), debugType.c_str(), debugSource.c_str(), id, message); + } +} + +} // anonymous namespace + +// static +std::unique_ptr CDevice::Create(SDL_Window* window, const bool arb) +{ + std::unique_ptr device(new CDevice()); + + if (window) + { + // According to https://wiki.libsdl.org/SDL_CreateWindow we don't need to + // call SDL_GL_LoadLibrary if we have a window with SDL_WINDOW_OPENGL, + // because it'll be called internally for the first created window. + device->m_Window = window; + device->m_Context = SDL_GL_CreateContext(device->m_Window); + if (!device->m_Context) + { + LOGERROR("SDL_GL_CreateContext failed: '%s'", SDL_GetError()); + return nullptr; + } +#if OS_WIN + ogl_Init(SDL_GL_GetProcAddress, wutil_GetAppHDC()); +#elif (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND)) && !CONFIG2_GLES + SDL_SysWMinfo wminfo; + // The info structure must be initialized with the SDL version. + SDL_VERSION(&wminfo.version); + if (!SDL_GetWindowWMInfo(window, &wminfo)) + { + LOGERROR("Failed to query SDL WM info: %s", SDL_GetError()); + return nullptr; + } + switch (wminfo.subsystem) + { +#if defined(SDL_VIDEO_DRIVER_WAYLAND) + case SDL_SYSWM_WAYLAND: + // TODO: maybe we need to load X11 functions + // dynamically as well. + ogl_Init(SDL_GL_GetProcAddress, + GetWaylandDisplay(device->m_Window), + static_cast(wminfo.subsystem)); + break; +#endif +#if defined(SDL_VIDEO_DRIVER_X11) + case SDL_SYSWM_X11: + ogl_Init(SDL_GL_GetProcAddress, + GetX11Display(device->m_Window), + static_cast(wminfo.subsystem)); + break; +#endif + default: + ogl_Init(SDL_GL_GetProcAddress, nullptr, + static_cast(wminfo.subsystem)); + break; + } +#else + ogl_Init(SDL_GL_GetProcAddress); +#endif + } + else + { +#if OS_WIN + ogl_Init(SDL_GL_GetProcAddress, wutil_GetAppHDC()); +#elif (defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND)) && !CONFIG2_GLES + bool initialized = false; + // Currently we don't have access to the backend type without + // the window. So we use hack to detect X11. +#if defined(SDL_VIDEO_DRIVER_X11) + Display* display = XOpenDisplay(NULL); + if (display) + { + ogl_Init(SDL_GL_GetProcAddress, display, static_cast(SDL_SYSWM_X11)); + initialized = true; + } +#endif +#if defined(SDL_VIDEO_DRIVER_WAYLAND) + if (!initialized) + { + // glad will find default EGLDisplay internally. + ogl_Init(SDL_GL_GetProcAddress, nullptr, static_cast(SDL_SYSWM_WAYLAND)); + initialized = true; + } +#endif + if (!initialized) + { + LOGERROR("Can't initialize GL"); + return nullptr; + } +#else + ogl_Init(SDL_GL_GetProcAddress); +#endif + +#if OS_WIN || defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES + // Hack to stop things looking very ugly when scrolling in Atlas. + ogl_SetVsyncEnabled(true); +#endif + } + + // If we don't have GL2.0 then we don't have GLSL in core. + if (!arb && !ogl_HaveVersion(2, 0)) + return nullptr; + + if ((ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr) // ARB + && !ogl_HaveVersion(2, 0)) // GLSL + || !ogl_HaveExtension("GL_ARB_vertex_buffer_object") // VBO + || ogl_HaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", nullptr) + || (!ogl_HaveExtension("GL_EXT_framebuffer_object") && !ogl_HaveExtension("GL_ARB_framebuffer_object"))) + { + // 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" 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" + ); + } + + device->m_ARB = arb; + + device->m_Name = GetNameImpl(); + device->m_Version = GetVersionImpl(); + device->m_DriverInformation = GetDriverInformationImpl(); + device->m_Extensions = GetExtensionsImpl(); + + // Set packing parameters for uploading and downloading data. + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glEnable(GL_TEXTURE_2D); + + if (arb) + { +#if !CONFIG2_GLES + glEnable(GL_VERTEX_PROGRAM_ARB); + glEnable(GL_FRAGMENT_PROGRAM_ARB); +#endif + } + + device->m_Backbuffer = CFramebuffer::CreateBackbuffer(device.get()); + + Capabilities& capabilities = device->m_Capabilities; + capabilities.ARBShaders = !ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr); + if (capabilities.ARBShaders) + capabilities.ARBShadersShadow = ogl_HaveExtension("GL_ARB_fragment_program_shadow"); + capabilities.computeShaders = ogl_HaveVersion(4, 3) || ogl_HaveExtension("GL_ARB_compute_shader"); +#if CONFIG2_GLES + // Some GLES implementations have GL_EXT_texture_compression_dxt1 + // but that only supports DXT1 so we can't use it. + capabilities.S3TC = ogl_HaveExtensions(0, "GL_EXT_texture_compression_s3tc", nullptr) == 0; +#else + // Note: we don't bother checking for GL_S3_s3tc - it is incompatible + // and irrelevant (was never widespread). + capabilities.S3TC = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", nullptr) == 0; +#endif +#if CONFIG2_GLES + capabilities.multisampling = false; + capabilities.maxSampleCount = 1; +#else + capabilities.multisampling = + ogl_HaveVersion(3, 3) && + ogl_HaveExtension("GL_ARB_multisample") && + ogl_HaveExtension("GL_ARB_texture_multisample"); + if (capabilities.multisampling) + { + // By default GL_MULTISAMPLE should be enabled, but enable it for buggy drivers. + glEnable(GL_MULTISAMPLE); + GLint maxSamples = 1; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + capabilities.maxSampleCount = maxSamples; + } +#endif + capabilities.anisotropicFiltering = ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"); + if (capabilities.anisotropicFiltering) + { + GLfloat maxAnisotropy = 1.0f; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); + capabilities.maxAnisotropy = maxAnisotropy; + } + GLint maxTextureSize = 1024; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + capabilities.maxTextureSize = maxTextureSize; + +#if CONFIG2_GLES + const bool isDebugInCore = ogl_HaveVersion(3, 2); +#else + const bool isDebugInCore = ogl_HaveVersion(4, 3); +#endif + const bool hasDebug = isDebugInCore || ogl_HaveExtension("GL_KHR_debug"); + if (hasDebug) + { +#ifdef NDEBUG + bool enableDebugMessages = false; + CFG_GET_VAL("renderer.backend.debugmessages", enableDebugMessages); + capabilities.debugLabels = false; + CFG_GET_VAL("renderer.backend.debuglabels", capabilities.debugLabels); + capabilities.debugScopedLabels = false; + CFG_GET_VAL("renderer.backend.debugscopedlabels", capabilities.debugScopedLabels); +#else + const bool enableDebugMessages = true; + capabilities.debugLabels = true; + capabilities.debugScopedLabels = true; +#endif + if (enableDebugMessages) + { + glEnable(GL_DEBUG_OUTPUT); +#if !CONFIG2_GLES + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); +#else +#warning GLES without GL_DEBUG_OUTPUT_SYNCHRONOUS might call the callback from different threads which might be unsafe. +#endif + glDebugMessageCallback(OnDebugMessage, nullptr); + + // Filter out our own debug group messages + const GLuint id = 0x0AD; + glDebugMessageControl( + GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, GL_DONT_CARE, 1, &id, GL_FALSE); + glDebugMessageControl( + GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, GL_DONT_CARE, 1, &id, GL_FALSE); + } + } + +#if CONFIG2_GLES + capabilities.instancing = false; +#else + capabilities.instancing = + !device->m_ARB && + (ogl_HaveVersion(3, 3) || + (ogl_HaveExtension("GL_ARB_draw_instanced") && + ogl_HaveExtension("GL_ARB_instanced_arrays"))); +#endif + + return device; +} + +CDevice::CDevice() = default; + +CDevice::~CDevice() +{ + if (m_Context) + SDL_GL_DeleteContext(m_Context); +} + +void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings) +{ + const char* errstr = "(error)"; + + Script::SetProperty(rq, settings, "name", m_ARB ? "glarb" : "gl"); + +#define INTEGER(id) do { \ + GLint i = -1; \ + glGetIntegerv(GL_##id, &i); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) \ + Script::SetProperty(rq, settings, "GL_" #id, errstr); \ + else \ + Script::SetProperty(rq, settings, "GL_" #id, i); \ + } while (false) + +#define INTEGER2(id) do { \ + GLint i[2] = { -1, -1 }; \ + glGetIntegerv(GL_##id, i); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) { \ + Script::SetProperty(rq, settings, "GL_" #id "[0]", errstr); \ + Script::SetProperty(rq, settings, "GL_" #id "[1]", errstr); \ + } else { \ + Script::SetProperty(rq, settings, "GL_" #id "[0]", i[0]); \ + Script::SetProperty(rq, settings, "GL_" #id "[1]", i[1]); \ + } \ + } while (false) + +#define FLOAT(id) do { \ + GLfloat f = std::numeric_limits::quiet_NaN(); \ + glGetFloatv(GL_##id, &f); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) \ + Script::SetProperty(rq, settings, "GL_" #id, errstr); \ + else \ + Script::SetProperty(rq, settings, "GL_" #id, f); \ + } while (false) + +#define FLOAT2(id) do { \ + GLfloat f[2] = { std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN() }; \ + glGetFloatv(GL_##id, f); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) { \ + Script::SetProperty(rq, settings, "GL_" #id "[0]", errstr); \ + Script::SetProperty(rq, settings, "GL_" #id "[1]", errstr); \ + } else { \ + Script::SetProperty(rq, settings, "GL_" #id "[0]", f[0]); \ + Script::SetProperty(rq, settings, "GL_" #id "[1]", f[1]); \ + } \ + } while (false) + +#define STRING(id) do { \ + const char* c = (const char*)glGetString(GL_##id); \ + if (!c) c = ""; \ + if (ogl_SquelchError(GL_INVALID_ENUM)) c = errstr; \ + Script::SetProperty(rq, settings, "GL_" #id, std::string(c)); \ + } while (false) + +#define QUERY(target, pname) do { \ + GLint i = -1; \ + glGetQueryivARB(GL_##target, GL_##pname, &i); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) \ + Script::SetProperty(rq, settings, "GL_" #target ".GL_" #pname, errstr); \ + else \ + Script::SetProperty(rq, settings, "GL_" #target ".GL_" #pname, i); \ + } while (false) + +#define VERTEXPROGRAM(id) do { \ + GLint i = -1; \ + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_##id, &i); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) \ + Script::SetProperty(rq, settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, errstr); \ + else \ + Script::SetProperty(rq, settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, i); \ + } while (false) + +#define FRAGMENTPROGRAM(id) do { \ + GLint i = -1; \ + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_##id, &i); \ + if (ogl_SquelchError(GL_INVALID_ENUM)) \ + Script::SetProperty(rq, settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, errstr); \ + else \ + Script::SetProperty(rq, settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, i); \ + } while (false) + +#define BOOL(id) INTEGER(id) + + ogl_WarnIfError(); + + // Core OpenGL 1.3: + // (We don't bother checking extension strings for anything older than 1.3; + // it'll just produce harmless warnings) + STRING(VERSION); + STRING(VENDOR); + STRING(RENDERER); + STRING(EXTENSIONS); + +#if !CONFIG2_GLES + INTEGER(MAX_CLIP_PLANES); +#endif + INTEGER(SUBPIXEL_BITS); +#if !CONFIG2_GLES + INTEGER(MAX_3D_TEXTURE_SIZE); +#endif + INTEGER(MAX_TEXTURE_SIZE); + INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE); + INTEGER2(MAX_VIEWPORT_DIMS); + +#if !CONFIG2_GLES + BOOL(RGBA_MODE); + BOOL(INDEX_MODE); + BOOL(DOUBLEBUFFER); + BOOL(STEREO); +#endif + + FLOAT2(ALIASED_POINT_SIZE_RANGE); + FLOAT2(ALIASED_LINE_WIDTH_RANGE); +#if !CONFIG2_GLES + INTEGER(MAX_ELEMENTS_INDICES); + INTEGER(MAX_ELEMENTS_VERTICES); + INTEGER(MAX_TEXTURE_UNITS); +#endif + INTEGER(SAMPLE_BUFFERS); + INTEGER(SAMPLES); + // TODO: compressed texture formats + INTEGER(RED_BITS); + INTEGER(GREEN_BITS); + INTEGER(BLUE_BITS); + INTEGER(ALPHA_BITS); +#if !CONFIG2_GLES + INTEGER(INDEX_BITS); +#endif + INTEGER(DEPTH_BITS); + INTEGER(STENCIL_BITS); + +#if !CONFIG2_GLES + + // Core OpenGL 2.0 (treated as extensions): + + if (ogl_HaveExtension("GL_EXT_texture_lod_bias")) + { + FLOAT(MAX_TEXTURE_LOD_BIAS_EXT); + } + + if (ogl_HaveExtension("GL_ARB_occlusion_query")) + { + QUERY(SAMPLES_PASSED, QUERY_COUNTER_BITS); + } + + if (ogl_HaveExtension("GL_ARB_shading_language_100")) + { + STRING(SHADING_LANGUAGE_VERSION_ARB); + } + + if (ogl_HaveExtension("GL_ARB_vertex_shader")) + { + INTEGER(MAX_VERTEX_ATTRIBS_ARB); + INTEGER(MAX_VERTEX_UNIFORM_COMPONENTS_ARB); + INTEGER(MAX_VARYING_FLOATS_ARB); + INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB); + INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB); + } + + if (ogl_HaveExtension("GL_ARB_fragment_shader")) + { + INTEGER(MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB); + } + + if (ogl_HaveExtension("GL_ARB_vertex_shader") || ogl_HaveExtension("GL_ARB_fragment_shader") || + ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program")) + { + INTEGER(MAX_TEXTURE_IMAGE_UNITS_ARB); + INTEGER(MAX_TEXTURE_COORDS_ARB); + } + + if (ogl_HaveExtension("GL_ARB_draw_buffers")) + { + INTEGER(MAX_DRAW_BUFFERS_ARB); + } + + // Core OpenGL 3.0: + + if (ogl_HaveExtension("GL_EXT_gpu_shader4")) + { + INTEGER(MIN_PROGRAM_TEXEL_OFFSET_EXT); // no _EXT version of these in glext.h + INTEGER(MAX_PROGRAM_TEXEL_OFFSET_EXT); + } + + if (ogl_HaveExtension("GL_EXT_framebuffer_object")) + { + INTEGER(MAX_COLOR_ATTACHMENTS_EXT); + INTEGER(MAX_RENDERBUFFER_SIZE_EXT); + } + + if (ogl_HaveExtension("GL_EXT_framebuffer_multisample")) + { + INTEGER(MAX_SAMPLES_EXT); + } + + if (ogl_HaveExtension("GL_EXT_texture_array")) + { + INTEGER(MAX_ARRAY_TEXTURE_LAYERS_EXT); + } + + if (ogl_HaveExtension("GL_EXT_transform_feedback")) + { + INTEGER(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT); + INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT); + INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT); + } + + + // Other interesting extensions: + + if (ogl_HaveExtension("GL_EXT_timer_query") || ogl_HaveExtension("GL_ARB_timer_query")) + { + QUERY(TIME_ELAPSED, QUERY_COUNTER_BITS); + } + + if (ogl_HaveExtension("GL_ARB_timer_query")) + { + QUERY(TIMESTAMP, QUERY_COUNTER_BITS); + } + + if (ogl_HaveExtension("GL_EXT_texture_filter_anisotropic")) + { + FLOAT(MAX_TEXTURE_MAX_ANISOTROPY_EXT); + } + + if (ogl_HaveExtension("GL_ARB_texture_rectangle")) + { + INTEGER(MAX_RECTANGLE_TEXTURE_SIZE_ARB); + } + + if (m_ARB) + { + if (ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program")) + { + INTEGER(MAX_PROGRAM_MATRICES_ARB); + INTEGER(MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB); + } + + if (ogl_HaveExtension("GL_ARB_vertex_program")) + { + VERTEXPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB); + VERTEXPROGRAM(MAX_PROGRAM_PARAMETERS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_ATTRIBS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB); + + if (ogl_HaveExtension("GL_ARB_fragment_program")) + { + // The spec seems to say these should be supported, but + // Mesa complains about them so let's not bother + /* + VERTEXPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB); + VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB); + */ + } + } + + if (ogl_HaveExtension("GL_ARB_fragment_program")) + { + FRAGMENTPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_PARAMETERS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_ATTRIBS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB); + + if (ogl_HaveExtension("GL_ARB_vertex_program")) + { + // The spec seems to say these should be supported, but + // Intel drivers on Windows complain about them so let's not bother + /* + FRAGMENTPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB); + FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB); + */ + } + } + } + + if (ogl_HaveExtension("GL_ARB_geometry_shader4")) + { + INTEGER(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB); + INTEGER(MAX_GEOMETRY_OUTPUT_VERTICES_ARB); + INTEGER(MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB); + INTEGER(MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB); + INTEGER(MAX_GEOMETRY_VARYING_COMPONENTS_ARB); + INTEGER(MAX_VERTEX_VARYING_COMPONENTS_ARB); + } + +#else // CONFIG2_GLES + + // Core OpenGL ES 2.0: + + STRING(SHADING_LANGUAGE_VERSION); + INTEGER(MAX_VERTEX_ATTRIBS); + INTEGER(MAX_VERTEX_UNIFORM_VECTORS); + INTEGER(MAX_VARYING_VECTORS); + INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS); + INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS); + INTEGER(MAX_FRAGMENT_UNIFORM_VECTORS); + INTEGER(MAX_TEXTURE_IMAGE_UNITS); + INTEGER(MAX_RENDERBUFFER_SIZE); + +#endif // CONFIG2_GLES + + +// TODO: Support OpenGL platforms which don't use GLX as well. +#if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES + +#define GLXQCR_INTEGER(id) do { \ + unsigned int i = UINT_MAX; \ + if (glXQueryCurrentRendererIntegerMESA(id, &i)) \ + Script::SetProperty(rq, settings, #id, i); \ + } while (false) + +#define GLXQCR_INTEGER2(id) do { \ + unsigned int i[2] = { UINT_MAX, UINT_MAX }; \ + if (glXQueryCurrentRendererIntegerMESA(id, i)) { \ + Script::SetProperty(rq, settings, #id "[0]", i[0]); \ + Script::SetProperty(rq, settings, #id "[1]", i[1]); \ + } \ + } while (false) + +#define GLXQCR_INTEGER3(id) do { \ + unsigned int i[3] = { UINT_MAX, UINT_MAX, UINT_MAX }; \ + if (glXQueryCurrentRendererIntegerMESA(id, i)) { \ + Script::SetProperty(rq, settings, #id "[0]", i[0]); \ + Script::SetProperty(rq, settings, #id "[1]", i[1]); \ + Script::SetProperty(rq, settings, #id "[2]", i[2]); \ + } \ + } while (false) + +#define GLXQCR_STRING(id) do { \ + const char* str = glXQueryCurrentRendererStringMESA(id); \ + if (str) \ + Script::SetProperty(rq, settings, #id ".string", str); \ + } while (false) + + + SDL_SysWMinfo wminfo; + SDL_VERSION(&wminfo.version); + const int ret = SDL_GetWindowWMInfo(m_Window, &wminfo); + if (ret && wminfo.subsystem == SDL_SYSWM_X11) + { + Display* dpy = wminfo.info.x11.display; + int scrnum = DefaultScreen(dpy); + + const char* glxexts = glXQueryExtensionsString(dpy, scrnum); + + Script::SetProperty(rq, settings, "glx_extensions", glxexts); + + if (strstr(glxexts, "GLX_MESA_query_renderer") && glXQueryCurrentRendererIntegerMESA && glXQueryCurrentRendererStringMESA) + { + GLXQCR_INTEGER(GLX_RENDERER_VENDOR_ID_MESA); + GLXQCR_INTEGER(GLX_RENDERER_DEVICE_ID_MESA); + GLXQCR_INTEGER3(GLX_RENDERER_VERSION_MESA); + GLXQCR_INTEGER(GLX_RENDERER_ACCELERATED_MESA); + GLXQCR_INTEGER(GLX_RENDERER_VIDEO_MEMORY_MESA); + GLXQCR_INTEGER(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA); + GLXQCR_INTEGER(GLX_RENDERER_PREFERRED_PROFILE_MESA); + GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA); + GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA); + GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA); + GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA); + GLXQCR_STRING(GLX_RENDERER_VENDOR_ID_MESA); + GLXQCR_STRING(GLX_RENDERER_DEVICE_ID_MESA); + } + } +#endif // SDL_VIDEO_DRIVER_X11 +} + +std::unique_ptr CDevice::CreateCommandContext() +{ + std::unique_ptr commandContet = CDeviceCommandContext::Create(this); + m_ActiveCommandContext = commandContet.get(); + return commandContet; +} + +std::unique_ptr CDevice::CreateTexture(const char* name, const ITexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) +{ + return CTexture::Create(this, name, type, + format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount); +} + +std::unique_ptr CDevice::CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) +{ + return CreateTexture(name, CTexture::Type::TEXTURE_2D, + format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount); +} + +std::unique_ptr CDevice::CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment) +{ + return CreateFramebuffer(name, colorAttachment, depthStencilAttachment, CColor(0.0f, 0.0f, 0.0f, 0.0f)); +} + +std::unique_ptr CDevice::CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment, const CColor& clearColor) +{ + return CFramebuffer::Create( + this, name, colorAttachment->As(), depthStencilAttachment->As(), clearColor); +} + +std::unique_ptr CDevice::CreateBuffer( + const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) +{ + return CBuffer::Create(this, name, type, size, dynamic); +} + +std::unique_ptr CDevice::CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) +{ + return CShaderProgram::Create(this, name, defines); +} + +void CDevice::Present() +{ + if (m_Window) + { + PROFILE3("swap buffers"); + SDL_GL_SwapWindow(m_Window); + ogl_WarnIfError(); + } + + bool checkGLErrorAfterSwap = false; + CFG_GET_VAL("gl.checkerrorafterswap", checkGLErrorAfterSwap); +#if defined(NDEBUG) + if (!checkGLErrorAfterSwap) + return; +#endif + PROFILE3("error check"); + // We have to check GL errors after SwapBuffer to avoid possible + // synchronizations during rendering. + if (GLenum err = glGetError()) + ONCE(LOGERROR("GL error %s (0x%04x) occurred", ogl_GetErrorName(err), err)); +} + +bool CDevice::IsTextureFormatSupported(const Format format) const +{ + bool supported = false; + switch (format) + { + case Format::UNDEFINED: + break; + + case Format::R8G8B8_UNORM: FALLTHROUGH; + case Format::R8G8B8A8_UNORM: FALLTHROUGH; + case Format::A8_UNORM: FALLTHROUGH; + case Format::L8_UNORM: + supported = true; + break; + + case Format::R32_SFLOAT: FALLTHROUGH; + case Format::R32G32_SFLOAT: FALLTHROUGH; + case Format::R32G32B32_SFLOAT: FALLTHROUGH; + case Format::R32G32B32A32_SFLOAT: + break; + + case Format::D16: FALLTHROUGH; + case Format::D24: FALLTHROUGH; + case Format::D32: + supported = true; + break; + case Format::D24_S8: +#if !CONFIG2_GLES + supported = true; +#endif + break; + + case Format::BC1_RGB_UNORM: FALLTHROUGH; + case Format::BC1_RGBA_UNORM: FALLTHROUGH; + case Format::BC2_UNORM: FALLTHROUGH; + case Format::BC3_UNORM: + supported = m_Capabilities.S3TC; + break; + + default: + break; + } + return supported; +} + +bool CDevice::IsFramebufferFormatSupported(const Format format) const +{ + bool supported = false; + switch (format) + { + case Format::UNDEFINED: + break; +#if !CONFIG2_GLES + case Format::R8_UNORM: + supported = ogl_HaveVersion(3, 0); + break; +#endif + case Format::R8G8B8A8_UNORM: + supported = true; + break; + default: + break; + } + return supported; +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Device.h 0ad-0.0.26/source/renderer/backend/gl/Device.h --- 0ad-0.0.25b/source/renderer/backend/gl/Device.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Device.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,129 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_DEVICE +#define INCLUDED_RENDERER_BACKEND_GL_DEVICE + +#include "renderer/backend/Format.h" +#include "renderer/backend/gl/Buffer.h" +#include "renderer/backend/gl/Framebuffer.h" +#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/gl/Texture.h" +#include "renderer/backend/IDevice.h" +#include "scriptinterface/ScriptForward.h" + +#include +#include +#include + +typedef struct SDL_Window SDL_Window; +typedef void* SDL_GLContext; + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDeviceCommandContext; + +class CDevice final : public IDevice +{ +public: + ~CDevice() override; + + /** + * Creates the GL device and the GL context for the window if it presents. + */ + static std::unique_ptr Create(SDL_Window* window, const bool arb); + + const std::string& GetName() const override { return m_Name; } + const std::string& GetVersion() const override { return m_Version; } + const std::string& GetDriverInformation() const override { return m_DriverInformation; } + const std::vector& GetExtensions() const override { return m_Extensions; } + + void Report(const ScriptRequest& rq, JS::HandleValue settings) override; + + IFramebuffer* GetCurrentBackbuffer() override { return m_Backbuffer.get(); } + + std::unique_ptr CreateCommandContext() override; + + CDeviceCommandContext* GetActiveCommandContext() { return m_ActiveCommandContext; } + + std::unique_ptr CreateTexture(const char* name, const ITexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) override; + + std::unique_ptr CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override; + + std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment) override; + + std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment, const CColor& clearColor) override; + + std::unique_ptr CreateBuffer( + const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) override; + + std::unique_ptr CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) override; + + void Present() override; + + bool IsTextureFormatSupported(const Format format) const override; + + bool IsFramebufferFormatSupported(const Format format) const override; + + const Capabilities& GetCapabilities() const override { return m_Capabilities; } + +private: + CDevice(); + + SDL_Window* m_Window = nullptr; + SDL_GLContext m_Context = nullptr; + + bool m_ARB = false; + + std::string m_Name; + std::string m_Version; + std::string m_DriverInformation; + std::vector m_Extensions; + + // GL can have the only one command context at once. + // TODO: remove as soon as we have no GL code outside backend, currently + // it's used only as a helper for transition. + CDeviceCommandContext* m_ActiveCommandContext = nullptr; + + std::unique_ptr m_Backbuffer; + + Capabilities m_Capabilities{}; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_DEVICE diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Framebuffer.cpp 0ad-0.0.26/source/renderer/backend/gl/Framebuffer.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/Framebuffer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Framebuffer.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -0,0 +1,181 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Framebuffer.h" + +#include "lib/code_annotation.h" +#include "lib/config2.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/Texture.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +// static +std::unique_ptr CFramebuffer::Create( + CDevice* device, const char* name, + CTexture* colorAttachment, CTexture* depthStencilAttachment, + const CColor& clearColor) +{ + ENSURE(colorAttachment || depthStencilAttachment); + + std::unique_ptr framebuffer(new CFramebuffer()); + framebuffer->m_Device = device; + framebuffer->m_ClearColor = clearColor; + + glGenFramebuffersEXT(1, &framebuffer->m_Handle); + if (!framebuffer->m_Handle) + { + LOGERROR("Failed to create CFramebuffer object"); + return nullptr; + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->m_Handle); + + if (colorAttachment) + { + ENSURE(device->IsFramebufferFormatSupported(colorAttachment->GetFormat())); + + framebuffer->m_AttachmentMask |= GL_COLOR_BUFFER_BIT; + +#if CONFIG2_GLES + ENSURE(colorAttachment->GetType() == CTexture::Type::TEXTURE_2D); + const GLenum textureTarget = GL_TEXTURE_2D; +#else + const GLenum textureTarget = colorAttachment->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? + GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; +#endif + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + textureTarget, colorAttachment->GetHandle(), 0); + } + if (depthStencilAttachment) + { + framebuffer->m_Width = depthStencilAttachment->GetWidth(); + framebuffer->m_Height = depthStencilAttachment->GetHeight(); + framebuffer->m_AttachmentMask |= GL_DEPTH_BUFFER_BIT; + if (depthStencilAttachment->GetFormat() == Format::D24_S8) + framebuffer->m_AttachmentMask |= GL_STENCIL_BUFFER_BIT; + if (colorAttachment) + { + ENSURE(colorAttachment->GetWidth() == depthStencilAttachment->GetWidth()); + ENSURE(colorAttachment->GetHeight() == depthStencilAttachment->GetHeight()); + ENSURE(colorAttachment->GetType() == depthStencilAttachment->GetType()); + } + ENSURE( + depthStencilAttachment->GetFormat() == Format::D16 || + depthStencilAttachment->GetFormat() == Format::D24 || + depthStencilAttachment->GetFormat() == Format::D32 || + depthStencilAttachment->GetFormat() == Format::D24_S8); +#if CONFIG2_GLES + ENSURE(depthStencilAttachment->GetFormat() != Format::D24_S8); + const GLenum attachment = GL_DEPTH_ATTACHMENT; + ENSURE(depthStencilAttachment->GetType() == CTexture::Type::TEXTURE_2D); + const GLenum textureTarget = GL_TEXTURE_2D; +#else + const GLenum attachment = depthStencilAttachment->GetFormat() == Format::D24_S8 ? + GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; + const GLenum textureTarget = depthStencilAttachment->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? + GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; +#endif + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + textureTarget, depthStencilAttachment->GetHandle(), 0); + } + else + { + framebuffer->m_Width = colorAttachment->GetWidth(); + framebuffer->m_Height = colorAttachment->GetHeight(); + } + + ogl_WarnIfError(); + +#if !CONFIG2_GLES + if (!colorAttachment) + { + glReadBuffer(GL_NONE); + glDrawBuffer(GL_NONE); + } + else + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); +#endif + + ogl_WarnIfError(); + +#if !CONFIG2_GLES + if (framebuffer->m_Device->GetCapabilities().debugLabels) + { + glObjectLabel(GL_FRAMEBUFFER, framebuffer->m_Handle, -1, name); + } +#else + UNUSED2(name); +#endif + + const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + LOGERROR("CFramebuffer object incomplete: 0x%04X", status); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + return nullptr; + } + + ogl_WarnIfError(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + return framebuffer; +} + +// static +std::unique_ptr CFramebuffer::CreateBackbuffer( + CDevice* device) +{ + // Backbuffer for GL is a special case with a zero framebuffer. + std::unique_ptr framebuffer(new CFramebuffer()); + framebuffer->m_Device = device; + framebuffer->m_AttachmentMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + CStr skyString = "0 0 0"; + CFG_GET_VAL("skycolor", skyString); + framebuffer->m_ClearColor.ParseString(skyString, 0.0f); + return framebuffer; +} + +CFramebuffer::CFramebuffer() = default; + +CFramebuffer::~CFramebuffer() +{ + if (m_Handle) + glDeleteFramebuffersEXT(1, &m_Handle); +} + +IDevice* CFramebuffer::GetDevice() +{ + return m_Device; +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Framebuffer.h 0ad-0.0.26/source/renderer/backend/gl/Framebuffer.h --- 0ad-0.0.25b/source/renderer/backend/gl/Framebuffer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Framebuffer.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,78 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_FRAMEBUFFER +#define INCLUDED_RENDERER_BACKEND_GL_FRAMEBUFFER + +#include "graphics/Color.h" +#include "lib/ogl.h" +#include "renderer/backend/IFramebuffer.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; +class CTexture; + +class CFramebuffer final : public IFramebuffer +{ +public: + ~CFramebuffer() override; + + IDevice* GetDevice() override; + + const CColor& GetClearColor() const override { return m_ClearColor; } + + GLuint GetHandle() const { return m_Handle; } + GLbitfield GetAttachmentMask() const { return m_AttachmentMask; } + + uint32_t GetWidth() const { return m_Width; } + uint32_t GetHeight() const { return m_Height; } + +private: + friend class CDevice; + + static std::unique_ptr Create( + CDevice* device, const char* name, + CTexture* colorAttachment, CTexture* depthStencilAttachment, const CColor& clearColor); + static std::unique_ptr CreateBackbuffer(CDevice* device); + + CFramebuffer(); + + CDevice* m_Device = nullptr; + GLuint m_Handle = 0; + uint32_t m_Width = 0, m_Height = 0; + GLbitfield m_AttachmentMask = 0; + CColor m_ClearColor; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_FRAMEBUFFER diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Mapping.cpp 0ad-0.0.26/source/renderer/backend/gl/Mapping.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/Mapping.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Mapping.cpp 2022-08-21 12:45:25.000000000 +0000 @@ -0,0 +1,135 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Mapping.h" + +#include "lib/code_annotation.h" +#include "lib/config2.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace Mapping +{ + +GLenum FromCompareOp(const CompareOp compareOp) +{ + GLenum op = GL_NEVER; + switch (compareOp) + { +#define CASE(NAME, GL_NAME) case CompareOp::NAME: op = GL_NAME; break + CASE(NEVER, GL_NEVER); + CASE(LESS, GL_LESS); + CASE(EQUAL, GL_EQUAL); + CASE(LESS_OR_EQUAL, GL_LEQUAL); + CASE(GREATER, GL_GREATER); + CASE(NOT_EQUAL, GL_NOTEQUAL); + CASE(GREATER_OR_EQUAL, GL_GEQUAL); + CASE(ALWAYS, GL_ALWAYS); +#undef CASE + } + return op; +} + +GLenum FromStencilOp(const StencilOp stencilOp) +{ + GLenum op = GL_KEEP; + switch (stencilOp) + { +#define CASE(NAME, GL_NAME) case StencilOp::NAME: op = GL_NAME; break + CASE(KEEP, GL_KEEP); + CASE(ZERO, GL_ZERO); + CASE(REPLACE, GL_REPLACE); + CASE(INCREMENT_AND_CLAMP, GL_INCR); + CASE(DECREMENT_AND_CLAMP, GL_DECR); + CASE(INVERT, GL_INVERT); + CASE(INCREMENT_AND_WRAP, GL_INCR_WRAP); + CASE(DECREMENT_AND_WRAP, GL_DECR_WRAP); +#undef CASE + } + return op; +} + +GLenum FromBlendFactor(const BlendFactor blendFactor) +{ + GLenum factor = GL_ZERO; + switch (blendFactor) + { +#define CASE(NAME) case BlendFactor::NAME: factor = GL_##NAME; break + CASE(ZERO); + CASE(ONE); + CASE(SRC_COLOR); + CASE(ONE_MINUS_SRC_COLOR); + CASE(DST_COLOR); + CASE(ONE_MINUS_DST_COLOR); + CASE(SRC_ALPHA); + CASE(ONE_MINUS_SRC_ALPHA); + CASE(DST_ALPHA); + CASE(ONE_MINUS_DST_ALPHA); + CASE(CONSTANT_COLOR); + CASE(ONE_MINUS_CONSTANT_COLOR); + CASE(CONSTANT_ALPHA); + CASE(ONE_MINUS_CONSTANT_ALPHA); + CASE(SRC_ALPHA_SATURATE); +#undef CASE + // Dual source blending presents only in GL_VERSION >= 3.3. + case BlendFactor::SRC1_COLOR: FALLTHROUGH; + case BlendFactor::ONE_MINUS_SRC1_COLOR: FALLTHROUGH; + case BlendFactor::SRC1_ALPHA: FALLTHROUGH; + case BlendFactor::ONE_MINUS_SRC1_ALPHA: + debug_warn("Unsupported blend factor."); + break; + } + return factor; +} + +GLenum FromBlendOp(const BlendOp blendOp) +{ + GLenum mode = GL_FUNC_ADD; + switch (blendOp) + { + case BlendOp::ADD: mode = GL_FUNC_ADD; break; + case BlendOp::SUBTRACT: mode = GL_FUNC_SUBTRACT; break; + case BlendOp::REVERSE_SUBTRACT: mode = GL_FUNC_REVERSE_SUBTRACT; break; +#if !CONFIG2_GLES + case BlendOp::MIN: mode = GL_MIN; break; + case BlendOp::MAX: mode = GL_MAX; break; +#else + case BlendOp::MIN: FALLTHROUGH; + case BlendOp::MAX: + debug_warn("Unsupported blend op."); + break; +#endif + }; + return mode; +} + +} // namespace Mapping + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Mapping.h 0ad-0.0.26/source/renderer/backend/gl/Mapping.h --- 0ad-0.0.25b/source/renderer/backend/gl/Mapping.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Mapping.h 2022-08-21 12:45:25.000000000 +0000 @@ -0,0 +1,52 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_MAPPING +#define INCLUDED_RENDERER_BACKEND_GL_MAPPING + +#include "lib/ogl.h" +#include "renderer/backend/PipelineState.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace Mapping +{ + +GLenum FromCompareOp(const CompareOp compareOp); + +GLenum FromStencilOp(const StencilOp stencilOp); + +GLenum FromBlendFactor(const BlendFactor blendFactor); + +GLenum FromBlendOp(const BlendOp blendOp); + +} // namespace Mapping + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_MAPPING diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/ShaderProgram.cpp 0ad-0.0.26/source/renderer/backend/gl/ShaderProgram.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/ShaderProgram.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/ShaderProgram.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,1500 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "ShaderProgram.h" + +#include "graphics/Color.h" +#include "graphics/PreprocessorWrapper.h" +#include "graphics/ShaderManager.h" +#include "graphics/TextureManager.h" +#include "ps/CLogger.h" +#include "ps/Filesystem.h" +#include "ps/Profile.h" +#include "ps/XML/Xeromyces.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/DeviceCommandContext.h" + +#define USE_SHADER_XML_VALIDATION 1 + +#if USE_SHADER_XML_VALIDATION +#include "ps/XML/RelaxNG.h" +#include "ps/XML/XMLWriter.h" +#endif + +#include +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace +{ + +struct Binding +{ + Binding(int a, int b) : first(a), second(b) { } + + Binding() : first(-1), second(-1) { } + + /** + * Returns whether this uniform attribute is active in the shader. + * If not then there's no point calling Uniform() to set its value. + */ + bool Active() const { return first != -1 || second != -1; } + + int first; + int second; +}; + +int GetStreamMask(const VertexAttributeStream stream) +{ + return 1 << static_cast(stream); +} + +GLint GLSizeFromFormat(const Format format) +{ + GLint size = 1; + if (format == Renderer::Backend::Format::R32_SFLOAT || + format == Renderer::Backend::Format::R16_SINT) + size = 1; + else if ( + format == Renderer::Backend::Format::R8G8_UNORM || + format == Renderer::Backend::Format::R8G8_UINT || + format == Renderer::Backend::Format::R16G16_SINT || + format == Renderer::Backend::Format::R32G32_SFLOAT) + size = 2; + else if (format == Renderer::Backend::Format::R32G32B32_SFLOAT) + size = 3; + else if ( + format == Renderer::Backend::Format::R32G32B32A32_SFLOAT || + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UINT) + size = 4; + else + debug_warn("Unsupported format."); + return size; +} + +GLenum GLTypeFromFormat(const Format format) +{ + GLenum type = GL_FLOAT; + if (format == Renderer::Backend::Format::R32_SFLOAT || + format == Renderer::Backend::Format::R32G32_SFLOAT || + format == Renderer::Backend::Format::R32G32B32_SFLOAT || + format == Renderer::Backend::Format::R32G32B32A32_SFLOAT) + type = GL_FLOAT; + else if ( + format == Renderer::Backend::Format::R16_SINT || + format == Renderer::Backend::Format::R16G16_SINT) + type = GL_SHORT; + else if ( + format == Renderer::Backend::Format::R8G8_UNORM || + format == Renderer::Backend::Format::R8G8_UINT || + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UINT) + type = GL_UNSIGNED_BYTE; + else + debug_warn("Unsupported format."); + return type; +} + +GLboolean NormalizedFromFormat(const Format format) +{ + switch (format) + { + case Format::R8G8_UNORM: FALLTHROUGH; + case Format::R8G8B8_UNORM: FALLTHROUGH; + case Format::R8G8B8A8_UNORM: FALLTHROUGH; + case Format::R16_UNORM: FALLTHROUGH; + case Format::R16G16_UNORM: + return GL_TRUE; + default: + break; + } + return GL_FALSE; +} + +int GetAttributeLocationFromStream( + CDevice* device, const VertexAttributeStream stream) +{ + // Old mapping makes sense only if we have an old/low-end hardware. Else we + // need to use sequential numbering to fix #3054. We use presence of + // compute shaders as a check that the hardware has universal CUs. + if (device->GetCapabilities().computeShaders) + { + return static_cast(stream); + } + else + { + // Map known semantics onto the attribute locations documented by NVIDIA: + // https://download.nvidia.com/developer/Papers/2005/OpenGL_2.0/NVIDIA_OpenGL_2.0_Support.pdf + // https://developer.download.nvidia.com/opengl/glsl/glsl_release_notes.pdf + switch (stream) + { + case VertexAttributeStream::POSITION: return 0; + case VertexAttributeStream::NORMAL: return 2; + case VertexAttributeStream::COLOR: return 3; + case VertexAttributeStream::UV0: return 8; + case VertexAttributeStream::UV1: return 9; + case VertexAttributeStream::UV2: return 10; + case VertexAttributeStream::UV3: return 11; + case VertexAttributeStream::UV4: return 12; + case VertexAttributeStream::UV5: return 13; + case VertexAttributeStream::UV6: return 14; + case VertexAttributeStream::UV7: return 15; + } + } + + debug_warn("Invalid attribute semantics"); + return 0; +} + +bool PreprocessShaderFile( + bool arb, const CShaderDefines& defines, const VfsPath& path, + CStr& source, std::vector& fileDependencies) +{ + CVFSFile file; + if (file.Load(g_VFS, path) != PSRETURN_OK) + { + LOGERROR("Failed to load shader file: '%s'", path.string8()); + return false; + } + + CPreprocessorWrapper preprocessor( + [arb, &fileDependencies](const CStr& includePath, CStr& out) -> bool + { + const VfsPath includeFilePath( + (arb ? L"shaders/arb/" : L"shaders/glsl/") + wstring_from_utf8(includePath)); + // Add dependencies anyway to reload the shader when the file is + // appeared. + fileDependencies.push_back(includeFilePath); + CVFSFile includeFile; + if (includeFile.Load(g_VFS, includeFilePath) != PSRETURN_OK) + { + LOGERROR("Failed to load shader include file: '%s'", includeFilePath.string8()); + return false; + } + out = includeFile.GetAsString(); + return true; + }); + preprocessor.AddDefines(defines); + +#if CONFIG2_GLES + if (!arb) + { + // GLES defines the macro "GL_ES" in its GLSL preprocessor, + // but since we run our own preprocessor first, we need to explicitly + // define it here + preprocessor.AddDefine("GL_ES", "1"); + } +#endif + + source = preprocessor.Preprocess(file.GetAsString()); + + return true; +} + +#if !CONFIG2_GLES +std::tuple GetElementTypeAndCountFromString(const CStr& str) +{ +#define CASE(MATCH_STRING, TYPE, ELEMENT_TYPE, ELEMENT_COUNT) \ + if (str == MATCH_STRING) return {GL_ ## TYPE, GL_ ## ELEMENT_TYPE, ELEMENT_COUNT} + + CASE("float", FLOAT, FLOAT, 1); + CASE("vec2", FLOAT_VEC2, FLOAT, 2); + CASE("vec3", FLOAT_VEC3, FLOAT, 3); + CASE("vec4", FLOAT_VEC4, FLOAT, 4); + CASE("mat2", FLOAT_MAT2, FLOAT, 4); + CASE("mat3", FLOAT_MAT3, FLOAT, 9); + CASE("mat4", FLOAT_MAT4, FLOAT, 16); +#if !CONFIG2_GLES // GL ES 2.0 doesn't support non-square matrices. + CASE("mat2x3", FLOAT_MAT2x3, FLOAT, 6); + CASE("mat2x4", FLOAT_MAT2x4, FLOAT, 8); + CASE("mat3x2", FLOAT_MAT3x2, FLOAT, 6); + CASE("mat3x4", FLOAT_MAT3x4, FLOAT, 12); + CASE("mat4x2", FLOAT_MAT4x2, FLOAT, 8); + CASE("mat4x3", FLOAT_MAT4x3, FLOAT, 12); +#endif + + // A somewhat incomplete listing, missing "shadow" and "rect" versions + // which are interpreted as 2D (NB: our shadowmaps may change + // type based on user config). +#if CONFIG2_GLES + if (str == "sampler1D") debug_warn(L"sampler1D not implemented on GLES"); +#else + CASE("sampler1D", SAMPLER_1D, TEXTURE_1D, 1); +#endif + CASE("sampler2D", SAMPLER_2D, TEXTURE_2D, 1); +#if CONFIG2_GLES + if (str == "sampler2DShadow") debug_warn(L"sampler2DShadow not implemented on GLES"); + if (str == "sampler3D") debug_warn(L"sampler3D not implemented on GLES"); +#else + CASE("sampler2DShadow", SAMPLER_2D_SHADOW, TEXTURE_2D, 1); + CASE("sampler3D", SAMPLER_3D, TEXTURE_3D, 1); +#endif + CASE("samplerCube", SAMPLER_CUBE, TEXTURE_CUBE_MAP, 1); + +#undef CASE + return {0, 0, 0}; +} +#endif // !CONFIG2_GLES + +} // anonymous namespace + +#if !CONFIG2_GLES + +class CShaderProgramARB final : public CShaderProgram +{ +public: + CShaderProgramARB( + CDevice* device, + const VfsPath& path, const VfsPath& vertexFilePath, const VfsPath& fragmentFilePath, + const CShaderDefines& defines, + const std::map>& vertexIndices, + const std::map>& fragmentIndices, + int streamflags) + : CShaderProgram(streamflags), m_Device(device) + { + glGenProgramsARB(1, &m_VertexProgram); + glGenProgramsARB(1, &m_FragmentProgram); + + std::vector newFileDependencies = {path, vertexFilePath, fragmentFilePath}; + + CStr vertexCode; + if (!PreprocessShaderFile(true, defines, vertexFilePath, vertexCode, newFileDependencies)) + return; + CStr fragmentCode; + if (!PreprocessShaderFile(true, defines, fragmentFilePath, fragmentCode, newFileDependencies)) + return; + + m_FileDependencies = std::move(newFileDependencies); + + // TODO: replace by scoped bind. + m_Device->GetActiveCommandContext()->SetGraphicsPipelineState( + MakeDefaultGraphicsPipelineStateDesc()); + + if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, vertexFilePath, vertexCode)) + return; + + if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, fragmentFilePath, fragmentCode)) + return; + + for (const auto& index : vertexIndices) + { + BindingSlot& bindingSlot = GetOrCreateBindingSlot(index.first); + bindingSlot.vertexProgramLocation = index.second.second; + const auto [type, elementType, elementCount] = GetElementTypeAndCountFromString(index.second.first); + bindingSlot.type = type; + bindingSlot.elementType = elementType; + bindingSlot.elementCount = elementCount; + } + + for (const auto& index : fragmentIndices) + { + BindingSlot& bindingSlot = GetOrCreateBindingSlot(index.first); + bindingSlot.fragmentProgramLocation = index.second.second; + const auto [type, elementType, elementCount] = GetElementTypeAndCountFromString(index.second.first); + if (bindingSlot.type && type != bindingSlot.type) + { + LOGERROR("CShaderProgramARB: vertex and fragment program uniforms with the same name should have the same type."); + } + bindingSlot.type = type; + bindingSlot.elementType = elementType; + bindingSlot.elementCount = elementCount; + } + } + + ~CShaderProgramARB() override + { + glDeleteProgramsARB(1, &m_VertexProgram); + glDeleteProgramsARB(1, &m_FragmentProgram); + } + + bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code) + { + ogl_WarnIfError(); + + glBindProgramARB(target, program); + + ogl_WarnIfError(); + + glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str()); + + if (ogl_SquelchError(GL_INVALID_OPERATION)) + { + GLint errPos = 0; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); + int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1; + char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); + LOGERROR("Failed to compile %s program '%s' (line %d):\n%s", targetName, file.string8(), errLine, errStr); + return false; + } + + glBindProgramARB(target, 0); + + ogl_WarnIfError(); + + return true; + } + + void Bind(CShaderProgram* previousShaderProgram) override + { + if (previousShaderProgram) + previousShaderProgram->Unbind(); + + glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram); + + BindClientStates(); + } + + void Unbind() override + { + glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + + UnbindClientStates(); + } + + IDevice* GetDevice() override { return m_Device; } + + int32_t GetBindingSlot(const CStrIntern name) const override + { + auto it = m_BindingSlotsMapping.find(name); + return it == m_BindingSlotsMapping.end() ? -1 : it->second; + } + + TextureUnit GetTextureUnit(const int32_t bindingSlot) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return { 0, 0, 0 }; + TextureUnit textureUnit; + textureUnit.type = m_BindingSlots[bindingSlot].type; + textureUnit.target = m_BindingSlots[bindingSlot].elementType; + textureUnit.unit = m_BindingSlots[bindingSlot].fragmentProgramLocation; + return textureUnit; + } + + void SetUniform( + const int32_t bindingSlot, + const float value) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float)"); + return; + } + SetUniform(m_BindingSlots[bindingSlot], value, 0.0f, 0.0f, 0.0f); + } + + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC2) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected vec2)"); + return; + } + SetUniform(m_BindingSlots[bindingSlot], valueX, valueY, 0.0f, 0.0f); + } + + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, const float valueZ) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC3) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected vec3)"); + return; + } + SetUniform(m_BindingSlots[bindingSlot], valueX, valueY, valueZ, 0.0f); + } + + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC4) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected vec4)"); + return; + } + SetUniform(m_BindingSlots[bindingSlot], valueX, valueY, valueZ, valueW); + } + + void SetUniform( + const int32_t bindingSlot, PS::span values) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].elementType != GL_FLOAT) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform element type (expected float)"); + return; + } + if (m_BindingSlots[bindingSlot].elementCount > static_cast(values.size())) + { + LOGERROR( + "CShaderProgramARB::SetUniform(): Invalid uniform element count (expected: %zu passed: %zu)", + m_BindingSlots[bindingSlot].elementCount, values.size()); + return; + } + const GLenum type = m_BindingSlots[bindingSlot].type; + + if (type == GL_FLOAT) + SetUniform(m_BindingSlots[bindingSlot], values[0], 0.0f, 0.0f, 0.0f); + else if (type == GL_FLOAT_VEC2) + SetUniform(m_BindingSlots[bindingSlot], values[0], values[1], 0.0f, 0.0f); + else if (type == GL_FLOAT_VEC3) + SetUniform(m_BindingSlots[bindingSlot], values[0], values[1], values[2], 0.0f); + else if (type == GL_FLOAT_VEC4) + SetUniform(m_BindingSlots[bindingSlot], values[0], values[1], values[2], values[3]); + else if (type == GL_FLOAT_MAT4) + SetUniformMatrix(m_BindingSlots[bindingSlot], values); + else + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float, vec2, vec3, vec4, mat4)"); + ogl_WarnIfError(); + } + + std::vector GetFileDependencies() const override + { + return m_FileDependencies; + } + +private: + struct BindingSlot + { + CStrIntern name; + int vertexProgramLocation; + int fragmentProgramLocation; + GLenum type; + GLenum elementType; + GLint elementCount; + }; + + BindingSlot& GetOrCreateBindingSlot(const CStrIntern name) + { + auto it = m_BindingSlotsMapping.find(name); + if (it == m_BindingSlotsMapping.end()) + { + m_BindingSlotsMapping[name] = m_BindingSlots.size(); + BindingSlot bindingSlot{}; + bindingSlot.name = name; + bindingSlot.vertexProgramLocation = -1; + bindingSlot.fragmentProgramLocation = -1; + bindingSlot.elementType = 0; + bindingSlot.elementCount = 0; + m_BindingSlots.emplace_back(std::move(bindingSlot)); + return m_BindingSlots.back(); + } + else + return m_BindingSlots[it->second]; + } + + void SetUniform( + const BindingSlot& bindingSlot, + const float v0, const float v1, const float v2, const float v3) + { + SetUniform(GL_VERTEX_PROGRAM_ARB, bindingSlot.vertexProgramLocation, v0, v1, v2, v3); + SetUniform(GL_FRAGMENT_PROGRAM_ARB, bindingSlot.fragmentProgramLocation, v0, v1, v2, v3); + } + + void SetUniform( + const GLenum target, const int location, + const float v0, const float v1, const float v2, const float v3) + { + if (location >= 0) + { + glProgramLocalParameter4fARB( + target, static_cast(location), v0, v1, v2, v3); + } + } + + void SetUniformMatrix( + const BindingSlot& bindingSlot, PS::span values) + { + const size_t mat4ElementCount = 16; + ENSURE(values.size() == mat4ElementCount); + SetUniformMatrix(GL_VERTEX_PROGRAM_ARB, bindingSlot.vertexProgramLocation, values); + SetUniformMatrix(GL_FRAGMENT_PROGRAM_ARB, bindingSlot.fragmentProgramLocation, values); + } + + void SetUniformMatrix( + const GLenum target, const int location, PS::span values) + { + if (location >= 0) + { + glProgramLocalParameter4fARB( + target, static_cast(location + 0), values[0], values[4], values[8], values[12]); + glProgramLocalParameter4fARB( + target, static_cast(location + 1), values[1], values[5], values[9], values[13]); + glProgramLocalParameter4fARB( + target, static_cast(location + 2), values[2], values[6], values[10], values[14]); + glProgramLocalParameter4fARB( + target, static_cast(location + 3), values[3], values[7], values[11], values[15]); + } + } + + CDevice* m_Device = nullptr; + + std::vector m_FileDependencies; + + GLuint m_VertexProgram; + GLuint m_FragmentProgram; + + std::vector m_BindingSlots; + std::unordered_map m_BindingSlotsMapping; +}; + +#endif // !CONFIG2_GLES + +class CShaderProgramGLSL final : public CShaderProgram +{ +public: + CShaderProgramGLSL( + CDevice* device, const CStr& name, + const VfsPath& path, const VfsPath& vertexFilePath, const VfsPath& fragmentFilePath, + const CShaderDefines& defines, + const std::map& vertexAttribs, + int streamflags) : + CShaderProgram(streamflags), + m_Device(device), m_Name(name), + m_VertexAttribs(vertexAttribs) + { + for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + m_ActiveVertexAttributes.emplace_back(it->second); + std::sort(m_ActiveVertexAttributes.begin(), m_ActiveVertexAttributes.end()); + + m_Program = 0; + m_VertexShader = glCreateShader(GL_VERTEX_SHADER); + m_FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + m_FileDependencies = {path, vertexFilePath, fragmentFilePath}; + +#if !CONFIG2_GLES + if (m_Device->GetCapabilities().debugLabels) + { + glObjectLabel(GL_SHADER, m_VertexShader, -1, vertexFilePath.string8().c_str()); + glObjectLabel(GL_SHADER, m_FragmentShader, -1, fragmentFilePath.string8().c_str()); + } +#endif + + std::vector newFileDependencies = {path, vertexFilePath, fragmentFilePath}; + + CStr vertexCode; + if (!PreprocessShaderFile(false, defines, vertexFilePath, vertexCode, newFileDependencies)) + return; + CStr fragmentCode; + if (!PreprocessShaderFile(false, defines, fragmentFilePath, fragmentCode, newFileDependencies)) + return; + + m_FileDependencies = std::move(newFileDependencies); + + if (vertexCode.empty()) + { + LOGERROR("Failed to preprocess vertex shader: '%s'", vertexFilePath.string8()); + return; + } + if (fragmentCode.empty()) + { + LOGERROR("Failed to preprocess fragment shader: '%s'", fragmentFilePath.string8()); + return; + } + +#if CONFIG2_GLES + // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00, + // and also to set default float precision for fragment shaders + vertexCode.Replace("#version 110\n", "#version 100\n"); + vertexCode.Replace("#version 110\r\n", "#version 100\n"); + vertexCode.Replace("#version 120\n", "#version 100\n"); + vertexCode.Replace("#version 120\r\n", "#version 100\n"); + fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n"); + fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n"); + fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n"); + fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n"); +#endif + + // TODO: replace by scoped bind. + m_Device->GetActiveCommandContext()->SetGraphicsPipelineState( + MakeDefaultGraphicsPipelineStateDesc()); + + if (!Compile(m_VertexShader, vertexFilePath, vertexCode)) + return; + + if (!Compile(m_FragmentShader, fragmentFilePath, fragmentCode)) + return; + + if (!Link(vertexFilePath, fragmentFilePath)) + return; + } + + ~CShaderProgramGLSL() override + { + if (m_Program) + glDeleteProgram(m_Program); + + glDeleteShader(m_VertexShader); + glDeleteShader(m_FragmentShader); + } + + bool Compile(GLuint shader, const VfsPath& file, const CStr& code) + { + const char* code_string = code.c_str(); + GLint code_length = code.length(); + glShaderSource(shader, 1, &code_string, &code_length); + + ogl_WarnIfError(); + + glCompileShader(shader); + + GLint ok = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + + GLint length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + + // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0 + // (http://code.google.com/p/android/issues/detail?id=9953) + if (!ok && length == 0) + length = 4096; + + if (length > 1) + { + char* infolog = new char[length]; + glGetShaderInfoLog(shader, length, NULL, infolog); + + if (ok) + LOGMESSAGE("Info when compiling shader '%s':\n%s", file.string8(), infolog); + else + LOGERROR("Failed to compile shader '%s':\n%s", file.string8(), infolog); + + delete[] infolog; + } + + ogl_WarnIfError(); + + return ok; + } + + bool Link(const VfsPath& vertexFilePath, const VfsPath& fragmentFilePath) + { + ENSURE(!m_Program); + m_Program = glCreateProgram(); + +#if !CONFIG2_GLES + if (m_Device->GetCapabilities().debugLabels) + { + glObjectLabel(GL_PROGRAM, m_Program, -1, m_Name.c_str()); + } +#endif + + glAttachShader(m_Program, m_VertexShader); + ogl_WarnIfError(); + glAttachShader(m_Program, m_FragmentShader); + ogl_WarnIfError(); + + // Set up the attribute bindings explicitly, since apparently drivers + // don't always pick the most efficient bindings automatically, + // and also this lets us hardcode indexes into VertexPointer etc + for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + glBindAttribLocation(m_Program, it->second, it->first.c_str()); + + glLinkProgram(m_Program); + + GLint ok = 0; + glGetProgramiv(m_Program, GL_LINK_STATUS, &ok); + + GLint length = 0; + glGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length); + + if (!ok && length == 0) + length = 4096; + + if (length > 1) + { + char* infolog = new char[length]; + glGetProgramInfoLog(m_Program, length, NULL, infolog); + + if (ok) + LOGMESSAGE("Info when linking program '%s'+'%s':\n%s", vertexFilePath.string8(), fragmentFilePath.string8(), infolog); + else + LOGERROR("Failed to link program '%s'+'%s':\n%s", vertexFilePath.string8(), fragmentFilePath.string8(), infolog); + + delete[] infolog; + } + + ogl_WarnIfError(); + + if (!ok) + return false; + + Bind(nullptr); + + ogl_WarnIfError(); + + // Reorder sampler units to decrease redundant texture unit changes when + // samplers bound in a different order. + const std::unordered_map requiredUnits = + { + {CStrIntern("baseTex"), 0}, + {CStrIntern("normTex"), 1}, + {CStrIntern("specTex"), 2}, + {CStrIntern("aoTex"), 3}, + {CStrIntern("shadowTex"), 4}, + {CStrIntern("losTex"), 5}, + }; + + std::vector occupiedUnits; + + GLint numUniforms = 0; + glGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); + ogl_WarnIfError(); + for (GLint i = 0; i < numUniforms; ++i) + { + // TODO: use GL_ACTIVE_UNIFORM_MAX_LENGTH for the size. + char name[256] = {0}; + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name); + ogl_WarnIfError(); + + const GLint location = glGetUniformLocation(m_Program, name); + + // OpenGL specification is a bit vague about a name returned by glGetActiveUniform. + // NVIDIA drivers return uniform name with "[0]", Intel Windows drivers without; + while (nameLength > 3 && + name[nameLength - 3] == '[' && + name[nameLength - 2] == '0' && + name[nameLength - 1] == ']') + { + nameLength -= 3; + } + name[nameLength] = 0; + + const CStrIntern nameIntern(name); + + m_BindingSlotsMapping[nameIntern] = m_BindingSlots.size(); + BindingSlot bindingSlot{}; + bindingSlot.name = nameIntern; + bindingSlot.location = location; + bindingSlot.size = size; + bindingSlot.type = type; + bindingSlot.isTexture = false; + +#define CASE(TYPE, ELEMENT_TYPE, ELEMENT_COUNT) \ + case GL_ ## TYPE: \ + bindingSlot.elementType = GL_ ## ELEMENT_TYPE; \ + bindingSlot.elementCount = ELEMENT_COUNT; \ + break; + + switch (type) + { + CASE(FLOAT, FLOAT, 1); + CASE(FLOAT_VEC2, FLOAT, 2); + CASE(FLOAT_VEC3, FLOAT, 3); + CASE(FLOAT_VEC4, FLOAT, 4); + CASE(INT, INT, 1); + CASE(FLOAT_MAT2, FLOAT, 4); + CASE(FLOAT_MAT3, FLOAT, 9); + CASE(FLOAT_MAT4, FLOAT, 16); +#if !CONFIG2_GLES // GL ES 2.0 doesn't support non-square matrices. + CASE(FLOAT_MAT2x3, FLOAT, 6); + CASE(FLOAT_MAT2x4, FLOAT, 8); + CASE(FLOAT_MAT3x2, FLOAT, 6); + CASE(FLOAT_MAT3x4, FLOAT, 12); + CASE(FLOAT_MAT4x2, FLOAT, 8); + CASE(FLOAT_MAT4x3, FLOAT, 12); +#endif + } +#undef CASE + + // Assign sampler uniforms to sequential texture units. + if (type == GL_SAMPLER_2D + || type == GL_SAMPLER_CUBE +#if !CONFIG2_GLES + || type == GL_SAMPLER_2D_SHADOW +#endif + ) + { + const auto it = requiredUnits.find(nameIntern); + const int unit = it == requiredUnits.end() ? -1 : it->second; + bindingSlot.elementType = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); + bindingSlot.elementCount = unit; + bindingSlot.isTexture = true; + if (unit != -1) + { + if (unit >= static_cast(occupiedUnits.size())) + occupiedUnits.resize(unit + 1); + occupiedUnits[unit] = true; + } + } + + if (bindingSlot.elementType == 0) + { + LOGERROR("CShaderProgramGLSL::Link: unsupported uniform type: 0x%04x", static_cast(type)); + } + + m_BindingSlots.emplace_back(std::move(bindingSlot)); + } + + for (BindingSlot& bindingSlot : m_BindingSlots) + { + if (!bindingSlot.isTexture) + continue; + if (bindingSlot.elementCount == -1) + { + // We need to find a minimal available unit. + int unit = 0; + while (unit < static_cast(occupiedUnits.size()) && occupiedUnits[unit]) + ++unit; + if (unit >= static_cast(occupiedUnits.size())) + occupiedUnits.resize(unit + 1); + occupiedUnits[unit] = true; + bindingSlot.elementCount = unit; + } + // Link uniform to unit. + glUniform1i(bindingSlot.location, bindingSlot.elementCount); + ogl_WarnIfError(); + } + + // TODO: verify that we're not using more samplers than is supported + + Unbind(); + + return true; + } + + void Bind(CShaderProgram* previousShaderProgram) override + { + CShaderProgramGLSL* previousShaderProgramGLSL = nullptr; + if (previousShaderProgram) + previousShaderProgramGLSL = static_cast(previousShaderProgram); + ENSURE(this != previousShaderProgramGLSL); + + glUseProgram(m_Program); + + if (previousShaderProgramGLSL) + { + std::vector::iterator itPrevious = previousShaderProgramGLSL->m_ActiveVertexAttributes.begin(); + std::vector::iterator itNext = m_ActiveVertexAttributes.begin(); + while ( + itPrevious != previousShaderProgramGLSL->m_ActiveVertexAttributes.end() || + itNext != m_ActiveVertexAttributes.end()) + { + if (itPrevious != previousShaderProgramGLSL->m_ActiveVertexAttributes.end() && + itNext != m_ActiveVertexAttributes.end()) + { + if (*itPrevious == *itNext) + { + ++itPrevious; + ++itNext; + } + else if (*itPrevious < *itNext) + { + glDisableVertexAttribArray(*itPrevious); + ++itPrevious; + } + else if (*itPrevious > *itNext) + { + glEnableVertexAttribArray(*itNext); + ++itNext; + } + } + else if (itPrevious != previousShaderProgramGLSL->m_ActiveVertexAttributes.end()) + { + glDisableVertexAttribArray(*itPrevious); + ++itPrevious; + } + else if (itNext != m_ActiveVertexAttributes.end()) + { + glEnableVertexAttribArray(*itNext); + ++itNext; + } + } + } + else + { + for (const int index : m_ActiveVertexAttributes) + glEnableVertexAttribArray(index); + } + + m_ValidStreams = 0; + } + + void Unbind() override + { + glUseProgram(0); + + for (const int index : m_ActiveVertexAttributes) + glDisableVertexAttribArray(index); + } + + IDevice* GetDevice() override { return m_Device; } + + int32_t GetBindingSlot(const CStrIntern name) const override + { + auto it = m_BindingSlotsMapping.find(name); + return it == m_BindingSlotsMapping.end() ? -1 : it->second; + } + + TextureUnit GetTextureUnit(const int32_t bindingSlot) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return { 0, 0, 0 }; + TextureUnit textureUnit; + textureUnit.type = m_BindingSlots[bindingSlot].type; + textureUnit.target = m_BindingSlots[bindingSlot].elementType; + textureUnit.unit = m_BindingSlots[bindingSlot].elementCount; + return textureUnit; + } + + void SetUniform( + const int32_t bindingSlot, + const float value) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT || + m_BindingSlots[bindingSlot].size != 1) + { + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected float) '%s'", m_BindingSlots[bindingSlot].name.c_str()); + return; + } + glUniform1f(m_BindingSlots[bindingSlot].location, value); + ogl_WarnIfError(); + } + + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC2 || + m_BindingSlots[bindingSlot].size != 1) + { + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected vec2) '%s'", m_BindingSlots[bindingSlot].name.c_str()); + return; + } + glUniform2f(m_BindingSlots[bindingSlot].location, valueX, valueY); + ogl_WarnIfError(); + } + + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, const float valueZ) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC3 || + m_BindingSlots[bindingSlot].size != 1) + { + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected vec3) '%s'", m_BindingSlots[bindingSlot].name.c_str()); + return; + } + glUniform3f(m_BindingSlots[bindingSlot].location, valueX, valueY, valueZ); + ogl_WarnIfError(); + } + + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC4 || + m_BindingSlots[bindingSlot].size != 1) + { + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected vec4) '%s'", m_BindingSlots[bindingSlot].name.c_str()); + return; + } + glUniform4f(m_BindingSlots[bindingSlot].location, valueX, valueY, valueZ, valueW); + ogl_WarnIfError(); + } + + void SetUniform( + const int32_t bindingSlot, PS::span values) override + { + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].elementType != GL_FLOAT) + { + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform element type (expected float) '%s'", m_BindingSlots[bindingSlot].name.c_str()); + return; + } + if (m_BindingSlots[bindingSlot].size == 1 && m_BindingSlots[bindingSlot].elementCount > static_cast(values.size())) + { + LOGERROR( + "CShaderProgramGLSL::SetUniform(): Invalid uniform element count (expected: %zu passed: %zu) '%s'", + m_BindingSlots[bindingSlot].elementCount, values.size(), m_BindingSlots[bindingSlot].name.c_str()); + return; + } + const GLint location = m_BindingSlots[bindingSlot].location; + const GLenum type = m_BindingSlots[bindingSlot].type; + + if (type == GL_FLOAT) + glUniform1fv(location, 1, values.data()); + else if (type == GL_FLOAT_VEC2) + glUniform2fv(location, 1, values.data()); + else if (type == GL_FLOAT_VEC3) + glUniform3fv(location, 1, values.data()); + else if (type == GL_FLOAT_VEC4) + glUniform4fv(location, 1, values.data()); + else if (type == GL_FLOAT_MAT4) + { + // For case of array of matrices we might pass less number of matrices. + const GLint size = std::min( + m_BindingSlots[bindingSlot].size, static_cast(values.size() / 16)); + glUniformMatrix4fv(location, size, GL_FALSE, values.data()); + } + else + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected float, vec2, vec3, vec4, mat4) '%s'", m_BindingSlots[bindingSlot].name.c_str()); + ogl_WarnIfError(); + } + + void VertexAttribPointer( + const VertexAttributeStream stream, const Format format, + const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const void* data) override + { + const int attributeLocation = GetAttributeLocationFromStream(m_Device, stream); + std::vector::const_iterator it = + std::lower_bound(m_ActiveVertexAttributes.begin(), m_ActiveVertexAttributes.end(), attributeLocation); + if (it == m_ActiveVertexAttributes.end() || *it != attributeLocation) + return; + const GLint size = GLSizeFromFormat(format); + const GLenum type = GLTypeFromFormat(format); + const GLboolean normalized = NormalizedFromFormat(format); + glVertexAttribPointer( + attributeLocation, size, type, normalized, stride, static_cast(data) + offset); +#if CONFIG2_GLES + ENSURE(!m_Device->GetCapabilities().instancing); + UNUSED2(rate); +#else + if (rate == VertexAttributeRate::PER_INSTANCE) + ENSURE(m_Device->GetCapabilities().instancing); + if (m_Device->GetCapabilities().instancing) + { + glVertexAttribDivisorARB(attributeLocation, rate == VertexAttributeRate::PER_INSTANCE ? 1 : 0); + } +#endif + m_ValidStreams |= GetStreamMask(stream); + } + + std::vector GetFileDependencies() const override + { + return m_FileDependencies; + } + +private: + CDevice* m_Device = nullptr; + + CStr m_Name; + std::vector m_FileDependencies; + + std::map m_VertexAttribs; + // Sorted list of active vertex attributes. + std::vector m_ActiveVertexAttributes; + + GLuint m_Program; + GLuint m_VertexShader, m_FragmentShader; + + struct BindingSlot + { + CStrIntern name; + GLint location; + GLint size; + GLenum type; + GLenum elementType; + GLint elementCount; + bool isTexture; + }; + std::vector m_BindingSlots; + std::unordered_map m_BindingSlotsMapping; +}; + +CShaderProgram::CShaderProgram(int streamflags) + : m_StreamFlags(streamflags), m_ValidStreams(0) +{ +} + +CShaderProgram::~CShaderProgram() = default; + +// static +std::unique_ptr CShaderProgram::Create(CDevice* device, const CStr& name, const CShaderDefines& baseDefines) +{ + PROFILE2("loading shader"); + PROFILE2_ATTR("name: %s", name.c_str()); + + VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml"; + + CXeromyces XeroFile; + PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); + if (ret != PSRETURN_OK) + return nullptr; + +#if USE_SHADER_XML_VALIDATION + { + // Serialize the XMB data and pass it to the validator + XMLWriter_File shaderFile; + shaderFile.SetPrettyPrint(false); + shaderFile.XMB(XeroFile); + bool ok = CXeromyces::ValidateEncoded("shader", name, shaderFile.GetOutput()); + if (!ok) + return nullptr; + } +#endif + + // Define all the elements and attributes used in the XML file +#define EL(x) int el_##x = XeroFile.GetElementID(#x) +#define AT(x) int at_##x = XeroFile.GetAttributeID(#x) + EL(define); + EL(fragment); + EL(stream); + EL(uniform); + EL(vertex); + AT(attribute); + AT(file); + AT(if); + AT(loc); + AT(name); + AT(type); + AT(value); +#undef AT +#undef EL + + CPreprocessorWrapper preprocessor; + preprocessor.AddDefines(baseDefines); + + XMBElement root = XeroFile.GetRoot(); + + const bool isGLSL = root.GetAttributes().GetNamedItem(at_type) == "glsl"; + + VfsPath vertexFile; + VfsPath fragmentFile; + CShaderDefines defines = baseDefines; + std::map> vertexUniforms; + std::map> fragmentUniforms; + std::map vertexAttribs; + int streamFlags = 0; + + XERO_ITER_EL(root, child) + { + if (child.GetNodeName() == el_define) + { + defines.Add(CStrIntern(child.GetAttributes().GetNamedItem(at_name)), CStrIntern(child.GetAttributes().GetNamedItem(at_value))); + } + else if (child.GetNodeName() == el_vertex) + { + vertexFile = L"shaders/" + child.GetAttributes().GetNamedItem(at_file).FromUTF8(); + + XERO_ITER_EL(child, param) + { + XMBAttributeList attributes = param.GetAttributes(); + + CStr cond = attributes.GetNamedItem(at_if); + if (!cond.empty() && !preprocessor.TestConditional(cond)) + continue; + + if (param.GetNodeName() == el_uniform) + { + vertexUniforms[CStrIntern(attributes.GetNamedItem(at_name))] = + std::make_pair(attributes.GetNamedItem(at_type), attributes.GetNamedItem(at_loc).ToInt()); + } + else if (param.GetNodeName() == el_stream) + { + const CStr streamName = attributes.GetNamedItem(at_name); + const CStr attributeName = attributes.GetNamedItem(at_attribute); + if (attributeName.empty() && isGLSL) + LOGERROR("Empty attribute name in vertex shader description '%s'", vertexFile.string8().c_str()); + + VertexAttributeStream stream = + VertexAttributeStream::UV7; + if (streamName == "pos") + stream = VertexAttributeStream::POSITION; + else if (streamName == "normal") + stream = VertexAttributeStream::NORMAL; + else if (streamName == "color") + stream = VertexAttributeStream::COLOR; + else if (streamName == "uv0") + stream = VertexAttributeStream::UV0; + else if (streamName == "uv1") + stream = VertexAttributeStream::UV1; + else if (streamName == "uv2") + stream = VertexAttributeStream::UV2; + else if (streamName == "uv3") + stream = VertexAttributeStream::UV3; + else if (streamName == "uv4") + stream = VertexAttributeStream::UV4; + else if (streamName == "uv5") + stream = VertexAttributeStream::UV5; + else if (streamName == "uv6") + stream = VertexAttributeStream::UV6; + else if (streamName == "uv7") + stream = VertexAttributeStream::UV7; + else + LOGERROR("Unknown stream '%s' in vertex shader description '%s'", streamName.c_str(), vertexFile.string8().c_str()); + + if (isGLSL) + { + const int attributeLocation = GetAttributeLocationFromStream(device, stream); + vertexAttribs[CStrIntern(attributeName)] = attributeLocation; + } + streamFlags |= GetStreamMask(stream); + } + } + } + else if (child.GetNodeName() == el_fragment) + { + fragmentFile = L"shaders/" + child.GetAttributes().GetNamedItem(at_file).FromUTF8(); + + XERO_ITER_EL(child, param) + { + XMBAttributeList attributes = param.GetAttributes(); + + CStr cond = attributes.GetNamedItem(at_if); + if (!cond.empty() && !preprocessor.TestConditional(cond)) + continue; + + if (param.GetNodeName() == el_uniform) + { + fragmentUniforms[CStrIntern(attributes.GetNamedItem(at_name))] = + std::make_pair(attributes.GetNamedItem(at_type), attributes.GetNamedItem(at_loc).ToInt()); + } + } + } + } + + if (isGLSL) + { + return std::make_unique( + device, name, xmlFilename, vertexFile, fragmentFile, defines, + vertexAttribs, streamFlags); + } + else + { +#if CONFIG2_GLES + LOGERROR("CShaderProgram::Create: '%s'+'%s': ARB shaders not supported on this device", + vertexFile.string8(), fragmentFile.string8()); + return nullptr; +#else + return std::make_unique( + device, xmlFilename, vertexFile, fragmentFile, defines, + vertexUniforms, fragmentUniforms, streamFlags); +#endif + } +} + +// These should all be overridden by CShaderProgramGLSL, and not used +// if a non-GLSL shader was loaded instead: + +#if CONFIG2_GLES + +// These should all be overridden by CShaderProgramGLSL +// (GLES doesn't support any other types of shader program): + +void CShaderProgram::VertexPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::VertexPointer should be overridden"); +} +void CShaderProgram::NormalPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::NormalPointer should be overridden"); +} +void CShaderProgram::ColorPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::ColorPointer should be overridden"); +} +void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::TexCoordPointer should be overridden"); +} + +#else + +// These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders +// both use the fixed-function vertex attribute pointers so we'll share their +// definitions here: + +void CShaderProgram::VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + const GLint size = GLSizeFromFormat(format); + ENSURE(2 <= size && size <= 4); + const GLenum type = GLTypeFromFormat(format); + glVertexPointer(size, type, stride, pointer); + m_ValidStreams |= GetStreamMask(VertexAttributeStream::POSITION); +} + +void CShaderProgram::NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + ENSURE(format == Renderer::Backend::Format::R32G32B32_SFLOAT); + glNormalPointer(GL_FLOAT, stride, pointer); + m_ValidStreams |= GetStreamMask(VertexAttributeStream::NORMAL); +} + +void CShaderProgram::ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + const GLint size = GLSizeFromFormat(format); + ENSURE(3 <= size && size <= 4); + const GLenum type = GLTypeFromFormat(format); + glColorPointer(size, type, stride, pointer); + m_ValidStreams |= GetStreamMask(VertexAttributeStream::COLOR); +} + +void CShaderProgram::TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + glClientActiveTextureARB(texture); + const GLint size = GLSizeFromFormat(format); + ENSURE(1 <= size && size <= 4); + const GLenum type = GLTypeFromFormat(format); + glTexCoordPointer(size, type, stride, pointer); + glClientActiveTextureARB(GL_TEXTURE0); + m_ValidStreams |= GetStreamMask(VertexAttributeStream::UV0) << (texture - GL_TEXTURE0); +} + +void CShaderProgram::BindClientStates() +{ + ENSURE(m_StreamFlags == (m_StreamFlags & ( + GetStreamMask(VertexAttributeStream::POSITION) | + GetStreamMask(VertexAttributeStream::NORMAL) | + GetStreamMask(VertexAttributeStream::COLOR) | + GetStreamMask(VertexAttributeStream::UV0) | + GetStreamMask(VertexAttributeStream::UV1)))); + + // Enable all the desired client states for non-GLSL rendering + + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::POSITION)) + glEnableClientState(GL_VERTEX_ARRAY); + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::NORMAL)) + glEnableClientState(GL_NORMAL_ARRAY); + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::COLOR)) + glEnableClientState(GL_COLOR_ARRAY); + + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::UV0)) + { + glClientActiveTextureARB(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::UV1)) + { + glClientActiveTextureARB(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0); + } + + // Rendering code must subsequently call VertexPointer etc for all of the streams + // that were activated in this function, else AssertPointersBound will complain + // that some arrays were unspecified + m_ValidStreams = 0; +} + +void CShaderProgram::UnbindClientStates() +{ + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::POSITION)) + glDisableClientState(GL_VERTEX_ARRAY); + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::NORMAL)) + glDisableClientState(GL_NORMAL_ARRAY); + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::COLOR)) + glDisableClientState(GL_COLOR_ARRAY); + + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::UV0)) + { + glClientActiveTextureARB(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (m_StreamFlags & GetStreamMask(VertexAttributeStream::UV1)) + { + glClientActiveTextureARB(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0); + } +} + +#endif // !CONFIG2_GLES + +bool CShaderProgram::IsStreamActive(const VertexAttributeStream stream) const +{ + return (m_StreamFlags & GetStreamMask(stream)) != 0; +} + +void CShaderProgram::VertexAttribPointer( + const VertexAttributeStream stream, const Format format, + const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const void* data) +{ + ENSURE(rate == VertexAttributeRate::PER_VERTEX); + switch (stream) + { + case VertexAttributeStream::POSITION: + VertexPointer(format, stride, static_cast(data) + offset); + break; + case VertexAttributeStream::NORMAL: + NormalPointer(format, stride, static_cast(data) + offset); + break; + case VertexAttributeStream::COLOR: + ColorPointer(format, stride, static_cast(data) + offset); + break; + case VertexAttributeStream::UV0: FALLTHROUGH; + case VertexAttributeStream::UV1: FALLTHROUGH; + case VertexAttributeStream::UV2: FALLTHROUGH; + case VertexAttributeStream::UV3: FALLTHROUGH; + case VertexAttributeStream::UV4: FALLTHROUGH; + case VertexAttributeStream::UV5: FALLTHROUGH; + case VertexAttributeStream::UV6: FALLTHROUGH; + case VertexAttributeStream::UV7: + { + const int indexOffset = static_cast(stream) - static_cast(VertexAttributeStream::UV0); + TexCoordPointer(GL_TEXTURE0 + indexOffset, format, stride, static_cast(data) + offset); + break; + } + default: + debug_warn("Unsupported stream"); + }; +} + +void CShaderProgram::AssertPointersBound() +{ + ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/ShaderProgram.h 0ad-0.0.26/source/renderer/backend/gl/ShaderProgram.h --- 0ad-0.0.25b/source/renderer/backend/gl/ShaderProgram.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/ShaderProgram.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,146 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_SHADERPROGRAM +#define INCLUDED_RENDERER_BACKEND_GL_SHADERPROGRAM + +#include "lib/ogl.h" +#include "lib/file/vfs/vfs_path.h" +#include "ps/CStrForward.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/gl/Texture.h" +#include "renderer/backend/IShaderProgram.h" + +#include +#include + +struct CColor; +class CMatrix3D; +class CVector3D; +class CShaderDefines; +class CStrIntern; + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +/** + * A compiled vertex+fragment shader program. + * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax) + * or GL_ARB_{vertex,fragment}_shader (GLSL), or may use hard-coded fixed-function + * multitexturing setup code; the difference is hidden from the caller. + * + * Texture/uniform IDs are typically strings, corresponding to the names defined in + * the shader .xml file. Alternatively (and more efficiently, if used very frequently), + * call GetBindingSlot and pass its return value as the ID. + * Setting uniforms that the shader .xml doesn't support is harmless. + * + * For a high-level overview of shaders and materials, see + * http://trac.wildfiregames.com/wiki/MaterialSystem + */ +class CShaderProgram : public IShaderProgram +{ + NONCOPYABLE(CShaderProgram); + +public: + typedef CStrIntern attrib_id_t; + + static std::unique_ptr Create( + CDevice* device, const CStr& name, const CShaderDefines& baseDefines); + + ~CShaderProgram() override; + + /** + * Binds the shader into the GL context. Call this before calling Uniform() + * or trying to render with it. + */ + virtual void Bind(CShaderProgram* previousShaderProgram) = 0; + + /** + * Unbinds the shader from the GL context. Call this after rendering with it. + */ + virtual void Unbind() = 0; + + struct TextureUnit + { + GLenum type; + GLenum target; + GLint unit; + }; + virtual TextureUnit GetTextureUnit(const int32_t bindingSlot) = 0; + + virtual void SetUniform( + const int32_t bindingSlot, + const float value) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) = 0; + virtual void SetUniform( + const int32_t bindingSlot, PS::span values) = 0; + + // Vertex attribute pointers (equivalent to glVertexPointer etc). + virtual void VertexAttribPointer( + const VertexAttributeStream stream, const Format format, + const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const void* data); + + bool IsStreamActive(const VertexAttributeStream stream) const; + + /** + * Checks that all the required vertex attributes have been set. + * Call this before calling Draw/DrawIndexed etc to avoid potential crashes. + */ + void AssertPointersBound(); + +protected: + CShaderProgram(int streamflags); + + void VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + + int m_StreamFlags; + + // Non-GLSL client state handling: + void BindClientStates(); + void UnbindClientStates(); + int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_SHADERPROGRAM diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Texture.cpp 0ad-0.0.26/source/renderer/backend/gl/Texture.cpp --- 0ad-0.0.25b/source/renderer/backend/gl/Texture.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Texture.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,316 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Texture.h" + +#include "lib/code_annotation.h" +#include "lib/config2.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/Mapping.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace +{ + +GLint CalculateMinFilter(const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount) +{ + if (MIPLevelCount == 1) + return defaultSamplerDesc.minFilter == Sampler::Filter::LINEAR ? GL_LINEAR : GL_NEAREST; + + if (defaultSamplerDesc.minFilter == Sampler::Filter::LINEAR) + return defaultSamplerDesc.mipFilter == Sampler::Filter::LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST; + + return defaultSamplerDesc.mipFilter == Sampler::Filter::LINEAR ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; +} + +GLint AddressModeToGLEnum(Sampler::AddressMode addressMode) +{ + switch (addressMode) + { + case Sampler::AddressMode::REPEAT: return GL_REPEAT; + case Sampler::AddressMode::MIRRORED_REPEAT: return GL_MIRRORED_REPEAT; + case Sampler::AddressMode::CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; + case Sampler::AddressMode::CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; + } + return GL_REPEAT; +} + +GLenum TypeToGLEnum(CTexture::Type type) +{ + GLenum target = GL_TEXTURE_2D; + switch (type) + { + case CTexture::Type::TEXTURE_2D: + target = GL_TEXTURE_2D; + break; + case CTexture::Type::TEXTURE_2D_MULTISAMPLE: +#if CONFIG2_GLES + ENSURE(false && "Multisample textures are unsupported on GLES"); +#else + target = GL_TEXTURE_2D_MULTISAMPLE; +#endif + break; + case CTexture::Type::TEXTURE_CUBE: + target = GL_TEXTURE_CUBE_MAP; + break; + } + return target; +} + +} // anonymous namespace + +// static +std::unique_ptr CTexture::Create(CDevice* device, const char* name, + const Type type, const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) +{ + std::unique_ptr texture(new CTexture()); + + ENSURE(format != Format::UNDEFINED); + ENSURE(width > 0 && height > 0 && MIPLevelCount > 0); + ENSURE((type == Type::TEXTURE_2D_MULTISAMPLE && sampleCount > 1) || sampleCount == 1); + + texture->m_Device = device; + texture->m_Format = format; + texture->m_Type = type; + texture->m_Width = width; + texture->m_Height = height; + texture->m_MIPLevelCount = MIPLevelCount; + + glGenTextures(1, &texture->m_Handle); + + ogl_WarnIfError(); + + const GLenum target = TypeToGLEnum(type); + + CDeviceCommandContext::ScopedBind scopedBind( + texture->m_Device->GetActiveCommandContext(), target, texture->m_Handle); + + // It's forbidden to set sampler state for multisample textures. + if (type != Type::TEXTURE_2D_MULTISAMPLE) + { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, CalculateMinFilter(defaultSamplerDesc, MIPLevelCount)); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, defaultSamplerDesc.magFilter == Sampler::Filter::LINEAR ? GL_LINEAR : GL_NEAREST); + + ogl_WarnIfError(); + + glTexParameteri(target, GL_TEXTURE_WRAP_S, AddressModeToGLEnum(defaultSamplerDesc.addressModeU)); + glTexParameteri(target, GL_TEXTURE_WRAP_T, AddressModeToGLEnum(defaultSamplerDesc.addressModeV)); + } + +#if !CONFIG2_GLES + if (type == Type::TEXTURE_CUBE) + glTexParameteri(target, GL_TEXTURE_WRAP_R, AddressModeToGLEnum(defaultSamplerDesc.addressModeW)); +#endif + + ogl_WarnIfError(); + +#if !CONFIG2_GLES + glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, MIPLevelCount - 1); + + if (defaultSamplerDesc.mipLODBias != 0.0f) + glTexParameteri(target, GL_TEXTURE_LOD_BIAS, defaultSamplerDesc.mipLODBias); +#endif // !CONFIG2_GLES + + if (type == Type::TEXTURE_2D && defaultSamplerDesc.anisotropyEnabled) + { + ENSURE(texture->m_Device->GetCapabilities().anisotropicFiltering); + const float maxAnisotropy = std::min( + defaultSamplerDesc.maxAnisotropy, texture->m_Device->GetCapabilities().maxAnisotropy); + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy); + } + + if (defaultSamplerDesc.addressModeU == Sampler::AddressMode::CLAMP_TO_BORDER || + defaultSamplerDesc.addressModeV == Sampler::AddressMode::CLAMP_TO_BORDER || + defaultSamplerDesc.addressModeW == Sampler::AddressMode::CLAMP_TO_BORDER) + { + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, defaultSamplerDesc.borderColor.AsFloatArray().data()); + } + + ogl_WarnIfError(); + + if (type == CTexture::Type::TEXTURE_2D) + { + bool compressedFormat = false; + GLint internalFormat = GL_RGBA; + // Actually pixel data is nullptr so it doesn't make sense to account + // it, but in theory some buggy drivers might complain about invalid + // pixel format. + GLenum pixelFormat = GL_RGBA; + GLenum pixelType = GL_UNSIGNED_BYTE; + switch (format) + { + case Format::UNDEFINED: + debug_warn("Texture should defined format"); + break; + case Format::R8G8B8A8_UNORM: + break; + case Format::R8G8B8_UNORM: + internalFormat = GL_RGB; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + break; +#if !CONFIG2_GLES + case Format::R8_UNORM: + internalFormat = GL_RED; + pixelFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + break; +#endif + case Format::A8_UNORM: + internalFormat = GL_ALPHA; + pixelFormat = GL_ALPHA; + pixelType = GL_UNSIGNED_BYTE; + break; + case Format::L8_UNORM: + internalFormat = GL_LUMINANCE; + pixelFormat = GL_LUMINANCE; + pixelType = GL_UNSIGNED_BYTE; + break; +#if CONFIG2_GLES + // GLES requires pixel type == UNSIGNED_SHORT or UNSIGNED_INT for depth. + case Format::D16: FALLTHROUGH; + case Format::D24: FALLTHROUGH; + case Format::D32: + internalFormat = GL_DEPTH_COMPONENT; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case Format::D24_S8: + debug_warn("Unsupported format"); + break; +#else + case Format::D16: + internalFormat = GL_DEPTH_COMPONENT16; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case Format::D24: + internalFormat = GL_DEPTH_COMPONENT24; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case Format::D32: + internalFormat = GL_DEPTH_COMPONENT32; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case Format::D24_S8: + internalFormat = GL_DEPTH24_STENCIL8_EXT; + pixelFormat = GL_DEPTH_STENCIL_EXT; + pixelType = GL_UNSIGNED_INT_24_8_EXT; + break; +#endif + case Format::BC1_RGB_UNORM: FALLTHROUGH; + case Format::BC1_RGBA_UNORM: FALLTHROUGH; + case Format::BC2_UNORM: FALLTHROUGH; + case Format::BC3_UNORM: + compressedFormat = true; + break; + default: + debug_warn("Unsupported format."); + } + // glCompressedTexImage2D can't accept a null data, so we will initialize it during uploading. + if (!compressedFormat) + { + for (uint32_t level = 0; level < MIPLevelCount; ++level) + { + glTexImage2D(target, level, internalFormat, + std::max(1u, width >> level), std::max(1u, height >> level), + 0, pixelFormat, pixelType, nullptr); + } + } + } + else if (type == CTexture::Type::TEXTURE_2D_MULTISAMPLE) + { + ENSURE(MIPLevelCount == 1); +#if !CONFIG2_GLES + if (format == Format::R8G8B8A8_UNORM) + { + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, GL_RGBA8, width, height, GL_TRUE); + } + else if (format == Format::D24_S8) + { + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, GL_DEPTH24_STENCIL8_EXT, width, height, GL_TRUE); + } + else +#endif // !CONFIG2_GLES + { + debug_warn("Unsupported format"); + } + } + + +#if !CONFIG2_GLES + if (format == Format::D16 || format == Format::D24 || format == Format::D32 || + format == Format::D24_S8) + { + if (defaultSamplerDesc.compareEnabled) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, + Mapping::FromCompareOp(defaultSamplerDesc.compareOp)); + } + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } +#endif + + ogl_WarnIfError(); + + if (texture->m_Device->GetCapabilities().debugLabels) + { + glObjectLabel(GL_TEXTURE, texture->m_Handle, -1, name); + } + + return texture; +} + +CTexture::CTexture() = default; + +CTexture::~CTexture() +{ + m_Device->GetActiveCommandContext()->OnTextureDestroy(this); + if (m_Handle) + glDeleteTextures(1, &m_Handle); +} + +IDevice* CTexture::GetDevice() +{ + return m_Device; +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/gl/Texture.h 0ad-0.0.26/source/renderer/backend/gl/Texture.h --- 0ad-0.0.25b/source/renderer/backend/gl/Texture.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/gl/Texture.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,86 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_TEXTURE +#define INCLUDED_RENDERER_BACKEND_GL_TEXTURE + +#include "lib/ogl.h" +#include "renderer/backend/ITexture.h" +#include "renderer/backend/Sampler.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +/** + * Represents a low-level GL texture, encapsulates all properties initialization. + */ +class CTexture final : public ITexture +{ +public: + ~CTexture() override; + + IDevice* GetDevice() override; + + Type GetType() const override { return m_Type; } + Format GetFormat() const override { return m_Format; } + + uint32_t GetWidth() const override { return m_Width; } + uint32_t GetHeight() const override { return m_Height; } + uint32_t GetMIPLevelCount() const override { return m_MIPLevelCount; } + + GLuint GetHandle() const { return m_Handle; } + +private: + friend class CDevice; + + CTexture(); + + CDevice* m_Device = nullptr; + + // GL before 3.3 doesn't support sampler objects, so each texture should have + // an own default sampler. + static std::unique_ptr Create(CDevice* device, const char* name, + const Type type, const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount); + + GLuint m_Handle = 0; + + Type m_Type = Type::TEXTURE_2D; + Format m_Format = Format::UNDEFINED; + uint32_t m_Width = 0; + uint32_t m_Height = 0; + uint32_t m_MIPLevelCount = 0; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_TEXTURE diff -Nru 0ad-0.0.25b/source/renderer/backend/IBuffer.h 0ad-0.0.26/source/renderer/backend/IBuffer.h --- 0ad-0.0.25b/source/renderer/backend/IBuffer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/IBuffer.h 2022-09-23 19:17:03.000000000 +0000 @@ -0,0 +1,49 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_IBUFFER +#define INCLUDED_RENDERER_BACKEND_IBUFFER + +#include "renderer/backend/IDeviceObject.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +class IBuffer : public IDeviceObject +{ +public: + enum class Type + { + VERTEX, + INDEX + }; + + virtual Type GetType() const = 0; + virtual uint32_t GetSize() const = 0; + virtual bool IsDynamic() const = 0; +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_IBUFFER diff -Nru 0ad-0.0.25b/source/renderer/backend/IDeviceCommandContext.h 0ad-0.0.26/source/renderer/backend/IDeviceCommandContext.h --- 0ad-0.0.25b/source/renderer/backend/IDeviceCommandContext.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/IDeviceCommandContext.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,166 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_IDEVICECOMMANDCONTEXT +#define INCLUDED_RENDERER_BACKEND_IDEVICECOMMANDCONTEXT + +#include "ps/containers/Span.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/IDeviceObject.h" +#include "renderer/backend/PipelineState.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +class IBuffer; +class IDevice; +class IFramebuffer; +class ITexture; + +class IDeviceCommandContext : public IDeviceObject +{ +public: + virtual void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) = 0; + + virtual void BlitFramebuffer( + IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) = 0; + + virtual void ClearFramebuffer() = 0; + virtual void ClearFramebuffer(const bool color, const bool depth, const bool stencil) = 0; + virtual void SetFramebuffer(IFramebuffer* framebuffer) = 0; + virtual void ReadbackFramebufferSync( + const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, + void* data) = 0; + + virtual void UploadTexture(ITexture* texture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t level = 0, const uint32_t layer = 0) = 0; + virtual void UploadTextureRegion(ITexture* texture, const Format dataFormat, + const void* data, const size_t dataSize, + const uint32_t xOffset, const uint32_t yOffset, + const uint32_t width, const uint32_t height, + const uint32_t level = 0, const uint32_t layer = 0) = 0; + + using UploadBufferFunction = std::function; + virtual void UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize) = 0; + virtual void UploadBuffer(IBuffer* buffer, const UploadBufferFunction& uploadFunction) = 0; + virtual void UploadBufferRegion( + IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize) = 0; + virtual void UploadBufferRegion( + IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize, + const UploadBufferFunction& uploadFunction) = 0; + + // TODO: maybe we should add a more common type, like CRectI. + struct Rect + { + int32_t x, y; + int32_t width, height; + }; + virtual void SetScissors(const uint32_t scissorCount, const Rect* scissors) = 0; + virtual void SetViewports(const uint32_t viewportCount, const Rect* viewports) = 0; + + virtual void SetVertexAttributeFormat( + const VertexAttributeStream stream, + const Format format, + const uint32_t offset, + const uint32_t stride, + const VertexAttributeRate rate, + const uint32_t bindingSlot) = 0; + virtual void SetVertexBuffer(const uint32_t bindingSlot, IBuffer* buffer) = 0; + virtual void SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) = 0; + + virtual void SetIndexBuffer(IBuffer* buffer) = 0; + virtual void SetIndexBufferData(const void* data, const uint32_t dataSize) = 0; + + virtual void BeginPass() = 0; + virtual void EndPass() = 0; + + virtual void Draw(const uint32_t firstVertex, const uint32_t vertexCount) = 0; + virtual void DrawIndexed( + const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) = 0; + virtual void DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) = 0; + virtual void DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) = 0; + // TODO: should be removed when performance impact is minimal on slow hardware. + virtual void DrawIndexedInRange( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t start, const uint32_t end) = 0; + + virtual void SetTexture(const int32_t bindingSlot, ITexture* texture) = 0; + + virtual void SetUniform( + const int32_t bindingSlot, + const float value) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) = 0; + virtual void SetUniform( + const int32_t bindingSlot, PS::span values) = 0; + + virtual void BeginScopedLabel(const char* name) = 0; + virtual void EndScopedLabel() = 0; + + virtual void Flush() = 0; +}; + +} // namespace Backend + +} // namespace Renderer + +#define GPU_SCOPED_LABEL(deviceCommandContext, name) \ + GPUScopedLabel scopedLabel((deviceCommandContext), (name)); + +class GPUScopedLabel +{ +public: + GPUScopedLabel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const char* name) + : m_DeviceCommandContext(deviceCommandContext) + { + m_DeviceCommandContext->BeginScopedLabel(name); + } + + ~GPUScopedLabel() + { + m_DeviceCommandContext->EndScopedLabel(); + } + +private: + Renderer::Backend::IDeviceCommandContext* m_DeviceCommandContext = nullptr; +}; + +#endif // INCLUDED_RENDERER_BACKEND_IDEVICECOMMANDCONTEXT diff -Nru 0ad-0.0.25b/source/renderer/backend/IDevice.h 0ad-0.0.26/source/renderer/backend/IDevice.h --- 0ad-0.0.25b/source/renderer/backend/IDevice.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/IDevice.h 2022-09-23 19:17:03.000000000 +0000 @@ -0,0 +1,111 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_IDEVICE +#define INCLUDED_RENDERER_BACKEND_IDEVICE + +#include "graphics/Color.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/IBuffer.h" +#include "renderer/backend/IDevice.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/IShaderProgram.h" +#include "renderer/backend/ITexture.h" +#include "scriptinterface/ScriptForward.h" + +#include +#include +#include + +class CShaderDefines; +class CStr; + +namespace Renderer +{ + +namespace Backend +{ + +class IDevice +{ +public: + struct Capabilities + { + bool S3TC; + bool ARBShaders; + bool ARBShadersShadow; + bool computeShaders; + bool debugLabels; + bool debugScopedLabels; + bool multisampling; + bool anisotropicFiltering; + uint32_t maxSampleCount; + float maxAnisotropy; + uint32_t maxTextureSize; + bool instancing; + }; + + virtual ~IDevice() {} + + virtual const std::string& GetName() const = 0; + virtual const std::string& GetVersion() const = 0; + virtual const std::string& GetDriverInformation() const = 0; + virtual const std::vector& GetExtensions() const = 0; + + virtual void Report(const ScriptRequest& rq, JS::HandleValue settings) = 0; + + virtual IFramebuffer* GetCurrentBackbuffer() = 0; + + virtual std::unique_ptr CreateCommandContext() = 0; + + virtual std::unique_ptr CreateTexture(const char* name, const ITexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) = 0; + + virtual std::unique_ptr CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) = 0; + + virtual std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment) = 0; + + virtual std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment, const CColor& clearColor) = 0; + + virtual std::unique_ptr CreateBuffer( + const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) = 0; + + virtual std::unique_ptr CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) = 0; + + virtual void Present() = 0; + + virtual bool IsTextureFormatSupported(const Format format) const = 0; + + virtual bool IsFramebufferFormatSupported(const Format format) const = 0; + + virtual const Capabilities& GetCapabilities() const = 0; +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_IDEVICE diff -Nru 0ad-0.0.25b/source/renderer/backend/IDeviceObject.h 0ad-0.0.26/source/renderer/backend/IDeviceObject.h --- 0ad-0.0.25b/source/renderer/backend/IDeviceObject.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/IDeviceObject.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_IDEVICEOBJECT +#define INCLUDED_RENDERER_BACKEND_IDEVICEOBJECT + +#include + +namespace Renderer +{ + +namespace Backend +{ + +class IDevice; + +template +class IDeviceObject +{ +public: + virtual ~IDeviceObject() {} + + virtual IDevice* GetDevice() = 0; + + template + T* As() + { + static_assert(std::is_base_of_v); + return static_cast(this); + } +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_IDEVICEOBJECT diff -Nru 0ad-0.0.25b/source/renderer/backend/IFramebuffer.h 0ad-0.0.26/source/renderer/backend/IFramebuffer.h --- 0ad-0.0.25b/source/renderer/backend/IFramebuffer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/IFramebuffer.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_IFRAMEBUFFER +#define INCLUDED_RENDERER_BACKEND_IFRAMEBUFFER + +#include "graphics/Color.h" +#include "renderer/backend/IDeviceObject.h" + +namespace Renderer +{ + +namespace Backend +{ + +class IFramebuffer : public IDeviceObject +{ +public: + virtual const CColor& GetClearColor() const = 0; +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_IFRAMEBUFFER diff -Nru 0ad-0.0.25b/source/renderer/backend/IShaderProgram.h 0ad-0.0.26/source/renderer/backend/IShaderProgram.h --- 0ad-0.0.25b/source/renderer/backend/IShaderProgram.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/IShaderProgram.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM +#define INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM + +#include "lib/file/vfs/vfs_path.h" +#include "ps/CStrIntern.h" +#include "renderer/backend/IDeviceObject.h" + +namespace Renderer +{ + +namespace Backend +{ + +enum class VertexAttributeStream : uint32_t +{ + POSITION, + NORMAL, + COLOR, + UV0, + UV1, + UV2, + UV3, + UV4, + UV5, + UV6, + UV7, +}; + +enum class VertexAttributeRate : uint32_t +{ + PER_VERTEX, + PER_INSTANCE +}; + +/** + * IShaderProgram is a container for multiple shaders of different types. + */ +class IShaderProgram : public IDeviceObject +{ +public: + virtual int32_t GetBindingSlot(const CStrIntern name) const = 0; + + virtual std::vector GetFileDependencies() const = 0; +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM diff -Nru 0ad-0.0.25b/source/renderer/backend/ITexture.h 0ad-0.0.26/source/renderer/backend/ITexture.h --- 0ad-0.0.25b/source/renderer/backend/ITexture.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/ITexture.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_ITEXTURE +#define INCLUDED_RENDERER_BACKEND_ITEXTURE + +#include "renderer/backend/Format.h" +#include "renderer/backend/IDeviceObject.h" +#include "renderer/backend/Sampler.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +class ITexture : public IDeviceObject +{ +public: + enum class Type + { + TEXTURE_2D, + TEXTURE_2D_MULTISAMPLE, + TEXTURE_CUBE + }; + + virtual Type GetType() const = 0; + virtual Format GetFormat() const = 0; + + virtual uint32_t GetWidth() const = 0; + virtual uint32_t GetHeight() const = 0; + virtual uint32_t GetMIPLevelCount() const = 0; +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_ITEXTURE diff -Nru 0ad-0.0.25b/source/renderer/backend/PipelineState.cpp 0ad-0.0.26/source/renderer/backend/PipelineState.cpp --- 0ad-0.0.25b/source/renderer/backend/PipelineState.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/PipelineState.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,159 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "PipelineState.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +GraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc() +{ + GraphicsPipelineStateDesc desc{}; + + desc.shaderProgram = nullptr; + + desc.depthStencilState.depthTestEnabled = true; + desc.depthStencilState.depthCompareOp = CompareOp::LESS_OR_EQUAL; + desc.depthStencilState.depthWriteEnabled = true; + desc.depthStencilState.stencilTestEnabled = false; + desc.depthStencilState.stencilFrontFace.failOp = StencilOp::KEEP; + desc.depthStencilState.stencilFrontFace.passOp = StencilOp::KEEP; + desc.depthStencilState.stencilFrontFace.depthFailOp = StencilOp::KEEP; + desc.depthStencilState.stencilFrontFace.compareOp = CompareOp::ALWAYS; + desc.depthStencilState.stencilBackFace = desc.depthStencilState.stencilFrontFace; + desc.depthStencilState.stencilReadMask = desc.depthStencilState.stencilWriteMask = + std::numeric_limits::max(); + desc.depthStencilState.stencilReference = 0; + + desc.blendState.enabled = false; + desc.blendState.srcColorBlendFactor = desc.blendState.srcAlphaBlendFactor = + BlendFactor::ONE; + desc.blendState.dstColorBlendFactor = desc.blendState.dstAlphaBlendFactor = + BlendFactor::ZERO; + desc.blendState.colorBlendOp = desc.blendState.alphaBlendOp = BlendOp::ADD; + desc.blendState.constant = CColor(0.0f, 0.0f, 0.0f, 0.0f); + desc.blendState.colorWriteMask = + ColorWriteMask::RED | ColorWriteMask::GREEN | ColorWriteMask::BLUE | ColorWriteMask::ALPHA; + + desc.rasterizationState.polygonMode = PolygonMode::FILL; + desc.rasterizationState.cullMode = CullMode::BACK; + desc.rasterizationState.frontFace = FrontFace::COUNTER_CLOCKWISE; + desc.rasterizationState.depthBiasEnabled = false; + desc.rasterizationState.depthBiasConstantFactor = 0.0f; + desc.rasterizationState.depthBiasSlopeFactor = 0.0f; + return desc; +} + +StencilOp ParseStencilOp(const CStr& str) +{ +#define CASE(NAME) if (str == #NAME) return StencilOp::NAME + CASE(KEEP); + CASE(ZERO); + CASE(REPLACE); + CASE(INCREMENT_AND_CLAMP); + CASE(DECREMENT_AND_CLAMP); + CASE(INVERT); + CASE(INCREMENT_AND_WRAP); + CASE(DECREMENT_AND_WRAP); +#undef CASE + debug_warn("Invalid stencil op"); + return StencilOp::KEEP; +} + +BlendFactor ParseBlendFactor(const CStr& str) +{ + // TODO: it might make sense to use upper case in XML for consistency. +#define CASE(NAME, VALUE) if (str == NAME) return BlendFactor::VALUE + CASE("zero", ZERO); + CASE("one", ONE); + CASE("src_color", SRC_COLOR); + CASE("one_minus_src_color", ONE_MINUS_SRC_COLOR); + CASE("dst_color", DST_COLOR); + CASE("one_minus_dst_color", ONE_MINUS_DST_COLOR); + CASE("src_alpha", SRC_ALPHA); + CASE("one_minus_src_alpha", ONE_MINUS_SRC_ALPHA); + CASE("dst_alpha", DST_ALPHA); + CASE("one_minus_dst_alpha", ONE_MINUS_DST_ALPHA); + CASE("constant_color", CONSTANT_COLOR); + CASE("one_minus_constant_color", ONE_MINUS_CONSTANT_COLOR); + CASE("constant_alpha", CONSTANT_ALPHA); + CASE("one_minus_constant_alpha", ONE_MINUS_CONSTANT_ALPHA); + CASE("src_alpha_saturate", SRC_ALPHA_SATURATE); + CASE("src1_color", SRC1_COLOR); + CASE("one_minus_src1_color", ONE_MINUS_SRC1_COLOR); + CASE("src1_alpha", SRC1_ALPHA); + CASE("one_minus_src1_alpha", ONE_MINUS_SRC1_ALPHA); +#undef CASE + debug_warn("Invalid blend factor"); + return BlendFactor::ZERO; +} + +BlendOp ParseBlendOp(const CStr& str) +{ +#define CASE(NAME) if (str == #NAME) return BlendOp::NAME + CASE(ADD); + CASE(SUBTRACT); + CASE(REVERSE_SUBTRACT); + CASE(MIN); + CASE(MAX); +#undef CASE + debug_warn("Invalid blend op"); + return BlendOp::ADD; +} + +PolygonMode ParsePolygonMode(const CStr& str) +{ + if (str == "FILL") + return PolygonMode::FILL; + else if (str == "LINE") + return PolygonMode::LINE; + debug_warn("Invalid polygon mode"); + return PolygonMode::FILL; +} + +CullMode ParseCullMode(const CStr& str) +{ + if (str == "NONE") + return CullMode::NONE; + else if (str == "FRONT") + return CullMode::FRONT; + else if (str == "BACK") + return CullMode::BACK; + debug_warn("Invalid cull mode"); + return CullMode::BACK; +} + +FrontFace ParseFrontFace(const CStr& str) +{ + if (str == "CLOCKWISE") + return FrontFace::CLOCKWISE; + else if (str == "COUNTER_CLOCKWISE") + return FrontFace::COUNTER_CLOCKWISE; + debug_warn("Invalid front face"); + return FrontFace::COUNTER_CLOCKWISE; +} + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/PipelineState.h 0ad-0.0.26/source/renderer/backend/PipelineState.h --- 0ad-0.0.25b/source/renderer/backend/PipelineState.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/PipelineState.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,190 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_PIPELINESTATE +#define INCLUDED_RENDERER_BACKEND_PIPELINESTATE + +#include "graphics/Color.h" +#include "renderer/backend/CompareOp.h" +#include "renderer/backend/IShaderProgram.h" + +class CStr; + +namespace Renderer +{ + +namespace Backend +{ + +enum class StencilOp +{ + // Keeps the current value. + KEEP, + // Sets the value to zero. + ZERO, + // Sets the value to reference. + REPLACE, + // Increments the value and clamps to the maximum representable unsigned + // value. + INCREMENT_AND_CLAMP, + // Decrements the value and clamps to zero. + DECREMENT_AND_CLAMP, + // Bitwise inverts the value. + INVERT, + // Increments the value and wraps it to zero when incrementing the maximum + // representable unsigned value. + INCREMENT_AND_WRAP, + // Decrements the value and wraps it to the maximum representable unsigned + // value when decrementing zero. + DECREMENT_AND_WRAP +}; + +struct StencilOpState +{ + StencilOp failOp; + StencilOp passOp; + StencilOp depthFailOp; + CompareOp compareOp; +}; + +struct DepthStencilStateDesc +{ + bool depthTestEnabled; + CompareOp depthCompareOp; + bool depthWriteEnabled; + bool stencilTestEnabled; + uint32_t stencilReadMask; + uint32_t stencilWriteMask; + uint32_t stencilReference; + StencilOpState stencilFrontFace; + StencilOpState stencilBackFace; +}; + +// TODO: add per constant description. + +enum class BlendFactor +{ + ZERO, + ONE, + SRC_COLOR, + ONE_MINUS_SRC_COLOR, + DST_COLOR, + ONE_MINUS_DST_COLOR, + SRC_ALPHA, + ONE_MINUS_SRC_ALPHA, + DST_ALPHA, + ONE_MINUS_DST_ALPHA, + CONSTANT_COLOR, + ONE_MINUS_CONSTANT_COLOR, + CONSTANT_ALPHA, + ONE_MINUS_CONSTANT_ALPHA, + SRC_ALPHA_SATURATE, + SRC1_COLOR, + ONE_MINUS_SRC1_COLOR, + SRC1_ALPHA, + ONE_MINUS_SRC1_ALPHA, +}; + +enum class BlendOp +{ + ADD, + SUBTRACT, + REVERSE_SUBTRACT, + MIN, + MAX +}; + +// Using a namespace instead of a enum allows using the same syntax while +// avoiding adding operator overrides and additional checks on casts. +namespace ColorWriteMask +{ +constexpr uint8_t RED = 0x01; +constexpr uint8_t GREEN = 0x02; +constexpr uint8_t BLUE = 0x04; +constexpr uint8_t ALPHA = 0x08; +} // namespace ColorWriteMask + +struct BlendStateDesc +{ + bool enabled; + BlendFactor srcColorBlendFactor; + BlendFactor dstColorBlendFactor; + BlendOp colorBlendOp; + BlendFactor srcAlphaBlendFactor; + BlendFactor dstAlphaBlendFactor; + BlendOp alphaBlendOp; + CColor constant; + uint8_t colorWriteMask; +}; + +enum class PolygonMode +{ + FILL, + LINE +}; + +enum class CullMode +{ + NONE, + FRONT, + BACK +}; + +enum class FrontFace +{ + COUNTER_CLOCKWISE, + CLOCKWISE +}; + +struct RasterizationStateDesc +{ + PolygonMode polygonMode; + CullMode cullMode; + FrontFace frontFace; + bool depthBiasEnabled; + float depthBiasConstantFactor; + float depthBiasSlopeFactor; +}; + +struct GraphicsPipelineStateDesc +{ + // It's a backend client reponsibility to keep the shader program alive + // while it's bound. + IShaderProgram* shaderProgram; + DepthStencilStateDesc depthStencilState; + BlendStateDesc blendState; + RasterizationStateDesc rasterizationState; +}; + +// We don't provide additional helpers intentionally because all custom states +// should be described with a related shader and should be switched together. +GraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc(); + +StencilOp ParseStencilOp(const CStr& str); + +BlendFactor ParseBlendFactor(const CStr& str); +BlendOp ParseBlendOp(const CStr& str); + +PolygonMode ParsePolygonMode(const CStr& str); +CullMode ParseCullMode(const CStr& str); +FrontFace ParseFrontFace(const CStr& str); + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_PIPELINESTATE diff -Nru 0ad-0.0.25b/source/renderer/backend/Sampler.cpp 0ad-0.0.26/source/renderer/backend/Sampler.cpp --- 0ad-0.0.25b/source/renderer/backend/Sampler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/Sampler.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Sampler.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Sampler +{ + +Desc MakeDefaultSampler(Filter filter, AddressMode addressMode) +{ + Desc desc{}; + desc.minFilter = filter; + desc.magFilter = filter; + desc.mipFilter = filter; + desc.addressModeU = addressMode; + desc.addressModeV = addressMode; + desc.addressModeW = addressMode; + desc.anisotropyEnabled = false; + desc.mipLODBias = 0.0f; + desc.borderColor = CColor(0.0f, 0.0f, 0.0f, 0.0f); + desc.compareEnabled = false; + return desc; +} + +} // namespace Sampler + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/Sampler.h 0ad-0.0.26/source/renderer/backend/Sampler.h --- 0ad-0.0.25b/source/renderer/backend/Sampler.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/Sampler.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_SAMPLER +#define INCLUDED_RENDERER_BACKEND_SAMPLER + +#include "graphics/Color.h" +#include "renderer/backend/CompareOp.h" + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Sampler +{ + +enum class Filter +{ + NEAREST, + LINEAR +}; + +enum class AddressMode +{ + REPEAT, + MIRRORED_REPEAT, + CLAMP_TO_EDGE, + CLAMP_TO_BORDER, +}; + +struct Desc +{ + Filter magFilter; + Filter minFilter; + Filter mipFilter; + AddressMode addressModeU; + AddressMode addressModeV; + AddressMode addressModeW; + float mipLODBias; + bool anisotropyEnabled; + float maxAnisotropy; + // When some filter is CLAMP_TO_BORDER. + CColor borderColor; + bool compareEnabled; + CompareOp compareOp; +}; + +Desc MakeDefaultSampler(Filter filter, AddressMode addressMode); + +} // namespace Sampler + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_SAMPLER diff -Nru 0ad-0.0.25b/source/renderer/backend/vulkan/Device.cpp 0ad-0.0.26/source/renderer/backend/vulkan/Device.cpp --- 0ad-0.0.25b/source/renderer/backend/vulkan/Device.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/vulkan/Device.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,175 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Device.h" + +#include "lib/external_libraries/libsdl.h" +#include "scriptinterface/JSON.h" +#include "scriptinterface/Object.h" +#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/ScriptRequest.h" + +#if SDL_VERSION_ATLEAST(2, 0, 8) +#include +#endif + +namespace Renderer +{ + +namespace Backend +{ + +namespace Vulkan +{ + +// static +std::unique_ptr CDevice::Create(SDL_Window* UNUSED(window)) +{ + std::unique_ptr device(new CDevice()); + return device; +} + +CDevice::CDevice() = default; + +CDevice::~CDevice() = default; + +void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings) +{ + Script::SetProperty(rq, settings, "name", "vulkan"); + + std::string vulkanSupport = "unsupported"; + // According to http://wiki.libsdl.org/SDL_Vulkan_LoadLibrary the following + // functionality is supported since SDL 2.0.8. +#if SDL_VERSION_ATLEAST(2, 0, 8) + if (!SDL_Vulkan_LoadLibrary(nullptr)) + { + void* vkGetInstanceProcAddr = SDL_Vulkan_GetVkGetInstanceProcAddr(); + if (vkGetInstanceProcAddr) + vulkanSupport = "supported"; + else + vulkanSupport = "noprocaddr"; + SDL_Vulkan_UnloadLibrary(); + } + else + { + vulkanSupport = "cantload"; + } +#endif + Script::SetProperty(rq, settings, "status", vulkanSupport); +} + +IFramebuffer* CDevice::GetCurrentBackbuffer() +{ + return nullptr; +} + +std::unique_ptr CDevice::CreateCommandContext() +{ + return nullptr; +} + +std::unique_ptr CDevice::CreateTexture(const char* name, const ITexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) +{ + UNUSED2(name); + UNUSED2(type); + UNUSED2(format); + UNUSED2(width); + UNUSED2(height); + UNUSED2(defaultSamplerDesc); + UNUSED2(MIPLevelCount); + UNUSED2(sampleCount); + return nullptr; +} + +std::unique_ptr CDevice::CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) +{ + UNUSED2(name); + UNUSED2(format); + UNUSED2(width); + UNUSED2(height); + UNUSED2(defaultSamplerDesc); + UNUSED2(MIPLevelCount); + UNUSED2(sampleCount); + return nullptr; +} + +std::unique_ptr CDevice::CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment) +{ + UNUSED2(name); + UNUSED2(colorAttachment); + UNUSED2(depthStencilAttachment); + return nullptr; +} + +std::unique_ptr CDevice::CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment, const CColor& clearColor) +{ + UNUSED2(name); + UNUSED2(colorAttachment); + UNUSED2(depthStencilAttachment); + UNUSED2(clearColor); + return nullptr; +} + +std::unique_ptr CDevice::CreateBuffer( + const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) +{ + UNUSED2(name); + UNUSED2(type); + UNUSED2(size); + UNUSED2(dynamic); + return nullptr; +} + +std::unique_ptr CDevice::CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) +{ + UNUSED2(name); + UNUSED2(defines); + return nullptr; +} + +void CDevice::Present() +{ +} + +bool CDevice::IsTextureFormatSupported(const Format format) const +{ + UNUSED2(format); + return false; +} + +bool CDevice::IsFramebufferFormatSupported(const Format format) const +{ + UNUSED2(format); + return false; +} + +} // namespace Vulkan + +} // namespace Backend + +} // namespace Renderer diff -Nru 0ad-0.0.25b/source/renderer/backend/vulkan/Device.h 0ad-0.0.26/source/renderer/backend/vulkan/Device.h --- 0ad-0.0.25b/source/renderer/backend/vulkan/Device.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/backend/vulkan/Device.h 2022-09-23 19:17:02.000000000 +0000 @@ -0,0 +1,105 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_VULKAN_DEVICE +#define INCLUDED_RENDERER_BACKEND_VULKAN_DEVICE + +#include "renderer/backend/IDevice.h" +#include "scriptinterface/ScriptForward.h" + +#include + +typedef struct SDL_Window SDL_Window; + +namespace Renderer +{ + +namespace Backend +{ + +namespace Vulkan +{ + +class CDevice : public IDevice +{ +public: + /** + * Creates the Vulkan device. + */ + static std::unique_ptr Create(SDL_Window* window); + + ~CDevice() override; + + const std::string& GetName() const override { return m_Name; } + const std::string& GetVersion() const override { return m_Version; } + const std::string& GetDriverInformation() const override { return m_DriverInformation; } + const std::vector& GetExtensions() const override { return m_Extensions; } + + void Report(const ScriptRequest& rq, JS::HandleValue settings) override; + + IFramebuffer* GetCurrentBackbuffer() override; + + std::unique_ptr CreateCommandContext() override; + + std::unique_ptr CreateTexture(const char* name, const ITexture::Type type, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) override; + + std::unique_ptr CreateTexture2D(const char* name, + const Format format, const uint32_t width, const uint32_t height, + const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override; + + std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment) override; + + std::unique_ptr CreateFramebuffer( + const char* name, ITexture* colorAttachment, + ITexture* depthStencilAttachment, const CColor& clearColor) override; + + std::unique_ptr CreateBuffer( + const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) override; + + std::unique_ptr CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) override; + + void Present() override; + + bool IsTextureFormatSupported(const Format format) const override; + + bool IsFramebufferFormatSupported(const Format format) const override; + + const Capabilities& GetCapabilities() const override { return m_Capabilities; } + +private: + CDevice(); + + std::string m_Name; + std::string m_Version; + std::string m_DriverInformation; + std::vector m_Extensions; + + Capabilities m_Capabilities{}; +}; + +} // namespace Vulkan + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_VULKAN_DEVICE diff -Nru 0ad-0.0.25b/source/renderer/DebugRenderer.cpp 0ad-0.0.26/source/renderer/DebugRenderer.cpp --- 0ad-0.0.25b/source/renderer/DebugRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/DebugRenderer.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,38 +23,82 @@ #include "graphics/Color.h" #include "graphics/ShaderManager.h" #include "graphics/ShaderProgram.h" -#include "lib/ogl.h" #include "maths/BoundingBoxAligned.h" #include "maths/Brush.h" #include "maths/Matrix3D.h" #include "maths/Vector3D.h" #include "ps/CStrInternStatic.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include -void CDebugRenderer::DrawLine(const CVector3D& from, const CVector3D& to, const CColor& color, const float width) +namespace +{ + +void SetGraphicsPipelineStateFromTechAndColor( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderTechniquePtr& tech, const CColor& color, const bool depthTestEnabled = true, + const bool wireframe = false) +{ + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = tech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthTestEnabled = depthTestEnabled; + if (color.a != 1.0f) + { + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + } + else + pipelineStateDesc.blendState.enabled = false; + if (wireframe) + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); +} + +} // anonymous namespace + +void CDebugRenderer::DrawLine( + const CVector3D& from, const CVector3D& to, const CColor& color, + const float width, const bool depthTestEnabled) { if (from == to) return; - DrawLine({from, to}, color, width); + DrawLine({from, to}, color, width, depthTestEnabled); } -void CDebugRenderer::DrawLine(const std::vector& line, const CColor& color, const float width) +void CDebugRenderer::DrawLine( + const std::vector& line, const CColor& color, + const float width, const bool depthTestEnabled) { -#if CONFIG2_GLES - #warning TODO: implement drawing line for GLES -#else + if (line.size() <= 1) + return; + CShaderTechniquePtr debugLineTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - debugLineTech->BeginPass(); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, debugLineTech, color, depthTestEnabled); + deviceCommandContext->BeginPass(); + + const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); + + Renderer::Backend::IShaderProgram* debugLineShader = debugLineTech->GetShader(); + const CMatrix3D transform = viewCamera.GetViewProjection(); + deviceCommandContext->SetUniform( + debugLineShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + debugLineShader->GetBindingSlot(str_color), color.AsFloatArray()); - CShaderProgramPtr debugLineShader = debugLineTech->GetShader(); - debugLineShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - debugLineShader->Uniform(str_color, color); - - const CVector3D cameraIn = g_Renderer.GetViewCamera().GetOrientation().GetIn(); + const CVector3D cameraIn = viewCamera.GetOrientation().GetIn(); std::vector vertices; vertices.reserve(line.size() * 6 * 3); @@ -83,28 +127,37 @@ #undef ADD - debugLineShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); - debugLineShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); + + deviceCommandContext->Draw(0, vertices.size() / 3); - debugLineTech->EndPass(); -#endif + deviceCommandContext->EndPass(); } void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, const CColor& color) { -#if CONFIG2_GLES - #warning TODO: implement drawing circle for GLES -#else CShaderTechniquePtr debugCircleTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - debugCircleTech->BeginPass(); - - const CCamera& camera = g_Renderer.GetViewCamera(); - - CShaderProgramPtr debugCircleShader = debugCircleTech->GetShader(); - debugCircleShader->Uniform(str_transform, camera.GetViewProjection()); - debugCircleShader->Uniform(str_color, color); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, debugCircleTech, color); + deviceCommandContext->BeginPass(); + + const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); + + Renderer::Backend::IShaderProgram* debugCircleShader = debugCircleTech->GetShader(); + + const CMatrix3D transform = camera.GetViewProjection(); + deviceCommandContext->SetUniform( + debugCircleShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + debugCircleShader->GetBindingSlot(str_color), color.AsFloatArray()); const CVector3D cameraUp = camera.GetOrientation().GetUp(); const CVector3D cameraLeft = camera.GetOrientation().GetLeft(); @@ -115,37 +168,40 @@ vertices.emplace_back((position).Y); \ vertices.emplace_back((position).Z); - ADD(origin) - constexpr size_t segments = 16; for (size_t idx = 0; idx <= segments; ++idx) { const float angle = M_PI * 2.0f * idx / segments; const CVector3D offset = cameraUp * sin(angle) - cameraLeft * cos(angle); + const float nextAngle = M_PI * 2.0f * (idx + 1) / segments; + const CVector3D nextOffset = cameraUp * sin(nextAngle) - cameraLeft * cos(nextAngle); + ADD(origin) ADD(origin + offset * radius) + ADD(origin + nextOffset * radius) } #undef ADD - debugCircleShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); - debugCircleShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 3); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); + + deviceCommandContext->Draw(0, vertices.size() / 3); - debugCircleTech->EndPass(); -#endif + deviceCommandContext->EndPass(); } -void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates) +void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates, bool wireframe) { -#if CONFIG2_GLES -#warning TODO: implement camera frustum for GLES -#else CCamera::Quad nearPoints; CCamera::Quad farPoints; camera.GetViewQuad(camera.GetNearPlane(), nearPoints); camera.GetViewQuad(camera.GetFarPlane(), farPoints); - for(int i = 0; i < 4; i++) + for (int i = 0; i < 4; ++i) { nearPoints[i] = camera.m_Orientation.Transform(nearPoints[i]); farPoints[i] = camera.m_Orientation.Transform(farPoints[i]); @@ -153,11 +209,19 @@ CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - overlayTech->BeginPass(); - - CShaderProgramPtr overlayShader = overlayTech->GetShader(); - overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - overlayShader->Uniform(str_color, color); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, overlayTech, color, true, wireframe); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); + + const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); std::vector vertices; #define ADD(position) \ @@ -169,69 +233,97 @@ ADD(nearPoints[0]); ADD(nearPoints[1]); ADD(nearPoints[2]); + ADD(nearPoints[0]); + ADD(nearPoints[2]); ADD(nearPoints[3]); // Far plane. ADD(farPoints[0]); ADD(farPoints[1]); ADD(farPoints[2]); + ADD(farPoints[0]); + ADD(farPoints[2]); ADD(farPoints[3]); // Intermediate planes. CVector3D intermediatePoints[4]; - for(int i = 0; i < intermediates; ++i) + for (int i = 0; i < intermediates; ++i) { const float t = (i + 1.0f) / (intermediates + 1.0f); - for(int j = 0; j < 4; ++j) + for (int j = 0; j < 4; ++j) intermediatePoints[j] = nearPoints[j] * t + farPoints[j] * (1.0f - t); ADD(intermediatePoints[0]); ADD(intermediatePoints[1]); ADD(intermediatePoints[2]); + ADD(intermediatePoints[0]); + ADD(intermediatePoints[2]); ADD(intermediatePoints[3]); } - overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); - overlayShader->AssertPointersBound(); - glDrawArrays(GL_QUADS, 0, vertices.size() / 3); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); + + deviceCommandContext->Draw(0, vertices.size() / 3); vertices.clear(); // Connection lines. - ADD(nearPoints[0]); - ADD(farPoints[0]); - ADD(nearPoints[1]); - ADD(farPoints[1]); - ADD(nearPoints[2]); - ADD(farPoints[2]); - ADD(nearPoints[3]); - ADD(farPoints[3]); - ADD(nearPoints[0]); - ADD(farPoints[0]); + for (int i = 0; i < 4; ++i) + { + const int nextI = (i + 1) % 4; + ADD(nearPoints[i]); + ADD(farPoints[nextI]); + ADD(farPoints[i]); + ADD(nearPoints[i]); + ADD(nearPoints[nextI]); + ADD(farPoints[nextI]); + } + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); - overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); - overlayShader->AssertPointersBound(); - glDrawArrays(GL_QUAD_STRIP, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); #undef ADD - overlayTech->EndPass(); -#endif + deviceCommandContext->EndPass(); } -void CDebugRenderer::DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color) +void CDebugRenderer::DrawBoundingBox( + const CBoundingBoxAligned& boundingBox, const CColor& color, + bool wireframe) { - DrawBoundingBox(boundingBox, color, g_Renderer.GetViewCamera().GetViewProjection()); + DrawBoundingBox( + boundingBox, color, + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(), wireframe); } -void CDebugRenderer::DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform) +void CDebugRenderer::DrawBoundingBox( + const CBoundingBoxAligned& boundingBox, const CColor& color, + const CMatrix3D& transform, bool wireframe) { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); - - CShaderProgramPtr shader = shaderTech->GetShader(); - shader->Uniform(str_color, color); - shader->Uniform(str_transform, transform); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, shaderTech, color, true, wireframe); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_color), color.AsFloatArray()); std::vector data; @@ -240,56 +332,6 @@ ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z); #define ADD_PT(u_, v_, x, y, z) \ STMT(int u = u_; int v = v_; \ - data.push_back(u); \ - data.push_back(v); \ - data.push_back(boundingBox[x].X); \ - data.push_back(boundingBox[y].Y); \ - data.push_back(boundingBox[z].Z); \ - ) - - ADD_FACE(u, v, 0); - ADD_FACE(0, u, v); - ADD_FACE(u, 0, 1-v); - ADD_FACE(u, 1-v, 1); - ADD_FACE(1, u, 1-v); - ADD_FACE(u, 1, v); - -#undef ADD_FACE - - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); - shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); - - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6*6); - - shaderTech->EndPass(); -} - -void CDebugRenderer::DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CColor& color) -{ - DrawBoundingBoxOutline(boundingBox, color, g_Renderer.GetViewCamera().GetViewProjection()); -} - -void CDebugRenderer::DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform) -{ - CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); - - CShaderProgramPtr shader = shaderTech->GetShader(); - shader->Uniform(str_color, color); - shader->Uniform(str_transform, transform); - - std::vector data; - -#define ADD_FACE(x, y, z) \ - ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); \ - ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \ - ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); \ - ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z); -#define ADD_PT(u_, v_, x, y, z) \ - STMT(int u = u_; int v = v_; \ - data.push_back(u); \ - data.push_back(v); \ data.push_back(boundingBox[x].X); \ data.push_back(boundingBox[y].Y); \ data.push_back(boundingBox[z].Z); \ @@ -304,23 +346,34 @@ #undef ADD_FACE - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); - shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, data.data(), data.size() * sizeof(data[0])); - shader->AssertPointersBound(); - glDrawArrays(GL_LINES, 0, 6*8); + deviceCommandContext->Draw(0, 6 * 6); - shaderTech->EndPass(); + deviceCommandContext->EndPass(); } -void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color) +void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wireframe) { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); - - CShaderProgramPtr shader = shaderTech->GetShader(); - shader->Uniform(str_color, color); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, shaderTech, color, true, wireframe); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + + const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_color), color.AsFloatArray()); std::vector data; @@ -329,8 +382,6 @@ #define ADD_VERT(a) \ STMT( \ - data.push_back(u); \ - data.push_back(v); \ data.push_back(brush.GetVertices()[faces[i][a]].X); \ data.push_back(brush.GetVertices()[faces[i][a]].Y); \ data.push_back(brush.GetVertices()[faces[i][a]].Z); \ @@ -341,8 +392,6 @@ // Triangulate into (0,1,2), (0,2,3), ... for (size_t j = 1; j < faces[i].size() - 2; ++j) { - float u = 0; - float v = 0; ADD_VERT(0); ADD_VERT(j); ADD_VERT(j+1); @@ -351,56 +400,15 @@ #undef ADD_VERT - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); - shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, data.data(), data.size() * sizeof(data[0])); - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, data.size() / 5); + deviceCommandContext->Draw(0, data.size() / 5); - shaderTech->EndPass(); + deviceCommandContext->EndPass(); } -void CDebugRenderer::DrawBrushOutline(const CBrush& brush, const CColor& color) -{ - CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); - - CShaderProgramPtr shader = shaderTech->GetShader(); - shader->Uniform(str_color, color); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - - std::vector data; - - std::vector> faces; - brush.GetFaces(faces); - -#define ADD_VERT(a) \ - STMT( \ - data.push_back(u); \ - data.push_back(v); \ - data.push_back(brush.GetVertices()[faces[i][a]].X); \ - data.push_back(brush.GetVertices()[faces[i][a]].Y); \ - data.push_back(brush.GetVertices()[faces[i][a]].Z); \ - ) - - for (size_t i = 0; i < faces.size(); ++i) - { - for (size_t j = 0; j < faces[i].size() - 1; ++j) - { - float u = 0; - float v = 0; - ADD_VERT(j); - ADD_VERT(j+1); - } - } - -#undef ADD_VERT - - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); - shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); - - shader->AssertPointersBound(); - glDrawArrays(GL_LINES, 0, data.size() / 5); - - shaderTech->EndPass(); -} diff -Nru 0ad-0.0.25b/source/renderer/DebugRenderer.h 0ad-0.0.26/source/renderer/DebugRenderer.h --- 0ad-0.0.25b/source/renderer/DebugRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/DebugRenderer.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,8 +36,10 @@ /** * Render the line in world space. */ - void DrawLine(const CVector3D& from, const CVector3D& to, const CColor& color, const float width); - void DrawLine(const std::vector& line, const CColor& color, const float width); + void DrawLine(const CVector3D& from, const CVector3D& to, + const CColor& color, const float width, const bool depthTestEnabled = true); + void DrawLine(const std::vector& line, + const CColor& color, const float width, const bool depthTestEnabled = true); /** * Render the circle in world space oriented to the view camera. @@ -50,29 +52,18 @@ * @param intermediates determines how many intermediate distance planes should * be hinted at between the near and far planes */ - void DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates = 0); + void DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates = 0, bool wireframe = false); /** * Render the surfaces of the bound box as triangles. */ - void DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color); - void DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform); - - /** - * Render the outline of the bound box as lines. - */ - void DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CColor& color); - void DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform); + void DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color, bool wireframe = false); + void DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform, bool wireframe = false); /** * Render the surfaces of the brush as triangles. */ - void DrawBrush(const CBrush& brush, const CColor& color); - - /** - * Render the outline of the brush as lines. - */ - void DrawBrushOutline(const CBrush& brush, const CColor& color); + void DrawBrush(const CBrush& brush, const CColor& color, bool wireframe = false); }; #endif // INCLUDED_DEBUGRENDERER diff -Nru 0ad-0.0.25b/source/renderer/DecalRData.cpp 0ad-0.0.26/source/renderer/DecalRData.cpp --- 0ad-0.0.25b/source/renderer/DecalRData.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/DecalRData.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,7 +36,6 @@ #include "simulation2/Simulation2.h" #include -#include // TODO: Currently each decal is a separate CDecalRData. We might want to use // lots of decals for special effects like shadows, footprints, etc, in which @@ -49,7 +48,8 @@ struct SDecalBatch { CDecalRData* decal; - CShaderTechniquePtr shaderTech; + CStrIntern shaderEffect; + CShaderDefines shaderDefines; CVertexBuffer::VBChunk* vertices; CVertexBuffer::VBChunk* indices; }; @@ -58,8 +58,14 @@ { bool operator()(const SDecalBatch& lhs, const SDecalBatch& rhs) const { - if (lhs.shaderTech != rhs.shaderTech) - return lhs.shaderTech < rhs.shaderTech; + if (lhs.shaderEffect != rhs.shaderEffect) + return lhs.shaderEffect < rhs.shaderEffect; + if (lhs.shaderDefines != rhs.shaderDefines) + return lhs.shaderDefines < rhs.shaderDefines; + const CMaterial& lhsMaterial = lhs.decal->GetDecal()->m_Decal.m_Material; + const CMaterial& rhsMaterial = rhs.decal->GetDecal()->m_Decal.m_Material; + if (lhsMaterial.GetDiffuseTexture() != rhsMaterial.GetDiffuseTexture()) + return lhsMaterial.GetDiffuseTexture() < rhsMaterial.GetDiffuseTexture(); if (lhs.vertices->m_Owner != rhs.vertices->m_Owner) return lhs.vertices->m_Owner < rhs.vertices->m_Owner; if (lhs.indices->m_Owner != rhs.indices->m_Owner) @@ -89,9 +95,11 @@ } void CDecalRData::RenderDecals( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const std::vector& decals, const CShaderDefines& context, ShadowMap* shadow) { PROFILE3("render terrain decals"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain decals"); using Arena = Allocators::DynamicArena<256 * KiB>; @@ -106,7 +114,7 @@ for (CDecalRData* decal : decals) { - CMaterial &material = decal->m_Decal->m_Decal.m_Material; + CMaterial& material = decal->m_Decal->m_Decal.m_Material; if (material.GetShaderEffect().empty()) { @@ -114,21 +122,13 @@ continue; } - CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect( - material.GetShaderEffect(), contextDecal, material.GetShaderDefines(0)); - if (!techBase) - { - LOGERROR("Terrain renderer failed to load shader effect (%s)\n", - material.GetShaderEffect().string().c_str()); - continue; - } - if (material.GetSamplers().empty() || !decal->m_VBDecals || !decal->m_VBDecalsIndices) continue; SDecalBatch batch; batch.decal = decal; - batch.shaderTech = techBase; + batch.shaderEffect = material.GetShaderEffect(); + batch.shaderDefines = material.GetShaderDefines(); batch.vertices = decal->m_VBDecals.Get(); batch.indices = decal->m_VBDecalsIndices.Get(); @@ -140,23 +140,53 @@ std::sort(batches.begin(), batches.end(), SDecalBatchComparator()); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - CVertexBuffer* lastIB = nullptr; for (auto itTechBegin = batches.begin(), itTechEnd = batches.begin(); itTechBegin != batches.end(); itTechBegin = itTechEnd) { - while (itTechEnd != batches.end() && itTechBegin->shaderTech == itTechEnd->shaderTech) + while (itTechEnd != batches.end() && + itTechBegin->shaderEffect == itTechEnd->shaderEffect && + itTechBegin->shaderDefines == itTechEnd->shaderDefines) + { ++itTechEnd; + } - const CShaderTechniquePtr& techBase = itTechBegin->shaderTech; - const int numPasses = techBase->GetNumPasses(); + CShaderDefines defines = contextDecal; + defines.SetMany(itTechBegin->shaderDefines); + CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect( + itTechBegin->shaderEffect, defines); + if (!techBase) + { + LOGERROR("Terrain renderer failed to load shader effect (%s)\n", + itTechBegin->shaderEffect.c_str()); + continue; + } + const int numPasses = techBase->GetNumPasses(); for (int pass = 0; pass < numPasses; ++pass) { - techBase->BeginPass(pass); - const CShaderProgramPtr& shader = techBase->GetShader(pass); - TerrainRenderer::PrepareShader(shader, shadow); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + techBase->GetGraphicsPipelineStateDesc(pass); + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + pipelineStateDesc.depthStencilState.depthWriteEnabled = false; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); + TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); + + CColor shadingColor(1.0f, 1.0f, 1.0f, 1.0f); + const int32_t shadingColorBindingSlot = + shader->GetBindingSlot(str_shadingColor); + deviceCommandContext->SetUniform( + shadingColorBindingSlot, shadingColor.AsFloatArray()); + + CShaderUniforms currentStaticUniforms; CVertexBuffer* lastVB = nullptr; for (auto itDecal = itTechBegin; itDecal != itTechEnd; ++itDecal) @@ -167,9 +197,19 @@ const CMaterial::SamplersVector& samplers = material.GetSamplers(); for (const CMaterial::TextureSampler& sampler : samplers) - shader->BindTexture(sampler.Name, sampler.Sampler); + sampler.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext); + for (const CMaterial::TextureSampler& sampler : samplers) + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(sampler.Name), + sampler.Sampler->GetBackendTexture()); + } - material.GetStaticUniforms().BindUniforms(shader); + if (currentStaticUniforms != material.GetStaticUniforms()) + { + currentStaticUniforms = material.GetStaticUniforms(); + material.GetStaticUniforms().BindUniforms(deviceCommandContext, shader); + } // TODO: Need to handle floating decals correctly. In particular, we need // to render non-floating before water and floating after water (to get @@ -178,47 +218,59 @@ // TerrainRenderer. // Also, need to mark the decals as dirty when water height changes. - // glDisable(GL_TEXTURE_2D); // m_Decal->GetBounds().Render(); - // glEnable(GL_TEXTURE_2D); - shader->Uniform(str_shadingColor, decal->m_Decal->GetShadingColor()); + if (shadingColor != decal->m_Decal->GetShadingColor()) + { + shadingColor = decal->m_Decal->GetShadingColor(); + deviceCommandContext->SetUniform( + shadingColorBindingSlot, shadingColor.AsFloatArray()); + } if (lastVB != batch.vertices->m_Owner) { lastVB = batch.vertices->m_Owner; - const GLsizei stride = sizeof(SDecalVertex); - SDecalVertex* base = (SDecalVertex*)batch.vertices->m_Owner->Bind(); - shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); - shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, &base->m_UV[0]); - } + batch.vertices->m_Owner->UploadIfNeeded(deviceCommandContext); - shader->AssertPointersBound(); + const uint32_t stride = sizeof(SDecalVertex); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SDecalVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SDecalVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SDecalVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, batch.vertices->m_Owner->GetBuffer()); + } if (lastIB != batch.indices->m_Owner) { lastIB = batch.indices->m_Owner; - batch.indices->m_Owner->Bind(); + batch.indices->m_Owner->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(batch.indices->m_Owner->GetBuffer()); } - u8* indexBase = nullptr; - if (!g_Renderer.m_SkipSubmit) - glDrawElements(GL_TRIANGLES, batch.indices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16) * (batch.indices->m_Index)); + deviceCommandContext->DrawIndexed(batch.indices->m_Index, batch.indices->m_Count, 0); // bump stats g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += batch.indices->m_Count / 3; } - techBase->EndPass(); + deviceCommandContext->EndPass(); } } - - CVertexBuffer::Unbind(); - - glDisable(GL_BLEND); } void CDecalRData::BuildVertexData() @@ -235,7 +287,7 @@ m_Decal->CalcVertexExtents(i0, j0, i1, j1); // Currently CalcVertexExtents might return empty rectangle, that means // we can't render it. - if (i1 <= i0 && j1 <= j0) + if (i1 <= i0 || j1 <= j0) { // We have nothing to render. m_VBDecals.Reset(); @@ -272,7 +324,11 @@ } if (!m_VBDecals || m_VBDecals->m_Count != vertices.size()) - m_VBDecals = g_VBMan.AllocateChunk(sizeof(SDecalVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); + { + m_VBDecals = g_VBMan.AllocateChunk( + sizeof(SDecalVertex), vertices.size(), + Renderer::Backend::IBuffer::Type::VERTEX, false); + } m_VBDecals->m_Owner->UpdateChunkVertices(m_VBDecals.Get(), vertices.data()); std::vector indices((i1 - i0) * (j1 - j0) * 6); @@ -310,6 +366,10 @@ // Construct vertex buffer. if (!m_VBDecalsIndices || m_VBDecalsIndices->m_Count != indices.size()) - m_VBDecalsIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); + { + m_VBDecalsIndices = g_VBMan.AllocateChunk( + sizeof(u16), indices.size(), + Renderer::Backend::IBuffer::Type::INDEX, false); + } m_VBDecalsIndices->m_Owner->UpdateChunkVertices(m_VBDecalsIndices.Get(), indices.data()); } diff -Nru 0ad-0.0.25b/source/renderer/DecalRData.h 0ad-0.0.26/source/renderer/DecalRData.h --- 0ad-0.0.25b/source/renderer/DecalRData.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/DecalRData.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,8 +21,11 @@ #include "graphics/RenderableObject.h" #include "maths/Vector2D.h" #include "maths/Vector3D.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/VertexBufferManager.h" +#include + class CModelDecal; class CShaderDefines; class CSimulation2; @@ -37,6 +40,7 @@ void Update(CSimulation2* simulation); static void RenderDecals( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const std::vector& decals, const CShaderDefines& context, ShadowMap* shadow); CModelDecal* GetDecal() { return m_Decal; } diff -Nru 0ad-0.0.25b/source/renderer/HWLightingModelRenderer.cpp 0ad-0.0.26/source/renderer/HWLightingModelRenderer.cpp --- 0ad-0.0.25b/source/renderer/HWLightingModelRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/HWLightingModelRenderer.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,18 +17,16 @@ #include "precompiled.h" -#include "lib/bits.h" -#include "lib/ogl.h" -#include "lib/sysdep/rtl.h" -#include "maths/Vector3D.h" +#include "renderer/HWLightingModelRenderer.h" #include "graphics/Color.h" #include "graphics/LightEnv.h" #include "graphics/Model.h" #include "graphics/ModelDef.h" #include "graphics/ShaderProgram.h" - -#include "renderer/HWLightingModelRenderer.h" +#include "lib/bits.h" +#include "lib/sysdep/rtl.h" +#include "maths/Vector3D.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" #include "renderer/VertexArray.h" @@ -50,19 +48,19 @@ ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef) - : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW) + : m_IndexArray(false), + m_Array(Renderer::Backend::IBuffer::Type::VERTEX, false) { size_t numVertices = mdef->GetNumVertices(); m_UVs.resize(mdef->GetNumUVsPerVertex()); for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); ++i) { - m_UVs[i].type = GL_FLOAT; - m_UVs[i].elems = 2; + m_UVs[i].format = Renderer::Backend::Format::R32G32_SFLOAT; m_Array.AddAttribute(&m_UVs[i]); } - m_Array.SetNumVertices(numVertices); + m_Array.SetNumberOfVertices(numVertices); m_Array.Layout(); for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); ++i) @@ -74,7 +72,7 @@ m_Array.Upload(); m_Array.FreeBackingStore(); - m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3); + m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces()*3); m_IndexArray.Layout(); ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); m_IndexArray.Upload(); @@ -91,7 +89,10 @@ VertexArray::Attribute m_Position; VertexArray::Attribute m_Normal; - ShaderModel(const void* key) : CModelRData(key), m_Array(GL_DYNAMIC_DRAW) { } + ShaderModel(const void* key) + : CModelRData(key), + m_Array(Renderer::Backend::IBuffer::Type::VERTEX, true) + {} }; @@ -132,15 +133,13 @@ // Positions and normals must be 16-byte aligned for SSE writes. - shadermodel->m_Position.type = GL_FLOAT; - shadermodel->m_Position.elems = 4; + shadermodel->m_Position.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT; shadermodel->m_Array.AddAttribute(&shadermodel->m_Position); - shadermodel->m_Normal.type = GL_FLOAT; - shadermodel->m_Normal.elems = 4; + shadermodel->m_Normal.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT; shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal); - shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices()); + shadermodel->m_Array.SetNumberOfVertices(mdef->GetNumVertices()); shadermodel->m_Array.Layout(); // Verify alignment @@ -174,71 +173,83 @@ // Setup one rendering pass -void ShaderModelVertexRenderer::BeginPass(int streamflags) +void ShaderModelVertexRenderer::BeginPass() { - ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_NORMAL))); } // Cleanup one rendering pass -void ShaderModelVertexRenderer::EndPass(int UNUSED(streamflags)) +void ShaderModelVertexRenderer::EndPass( + Renderer::Backend::IDeviceCommandContext* UNUSED(deviceCommandContext)) { - CVertexBuffer::Unbind(); } - // Prepare UV coordinates for this modeldef -void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) +void ShaderModelVertexRenderer::PrepareModelDef( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CModelDef& def) { m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m); ENSURE(m->shadermodeldef); - u8* base = m->shadermodeldef->m_Array.Bind(); - GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride(); + m->shadermodeldef->m_Array.UploadIfNeeded(deviceCommandContext); - if (streamflags & STREAM_UV0) - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m->shadermodeldef->m_UVs[0].offset); + const uint32_t stride = m->shadermodeldef->m_Array.GetStride(); + const uint32_t firstVertexOffset = m->shadermodeldef->m_Array.GetOffset() * stride; - if ((streamflags & STREAM_UV1) && def.GetNumUVsPerVertex() >= 2) - shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, base + m->shadermodeldef->m_UVs[1].offset); -} + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + m->shadermodeldef->m_UVs[0].format, + firstVertexOffset + m->shadermodeldef->m_UVs[0].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + if (def.GetNumUVsPerVertex() >= 2) + { + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + m->shadermodeldef->m_UVs[1].format, + firstVertexOffset + m->shadermodeldef->m_UVs[1].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + } + deviceCommandContext->SetVertexBuffer(0, m->shadermodeldef->m_Array.GetBuffer()); +} // Render one model -void ShaderModelVertexRenderer::RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) +void ShaderModelVertexRenderer::RenderModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* UNUSED(shader), CModel* model, CModelRData* data) { const CModelDefPtr& mdldef = model->GetModelDef(); ShaderModel* shadermodel = static_cast(data); - u8* base = shadermodel->m_Array.Bind(); - GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride(); + shadermodel->m_Array.UploadIfNeeded(deviceCommandContext); + m->shadermodeldef->m_IndexArray.UploadIfNeeded(deviceCommandContext); - u8* indexBase = m->shadermodeldef->m_IndexArray.Bind(); + const uint32_t stride = shadermodel->m_Array.GetStride(); + const uint32_t firstVertexOffset = shadermodel->m_Array.GetOffset() * stride; - if (streamflags & STREAM_POS) - shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + shadermodel->m_Position.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + shadermodel->m_Normal.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBuffer(1, shadermodel->m_Array.GetBuffer()); + deviceCommandContext->SetIndexBuffer(m->shadermodeldef->m_IndexArray.GetBuffer()); - if (streamflags & STREAM_NORMAL) - shader->NormalPointer(GL_FLOAT, stride, base + shadermodel->m_Normal.offset); + // Render the lot. + const size_t numberOfFaces = mdldef->GetNumFaces(); - shader->AssertPointersBound(); - - // render the lot - size_t numFaces = mdldef->GetNumFaces(); - - if (!g_Renderer.m_SkipSubmit) - { - // Draw with DrawRangeElements where available, since it might be more efficient -#if CONFIG2_GLES - glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase); -#else - pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1, - (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase); -#endif - } + deviceCommandContext->DrawIndexedInRange( + m->shadermodeldef->m_IndexArray.GetOffset(), numberOfFaces * 3, 0, mdldef->GetNumVertices() - 1); - // bump stats + // Bump stats. g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_ModelTris += numFaces; + g_Renderer.m_Stats.m_ModelTris += numberOfFaces; } diff -Nru 0ad-0.0.25b/source/renderer/HWLightingModelRenderer.h 0ad-0.0.26/source/renderer/HWLightingModelRenderer.h --- 0ad-0.0.25b/source/renderer/HWLightingModelRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/HWLightingModelRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,14 +36,18 @@ ShaderModelVertexRenderer(); ~ShaderModelVertexRenderer(); - // Implementations - CModelRData* CreateModelData(const void* key, CModel* model); - void UpdateModelData(CModel* model, CModelRData* data, int updateflags); - - void BeginPass(int streamflags); - void EndPass(int streamflags); - void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); - void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); + CModelRData* CreateModelData(const void* key, CModel* model) override; + void UpdateModelData(CModel* model, CModelRData* data, int updateflags) override; + + void BeginPass() override; + void EndPass( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) override; + void PrepareModelDef( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CModelDef& def) override; + void RenderModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* data) override; protected: struct ShaderModelRendererInternals; diff -Nru 0ad-0.0.25b/source/renderer/InstancingModelRenderer.cpp 0ad-0.0.26/source/renderer/InstancingModelRenderer.cpp --- 0ad-0.0.25b/source/renderer/InstancingModelRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/InstancingModelRenderer.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,7 +22,6 @@ #include "graphics/LightEnv.h" #include "graphics/Model.h" #include "graphics/ModelDef.h" -#include "lib/ogl.h" #include "maths/Vector3D.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" @@ -56,34 +55,36 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateTangents) - : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW) + : m_IndexArray(false), m_Array(Renderer::Backend::IBuffer::Type::VERTEX, false) { size_t numVertices = mdef->GetNumVertices(); - m_Position.type = GL_FLOAT; - m_Position.elems = 3; + m_Position.format = Renderer::Backend::Format::R32G32B32_SFLOAT; m_Array.AddAttribute(&m_Position); - m_Normal.type = GL_FLOAT; - m_Normal.elems = 3; + m_Normal.format = Renderer::Backend::Format::R32G32B32_SFLOAT; m_Array.AddAttribute(&m_Normal); m_UVs.resize(mdef->GetNumUVsPerVertex()); for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); i++) { - m_UVs[i].type = GL_FLOAT; - m_UVs[i].elems = 2; + m_UVs[i].format = Renderer::Backend::Format::R32G32_SFLOAT; m_Array.AddAttribute(&m_UVs[i]); } if (gpuSkinning) { - m_BlendJoints.type = GL_UNSIGNED_BYTE; - m_BlendJoints.elems = 4; + // We can't use a lot of bones because it costs uniform memory. Recommended + // number of bones per model is 32. + // Add 1 to NumBones because of the special 'root' bone. + if (mdef->GetNumBones() + 1 > 64) + LOGERROR("Model '%s' has too many bones %zu/64", mdef->GetName().string8().c_str(), mdef->GetNumBones() + 1); + ENSURE(mdef->GetNumBones() + 1 <= 64); + + m_BlendJoints.format = Renderer::Backend::Format::R8G8B8A8_UINT; m_Array.AddAttribute(&m_BlendJoints); - m_BlendWeights.type = GL_UNSIGNED_BYTE; - m_BlendWeights.elems = 4; + m_BlendWeights.format = Renderer::Backend::Format::R8G8B8A8_UNORM; m_Array.AddAttribute(&m_BlendWeights); } @@ -91,8 +92,7 @@ { // Generate tangents for the geometry:- - m_Tangent.type = GL_FLOAT; - m_Tangent.elems = 4; + m_Tangent.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT; m_Array.AddAttribute(&m_Tangent); // floats per vertex; position + normal + tangent + UV*sets [+ GPUskinning] @@ -122,7 +122,7 @@ // Copy the model data to graphics memory:- - m_Array.SetNumVertices(numVertices2); + m_Array.SetNumberOfVertices(numVertices2); m_Array.Layout(); VertexArrayIterator Position = m_Position.GetIterator(); @@ -174,7 +174,7 @@ m_Array.Upload(); m_Array.FreeBackingStore(); - m_IndexArray.SetNumVertices(mdef->GetNumFaces() * 3); + m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces() * 3); m_IndexArray.Layout(); VertexArrayIterator Indices = m_IndexArray.GetIterator(); @@ -196,7 +196,7 @@ { // Upload model without calculating tangents:- - m_Array.SetNumVertices(numVertices); + m_Array.SetNumberOfVertices(numVertices); m_Array.Layout(); VertexArrayIterator Position = m_Position.GetIterator(); @@ -228,7 +228,7 @@ m_Array.Upload(); m_Array.FreeBackingStore(); - m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3); + m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces()*3); m_IndexArray.Layout(); ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); m_IndexArray.Upload(); @@ -294,62 +294,87 @@ // Setup one rendering pass. -void InstancingModelRenderer::BeginPass(int streamflags) +void InstancingModelRenderer::BeginPass() { - ENSURE(streamflags == (streamflags & (STREAM_POS|STREAM_NORMAL|STREAM_UV0|STREAM_UV1))); } // Cleanup rendering pass. -void InstancingModelRenderer::EndPass(int UNUSED(streamflags)) +void InstancingModelRenderer::EndPass( + Renderer::Backend::IDeviceCommandContext* UNUSED(deviceCommandContext)) { - CVertexBuffer::Unbind(); } - // Prepare UV coordinates for this modeldef -void InstancingModelRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) +void InstancingModelRenderer::PrepareModelDef( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CModelDef& def) { m->imodeldef = (IModelDef*)def.GetRenderData(m); ENSURE(m->imodeldef); + m->imodeldef->m_Array.UploadIfNeeded(deviceCommandContext); + m->imodeldef->m_IndexArray.UploadIfNeeded(deviceCommandContext); - u8* base = m->imodeldef->m_Array.Bind(); - GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride(); + deviceCommandContext->SetIndexBuffer(m->imodeldef->m_IndexArray.GetBuffer()); - m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind(); + const uint32_t stride = m->imodeldef->m_Array.GetStride(); + const uint32_t firstVertexOffset = m->imodeldef->m_Array.GetOffset() * stride; - if (streamflags & STREAM_POS) - shader->VertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m->imodeldef->m_Position.format, + firstVertexOffset + m->imodeldef->m_Position.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::NORMAL, + m->imodeldef->m_Normal.format, + firstVertexOffset + m->imodeldef->m_Normal.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - if (streamflags & STREAM_NORMAL) - shader->NormalPointer(GL_FLOAT, stride, base + m->imodeldef->m_Normal.offset); - - if (m->calculateTangents) - shader->VertexAttribPointer(str_a_tangent, 4, GL_FLOAT, GL_FALSE, stride, base + m->imodeldef->m_Tangent.offset); - - // The last UV set is STREAM_UV3 - for (size_t uv = 0; uv < 4; ++uv) - if (streamflags & (STREAM_UV0 << uv)) - { - if (def.GetNumUVsPerVertex() >= uv + 1) - shader->TexCoordPointer(GL_TEXTURE0 + uv, 2, GL_FLOAT, stride, base + m->imodeldef->m_UVs[uv].offset); - else - ONCE(LOGERROR("Model '%s' has no UV%d set.", def.GetName().string8().c_str(), uv)); - } + constexpr size_t MAX_UV = 2; + for (size_t uv = 0; uv < std::min(MAX_UV, def.GetNumUVsPerVertex()); ++uv) + { + const Renderer::Backend::VertexAttributeStream stream = + static_cast( + static_cast(Renderer::Backend::VertexAttributeStream::UV0) + uv); + deviceCommandContext->SetVertexAttributeFormat( + stream, m->imodeldef->m_UVs[uv].format, + firstVertexOffset + m->imodeldef->m_UVs[uv].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + } - // GPU skinning requires extra attributes to compute positions/normals + // GPU skinning requires extra attributes to compute positions/normals. if (m->gpuSkinning) { - shader->VertexAttribPointer(str_a_skinJoints, 4, GL_UNSIGNED_BYTE, GL_FALSE, stride, base + m->imodeldef->m_BlendJoints.offset); - shader->VertexAttribPointer(str_a_skinWeights, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, base + m->imodeldef->m_BlendWeights.offset); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV2, + m->imodeldef->m_BlendJoints.format, + firstVertexOffset + m->imodeldef->m_BlendJoints.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV3, + m->imodeldef->m_BlendWeights.format, + firstVertexOffset + m->imodeldef->m_BlendWeights.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + } + + if (m->calculateTangents) + { + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV4, + m->imodeldef->m_Tangent.format, + firstVertexOffset + m->imodeldef->m_Tangent.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } - shader->AssertPointersBound(); + deviceCommandContext->SetVertexBuffer(0, m->imodeldef->m_Array.GetBuffer()); } // Render one model -void InstancingModelRenderer::RenderModel(const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data)) +void InstancingModelRenderer::RenderModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* UNUSED(data)) { const CModelDefPtr& mdldef = model->GetModelDef(); @@ -357,29 +382,20 @@ { // Bind matrices for current animation state. // Add 1 to NumBones because of the special 'root' bone. - // HACK: NVIDIA drivers return uniform name with "[0]", Intel Windows drivers without; - // try uploading both names since one of them should work, and this is easier than - // canonicalising the uniform names in CShaderProgramGLSL - shader->Uniform(str_skinBlendMatrices_0, mdldef->GetNumBones() + 1, model->GetAnimatedBoneMatrices()); - shader->Uniform(str_skinBlendMatrices, mdldef->GetNumBones() + 1, model->GetAnimatedBoneMatrices()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_skinBlendMatrices), + PS::span( + model->GetAnimatedBoneMatrices()[0]._data, + model->GetAnimatedBoneMatrices()[0].AsFloatArray().size() * (mdldef->GetNumBones() + 1))); } - // render the lot - size_t numFaces = mdldef->GetNumFaces(); + // Render the lot. + const size_t numberOfFaces = mdldef->GetNumFaces(); - if (!g_Renderer.m_SkipSubmit) - { - // Draw with DrawRangeElements where available, since it might be more efficient -#if CONFIG2_GLES - glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase); -#else - pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)m->imodeldef->m_Array.GetNumVertices()-1, - (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase); -#endif - } + deviceCommandContext->DrawIndexedInRange( + m->imodeldef->m_IndexArray.GetOffset(), numberOfFaces * 3, 0, m->imodeldef->m_Array.GetNumberOfVertices() - 1); - // bump stats + // Bump stats. g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_ModelTris += numFaces; - + g_Renderer.m_Stats.m_ModelTris += numberOfFaces; } diff -Nru 0ad-0.0.25b/source/renderer/InstancingModelRenderer.h 0ad-0.0.26/source/renderer/InstancingModelRenderer.h --- 0ad-0.0.25b/source/renderer/InstancingModelRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/InstancingModelRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,13 +39,17 @@ ~InstancingModelRenderer(); // Implementations - CModelRData* CreateModelData(const void* key, CModel* model); - void UpdateModelData(CModel* model, CModelRData* data, int updateflags); + CModelRData* CreateModelData(const void* key, CModel* model) override; + void UpdateModelData(CModel* model, CModelRData* data, int updateflags) override; - void BeginPass(int streamflags); - void EndPass(int streamflags); - void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); - void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); + void BeginPass() override; + void EndPass( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) override; + void PrepareModelDef( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CModelDef& def) override; + void RenderModel(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* data) override; protected: InstancingModelRendererInternals* m; diff -Nru 0ad-0.0.25b/source/renderer/MikktspaceWrap.cpp 0ad-0.0.26/source/renderer/MikktspaceWrap.cpp --- 0ad-0.0.25b/source/renderer/MikktspaceWrap.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/MikktspaceWrap.cpp 2022-08-21 12:45:26.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -81,11 +81,12 @@ { const MikkTSpace* userData = GetUserDataFromContext(pContext); const SModelFace& face = userData->m_Model->GetFaces()[iFace]; - const SModelVertex& v = userData->m_Model->GetVertices()[face.m_Verts[iVert]]; + const size_t numberOfUVPerVertex = userData->m_Model->GetNumUVsPerVertex(); // The tangents are calculated according to the 'default' UV set - fvTexcOut[0] = v.m_UVs[0]; - fvTexcOut[1] = 1.0 - v.m_UVs[1]; + const CVector2D& uv = userData->m_Model->GetUVCoordinates()[face.m_Verts[iVert] * numberOfUVPerVertex]; + fvTexcOut[0] = uv.X; + fvTexcOut[1] = 1.0 - uv.Y; } @@ -121,11 +122,12 @@ } } - size_t numUVsPerVertex = userData->m_Model->GetNumUVsPerVertex(); - for (size_t UVset = 0; UVset < numUVsPerVertex; ++UVset) + const size_t numberOfUVPerVertex = userData->m_Model->GetNumUVsPerVertex(); + for (size_t UVset = 0; UVset < numberOfUVPerVertex; ++UVset) { - userData->m_NewVertices.push_back(vertex.m_UVs[UVset * 2]); - userData->m_NewVertices.push_back(1.f - vertex.m_UVs[UVset * 2 + 1]); + const CVector2D& uv = userData->m_Model->GetUVCoordinates()[face.m_Verts[iVert] * numberOfUVPerVertex + UVset]; + userData->m_NewVertices.push_back(uv.X); + userData->m_NewVertices.push_back(1.f - uv.Y); } } diff -Nru 0ad-0.0.25b/source/renderer/MikktspaceWrap.h 0ad-0.0.26/source/renderer/MikktspaceWrap.h --- 0ad-0.0.25b/source/renderer/MikktspaceWrap.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/MikktspaceWrap.h 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,8 +24,6 @@ #include -class CVector3D; - class MikkTSpace { diff -Nru 0ad-0.0.25b/source/renderer/ModelRenderer.cpp 0ad-0.0.26/source/renderer/ModelRenderer.cpp --- 0ad-0.0.25b/source/renderer/ModelRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ModelRenderer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,7 +27,6 @@ #include "lib/allocators/DynamicArena.h" #include "lib/allocators/STLAllocators.h" #include "lib/hash.h" -#include "lib/ogl.h" #include "maths/Vector3D.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" @@ -38,6 +37,7 @@ #include "renderer/ModelVertexRenderer.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" +#include "renderer/SceneRenderer.h" #include "renderer/SkyManager.h" #include "renderer/TimeManager.h" #include "renderer/WaterManager.h" @@ -114,7 +114,7 @@ CModelDefPtr mdef = model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + const CLightEnv& lightEnv = g_Renderer.GetSceneRenderer().GetLightEnv(); CColor shadingColor = model->GetShadingColor(); for (size_t j = 0; j < numVertices; ++j) @@ -141,13 +141,14 @@ const VertexArrayIterator& UV, int UVset) { - size_t numVertices = mdef->GetNumVertices(); - SModelVertex* vertices = mdef->GetVertices(); + const size_t numVertices = mdef->GetNumVertices(); + const size_t numberOfUVPerVertex = mdef->GetNumUVsPerVertex(); for (size_t j = 0; j < numVertices; ++j) { - UV[j][0] = vertices[j].m_UVs[UVset * 2]; - UV[j][1] = 1.0 - vertices[j].m_UVs[UVset * 2 + 1]; + const CVector2D& uv = mdef->GetUVCoordinates()[j * numberOfUVPerVertex + UVset]; + UV[j][0] = uv.X; + UV[j][1] = 1.0 - uv.Y; } } @@ -192,7 +193,7 @@ ModelVertexRendererPtr vertexRenderer; /// List of submitted models for rendering in this frame - std::vector submissions[CRenderer::CULL_MAX]; + std::vector submissions[CSceneRenderer::CULL_MAX]; }; @@ -229,7 +230,7 @@ // Call update for all submitted models and enter the rendering phase void ShaderModelRenderer::PrepareModels() { - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i) { @@ -250,7 +251,7 @@ // Clear the submissions list void ShaderModelRenderer::EndFrame() { - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) m->submissions[cullGroup].clear(); } @@ -343,13 +344,15 @@ } }; -void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) +void ShaderModelRenderer::Render( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) { if (m->submissions[cullGroup].empty()) return; CMatrix3D worldToCam; - g_Renderer.GetViewCamera().GetOrientation().GetInverse(worldToCam); + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(worldToCam); /* * Rendering approach: @@ -426,34 +429,8 @@ for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i) { CModel* model = m->submissions[cullGroup][i]; - - uint32_t condFlags = 0; - - const CShaderConditionalDefines& condefs = model->GetMaterial().GetConditionalDefines(); - for (size_t j = 0; j < condefs.GetSize(); ++j) - { - const CShaderConditionalDefines::CondDefine& item = condefs.GetItem(j); - int type = item.m_CondType; - switch (type) - { - case DCOND_DISTANCE: - { - CVector3D modelpos = model->GetTransform().GetTranslation(); - float dist = worldToCam.Transform(modelpos).Z; - - float dmin = item.m_CondArgs[0]; - float dmax = item.m_CondArgs[1]; - - if ((dmin < 0 || dist >= dmin) && (dmax < 0 || dist < dmax)) - condFlags |= (1 << j); - - break; - } - } - } - - CShaderDefines defs = model->GetMaterial().GetShaderDefines(condFlags); - SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defs); + const CShaderDefines& defines = model->GetMaterial().GetShaderDefines(); + SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defines); MaterialBuckets_t::iterator it = materialBuckets.find(key); if (it == materialBuckets.end()) @@ -488,7 +465,9 @@ PROFILE3("processing material buckets"); for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it) { - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines); + CShaderDefines defines = context; + defines.SetMany(it->first.defines); + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, defines); // Skip invalid techniques (e.g. from data file errors) if (!tech) @@ -583,6 +562,8 @@ } } + const double time = g_Renderer.GetTimeManager().GetGlobalTime(); + { PROFILE3("rendering bucketed submissions"); @@ -598,8 +579,8 @@ // texBindings holds the identifier bindings in the shader, which can no longer be defined // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to // keep track of when bindings need to be reevaluated. - using BindingListAllocator = ProxyAllocator; - std::vector texBindings((BindingListAllocator(arena))); + using BindingListAllocator = ProxyAllocator; + std::vector texBindings((BindingListAllocator(arena))); texBindings.reserve(64); using BindingNamesListAllocator = ProxyAllocator; @@ -621,14 +602,20 @@ // For each of the technique's passes, render all the models in this run for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass) { - currentTech->BeginPass(pass); + deviceCommandContext->SetGraphicsPipelineState( + currentTech->GetGraphicsPipelineStateDesc(pass)); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = currentTech->GetShader(pass); - int streamflags = shader->GetStreamFlags(); + Renderer::Backend::IShaderProgram* shader = currentTech->GetShader(pass); - modifier->BeginPass(shader); + modifier->BeginPass(deviceCommandContext, shader); - m->vertexRenderer->BeginPass(streamflags); + // TODO: Use a more generic approach to handle bound queries. + bool boundTime = false; + bool boundWaterTexture = false; + bool boundSkyCube = false; + + m->vertexRenderer->BeginPass(); // When the shader technique changes, textures need to be // rebound, so ensure there are no remnants from the last pass. @@ -659,12 +646,12 @@ if (currentTexs.size() != samplersNum) { currentTexs.resize(samplersNum, NULL); - texBindings.resize(samplersNum, CShaderProgram::Binding()); + texBindings.resize(samplersNum, -1); texBindingNames.resize(samplersNum, CStrIntern()); // ensure they are definitely empty - std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding()); - std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL); + std::fill(texBindings.begin(), texBindings.end(), -1); + std::fill(currentTexs.begin(), currentTexs.end(), nullptr); std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern()); } @@ -675,17 +662,19 @@ // check that the handles are current // and reevaluate them if necessary - if (texBindingNames[s] != samp.Name || !texBindings[s].Active()) + if (texBindingNames[s] != samp.Name || texBindings[s] < 0) { - texBindings[s] = shader->GetTextureBinding(samp.Name); + texBindings[s] = shader->GetBindingSlot(samp.Name); texBindingNames[s] = samp.Name; } // same with the actual sampler bindings CTexture* newTex = samp.Sampler.get(); - if (texBindings[s].Active() && newTex != currentTexs[s]) + if (texBindings[s] >= 0 && newTex != currentTexs[s]) { - shader->BindTexture(texBindings[s], newTex->GetHandle()); + newTex->UploadBackendTextureIfNeeded(deviceCommandContext); + deviceCommandContext->SetTexture( + texBindings[s], newTex->GetBackendTexture()); currentTexs[s] = newTex; } } @@ -695,7 +684,7 @@ if (newModeldef != currentModeldef) { currentModeldef = newModeldef; - m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); + m->vertexRenderer->PrepareModelDef(deviceCommandContext, *currentModeldef); } // Bind all uniforms when any change @@ -703,7 +692,7 @@ if (newStaticUniforms != currentStaticUniforms) { currentStaticUniforms = newStaticUniforms; - currentStaticUniforms.BindUniforms(shader); + currentStaticUniforms.BindUniforms(deviceCommandContext, shader); } const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); @@ -713,43 +702,60 @@ CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); if (rq.first == RQUERY_TIME) { - CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); - if (binding.Active()) + if (!boundTime) { - double time = g_Renderer.GetTimeManager().GetGlobalTime(); - shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(rq.second), time); + boundTime = true; } } else if (rq.first == RQUERY_WATER_TEX) { - WaterManager* WaterMgr = g_Renderer.GetWaterManager(); - double time = WaterMgr->m_WaterTexTimer; - double period = 1.6; - int curTex = static_cast(time * 60.0 / period) % 60; - - if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) - shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); - else - shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); + if (!boundWaterTexture) + { + const double period = 1.6; + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); + if (waterManager.m_RenderWater && waterManager.WillRenderFancyWater()) + { + const CTexturePtr& waterTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]; + waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_waterTex), + waterTexture->GetBackendTexture()); + } + else + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_waterTex), + g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); + } + boundWaterTexture = true; + } } else if (rq.first == RQUERY_SKY_CUBE) { - shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); + if (!boundSkyCube) + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_skyCube), + g_Renderer.GetSceneRenderer().GetSkyManager().GetSkyCube()); + boundSkyCube = true; + } } } - modifier->PrepareModel(shader, model); + modifier->PrepareModel(deviceCommandContext, model); CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); - m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); + m->vertexRenderer->RenderModel(deviceCommandContext, shader, model, rdata); } } - m->vertexRenderer->EndPass(streamflags); + m->vertexRenderer->EndPass(deviceCommandContext); - currentTech->EndPass(pass); + deviceCommandContext->EndPass(); } idxTechStart = idxTechEnd; diff -Nru 0ad-0.0.25b/source/renderer/ModelRenderer.h 0ad-0.0.26/source/renderer/ModelRenderer.h --- 0ad-0.0.25b/source/renderer/ModelRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ModelRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,6 +29,7 @@ #include "graphics/MeshManager.h" #include "graphics/RenderableObject.h" #include "graphics/SColor.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/VertexArray.h" class RenderModifier; @@ -157,7 +158,9 @@ * If flags is non-zero, only models that contain flags in their * CModel::GetFlags() are rendered. */ - virtual void Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) = 0; + virtual void Render( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) = 0; /** * CopyPositionAndNormals: Copy unanimated object-space vertices and @@ -264,7 +267,9 @@ virtual void Submit(int cullGroup, CModel* model); virtual void PrepareModels(); virtual void EndFrame(); - virtual void Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags); + virtual void Render( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags); private: struct ShaderModelRendererInternals; diff -Nru 0ad-0.0.25b/source/renderer/ModelVertexRenderer.h 0ad-0.0.26/source/renderer/ModelVertexRenderer.h --- 0ad-0.0.25b/source/renderer/ModelVertexRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ModelVertexRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,6 +25,8 @@ #include "graphics/MeshManager.h" #include "graphics/ShaderProgramPtr.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" class CModel; class CModelRData; @@ -86,22 +88,20 @@ /** - * BeginPass: Setup global OpenGL state for this ModelVertexRenderer. + * BeginPass: Setup backend state for this ModelVertexRenderer. * - * ModelVertexRenderer implementations should prepare "heavy" OpenGL + * ModelVertexRenderer implementations should prepare "heavy" * state such as vertex shader state to prepare for rendering models * and delivering vertex data to the fragment stage as described by - * streamflags. + * shader. * * ModelRenderer implementations must call this function before any * calls to other rendering related functions. * * Recursive calls to BeginPass are not allowed, and every BeginPass * is matched by a corresponding call to EndPass. - * - * @param streamflags Vertex streams required by the fragment stage. */ - virtual void BeginPass(int streamflags) = 0; + virtual void BeginPass() = 0; /** @@ -109,16 +109,12 @@ * * ModelRenderer implementations must call this function after * rendering related functions for one pass have been called. - * - * @param streamflags Vertex streams required by the fragment stage. - * This equals the streamflags parameter passed on the last call to - * BeginPass. */ - virtual void EndPass(int streamflags) = 0; + virtual void EndPass(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) = 0; /** - * PrepareModelDef: Setup OpenGL state for rendering of models that + * PrepareModelDef: Setup backend state for rendering of models that * use the given CModelDef object as base. * * ModelRenderer implementations must call this function before @@ -126,12 +122,11 @@ * When a ModelRenderer switches back and forth between CModelDefs, * it must call PrepareModelDef for every switch. * - * @param streamflags Vertex streams required by the fragment stage. - * This equals the streamflags parameter passed on the last call to - * BeginPass. * @param def The model definition. */ - virtual void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0; + virtual void PrepareModelDef( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CModelDef& def) = 0; /** @@ -143,9 +138,6 @@ * preconditions : The most recent call to PrepareModelDef since * BeginPass has been for model->GetModelDef(). * - * @param streamflags Vertex streams required by the fragment stage. - * This equals the streamflags parameter passed on the last call to - * BeginPass. * @param model The model that should be rendered. * @param data Private data for the model as returned by CreateModelData. * @@ -153,7 +145,9 @@ * that use the same CModelDef object and the same texture must * succeed. */ - virtual void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0; + virtual void RenderModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* data) = 0; }; diff -Nru 0ad-0.0.25b/source/renderer/OverlayRenderer.cpp 0ad-0.0.26/source/renderer/OverlayRenderer.cpp --- 0ad-0.0.25b/source/renderer/OverlayRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/OverlayRenderer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,7 +26,6 @@ #include "graphics/Terrain.h" #include "graphics/TextureManager.h" #include "lib/hash.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "maths/Quaternion.h" #include "ps/CStrInternStatic.h" @@ -34,6 +33,7 @@ #include "ps/Profile.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TexturedLineRData.h" #include "renderer/VertexArray.h" #include "renderer/VertexBuffer.h" @@ -47,14 +47,9 @@ namespace { -CShaderProgramPtr GetOverlayLineShader(const CShaderDefines& defines) +CShaderTechniquePtr GetOverlayLineShaderTechnique(const CShaderDefines& defines) { - const char* shaderName; - if (g_RenderingOptions.GetPreferGLSL()) - shaderName = "glsl/overlayline"; - else - shaderName = "arb/overlayline"; - return g_Renderer.GetShaderManager().LoadProgram(shaderName, defines); + return g_Renderer.GetShaderManager().LoadEffect(str_overlay_line, defines); } } // anonymous namespace @@ -132,11 +127,11 @@ VertexArray::Attribute quadAttributeUV; VertexIndexArray quadIndices; - /// Maximum amount of quad overlays we support for rendering. This limit is set to be able to - /// render all quads from a single dedicated VB without having to reallocate it, which is much - /// faster in the typical case of rendering only a handful of quads. When modifying this value, - /// you must take care for the new amount of quads to fit in a single VBO (which is not likely - /// to be a problem). + // Maximum amount of quad overlays we support for rendering. This limit is set to be able to + // render all quads from a single dedicated VB without having to reallocate it, which is much + // faster in the typical case of rendering only a handful of quads. When modifying this value, + // you must take care for the new amount of quads to fit in a single backend buffer (which is + // not likely to be a problem). static const size_t MAX_QUAD_OVERLAYS = 1024; // Sets of commonly-(re)used shader defines. @@ -149,27 +144,26 @@ std::vector sphereIndexes; void GenerateSphere(); - /// Performs one-time setup. Called from CRenderer::Open, after graphics capabilities have - /// been detected. Note that no VBOs must be created before this is called, since the shader - /// path and graphics capabilities are not guaranteed to be stable before this point. + // Performs one-time setup. Called from CRenderer::Open, after graphics capabilities have + // been detected. Note that no backend buffer must be created before this is called, since + // the shader path and graphics capabilities are not guaranteed to be stable before this + // point. void Initialize(); }; const float OverlayRenderer::OVERLAY_VOFFSET = 0.2f; OverlayRendererInternals::OverlayRendererInternals() - : quadVertices(GL_DYNAMIC_DRAW), quadIndices(GL_STATIC_DRAW) + : quadVertices(Renderer::Backend::IBuffer::Type::VERTEX, true), + quadIndices(false) { - quadAttributePos.elems = 3; - quadAttributePos.type = GL_FLOAT; + quadAttributePos.format = Renderer::Backend::Format::R32G32B32_SFLOAT; quadVertices.AddAttribute(&quadAttributePos); - quadAttributeColor.elems = 4; - quadAttributeColor.type = GL_FLOAT; + quadAttributeColor.format = Renderer::Backend::Format::R8G8B8A8_UNORM; quadVertices.AddAttribute(&quadAttributeColor); - quadAttributeUV.elems = 2; - quadAttributeUV.type = GL_SHORT; // don't use GL_UNSIGNED_SHORT here, TexCoordPointer won't accept it + quadAttributeUV.format = Renderer::Backend::Format::R16G16_SINT; quadVertices.AddAttribute(&quadAttributeUV); // Note that we're reusing the textured overlay line shader for the quad overlay rendering. This @@ -184,13 +178,13 @@ void OverlayRendererInternals::Initialize() { // Perform any initialization after graphics capabilities have been detected. Notably, - // only at this point can we safely allocate VBOs (in contrast to e.g. in the constructor), + // only at this point can we safely allocate backend buffer (in contrast to e.g. in the constructor), // because their creation depends on the shader path, which is not reliably set before this point. - quadVertices.SetNumVertices(MAX_QUAD_OVERLAYS * 4); + quadVertices.SetNumberOfVertices(MAX_QUAD_OVERLAYS * 4); quadVertices.Layout(); // allocate backing store - quadIndices.SetNumVertices(MAX_QUAD_OVERLAYS * 6); + quadIndices.SetNumberOfVertices(MAX_QUAD_OVERLAYS * 6); quadIndices.Layout(); // allocate backing store // Since the quads in the vertex array are independent and always consist of exactly 4 vertices per quad, the @@ -313,7 +307,7 @@ // Write quad overlay vertices/indices to VA backing store VertexArrayIterator vertexPos = m->quadAttributePos.GetIterator(); - VertexArrayIterator vertexColor = m->quadAttributeColor.GetIterator(); + VertexArrayIterator vertexColor = m->quadAttributeColor.GetIterator(); VertexArrayIterator vertexUV = m->quadAttributeUV.GetIterator(); size_t indicesIdx = 0; @@ -335,9 +329,7 @@ { const SOverlayQuad* quad = batchRenderData.m_Quads[i]; - // TODO: this is kind of ugly, the iterator should use a type that can have quad->m_Color assigned - // to it directly - const CVector4D quadColor(quad->m_Color.r, quad->m_Color.g, quad->m_Color.b, quad->m_Color.a); + const SColor4ub quadColor = quad->m_Color.AsSColor4ub(); *vertexPos++ = quad->m_Corners[0] + vOffset; *vertexPos++ = quad->m_Corners[1] + vOffset; @@ -375,17 +367,11 @@ m->quadVertices.PrepareForRendering(); } -void OverlayRenderer::RenderOverlaysBeforeWater() +void OverlayRenderer::RenderOverlaysBeforeWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { PROFILE3_GPU("overlays (before)"); - -#if CONFIG2_GLES -#warning TODO: implement OverlayRenderer::RenderOverlaysBeforeWater for GLES -#else - glEnable(GL_BLEND); - // Ignore z so that we draw behind terrain (but don't disable GL_DEPTH_TEST - // since we still want to write to the z buffer) - glDepthFunc(GL_ALWAYS); + GPU_SCOPED_LABEL(deviceCommandContext, "Render overlays before water"); for (SOverlayLine* line : m->lines) { @@ -394,93 +380,106 @@ g_Renderer.GetDebugRenderer().DrawLine(line->m_Coords, line->m_Color, static_cast(line->m_Thickness)); } - - glDepthFunc(GL_LEQUAL); - glDisable(GL_BLEND); -#endif } -void OverlayRenderer::RenderOverlaysAfterWater() +void OverlayRenderer::RenderOverlaysAfterWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { PROFILE3_GPU("overlays (after)"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render overlays after water"); - RenderTexturedOverlayLines(); - RenderQuadOverlays(); - RenderSphereOverlays(); + RenderTexturedOverlayLines(deviceCommandContext); + RenderQuadOverlays(deviceCommandContext); + RenderSphereOverlays(deviceCommandContext); } -void OverlayRenderer::RenderTexturedOverlayLines() +void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { -#if CONFIG2_GLES -#warning TODO: implement OverlayRenderer::RenderTexturedOverlayLines for GLES - return; -#endif if (m->texlines.empty()) return; - ogl_WarnIfError(); - - pglActiveTextureARB(GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glDepthMask(0); - - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - CShaderProgramPtr shaderTexLineNormal = GetOverlayLineShader(m->defsOverlayLineNormal); - CShaderProgramPtr shaderTexLineAlwaysVisible = GetOverlayLineShader(m->defsOverlayLineAlwaysVisible); - - // ---------------------------------------------------------------------------------------- - - if (shaderTexLineNormal) + CShaderTechniquePtr shaderTechTexLineNormal = GetOverlayLineShaderTechnique(m->defsOverlayLineNormal); + if (shaderTechTexLineNormal) { - shaderTexLineNormal->Bind(); - shaderTexLineNormal->BindTexture(str_losTex, los.GetTexture()); - shaderTexLineNormal->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - - shaderTexLineNormal->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + shaderTechTexLineNormal->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthWriteEnabled = false; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shaderTexLineNormal = shaderTechTexLineNormal->GetShader(); + + deviceCommandContext->SetTexture( + shaderTexLineNormal->GetBindingSlot(str_losTex), los.GetTexture()); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shaderTexLineNormal->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shaderTexLineNormal->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); // batch render only the non-always-visible overlay lines using the normal shader - RenderTexturedOverlayLines(shaderTexLineNormal, false); + RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineNormal, false); - shaderTexLineNormal->Unbind(); + deviceCommandContext->EndPass(); } - // ---------------------------------------------------------------------------------------- - - if (shaderTexLineAlwaysVisible) + CShaderTechniquePtr shaderTechTexLineAlwaysVisible = GetOverlayLineShaderTechnique(m->defsOverlayLineAlwaysVisible); + if (shaderTechTexLineAlwaysVisible) { - shaderTexLineAlwaysVisible->Bind(); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + shaderTechTexLineAlwaysVisible->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthWriteEnabled = false; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shaderTexLineAlwaysVisible = shaderTechTexLineAlwaysVisible->GetShader(); + // TODO: losTex and losTransform are unused in the always visible shader; see if these can be safely omitted - shaderTexLineAlwaysVisible->BindTexture(str_losTex, los.GetTexture()); - shaderTexLineAlwaysVisible->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); + deviceCommandContext->SetTexture( + shaderTexLineAlwaysVisible->GetBindingSlot(str_losTex), los.GetTexture()); - shaderTexLineAlwaysVisible->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shaderTexLineAlwaysVisible->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shaderTexLineAlwaysVisible->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); // batch render only the always-visible overlay lines using the LoS-ignored shader - RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true); + RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineAlwaysVisible, true); - shaderTexLineAlwaysVisible->Unbind(); + deviceCommandContext->EndPass(); } - - // ---------------------------------------------------------------------------------------- - - // TODO: the shaders should probably be responsible for unbinding their textures - g_Renderer.BindTexture(1, 0); - g_Renderer.BindTexture(0, 0); - - CVertexBuffer::Unbind(); - - glDepthMask(1); - glDisable(GL_BLEND); } -void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible) +void OverlayRenderer::RenderTexturedOverlayLines( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* 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]; @@ -490,164 +489,200 @@ continue; ENSURE(line->m_RenderData); - line->m_RenderData->Render(*line, shader); + line->m_RenderData->Render(deviceCommandContext, *line, shader); } -#if !CONFIG2_GLES - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif } -void OverlayRenderer::RenderQuadOverlays() +void OverlayRenderer::RenderQuadOverlays( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { -#if CONFIG2_GLES -#warning TODO: implement OverlayRenderer::RenderQuadOverlays for GLES - return; -#endif if (m->quadBatchMap.empty()) return; - CShaderProgramPtr shader = GetOverlayLineShader(m->defsQuadOverlay); + CShaderTechniquePtr shaderTech = GetOverlayLineShaderTechnique(m->defsQuadOverlay); - if (!shader) + if (!shaderTech) 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); - glDepthMask(0); - - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); - - shader->Bind(); - shader->BindTexture(str_losTex, los.GetTexture()); - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - - // Base offsets (in bytes) of the two backing stores relative to their owner VBO - u8* indexBase = m->quadIndices.Bind(); - u8* vertexBase = m->quadVertices.Bind(); - GLsizei indexStride = m->quadIndices.GetStride(); - GLsizei vertexStride = m->quadVertices.GetStride(); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + shaderTech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthWriteEnabled = false; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + + m->quadVertices.UploadIfNeeded(deviceCommandContext); + m->quadIndices.UploadIfNeeded(deviceCommandContext); + + const uint32_t vertexStride = m->quadVertices.GetStride(); + const uint32_t firstVertexOffset = m->quadVertices.GetOffset() * vertexStride; + + const int32_t baseTexBindingSlot = shader->GetBindingSlot(str_baseTex); + const int32_t maskTexBindingSlot = shader->GetBindingSlot(str_maskTex); for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it) { QuadBatchData& batchRenderData = it->second; const size_t batchNumQuads = batchRenderData.m_NumRenderQuads; - // Careful; some drivers don't like drawing calls with 0 stuff to draw. if (batchNumQuads == 0) continue; const QuadBatchKey& maskPair = it->first; - shader->BindTexture(str_baseTex, maskPair.m_Texture->GetHandle()); - shader->BindTexture(str_maskTex, maskPair.m_TextureMask->GetHandle()); - - int streamflags = shader->GetStreamFlags(); + maskPair.m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); + maskPair.m_TextureMask->UploadBackendTextureIfNeeded(deviceCommandContext); - if (streamflags & STREAM_POS) - shader->VertexPointer(m->quadAttributePos.elems, m->quadAttributePos.type, vertexStride, vertexBase + m->quadAttributePos.offset); + deviceCommandContext->SetTexture( + baseTexBindingSlot, maskPair.m_Texture->GetBackendTexture()); + deviceCommandContext->SetTexture( + maskTexBindingSlot, maskPair.m_TextureMask->GetBackendTexture()); + + // TODO: move setting format out of the loop, we might want move the offset + // to the index offset when it's supported. + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m->quadAttributePos.format, firstVertexOffset + m->quadAttributePos.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::COLOR, + m->quadAttributeColor.format, firstVertexOffset + m->quadAttributeColor.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + m->quadAttributeUV.format, firstVertexOffset + m->quadAttributeUV.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + m->quadAttributeUV.format, firstVertexOffset + m->quadAttributeUV.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - if (streamflags & STREAM_UV0) - shader->TexCoordPointer(GL_TEXTURE0, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset); + deviceCommandContext->SetVertexBuffer(0, m->quadVertices.GetBuffer()); + deviceCommandContext->SetIndexBuffer(m->quadIndices.GetBuffer()); - if (streamflags & STREAM_UV1) - shader->TexCoordPointer(GL_TEXTURE1, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset); - - if (streamflags & STREAM_COLOR) - shader->ColorPointer(m->quadAttributeColor.elems, m->quadAttributeColor.type, vertexStride, vertexBase + m->quadAttributeColor.offset); - - shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, (GLsizei)(batchNumQuads * 6), GL_UNSIGNED_SHORT, indexBase + indexStride * batchRenderData.m_IndicesBase); + deviceCommandContext->DrawIndexed(m->quadIndices.GetOffset() + batchRenderData.m_IndicesBase, batchNumQuads * 6, 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += batchNumQuads*2; } - shader->Unbind(); - - // TODO: the shader should probably be responsible for unbinding its textures - g_Renderer.BindTexture(1, 0); - g_Renderer.BindTexture(0, 0); - - CVertexBuffer::Unbind(); - - glDepthMask(1); - glDisable(GL_BLEND); - -#if !CONFIG2_GLES - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif + deviceCommandContext->EndPass(); } -void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) +void OverlayRenderer::RenderForegroundOverlays( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CCamera& viewCamera) { PROFILE3_GPU("overlays (fg)"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render foreground overlays"); -#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); - glDisable(GL_DEPTH_TEST); - - CVector3D right = -viewCamera.GetOrientation().GetLeft(); - CVector3D up = viewCamera.GetOrientation().GetUp(); + const CVector3D right = -viewCamera.GetOrientation().GetLeft(); + const CVector3D up = viewCamera.GetOrientation().GetUp(); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_foreground_overlay); - tech->BeginPass(); - CShaderProgramPtr shader = tech->GetShader(); - - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + tech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthTestEnabled = false; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + + const CVector2D uvs[6] = + { + {0.0f, 1.0f}, + {1.0f, 1.0f}, + {1.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 0.0f}, + {0.0f, 0.0f}, + }; + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - float uvs[8] = { 0,1, 1,1, 1,0, 0,0 }; + deviceCommandContext->SetVertexBufferData( + 1, &uvs[0], std::size(uvs) * sizeof(uvs[0])); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(float)*2, &uvs[0]); + const int32_t baseTexBindingSlot = shader->GetBindingSlot(str_baseTex); + const int32_t colorMulBindingSlot = shader->GetBindingSlot(str_colorMul); for (size_t i = 0; i < m->sprites.size(); ++i) { SOverlaySprite* sprite = m->sprites[i]; if (!i || sprite->m_Texture != m->sprites[i - 1]->m_Texture) - shader->BindTexture(str_baseTex, sprite->m_Texture); + { + sprite->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); + deviceCommandContext->SetTexture( + baseTexBindingSlot, sprite->m_Texture->GetBackendTexture()); + } - shader->Uniform(str_colorMul, sprite->m_Color); + deviceCommandContext->SetUniform( + colorMulBindingSlot, sprite->m_Color.AsFloatArray()); - CVector3D pos[4] = { + const CVector3D position[6] = + { sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y0, sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y0, sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y1, + sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y0, + sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y1, sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y1 }; - shader->VertexPointer(3, GL_FLOAT, sizeof(float)*3, &pos[0].X); + deviceCommandContext->SetVertexBufferData( + 0, &position[0].X, std::size(position) * sizeof(position[0])); - glDrawArrays(GL_QUADS, 0, (GLsizei)4); + deviceCommandContext->Draw(0, 6); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += 2; } - tech->EndPass(); - - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif + deviceCommandContext->EndPass(); } static void TessellateSphereFace(const CVector3D& a, u16 ai, @@ -711,54 +746,72 @@ TessellateSphere(sphereVertexes, sphereIndexes, 3); } -void OverlayRenderer::RenderSphereOverlays() +void OverlayRenderer::RenderSphereOverlays( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { PROFILE3_GPU("overlays (spheres)"); -#if CONFIG2_GLES -#warning TODO: implement OverlayRenderer::RenderSphereOverlays for GLES -#else if (m->spheres.empty()) return; - glDisable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glDepthMask(0); - - CShaderProgramPtr shader; + Renderer::Backend::IShaderProgram* shader = nullptr; CShaderTechniquePtr tech; tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid); - tech->BeginPass(); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + tech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthWriteEnabled = false; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + shader = tech->GetShader(); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + m->GenerateSphere(); - shader->VertexPointer(3, GL_FLOAT, 0, &m->sphereVertexes[0]); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBufferData( + 0, m->sphereVertexes.data(), m->sphereVertexes.size() * sizeof(m->sphereVertexes[0])); + deviceCommandContext->SetIndexBufferData( + m->sphereIndexes.data(), m->sphereIndexes.size() * sizeof(m->sphereIndexes[0])); for (size_t i = 0; i < m->spheres.size(); ++i) { SOverlaySphere* sphere = m->spheres[i]; - CMatrix3D transform; - transform.SetIdentity(); - transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius); - transform.Translate(sphere->m_Center); + CMatrix3D instancingTransform; + instancingTransform.SetIdentity(); + instancingTransform.Scale( + sphere->m_Radius, sphere->m_Radius, sphere->m_Radius); + instancingTransform.Translate(sphere->m_Center); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_instancingTransform), + instancingTransform.AsFloatArray()); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->Uniform(str_instancingTransform, transform); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_color), sphere->m_Color.AsFloatArray()); - shader->Uniform(str_color, sphere->m_Color); - - glDrawElements(GL_TRIANGLES, m->sphereIndexes.size(), GL_UNSIGNED_SHORT, &m->sphereIndexes[0]); + deviceCommandContext->DrawIndexed(0, m->sphereIndexes.size(), 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3; } - tech->EndPass(); - - glDepthMask(1); - glDisable(GL_BLEND); -#endif + deviceCommandContext->EndPass(); } diff -Nru 0ad-0.0.25b/source/renderer/OverlayRenderer.h 0ad-0.0.26/source/renderer/OverlayRenderer.h --- 0ad-0.0.25b/source/renderer/OverlayRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/OverlayRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,8 @@ #ifndef INCLUDED_OVERLAYRENDERER #define INCLUDED_OVERLAYRENDERER -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" +#include "renderer/backend/IDeviceCommandContext.h" struct SOverlayLine; struct SOverlayTexturedLine; @@ -43,7 +44,7 @@ /** * Performs one-time initialization. Called by CRenderer::Open after graphics - * capabilities and the shader path have been determined (notably VBO support). + * capabilities and the shader path have been determined. */ void Initialize(); @@ -99,21 +100,25 @@ * (i.e. rendered behind other objects in the normal 3D way) * and should be drawn before water (i.e. may be visible under the water) */ - void RenderOverlaysBeforeWater(); + void RenderOverlaysBeforeWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Render all the submitted overlays that are embedded in the world * (i.e. rendered behind other objects in the normal 3D way) * and should be drawn after water (i.e. may be visible on top of the water) */ - void RenderOverlaysAfterWater(); + void RenderOverlaysAfterWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Render all the submitted overlays that should appear on top of everything * in the world. * @param viewCamera camera to be used for billboard computations */ - void RenderForegroundOverlays(const CCamera& viewCamera); + void RenderForegroundOverlays( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CCamera& viewCamera); /// Small vertical offset of overlays from terrain to prevent visual glitches static const float OVERLAY_VOFFSET; @@ -125,7 +130,7 @@ * renders textured overlay lines batched according to their visibility status by delegating * to RenderTexturedOverlayLines(CShaderProgramPtr, bool). */ - void RenderTexturedOverlayLines(); + void RenderTexturedOverlayLines(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Helper method; renders those overlay lines currently registered in the internals (i.e. @@ -133,17 +138,19 @@ * batch rendering the overlay lines according to their alwaysVisible status, as this * requires a separate shader to be used. */ - void RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible); + void RenderTexturedOverlayLines( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, bool alwaysVisible); /** * Helper method; batch-renders all registered quad overlays, batched by their texture for effiency. */ - void RenderQuadOverlays(); + void RenderQuadOverlays(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Helper method; batch-renders all sphere quad overlays. */ - void RenderSphereOverlays(); + void RenderSphereOverlays(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); private: OverlayRendererInternals* m; diff -Nru 0ad-0.0.25b/source/renderer/ParticleRenderer.cpp 0ad-0.0.26/source/renderer/ParticleRenderer.cpp --- 0ad-0.0.25b/source/renderer/ParticleRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ParticleRenderer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,13 +27,17 @@ #include "ps/Profile.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" struct ParticleRendererInternals { int frameNumber; - CShaderTechniquePtr shader; - CShaderTechniquePtr shaderSolid; - std::vector emitters[CRenderer::CULL_MAX]; + CShaderTechniquePtr techAdd; + CShaderTechniquePtr techSubtract; + CShaderTechniquePtr techOverlay; + CShaderTechniquePtr techMultiply; + CShaderTechniquePtr techWireframe; + std::vector emitters[CSceneRenderer::CULL_MAX]; }; ParticleRenderer::ParticleRenderer() @@ -54,7 +58,7 @@ void ParticleRenderer::EndFrame() { - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) m->emitters[cullGroup].clear(); // this should leave the capacity unchanged, which is okay since it // won't be very large or very variable @@ -86,15 +90,20 @@ // Can't load the shader in the constructor because it's called before the // renderer initialisation is complete, so load it the first time through here - if (!m->shader) + if (!m->techWireframe) { - m->shader = g_Renderer.GetShaderManager().LoadEffect(str_particle, context, CShaderDefines()); - m->shaderSolid = g_Renderer.GetShaderManager().LoadEffect(str_particle_solid, context, CShaderDefines()); + m->techAdd = g_Renderer.GetShaderManager().LoadEffect(str_particle_add, context); + m->techSubtract = g_Renderer.GetShaderManager().LoadEffect(str_particle_subtract, context); + m->techOverlay = g_Renderer.GetShaderManager().LoadEffect(str_particle_overlay, context); + m->techMultiply = g_Renderer.GetShaderManager().LoadEffect(str_particle_multiply, context); + CShaderDefines contextWithWireframe = context; + contextWithWireframe.Add(str_MODE_WIREFRAME, str_1); + m->techWireframe = g_Renderer.GetShaderManager().LoadEffect(str_particle_solid, contextWithWireframe); } ++m->frameNumber; - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { PROFILE("update emitters"); for (size_t i = 0; i < m->emitters[cullGroup].size(); ++i) @@ -105,50 +114,65 @@ } } - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { // Sort back-to-front by distance from camera PROFILE("sort emitters"); CMatrix3D worldToCam; - g_Renderer.GetViewCamera().GetOrientation().GetInverse(worldToCam); + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(worldToCam); std::stable_sort(m->emitters[cullGroup].begin(), m->emitters[cullGroup].end(), SortEmitterDistance(worldToCam)); } // TODO: should batch by texture here when possible, maybe } -void ParticleRenderer::RenderParticles(int cullGroup, bool solidColor) +void ParticleRenderer::RenderParticles( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup, bool wireframe) { - CShaderTechniquePtr shader = solidColor ? m->shaderSolid : m->shader; - - std::vector& emitters = m->emitters[cullGroup]; - - shader->BeginPass(); - - shader->GetShader()->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->GetShader()->Uniform(str_modelViewMatrix, g_Renderer.GetViewCamera().GetOrientation().GetInverse()); - - if (!solidColor) - glEnable(GL_BLEND); - glDepthMask(0); - - for (size_t i = 0; i < emitters.size(); ++i) + CShaderTechnique* lastTech = nullptr; + for (CParticleEmitter* emitter : m->emitters[cullGroup]) { - CParticleEmitter* emitter = emitters[i]; - - emitter->Bind(shader->GetShader()); - emitter->RenderArray(shader->GetShader()); + CShaderTechnique* currentTech = nullptr; + if (wireframe) + { + currentTech = m->techWireframe.get(); + } + else + { + switch (emitter->m_Type->m_BlendMode) + { + case CParticleEmitterType::BlendMode::ADD: currentTech = m->techAdd.get(); break; + case CParticleEmitterType::BlendMode::SUBTRACT: currentTech = m->techSubtract.get(); break; + case CParticleEmitterType::BlendMode::OVERLAY: currentTech = m->techOverlay.get(); break; + case CParticleEmitterType::BlendMode::MULTIPLY: currentTech = m->techMultiply.get(); break; + } + } + ENSURE(currentTech); + if (lastTech != currentTech) + { + if (lastTech) + deviceCommandContext->EndPass(); + lastTech = currentTech; + deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = lastTech->GetShader(); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + const CMatrix3D modelViewMatrix = + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_modelViewMatrix), modelViewMatrix.AsFloatArray()); + } + emitter->Bind(deviceCommandContext, lastTech->GetShader()); + emitter->RenderArray(deviceCommandContext); } - CVertexBuffer::Unbind(); - - pglBlendEquationEXT(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glDisable(GL_BLEND); - glDepthMask(1); - - shader->EndPass(); + if (lastTech) + deviceCommandContext->EndPass(); } void ParticleRenderer::RenderBounds(int cullGroup) @@ -157,6 +181,6 @@ { const CBoundingBoxAligned bounds = emitter->m_Type->CalculateBounds(emitter->GetPosition(), emitter->GetParticleBounds()); - g_Renderer.GetDebugRenderer().DrawBoundingBox(bounds, CColor(0.0f, 1.0f, 0.0f, 1.0f)); + g_Renderer.GetDebugRenderer().DrawBoundingBox(bounds, CColor(0.0f, 1.0f, 0.0f, 1.0f), true); } } diff -Nru 0ad-0.0.25b/source/renderer/ParticleRenderer.h 0ad-0.0.26/source/renderer/ParticleRenderer.h --- 0ad-0.0.25b/source/renderer/ParticleRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ParticleRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,6 +18,8 @@ #ifndef INCLUDED_PARTICLERENDERER #define INCLUDED_PARTICLERENDERER +#include "renderer/backend/IDeviceCommandContext.h" + class CParticleEmitter; class CShaderDefines; struct ParticleRendererInternals; @@ -53,7 +55,9 @@ /** * Render all the submitted particles. */ - void RenderParticles(int cullGroup, bool solidColor = false); + void RenderParticles( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup, bool wireframe = false); /** * Render bounding boxes for all the submitted emitters. diff -Nru 0ad-0.0.25b/source/renderer/PatchRData.cpp 0ad-0.0.26/source/renderer/PatchRData.cpp --- 0ad-0.0.25b/source/renderer/PatchRData.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/PatchRData.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,6 +27,7 @@ #include "graphics/Terrain.h" #include "graphics/TerrainTextureEntry.h" #include "graphics/TextRenderer.h" +#include "graphics/TextureManager.h" #include "lib/allocators/DynamicArena.h" #include "lib/allocators/STLAllocators.h" #include "maths/MathUtil.h" @@ -36,10 +37,12 @@ #include "ps/GameSetup/Config.h" #include "ps/Profile.h" #include "ps/Pyrogenesis.h" +#include "ps/VideoMode.h" #include "ps/World.h" #include "renderer/AlphaMapCalculator.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TerrainRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/components/ICmpWaterManager.h" @@ -62,12 +65,7 @@ }; CPatchRData::CPatchRData(CPatch* patch, CSimulation2* simulation) : - m_Patch(patch), m_VBSides(), - m_VBBase(), m_VBBaseIndices(), - m_VBBlends(), m_VBBlendIndices(), - m_VBWater(), m_VBWaterIndices(), - m_VBWaterShore(), m_VBWaterIndicesShore(), - m_Simulation(simulation) + m_Patch(patch), m_Simulation(simulation) { ENSURE(patch); Build(); @@ -283,14 +281,20 @@ { // Construct vertex buffer - m_VBBlends = g_VBMan.AllocateChunk(sizeof(SBlendVertex), blendVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + m_VBBlends = g_VBMan.AllocateChunk( + sizeof(SBlendVertex), blendVertices.size(), + Renderer::Backend::IBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::TERRAIN); m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends.Get(), &blendVertices[0]); // Update the indices to include the base offset of the vertex data for (size_t k = 0; k < blendIndices.size(); ++k) blendIndices[k] += static_cast(m_VBBlends->m_Index); - m_VBBlendIndices = g_VBMan.AllocateChunk(sizeof(u16), blendIndices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + m_VBBlendIndices = g_VBMan.AllocateChunk( + sizeof(u16), blendIndices.size(), + Renderer::Backend::IBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::TERRAIN); m_VBBlendIndices->m_Owner->UpdateChunkVertices(m_VBBlendIndices.Get(), &blendIndices[0]); } } @@ -491,7 +495,9 @@ ENSURE(indices.size()); // Construct vertex buffer - m_VBBaseIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + m_VBBaseIndices = g_VBMan.AllocateChunk( + sizeof(u16), indices.size(), + Renderer::Backend::IBuffer::Type::INDEX, false, nullptr, CVertexBufferManager::Group::TERRAIN); m_VBBaseIndices->m_Owner->UpdateChunkVertices(m_VBBaseIndices.Get(), &indices[0]); } @@ -534,7 +540,12 @@ // upload to vertex buffer if (!m_VBBase) - m_VBBase = g_VBMan.AllocateChunk(sizeof(SBaseVertex), vsize * vsize, GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + { + m_VBBase = g_VBMan.AllocateChunk( + sizeof(SBaseVertex), vsize * vsize, + Renderer::Backend::IBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::TERRAIN); + } m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase.Get(), &vertices[0]); } @@ -571,17 +582,24 @@ v1.m_Position = pos; v1.m_Position.Y = 0; - // If this is the start of this tristrip, but we've already got a partial - // tristrip, add a couple of degenerate triangles to join the strips properly - if (k == 0 && !vertices.empty()) + if (k == 0) { - vertices.push_back(vertices.back()); - vertices.push_back(v1); + vertices.emplace_back(v1); + vertices.emplace_back(v0); + } + if (k > 0) + { + const size_t lastIndex = vertices.size() - 1; + vertices.emplace_back(v1); + vertices.emplace_back(vertices[lastIndex]); + vertices.emplace_back(v0); + vertices.emplace_back(v1); + if (k + 1 < vsize) + { + vertices.emplace_back(v1); + vertices.emplace_back(v0); + } } - - // Now add the new triangles - vertices.push_back(v1); - vertices.push_back(v0); } } @@ -616,7 +634,12 @@ return; if (!m_VBSides) - m_VBSides = g_VBMan.AllocateChunk(sizeof(SSideVertex), sideVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::DEFAULT); + { + m_VBSides = g_VBMan.AllocateChunk( + sizeof(SSideVertex), sideVertices.size(), + Renderer::Backend::IBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::DEFAULT); + } m_VBSides->m_Owner->UpdateChunkVertices(m_VBSides.Get(), &sideVertices[0]); } @@ -646,8 +669,6 @@ } } -// Types used for glMultiDrawElements batching: - // To minimise the cost of memory allocations, everything used for computing // batches uses a arena allocator. (All allocations are short-lived so we can // just throw away the whole arena at the end of each frame.) @@ -679,7 +700,7 @@ } // Each multidraw batch has a list of index counts, and a list of pointers-to-first-indexes -using BatchElements = std::pair>, std::vector>>; +using BatchElements = std::pair>, std::vector>>; // Group batches by index buffer using IndexBufferBatches = PooledBatchMap; @@ -691,12 +712,14 @@ using TextureBatches = PooledBatchMap; // Group batches by shaders. -using ShaderTechniqueBatches = PooledBatchMap; +using ShaderTechniqueBatches = PooledBatchMap, TextureBatches>; void CPatchRData::RenderBases( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow) { PROFILE3("render terrain bases"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain bases"); Arena arena; @@ -717,13 +740,11 @@ LOGERROR("Terrain renderer failed to load shader effect.\n"); continue; } - CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect( - material.GetShaderEffect(), context, material.GetShaderDefines(0)); BatchElements& batch = PooledPairGet( PooledMapGet( PooledMapGet( - PooledMapGet(batches, techBase, arena), + PooledMapGet(batches, std::make_pair(material.GetShaderEffect(), material.GetShaderDefines()), arena), splat.m_Texture, arena ), patch->m_VBBase->m_Owner, arena @@ -733,8 +754,7 @@ batch.first.push_back(splat.m_IndexCount); - u8* indexBase = nullptr; - batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart)); + batch.second.push_back(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart); } } @@ -743,69 +763,98 @@ // Render each batch for (ShaderTechniqueBatches::iterator itTech = batches.begin(); itTech != batches.end(); ++itTech) { - const CShaderTechniquePtr& techBase = itTech->first; + CShaderDefines defines = context; + defines.SetMany(itTech->first.second); + CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect( + itTech->first.first, defines); + const int numPasses = techBase->GetNumPasses(); for (int pass = 0; pass < numPasses; ++pass) { - techBase->BeginPass(pass); - const CShaderProgramPtr& shader = techBase->GetShader(pass); - TerrainRenderer::PrepareShader(shader, shadow); + deviceCommandContext->SetGraphicsPipelineState( + techBase->GetGraphicsPipelineStateDesc(pass)); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); + TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); + + const int32_t baseTexBindingSlot = + shader->GetBindingSlot(str_baseTex); + const int32_t textureTransformBindingSlot = + shader->GetBindingSlot(str_textureTransform); TextureBatches& textureBatches = itTech->second; for (TextureBatches::iterator itt = textureBatches.begin(); itt != textureBatches.end(); ++itt) { - if (itt->first->GetMaterial().GetSamplers().size() != 0) + if (!itt->first->GetMaterial().GetSamplers().empty()) { - const CMaterial::SamplersVector& samplers = itt->first->GetMaterial().GetSamplers(); + const CMaterial::SamplersVector& samplers = + itt->first->GetMaterial().GetSamplers(); + for(const CMaterial::TextureSampler& samp : samplers) + samp.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext); for(const CMaterial::TextureSampler& samp : samplers) - shader->BindTexture(samp.Name, samp.Sampler); + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(samp.Name), + samp.Sampler->GetBackendTexture()); + } - itt->first->GetMaterial().GetStaticUniforms().BindUniforms(shader); + itt->first->GetMaterial().GetStaticUniforms().BindUniforms( + deviceCommandContext, shader); float c = itt->first->GetTextureMatrix()[0]; float ms = itt->first->GetTextureMatrix()[8]; - shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); + deviceCommandContext->SetUniform( + textureTransformBindingSlot, c, ms); } else { - shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()); + deviceCommandContext->SetTexture( + baseTexBindingSlot, + g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); } for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv) { - GLsizei stride = sizeof(SBaseVertex); - SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); - shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); - shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); - shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); + itv->first->UploadIfNeeded(deviceCommandContext); + + const uint32_t stride = sizeof(SBaseVertex); - shader->AssertPointersBound(); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, itv->first->GetBuffer()); for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { - it->first->Bind(); + it->first->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(it->first->GetBuffer()); BatchElements& batch = it->second; - if (!g_Renderer.m_SkipSubmit) - { - // Don't use glMultiDrawElements here since it doesn't have a significant - // performance impact and it suffers from various driver bugs (e.g. it breaks - // in Mesa 7.10 swrast with index VBOs) - for (size_t i = 0; i < batch.first.size(); ++i) - glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); - } + for (size_t i = 0; i < batch.first.size(); ++i) + deviceCommandContext->DrawIndexed(batch.second[i], batch.first[i], 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; } } } - techBase->EndPass(); + deviceCommandContext->EndPass(); } } - - CVertexBuffer::Unbind(); } /** @@ -841,9 +890,11 @@ }; void CPatchRData::RenderBlends( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow) { PROFILE3("render terrain blends"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain blends"); Arena arena; @@ -898,8 +949,7 @@ BatchElements& batch = PooledPairGet(PooledMapGet(batches.back().m_Batches, vertices->m_Owner, arena), indices->m_Owner, arena); batch.first.push_back(splats.back().m_IndexCount); - u8* indexBase = nullptr; - batch.second.push_back(indexBase + sizeof(u16)*(indices->m_Index + splats.back().m_IndexStart)); + batch.second.push_back(indices->m_Index + splats.back().m_IndexStart); splats.pop_back(); } @@ -926,19 +976,18 @@ layer.m_Texture = bestTex; if (!bestTex->GetMaterial().GetSamplers().empty()) { + CShaderDefines defines = contextBlend; + defines.SetMany(bestTex->GetMaterial().GetShaderDefines()); layer.m_ShaderTech = g_Renderer.GetShaderManager().LoadEffect( - bestTex->GetMaterial().GetShaderEffect(), contextBlend, bestTex->GetMaterial().GetShaderDefines(0)); + bestTex->GetMaterial().GetShaderEffect(), defines); } batches.push_back(layer); } PROFILE_END("compute batches"); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - CVertexBuffer* lastVB = nullptr; - CShaderProgramPtr previousShader; + Renderer::Backend::IShaderProgram* previousShader = nullptr; for (BatchesStack::iterator itTechBegin = batches.begin(), itTechEnd = batches.begin(); itTechBegin != batches.end(); itTechBegin = itTechEnd) { while (itTechEnd != batches.end() && itTechEnd->m_ShaderTech == itTechBegin->m_ShaderTech) @@ -948,11 +997,29 @@ const int numPasses = techBase->GetNumPasses(); for (int pass = 0; pass < numPasses; ++pass) { - techBase->BeginPass(pass); - const CShaderProgramPtr& shader = techBase->GetShader(pass); - TerrainRenderer::PrepareShader(shader, shadow); - - Handle lastBlendTex = 0; + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + techBase->GetGraphicsPipelineStateDesc(pass); + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); + TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); + + Renderer::Backend::ITexture* lastBlendTex = nullptr; + + const int32_t baseTexBindingSlot = + shader->GetBindingSlot(str_baseTex); + const int32_t blendTexBindingSlot = + shader->GetBindingSlot(str_blendTex); + const int32_t textureTransformBindingSlot = + shader->GetBindingSlot(str_textureTransform); for (BatchesStack::iterator itt = itTechBegin; itt != itTechEnd; ++itt) { @@ -963,24 +1030,33 @@ { const CMaterial::SamplersVector& samplers = itt->m_Texture->GetMaterial().GetSamplers(); for (const CMaterial::TextureSampler& samp : samplers) - shader->BindTexture(samp.Name, samp.Sampler); + samp.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext); + for (const CMaterial::TextureSampler& samp : samplers) + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(samp.Name), + samp.Sampler->GetBackendTexture()); + } - Handle currentBlendTex = itt->m_Texture->m_TerrainAlpha->second.m_hCompositeAlphaMap; + Renderer::Backend::ITexture* currentBlendTex = itt->m_Texture->m_TerrainAlpha->second.m_CompositeAlphaMap.get(); if (currentBlendTex != lastBlendTex) { - shader->BindTexture(str_blendTex, currentBlendTex); + deviceCommandContext->SetTexture( + blendTexBindingSlot, currentBlendTex); lastBlendTex = currentBlendTex; } - itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(shader); + itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(deviceCommandContext, shader); float c = itt->m_Texture->GetTextureMatrix()[0]; float ms = itt->m_Texture->GetTextureMatrix()[8]; - shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); + deviceCommandContext->SetUniform( + textureTransformBindingSlot, c, ms); } else { - shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()); + deviceCommandContext->SetTexture( + baseTexBindingSlot, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); } for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv) @@ -990,28 +1066,44 @@ { lastVB = itv->first; previousShader = shader; - GLsizei stride = sizeof(SBlendVertex); - SBlendVertex *base = (SBlendVertex *)itv->first->Bind(); - shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); - 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]); - } + itv->first->UploadIfNeeded(deviceCommandContext); - shader->AssertPointersBound(); + const uint32_t stride = sizeof(SBlendVertex); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBlendVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBlendVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBlendVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SBlendVertex, m_AlphaUVs), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, itv->first->GetBuffer()); + } for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { - it->first->Bind(); + it->first->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(it->first->GetBuffer()); BatchElements& batch = it->second; - if (!g_Renderer.m_SkipSubmit) - { - for (size_t i = 0; i < batch.first.size(); ++i) - glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); - } + for (size_t i = 0; i < batch.first.size(); ++i) + deviceCommandContext->DrawIndexed(batch.second[i], batch.first[i], 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_BlendSplats++; @@ -1019,27 +1111,25 @@ } } } - techBase->EndPass(); + deviceCommandContext->EndPass(); } } - - glDisable(GL_BLEND); - - CVertexBuffer::Unbind(); } -void CPatchRData::RenderStreams(const std::vector& patches, const CShaderProgramPtr& shader, int streamflags) +void CPatchRData::RenderStreams( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const std::vector& patches, const bool bindPositionAsTexCoord) { PROFILE3("render terrain streams"); // Each batch has a list of index counts, and a list of pointers-to-first-indexes - using StreamBatchElements = std::pair, std::vector > ; + using StreamBatchElements = std::pair, std::vector>; // Group batches by index buffer - using StreamIndexBufferBatches = std::map ; + using StreamIndexBufferBatches = std::map; // Group batches by vertex buffer - using StreamVertexBufferBatches = std::map ; + using StreamVertexBufferBatches = std::map; StreamVertexBufferBatches batches; @@ -1052,46 +1142,48 @@ batch.first.push_back(patch->m_VBBaseIndices->m_Count); - u8* indexBase = nullptr; - batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index)); + batch.second.push_back(patch->m_VBBaseIndices->m_Index); } PROFILE_END("compute batches"); - ENSURE(!(streamflags & ~(STREAM_POS|STREAM_POSTOUV0|STREAM_POSTOUV1))); + const uint32_t stride = sizeof(SBaseVertex); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + if (bindPositionAsTexCoord) + { + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + } // Render each batch for (const std::pair& streamBatch : batches) { - GLsizei stride = sizeof(SBaseVertex); - SBaseVertex *base = (SBaseVertex *)streamBatch.first->Bind(); + streamBatch.first->UploadIfNeeded(deviceCommandContext); - shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position); - if (streamflags & STREAM_POSTOUV0) - 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); - - shader->AssertPointersBound(); + deviceCommandContext->SetVertexBuffer(0, streamBatch.first->GetBuffer()); for (const std::pair& batchIndexBuffer : streamBatch.second) { - batchIndexBuffer.first->Bind(); + batchIndexBuffer.first->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(batchIndexBuffer.first->GetBuffer()); const StreamBatchElements& batch = batchIndexBuffer.second; - if (!g_Renderer.m_SkipSubmit) - { - for (size_t i = 0; i < batch.first.size(); ++i) - glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); - } + for (size_t i = 0; i < batch.first.size(); ++i) + deviceCommandContext->DrawIndexed(batch.second[i], batch.first[i], 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; } } - - CVertexBuffer::Unbind(); } void CPatchRData::RenderOutline() @@ -1126,11 +1218,22 @@ g_Renderer.GetDebugRenderer().DrawLine(line, CColor(0.0f, 0.0f, 1.0f, 1.0f), 0.1f); } -void CPatchRData::RenderSides(const std::vector& patches, const CShaderProgramPtr& shader) +void CPatchRData::RenderSides( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const std::vector& patches) { PROFILE3("render terrain sides"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain sides"); + + if (patches.empty()) + return; - glDisable(GL_CULL_FACE); + const uint32_t stride = sizeof(SSideVertex); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SSideVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); CVertexBuffer* lastVB = nullptr; for (CPatchRData* patch : patches) @@ -1141,26 +1244,17 @@ if (lastVB != patch->m_VBSides->m_Owner) { lastVB = patch->m_VBSides->m_Owner; - SSideVertex *base = (SSideVertex*)patch->m_VBSides->m_Owner->Bind(); + patch->m_VBSides->m_Owner->UploadIfNeeded(deviceCommandContext); - // setup data pointers - GLsizei stride = sizeof(SSideVertex); - shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position); + deviceCommandContext->SetVertexBuffer(0, patch->m_VBSides->m_Owner->GetBuffer()); } - shader->AssertPointersBound(); - - if (!g_Renderer.m_SkipSubmit) - glDrawArrays(GL_TRIANGLE_STRIP, patch->m_VBSides->m_Index, (GLsizei)patch->m_VBSides->m_Count); + deviceCommandContext->Draw(patch->m_VBSides->m_Index, patch->m_VBSides->m_Count); // bump stats g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_TerrainTris += patch->m_VBSides->m_Count - 2; + g_Renderer.m_Stats.m_TerrainTris += patch->m_VBSides->m_Count / 3; } - - CVertexBuffer::Unbind(); - - glEnable(GL_CULL_FACE); } void CPatchRData::RenderPriorities(CTextRenderer& textRenderer) @@ -1217,17 +1311,17 @@ // Build data for water std::vector water_vertex_data; - std::vector water_indices; + std::vector water_indices; u16 water_index_map[PATCH_SIZE+1][PATCH_SIZE+1]; memset(water_index_map, 0xFF, sizeof(water_index_map)); // Build data for shore std::vector water_vertex_data_shore; - std::vector water_indices_shore; + std::vector water_indices_shore; u16 water_shore_index_map[PATCH_SIZE+1][PATCH_SIZE+1]; memset(water_shore_index_map, 0xFF, sizeof(water_shore_index_map)); - WaterManager* WaterMgr = g_Renderer.GetWaterManager(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); CPatch* patch = m_Patch; CTerrain* terrain = patch->m_Parent; @@ -1298,7 +1392,7 @@ m_WaterBounds += vertex.m_Position; - vertex.m_WaterData = CVector2D(WaterMgr->m_WindStrength[xx + zz*mapSize], depth); + vertex.m_WaterData = CVector2D(waterManager.m_WindStrength[xx + zz*mapSize], depth); water_index_map[z+moves[i][1]][x+moves[i][0]] = static_cast(water_vertex_data.size()); water_vertex_data.push_back(vertex); @@ -1360,81 +1454,104 @@ // No vertex buffers if no data generated if (!water_indices.empty()) { - m_VBWater = g_VBMan.AllocateChunk(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWater = g_VBMan.AllocateChunk( + sizeof(SWaterVertex), water_vertex_data.size(), + Renderer::Backend::IBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater.Get(), &water_vertex_data[0]); - m_VBWaterIndices = g_VBMan.AllocateChunk(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWaterIndices = g_VBMan.AllocateChunk( + sizeof(u16), water_indices.size(), + Renderer::Backend::IBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices.Get(), &water_indices[0]); } if (!water_indices_shore.empty()) { - m_VBWaterShore = g_VBMan.AllocateChunk(sizeof(SWaterVertex), water_vertex_data_shore.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWaterShore = g_VBMan.AllocateChunk( + sizeof(SWaterVertex), water_vertex_data_shore.size(), + Renderer::Backend::IBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWaterShore->m_Owner->UpdateChunkVertices(m_VBWaterShore.Get(), &water_vertex_data_shore[0]); // Construct indices buffer - m_VBWaterIndicesShore = g_VBMan.AllocateChunk(sizeof(GLushort), water_indices_shore.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWaterIndicesShore = g_VBMan.AllocateChunk( + sizeof(u16), water_indices_shore.size(), + Renderer::Backend::IBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWaterIndicesShore->m_Owner->UpdateChunkVertices(m_VBWaterIndicesShore.Get(), &water_indices_shore[0]); } } -void CPatchRData::RenderWater(CShaderProgramPtr& shader, bool onlyShore, bool fixedPipeline) +void CPatchRData::RenderWaterSurface( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const bool bindWaterData) { - ASSERT(m_UpdateFlags==0); + ASSERT(m_UpdateFlags == 0); - if (g_Renderer.m_SkipSubmit || (!m_VBWater && !m_VBWaterShore)) + if (!m_VBWater) return; -#if !CONFIG2_GLES - if (g_Renderer.GetWaterRenderMode() == WIREFRAME) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -#endif - - if (m_VBWater && !onlyShore) - { - SWaterVertex *base=(SWaterVertex *)m_VBWater->m_Owner->Bind(); - - // setup data pointers - GLsizei stride = sizeof(SWaterVertex); - shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_Position); - if (!fixedPipeline) - shader->VertexAttribPointer(str_a_waterInfo, 2, GL_FLOAT, false, stride, &base[m_VBWater->m_Index].m_WaterData); - - shader->AssertPointersBound(); - - u8* indexBase = m_VBWaterIndices->m_Owner->Bind(); - glDrawElements(GL_TRIANGLES, (GLsizei) m_VBWaterIndices->m_Count, - GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index)); + m_VBWater->m_Owner->UploadIfNeeded(deviceCommandContext); + m_VBWaterIndices->m_Owner->UploadIfNeeded(deviceCommandContext); - g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 3; - } + const uint32_t stride = sizeof(SWaterVertex); + const uint32_t firstVertexOffset = m_VBWater->m_Index * stride; - if (m_VBWaterShore && - g_Renderer.GetWaterManager()->m_WaterEffects && - g_Renderer.GetWaterManager()->m_WaterFancyEffects) + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + if (bindWaterData) { - SWaterVertex *base=(SWaterVertex *)m_VBWaterShore->m_Owner->Bind(); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + firstVertexOffset + offsetof(SWaterVertex, m_WaterData), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + } - GLsizei stride = sizeof(SWaterVertex); - shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWaterShore->m_Index].m_Position); - if (!fixedPipeline) - shader->VertexAttribPointer(str_a_waterInfo, 2, GL_FLOAT, false, stride, &base[m_VBWaterShore->m_Index].m_WaterData); + deviceCommandContext->SetVertexBuffer(0, m_VBWater->m_Owner->GetBuffer()); + deviceCommandContext->SetIndexBuffer(m_VBWaterIndices->m_Owner->GetBuffer()); - shader->AssertPointersBound(); + deviceCommandContext->DrawIndexed(m_VBWaterIndices->m_Index, m_VBWaterIndices->m_Count, 0); - u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind(); - glDrawElements(GL_TRIANGLES, (GLsizei) m_VBWaterIndicesShore->m_Count, - GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndicesShore->m_Index)); + g_Renderer.m_Stats.m_DrawCalls++; + g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 3; +} - g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndicesShore->m_Count / 3; - } +void CPatchRData::RenderWaterShore( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + ASSERT(m_UpdateFlags == 0); + + if (!m_VBWaterShore) + return; + + m_VBWaterShore->m_Owner->UploadIfNeeded(deviceCommandContext); + m_VBWaterIndicesShore->m_Owner->UploadIfNeeded(deviceCommandContext); + + const uint32_t stride = sizeof(SWaterVertex); + const uint32_t firstVertexOffset = m_VBWaterShore->m_Index * stride; + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + firstVertexOffset + offsetof(SWaterVertex, m_WaterData), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, m_VBWaterShore->m_Owner->GetBuffer()); + deviceCommandContext->SetIndexBuffer(m_VBWaterIndicesShore->m_Owner->GetBuffer()); - CVertexBuffer::Unbind(); + deviceCommandContext->DrawIndexed(m_VBWaterIndicesShore->m_Index, m_VBWaterIndicesShore->m_Count, 0); -#if !CONFIG2_GLES - if (g_Renderer.GetWaterRenderMode() == WIREFRAME) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif + g_Renderer.m_Stats.m_DrawCalls++; + g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndicesShore->m_Count / 3; } diff -Nru 0ad-0.0.25b/source/renderer/PatchRData.h 0ad-0.0.26/source/renderer/PatchRData.h --- 0ad-0.0.25b/source/renderer/PatchRData.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/PatchRData.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,9 +20,10 @@ #include "graphics/Patch.h" #include "graphics/RenderableObject.h" -#include "graphics/ShaderProgramPtr.h" #include "maths/Vector2D.h" #include "maths/Vector3D.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/VertexBufferManager.h" #include @@ -47,20 +48,30 @@ void RenderOutline(); void RenderPriorities(CTextRenderer& textRenderer); - void RenderWater(CShaderProgramPtr& shader, bool onlyShore = false, bool fixedPipeline = false); + void RenderWaterSurface( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const bool bindWaterData); + void RenderWaterShore( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); CPatch* GetPatch() { return m_Patch; } const CBoundingBoxAligned& GetWaterBounds() const { return m_WaterBounds; } static void RenderBases( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); static void RenderBlends( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); - static void RenderStreams(const std::vector& patches, const CShaderProgramPtr& shader, int streamflags); - static void RenderSides(const std::vector& patches, const CShaderProgramPtr& shader); + static void RenderStreams( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const std::vector& patches, const bool bindPositionAsTexCoord); + static void RenderSides( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const std::vector& patches); - static void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow); + static void PrepareShader(ShadowMap* shadow); private: friend struct SBlendStackItem; diff -Nru 0ad-0.0.25b/source/renderer/PostprocManager.cpp 0ad-0.0.26/source/renderer/PostprocManager.cpp --- 0ad-0.0.25b/source/renderer/PostprocManager.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/PostprocManager.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,27 +23,22 @@ #include "graphics/LightEnv.h" #include "graphics/ShaderManager.h" #include "lib/bits.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "ps/ConfigDB.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/Game.h" +#include "ps/VideoMode.h" #include "ps/World.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "tools/atlas/GameInterface/GameLoop.h" -#if !CONFIG2_GLES - CPostprocManager::CPostprocManager() - : m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"), - m_ColorTex1(0), m_ColorTex2(0), m_DepthTex(0), m_BloomFbo(0), m_BlurTex2a(0), - m_BlurTex2b(0), m_BlurTex4a(0), m_BlurTex4b(0), m_BlurTex8a(0), m_BlurTex8b(0), - m_WhichBuffer(true), m_Sharpness(0.3f), m_UsingMultisampleBuffer(false), - m_MultisampleFBO(0), m_MultisampleColorTex(0), m_MultisampleDepthTex(0), - m_MultisampleCount(0) + : m_IsInitialized(false), m_PostProcEffect(L"default"), m_WhichBuffer(true), + m_Sharpness(0.3f), m_UsingMultisampleBuffer(false), m_MultisampleCount(0) { } @@ -52,28 +47,37 @@ Cleanup(); } +bool CPostprocManager::IsEnabled() const +{ + return + g_RenderingOptions.GetPostProc() && + g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB && + g_VideoMode.GetBackendDevice()->IsTextureFormatSupported( + Renderer::Backend::Format::D24_S8); +} + void CPostprocManager::Cleanup() { if (!m_IsInitialized) // Only cleanup if previously used return; - if (m_PingFbo) pglDeleteFramebuffersEXT(1, &m_PingFbo); - if (m_PongFbo) pglDeleteFramebuffersEXT(1, &m_PongFbo); - if (m_BloomFbo) pglDeleteFramebuffersEXT(1, &m_BloomFbo); - m_PingFbo = m_PongFbo = m_BloomFbo = 0; - - if (m_ColorTex1) glDeleteTextures(1, &m_ColorTex1); - if (m_ColorTex2) glDeleteTextures(1, &m_ColorTex2); - if (m_DepthTex) glDeleteTextures(1, &m_DepthTex); - m_ColorTex1 = m_ColorTex2 = m_DepthTex = 0; - - if (m_BlurTex2a) glDeleteTextures(1, &m_BlurTex2a); - if (m_BlurTex2b) glDeleteTextures(1, &m_BlurTex2b); - if (m_BlurTex4a) glDeleteTextures(1, &m_BlurTex4a); - if (m_BlurTex4b) glDeleteTextures(1, &m_BlurTex4b); - if (m_BlurTex8a) glDeleteTextures(1, &m_BlurTex8a); - if (m_BlurTex8b) glDeleteTextures(1, &m_BlurTex8b); - m_BlurTex2a = m_BlurTex2b = m_BlurTex4a = m_BlurTex4b = m_BlurTex8a = m_BlurTex8b = 0; + m_CaptureFramebuffer.reset(); + + m_PingFramebuffer.reset(); + m_PongFramebuffer.reset(); + + m_ColorTex1.reset(); + m_ColorTex2.reset(); + m_DepthTex.reset(); + + for (BlurScale& scale : m_BlurScales) + { + for (BlurScale::Step& step : scale.steps) + { + step.framebuffer.reset(); + step.texture.reset(); + } + } } void CPostprocManager::Initialize() @@ -81,13 +85,12 @@ if (m_IsInitialized) return; - GLint maxSamples = 0; - glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); - const GLsizei possibleSampleCounts[] = {2, 4, 8, 16}; + const uint32_t maxSamples = g_VideoMode.GetBackendDevice()->GetCapabilities().maxSampleCount; + const uint32_t possibleSampleCounts[] = {2, 4, 8, 16}; std::copy_if( std::begin(possibleSampleCounts), std::end(possibleSampleCounts), std::back_inserter(m_AllowedSampleCounts), - [maxSamples](const GLsizei sampleCount) { return sampleCount <= maxSamples; } ); + [maxSamples](const uint32_t sampleCount) { return sampleCount <= maxSamples; } ); // The screen size starts out correct and then must be updated with Resize() m_Width = g_Renderer.GetWidth(); @@ -119,14 +122,14 @@ { Cleanup(); + Renderer::Backend::IDevice* backendDevice = g_VideoMode.GetBackendDevice(); + #define GEN_BUFFER_RGBA(name, w, h) \ - glGenTextures(1, (GLuint*)&name); \ - glBindTexture(GL_TEXTURE_2D, name); \ - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); \ - 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_CLAMP_TO_EDGE); \ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + name = backendDevice->CreateTexture2D( \ + "PostProc" #name, Renderer::Backend::Format::R8G8B8A8_UNORM, w, h, \ + Renderer::Backend::Sampler::MakeDefaultSampler( \ + Renderer::Backend::Sampler::Filter::LINEAR, \ + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); // Two fullscreen ping-pong textures. GEN_BUFFER_RGBA(m_ColorTex1, m_Width, m_Height); @@ -136,120 +139,79 @@ // m_BlurTex2b, thus avoiding the need for m_BlurTex4b and m_BlurTex8b, though given // that these are fairly small it's probably not worth complicating the coordinates passed // to the blur helper functions. - GEN_BUFFER_RGBA(m_BlurTex2a, m_Width / 2, m_Height / 2); - GEN_BUFFER_RGBA(m_BlurTex2b, m_Width / 2, m_Height / 2); - - GEN_BUFFER_RGBA(m_BlurTex4a, m_Width / 4, m_Height / 4); - GEN_BUFFER_RGBA(m_BlurTex4b, m_Width / 4, m_Height / 4); - - GEN_BUFFER_RGBA(m_BlurTex8a, m_Width / 8, m_Height / 8); - GEN_BUFFER_RGBA(m_BlurTex8b, m_Width / 8, m_Height / 8); + uint32_t width = m_Width / 2, height = m_Height / 2; + for (BlurScale& scale : m_BlurScales) + { + for (BlurScale::Step& step : scale.steps) + { + GEN_BUFFER_RGBA(step.texture, width, height); + step.framebuffer = backendDevice->CreateFramebuffer("BlurScaleSteoFramebuffer", + step.texture.get(), nullptr); + } + width /= 2; + height /= 2; + } #undef GEN_BUFFER_RGBA // Allocate the Depth/Stencil texture. - glGenTextures(1, (GLuint*)&m_DepthTex); - glBindTexture(GL_TEXTURE_2D, m_DepthTex); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, m_Width, m_Height, - 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - 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_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, 0); + m_DepthTex = backendDevice->CreateTexture2D("PostPRocDepthTexture", + Renderer::Backend::Format::D24_S8, m_Width, m_Height, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); // Set up the framebuffers with some initial textures. + m_CaptureFramebuffer = backendDevice->CreateFramebuffer("PostprocCaptureFramebuffer", + m_ColorTex1.get(), m_DepthTex.get(), + g_VideoMode.GetBackendDevice()->GetCurrentBackbuffer()->GetClearColor()); + + m_PingFramebuffer = backendDevice->CreateFramebuffer("PostprocPingFramebuffer", + m_ColorTex1.get(), nullptr); + m_PongFramebuffer = backendDevice->CreateFramebuffer("PostprocPongFramebuffer", + m_ColorTex2.get(), nullptr); - pglGenFramebuffersEXT(1, &m_PingFbo); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_ColorTex1, 0); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, m_DepthTex, 0); - - GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (!m_CaptureFramebuffer || !m_PingFramebuffer || !m_PongFramebuffer) { - LOGWARNING("Framebuffer object incomplete (A): 0x%04X", status); + LOGWARNING("Failed to create postproc framebuffers"); + g_RenderingOptions.SetPostProc(false); } - pglGenFramebuffersEXT(1, &m_PongFbo); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_ColorTex2, 0); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, m_DepthTex, 0); - - status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Framebuffer object incomplete (B): 0x%04X", status); - } - - pglGenFramebuffersEXT(1, &m_BloomFbo); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - - /* - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_BloomTex1, 0); - - status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Framebuffer object incomplete (B): 0x%04X", status); - } - */ - if (m_UsingMultisampleBuffer) { DestroyMultisampleBuffer(); CreateMultisampleBuffer(); } - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } -void CPostprocManager::ApplyBlurDownscale2x(GLuint inTex, GLuint outTex, int inWidth, int inHeight) +void CPostprocManager::ApplyBlurDownscale2x( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IFramebuffer* framebuffer, + Renderer::Backend::ITexture* inTex, int inWidth, int inHeight) { - // Bind inTex to framebuffer for rendering. - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, outTex, 0); + deviceCommandContext->SetFramebuffer(framebuffer); // Get bloom shader with instructions to simply copy texels. CShaderDefines defines; defines.Add(str_BLOOM_NOP, str_1); - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, - g_Renderer.GetSystemShaderDefines(), defines); - - tech->BeginPass(); - CShaderProgramPtr shader = tech->GetShader(); + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines); - GLuint renderedTex = inTex; + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); - // Cheat by creating high quality mipmaps for inTex, so the copying operation actually - // produces good scaling due to hardware filtering. - glBindTexture(GL_TEXTURE_2D, renderedTex); - pglGenerateMipmapEXT(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - - shader->BindTexture(str_renderedTex, renderedTex); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), inTex); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = { 0, 0, inWidth / 2, inHeight / 2 }; g_Renderer.SetViewport(vp); - float quadVerts[] = { + // TODO: remove the fullscreen quad drawing duplication. + float quadVerts[] = + { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, @@ -258,7 +220,8 @@ 1.0f, -1.0f, 1.0f, 1.0f }; - float quadTex[] = { + float quadTex[] = + { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -267,38 +230,58 @@ 1.0f, 0.0f, 1.0f, 1.0f }; - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); + + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); - tech->EndPass(); + deviceCommandContext->EndPass(); } -void CPostprocManager::ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight) +void CPostprocManager::ApplyBlurGauss( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::ITexture* inTex, + Renderer::Backend::ITexture* tempTex, + Renderer::Backend::IFramebuffer* tempFramebuffer, + Renderer::Backend::IFramebuffer* outFramebuffer, + int inWidth, int inHeight) { - // Set tempTex as our rendering target. - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tempTex, 0); + deviceCommandContext->SetFramebuffer(tempFramebuffer); // Get bloom shader, for a horizontal Gaussian blur pass. CShaderDefines defines2; defines2.Add(str_BLOOM_PASS_H, str_1); - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, - g_Renderer.GetSystemShaderDefines(), defines2); + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines2); - tech->BeginPass(); - CShaderProgramPtr shader = tech->GetShader(); - shader->BindTexture(str_renderedTex, inOutTex); - shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), inTex); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_texSize), inWidth, inHeight); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = { 0, 0, inWidth, inHeight }; g_Renderer.SetViewport(vp); - float quadVerts[] = { + float quadVerts[] = + { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, @@ -307,7 +290,8 @@ 1.0f, -1.0f, 1.0f, 1.0f }; - float quadTex[] = { + float quadTex[] = + { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -316,152 +300,162 @@ 1.0f, 0.0f, 1.0f, 1.0f }; - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); + + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); - tech->EndPass(); + deviceCommandContext->EndPass(); - // Set result texture as our render target. - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, inOutTex, 0); + deviceCommandContext->SetFramebuffer(outFramebuffer); // Get bloom shader, for a vertical Gaussian blur pass. CShaderDefines defines3; defines3.Add(str_BLOOM_PASS_V, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, - g_Renderer.GetSystemShaderDefines(), defines3); + tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines3); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); - tech->BeginPass(); + deviceCommandContext->BeginPass(); shader = tech->GetShader(); // Our input texture to the shader is the output of the horizontal pass. - shader->BindTexture(str_renderedTex, tempTex); - shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), tempTex); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_texSize), inWidth, inHeight); g_Renderer.SetViewport(vp); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); + + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); - tech->EndPass(); + deviceCommandContext->EndPass(); } -void CPostprocManager::ApplyBlur() +void CPostprocManager::ApplyBlur( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - glDisable(GL_BLEND); - - int width = m_Width, height = m_Height; + uint32_t width = m_Width, height = m_Height; + Renderer::Backend::ITexture* previousTexture = + (m_WhichBuffer ? m_ColorTex1 : m_ColorTex2).get(); - #define SCALE_AND_BLUR(tex1, tex2, temptex) \ - ApplyBlurDownscale2x(tex1, tex2, width, height); \ - width /= 2; \ - height /= 2; \ - ApplyBlurGauss(tex2, temptex, width, height); - - // We do the same thing for each scale, incrementally adding more and more blur. - SCALE_AND_BLUR(m_WhichBuffer ? m_ColorTex1 : m_ColorTex2, m_BlurTex2a, m_BlurTex2b); - SCALE_AND_BLUR(m_BlurTex2a, m_BlurTex4a, m_BlurTex4b); - SCALE_AND_BLUR(m_BlurTex4a, m_BlurTex8a, m_BlurTex8b); - - #undef SCALE_AND_BLUR + for (BlurScale& scale : m_BlurScales) + { + ApplyBlurDownscale2x(deviceCommandContext, scale.steps[0].framebuffer.get(), previousTexture, width, height); + width /= 2; + height /= 2; + ApplyBlurGauss(deviceCommandContext, scale.steps[0].texture.get(), + scale.steps[1].texture.get(), scale.steps[1].framebuffer.get(), + scale.steps[0].framebuffer.get(), width, height); + } } -void CPostprocManager::CaptureRenderOutput() +void CPostprocManager::CaptureRenderOutput( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { ENSURE(m_IsInitialized); // Leaves m_PingFbo selected for rendering; m_WhichBuffer stays true at this point. - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - - GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; - pglDrawBuffers(1, buffers); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - pglDrawBuffers(1, buffers); + if (m_UsingMultisampleBuffer) + deviceCommandContext->SetFramebuffer(m_MultisampleFramebuffer.get()); + else + deviceCommandContext->SetFramebuffer(m_CaptureFramebuffer.get()); m_WhichBuffer = true; - - if (m_UsingMultisampleBuffer) - { - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_MultisampleFBO); - pglDrawBuffers(1, buffers); - } } -void CPostprocManager::ReleaseRenderOutput() +void CPostprocManager::ReleaseRenderOutput( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { ENSURE(m_IsInitialized); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - // we blit to screen from the previous active buffer - if (m_WhichBuffer) - pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_PingFbo); - else - pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_PongFbo); + GPU_SCOPED_LABEL(deviceCommandContext, "Copy postproc to backbuffer"); - pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - pglBlitFramebufferEXT(0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height, - GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); + // We blit to the backbuffer from the previous active buffer. + deviceCommandContext->BlitFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer(), + (m_WhichBuffer ? m_PingFramebuffer : m_PongFramebuffer).get()); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } -void CPostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1, int pass) +void CPostprocManager::ApplyEffect( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderTechniquePtr& shaderTech, int pass) { // select the other FBO for rendering - if (!m_WhichBuffer) - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - else - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); + deviceCommandContext->SetFramebuffer( + (m_WhichBuffer ? m_PongFramebuffer : m_PingFramebuffer).get()); - shaderTech1->BeginPass(pass); - CShaderProgramPtr shader = shaderTech1->GetShader(pass); - - shader->Bind(); + deviceCommandContext->SetGraphicsPipelineState( + shaderTech->GetGraphicsPipelineStateDesc(pass)); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(pass); // Use the textures from the current FBO as input to the shader. // We also bind a bunch of other textures and parameters, but since // this only happens once per frame the overhead is negligible. - if (m_WhichBuffer) - shader->BindTexture(str_renderedTex, m_ColorTex1); - else - shader->BindTexture(str_renderedTex, m_ColorTex2); - - shader->BindTexture(str_depthTex, m_DepthTex); - - shader->BindTexture(str_blurTex2, m_BlurTex2a); - shader->BindTexture(str_blurTex4, m_BlurTex4a); - shader->BindTexture(str_blurTex8, m_BlurTex8a); - - shader->Uniform(str_width, m_Width); - shader->Uniform(str_height, m_Height); - shader->Uniform(str_zNear, m_NearPlane); - shader->Uniform(str_zFar, m_FarPlane); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), + m_WhichBuffer ? m_ColorTex1.get() : m_ColorTex2.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_depthTex), m_DepthTex.get()); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_blurTex2), m_BlurScales[0].steps[0].texture.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_blurTex4), m_BlurScales[1].steps[0].texture.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_blurTex8), m_BlurScales[2].steps[0].texture.get()); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_width), m_Width); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_height), m_Height); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_zNear), m_NearPlane); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_zFar), m_FarPlane); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_sharpness), m_Sharpness); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_brightness), g_LightEnv.m_Brightness); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_hdr), g_LightEnv.m_Contrast); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_saturation), g_LightEnv.m_Saturation); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_bloom), g_LightEnv.m_Bloom); - shader->Uniform(str_sharpness, m_Sharpness); - - shader->Uniform(str_brightness, g_LightEnv.m_Brightness); - shader->Uniform(str_hdr, g_LightEnv.m_Contrast); - shader->Uniform(str_saturation, g_LightEnv.m_Saturation); - shader->Uniform(str_bloom, g_LightEnv.m_Bloom); - - float quadVerts[] = { + float quadVerts[] = + { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, @@ -470,7 +464,8 @@ 1.0f, -1.0f, 1.0f, 1.0f }; - float quadTex[] = { + float quadTex[] = + { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -479,75 +474,63 @@ 1.0f, 0.0f, 1.0f, 1.0f }; - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); - shader->Unbind(); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); - shaderTech1->EndPass(pass); + deviceCommandContext->Draw(0, 6); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); + deviceCommandContext->EndPass(); m_WhichBuffer = !m_WhichBuffer; } -void CPostprocManager::ApplyPostproc() +void CPostprocManager::ApplyPostproc( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { ENSURE(m_IsInitialized); // Don't do anything if we are using the default effect and no AA. const bool hasEffects = m_PostProcEffect != L"default"; - const bool hasAA = m_AATech && g_RenderingOptions.GetPreferGLSL(); - const bool hasSharp = m_SharpTech && g_RenderingOptions.GetPreferGLSL(); + const bool hasARB = g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB; + const bool hasAA = m_AATech && !hasARB; + const bool hasSharp = m_SharpTech && !hasARB; if (!hasEffects && !hasAA && !hasSharp) return; - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0); - - GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT }; - pglDrawBuffers(1, buffers); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0); - pglDrawBuffers(1, buffers); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + GPU_SCOPED_LABEL(deviceCommandContext, "Render postproc"); if (hasEffects) { // First render blur textures. Note that this only happens ONLY ONCE, before any effects are applied! // (This may need to change depending on future usage, however that will have a fps hit) - ApplyBlur(); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); + ApplyBlur(deviceCommandContext); for (int pass = 0; pass < m_PostProcTech->GetNumPasses(); ++pass) - ApplyEffect(m_PostProcTech, pass); + ApplyEffect(deviceCommandContext, m_PostProcTech, pass); } if (hasAA) { for (int pass = 0; pass < m_AATech->GetNumPasses(); ++pass) - ApplyEffect(m_AATech, pass); + ApplyEffect(deviceCommandContext, m_AATech, pass); } if (hasSharp) { for (int pass = 0; pass < m_SharpTech->GetNumPasses(); ++pass) - ApplyEffect(m_SharpTech, pass); + ApplyEffect(deviceCommandContext, m_SharpTech, pass); } - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0); } @@ -590,7 +573,7 @@ void CPostprocManager::UpdateAntiAliasingTechnique() { - if (!g_RenderingOptions.GetPreferGLSL() || !m_IsInitialized) + if (g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB || !m_IsInitialized) return; CStr newAAName; @@ -616,17 +599,10 @@ } else if (m_AAName.size() > msaaPrefix.size() && m_AAName.substr(0, msaaPrefix.size()) == msaaPrefix) { -#if !CONFIG2_GLES // We don't want to enable MSAA in Atlas, because it uses wxWidgets and its canvas. if (g_AtlasGameLoop && g_AtlasGameLoop->running) return; - const bool is_msaa_supported = - ogl_HaveVersion("3.3") && - ogl_HaveExtension("GL_ARB_multisample") && - ogl_HaveExtension("GL_ARB_texture_multisample") && - !m_AllowedSampleCounts.empty() && - g_RenderingOptions.GetPreferGLSL(); - if (!is_msaa_supported) + if (!g_VideoMode.GetBackendDevice()->GetCapabilities().multisampling || m_AllowedSampleCounts.empty()) { LOGWARNING("MSAA is unsupported."); return; @@ -636,21 +612,17 @@ if (std::find(std::begin(m_AllowedSampleCounts), std::end(m_AllowedSampleCounts), m_MultisampleCount) == std::end(m_AllowedSampleCounts)) { - m_MultisampleCount = 4; + m_MultisampleCount = std::min(4u, g_VideoMode.GetBackendDevice()->GetCapabilities().maxSampleCount); LOGWARNING("Wrong MSAA sample count: %s.", m_AAName.EscapeToPrintableASCII().c_str()); } m_UsingMultisampleBuffer = true; CreateMultisampleBuffer(); -#else - #warning TODO: implement and test MSAA for GLES - LOGWARNING("MSAA is unsupported."); -#endif } } void CPostprocManager::UpdateSharpeningTechnique() { - if (!g_RenderingOptions.GetPreferGLSL() || !m_IsInitialized) + if (g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB || !m_IsInitialized) return; CStr newSharpName; @@ -679,56 +651,43 @@ void CPostprocManager::CreateMultisampleBuffer() { - glEnable(GL_MULTISAMPLE); + Renderer::Backend::IDevice* backendDevice = g_VideoMode.GetBackendDevice(); - glGenTextures(1, &m_MultisampleColorTex); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleColorTex); - pglTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleCount, GL_RGBA, m_Width, m_Height, GL_TRUE); + m_MultisampleColorTex = backendDevice->CreateTexture("PostProcColorMS", + Renderer::Backend::ITexture::Type::TEXTURE_2D_MULTISAMPLE, + Renderer::Backend::Format::R8G8B8A8_UNORM, m_Width, m_Height, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, m_MultisampleCount); // Allocate the Depth/Stencil texture. - glGenTextures(1, &m_MultisampleDepthTex); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleDepthTex); - pglTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleCount, GL_DEPTH24_STENCIL8_EXT, m_Width, m_Height, GL_TRUE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); - - ogl_WarnIfError(); + m_MultisampleDepthTex = backendDevice->CreateTexture("PostProcDepthMS", + Renderer::Backend::ITexture::Type::TEXTURE_2D_MULTISAMPLE, + Renderer::Backend::Format::D24_S8, m_Width, m_Height, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, m_MultisampleCount); // Set up the framebuffers with some initial textures. - pglGenFramebuffersEXT(1, &m_MultisampleFBO); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_MultisampleFBO); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleColorTex, 0); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleDepthTex, 0); + m_MultisampleFramebuffer = backendDevice->CreateFramebuffer("PostprocMultisampleFramebuffer", + m_MultisampleColorTex.get(), m_MultisampleDepthTex.get(), + g_VideoMode.GetBackendDevice()->GetCurrentBackbuffer()->GetClearColor()); - GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (!m_MultisampleFramebuffer) { - LOGWARNING("Multisample framebuffer object incomplete (A): 0x%04X", status); + LOGERROR("Failed to create postproc multisample framebuffer"); m_UsingMultisampleBuffer = false; DestroyMultisampleBuffer(); } - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); - glBindTexture(GL_TEXTURE_2D, 0); } void CPostprocManager::DestroyMultisampleBuffer() { if (m_UsingMultisampleBuffer) return; - if (m_MultisampleFBO) - pglDeleteFramebuffersEXT(1, &m_MultisampleFBO); - if (m_MultisampleColorTex) - glDeleteTextures(1, &m_MultisampleColorTex); - if (m_MultisampleDepthTex) - glDeleteTextures(1, &m_MultisampleDepthTex); - glDisable(GL_MULTISAMPLE); + m_MultisampleFramebuffer.reset(); + m_MultisampleColorTex.reset(); + m_MultisampleDepthTex.reset(); } bool CPostprocManager::IsMultisampleEnabled() const @@ -736,110 +695,14 @@ return m_UsingMultisampleBuffer; } -void CPostprocManager::ResolveMultisampleFramebuffer() +void CPostprocManager::ResolveMultisampleFramebuffer( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { if (!m_UsingMultisampleBuffer) return; - pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_PingFbo); - pglBlitFramebufferEXT(0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height, - GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); -} - -#else - -#warning TODO: implement PostprocManager for GLES - -void ApplyBlurDownscale2x(GLuint UNUSED(inTex), GLuint UNUSED(outTex), int UNUSED(inWidth), int UNUSED(inHeight)) -{ -} - -void CPostprocManager::ApplyBlurGauss(GLuint UNUSED(inOutTex), GLuint UNUSED(tempTex), int UNUSED(inWidth), int UNUSED(inHeight)) -{ -} - -void CPostprocManager::ApplyEffect(CShaderTechniquePtr &UNUSED(shaderTech1), int UNUSED(pass)) -{ -} - -CPostprocManager::CPostprocManager() -{ -} - -CPostprocManager::~CPostprocManager() -{ -} - -void CPostprocManager::Initialize() -{ -} - -void CPostprocManager::Resize() -{ -} - -void CPostprocManager::Cleanup() -{ + GPU_SCOPED_LABEL(deviceCommandContext, "Resolve postproc multisample"); + deviceCommandContext->BlitFramebuffer( + m_PingFramebuffer.get(), m_MultisampleFramebuffer.get()); + deviceCommandContext->SetFramebuffer(m_PingFramebuffer.get()); } - -void CPostprocManager::RecreateBuffers() -{ -} - -std::vector CPostprocManager::GetPostEffects() -{ - return std::vector(); -} - -void CPostprocManager::SetPostEffect(const CStrW& UNUSED(name)) -{ -} - -void CPostprocManager::SetDepthBufferClipPlanes(float UNUSED(nearPlane), float UNUSED(farPlane)) -{ -} - -void CPostprocManager::UpdateAntiAliasingTechnique() -{ -} - -void CPostprocManager::UpdateSharpeningTechnique() -{ -} - -void CPostprocManager::UpdateSharpnessFactor() -{ -} - -void CPostprocManager::CaptureRenderOutput() -{ -} - -void CPostprocManager::ApplyPostproc() -{ -} - -void CPostprocManager::ReleaseRenderOutput() -{ -} - -void CPostprocManager::CreateMultisampleBuffer() -{ -} - -void CPostprocManager::DestroyMultisampleBuffer() -{ -} - -bool CPostprocManager::IsMultisampleEnabled() const -{ - return false; -} - -void CPostprocManager::ResolveMultisampleFramebuffer() -{ -} - -#endif diff -Nru 0ad-0.0.25b/source/renderer/PostprocManager.h 0ad-0.0.26/source/renderer/PostprocManager.h --- 0ad-0.0.25b/source/renderer/PostprocManager.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/PostprocManager.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,9 +19,12 @@ #define INCLUDED_POSTPROCMANAGER #include "graphics/ShaderTechniquePtr.h" -#include "lib/ogl.h" #include "ps/CStr.h" +#include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/ITexture.h" +#include #include class CPostprocManager @@ -30,6 +33,9 @@ CPostprocManager(); ~CPostprocManager(); + // Returns true if the the manager can be used. + bool IsEnabled() const; + // Create all buffers/textures in GPU memory and set default effect. // @note Must be called before using in the renderer. May be called multiple times. void Initialize(); @@ -59,40 +65,53 @@ // Clears the two color buffers and depth buffer, and redirects all rendering // to our textures instead of directly to the system framebuffer. // @note CPostprocManager must be initialized first - void CaptureRenderOutput(); + void CaptureRenderOutput( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); // First renders blur textures, then calls ApplyEffect for each effect pass, // ping-ponging the buffers at each step. // @note CPostprocManager must be initialized first - void ApplyPostproc(); + void ApplyPostproc( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); // Blits the final postprocessed texture to the system framebuffer. The system framebuffer // is selected as the output buffer. Should be called before silhouette rendering. // @note CPostprocManager must be initialized first - void ReleaseRenderOutput(); + void ReleaseRenderOutput(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); // Returns true if we render main scene in the MSAA framebuffer. bool IsMultisampleEnabled() const; // Resolves the MSAA framebuffer into the regular one. - void ResolveMultisampleFramebuffer(); + void ResolveMultisampleFramebuffer( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); private: void CreateMultisampleBuffer(); void DestroyMultisampleBuffer(); // Two framebuffers, that we flip between at each shader pass. - GLuint m_PingFbo, m_PongFbo; + std::unique_ptr + m_CaptureFramebuffer, m_PingFramebuffer, m_PongFramebuffer; // Unique color textures for the framebuffers. - GLuint m_ColorTex1, m_ColorTex2; + std::unique_ptr m_ColorTex1, m_ColorTex2; // The framebuffers share a depth/stencil texture. - GLuint m_DepthTex; + std::unique_ptr m_DepthTex; float m_NearPlane, m_FarPlane; // A framebuffer and textures x2 for each blur level we render. - GLuint m_BloomFbo, m_BlurTex2a, m_BlurTex2b, m_BlurTex4a, m_BlurTex4b, m_BlurTex8a, m_BlurTex8b; + struct BlurScale + { + struct Step + { + std::unique_ptr framebuffer; + std::unique_ptr texture; + }; + std::array steps; + }; + std::array m_BlurScales; // Indicates which of the ping-pong buffers is used for reading and which for drawing. bool m_WhichBuffer; @@ -109,10 +128,11 @@ CStr m_AAName; CShaderTechniquePtr m_AATech; bool m_UsingMultisampleBuffer; - GLuint m_MultisampleFBO; - GLuint m_MultisampleColorTex, m_MultisampleDepthTex; - GLsizei m_MultisampleCount; - std::vector m_AllowedSampleCounts; + std::unique_ptr m_MultisampleFramebuffer; + std::unique_ptr + m_MultisampleColorTex, m_MultisampleDepthTex; + uint32_t m_MultisampleCount; + std::vector m_AllowedSampleCounts; // The current screen dimensions in pixels. int m_Width, m_Height; @@ -121,22 +141,35 @@ bool m_IsInitialized; // Creates blur textures at various scales, for bloom, DOF, etc. - void ApplyBlur(); + void ApplyBlur( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); // High quality GPU image scaling to half size. outTex must have exactly half the size // of inTex. inWidth and inHeight are the dimensions of inTex in texels. - void ApplyBlurDownscale2x(GLuint inTex, GLuint outTex, int inWidth, int inHeight); + void ApplyBlurDownscale2x( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IFramebuffer* framebuffer, + Renderer::Backend::ITexture* inTex, + int inWidth, int inHeight); // GPU-based Gaussian blur in two passes. inOutTex contains the input image and will be filled // with the blurred image. tempTex must have the same size as inOutTex. // inWidth and inHeight are the dimensions of the images in texels. - void ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight); + void ApplyBlurGauss( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::ITexture* inTex, + Renderer::Backend::ITexture* tempTex, + Renderer::Backend::IFramebuffer* tempFramebuffer, + Renderer::Backend::IFramebuffer* outFramebuffer, + int inWidth, int inHeight); // Applies a pass of a given effect to the entire current framebuffer. The shader is // provided with a number of general-purpose variables, including the rendered screen so far, // the depth buffer, a number of blur textures, the screen size, the zNear/zFar planes and // some other parameters used by the optional bloom/HDR pass. - void ApplyEffect(CShaderTechniquePtr &shaderTech1, int pass); + void ApplyEffect( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderTechniquePtr& shaderTech, int pass); // Delete all allocated buffers/textures from GPU memory. void Cleanup(); diff -Nru 0ad-0.0.25b/source/renderer/Renderer.cpp 0ad-0.0.26/source/renderer/Renderer.cpp --- 0ad-0.0.25b/source/renderer/Renderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/Renderer.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,72 +15,58 @@ * along with 0 A.D. If not, see . */ -/* - * higher level interface on top of OpenGL to render basic objects: - * terrain, models, sprites, particles etc. - */ - #include "precompiled.h" #include "Renderer.h" -#include "lib/bits.h" // is_pow2 -#include "lib/res/graphics/ogl_tex.h" +#include "graphics/Canvas2D.h" +#include "graphics/CinemaManager.h" +#include "graphics/GameView.h" +#include "graphics/LightEnv.h" +#include "graphics/ModelDef.h" +#include "graphics/TerrainTextureManager.h" +#include "i18n/L10n.h" #include "lib/allocators/shared_ptr.h" -#include "maths/Matrix3D.h" -#include "maths/MathUtil.h" +#include "lib/tex/tex.h" +#include "gui/GUIManager.h" +#include "ps/CConsole.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" #include "ps/Game.h" +#include "ps/GameSetup/Config.h" +#include "ps/GameSetup/GameSetup.h" +#include "ps/Globals.h" +#include "ps/Loader.h" #include "ps/Profile.h" #include "ps/Filesystem.h" #include "ps/World.h" -#include "ps/Loader.h" #include "ps/ProfileViewer.h" #include "graphics/Camera.h" -#include "graphics/Decal.h" #include "graphics/FontManager.h" -#include "graphics/GameView.h" -#include "graphics/LightEnv.h" -#include "graphics/LOSTexture.h" -#include "graphics/MaterialManager.h" -#include "graphics/MiniMapTexture.h" -#include "graphics/Model.h" -#include "graphics/ModelDef.h" -#include "graphics/ParticleManager.h" -#include "graphics/Patch.h" #include "graphics/ShaderManager.h" #include "graphics/Terrain.h" #include "graphics/Texture.h" #include "graphics/TextureManager.h" +#include "ps/Util.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" #include "renderer/DebugRenderer.h" -#include "renderer/HWLightingModelRenderer.h" -#include "renderer/InstancingModelRenderer.h" -#include "renderer/ModelRenderer.h" -#include "renderer/OverlayRenderer.h" -#include "renderer/ParticleRenderer.h" #include "renderer/PostprocManager.h" #include "renderer/RenderingOptions.h" #include "renderer/RenderModifiers.h" -#include "renderer/ShadowMap.h" -#include "renderer/SilhouetteRenderer.h" -#include "renderer/SkyManager.h" -#include "renderer/TerrainOverlay.h" -#include "renderer/TerrainRenderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TimeManager.h" #include "renderer/VertexBufferManager.h" -#include "renderer/WaterManager.h" +#include "tools/atlas/GameInterface/GameLoop.h" +#include "tools/atlas/GameInterface/View.h" #include -#include -#include -#include -struct SScreenRect +namespace { - GLint x1, y1, x2, y2; -}; + +size_t g_NextScreenShotNumber = 0; /////////////////////////////////////////////////////////////////////////////////// // CRendererStatsTable - Profile display of rendering stats @@ -113,7 +99,8 @@ /// Column descriptions std::vector columnDescriptions; - enum { + enum + { Row_DrawCalls = 0, Row_TerrainTris, Row_WaterTris, @@ -242,6 +229,7 @@ return 0; } +} // anonymous namespace /////////////////////////////////////////////////////////////////////////////////// // CRenderer implementation @@ -250,10 +238,12 @@ * Struct CRendererInternals: Truly hide data that is supposed to be hidden * in this structure so it won't even appear in header files. */ -struct CRendererInternals +class CRenderer::Internals { - NONCOPYABLE(CRendererInternals); + NONCOPYABLE(Internals); public: + std::unique_ptr deviceCommandContext; + /// true if CRenderer::Open has been called bool IsOpen; @@ -266,287 +256,80 @@ /// Shader manager CShaderManager shaderManager; - /// Water manager - WaterManager waterManager; - - /// Sky manager - SkyManager skyManager; - /// Texture manager CTextureManager textureManager; - /// Terrain renderer - TerrainRenderer terrainRenderer; - - /// Overlay renderer - OverlayRenderer overlayRenderer; - - /// Particle manager - CParticleManager particleManager; - - /// Particle renderer - ParticleRenderer particleRenderer; - - /// Material manager - CMaterialManager materialManager; - /// Time manager CTimeManager timeManager; - /// Shadow map - ShadowMap shadow; - /// Postprocessing effect manager CPostprocManager postprocManager; + CSceneRenderer sceneRenderer; + CDebugRenderer debugRenderer; CFontManager fontManager; - SilhouetteRenderer silhouetteRenderer; - - /// Various model renderers - struct Models - { - // NOTE: The current renderer design (with ModelRenderer, ModelVertexRenderer, - // RenderModifier, etc) is mostly a relic of an older design that implemented - // the different materials and rendering modes through extensive subclassing - // and hooking objects together in various combinations. - // The new design uses the CShaderManager API to abstract away the details - // of rendering, and uses a data-driven approach to materials, so there are - // now a small number of generic subclasses instead of many specialised subclasses, - // but most of the old infrastructure hasn't been refactored out yet and leads to - // some unwanted complexity. - - // Submitted models are split on two axes: - // - Normal vs Transp[arent] - alpha-blended models are stored in a separate - // list so we can draw them above/below the alpha-blended water plane correctly - // - Skinned vs Unskinned - with hardware lighting we don't need to - // duplicate mesh data per model instance (except for skinned models), - // so non-skinned models get different ModelVertexRenderers - - ModelRendererPtr NormalSkinned; - ModelRendererPtr NormalUnskinned; // == NormalSkinned if unskinned shader instancing not supported - ModelRendererPtr TranspSkinned; - ModelRendererPtr TranspUnskinned; // == TranspSkinned if unskinned shader instancing not supported - - ModelVertexRendererPtr VertexRendererShader; - ModelVertexRendererPtr VertexInstancingShader; - ModelVertexRendererPtr VertexGPUSkinningShader; - - LitRenderModifierPtr ModShader; - } Model; - - CShaderDefines globalContext; - - CRendererInternals() : - IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats), textureManager(g_VFS, false, false) - { - } - - /** - * Renders all non-alpha-blended models with the given context. - */ - void CallModelRenderers(const CShaderDefines& context, int cullGroup, int flags) - { - CShaderDefines contextSkinned = context; - if (g_RenderingOptions.GetGPUSkinning()) - { - contextSkinned.Add(str_USE_INSTANCING, str_1); - contextSkinned.Add(str_USE_GPU_SKINNING, str_1); - } - Model.NormalSkinned->Render(Model.ModShader, contextSkinned, cullGroup, flags); - - if (Model.NormalUnskinned != Model.NormalSkinned) - { - CShaderDefines contextUnskinned = context; - contextUnskinned.Add(str_USE_INSTANCING, str_1); - Model.NormalUnskinned->Render(Model.ModShader, contextUnskinned, cullGroup, flags); - } - } - - /** - * Renders all alpha-blended models with the given context. - */ - void CallTranspModelRenderers(const CShaderDefines& context, int cullGroup, int flags) + Internals() : + IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats), + deviceCommandContext(g_VideoMode.GetBackendDevice()->CreateCommandContext()), + textureManager(g_VFS, false, g_VideoMode.GetBackendDevice()) { - CShaderDefines contextSkinned = context; - if (g_RenderingOptions.GetGPUSkinning()) - { - contextSkinned.Add(str_USE_INSTANCING, str_1); - contextSkinned.Add(str_USE_GPU_SKINNING, str_1); - } - Model.TranspSkinned->Render(Model.ModShader, contextSkinned, cullGroup, flags); - - if (Model.TranspUnskinned != Model.TranspSkinned) - { - CShaderDefines contextUnskinned = context; - contextUnskinned.Add(str_USE_INSTANCING, str_1); - Model.TranspUnskinned->Render(Model.ModShader, contextUnskinned, cullGroup, flags); - } } }; -/////////////////////////////////////////////////////////////////////////////////// -// CRenderer constructor CRenderer::CRenderer() { - m = new CRendererInternals; - m_WaterManager = &m->waterManager; - m_SkyManager = &m->skyManager; + TIMER(L"InitRenderer"); + + m = std::make_unique(); g_ProfileViewer.AddRootTable(&m->profileTable); m_Width = 0; m_Height = 0; - 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; - m_SkipSubmit = false; - - CStr skystring = "0 0 0"; - CColor skycolor; - CFG_GET_VAL("skycolor", skystring); - if (skycolor.ParseString(skystring, 255.f)) - SetClearColor(skycolor.AsSColor4ub()); - m_LightEnv = nullptr; + m_Stats.Reset(); - m_CurrentScene = nullptr; + // Create terrain related stuff. + new CTerrainTextureManager; - m_hCompositeAlphaMap = 0; + Open(g_xres, g_yres); - m_Stats.Reset(); + // Setup lighting environment. Since the Renderer accesses the + // lighting environment through a pointer, this has to be done before + // the first Frame. + GetSceneRenderer().SetLightEnv(&g_LightEnv); - RegisterFileReloadFunc(ReloadChangedFileCB, this); + // I haven't seen the camera affecting GUI rendering and such, but the + // viewport has to be updated according to the video mode + SViewPort vp; + vp.m_X = 0; + vp.m_Y = 0; + vp.m_Width = g_xres; + vp.m_Height = g_yres; + SetViewport(vp); + ModelDefActivateFastImpl(); + ColorActivateFastImpl(); + ModelRenderer::Init(); } -/////////////////////////////////////////////////////////////////////////////////// -// CRenderer destructor CRenderer::~CRenderer() { - UnregisterFileReloadFunc(ReloadChangedFileCB, this); + delete &g_TexMan; - // we no longer UnloadAlphaMaps / UnloadWaterTextures here - + // We no longer UnloadWaterTextures here - // that is the responsibility of the module that asked for // them to be loaded (i.e. CGameView). - delete m; -} - - -/////////////////////////////////////////////////////////////////////////////////// -// EnumCaps: build card cap bits -void CRenderer::EnumCaps() -{ - // assume support for nothing - m_Caps.m_ARBProgram = false; - m_Caps.m_ARBProgramShadow = false; - m_Caps.m_VertexShader = false; - m_Caps.m_FragmentShader = false; - m_Caps.m_Shadows = false; - m_Caps.m_PrettyWater = false; - - // now start querying extensions - if (0 == ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", NULL)) - { - m_Caps.m_ARBProgram = true; - if (ogl_HaveExtension("GL_ARB_fragment_program_shadow")) - m_Caps.m_ARBProgramShadow = true; - } - - if (0 == ogl_HaveExtensions(0, "GL_ARB_shader_objects", "GL_ARB_shading_language_100", NULL)) - { - if (ogl_HaveExtension("GL_ARB_vertex_shader")) - m_Caps.m_VertexShader = true; - if (ogl_HaveExtension("GL_ARB_fragment_shader")) - m_Caps.m_FragmentShader = true; - } - -#if CONFIG2_GLES - m_Caps.m_Shadows = true; -#else - if (0 == ogl_HaveExtensions(0, "GL_ARB_shadow", "GL_ARB_depth_texture", "GL_EXT_framebuffer_object", NULL)) - { - if (ogl_max_tex_units >= 4) - m_Caps.m_Shadows = true; - } -#endif - -#if CONFIG2_GLES - m_Caps.m_PrettyWater = true; -#else - if (0 == ogl_HaveExtensions(0, "GL_ARB_vertex_shader", "GL_ARB_fragment_shader", "GL_EXT_framebuffer_object", NULL)) - m_Caps.m_PrettyWater = true; -#endif -} - -void CRenderer::RecomputeSystemShaderDefines() -{ - CShaderDefines defines; - - if (m_Caps.m_ARBProgram) - defines.Add(str_SYS_HAS_ARB, str_1); - - if (m_Caps.m_VertexShader && m_Caps.m_FragmentShader) - defines.Add(str_SYS_HAS_GLSL, str_1); - - if (g_RenderingOptions.GetPreferGLSL()) - defines.Add(str_SYS_PREFER_GLSL, str_1); - - m_SystemShaderDefines = defines; + m.reset(); } void CRenderer::ReloadShaders() { ENSURE(m->IsOpen); - m->globalContext = m_SystemShaderDefines; - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - { - m->globalContext.Add(str_USE_SHADOW, str_1); - if (m_Caps.m_ARBProgramShadow && g_RenderingOptions.GetARBProgramShadow()) - m->globalContext.Add(str_USE_FP_SHADOW, str_1); - if (g_RenderingOptions.GetShadowPCF()) - m->globalContext.Add(str_USE_SHADOW_PCF, str_1); - const int cascadeCount = m->shadow.GetCascadeCount(); - ENSURE(1 <= cascadeCount && cascadeCount <= 4); - const CStrIntern cascadeCountStr[5] = {str_0, str_1, str_2, str_3, str_4}; - m->globalContext.Add(str_SHADOWS_CASCADE_COUNT, cascadeCountStr[cascadeCount]); -#if !CONFIG2_GLES - m->globalContext.Add(str_USE_SHADOW_SAMPLER, str_1); -#endif - } - - if (g_RenderingOptions.GetPreferGLSL() && g_RenderingOptions.GetFog()) - m->globalContext.Add(str_USE_FOG, str_1); - - m->Model.ModShader = LitRenderModifierPtr(new ShaderRenderModifier()); - - ENSURE(g_RenderingOptions.GetRenderPath() != RenderPath::FIXED); - m->Model.VertexRendererShader = ModelVertexRendererPtr(new ShaderModelVertexRenderer()); - m->Model.VertexInstancingShader = ModelVertexRendererPtr(new InstancingModelRenderer(false, g_RenderingOptions.GetPreferGLSL())); - - if (g_RenderingOptions.GetGPUSkinning()) // TODO: should check caps and GLSL etc too - { - m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new InstancingModelRenderer(true, g_RenderingOptions.GetPreferGLSL())); - m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); - m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); - } - else - { - m->Model.VertexGPUSkinningShader.reset(); - m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); - m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); - } - - m->Model.NormalUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); - m->Model.TranspUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); - + m->sceneRenderer.ReloadShaders(); m->ShadersDirty = false; } @@ -554,66 +337,31 @@ { m->IsOpen = true; - // Must query card capabilities before creating renderers that depend - // on card capabilities. - EnumCaps(); - // Dimensions m_Width = width; m_Height = height; - // set packing parameters - glPixelStorei(GL_PACK_ALIGNMENT,1); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - - // setup default state - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - glEnable(GL_CULL_FACE); - - GLint bits; - glGetIntegerv(GL_DEPTH_BITS,&bits); - LOGMESSAGE("CRenderer::Open: depth bits %d",bits); - glGetIntegerv(GL_STENCIL_BITS,&bits); - LOGMESSAGE("CRenderer::Open: stencil bits %d",bits); - glGetIntegerv(GL_ALPHA_BITS,&bits); - LOGMESSAGE("CRenderer::Open: alpha bits %d",bits); - // Validate the currently selected render path SetRenderPath(g_RenderingOptions.GetRenderPath()); - RecomputeSystemShaderDefines(); - - // Let component renderers perform one-time initialization after graphics capabilities and - // the shader path have been determined. - m->overlayRenderer.Initialize(); - - if (g_RenderingOptions.GetPostProc()) + if (m->postprocManager.IsEnabled()) m->postprocManager.Initialize(); + m->sceneRenderer.Initialize(); + return true; } -// resize renderer view void CRenderer::Resize(int width, int height) { - // need to recreate the shadow map object to resize the shadow texture - m->shadow.RecreateTexture(); - m_Width = width; m_Height = height; m->postprocManager.Resize(); - m_WaterManager->Resize(); + m->sceneRenderer.Resize(width, height); } -////////////////////////////////////////////////////////////////////////////////////////// -// SetRenderPath: Select the preferred render path. -// This may only be called before Open(), because the layout of vertex arrays and other -// data may depend on the chosen render path. void CRenderer::SetRenderPath(RenderPath rp) { if (!m->IsOpen) @@ -623,9 +371,12 @@ } // Renderer has been opened, so validate the selected renderpath + const bool hasShadersSupport = + g_VideoMode.GetBackendDevice()->GetCapabilities().ARBShaders || + g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB; if (rp == RenderPath::DEFAULT) { - if (m_Caps.m_ARBProgram || (m_Caps.m_VertexShader && m_Caps.m_FragmentShader && g_RenderingOptions.GetPreferGLSL())) + if (hasShadersSupport) rp = RenderPath::SHADER; else rp = RenderPath::FIXED; @@ -633,7 +384,7 @@ if (rp == RenderPath::SHADER) { - if (!(m_Caps.m_ARBProgram || (m_Caps.m_VertexShader && m_Caps.m_FragmentShader && g_RenderingOptions.GetPreferGLSL()))) + if (!hasShadersSupport) { LOGWARNING("Falling back to fixed function\n"); rp = RenderPath::FIXED; @@ -644,868 +395,329 @@ g_RenderingOptions.m_RenderPath = rp; MakeShadersDirty(); - RecomputeSystemShaderDefines(); - - // We might need to regenerate some render data after changing path - if (g_Game) - g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_COLOR); } -////////////////////////////////////////////////////////////////////////////////////////// -// BeginFrame: signal frame start -void CRenderer::BeginFrame() -{ - PROFILE("begin frame"); - - // zero out all the per-frame stats - m_Stats.Reset(); - - // choose model renderers for this frame - - if (m->ShadersDirty) - ReloadShaders(); - - m->Model.ModShader->SetShadowMap(&m->shadow); - m->Model.ModShader->SetLightEnv(m_LightEnv); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void CRenderer::SetSimulation(CSimulation2* simulation) -{ - // set current simulation context for terrain renderer - m->terrainRenderer.SetSimulation(simulation); -} - -// SetClearColor: set color used to clear screen in BeginFrame() -void CRenderer::SetClearColor(SColor4ub color) +bool CRenderer::ShouldRender() const { - m_ClearColor[0] = float(color.R) / 255.0f; - m_ClearColor[1] = float(color.G) / 255.0f; - m_ClearColor[2] = float(color.B) / 255.0f; - m_ClearColor[3] = float(color.A) / 255.0f; + return !g_app_minimized && (g_app_has_focus || !g_VideoMode.IsInFullscreen()); } -void CRenderer::RenderShadowMap(const CShaderDefines& context) +void CRenderer::RenderFrame(const bool needsPresent) { - PROFILE3_GPU("shadow map"); - - CShaderDefines contextCast = context; - contextCast.Add(str_MODE_SHADOWCAST, str_1); - - m->shadow.BeginRender(); + // Do not render if not focused while in fullscreen or minimised, + // as that triggers a difficult-to-reproduce crash on some graphic cards. + if (!ShouldRender()) + return; - const int cascadeCount = m->shadow.GetCascadeCount(); - ENSURE(0 <= cascadeCount && cascadeCount <= 4); - for (int cascade = 0; cascade < cascadeCount; ++cascade) + if (m_ShouldPreloadResourcesBeforeNextFrame) { - m->shadow.PrepareCamera(cascade); - - const int cullGroup = CULL_SHADOWS_CASCADE_0 + cascade; - { - PROFILE("render patches"); - glCullFace(GL_FRONT); - glEnable(GL_CULL_FACE); - m->terrainRenderer.RenderPatches(cullGroup); - glCullFace(GL_BACK); - } - - { - PROFILE("render models"); - m->CallModelRenderers(contextCast, cullGroup, MODELFLAG_CASTSHADOWS); - } - - { - PROFILE("render transparent models"); - // disable face-culling for two-sided models - glDisable(GL_CULL_FACE); - m->CallTranspModelRenderers(contextCast, cullGroup, MODELFLAG_CASTSHADOWS); - glEnable(GL_CULL_FACE); - } + m_ShouldPreloadResourcesBeforeNextFrame = false; + // We don't need to render logger for the preload. + RenderFrameImpl(true, false); } - m->shadow.EndRender(); - - SetViewport(m_ViewCamera.GetViewPort()); -} - -void CRenderer::RenderPatches(const CShaderDefines& context, int cullGroup) -{ - PROFILE3_GPU("patches"); - -#if CONFIG2_GLES -#warning TODO: implement wireface/edged rendering mode GLES -#else - // switch on wireframe if we need it - if (m_TerrainRenderMode == WIREFRAME) + if (m_ScreenShotType == ScreenShotType::BIG) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + RenderBigScreenShot(needsPresent); } -#endif - - // render all the patches, including blend pass - ENSURE(g_RenderingOptions.GetRenderPath() != RenderPath::FIXED); - m->terrainRenderer.RenderTerrainShader(context, cullGroup, (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) ? &m->shadow : 0); - -#if !CONFIG2_GLES - if (m_TerrainRenderMode == WIREFRAME) + else if (m_ScreenShotType == ScreenShotType::DEFAULT) { - // switch wireframe off again - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + RenderScreenShot(needsPresent); } - else if (m_TerrainRenderMode == EDGED_FACES) + else { - // edged faces: need to make a second pass over the data: - // first switch on wireframe - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - // setup some renderstate .. - pglActiveTextureARB(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); - glLineWidth(2.0f); - - // render tiles edges - m->terrainRenderer.RenderPatches(cullGroup, CColor(0.5f, 0.5f, 1.0f, 1.0f)); + RenderFrameImpl(true, true); - glLineWidth(4.0f); - - // render outline of each patch - m->terrainRenderer.RenderOutlines(cullGroup); - - // .. and restore the renderstates - glLineWidth(1.0f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + m->deviceCommandContext->Flush(); + if (needsPresent) + g_VideoMode.GetBackendDevice()->Present(); } -#endif } -void CRenderer::RenderModels(const CShaderDefines& context, int cullGroup) +void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger) { - PROFILE3_GPU("models"); + PROFILE3("render"); - int flags = 0; + g_Profiler2.RecordGPUFrameStart(); -#if !CONFIG2_GLES - if (m_ModelRenderMode == WIREFRAME) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } -#endif + g_TexMan.UploadResourcesIfNeeded(m->deviceCommandContext.get()); - m->CallModelRenderers(context, cullGroup, flags); + m->textureManager.MakeUploadProgress(m->deviceCommandContext.get()); -#if !CONFIG2_GLES - if (m_ModelRenderMode == WIREFRAME) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else if (m_ModelRenderMode == EDGED_FACES) - { - CShaderDefines contextWireframe = context; - contextWireframe.Add(str_MODE_WIREFRAME, str_1); + // prepare before starting the renderer frame + if (g_Game && g_Game->IsGameStarted()) + g_Game->GetView()->BeginFrame(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDisable(GL_TEXTURE_2D); - - m->CallModelRenderers(contextWireframe, cullGroup, flags); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -#endif -} - -void CRenderer::RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling) -{ - PROFILE3_GPU("transparent models"); + if (g_Game) + m->sceneRenderer.SetSimulation(g_Game->GetSimulation2()); - int flags = 0; + // start new frame + BeginFrame(); -#if !CONFIG2_GLES - // switch on wireframe if we need it - if (m_ModelRenderMode == WIREFRAME) + if (g_Game && g_Game->IsGameStarted()) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + g_Game->GetView()->Render(); } -#endif - // disable face culling for two-sided models in sub-renders - if (disableFaceCulling) - glDisable(GL_CULL_FACE); + m->deviceCommandContext->SetFramebuffer( + m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); - CShaderDefines contextOpaque = context; - contextOpaque.Add(str_ALPHABLEND_PASS_OPAQUE, str_1); - - CShaderDefines contextBlend = context; - contextBlend.Add(str_ALPHABLEND_PASS_BLEND, str_1); - - if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_OPAQUE) - m->CallTranspModelRenderers(contextOpaque, cullGroup, flags); - - if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_BLEND) - m->CallTranspModelRenderers(contextBlend, cullGroup, flags); - - if (disableFaceCulling) - glEnable(GL_CULL_FACE); - -#if !CONFIG2_GLES - if (m_ModelRenderMode == WIREFRAME) - { - // switch wireframe off again - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else if (m_ModelRenderMode == EDGED_FACES) + // If we're in Atlas game view, render special tools + if (g_AtlasGameLoop && g_AtlasGameLoop->view) { - CShaderDefines contextWireframe = contextOpaque; - contextWireframe.Add(str_MODE_WIREFRAME, str_1); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDisable(GL_TEXTURE_2D); - - m->CallTranspModelRenderers(contextWireframe, cullGroup, flags); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + g_AtlasGameLoop->view->DrawCinemaPathTool(); } -#endif -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space) -// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html -// - worldPlane is a clip plane in world space (worldPlane.Dot(v) >= 0 for any vector v passing the clipping test) -void CRenderer::SetObliqueFrustumClipping(CCamera& camera, const CVector4D& worldPlane) const -{ - // First, we'll convert the given clip plane to camera space, then we'll - // Get the view matrix and normal matrix (top 3x3 part of view matrix) - CMatrix3D normalMatrix = camera.GetOrientation().GetTranspose(); - CVector4D camPlane = normalMatrix.Transform(worldPlane); - - CMatrix3D matrix = camera.GetProjection(); - // Calculate the clip-space corner point opposite the clipping plane - // as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and - // transform it into camera space by multiplying it - // by the inverse of the projection matrix - - CVector4D q; - q.X = (sgn(camPlane.X) - matrix[8]/matrix[11]) / matrix[0]; - q.Y = (sgn(camPlane.Y) - matrix[9]/matrix[11]) / matrix[5]; - q.Z = 1.0f/matrix[11]; - q.W = (1.0f - matrix[10]/matrix[11]) / matrix[14]; - - // Calculate the scaled plane vector - CVector4D c = camPlane * (2.0f * matrix[11] / camPlane.Dot(q)); - - // Replace the third row of the projection matrix - matrix[2] = c.X; - matrix[6] = c.Y; - matrix[10] = c.Z - matrix[11]; - matrix[14] = c.W; - - // Load it back into the camera - camera.SetProjection(matrix); -} - -void CRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const -{ - WaterManager& wm = m->waterManager; - - CMatrix3D projection; - if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) + if (g_Game && g_Game->IsGameStarted()) { - const float aspectRatio = 1.0f; - // Expand fov slightly since ripples can reflect parts of the scene that - // are slightly outside the normal camera view, and we want to avoid any - // noticeable edge-filtering artifacts - projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); + g_Game->GetView()->GetCinema()->Render(); } - else - projection = m_ViewCamera.GetProjection(); - camera = m_ViewCamera; + RenderFrame2D(renderGUI, renderLogger); - // Temporarily change the camera to one that is reflected. - // Also, for texturing purposes, make it render to a view port the size of the - // water texture, stretch the image according to our aspect ratio so it covers - // the whole screen despite being rendered into a square, and cover slightly more - // of the view so we can see wavy reflections of slightly off-screen objects. - camera.m_Orientation.Scale(1, -1, 1); - camera.m_Orientation.Translate(0, 2 * wm.m_WaterHeight, 0); - camera.UpdateFrustum(scissor); - // Clip slightly above the water to improve reflections of objects on the water - // when the reflections are distorted. - camera.ClipFrustum(CVector4D(0, 1, 0, -wm.m_WaterHeight + 2.0f)); + EndFrame(); - SViewPort vp; - vp.m_Height = wm.m_RefTextureSize; - vp.m_Width = wm.m_RefTextureSize; - vp.m_X = 0; - vp.m_Y = 0; - camera.SetViewPort(vp); - camera.SetProjection(projection); - CMatrix3D scaleMat; - scaleMat.SetScaling(m_Height / static_cast(std::max(1, m_Width)), 1.0f, 1.0f); - camera.SetProjection(scaleMat * camera.GetProjection()); + const Stats& stats = GetStats(); + PROFILE2_ATTR("draw calls: %zu", stats.m_DrawCalls); + PROFILE2_ATTR("terrain tris: %zu", stats.m_TerrainTris); + PROFILE2_ATTR("water tris: %zu", stats.m_WaterTris); + PROFILE2_ATTR("model tris: %zu", stats.m_ModelTris); + PROFILE2_ATTR("overlay tris: %zu", stats.m_OverlayTris); + PROFILE2_ATTR("blend splats: %zu", stats.m_BlendSplats); + PROFILE2_ATTR("particles: %zu", stats.m_Particles); - CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight + 0.5f); - SetObliqueFrustumClipping(camera, camPlane); + g_Profiler2.RecordGPUFrameEnd(); } -void CRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const +void CRenderer::RenderFrame2D(const bool renderGUI, const bool renderLogger) { - WaterManager& wm = m->waterManager; - - CMatrix3D projection; - if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) - { - const float aspectRatio = 1.0f; - // Expand fov slightly since ripples can reflect parts of the scene that - // are slightly outside the normal camera view, and we want to avoid any - // noticeable edge-filtering artifacts - projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); - } - else - projection = m_ViewCamera.GetProjection(); + CCanvas2D canvas(m->deviceCommandContext.get()); - camera = m_ViewCamera; + m->sceneRenderer.RenderTextOverlays(canvas); - // Temporarily change the camera to make it render to a view port the size of the - // water texture, stretch the image according to our aspect ratio so it covers - // the whole screen despite being rendered into a square, and cover slightly more - // of the view so we can see wavy refractions of slightly off-screen objects. - camera.UpdateFrustum(scissor); - camera.ClipFrustum(CVector4D(0, -1, 0, wm.m_WaterHeight + 0.5f)); // add some to avoid artifacts near steep shores. - - SViewPort vp; - vp.m_Height = wm.m_RefTextureSize; - vp.m_Width = wm.m_RefTextureSize; - vp.m_X = 0; - vp.m_Y = 0; - camera.SetViewPort(vp); - camera.SetProjection(projection); - CMatrix3D scaleMat; - scaleMat.SetScaling(m_Height / static_cast(std::max(1, m_Width)), 1.0f, 1.0f); - camera.SetProjection(scaleMat * camera.GetProjection()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RenderReflections: render the water reflections to the reflection texture -void CRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor) -{ - PROFILE3_GPU("water reflections"); - - WaterManager& wm = m->waterManager; - - // Remember old camera - CCamera normalCamera = m_ViewCamera; - - ComputeReflectionCamera(m_ViewCamera, scissor); - const CBoundingBoxAligned reflectionScissor = - m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); - - SetViewport(m_ViewCamera.GetViewPort()); - - // Save the model-view-projection matrix so the shaders can use it for projective texturing - wm.m_ReflectionMatrix = m_ViewCamera.GetViewProjection(); - - float vpHeight = wm.m_RefTextureSize; - float vpWidth = wm.m_RefTextureSize; - - SScreenRect screenScissor; - screenScissor.x1 = (GLint)floor((reflectionScissor[0].X*0.5f+0.5f)*vpWidth); - screenScissor.y1 = (GLint)floor((reflectionScissor[0].Y*0.5f+0.5f)*vpHeight); - screenScissor.x2 = (GLint)ceil((reflectionScissor[1].X*0.5f+0.5f)*vpWidth); - screenScissor.y2 = (GLint)ceil((reflectionScissor[1].Y*0.5f+0.5f)*vpHeight); - - glEnable(GL_SCISSOR_TEST); - glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1); - - // try binding the framebuffer - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_ReflectionFbo); - - glClearColor(0.5f, 0.5f, 1.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glFrontFace(GL_CW); - - if (!g_RenderingOptions.GetWaterReflection()) - { - m->skyManager.RenderSky(); - ogl_WarnIfError(); - } - else + if (renderGUI) { - // Render terrain and models - RenderPatches(context, CULL_REFLECTIONS); - ogl_WarnIfError(); - RenderModels(context, CULL_REFLECTIONS); - ogl_WarnIfError(); - RenderTransparentModels(context, CULL_REFLECTIONS, TRANSPARENT, true); - ogl_WarnIfError(); + GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render GUI"); + // All GUI elements are drawn in Z order to render semi-transparent + // objects correctly. + g_GUI->Draw(canvas); } - glFrontFace(GL_CCW); - // Particles are always oriented to face the camera in the vertex shader, - // so they don't need the inverted glFrontFace - if (g_RenderingOptions.GetParticles()) + // If we're in Atlas game view, render special overlays (e.g. editor bandbox). + if (g_AtlasGameLoop && g_AtlasGameLoop->view) { - RenderParticles(CULL_REFLECTIONS); - ogl_WarnIfError(); + g_AtlasGameLoop->view->DrawOverlays(canvas); } - glDisable(GL_SCISSOR_TEST); - - // Reset old camera - m_ViewCamera = normalCamera; - SetViewport(m_ViewCamera.GetViewPort()); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RenderRefractions: render the water refractions to the refraction texture -void CRenderer::RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned &scissor) -{ - PROFILE3_GPU("water refractions"); - - WaterManager& wm = m->waterManager; - - // Remember old camera - CCamera normalCamera = m_ViewCamera; - - ComputeRefractionCamera(m_ViewCamera, scissor); - const CBoundingBoxAligned refractionScissor = - m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); - - CVector4D camPlane(0, -1, 0, wm.m_WaterHeight + 2.0f); - SetObliqueFrustumClipping(m_ViewCamera, camPlane); - - SetViewport(m_ViewCamera.GetViewPort()); - - // Save the model-view-projection matrix so the shaders can use it for projective texturing - wm.m_RefractionMatrix = m_ViewCamera.GetViewProjection(); - wm.m_RefractionProjInvMatrix = m_ViewCamera.GetProjection().GetInverse(); - wm.m_RefractionViewInvMatrix = m_ViewCamera.GetOrientation(); - - float vpHeight = wm.m_RefTextureSize; - float vpWidth = wm.m_RefTextureSize; - - SScreenRect screenScissor; - screenScissor.x1 = (GLint)floor((refractionScissor[0].X*0.5f+0.5f)*vpWidth); - screenScissor.y1 = (GLint)floor((refractionScissor[0].Y*0.5f+0.5f)*vpHeight); - screenScissor.x2 = (GLint)ceil((refractionScissor[1].X*0.5f+0.5f)*vpWidth); - screenScissor.y2 = (GLint)ceil((refractionScissor[1].Y*0.5f+0.5f)*vpHeight); - - glEnable(GL_SCISSOR_TEST); - glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1); - - // try binding the framebuffer - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_RefractionFbo); - - glClearColor(1.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Render terrain and models - RenderPatches(context, CULL_REFRACTIONS); - ogl_WarnIfError(); - RenderModels(context, CULL_REFRACTIONS); - ogl_WarnIfError(); - RenderTransparentModels(context, CULL_REFRACTIONS, TRANSPARENT_OPAQUE, false); - ogl_WarnIfError(); - - glDisable(GL_SCISSOR_TEST); - - // Reset old camera - m_ViewCamera = normalCamera; - SetViewport(m_ViewCamera.GetViewPort()); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -} - -void CRenderer::RenderSilhouettes(const CShaderDefines& context) -{ - PROFILE3_GPU("silhouettes"); - - CShaderDefines contextOccluder = context; - contextOccluder.Add(str_MODE_SILHOUETTEOCCLUDER, str_1); - - CShaderDefines contextDisplay = context; - contextDisplay.Add(str_MODE_SILHOUETTEDISPLAY, str_1); - - // Render silhouettes of units hidden behind terrain or occluders. - // To avoid breaking the standard rendering of alpha-blended objects, this - // has to be done in a separate pass. - // First we render all occluders into depth, then render all units with - // inverted depth test so any behind an occluder will get drawn in a constant - // color. - - float silhouetteAlpha = 0.75f; - - // Silhouette blending requires an almost-universally-supported extension; - // fall back to non-blended if unavailable - if (!ogl_HaveExtension("GL_EXT_blend_color")) - silhouetteAlpha = 1.f; - - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - glColorMask(0, 0, 0, 0); - - // Render occluders: - { - PROFILE("render patches"); - - // To prevent units displaying silhouettes when parts of their model - // protrude into the ground, only occlude with the back faces of the - // terrain (so silhouettes will still display when behind hills) - glCullFace(GL_FRONT); - m->terrainRenderer.RenderPatches(CULL_SILHOUETTE_OCCLUDER); - glCullFace(GL_BACK); + GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render console"); + g_Console->Render(canvas); } + if (renderLogger) { - PROFILE("render model occluders"); - m->CallModelRenderers(contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); + GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render logger"); + g_Logger->Render(canvas); } { - PROFILE("render transparent occluders"); - m->CallTranspModelRenderers(contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); - } - - glDepthFunc(GL_GEQUAL); - glColorMask(1, 1, 1, 1); - - // Render more efficiently if alpha == 1 - if (silhouetteAlpha == 1.f) - { - // Ideally we'd render objects back-to-front so nearer silhouettes would - // appear on top, but sorting has non-zero cost. So we'll keep the depth - // write enabled, to do the opposite - far objects will consistently appear - // on top. - glDepthMask(0); + GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render profiler"); + // Profile information + g_ProfileViewer.RenderProfile(canvas); } - else - { - // Since we can't sort, we'll use the stencil buffer to ensure we only draw - // a pixel once (using the color of whatever model happens to be drawn first). - glEnable(GL_BLEND); - glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); - pglBlendColorEXT(0, 0, 0, silhouetteAlpha); +} - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_NOTEQUAL, 1, (GLuint)-1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } +void CRenderer::RenderScreenShot(const bool needsPresent) +{ + m_ScreenShotType = ScreenShotType::NONE; - { - PROFILE("render model casters"); - m->CallModelRenderers(contextDisplay, CULL_SILHOUETTE_CASTER, 0); - } + // get next available numbered filename + // note: %04d -> always 4 digits, so sorting by filename works correctly. + const VfsPath filenameFormat(L"screenshots/screenshot%04d.png"); + VfsPath filename; + vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename); - { - PROFILE("render transparent casters"); - m->CallTranspModelRenderers(contextDisplay, CULL_SILHOUETTE_CASTER, 0); - } + const size_t width = static_cast(g_xres), height = static_cast(g_yres); + const size_t bpp = 24; - // Restore state - glDepthFunc(GL_LEQUAL); - if (silhouetteAlpha == 1.f) - { - glDepthMask(1); - } - else - { - glDisable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - pglBlendColorEXT(0, 0, 0, 0); - glDisable(GL_STENCIL_TEST); - } -} + // Hide log messages and re-render + RenderFrameImpl(true, false); -void CRenderer::RenderParticles(int cullGroup) -{ - PROFILE3_GPU("particles"); + const size_t img_size = width * height * bpp / 8; + const size_t hdr_size = tex_hdr_size(filename); + std::shared_ptr buf; + AllocateAligned(buf, hdr_size + img_size, maxSectorSize); + void* img = buf.get() + hdr_size; + Tex t; + if (t.wrap(width, height, bpp, TEX_BOTTOM_UP, buf, hdr_size) < 0) + return; - m->particleRenderer.RenderParticles(cullGroup); + m->deviceCommandContext->ReadbackFramebufferSync(0, 0, width, height, img); + m->deviceCommandContext->Flush(); + if (needsPresent) + g_VideoMode.GetBackendDevice()->Present(); -#if !CONFIG2_GLES - if (m_ModelRenderMode == EDGED_FACES) + if (tex_write(&t, filename) == INFO::OK) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + OsPath realPath; + g_VFS->GetRealPath(filename, realPath); - m->particleRenderer.RenderParticles(true); - m->particleRenderer.RenderBounds(cullGroup); + LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + debug_printf( + CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(), + realPath.string8().c_str()); } -#endif + else + LOGERROR("Error writing screenshot to '%s'", filename.string8()); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RenderSubmissions: force rendering of any batched objects -void CRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor) +void CRenderer::RenderBigScreenShot(const bool needsPresent) { - PROFILE3("render submissions"); - - GetScene().GetLOSTexture().InterpolateLOS(); - - GetScene().GetMiniMapTexture().Render(); - - CShaderDefines context = m->globalContext; + m_ScreenShotType = ScreenShotType::NONE; - int cullGroup = CULL_DEFAULT; + // If the game hasn't started yet then use WriteScreenshot to generate the image. + if (!g_Game) + return RenderScreenShot(needsPresent); - ogl_WarnIfError(); - - // Set the camera - SetViewport(m_ViewCamera.GetViewPort()); - - // Prepare model renderers + int tiles = 4, tileWidth = 256, tileHeight = 256; + CFG_GET_VAL("screenshot.tiles", tiles); + CFG_GET_VAL("screenshot.tilewidth", tileWidth); + CFG_GET_VAL("screenshot.tileheight", tileHeight); + if (tiles <= 0 || tileWidth <= 0 || tileHeight <= 0 || tileWidth * tiles % 4 != 0 || tileHeight * tiles % 4 != 0) { - PROFILE3("prepare models"); - m->Model.NormalSkinned->PrepareModels(); - m->Model.TranspSkinned->PrepareModels(); - if (m->Model.NormalUnskinned != m->Model.NormalSkinned) - m->Model.NormalUnskinned->PrepareModels(); - if (m->Model.TranspUnskinned != m->Model.TranspSkinned) - m->Model.TranspUnskinned->PrepareModels(); + LOGWARNING("Invalid big screenshot size: tiles=%d tileWidth=%d tileHeight=%d", tiles, tileWidth, tileHeight); + return; } - m->terrainRenderer.PrepareForRendering(); - - m->overlayRenderer.PrepareForRendering(); - - m->particleRenderer.PrepareForRendering(context); - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) + // get next available numbered filename + // note: %04d -> always 4 digits, so sorting by filename works correctly. + const VfsPath filenameFormat(L"screenshots/screenshot%04d.bmp"); + VfsPath filename; + vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename); + + // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and + // hope the screen is actually large enough for that. + ENSURE(g_xres >= tileWidth && g_yres >= tileHeight); + + const int imageWidth = tileWidth * tiles, imageHeight = tileHeight * tiles; + const int bpp = 24; + + const size_t imageSize = imageWidth * imageHeight * bpp / 8; + const size_t tileSize = tileWidth * tileHeight * bpp / 8; + const size_t headerSize = tex_hdr_size(filename); + void* tileData = malloc(tileSize); + if (!tileData) { - RenderShadowMap(context); + WARN_IF_ERR(ERR::NO_MEM); + return; } + std::shared_ptr imageBuffer; + AllocateAligned(imageBuffer, headerSize + imageSize, maxSectorSize); - ogl_WarnIfError(); - - if (m_WaterManager->m_RenderWater) + Tex t; + void* img = imageBuffer.get() + headerSize; + if (t.wrap(imageWidth, imageHeight, bpp, TEX_BOTTOM_UP, imageBuffer, headerSize) < 0) { - if (waterScissor.GetVolume() > 0 && m_WaterManager->WillRenderFancyWater()) - { - PROFILE3_GPU("water scissor"); - RenderReflections(context, waterScissor); - - if (g_RenderingOptions.GetWaterRefraction()) - RenderRefractions(context, waterScissor); - } + free(tileData); + return; } - if (g_RenderingOptions.GetPostProc()) - { - // We have to update the post process manager with real near/far planes - // that we use for the scene rendering. - m->postprocManager.SetDepthBufferClipPlanes( - m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane() - ); - m->postprocManager.Initialize(); - m->postprocManager.CaptureRenderOutput(); - } + CCamera oldCamera = *g_Game->GetView()->GetCamera(); + // Resize various things so that the sizes and aspect ratios are correct { - PROFILE3_GPU("clear buffers"); - glClearColor(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + g_Renderer.Resize(tileWidth, tileHeight); + SViewPort vp = { 0, 0, tileWidth, tileHeight }; + g_Game->GetView()->SetViewport(vp); } - m->skyManager.RenderSky(); - - // render submitted patches and models - RenderPatches(context, cullGroup); - ogl_WarnIfError(); - - // render debug-related terrain overlays - ITerrainOverlay::RenderOverlaysBeforeWater(); - ogl_WarnIfError(); - - // render other debug-related overlays before water (so they can be seen when underwater) - m->overlayRenderer.RenderOverlaysBeforeWater(); - ogl_WarnIfError(); - - RenderModels(context, cullGroup); - ogl_WarnIfError(); - - // render water - if (m_WaterManager->m_RenderWater && g_Game && waterScissor.GetVolume() > 0) + // Render each tile + CMatrix3D projection; + projection.SetIdentity(); + const float aspectRatio = 1.0f * tileWidth / tileHeight; + for (int tileY = 0; tileY < tiles; ++tileY) { - if (m_WaterManager->WillRenderFancyWater()) + for (int tileX = 0; tileX < tiles; ++tileX) { - // Render transparent stuff, but only the solid parts that can occlude block water. - RenderTransparentModels(context, cullGroup, TRANSPARENT_OPAQUE, false); - ogl_WarnIfError(); - - m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow); - ogl_WarnIfError(); - - // Render transparent stuff again, but only the blended parts that overlap water. - RenderTransparentModels(context, cullGroup, TRANSPARENT_BLEND, false); - ogl_WarnIfError(); - } - else - { - m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow); - ogl_WarnIfError(); - - // Render transparent stuff, so it can overlap models/terrain. - RenderTransparentModels(context, cullGroup, TRANSPARENT, false); - ogl_WarnIfError(); - } - } - else - { - // render transparent stuff, so it can overlap models/terrain - RenderTransparentModels(context, cullGroup, TRANSPARENT, false); - ogl_WarnIfError(); - } + // Adjust the camera to render the appropriate region + if (oldCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) + { + projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tileX, tileY); + } + g_Game->GetView()->GetCamera()->SetProjection(projection); - // render debug-related terrain overlays - ITerrainOverlay::RenderOverlaysAfterWater(cullGroup); - ogl_WarnIfError(); + RenderFrameImpl(false, false); - // render some other overlays after water (so they can be displayed on top of water) - m->overlayRenderer.RenderOverlaysAfterWater(); - ogl_WarnIfError(); + m->deviceCommandContext->ReadbackFramebufferSync(0, 0, tileWidth, tileHeight, tileData); + m->deviceCommandContext->Flush(); + if (needsPresent) + g_VideoMode.GetBackendDevice()->Present(); - // particles are transparent so render after water - if (g_RenderingOptions.GetParticles()) - { - RenderParticles(cullGroup); - ogl_WarnIfError(); + // Copy the tile pixels into the main image + for (int y = 0; y < tileHeight; ++y) + { + void* dest = static_cast(img) + ((tileY * tileHeight + y) * imageWidth + (tileX * tileWidth)) * bpp / 8; + void* src = static_cast(tileData) + y * tileWidth * bpp / 8; + memcpy(dest, src, tileWidth * bpp / 8); + } + } } - if (g_RenderingOptions.GetPostProc()) + // Restore the viewport settings { - if (g_Renderer.GetPostprocManager().IsMultisampleEnabled()) - g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer(); - - m->postprocManager.ApplyPostproc(); - m->postprocManager.ReleaseRenderOutput(); + g_Renderer.Resize(g_xres, g_yres); + SViewPort vp = { 0, 0, g_xres, g_yres }; + g_Game->GetView()->SetViewport(vp); + g_Game->GetView()->GetCamera()->SetProjectionFromCamera(oldCamera); } - if (g_RenderingOptions.GetSilhouettes()) + if (tex_write(&t, filename) == INFO::OK) { - RenderSilhouettes(context); - } + OsPath realPath; + g_VFS->GetRealPath(filename, realPath); - // render debug lines - if (g_RenderingOptions.GetDisplayFrustum()) - DisplayFrustum(); + LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8()); - if (g_RenderingOptions.GetDisplayShadowsFrustum()) - { - m->shadow.RenderDebugBounds(); - m->shadow.RenderDebugTexture(); + debug_printf( + CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(), + realPath.string8().c_str()); } + else + LOGERROR("Error writing screenshot to '%s'", filename.string8()); - m->silhouetteRenderer.RenderDebugOverlays(m_ViewCamera); - - // render overlays that should appear on top of all other objects - m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera); - ogl_WarnIfError(); - -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// EndFrame: signal frame end -void CRenderer::EndFrame() -{ - PROFILE3("end frame"); - - // empty lists - m->terrainRenderer.EndFrame(); - m->overlayRenderer.EndFrame(); - m->particleRenderer.EndFrame(); - m->silhouetteRenderer.EndFrame(); - - // Finish model renderers - m->Model.NormalSkinned->EndFrame(); - m->Model.TranspSkinned->EndFrame(); - if (m->Model.NormalUnskinned != m->Model.NormalSkinned) - m->Model.NormalUnskinned->EndFrame(); - if (m->Model.TranspUnskinned != m->Model.TranspSkinned) - m->Model.TranspUnskinned->EndFrame(); - - ogl_tex_bind(0, 0); -} - -void CRenderer::OnSwapBuffers() -{ - bool checkGLErrorAfterSwap = false; - CFG_GET_VAL("gl.checkerrorafterswap", checkGLErrorAfterSwap); - if (!checkGLErrorAfterSwap) - return; - PROFILE3("error check"); - // We have to check GL errors after SwapBuffer to avoid possible - // synchronizations during rendering. - if (GLenum err = glGetError()) - ONCE(LOGERROR("GL error %s (0x%04x) occurred", ogl_GetErrorName(err), err)); + free(tileData); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// DisplayFrustum: debug displays -// - white: cull camera frustum -// - red: bounds of shadow casting objects -void CRenderer::DisplayFrustum() +void CRenderer::BeginFrame() { -#if CONFIG2_GLES -#warning TODO: implement CRenderer::DisplayFrustum for GLES -#else - glDepthMask(0); - glDisable(GL_CULL_FACE); - glDisable(GL_TEXTURE_2D); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 0.25f), 2); - glDisable(GL_BLEND); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 1.0f), 2); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glEnable(GL_CULL_FACE); - glDepthMask(1); -#endif - - ogl_WarnIfError(); -} + PROFILE("begin frame"); -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Text overlay rendering -void CRenderer::RenderTextOverlays() -{ - PROFILE3_GPU("text overlays"); + // Zero out all the per-frame stats. + m_Stats.Reset(); - if (m_DisplayTerrainPriorities) - m->terrainRenderer.RenderPriorities(CULL_DEFAULT); + if (m->ShadersDirty) + ReloadShaders(); - ogl_WarnIfError(); + m->sceneRenderer.BeginFrame(); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// SetSceneCamera: setup projection and transform of camera and adjust viewport to current view -// The camera always represents the actual camera used to render a scene, not any virtual camera -// used for shadow rendering or reflections. -void CRenderer::SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera) +void CRenderer::EndFrame() { - m_ViewCamera = viewCamera; - m_CullCamera = cullCamera; + PROFILE3("end frame"); - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - m->shadow.SetupFrame(m_CullCamera, m_LightEnv->GetSunDir()); + m->sceneRenderer.EndFrame(); } - void CRenderer::SetViewport(const SViewPort &vp) { m_Viewport = vp; - glViewport((GLint)vp.m_X,(GLint)vp.m_Y,(GLsizei)vp.m_Width,(GLsizei)vp.m_Height); + Renderer::Backend::IDeviceCommandContext::Rect viewportRect; + viewportRect.x = vp.m_X; + viewportRect.y = vp.m_Y; + viewportRect.width = vp.m_Width; + viewportRect.height = vp.m_Height; + m->deviceCommandContext->SetViewports(1, &viewportRect); } SViewPort CRenderer::GetViewport() @@ -1513,390 +725,10 @@ return m_Viewport; } -void CRenderer::Submit(CPatch* patch) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - { - m->shadow.AddShadowReceiverBound(patch->GetWorldBounds()); - m->silhouetteRenderer.AddOccluder(patch); - } - - if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) - { - const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; - m->shadow.AddShadowCasterBound(cascade, patch->GetWorldBounds()); - } - - m->terrainRenderer.Submit(m_CurrentCullGroup, patch); -} - -void CRenderer::Submit(SOverlayLine* overlay) -{ - // Overlays are only needed in the default cull group for now, - // so just ignore submissions to any other group - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlayTexturedLine* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlaySprite* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlayQuad* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlaySphere* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(CModelDecal* decal) -{ - // Decals can't cast shadows since they're flat on the terrain. - // They can receive shadows, but the terrain under them will have - // already been passed to AddShadowCasterBound, so don't bother - // doing it again here. - - m->terrainRenderer.Submit(m_CurrentCullGroup, decal); -} - -void CRenderer::Submit(CParticleEmitter* emitter) -{ - m->particleRenderer.Submit(m_CurrentCullGroup, emitter); -} - -void CRenderer::SubmitNonRecursive(CModel* model) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - { - m->shadow.AddShadowReceiverBound(model->GetWorldBounds()); - - if (model->GetFlags() & MODELFLAG_SILHOUETTE_OCCLUDER) - m->silhouetteRenderer.AddOccluder(model); - if (model->GetFlags() & MODELFLAG_SILHOUETTE_DISPLAY) - m->silhouetteRenderer.AddCaster(model); - } - - if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) - { - if (!(model->GetFlags() & MODELFLAG_CASTSHADOWS)) - return; - - const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; - m->shadow.AddShadowCasterBound(cascade, model->GetWorldBounds()); - } - - bool requiresSkinning = (model->GetModelDef()->GetNumBones() != 0); - - if (model->GetMaterial().UsesAlphaBlending()) - { - if (requiresSkinning) - m->Model.TranspSkinned->Submit(m_CurrentCullGroup, model); - else - m->Model.TranspUnskinned->Submit(m_CurrentCullGroup, model); - } - else - { - if (requiresSkinning) - m->Model.NormalSkinned->Submit(m_CurrentCullGroup, model); - else - m->Model.NormalUnskinned->Submit(m_CurrentCullGroup, model); - } -} - - -/////////////////////////////////////////////////////////// -// Render the given scene -void CRenderer::RenderScene(Scene& scene) -{ - m_CurrentScene = &scene; - - CFrustum frustum = m_CullCamera.GetFrustum(); - - m_CurrentCullGroup = CULL_DEFAULT; - - scene.EnumerateObjects(frustum, this); - - m->particleManager.RenderSubmit(*this, frustum); - - if (g_RenderingOptions.GetSilhouettes()) - { - m->silhouetteRenderer.ComputeSubmissions(m_ViewCamera); - - m_CurrentCullGroup = CULL_DEFAULT; - m->silhouetteRenderer.RenderSubmitOverlays(*this); - - m_CurrentCullGroup = CULL_SILHOUETTE_OCCLUDER; - m->silhouetteRenderer.RenderSubmitOccluders(*this); - - m_CurrentCullGroup = CULL_SILHOUETTE_CASTER; - m->silhouetteRenderer.RenderSubmitCasters(*this); - } - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - { - for (int cascade = 0; cascade <= m->shadow.GetCascadeCount(); ++cascade) - { - m_CurrentCullGroup = CULL_SHADOWS_CASCADE_0 + cascade; - const CFrustum shadowFrustum = m->shadow.GetShadowCasterCullFrustum(cascade); - scene.EnumerateObjects(shadowFrustum, this); - } - } - - CBoundingBoxAligned waterScissor; - if (m_WaterManager->m_RenderWater) - { - waterScissor = m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); - - if (waterScissor.GetVolume() > 0 && m_WaterManager->WillRenderFancyWater()) - { - if (g_RenderingOptions.GetWaterReflection()) - { - m_CurrentCullGroup = CULL_REFLECTIONS; - - CCamera reflectionCamera; - ComputeReflectionCamera(reflectionCamera, waterScissor); - - scene.EnumerateObjects(reflectionCamera.GetFrustum(), this); - } - - if (g_RenderingOptions.GetWaterRefraction()) - { - m_CurrentCullGroup = CULL_REFRACTIONS; - - CCamera refractionCamera; - ComputeRefractionCamera(refractionCamera, waterScissor); - - scene.EnumerateObjects(refractionCamera.GetFrustum(), this); - } - - // Render the waves to the Fancy effects texture - m_WaterManager->RenderWaves(frustum); - } - } - - m_CurrentCullGroup = -1; - - ogl_WarnIfError(); - - RenderSubmissions(waterScissor); - - m_CurrentScene = NULL; -} - -Scene& CRenderer::GetScene() -{ - ENSURE(m_CurrentScene); - return *m_CurrentScene; -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// BindTexture: bind a GL texture object to current active unit -void CRenderer::BindTexture(int unit, GLuint tex) -{ - pglActiveTextureARB(GL_TEXTURE0+unit); - - glBindTexture(GL_TEXTURE_2D, tex); -#if !CONFIG2_GLES - if (tex) { - glEnable(GL_TEXTURE_2D); - } else { - glDisable(GL_TEXTURE_2D); - } -#endif -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and -// calculate the coordinate of each alphamap within this packed texture -// NB: A variant of this function is duplicated in TerrainTextureEntry.cpp, for use with the Shader -// renderpath. This copy is kept to load the 'standard' maps for the fixed pipeline and should -// be removed if/when the fixed pipeline goes. -int CRenderer::LoadAlphaMaps() -{ - const wchar_t* const key = L"(alpha map composite)"; - Handle ht = ogl_tex_find(key); - // alpha map texture had already been created and is still in memory: - // reuse it, do not load again. - if(ht > 0) - { - m_hCompositeAlphaMap = ht; - return 0; - } - - // - // load all textures and store Handle in array - // - Handle textures[NumAlphaMaps] = {0}; - VfsPath path(L"art/textures/terrain/alphamaps/standard"); - const wchar_t* fnames[NumAlphaMaps] = { - L"blendcircle.png", - L"blendlshape.png", - L"blendedge.png", - L"blendedgecorner.png", - L"blendedgetwocorners.png", - L"blendfourcorners.png", - L"blendtwooppositecorners.png", - L"blendlshapecorner.png", - L"blendtwocorners.png", - L"blendcorner.png", - L"blendtwoedges.png", - L"blendthreecorners.png", - L"blendushape.png", - L"blendbad.png" - }; - size_t base = 0; // texture width/height (see below) - // for convenience, we require all alpha maps to be of the same BPP - // (avoids another ogl_tex_get_size call, and doesn't hurt) - size_t bpp = 0; - for(size_t i=0;i data; - AllocateAligned(data, total_w*total_h, maxSectorSize); - // for each tile on row - for (size_t i = 0; i < NumAlphaMaps; i++) - { - // get src of copy - u8* src = 0; - ignore_result(ogl_tex_get_data(textures[i], &src)); - - size_t srcstep = bpp/8; - - // get destination of copy - u8* dst = data.get() + (i*tile_w); - - // for each row of image - for (size_t j = 0; j < base; j++) - { - // duplicate first pixel - *dst++ = *src; - *dst++ = *src; - - // copy a row - for (size_t k = 0; k < base; k++) - { - *dst++ = *src; - src += srcstep; - } - - // duplicate last pixel - *dst++ = *(src-srcstep); - *dst++ = *(src-srcstep); - - // advance write pointer for next row - dst += total_w-tile_w; - } - - m_AlphaMapCoords[i].u0 = float(i*tile_w+2) / float(total_w); - m_AlphaMapCoords[i].u1 = float((i+1)*tile_w-2) / float(total_w); - m_AlphaMapCoords[i].v0 = 0.0f; - m_AlphaMapCoords[i].v1 = 1.0f; - } - - for (size_t i = 0; i < NumAlphaMaps; i++) - ignore_result(ogl_tex_free(textures[i])); - - // upload the composite texture - Tex t; - ignore_result(t.wrap(total_w, total_h, 8, TEX_GREY, data, 0)); - - /*VfsPath filename("blendtex.png"); - - DynArray da; - RETURN_STATUS_IF_ERR(tex_encode(&t, filename.Extension(), &da)); - - // write to disk - //Status ret = INFO::OK; - { - std::shared_ptr file = DummySharedPtr(da.base); - const ssize_t bytes_written = g_VFS->CreateFile(filename, file, da.pos); - if(bytes_written > 0) - ENSURE(bytes_written == (ssize_t)da.pos); - //else - // ret = (Status)bytes_written; - } - - ignore_result(da_free(&da));*/ - - m_hCompositeAlphaMap = ogl_tex_wrap(&t, g_VFS, key); - ignore_result(ogl_tex_set_filter(m_hCompositeAlphaMap, GL_LINEAR)); - ignore_result(ogl_tex_set_wrap (m_hCompositeAlphaMap, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE)); - int ret = ogl_tex_upload(m_hCompositeAlphaMap, GL_ALPHA, 0, 0); - - return ret; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UnloadAlphaMaps: frees the resources allocates by LoadAlphaMaps -void CRenderer::UnloadAlphaMaps() -{ - ogl_tex_free(m_hCompositeAlphaMap); - m_hCompositeAlphaMap = 0; -} - - - -Status CRenderer::ReloadChangedFileCB(void* param, const VfsPath& path) -{ - CRenderer* renderer = static_cast(param); - - // If an alpha map changed, and we already loaded them, then reload them - if (boost::algorithm::starts_with(path.string(), L"art/textures/terrain/alphamaps/")) - { - if (renderer->m_hCompositeAlphaMap) - { - renderer->UnloadAlphaMaps(); - renderer->LoadAlphaMaps(); - } - } - - return INFO::OK; -} - void CRenderer::MakeShadersDirty() { m->ShadersDirty = true; - m_WaterManager->m_NeedsReloading = true; + m->sceneRenderer.MakeShadersDirty(); } CTextureManager& CRenderer::GetTextureManager() @@ -1909,29 +741,19 @@ return m->shaderManager; } -CParticleManager& CRenderer::GetParticleManager() -{ - return m->particleManager; -} - -TerrainRenderer& CRenderer::GetTerrainRenderer() -{ - return m->terrainRenderer; -} - CTimeManager& CRenderer::GetTimeManager() { return m->timeManager; } -CMaterialManager& CRenderer::GetMaterialManager() +CPostprocManager& CRenderer::GetPostprocManager() { - return m->materialManager; + return m->postprocManager; } -CPostprocManager& CRenderer::GetPostprocManager() +CSceneRenderer& CRenderer::GetSceneRenderer() { - return m->postprocManager; + return m->sceneRenderer; } CDebugRenderer& CRenderer::GetDebugRenderer() @@ -1944,13 +766,17 @@ return m->fontManager; } -ShadowMap& CRenderer::GetShadowMap() +void CRenderer::PreloadResourcesBeforeNextFrame() +{ + m_ShouldPreloadResourcesBeforeNextFrame = true; +} + +void CRenderer::MakeScreenShotOnNextFrame(ScreenShotType screenShotType) { - return m->shadow; + m_ScreenShotType = screenShotType; } -void CRenderer::ResetState() +Renderer::Backend::IDeviceCommandContext* CRenderer::GetDeviceCommandContext() { - // Clear all emitters, that were created in previous games - GetParticleManager().ClearUnattachedEmitters(); + return m->deviceCommandContext.get(); } diff -Nru 0ad-0.0.25b/source/renderer/Renderer.h 0ad-0.0.26/source/renderer/Renderer.h --- 0ad-0.0.25b/source/renderer/Renderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/Renderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,78 +15,37 @@ * along with 0 A.D. If not, see . */ -/* - * higher level interface on top of OpenGL to render basic objects: - * terrain, models, sprites, particles etc. - */ - #ifndef INCLUDED_RENDERER #define INCLUDED_RENDERER #include "graphics/Camera.h" -#include "graphics/SColor.h" #include "graphics/ShaderDefines.h" #include "graphics/ShaderProgramPtr.h" -#include "lib/file/vfs/vfs_path.h" -#include "lib/res/handle.h" #include "ps/Singleton.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/RenderingOptions.h" #include "renderer/Scene.h" +#include + class CDebugRenderer; class CFontManager; -class CLightEnv; -class CMaterial; -class CMaterialManager; -class CModel; -class CParticleManager; -class CPatch; class CPostprocManager; +class CSceneRenderer; class CShaderManager; -class CSimulation2; class CTextureManager; class CTimeManager; -class RenderPathVertexShader; -class ShadowMap; -class SkyManager; -class TerrainRenderer; -class WaterManager; - -// rendering modes -enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES }; - -// transparency modes -enum ETransparentMode { TRANSPARENT, TRANSPARENT_OPAQUE, TRANSPARENT_BLEND }; -// access to sole renderer object #define g_Renderer CRenderer::GetSingleton() -/////////////////////////////////////////////////////////////////////////////////////////// -// CRenderer: base renderer class - primary interface to the rendering engine -struct CRendererInternals; - -class CRenderer : - public Singleton, - private SceneCollector +/** + * Higher level interface on top of the whole frame rendering. It does know + * what should be rendered and via which renderer but shouldn't know how to + * render a particular area, like UI or scene. + */ +class CRenderer : public Singleton { public: - // various enumerations and renderer related constants - enum { NumAlphaMaps=14 }; - - enum CullGroup - { - CULL_DEFAULT, - CULL_SHADOWS_CASCADE_0, - CULL_SHADOWS_CASCADE_1, - CULL_SHADOWS_CASCADE_2, - CULL_SHADOWS_CASCADE_3, - CULL_REFLECTIONS, - CULL_REFRACTIONS, - CULL_SILHOUETTE_OCCLUDER, - CULL_SILHOUETTE_CASTER, - CULL_MAX - }; - // stats class - per frame counts of number of draw calls, poly counts etc struct Stats { @@ -108,340 +67,115 @@ size_t m_Particles; }; - struct Caps + enum class ScreenShotType { - bool m_ARBProgram; - bool m_ARBProgramShadow; - bool m_VertexShader; - bool m_FragmentShader; - bool m_Shadows; - bool m_PrettyWater; + NONE, + DEFAULT, + BIG }; public: - // constructor, destructor CRenderer(); ~CRenderer(); // open up the renderer: performs any necessary initialisation - bool Open(int width,int height); + bool Open(int width, int height); // resize renderer view - void Resize(int width,int height); + void Resize(int width, int height); // return view width int GetWidth() const { return m_Width; } // return view height int GetHeight() const { return m_Height; } - // return view aspect ratio - float GetAspect() const { return float(m_Width)/float(m_Height); } + + void RenderFrame(bool needsPresent); // signal frame start void BeginFrame(); // signal frame end void EndFrame(); - /** - * Should be called after each SwapBuffers call. - */ - void OnSwapBuffers(); - - /** - * Set simulation context for rendering purposes. - * Must be called at least once when the game has started and before - * frames are rendered. - */ - void SetSimulation(CSimulation2* simulation); - - // set color used to clear screen in BeginFrame() - void SetClearColor(SColor4ub color); - // trigger a reload of shaders (when parameters they depend on have changed) void MakeShadersDirty(); - /** - * Set up the camera used for rendering the next scene; this includes - * setting OpenGL state like viewport, projection and modelview matrices. - * - * @param viewCamera this camera determines the eye position for rendering - * @param cullCamera this camera determines the frustum for culling in the renderer and - * for shadow calculations - */ - void SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera); - // set the viewport void SetViewport(const SViewPort &); // get the last viewport SViewPort GetViewport(); - /** - * Render the given scene immediately. - * @param scene a Scene object describing what should be rendered. - */ - void RenderScene(Scene& scene); - - /** - * Return the scene that is currently being rendered. - * Only valid when the renderer is in a RenderScene call. - */ - Scene& GetScene(); - - /** - * Render text overlays on top of the scene. - * Assumes the caller has set up the GL environment for orthographic rendering - * with texturing and blending. - */ - void RenderTextOverlays(); - - // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, - // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) - void SetLightEnv(CLightEnv* lightenv) - { - m_LightEnv = lightenv; - } - - // set the mode to render subsequent terrain patches - void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode = mode; } - // get the mode to render subsequent terrain patches - ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; } - - // set the mode to render subsequent water patches - void SetWaterRenderMode(ERenderMode mode) { m_WaterRenderMode = mode; } - // get the mode to render subsequent water patches - ERenderMode GetWaterRenderMode() const { return m_WaterRenderMode; } - - // set the mode to render subsequent models - void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode = mode; } - // 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; } - - // bind a GL texture object to active unit - void BindTexture(int unit, unsigned int tex); - - // load the default set of alphamaps. - // return a negative error code if anything along the way fails. - // called via delay-load mechanism. - int LoadAlphaMaps(); - void UnloadAlphaMaps(); - // return stats accumulated for current frame Stats& GetStats() { return m_Stats; } - // return the current light environment - const CLightEnv &GetLightEnv() { return *m_LightEnv; } - - // return the current view camera - const CCamera& GetViewCamera() const { return m_ViewCamera; } - // replace the current view camera - void SetViewCamera(const CCamera& camera) { m_ViewCamera = camera; } - - // return the current cull camera - const CCamera& GetCullCamera() const { return m_CullCamera; } - - /** - * GetWaterManager: Return the renderer's water manager. - * - * @return the WaterManager object used by the renderer - */ - WaterManager* GetWaterManager() { return m_WaterManager; } - - /** - * GetSkyManager: Return the renderer's sky manager. - * - * @return the SkyManager object used by the renderer - */ - SkyManager* GetSkyManager() { return m_SkyManager; } - CTextureManager& GetTextureManager(); CShaderManager& GetShaderManager(); - CParticleManager& GetParticleManager(); - - TerrainRenderer& GetTerrainRenderer(); - - CMaterialManager& GetMaterialManager(); - CFontManager& GetFontManager(); - CShaderDefines GetSystemShaderDefines() { return m_SystemShaderDefines; } - CTimeManager& GetTimeManager(); CPostprocManager& GetPostprocManager(); + CSceneRenderer& GetSceneRenderer(); + CDebugRenderer& GetDebugRenderer(); /** - * GetCapabilities: Return which OpenGL capabilities are available and enabled. - * - * @return capabilities structure + * Performs a complete frame without presenting to force loading all needed + * resources. It's used for the first frame on a game start. + * TODO: It might be better to preload resources without a complete frame + * rendering. */ - const Caps& GetCapabilities() const { return m_Caps; } - - ShadowMap& GetShadowMap(); + void PreloadResourcesBeforeNextFrame(); /** - * Resets the render state to default, that was before a game started + * Makes a screenshot on the next RenderFrame according of the given + * screenshot type. */ - void ResetState(); + void MakeScreenShotOnNextFrame(ScreenShotType screenShotType); - /** - * m_SkipSubmit: Disable the actual submission of rendering commands to OpenGL. - * All state setup is still performed as usual. - */ - bool DoSkipSubmit() const { return m_SkipSubmit; } + Renderer::Backend::IDeviceCommandContext* GetDeviceCommandContext(); protected: - friend struct CRendererInternals; - friend class CVertexBuffer; friend class CPatchRData; friend class CDecalRData; - friend class FixedFunctionModelRenderer; - friend class ModelRenderer; - friend class PolygonSortModelRenderer; - friend class SortModelRenderer; - friend class RenderPathVertexShader; friend class HWLightingModelRenderer; friend class ShaderModelVertexRenderer; friend class InstancingModelRenderer; - friend class ShaderInstancingModelRenderer; - friend class TerrainRenderer; - friend class WaterRenderer; friend class CRenderingOptions; - //BEGIN: Implementation of SceneCollector - void Submit(CPatch* patch); - void Submit(SOverlayLine* overlay); - void Submit(SOverlayTexturedLine* overlay); - void Submit(SOverlaySprite* overlay); - void Submit(SOverlayQuad* overlay); - void Submit(CModelDecal* decal); - void Submit(CParticleEmitter* emitter); - void Submit(SOverlaySphere* overlay); - void SubmitNonRecursive(CModel* model); - //END: Implementation of SceneCollector - - // render any batched objects - void RenderSubmissions(const CBoundingBoxAligned& waterScissor); - - // patch rendering stuff - void RenderPatches(const CShaderDefines& context, int cullGroup); - - // model rendering stuff - void RenderModels(const CShaderDefines& context, int cullGroup); - void RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling); - - void RenderSilhouettes(const CShaderDefines& context); - - void RenderParticles(int cullGroup); - - // shadow rendering stuff - void RenderShadowMap(const CShaderDefines& context); - - // render water reflection and refraction textures - void RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor); - void RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned& scissor); - - void ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; - void ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; - - // debugging - void DisplayFrustum(); - - // enable oblique frustum clipping with the given clip plane - void SetObliqueFrustumClipping(CCamera& camera, const CVector4D& clipPlane) const; + bool ShouldRender() const; + void RenderFrameImpl(const bool renderGUI, const bool renderLogger); + void RenderFrame2D(const bool renderGUI, const bool renderLogger); + void RenderScreenShot(const bool needsPresent); + void RenderBigScreenShot(const bool needsPresent); + + // SetRenderPath: Select the preferred render path. + // This may only be called before Open(), because the layout of vertex arrays and other + // data may depend on the chosen render path. void SetRenderPath(RenderPath rp); void ReloadShaders(); - void RecomputeSystemShaderDefines(); - // hotloading - static Status ReloadChangedFileCB(void* param, const VfsPath& path); - - // RENDERER DATA: - /// Private data that is not needed by inline functions - CRendererInternals* m; + // Private data that is not needed by inline functions. + class Internals; + std::unique_ptr m; // view width - int m_Width; + int m_Width = 0; // view height - int m_Height; - - // Current terrain rendering mode. - ERenderMode m_TerrainRenderMode; - // Current water rendering mode. - ERenderMode m_WaterRenderMode; - // Current model rendering mode. - ERenderMode m_ModelRenderMode; - // Current overlay rendering mode. - ERenderMode m_OverlayRenderMode; - - CShaderDefines m_SystemShaderDefines; + int m_Height = 0; SViewPort m_Viewport; - /** - * m_ViewCamera: determines the eye position for rendering - * - * @see CGameView::m_ViewCamera - */ - CCamera m_ViewCamera; - - /** - * m_CullCamera: determines the frustum for culling and shadowmap calculations - * - * @see CGameView::m_ViewCamera - */ - CCamera m_CullCamera; - - // only valid inside a call to RenderScene - Scene* m_CurrentScene; - int m_CurrentCullGroup; - - // color used to clear screen in BeginFrame - float m_ClearColor[4]; - // current lighting setup - CLightEnv* m_LightEnv; - // ogl_tex handle of composite alpha map (all the alpha maps packed into one texture) - Handle m_hCompositeAlphaMap; - // coordinates of each (untransformed) alpha map within the packed texture - struct { - float u0,u1,v0,v1; - } m_AlphaMapCoords[NumAlphaMaps]; - // card capabilities - Caps m_Caps; - // build card cap bits - void EnumCaps(); // per-frame renderer stats Stats m_Stats; - /** - * m_WaterManager: the WaterManager object used for water textures and settings - * (e.g. water color, water height) - */ - WaterManager* m_WaterManager; - - /** - * m_SkyManager: the SkyManager object used for sky textures and settings - */ - SkyManager* m_SkyManager; - - /** - * Enable rendering of terrain tile priority text overlay, for debugging. - */ - bool m_DisplayTerrainPriorities; + bool m_ShouldPreloadResourcesBeforeNextFrame = false; - bool m_SkipSubmit; + ScreenShotType m_ScreenShotType = ScreenShotType::NONE; }; #endif // INCLUDED_RENDERER diff -Nru 0ad-0.0.25b/source/renderer/RenderingOptions.cpp 0ad-0.0.26/source/renderer/RenderingOptions.cpp --- 0ad-0.0.25b/source/renderer/RenderingOptions.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/RenderingOptions.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,12 +19,17 @@ #include "RenderingOptions.h" +#include "graphics/TextureManager.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStr.h" +#include "ps/CStrInternStatic.h" +#include "ps/VideoMode.h" #include "renderer/Renderer.h" #include "renderer/PostprocManager.h" +#include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" +#include "renderer/WaterManager.h" CRenderingOptions g_RenderingOptions; @@ -74,6 +79,37 @@ return "default"; // Silence warning about reaching end of non-void function. } +RenderDebugMode RenderDebugModeEnum::FromString(const CStr8& name) +{ + if (name == str_RENDER_DEBUG_MODE_NONE.c_str()) + return RenderDebugMode::NONE; + if (name == str_RENDER_DEBUG_MODE_AO.c_str()) + return RenderDebugMode::AO; + if (name == str_RENDER_DEBUG_MODE_ALPHA.c_str()) + return RenderDebugMode::ALPHA; + if (name == str_RENDER_DEBUG_MODE_CUSTOM.c_str()) + return RenderDebugMode::CUSTOM; + + LOGWARNING("Unknown render debug mode %s", name.c_str()); + return RenderDebugMode::NONE; +} + +CStrIntern RenderDebugModeEnum::ToString(RenderDebugMode mode) +{ + switch (mode) + { + case RenderDebugMode::AO: + return str_RENDER_DEBUG_MODE_AO; + case RenderDebugMode::ALPHA: + return str_RENDER_DEBUG_MODE_ALPHA; + case RenderDebugMode::CUSTOM: + return str_RENDER_DEBUG_MODE_CUSTOM; + default: + break; + } + return str_RENDER_DEBUG_MODE_NONE; +} + CRenderingOptions::CRenderingOptions() : m_ConfigHooks(new ConfigHooks()) { m_RenderPath = RenderPath::DEFAULT; @@ -84,13 +120,10 @@ m_WaterRefraction = false; m_WaterReflection = false; m_ShadowAlphaFix = false; - m_ARBProgramShadow = true; m_ShadowPCF = false; m_Particles = false; m_Silhouettes = false; - m_PreferGLSL = false; m_Fog = false; - m_ForceAlphaTest = false; m_GPUSkinning = false; m_SmoothLOS = false; m_PostProc = false; @@ -112,35 +145,27 @@ SetRenderPath(RenderPathEnum::FromString(renderPath)); }); - m_ConfigHooks->Setup("preferglsl", [this]() { - bool enabled; - CFG_GET_VAL("preferglsl", enabled); - SetPreferGLSL(enabled); - if (CRenderer::IsInitialised()) - g_Renderer.GetShadowMap().RecreateTexture(); - }); - m_ConfigHooks->Setup("shadowquality", []() { if (CRenderer::IsInitialised()) - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadowscascadecount", []() { if (CRenderer::IsInitialised()) { - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscovermap", []() { if (CRenderer::IsInitialised()) { - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscutoffdistance", []() { if (CRenderer::IsInitialised()) - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadows", [this]() { @@ -173,11 +198,35 @@ m_ConfigHooks->Setup("smoothlos", m_SmoothLOS); - m_ConfigHooks->Setup("watereffects", m_WaterEffects); - m_ConfigHooks->Setup("waterfancyeffects", m_WaterFancyEffects); + m_ConfigHooks->Setup("watereffects", [this]() { + bool enabled; + CFG_GET_VAL("watereffects", enabled); + SetWaterEffects(enabled); + if (CRenderer::IsInitialised()) + g_Renderer.GetSceneRenderer().GetWaterManager().RecreateOrLoadTexturesIfNeeded(); + }); + m_ConfigHooks->Setup("waterfancyeffects", [this]() { + bool enabled; + CFG_GET_VAL("waterfancyeffects", enabled); + SetWaterFancyEffects(enabled); + if (CRenderer::IsInitialised()) + g_Renderer.GetSceneRenderer().GetWaterManager().RecreateOrLoadTexturesIfNeeded(); + }); m_ConfigHooks->Setup("waterrealdepth", m_WaterRealDepth); - m_ConfigHooks->Setup("waterrefraction", m_WaterRefraction); - m_ConfigHooks->Setup("waterreflection", m_WaterReflection); + m_ConfigHooks->Setup("waterrefraction", [this]() { + bool enabled; + CFG_GET_VAL("waterrefraction", enabled); + SetWaterRefraction(enabled); + if (CRenderer::IsInitialised()) + g_Renderer.GetSceneRenderer().GetWaterManager().RecreateOrLoadTexturesIfNeeded(); + }); + m_ConfigHooks->Setup("waterreflection", [this]() { + bool enabled; + CFG_GET_VAL("waterreflection", enabled); + SetWaterReflection(enabled); + if (CRenderer::IsInitialised()) + g_Renderer.GetSceneRenderer().GetWaterManager().RecreateOrLoadTexturesIfNeeded(); + }); m_ConfigHooks->Setup("particles", m_Particles); m_ConfigHooks->Setup("fog", [this]() { @@ -187,17 +236,25 @@ }); m_ConfigHooks->Setup("silhouettes", m_Silhouettes); - m_ConfigHooks->Setup("forcealphatest", m_ForceAlphaTest); m_ConfigHooks->Setup("gpuskinning", [this]() { bool enabled; CFG_GET_VAL("gpuskinning", enabled); - if (enabled && !m_PreferGLSL) - LOGWARNING("GPUSkinning has been disabled, because it is not supported with PreferGLSL disabled."); + if (enabled && g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB) + LOGWARNING("GPUSkinning has been disabled, because it is not supported with ARB shaders."); else if (enabled) m_GPUSkinning = true; }); m_ConfigHooks->Setup("renderactors", m_RenderActors); + + m_ConfigHooks->Setup("textures.quality", []() { + if (CRenderer::IsInitialised()) + g_Renderer.GetTextureManager().OnQualityChanged(); + }); + m_ConfigHooks->Setup("textures.maxanisotropy", []() { + if (CRenderer::IsInitialised()) + g_Renderer.GetTextureManager().OnQualityChanged(); + }); } void CRenderingOptions::ClearHooks() @@ -226,27 +283,16 @@ g_Renderer.MakeShadersDirty(); } -void CRenderingOptions::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; - if (!CRenderer::IsInitialised()) - return; - g_Renderer.MakeShadersDirty(); - g_Renderer.RecomputeSystemShaderDefines(); -} - - void CRenderingOptions::SetRenderPath(RenderPath value) { m_RenderPath = value; if (CRenderer::IsInitialised()) g_Renderer.SetRenderPath(m_RenderPath); } + +void CRenderingOptions::SetRenderDebugMode(RenderDebugMode value) +{ + m_RenderDebugMode = value; + if (CRenderer::IsInitialised()) + g_Renderer.MakeShadersDirty(); +} diff -Nru 0ad-0.0.25b/source/renderer/RenderingOptions.h 0ad-0.0.26/source/renderer/RenderingOptions.h --- 0ad-0.0.25b/source/renderer/RenderingOptions.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/RenderingOptions.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,11 +27,13 @@ #ifndef INCLUDED_RENDERINGOPTIONS #define INCLUDED_RENDERINGOPTIONS -class CConfigDB; -class CStr8; +#include "ps/CStr.h" +#include "ps/CStrIntern.h" + class CRenderer; -enum RenderPath { +enum RenderPath +{ // If no rendering path is configured explicitly, the renderer // will choose the path when Open() is called. DEFAULT, @@ -49,6 +51,20 @@ static CStr8 ToString(RenderPath); }; +enum class RenderDebugMode +{ + NONE, + AO, + ALPHA, + CUSTOM +}; + +struct RenderDebugModeEnum +{ + static RenderDebugMode FromString(const CStr8& name); + static CStrIntern ToString(RenderDebugMode mode); +}; + class CRenderingOptions { // The renderer needs access to our private variables directly because capabilities have not yet been extracted @@ -82,11 +98,12 @@ OPTION_WITH_SIDE_EFFECT(Shadows, bool); OPTION_WITH_SIDE_EFFECT(ShadowPCF, bool); - OPTION_WITH_SIDE_EFFECT(PreferGLSL, bool); OPTION_WITH_SIDE_EFFECT(Fog, bool); OPTION_WITH_SIDE_EFFECT(RenderPath, RenderPath); + OPTION_WITH_SIDE_EFFECT(RenderDebugMode, RenderDebugMode); + OPTION(WaterEffects, bool); OPTION(WaterFancyEffects, bool); OPTION(WaterRealDepth, bool); @@ -94,9 +111,7 @@ OPTION(WaterReflection, bool); OPTION(ShadowAlphaFix, bool); - OPTION(ARBProgramShadow, bool); OPTION(Particles, bool); - OPTION(ForceAlphaTest, bool); OPTION(GPUSkinning, bool); OPTION(Silhouettes, bool); OPTION(SmoothLOS, bool); diff -Nru 0ad-0.0.25b/source/renderer/RenderModifiers.cpp 0ad-0.0.26/source/renderer/RenderModifiers.cpp --- 0ad-0.0.25b/source/renderer/RenderModifiers.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/RenderModifiers.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,28 +15,22 @@ * along with 0 A.D. If not, see . */ -/* - * Implementation of common RenderModifiers - */ - #include "precompiled.h" -#include "lib/ogl.h" -#include "maths/Vector3D.h" -#include "maths/Vector4D.h" -#include "maths/Matrix3D.h" - -#include "ps/CStrInternStatic.h" -#include "ps/Game.h" +#include "renderer/RenderModifiers.h" #include "graphics/GameView.h" #include "graphics/LightEnv.h" #include "graphics/LOSTexture.h" #include "graphics/Model.h" #include "graphics/TextureManager.h" - -#include "renderer/RenderModifiers.h" +#include "maths/Vector3D.h" +#include "maths/Vector4D.h" +#include "maths/Matrix3D.h" +#include "ps/CStrInternStatic.h" +#include "ps/Game.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" #include @@ -69,48 +63,100 @@ // ShaderRenderModifier implementation ShaderRenderModifier::ShaderRenderModifier() + : m_ShadingColor(1.0f, 1.0f, 1.0f, 1.0f), m_PlayerColor(1.0f, 1.0f, 1.0f, 1.0f) { } -void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader) +void ShaderRenderModifier::BeginPass( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) { - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->Uniform(str_cameraPos, g_Renderer.GetViewCamera().GetOrientation().GetTranslation()); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_cameraPos), + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetTranslation().AsFloatArray()); if (GetShadowMap()) - GetShadowMap()->BindTo(shader); + GetShadowMap()->BindTo(deviceCommandContext, shader); if (GetLightEnv()) { - shader->Uniform(str_ambient, GetLightEnv()->m_AmbientColor); - shader->Uniform(str_sunDir, GetLightEnv()->GetSunDir()); - shader->Uniform(str_sunColor, GetLightEnv()->m_SunColor); - - shader->Uniform(str_fogColor, GetLightEnv()->m_FogColor); - shader->Uniform(str_fogParams, GetLightEnv()->m_FogFactor, GetLightEnv()->m_FogMax, 0.f, 0.f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_ambient), + GetLightEnv()->m_AmbientColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunDir), + GetLightEnv()->GetSunDir().AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunColor), + GetLightEnv()->m_SunColor.AsFloatArray()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogColor), + GetLightEnv()->m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogParams), + GetLightEnv()->m_FogFactor, GetLightEnv()->m_FogMax); } - if (shader->GetTextureBinding(str_losTex).Active()) + if (shader->GetBindingSlot(str_losTex) >= 0) { - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTextureSmooth()); + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); // Don't bother sending the whole matrix, we just need two floats (scale and translation) - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); } - m_BindingInstancingTransform = shader->GetUniformBinding(str_instancingTransform); - m_BindingShadingColor = shader->GetUniformBinding(str_shadingColor); - m_BindingPlayerColor = shader->GetUniformBinding(str_playerColor); + m_BindingInstancingTransform = shader->GetBindingSlot(str_instancingTransform); + m_BindingShadingColor = shader->GetBindingSlot(str_shadingColor); + m_BindingPlayerColor = shader->GetBindingSlot(str_playerColor); + + if (m_BindingShadingColor >= 0) + { + m_ShadingColor = CColor(1.0f, 1.0f, 1.0f, 1.0f); + deviceCommandContext->SetUniform( + m_BindingShadingColor, m_ShadingColor.AsFloatArray()); + } + + if (m_BindingPlayerColor >= 0) + { + m_PlayerColor = g_Game->GetPlayerColor(0); + deviceCommandContext->SetUniform( + m_BindingPlayerColor, m_PlayerColor.AsFloatArray()); + } } -void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model) +void ShaderRenderModifier::PrepareModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + CModel* model) { - if (m_BindingInstancingTransform.Active()) - shader->Uniform(m_BindingInstancingTransform, model->GetTransform()); + if (m_BindingInstancingTransform >= 0) + { + deviceCommandContext->SetUniform( + m_BindingInstancingTransform, model->GetTransform().AsFloatArray()); + } - if (m_BindingShadingColor.Active()) - shader->Uniform(m_BindingShadingColor, model->GetShadingColor()); + if (m_BindingShadingColor >= 0 && m_ShadingColor != model->GetShadingColor()) + { + m_ShadingColor = model->GetShadingColor(); + deviceCommandContext->SetUniform( + m_BindingShadingColor, m_ShadingColor.AsFloatArray()); + } - if (m_BindingPlayerColor.Active()) - shader->Uniform(m_BindingPlayerColor, g_Game->GetPlayerColor(model->GetPlayerID())); + if (m_BindingPlayerColor >= 0) + { + const CColor& playerColor = g_Game->GetPlayerColor(model->GetPlayerID()); + if (m_PlayerColor != playerColor) + { + m_PlayerColor = playerColor; + deviceCommandContext->SetUniform( + m_BindingPlayerColor, m_PlayerColor.AsFloatArray()); + } + } } diff -Nru 0ad-0.0.25b/source/renderer/RenderModifiers.h 0ad-0.0.26/source/renderer/RenderModifiers.h --- 0ad-0.0.25b/source/renderer/RenderModifiers.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/RenderModifiers.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,12 +29,12 @@ #define INCLUDED_RENDERMODIFIERS #include "ModelRenderer.h" +#include "graphics/Color.h" #include "graphics/ShaderProgram.h" #include "graphics/ShaderTechnique.h" #include "graphics/Texture.h" class CLightEnv; -class CMatrix3D; class CModel; class ShadowMap; @@ -55,23 +55,21 @@ * BeginPass: Setup OpenGL for the given rendering pass. * * Must be implemented by derived classes. - * - * @param pass The current pass number (pass == 0 is the first pass) - * - * @return The streamflags that indicate which vertex components - * are required by the fragment stages (see STREAM_XYZ constants). */ - virtual void BeginPass(const CShaderProgramPtr& shader) = 0; + virtual void BeginPass( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) = 0; /** * PrepareModel: Called before rendering the given model. * * Default behaviour does nothing. * - * @param pass The current pass number (pass == 0 is the first pass) * @param model The model that is about to be rendered. */ - virtual void PrepareModel(const CShaderProgramPtr& shader, CModel* model) = 0; + virtual void PrepareModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + CModel* model) = 0; }; @@ -122,13 +120,19 @@ ShaderRenderModifier(); // Implementation - void BeginPass(const CShaderProgramPtr& shader); - void PrepareModel(const CShaderProgramPtr& shader, CModel* model); + void BeginPass( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) override; + void PrepareModel( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + CModel* model) override; private: - CShaderProgram::Binding m_BindingInstancingTransform; - CShaderProgram::Binding m_BindingShadingColor; - CShaderProgram::Binding m_BindingPlayerColor; + int32_t m_BindingInstancingTransform = -1; + int32_t m_BindingShadingColor = -1; + int32_t m_BindingPlayerColor = -1; + + CColor m_ShadingColor, m_PlayerColor; }; #endif // INCLUDED_RENDERMODIFIERS diff -Nru 0ad-0.0.25b/source/renderer/SceneRenderer.cpp 0ad-0.0.26/source/renderer/SceneRenderer.cpp --- 0ad-0.0.25b/source/renderer/SceneRenderer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/SceneRenderer.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,1193 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "SceneRenderer.h" + +#include "graphics/Camera.h" +#include "graphics/Decal.h" +#include "graphics/GameView.h" +#include "graphics/LightEnv.h" +#include "graphics/LOSTexture.h" +#include "graphics/MaterialManager.h" +#include "graphics/MiniMapTexture.h" +#include "graphics/Model.h" +#include "graphics/ModelDef.h" +#include "graphics/ParticleManager.h" +#include "graphics/Patch.h" +#include "graphics/ShaderManager.h" +#include "graphics/TerritoryTexture.h" +#include "graphics/Terrain.h" +#include "graphics/Texture.h" +#include "graphics/TextureManager.h" +#include "maths/Matrix3D.h" +#include "maths/MathUtil.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "ps/CStrInternStatic.h" +#include "ps/Game.h" +#include "ps/Profile.h" +#include "ps/VideoMode.h" +#include "ps/World.h" +#include "renderer/backend/IDevice.h" +#include "renderer/DebugRenderer.h" +#include "renderer/HWLightingModelRenderer.h" +#include "renderer/InstancingModelRenderer.h" +#include "renderer/ModelRenderer.h" +#include "renderer/OverlayRenderer.h" +#include "renderer/ParticleRenderer.h" +#include "renderer/PostprocManager.h" +#include "renderer/Renderer.h" +#include "renderer/RenderingOptions.h" +#include "renderer/RenderModifiers.h" +#include "renderer/ShadowMap.h" +#include "renderer/SilhouetteRenderer.h" +#include "renderer/SkyManager.h" +#include "renderer/TerrainOverlay.h" +#include "renderer/TerrainRenderer.h" +#include "renderer/WaterManager.h" + +#include + +struct SScreenRect +{ + int x1, y1, x2, y2; +}; + +/** + * Struct CSceneRendererInternals: Truly hide data that is supposed to be hidden + * in this structure so it won't even appear in header files. + */ +class CSceneRenderer::Internals +{ + NONCOPYABLE(Internals); +public: + Internals() = default; + ~Internals() = default; + + /// Water manager + WaterManager waterManager; + + /// Sky manager + SkyManager skyManager; + + /// Terrain renderer + TerrainRenderer terrainRenderer; + + /// Overlay renderer + OverlayRenderer overlayRenderer; + + /// Particle manager + CParticleManager particleManager; + + /// Particle renderer + ParticleRenderer particleRenderer; + + /// Material manager + CMaterialManager materialManager; + + /// Shadow map + ShadowMap shadow; + + SilhouetteRenderer silhouetteRenderer; + + /// Various model renderers + struct Models + { + // NOTE: The current renderer design (with ModelRenderer, ModelVertexRenderer, + // RenderModifier, etc) is mostly a relic of an older design that implemented + // the different materials and rendering modes through extensive subclassing + // and hooking objects together in various combinations. + // The new design uses the CShaderManager API to abstract away the details + // of rendering, and uses a data-driven approach to materials, so there are + // now a small number of generic subclasses instead of many specialised subclasses, + // but most of the old infrastructure hasn't been refactored out yet and leads to + // some unwanted complexity. + + // Submitted models are split on two axes: + // - Normal vs Transp[arent] - alpha-blended models are stored in a separate + // list so we can draw them above/below the alpha-blended water plane correctly + // - Skinned vs Unskinned - with hardware lighting we don't need to + // duplicate mesh data per model instance (except for skinned models), + // so non-skinned models get different ModelVertexRenderers + + ModelRendererPtr NormalSkinned; + ModelRendererPtr NormalUnskinned; // == NormalSkinned if unskinned shader instancing not supported + ModelRendererPtr TranspSkinned; + ModelRendererPtr TranspUnskinned; // == TranspSkinned if unskinned shader instancing not supported + + ModelVertexRendererPtr VertexRendererShader; + ModelVertexRendererPtr VertexInstancingShader; + ModelVertexRendererPtr VertexGPUSkinningShader; + + LitRenderModifierPtr ModShader; + } Model; + + CShaderDefines globalContext; + + /** + * Renders all non-alpha-blended models with the given context. + */ + void CallModelRenderers( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, int flags) + { + CShaderDefines contextSkinned = context; + if (g_RenderingOptions.GetGPUSkinning()) + { + contextSkinned.Add(str_USE_INSTANCING, str_1); + contextSkinned.Add(str_USE_GPU_SKINNING, str_1); + } + Model.NormalSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags); + + if (Model.NormalUnskinned != Model.NormalSkinned) + { + CShaderDefines contextUnskinned = context; + contextUnskinned.Add(str_USE_INSTANCING, str_1); + Model.NormalUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags); + } + } + + /** + * Renders all alpha-blended models with the given context. + */ + void CallTranspModelRenderers( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, int flags) + { + CShaderDefines contextSkinned = context; + if (g_RenderingOptions.GetGPUSkinning()) + { + contextSkinned.Add(str_USE_INSTANCING, str_1); + contextSkinned.Add(str_USE_GPU_SKINNING, str_1); + } + Model.TranspSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags); + + if (Model.TranspUnskinned != Model.TranspSkinned) + { + CShaderDefines contextUnskinned = context; + contextUnskinned.Add(str_USE_INSTANCING, str_1); + Model.TranspUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags); + } + } +}; + +CSceneRenderer::CSceneRenderer() +{ + m = std::make_unique(); + + m_TerrainRenderMode = SOLID; + m_WaterRenderMode = SOLID; + m_ModelRenderMode = SOLID; + m_OverlayRenderMode = SOLID; + + m_DisplayTerrainPriorities = false; + + m_LightEnv = nullptr; + + m_CurrentScene = nullptr; +} + +CSceneRenderer::~CSceneRenderer() +{ + // We no longer UnloadWaterTextures here - + // that is the responsibility of the module that asked for + // them to be loaded (i.e. CGameView). + m.reset(); +} + +void CSceneRenderer::ReloadShaders() +{ + m->globalContext = CShaderDefines(); + + if (g_RenderingOptions.GetShadows()) + { + m->globalContext.Add(str_USE_SHADOW, str_1); + if (g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB && + g_VideoMode.GetBackendDevice()->GetCapabilities().ARBShadersShadow) + { + m->globalContext.Add(str_USE_FP_SHADOW, str_1); + } + if (g_RenderingOptions.GetShadowPCF()) + m->globalContext.Add(str_USE_SHADOW_PCF, str_1); + const int cascadeCount = m->shadow.GetCascadeCount(); + ENSURE(1 <= cascadeCount && cascadeCount <= 4); + const CStrIntern cascadeCountStr[5] = {str_0, str_1, str_2, str_3, str_4}; + m->globalContext.Add(str_SHADOWS_CASCADE_COUNT, cascadeCountStr[cascadeCount]); +#if !CONFIG2_GLES + m->globalContext.Add(str_USE_SHADOW_SAMPLER, str_1); +#endif + } + + m->globalContext.Add(str_RENDER_DEBUG_MODE, + RenderDebugModeEnum::ToString(g_RenderingOptions.GetRenderDebugMode())); + + if (g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB && g_RenderingOptions.GetFog()) + m->globalContext.Add(str_USE_FOG, str_1); + + m->Model.ModShader = LitRenderModifierPtr(new ShaderRenderModifier()); + + ENSURE(g_RenderingOptions.GetRenderPath() != RenderPath::FIXED); + m->Model.VertexRendererShader = ModelVertexRendererPtr(new ShaderModelVertexRenderer()); + m->Model.VertexInstancingShader = ModelVertexRendererPtr(new InstancingModelRenderer(false, g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB)); + + if (g_RenderingOptions.GetGPUSkinning()) // TODO: should check caps and GLSL etc too + { + m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new InstancingModelRenderer(true, g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB)); + m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); + m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); + } + else + { + m->Model.VertexGPUSkinningShader.reset(); + m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); + m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); + } + + m->Model.NormalUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); + m->Model.TranspUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); +} + +void CSceneRenderer::Initialize() +{ + // Let component renderers perform one-time initialization after graphics capabilities and + // the shader path have been determined. + m->overlayRenderer.Initialize(); +} + +// resize renderer view +void CSceneRenderer::Resize(int UNUSED(width), int UNUSED(height)) +{ + // need to recreate the shadow map object to resize the shadow texture + m->shadow.RecreateTexture(); + + m->waterManager.RecreateOrLoadTexturesIfNeeded(); +} + +void CSceneRenderer::BeginFrame() +{ + // choose model renderers for this frame + m->Model.ModShader->SetShadowMap(&m->shadow); + m->Model.ModShader->SetLightEnv(m_LightEnv); +} + +void CSceneRenderer::SetSimulation(CSimulation2* simulation) +{ + // set current simulation context for terrain renderer + m->terrainRenderer.SetSimulation(simulation); +} + +void CSceneRenderer::RenderShadowMap( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context) +{ + PROFILE3_GPU("shadow map"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render shadow map"); + + CShaderDefines shadowsContext = context; + shadowsContext.Add(str_PASS_SHADOWS, str_1); + + CShaderDefines contextCast = shadowsContext; + contextCast.Add(str_MODE_SHADOWCAST, str_1); + + m->shadow.BeginRender(); + + const int cascadeCount = m->shadow.GetCascadeCount(); + ENSURE(0 <= cascadeCount && cascadeCount <= 4); + for (int cascade = 0; cascade < cascadeCount; ++cascade) + { + m->shadow.PrepareCamera(cascade); + + const int cullGroup = CULL_SHADOWS_CASCADE_0 + cascade; + { + PROFILE("render patches"); + m->terrainRenderer.RenderPatches(deviceCommandContext, cullGroup, shadowsContext); + } + + { + PROFILE("render models"); + m->CallModelRenderers(deviceCommandContext, contextCast, cullGroup, MODELFLAG_CASTSHADOWS); + } + + { + PROFILE("render transparent models"); + m->CallTranspModelRenderers(deviceCommandContext, contextCast, cullGroup, MODELFLAG_CASTSHADOWS); + } + } + + m->shadow.EndRender(); + + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); +} + +void CSceneRenderer::RenderPatches( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup) +{ + PROFILE3_GPU("patches"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render patches"); + + // Switch on wireframe if we need it. + CShaderDefines localContext = context; + if (m_TerrainRenderMode == WIREFRAME) + localContext.Add(str_MODE_WIREFRAME, str_1); + + // Render all the patches, including blend pass. + m->terrainRenderer.RenderTerrainShader(deviceCommandContext, localContext, cullGroup, + g_RenderingOptions.GetShadows() ? &m->shadow : nullptr); + + if (m_TerrainRenderMode == EDGED_FACES) + { + localContext.Add(str_MODE_WIREFRAME, str_1); + // Edged faces: need to make a second pass over the data. + + // Render tiles edges. + m->terrainRenderer.RenderPatches( + deviceCommandContext, cullGroup, localContext, CColor(0.5f, 0.5f, 1.0f, 1.0f)); + + // Render outline of each patch. + m->terrainRenderer.RenderOutlines(deviceCommandContext, cullGroup); + } +} + +void CSceneRenderer::RenderModels( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup) +{ + PROFILE3_GPU("models"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render models"); + + int flags = 0; + + CShaderDefines localContext = context; + + if (m_ModelRenderMode == WIREFRAME) + localContext.Add(str_MODE_WIREFRAME, str_1); + + m->CallModelRenderers(deviceCommandContext, localContext, cullGroup, flags); + + if (m_ModelRenderMode == EDGED_FACES) + { + localContext.Add(str_MODE_WIREFRAME_SOLID, str_1); + m->CallModelRenderers(deviceCommandContext, localContext, cullGroup, flags); + } +} + +void CSceneRenderer::RenderTransparentModels( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode) +{ + PROFILE3_GPU("transparent models"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render transparent models"); + + int flags = 0; + + CShaderDefines contextOpaque = context; + contextOpaque.Add(str_ALPHABLEND_PASS_OPAQUE, str_1); + + CShaderDefines contextBlend = context; + contextBlend.Add(str_ALPHABLEND_PASS_BLEND, str_1); + + if (m_ModelRenderMode == WIREFRAME) + { + contextOpaque.Add(str_MODE_WIREFRAME, str_1); + contextBlend.Add(str_MODE_WIREFRAME, str_1); + } + + if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_OPAQUE) + m->CallTranspModelRenderers(deviceCommandContext, contextOpaque, cullGroup, flags); + + if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_BLEND) + m->CallTranspModelRenderers(deviceCommandContext, contextBlend, cullGroup, flags); + + if (m_ModelRenderMode == EDGED_FACES) + { + CShaderDefines contextWireframe = contextOpaque; + contextWireframe.Add(str_MODE_WIREFRAME, str_1); + + m->CallTranspModelRenderers(deviceCommandContext, contextWireframe, cullGroup, flags); + } +} + +// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space) +// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html +// - worldPlane is a clip plane in world space (worldPlane.Dot(v) >= 0 for any vector v passing the clipping test) +void CSceneRenderer::SetObliqueFrustumClipping(CCamera& camera, const CVector4D& worldPlane) const +{ + // First, we'll convert the given clip plane to camera space, then we'll + // Get the view matrix and normal matrix (top 3x3 part of view matrix) + CMatrix3D normalMatrix = camera.GetOrientation().GetTranspose(); + CVector4D camPlane = normalMatrix.Transform(worldPlane); + + CMatrix3D matrix = camera.GetProjection(); + + // Calculate the clip-space corner point opposite the clipping plane + // as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + + CVector4D q; + q.X = (Sign(camPlane.X) - matrix[8] / matrix[11]) / matrix[0]; + q.Y = (Sign(camPlane.Y) - matrix[9] / matrix[11]) / matrix[5]; + q.Z = 1.0f / matrix[11]; + q.W = (1.0f - matrix[10] / matrix[11]) / matrix[14]; + + // Calculate the scaled plane vector + CVector4D c = camPlane * (2.0f * matrix[11] / camPlane.Dot(q)); + + // Replace the third row of the projection matrix + matrix[2] = c.X; + matrix[6] = c.Y; + matrix[10] = c.Z - matrix[11]; + matrix[14] = c.W; + + // Load it back into the camera + camera.SetProjection(matrix); +} + +void CSceneRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const +{ + WaterManager& wm = m->waterManager; + + CMatrix3D projection; + if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) + { + const float aspectRatio = 1.0f; + // Expand fov slightly since ripples can reflect parts of the scene that + // are slightly outside the normal camera view, and we want to avoid any + // noticeable edge-filtering artifacts + projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); + } + else + projection = m_ViewCamera.GetProjection(); + + camera = m_ViewCamera; + + // Temporarily change the camera to one that is reflected. + // Also, for texturing purposes, make it render to a view port the size of the + // water texture, stretch the image according to our aspect ratio so it covers + // the whole screen despite being rendered into a square, and cover slightly more + // of the view so we can see wavy reflections of slightly off-screen objects. + camera.m_Orientation.Scale(1, -1, 1); + camera.m_Orientation.Translate(0, 2 * wm.m_WaterHeight, 0); + camera.UpdateFrustum(scissor); + // Clip slightly above the water to improve reflections of objects on the water + // when the reflections are distorted. + camera.ClipFrustum(CVector4D(0, 1, 0, -wm.m_WaterHeight + 2.0f)); + + SViewPort vp; + vp.m_Height = wm.m_RefTextureSize; + vp.m_Width = wm.m_RefTextureSize; + vp.m_X = 0; + vp.m_Y = 0; + camera.SetViewPort(vp); + camera.SetProjection(projection); + CMatrix3D scaleMat; + scaleMat.SetScaling(g_Renderer.GetHeight() / static_cast(std::max(1, g_Renderer.GetWidth())), 1.0f, 1.0f); + camera.SetProjection(scaleMat * camera.GetProjection()); + + CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight + 0.5f); + SetObliqueFrustumClipping(camera, camPlane); +} + +void CSceneRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const +{ + WaterManager& wm = m->waterManager; + + CMatrix3D projection; + if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) + { + const float aspectRatio = 1.0f; + // Expand fov slightly since ripples can reflect parts of the scene that + // are slightly outside the normal camera view, and we want to avoid any + // noticeable edge-filtering artifacts + projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); + } + else + projection = m_ViewCamera.GetProjection(); + + camera = m_ViewCamera; + + // Temporarily change the camera to make it render to a view port the size of the + // water texture, stretch the image according to our aspect ratio so it covers + // the whole screen despite being rendered into a square, and cover slightly more + // of the view so we can see wavy refractions of slightly off-screen objects. + camera.UpdateFrustum(scissor); + camera.ClipFrustum(CVector4D(0, -1, 0, wm.m_WaterHeight + 0.5f)); // add some to avoid artifacts near steep shores. + + SViewPort vp; + vp.m_Height = wm.m_RefTextureSize; + vp.m_Width = wm.m_RefTextureSize; + vp.m_X = 0; + vp.m_Y = 0; + camera.SetViewPort(vp); + camera.SetProjection(projection); + CMatrix3D scaleMat; + scaleMat.SetScaling(g_Renderer.GetHeight() / static_cast(std::max(1, g_Renderer.GetWidth())), 1.0f, 1.0f); + camera.SetProjection(scaleMat * camera.GetProjection()); +} + +// RenderReflections: render the water reflections to the reflection texture +void CSceneRenderer::RenderReflections( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, const CBoundingBoxAligned& scissor) +{ + PROFILE3_GPU("water reflections"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render water reflections"); + + WaterManager& wm = m->waterManager; + + // Remember old camera + CCamera normalCamera = m_ViewCamera; + + ComputeReflectionCamera(m_ViewCamera, scissor); + const CBoundingBoxAligned reflectionScissor = + m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); + if (reflectionScissor.IsEmpty()) + { + m_ViewCamera = normalCamera; + return; + } + + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + // Save the model-view-projection matrix so the shaders can use it for projective texturing + wm.m_ReflectionMatrix = m_ViewCamera.GetViewProjection(); + + float vpHeight = wm.m_RefTextureSize; + float vpWidth = wm.m_RefTextureSize; + + SScreenRect screenScissor; + screenScissor.x1 = static_cast(floor((reflectionScissor[0].X * 0.5f + 0.5f) * vpWidth)); + screenScissor.y1 = static_cast(floor((reflectionScissor[0].Y * 0.5f + 0.5f) * vpHeight)); + screenScissor.x2 = static_cast(ceil((reflectionScissor[1].X * 0.5f + 0.5f) * vpWidth)); + screenScissor.y2 = static_cast(ceil((reflectionScissor[1].Y * 0.5f + 0.5f) * vpHeight)); + + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = screenScissor.x1; + scissorRect.y = screenScissor.y1; + scissorRect.width = screenScissor.x2 - screenScissor.x1; + scissorRect.height = screenScissor.y2 - screenScissor.y1; + deviceCommandContext->SetScissors(1, &scissorRect); + + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + deviceCommandContext->SetFramebuffer(wm.m_ReflectionFramebuffer.get()); + deviceCommandContext->ClearFramebuffer(); + + CShaderDefines reflectionsContext = context; + reflectionsContext.Add(str_PASS_REFLECTIONS, str_1); + + // Render terrain and models + RenderPatches(deviceCommandContext, reflectionsContext, CULL_REFLECTIONS); + RenderModels(deviceCommandContext, reflectionsContext, CULL_REFLECTIONS); + RenderTransparentModels(deviceCommandContext, reflectionsContext, CULL_REFLECTIONS, TRANSPARENT); + + // Particles are always oriented to face the camera in the vertex shader, + // so they don't need the inverted cull face. + if (g_RenderingOptions.GetParticles()) + { + RenderParticles(deviceCommandContext, CULL_REFLECTIONS); + } + + deviceCommandContext->SetScissors(0, nullptr); + + // Reset old camera + m_ViewCamera = normalCamera; + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); +} + +// RenderRefractions: render the water refractions to the refraction texture +void CSceneRenderer::RenderRefractions( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, const CBoundingBoxAligned &scissor) +{ + PROFILE3_GPU("water refractions"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render water refractions"); + + WaterManager& wm = m->waterManager; + + // Remember old camera + CCamera normalCamera = m_ViewCamera; + + ComputeRefractionCamera(m_ViewCamera, scissor); + const CBoundingBoxAligned refractionScissor = + m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); + if (refractionScissor.IsEmpty()) + { + m_ViewCamera = normalCamera; + return; + } + + CVector4D camPlane(0, -1, 0, wm.m_WaterHeight + 2.0f); + SetObliqueFrustumClipping(m_ViewCamera, camPlane); + + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + // Save the model-view-projection matrix so the shaders can use it for projective texturing + wm.m_RefractionMatrix = m_ViewCamera.GetViewProjection(); + wm.m_RefractionProjInvMatrix = m_ViewCamera.GetProjection().GetInverse(); + wm.m_RefractionViewInvMatrix = m_ViewCamera.GetOrientation(); + + float vpHeight = wm.m_RefTextureSize; + float vpWidth = wm.m_RefTextureSize; + + SScreenRect screenScissor; + screenScissor.x1 = static_cast(floor((refractionScissor[0].X * 0.5f + 0.5f) * vpWidth)); + screenScissor.y1 = static_cast(floor((refractionScissor[0].Y * 0.5f + 0.5f) * vpHeight)); + screenScissor.x2 = static_cast(ceil((refractionScissor[1].X * 0.5f + 0.5f) * vpWidth)); + screenScissor.y2 = static_cast(ceil((refractionScissor[1].Y * 0.5f + 0.5f) * vpHeight)); + + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = screenScissor.x1; + scissorRect.y = screenScissor.y1; + scissorRect.width = screenScissor.x2 - screenScissor.x1; + scissorRect.height = screenScissor.y2 - screenScissor.y1; + deviceCommandContext->SetScissors(1, &scissorRect); + + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + deviceCommandContext->SetFramebuffer(wm.m_RefractionFramebuffer.get()); + deviceCommandContext->ClearFramebuffer(); + + // Render terrain and models + RenderPatches(deviceCommandContext, context, CULL_REFRACTIONS); + + // Render debug-related terrain overlays to make it visible under water. + ITerrainOverlay::RenderOverlaysBeforeWater(deviceCommandContext); + + RenderModels(deviceCommandContext, context, CULL_REFRACTIONS); + RenderTransparentModels(deviceCommandContext, context, CULL_REFRACTIONS, TRANSPARENT_OPAQUE); + + deviceCommandContext->SetScissors(0, nullptr); + + // Reset old camera + m_ViewCamera = normalCamera; + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); +} + +void CSceneRenderer::RenderSilhouettes( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context) +{ + PROFILE3_GPU("silhouettes"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render silhouettes"); + + CShaderDefines contextOccluder = context; + contextOccluder.Add(str_MODE_SILHOUETTEOCCLUDER, str_1); + + CShaderDefines contextDisplay = context; + contextDisplay.Add(str_MODE_SILHOUETTEDISPLAY, str_1); + + // Render silhouettes of units hidden behind terrain or occluders. + // To avoid breaking the standard rendering of alpha-blended objects, this + // has to be done in a separate pass. + // First we render all occluders into depth, then render all units with + // inverted depth test so any behind an occluder will get drawn in a constant + // color. + + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + deviceCommandContext->ClearFramebuffer(false, true, true); + + // Render occluders: + + { + PROFILE("render patches"); + m->terrainRenderer.RenderPatches(deviceCommandContext, CULL_SILHOUETTE_OCCLUDER, contextOccluder); + } + + { + PROFILE("render model occluders"); + m->CallModelRenderers(deviceCommandContext, contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); + } + + { + PROFILE("render transparent occluders"); + m->CallTranspModelRenderers(deviceCommandContext, contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); + } + + // Since we can't sort, we'll use the stencil buffer to ensure we only draw + // a pixel once (using the color of whatever model happens to be drawn first). + { + PROFILE("render model casters"); + m->CallModelRenderers(deviceCommandContext, contextDisplay, CULL_SILHOUETTE_CASTER, 0); + } + + { + PROFILE("render transparent casters"); + m->CallTranspModelRenderers(deviceCommandContext, contextDisplay, CULL_SILHOUETTE_CASTER, 0); + } +} + +void CSceneRenderer::RenderParticles( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup) +{ + PROFILE3_GPU("particles"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render particles"); + + m->particleRenderer.RenderParticles( + deviceCommandContext, cullGroup, m_ModelRenderMode == WIREFRAME); + + if (m_ModelRenderMode == EDGED_FACES) + { + m->particleRenderer.RenderParticles( + deviceCommandContext, cullGroup, true); + m->particleRenderer.RenderBounds(cullGroup); + } +} + +// RenderSubmissions: force rendering of any batched objects +void CSceneRenderer::RenderSubmissions( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CBoundingBoxAligned& waterScissor) +{ + PROFILE3("render submissions"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render submissions"); + + m->skyManager.LoadAndUploadSkyTexturesIfNeeded(deviceCommandContext); + + GetScene().GetLOSTexture().InterpolateLOS(deviceCommandContext); + GetScene().GetTerritoryTexture().UpdateIfNeeded(deviceCommandContext); + GetScene().GetMiniMapTexture().Render(deviceCommandContext); + + CShaderDefines context = m->globalContext; + + int cullGroup = CULL_DEFAULT; + + // Set the camera + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + // Prepare model renderers + { + PROFILE3("prepare models"); + m->Model.NormalSkinned->PrepareModels(); + m->Model.TranspSkinned->PrepareModels(); + if (m->Model.NormalUnskinned != m->Model.NormalSkinned) + m->Model.NormalUnskinned->PrepareModels(); + if (m->Model.TranspUnskinned != m->Model.TranspSkinned) + m->Model.TranspUnskinned->PrepareModels(); + } + + m->terrainRenderer.PrepareForRendering(); + + m->overlayRenderer.PrepareForRendering(); + + m->particleRenderer.PrepareForRendering(context); + + if (g_RenderingOptions.GetShadows()) + { + RenderShadowMap(deviceCommandContext, context); + } + + if (m->waterManager.m_RenderWater) + { + if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) + { + m->waterManager.UpdateQuality(); + + PROFILE3_GPU("water scissor"); + if (g_RenderingOptions.GetWaterReflection()) + RenderReflections(deviceCommandContext, context, waterScissor); + + if (g_RenderingOptions.GetWaterRefraction()) + RenderRefractions(deviceCommandContext, context, waterScissor); + + if (g_RenderingOptions.GetWaterFancyEffects()) + m->terrainRenderer.RenderWaterFoamOccluders(deviceCommandContext, cullGroup); + } + } + + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + + CPostprocManager& postprocManager = g_Renderer.GetPostprocManager(); + if (postprocManager.IsEnabled()) + { + // We have to update the post process manager with real near/far planes + // that we use for the scene rendering. + postprocManager.SetDepthBufferClipPlanes( + m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane() + ); + postprocManager.Initialize(); + postprocManager.CaptureRenderOutput(deviceCommandContext); + } + else + { + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + } + + { + PROFILE3_GPU("clear buffers"); + // We don't need to clear the color attachment of the framebuffer if the sky + // is going to be rendered. Because it covers the whole view. + deviceCommandContext->ClearFramebuffer(!m->skyManager.IsSkyVisible(), true, true); + } + + m->skyManager.RenderSky(deviceCommandContext); + + // render submitted patches and models + RenderPatches(deviceCommandContext, context, cullGroup); + + // render debug-related terrain overlays + ITerrainOverlay::RenderOverlaysBeforeWater(deviceCommandContext); + + // render other debug-related overlays before water (so they can be seen when underwater) + m->overlayRenderer.RenderOverlaysBeforeWater(deviceCommandContext); + + RenderModels(deviceCommandContext, context, cullGroup); + + // render water + if (m->waterManager.m_RenderWater && g_Game && waterScissor.GetVolume() > 0) + { + if (m->waterManager.WillRenderFancyWater()) + { + // Render transparent stuff, but only the solid parts that can occlude block water. + RenderTransparentModels(deviceCommandContext, context, cullGroup, TRANSPARENT_OPAQUE); + + m->terrainRenderer.RenderWater(deviceCommandContext, context, cullGroup, &m->shadow); + + // Render transparent stuff again, but only the blended parts that overlap water. + RenderTransparentModels(deviceCommandContext, context, cullGroup, TRANSPARENT_BLEND); + } + else + { + m->terrainRenderer.RenderWater(deviceCommandContext, context, cullGroup, &m->shadow); + + // Render transparent stuff, so it can overlap models/terrain. + RenderTransparentModels(deviceCommandContext, context, cullGroup, TRANSPARENT); + } + } + else + { + // render transparent stuff, so it can overlap models/terrain + RenderTransparentModels(deviceCommandContext, context, cullGroup, TRANSPARENT); + } + + // render debug-related terrain overlays + ITerrainOverlay::RenderOverlaysAfterWater(deviceCommandContext, cullGroup); + + // render some other overlays after water (so they can be displayed on top of water) + m->overlayRenderer.RenderOverlaysAfterWater(deviceCommandContext); + + // particles are transparent so render after water + if (g_RenderingOptions.GetParticles()) + { + RenderParticles(deviceCommandContext, cullGroup); + } + + if (postprocManager.IsEnabled()) + { + if (g_Renderer.GetPostprocManager().IsMultisampleEnabled()) + g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer(deviceCommandContext); + + postprocManager.ApplyPostproc(deviceCommandContext); + postprocManager.ReleaseRenderOutput(deviceCommandContext); + } + + if (g_RenderingOptions.GetSilhouettes()) + { + RenderSilhouettes(deviceCommandContext, context); + } + + // render debug lines + if (g_RenderingOptions.GetDisplayFrustum()) + DisplayFrustum(); + + if (g_RenderingOptions.GetDisplayShadowsFrustum()) + m->shadow.RenderDebugBounds(); + + m->silhouetteRenderer.RenderDebugBounds(deviceCommandContext); + m->silhouetteRenderer.RenderDebugOverlays(deviceCommandContext); + + // render overlays that should appear on top of all other objects + m->overlayRenderer.RenderForegroundOverlays(deviceCommandContext, m_ViewCamera); +} + +void CSceneRenderer::EndFrame() +{ + // empty lists + m->terrainRenderer.EndFrame(); + m->overlayRenderer.EndFrame(); + m->particleRenderer.EndFrame(); + m->silhouetteRenderer.EndFrame(); + + // Finish model renderers + m->Model.NormalSkinned->EndFrame(); + m->Model.TranspSkinned->EndFrame(); + if (m->Model.NormalUnskinned != m->Model.NormalSkinned) + m->Model.NormalUnskinned->EndFrame(); + if (m->Model.TranspUnskinned != m->Model.TranspSkinned) + m->Model.TranspUnskinned->EndFrame(); +} + +void CSceneRenderer::DisplayFrustum() +{ + g_Renderer.GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 0.25f), 2); + g_Renderer.GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 1.0f), 2, true); +} + +// Text overlay rendering +void CSceneRenderer::RenderTextOverlays(CCanvas2D& canvas) +{ + PROFILE3_GPU("text overlays"); + + if (m_DisplayTerrainPriorities) + m->terrainRenderer.RenderPriorities(canvas, CULL_DEFAULT); +} + +// SetSceneCamera: setup projection and transform of camera and adjust viewport to current view +// The camera always represents the actual camera used to render a scene, not any virtual camera +// used for shadow rendering or reflections. +void CSceneRenderer::SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera) +{ + m_ViewCamera = viewCamera; + m_CullCamera = cullCamera; + + if (g_RenderingOptions.GetShadows()) + m->shadow.SetupFrame(m_CullCamera, m_LightEnv->GetSunDir()); +} + +void CSceneRenderer::Submit(CPatch* patch) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + { + m->shadow.AddShadowReceiverBound(patch->GetWorldBounds()); + m->silhouetteRenderer.AddOccluder(patch); + } + + if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) + { + const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; + m->shadow.AddShadowCasterBound(cascade, patch->GetWorldBounds()); + } + + m->terrainRenderer.Submit(m_CurrentCullGroup, patch); +} + +void CSceneRenderer::Submit(SOverlayLine* overlay) +{ + // Overlays are only needed in the default cull group for now, + // so just ignore submissions to any other group + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlayTexturedLine* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlaySprite* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlayQuad* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlaySphere* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(CModelDecal* decal) +{ + // Decals can't cast shadows since they're flat on the terrain. + // They can receive shadows, but the terrain under them will have + // already been passed to AddShadowCasterBound, so don't bother + // doing it again here. + + m->terrainRenderer.Submit(m_CurrentCullGroup, decal); +} + +void CSceneRenderer::Submit(CParticleEmitter* emitter) +{ + m->particleRenderer.Submit(m_CurrentCullGroup, emitter); +} + +void CSceneRenderer::SubmitNonRecursive(CModel* model) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + { + m->shadow.AddShadowReceiverBound(model->GetWorldBounds()); + + if (model->GetFlags() & MODELFLAG_SILHOUETTE_OCCLUDER) + m->silhouetteRenderer.AddOccluder(model); + if (model->GetFlags() & MODELFLAG_SILHOUETTE_DISPLAY) + m->silhouetteRenderer.AddCaster(model); + } + + if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) + { + if (!(model->GetFlags() & MODELFLAG_CASTSHADOWS)) + return; + + const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; + m->shadow.AddShadowCasterBound(cascade, model->GetWorldBounds()); + } + + bool requiresSkinning = (model->GetModelDef()->GetNumBones() != 0); + + if (model->GetMaterial().UsesAlphaBlending()) + { + if (requiresSkinning) + m->Model.TranspSkinned->Submit(m_CurrentCullGroup, model); + else + m->Model.TranspUnskinned->Submit(m_CurrentCullGroup, model); + } + else + { + if (requiresSkinning) + m->Model.NormalSkinned->Submit(m_CurrentCullGroup, model); + else + m->Model.NormalUnskinned->Submit(m_CurrentCullGroup, model); + } +} + +// Render the given scene +void CSceneRenderer::RenderScene( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, Scene& scene) +{ + m_CurrentScene = &scene; + + CFrustum frustum = m_CullCamera.GetFrustum(); + + m_CurrentCullGroup = CULL_DEFAULT; + + scene.EnumerateObjects(frustum, this); + + m->particleManager.RenderSubmit(*this, frustum); + + if (g_RenderingOptions.GetSilhouettes()) + { + m->silhouetteRenderer.ComputeSubmissions(m_ViewCamera); + + m_CurrentCullGroup = CULL_DEFAULT; + m->silhouetteRenderer.RenderSubmitOverlays(*this); + + m_CurrentCullGroup = CULL_SILHOUETTE_OCCLUDER; + m->silhouetteRenderer.RenderSubmitOccluders(*this); + + m_CurrentCullGroup = CULL_SILHOUETTE_CASTER; + m->silhouetteRenderer.RenderSubmitCasters(*this); + } + + if (g_RenderingOptions.GetShadows()) + { + for (int cascade = 0; cascade <= m->shadow.GetCascadeCount(); ++cascade) + { + m_CurrentCullGroup = CULL_SHADOWS_CASCADE_0 + cascade; + const CFrustum shadowFrustum = m->shadow.GetShadowCasterCullFrustum(cascade); + scene.EnumerateObjects(shadowFrustum, this); + } + } + + CBoundingBoxAligned waterScissor; + if (m->waterManager.m_RenderWater) + { + waterScissor = m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); + + if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) + { + if (g_RenderingOptions.GetWaterReflection()) + { + m_CurrentCullGroup = CULL_REFLECTIONS; + + CCamera reflectionCamera; + ComputeReflectionCamera(reflectionCamera, waterScissor); + + scene.EnumerateObjects(reflectionCamera.GetFrustum(), this); + } + + if (g_RenderingOptions.GetWaterRefraction()) + { + m_CurrentCullGroup = CULL_REFRACTIONS; + + CCamera refractionCamera; + ComputeRefractionCamera(refractionCamera, waterScissor); + + scene.EnumerateObjects(refractionCamera.GetFrustum(), this); + } + + // Render the waves to the Fancy effects texture + m->waterManager.RenderWaves(deviceCommandContext, frustum); + } + } + + m_CurrentCullGroup = -1; + + RenderSubmissions(deviceCommandContext, waterScissor); + + m_CurrentScene = NULL; +} + +Scene& CSceneRenderer::GetScene() +{ + ENSURE(m_CurrentScene); + return *m_CurrentScene; +} + +void CSceneRenderer::MakeShadersDirty() +{ + m->waterManager.m_NeedsReloading = true; +} + +WaterManager& CSceneRenderer::GetWaterManager() +{ + return m->waterManager; +} + +SkyManager& CSceneRenderer::GetSkyManager() +{ + return m->skyManager; +} + +CParticleManager& CSceneRenderer::GetParticleManager() +{ + return m->particleManager; +} + +TerrainRenderer& CSceneRenderer::GetTerrainRenderer() +{ + return m->terrainRenderer; +} + +CMaterialManager& CSceneRenderer::GetMaterialManager() +{ + return m->materialManager; +} + +ShadowMap& CSceneRenderer::GetShadowMap() +{ + return m->shadow; +} + +void CSceneRenderer::ResetState() +{ + // Clear all emitters, that were created in previous games + GetParticleManager().ClearUnattachedEmitters(); +} diff -Nru 0ad-0.0.25b/source/renderer/SceneRenderer.h 0ad-0.0.26/source/renderer/SceneRenderer.h --- 0ad-0.0.25b/source/renderer/SceneRenderer.h 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/renderer/SceneRenderer.h 2022-09-23 19:17:05.000000000 +0000 @@ -0,0 +1,284 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_SCENERENDERER +#define INCLUDED_RENDERER_SCENERENDERER + +#include "graphics/Camera.h" +#include "graphics/ShaderDefines.h" +#include "graphics/ShaderProgramPtr.h" +#include "ps/Singleton.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/RenderingOptions.h" +#include "renderer/Scene.h" + +#include + +class CCanvas2D; +class CLightEnv; +class CMaterial; +class CMaterialManager; +class CModel; +class CParticleManager; +class CPatch; +class CSimulation2; +class ShadowMap; +class SkyManager; +class TerrainRenderer; +class WaterManager; + +// rendering modes +enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES }; + +// transparency modes +enum ETransparentMode { TRANSPARENT, TRANSPARENT_OPAQUE, TRANSPARENT_BLEND }; + +class CSceneRenderer : public SceneCollector +{ +public: + enum CullGroup + { + CULL_DEFAULT, + CULL_SHADOWS_CASCADE_0, + CULL_SHADOWS_CASCADE_1, + CULL_SHADOWS_CASCADE_2, + CULL_SHADOWS_CASCADE_3, + CULL_REFLECTIONS, + CULL_REFRACTIONS, + CULL_SILHOUETTE_OCCLUDER, + CULL_SILHOUETTE_CASTER, + CULL_MAX + }; + + CSceneRenderer(); + ~CSceneRenderer(); + + void Initialize(); + void Resize(int width, int height); + + void BeginFrame(); + void EndFrame(); + + /** + * Set simulation context for rendering purposes. + * Must be called at least once when the game has started and before + * frames are rendered. + */ + void SetSimulation(CSimulation2* simulation); + + // trigger a reload of shaders (when parameters they depend on have changed) + void MakeShadersDirty(); + + /** + * Set up the camera used for rendering the next scene; this includes + * setting OpenGL state like viewport, projection and modelview matrices. + * + * @param viewCamera this camera determines the eye position for rendering + * @param cullCamera this camera determines the frustum for culling in the renderer and + * for shadow calculations + */ + void SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera); + + /** + * Render the given scene immediately. + * @param scene a Scene object describing what should be rendered. + */ + void RenderScene(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, Scene& scene); + + /** + * Return the scene that is currently being rendered. + * Only valid when the renderer is in a RenderScene call. + */ + Scene& GetScene(); + + /** + * Render text overlays on top of the scene. + * Assumes the caller has set up the GL environment for orthographic rendering + * with texturing and blending. + */ + void RenderTextOverlays(CCanvas2D& canvas); + + // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, + // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) + void SetLightEnv(CLightEnv* lightenv) + { + m_LightEnv = lightenv; + } + + // set the mode to render subsequent terrain patches + void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode = mode; } + // get the mode to render subsequent terrain patches + ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; } + + // set the mode to render subsequent water patches + void SetWaterRenderMode(ERenderMode mode) { m_WaterRenderMode = mode; } + // get the mode to render subsequent water patches + ERenderMode GetWaterRenderMode() const { return m_WaterRenderMode; } + + // set the mode to render subsequent models + void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode = mode; } + // 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; } + + // return the current light environment + const CLightEnv &GetLightEnv() { return *m_LightEnv; } + + // return the current view camera + const CCamera& GetViewCamera() const { return m_ViewCamera; } + // replace the current view camera + void SetViewCamera(const CCamera& camera) { m_ViewCamera = camera; } + + // return the current cull camera + const CCamera& GetCullCamera() const { return m_CullCamera; } + + /** + * GetWaterManager: Return the renderer's water manager. + * + * @return the WaterManager object used by the renderer + */ + WaterManager& GetWaterManager(); + + /** + * GetSkyManager: Return the renderer's sky manager. + * + * @return the SkyManager object used by the renderer + */ + SkyManager& GetSkyManager(); + + CParticleManager& GetParticleManager(); + + TerrainRenderer& GetTerrainRenderer(); + + CMaterialManager& GetMaterialManager(); + + ShadowMap& GetShadowMap(); + + /** + * Resets the render state to default, that was before a game started + */ + void ResetState(); + + void ReloadShaders(); + +protected: + void Submit(CPatch* patch) override; + void Submit(SOverlayLine* overlay) override; + void Submit(SOverlayTexturedLine* overlay) override; + void Submit(SOverlaySprite* overlay) override; + void Submit(SOverlayQuad* overlay) override; + void Submit(CModelDecal* decal) override; + void Submit(CParticleEmitter* emitter) override; + void Submit(SOverlaySphere* overlay) override; + void SubmitNonRecursive(CModel* model) override; + + // render any batched objects + void RenderSubmissions( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CBoundingBoxAligned& waterScissor); + + // patch rendering stuff + void RenderPatches( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup); + + // model rendering stuff + void RenderModels( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup); + void RenderTransparentModels( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode); + + void RenderSilhouettes( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context); + + void RenderParticles( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup); + + // shadow rendering stuff + void RenderShadowMap( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context); + + // render water reflection and refraction textures + void RenderReflections( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, const CBoundingBoxAligned& scissor); + void RenderRefractions( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, const CBoundingBoxAligned& scissor); + + void ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; + void ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; + + // debugging + void DisplayFrustum(); + + // enable oblique frustum clipping with the given clip plane + void SetObliqueFrustumClipping(CCamera& camera, const CVector4D& clipPlane) const; + + // Private data that is not needed by inline functions. + class Internals; + std::unique_ptr m; + + // Current terrain rendering mode. + ERenderMode m_TerrainRenderMode; + // Current water rendering mode. + ERenderMode m_WaterRenderMode; + // Current model rendering mode. + ERenderMode m_ModelRenderMode; + // Current overlay rendering mode. + ERenderMode m_OverlayRenderMode; + + /** + * m_ViewCamera: determines the eye position for rendering + * + * @see CGameView::m_ViewCamera + */ + CCamera m_ViewCamera; + + /** + * m_CullCamera: determines the frustum for culling and shadowmap calculations + * + * @see CGameView::m_ViewCamera + */ + CCamera m_CullCamera; + + // only valid inside a call to RenderScene + Scene* m_CurrentScene; + int m_CurrentCullGroup; + + // current lighting setup + CLightEnv* m_LightEnv; + + /** + * Enable rendering of terrain tile priority text overlay, for debugging. + */ + bool m_DisplayTerrainPriorities; +}; + +#endif // INCLUDED_RENDERER_SCENERENDERER diff -Nru 0ad-0.0.25b/source/renderer/scripting/JSInterface_Renderer.cpp 0ad-0.0.26/source/renderer/scripting/JSInterface_Renderer.cpp --- 0ad-0.0.25b/source/renderer/scripting/JSInterface_Renderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/scripting/JSInterface_Renderer.cpp 2022-08-21 12:45:26.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -47,6 +47,16 @@ return RenderPathEnum::ToString(g_RenderingOptions.GetRenderPath()); } +std::string GetRenderDebugMode() +{ + return RenderDebugModeEnum::ToString(g_RenderingOptions.GetRenderDebugMode()).c_str(); +} + +void SetRenderDebugMode(const std::string& mode) +{ + g_RenderingOptions.SetRenderDebugMode(RenderDebugModeEnum::FromString(mode)); +} + bool TextureExists(const std::wstring& filename) { return g_Renderer.GetTextureManager().TextureExists(filename); @@ -60,6 +70,8 @@ { ScriptFunction::Register<&GetRenderPath>(rq, "Renderer_GetRenderPath"); ScriptFunction::Register<&TextureExists>(rq, "TextureExists"); + ScriptFunction::Register<&GetRenderDebugMode>(rq, "Renderer_GetRenderDebugMode"); + ScriptFunction::Register<&SetRenderDebugMode>(rq, "Renderer_SetRenderDebugMode"); REGISTER_BOOLEAN_SCRIPT_SETTING(DisplayFrustum); REGISTER_BOOLEAN_SCRIPT_SETTING(DisplayShadowsFrustum); } diff -Nru 0ad-0.0.25b/source/renderer/ShadowMap.cpp 0ad-0.0.26/source/renderer/ShadowMap.cpp --- 0ad-0.0.25b/source/renderer/ShadowMap.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ShadowMap.cpp 2022-09-23 19:16:59.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,7 +24,6 @@ #include "graphics/ShaderManager.h" #include "gui/GUIMatrix.h" #include "lib/bits.h" -#include "lib/ogl.h" #include "maths/BoundingBoxAligned.h" #include "maths/Brush.h" #include "maths/Frustum.h" @@ -34,9 +33,13 @@ #include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" #include "ps/Profile.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" +#include "renderer/backend/ITexture.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include @@ -55,10 +58,8 @@ */ struct ShadowMapInternals { - // the EXT_framebuffer_object framebuffer - GLuint Framebuffer; - // handle of shadow map - GLuint Texture; + std::unique_ptr Framebuffer; + std::unique_ptr Texture; // bit depth for the depth texture int DepthTextureBits; @@ -108,15 +109,12 @@ // incorrectly when the FBO has only a depth attachment. // When m_ShadowAlphaFix is true, we use DummyTexture to store a useless // alpha texture which is attached to the FBO as a workaround. - GLuint DummyTexture; + std::unique_ptr DummyTexture; // Copy of renderer's standard view camera, saved between // BeginRender and EndRender while we replace it with the shadow camera CCamera SavedViewCamera; - // Save the caller's FBO so it can be restored - GLint SavedViewFBO; - void CalculateShadowMatrices(const int cascade); void CreateTexture(); void UpdateCascadesParameters(); @@ -127,7 +125,7 @@ CascadeCount = 1; CFG_GET_VAL("shadowscascadecount", CascadeCount); - if (CascadeCount < 1 || CascadeCount > MAX_CASCADE_COUNT || !g_RenderingOptions.GetPreferGLSL()) + if (CascadeCount < 1 || CascadeCount > MAX_CASCADE_COUNT || g_VideoMode.GetBackend() == CVideoMode::Backend::GL_ARB) CascadeCount = 1; ShadowsCoverMap = false; @@ -190,8 +188,6 @@ { m = new ShadowMapInternals; m->Framebuffer = 0; - m->Texture = 0; - m->DummyTexture = 0; m->Width = 0; m->Height = 0; m->QualityLevel = 0; @@ -212,12 +208,9 @@ ShadowMap::~ShadowMap() { - if (m->Texture) - glDeleteTextures(1, &m->Texture); - if (m->DummyTexture) - glDeleteTextures(1, &m->DummyTexture); - if (m->Framebuffer) - pglDeleteFramebuffersEXT(1, &m->Framebuffer); + m->Framebuffer.reset(); + m->Texture.reset(); + m->DummyTexture.reset(); delete m; } @@ -226,16 +219,9 @@ // size has changed void ShadowMap::RecreateTexture() { - if (m->Texture) - glDeleteTextures(1, &m->Texture); - if (m->DummyTexture) - glDeleteTextures(1, &m->DummyTexture); - if (m->Framebuffer) - pglDeleteFramebuffersEXT(1, &m->Framebuffer); - - m->Texture = 0; - m->DummyTexture = 0; - m->Framebuffer = 0; + m->Framebuffer.reset(); + m->Texture.reset(); + m->DummyTexture.reset(); m->UpdateCascadesParameters(); @@ -482,26 +468,11 @@ void ShadowMapInternals::CreateTexture() { // Cleanup - if (Texture) - { - glDeleteTextures(1, &Texture); - Texture = 0; - } - if (DummyTexture) - { - glDeleteTextures(1, &DummyTexture); - DummyTexture = 0; - } - if (Framebuffer) - { - pglDeleteFramebuffersEXT(1, &Framebuffer); - Framebuffer = 0; - } + Framebuffer.reset(); + Texture.reset(); + DummyTexture.reset(); - // save the caller's FBO - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &SavedViewFBO); - - pglGenFramebuffersEXT(1, &Framebuffer); + Renderer::Backend::IDevice* backendDevice = g_VideoMode.GetBackendDevice(); CFG_GET_VAL("shadowquality", QualityLevel); @@ -519,7 +490,7 @@ break; // Ultra case 2: - shadowMapSize = std::max(round_up_to_pow2(std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight())) * 4, 4096); + shadowMapSize = std::max(round_up_to_pow2(std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight())), 4096); break; // Medium as is default: @@ -528,7 +499,8 @@ } // Clamp to the maximum texture size. - shadowMapSize = std::min(shadowMapSize, static_cast(ogl_max_tex_size)); + shadowMapSize = std::min( + shadowMapSize, static_cast(backendDevice->GetCapabilities().maxTextureSize)); Width = Height = shadowMapSize; @@ -536,18 +508,18 @@ EffectiveWidth = Width; EffectiveHeight = Height; - GLenum format; const char* formatName; + Renderer::Backend::Format backendFormat = Renderer::Backend::Format::UNDEFINED; #if CONFIG2_GLES - format = GL_DEPTH_COMPONENT; formatName = "DEPTH_COMPONENT"; + backendFormat = Renderer::Backend::Format::D24; #else switch (DepthTextureBits) { - case 16: format = GL_DEPTH_COMPONENT16; formatName = "DEPTH_COMPONENT16"; break; - case 24: format = GL_DEPTH_COMPONENT24; formatName = "DEPTH_COMPONENT24"; break; - case 32: format = GL_DEPTH_COMPONENT32; formatName = "DEPTH_COMPONENT32"; break; - default: format = GL_DEPTH_COMPONENT; formatName = "DEPTH_COMPONENT"; break; + case 16: formatName = "Format::D16"; backendFormat = Renderer::Backend::Format::D16; break; + case 24: formatName = "Format::D24"; backendFormat = Renderer::Backend::Format::D24; break; + case 32: formatName = "Format::D32"; backendFormat = Renderer::Backend::Format::D32; break; + default: formatName = "Format::D24"; backendFormat = Renderer::Backend::Format::D24; break; } #endif ENSURE(formatName); @@ -557,77 +529,39 @@ if (g_RenderingOptions.GetShadowAlphaFix()) { - glGenTextures(1, &DummyTexture); - g_Renderer.BindTexture(0, DummyTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - - glGenTextures(1, &Texture); - g_Renderer.BindTexture(0, Texture); - - glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); - // GLES requires type == UNSIGNED_SHORT or UNSIGNED_INT - - // set texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - -#if CONFIG2_GLES - // GLES doesn't do depth comparisons, so treat it as a - // basic unfiltered depth texture - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -#else - // Enable automatic depth comparisons - glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - - // Use GL_LINEAR to trigger automatic PCF on some devices - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#endif - - ogl_WarnIfError(); - - // bind to framebuffer object - glBindTexture(GL_TEXTURE_2D, 0); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer); - - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Texture, 0); - - if (g_RenderingOptions.GetShadowAlphaFix()) - { - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, DummyTexture, 0); + DummyTexture = backendDevice->CreateTexture2D("ShadowMapDummy", + Renderer::Backend::Format::R8G8B8A8_UNORM, Width, Height, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::NEAREST, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); } - else - { + + Renderer::Backend::Sampler::Desc samplerDesc = + Renderer::Backend::Sampler::MakeDefaultSampler( #if CONFIG2_GLES -#warning TODO: figure out whether the glDrawBuffer/glReadBuffer stuff is needed, since it is not supported by GLES + // GLES doesn't do depth comparisons, so treat it as a + // basic unfiltered depth texture + Renderer::Backend::Sampler::Filter::NEAREST, #else - glDrawBuffer(GL_NONE); + // Use LINEAR to trigger automatic PCF on some devices. + Renderer::Backend::Sampler::Filter::LINEAR, #endif - } - -#if !CONFIG2_GLES - glReadBuffer(GL_NONE); -#endif - - ogl_WarnIfError(); + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + // Enable automatic depth comparisons + samplerDesc.compareEnabled = true; + samplerDesc.compareOp = Renderer::Backend::CompareOp::LESS_OR_EQUAL; - GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + Texture = backendDevice->CreateTexture2D("ShadowMapDepth", + backendFormat, Width, Height, samplerDesc); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, SavedViewFBO); + Framebuffer = backendDevice->CreateFramebuffer("ShadowMapFramebuffer", + g_RenderingOptions.GetShadowAlphaFix() ? DummyTexture.get() : nullptr, Texture.get()); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (!Framebuffer) { - LOGWARNING("Framebuffer object incomplete: 0x%04X", status); + LOGERROR("Failed to create shadows framebuffer"); - // Disable shadow rendering (but let the user try again if they want) + // Disable shadow rendering (but let the user try again if they want). g_RenderingOptions.SetShadows(false); } } @@ -635,10 +569,15 @@ // Set up to render into shadow map texture void ShadowMap::BeginRender() { + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + { PROFILE("bind framebuffer"); - glBindTexture(GL_TEXTURE_2D, 0); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m->Framebuffer); + ENSURE(m->Framebuffer); + deviceCommandContext->SetFramebuffer(m->Framebuffer.get()); } // clear buffers @@ -647,18 +586,10 @@ // In case we used m_ShadowAlphaFix, we ought to clear the unused // color buffer too, else Mali 400 drivers get confused. // Might as well clear stencil too for completeness. - if (g_RenderingOptions.GetShadowAlphaFix()) - { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - glColorMask(0, 0, 0, 0); - } - else - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + deviceCommandContext->ClearFramebuffer(); } - m->SavedViewCamera = g_Renderer.GetViewCamera(); - - glEnable(GL_SCISSOR_TEST); + m->SavedViewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); } void ShadowMap::PrepareCamera(const int cascade) @@ -671,47 +602,57 @@ CCamera camera = m->SavedViewCamera; camera.SetProjection(m->Cascades[cascade].LightProjection); camera.GetOrientation() = m->InvLightTransform; - g_Renderer.SetViewCamera(camera); + g_Renderer.GetSceneRenderer().SetViewCamera(camera); const SViewPort& cascadeViewPort = m->Cascades[cascade].ViewPort; - glScissor( - cascadeViewPort.m_X, cascadeViewPort.m_Y, - cascadeViewPort.m_Width, cascadeViewPort.m_Height); + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = cascadeViewPort.m_X; + scissorRect.y = cascadeViewPort.m_Y; + scissorRect.width = cascadeViewPort.m_Width; + scissorRect.height = cascadeViewPort.m_Height; + g_Renderer.GetDeviceCommandContext()->SetScissors(1, &scissorRect); } // Finish rendering into shadow map texture void ShadowMap::EndRender() { - glDisable(GL_SCISSOR_TEST); + g_Renderer.GetDeviceCommandContext()->SetScissors(0, nullptr); - g_Renderer.SetViewCamera(m->SavedViewCamera); + g_Renderer.GetSceneRenderer().SetViewCamera(m->SavedViewCamera); { PROFILE("unbind framebuffer"); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + g_Renderer.GetDeviceCommandContext()->SetFramebuffer( + g_VideoMode.GetBackendDevice()->GetCurrentBackbuffer()); } const SViewPort vp = { 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight() }; g_Renderer.SetViewport(vp); - - if (g_RenderingOptions.GetShadowAlphaFix()) - glColorMask(1, 1, 1, 1); } -void ShadowMap::BindTo(const CShaderProgramPtr& shader) const +void ShadowMap::BindTo( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const { - if (!shader->GetTextureBinding(str_shadowTex).Active()) + const int32_t shadowTexBindingSlot = shader->GetBindingSlot(str_shadowTex); + if (shadowTexBindingSlot < 0 || !m->Texture) return; - shader->BindTexture(str_shadowTex, m->Texture); - shader->Uniform(str_shadowScale, m->Width, m->Height, 1.0f / m->Width, 1.0f / m->Height); - const CVector3D cameraForward = g_Renderer.GetCullCamera().GetOrientation().GetIn(); - shader->Uniform(str_cameraForward, cameraForward.X, cameraForward.Y, cameraForward.Z, - cameraForward.Dot(g_Renderer.GetCullCamera().GetOrientation().GetTranslation())); + deviceCommandContext->SetTexture(shadowTexBindingSlot, m->Texture.get()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowScale), m->Width, m->Height, 1.0f / m->Width, 1.0f / m->Height); + const CVector3D cameraForward = g_Renderer.GetSceneRenderer().GetCullCamera().GetOrientation().GetIn(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_cameraForward), cameraForward.X, cameraForward.Y, cameraForward.Z, + cameraForward.Dot(g_Renderer.GetSceneRenderer().GetCullCamera().GetOrientation().GetTranslation())); + if (GetCascadeCount() == 1) { - shader->Uniform(str_shadowTransform, m->Cascades[0].TextureMatrix); - shader->Uniform(str_shadowDistance, m->Cascades[0].Distance); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowTransform), + m->Cascades[0].TextureMatrix.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowDistance), m->Cascades[0].Distance); } else { @@ -722,10 +663,14 @@ shadowDistances.emplace_back(cascade.Distance); shadowTransforms.emplace_back(cascade.TextureMatrix); } - shader->Uniform(str_shadowTransforms_0, GetCascadeCount(), shadowTransforms.data()); - shader->Uniform(str_shadowTransforms, GetCascadeCount(), shadowTransforms.data()); - shader->Uniform(str_shadowDistances_0, GetCascadeCount(), shadowDistances.data()); - shader->Uniform(str_shadowDistances, GetCascadeCount(), shadowDistances.data()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowTransform), + PS::span( + shadowTransforms[0]._data, + shadowTransforms[0].AsFloatArray().size() * GetCascadeCount())); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowDistance), + PS::span(shadowDistances.data(), shadowDistances.size())); } } @@ -739,11 +684,7 @@ { if (bits != m->DepthTextureBits) { - if (m->Texture) - { - glDeleteTextures(1, &m->Texture); - m->Texture = 0; - } + m->Texture.reset(); m->Width = m->Height = 0; m->DepthTextureBits = bits; @@ -752,26 +693,22 @@ void ShadowMap::RenderDebugBounds() { - glDepthMask(0); - glDisable(GL_CULL_FACE); - // Render various shadow bounds: // Yellow = bounds of objects in view frustum that receive shadows // Red = culling frustum used to find potential shadow casters // Blue = frustum used for rendering the shadow map - const CMatrix3D transform = g_Renderer.GetViewCamera().GetViewProjection() * m->InvLightTransform; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection() * m->InvLightTransform; - g_Renderer.GetDebugRenderer().DrawBoundingBoxOutline(m->ShadowReceiverBound, CColor(1.0f, 1.0f, 0.0f, 1.0f), transform); + g_Renderer.GetDebugRenderer().DrawBoundingBox( + m->ShadowReceiverBound, CColor(1.0f, 1.0f, 0.0f, 1.0f), transform, true); for (int cascade = 0; cascade < GetCascadeCount(); ++cascade) { - glEnable(GL_BLEND); - g_Renderer.GetDebugRenderer().DrawBoundingBox(m->Cascades[cascade].ShadowRenderBound, CColor(0.0f, 0.0f, 1.0f, 0.10f), transform); - g_Renderer.GetDebugRenderer().DrawBoundingBoxOutline(m->Cascades[cascade].ShadowRenderBound, CColor(0.0f, 0.0f, 1.0f, 0.5f), transform); - glDisable(GL_BLEND); + g_Renderer.GetDebugRenderer().DrawBoundingBox( + m->Cascades[cascade].ShadowRenderBound, CColor(0.0f, 0.0f, 1.0f, 0.10f), transform); + g_Renderer.GetDebugRenderer().DrawBoundingBox( + m->Cascades[cascade].ShadowRenderBound, CColor(0.0f, 0.0f, 1.0f, 0.5f), transform, true); const CFrustum frustum = GetShadowCasterCullFrustum(cascade); // We don't have a function to create a brush directly from a frustum, so use @@ -781,65 +718,9 @@ CBrush frustumBrush; brush.Intersect(frustum, frustumBrush); - glEnable(GL_BLEND); g_Renderer.GetDebugRenderer().DrawBrush(frustumBrush, CColor(1.0f, 0.0f, 0.0f, 0.1f)); - g_Renderer.GetDebugRenderer().DrawBrushOutline(frustumBrush, CColor(1.0f, 0.0f, 0.0f, 0.5f)); - glDisable(GL_BLEND); + g_Renderer.GetDebugRenderer().DrawBrush(frustumBrush, CColor(1.0f, 0.0f, 0.0f, 0.1f), true); } - - glEnable(GL_CULL_FACE); - glDepthMask(1); - - ogl_WarnIfError(); -} - -void ShadowMap::RenderDebugTexture() -{ - glDepthMask(0); - - glDisable(GL_DEPTH_TEST); - -#if !CONFIG2_GLES - g_Renderer.BindTexture(0, m->Texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); -#endif - - CShaderTechniquePtr texTech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d); - texTech->BeginPass(); - CShaderProgramPtr texShader = texTech->GetShader(); - - texShader->Uniform(str_transform, GetDefaultGuiMatrix()); - texShader->BindTexture(str_tex, m->Texture); - texShader->Uniform(str_colorAdd, CColor(0.0f, 0.0f, 0.0f, 1.0f)); - texShader->Uniform(str_colorMul, CColor(1.0f, 1.0f, 1.0f, 0.0f)); - texShader->Uniform(str_grayscaleFactor, 0.0f); - - float s = 256.f; - float boxVerts[] = { - 0,0, 0,s, s,0, - s,0, 0,s, s,s - }; - float boxUV[] = { - 0,0, 0,1, 1,0, - 1,0, 0,1, 1,1 - }; - - texShader->VertexPointer(2, GL_FLOAT, 0, boxVerts); - texShader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, boxUV); - texShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); - - texTech->EndPass(); - -#if !CONFIG2_GLES - g_Renderer.BindTexture(0, m->Texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); -#endif - - glEnable(GL_DEPTH_TEST); - glDepthMask(1); - - ogl_WarnIfError(); } int ShadowMap::GetCascadeCount() const diff -Nru 0ad-0.0.25b/source/renderer/ShadowMap.h 0ad-0.0.26/source/renderer/ShadowMap.h --- 0ad-0.0.25b/source/renderer/ShadowMap.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/ShadowMap.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,13 +18,12 @@ #ifndef INCLUDED_SHADOWMAP #define INCLUDED_SHADOWMAP -#include "graphics/ShaderProgramPtr.h" -#include "lib/ogl.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" class CBoundingBoxAligned; class CCamera; class CFrustum; -class CMatrix3D; class CVector3D; struct ShadowMapInternals; @@ -127,7 +126,9 @@ /** * Binds all needed resources and uniforms to draw shadows using the shader. */ - void BindTo(const CShaderProgramPtr& shader) const; + void BindTo( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const; /** * Visualize shadow mapping calculations to help in @@ -135,11 +136,6 @@ */ void RenderDebugBounds(); - /** - * Visualize shadow map texture to help in debugging. - */ - void RenderDebugTexture(); - private: ShadowMapInternals* m; }; diff -Nru 0ad-0.0.25b/source/renderer/SilhouetteRenderer.cpp 0ad-0.0.26/source/renderer/SilhouetteRenderer.cpp --- 0ad-0.0.25b/source/renderer/SilhouetteRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/SilhouetteRenderer.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -443,17 +443,23 @@ collector.SubmitNonRecursive(m_VisibleModelCasters[i]); } -void SilhouetteRenderer::RenderDebugOverlays(const CCamera& UNUSED(camera)) +void SilhouetteRenderer::RenderDebugBounds( + Renderer::Backend::IDeviceCommandContext* UNUSED(deviceCommandContext)) { - if (m_DebugBounds.empty() && m_DebugRects.empty()) + if (m_DebugBounds.empty()) return; - glDepthMask(0); - glDisable(GL_CULL_FACE); - for (size_t i = 0; i < m_DebugBounds.size(); ++i) - g_Renderer.GetDebugRenderer().DrawBoundingBoxOutline(m_DebugBounds[i].bounds, m_DebugBounds[i].color); + g_Renderer.GetDebugRenderer().DrawBoundingBox(m_DebugBounds[i].bounds, m_DebugBounds[i].color, true); +} + +void SilhouetteRenderer::RenderDebugOverlays( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + if (m_DebugRects.empty()) + return; + // TODO: use CCanvas2D for drawing rects. CMatrix3D m; m.SetIdentity(); m.Scale(1.0f, -1.f, 1.0f); @@ -463,32 +469,45 @@ proj.SetOrtho(0.f, g_MaxCoord, 0.f, g_MaxCoord, -1.f, 1000.f); m = proj * m; - CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + shaderTech->GetGraphicsPipelineStateDesc(); + deviceCommandContext->BeginPass(); + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), proj.AsFloatArray()); - CShaderProgramPtr shader = shaderTech->GetShader(); - shader->Uniform(str_transform, proj); - - for (size_t i = 0; i < m_DebugRects.size(); ++i) + const int32_t colorBindingSlot = shader->GetBindingSlot(str_color); + for (const DebugRect& r : m_DebugRects) { - const DebugRect& r = m_DebugRects[i]; - shader->Uniform(str_color, r.color); - u16 verts[] = { + deviceCommandContext->SetUniform( + colorBindingSlot, r.color.AsFloatArray()); + u16 verts[] = + { r.x0, r.y0, r.x1, r.y0, r.x1, r.y1, - r.x0, r.y1, r.x0, r.y0, + r.x1, r.y1, + r.x0, r.y1, }; - shader->VertexPointer(2, GL_SHORT, 0, verts); - glDrawArrays(GL_LINE_STRIP, 0, 5); - } - shaderTech->EndPass(); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R16G16_SINT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBufferData( + 0, verts, std::size(verts) * sizeof(verts[0])); + + deviceCommandContext->Draw(0, 6); + } - glEnable(GL_CULL_FACE); - glDepthMask(1); + deviceCommandContext->EndPass(); } void SilhouetteRenderer::EndFrame() diff -Nru 0ad-0.0.25b/source/renderer/SilhouetteRenderer.h 0ad-0.0.26/source/renderer/SilhouetteRenderer.h --- 0ad-0.0.25b/source/renderer/SilhouetteRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/SilhouetteRenderer.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "graphics/Overlay.h" #include "maths/BoundingBoxAligned.h" +#include "renderer/backend/IDeviceCommandContext.h" class CCamera; class CModel; @@ -40,7 +41,10 @@ void RenderSubmitOccluders(SceneCollector& collector); void RenderSubmitCasters(SceneCollector& collector); - void RenderDebugOverlays(const CCamera& camera); + void RenderDebugBounds( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + void RenderDebugOverlays( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); void EndFrame(); diff -Nru 0ad-0.0.25b/source/renderer/SkyManager.cpp 0ad-0.0.26/source/renderer/SkyManager.cpp --- 0ad-0.0.25b/source/renderer/SkyManager.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/SkyManager.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,10 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * Sky settings, texture management and rendering. - */ - #include "precompiled.h" #include "renderer/SkyManager.h" @@ -27,9 +23,8 @@ #include "graphics/ShaderManager.h" #include "graphics/Terrain.h" #include "graphics/TextureManager.h" +#include "lib/bits.h" #include "lib/tex/tex.h" -#include "lib/timer.h" -#include "lib/res/graphics/ogl_tex.h" #include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" @@ -37,31 +32,38 @@ #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/Game.h" -#include "ps/Loader.h" -#include "ps/World.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/RenderingOptions.h" #include SkyManager::SkyManager() - : m_RenderSky(true), m_SkyCubeMap(0) + : m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX, false) { - CFG_GET_VAL("showsky", m_RenderSky); + CFG_GET_VAL("showsky", m_SkyVisible); } -/////////////////////////////////////////////////////////////////// -// Load all sky textures -void SkyManager::LoadSkyTextures() +void SkyManager::LoadAndUploadSkyTexturesIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { + if (m_SkyTextureCube) + return; + + m_SkyTextureCube = g_Renderer.GetTextureManager().GetBlackTextureCube(); + + GPU_SCOPED_LABEL(deviceCommandContext, "Load Sky Textures"); static const CStrW images[NUMBER_OF_TEXTURES + 1] = { L"front", L"back", - L"right", - L"left", L"top", - L"top" + L"top", + L"right", + L"left" }; + /*for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i) { VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds"); @@ -77,101 +79,108 @@ // HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely // as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs. - glGenTextures(1, &m_SkyCubeMap); - glBindTexture(GL_TEXTURE_CUBE_MAP, m_SkyCubeMap); - - static const int types[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - }; + Tex textures[NUMBER_OF_TEXTURES + 1]; for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i) { - VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds"); + VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i]) + L".dds"); std::shared_ptr file; size_t fileSize; if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK) { - path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds.cached.dds"); + path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i]) + L".dds.cached.dds"); if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK) { - glDeleteTextures(1, &m_SkyCubeMap); - LOGERROR("Error creating sky cubemap."); + LOGERROR("Error creating sky cubemap '%s', can't load file: '%s'.", m_SkySet.ToUTF8().c_str(), path.string8().c_str()); return; } } - Tex tex; - tex.decode(file, fileSize); + if (textures[i].decode(file, fileSize) != INFO::OK || + textures[i].transform_to((textures[i].m_Flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) != INFO::OK) + { + LOGERROR("Error creating sky cubemap '%s', can't decode file: '%s'.", m_SkySet.ToUTF8().c_str(), path.string8().c_str()); + return; + } - tex.transform_to((tex.m_Flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)); + if (!is_pow2(textures[i].m_Width) || !is_pow2(textures[i].m_Height)) + { + LOGERROR("Error creating sky cubemap '%s', cube textures should have power of 2 sizes.", m_SkySet.ToUTF8().c_str()); + return; + } - u8* data = tex.get_data(); + if (textures[i].m_Width != textures[0].m_Width || textures[i].m_Height != textures[0].m_Height) + { + LOGERROR("Error creating sky cubemap '%s', cube textures have different sizes.", m_SkySet.ToUTF8().c_str()); + return; + } + } + + std::unique_ptr skyCubeMap = + g_VideoMode.GetBackendDevice()->CreateTexture("SkyCubeMap", + Renderer::Backend::ITexture::Type::TEXTURE_CUBE, + Renderer::Backend::Format::R8G8B8A8_UNORM, textures[0].m_Width, textures[0].m_Height, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1); + + std::vector rotated; + for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i) + { + u8* data = textures[i].get_data(); - if (types[i] == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || types[i] == GL_TEXTURE_CUBE_MAP_POSITIVE_Y) + // We need to rotate the side if it's looking up or down. + // TODO: maybe it should be done during texture conversion. + if (i == 2 || i == 3) { - std::vector rotated(tex.m_DataSize); + rotated.resize(textures[i].m_DataSize); - for (size_t y = 0; y < tex.m_Height; ++y) + for (size_t y = 0; y < textures[i].m_Height; ++y) { - for (size_t x = 0; x < tex.m_Width; ++x) + for (size_t x = 0; x < textures[i].m_Width; ++x) { - size_t invx = y, invy = tex.m_Width-x-1; + const size_t invX = y; + const size_t invY = textures[i].m_Width - x - 1; - rotated[(y*tex.m_Width + x) * 4 + 0] = data[(invy*tex.m_Width + invx) * 4 + 0]; - rotated[(y*tex.m_Width + x) * 4 + 1] = data[(invy*tex.m_Width + invx) * 4 + 1]; - rotated[(y*tex.m_Width + x) * 4 + 2] = data[(invy*tex.m_Width + invx) * 4 + 2]; - rotated[(y*tex.m_Width + x) * 4 + 3] = data[(invy*tex.m_Width + invx) * 4 + 3]; + rotated[(y * textures[i].m_Width + x) * 4 + 0] = data[(invY * textures[i].m_Width + invX) * 4 + 0]; + rotated[(y * textures[i].m_Width + x) * 4 + 1] = data[(invY * textures[i].m_Width + invX) * 4 + 1]; + rotated[(y * textures[i].m_Width + x) * 4 + 2] = data[(invY * textures[i].m_Width + invX) * 4 + 2]; + rotated[(y * textures[i].m_Width + x) * 4 + 3] = data[(invY * textures[i].m_Width + invX) * 4 + 3]; } } - glTexImage2D(types[i], 0, GL_RGBA, tex.m_Width, tex.m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rotated[0]); + deviceCommandContext->UploadTexture( + skyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + &rotated[0], textures[i].m_DataSize, 0, i); } else { - glTexImage2D(types[i], 0, GL_RGBA, tex.m_Width, tex.m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + deviceCommandContext->UploadTexture( + skyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + data, textures[i].m_DataSize, 0, i); } } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -#if CONFIG2_GLES -#warning TODO: fix SkyManager::LoadSkyTextures for GLES -#else - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); -#endif - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + m_SkyTextureCube = g_Renderer.GetTextureManager().WrapBackendTexture(std::move(skyCubeMap)); /////////////////////////////////////////////////////////////////////////// } +Renderer::Backend::ITexture* SkyManager::GetSkyCube() +{ + return m_SkyTextureCube->GetBackendTexture(); +} -/////////////////////////////////////////////////////////////////// -// Switch to a different sky set (while the game is running) void SkyManager::SetSkySet(const CStrW& newSet) { if (newSet == m_SkySet) return; - if (m_SkyCubeMap) - { - glDeleteTextures(1, &m_SkyCubeMap); - m_SkyCubeMap = 0; - } + m_SkyTextureCube.reset(); m_SkySet = newSet; - - LoadSkyTextures(); } -/////////////////////////////////////////////////////////////////// -// Generate list of available skies std::vector SkyManager::GetSkySets() const { std::vector skies; @@ -193,33 +202,31 @@ return skies; } -/////////////////////////////////////////////////////////////////// -// Render sky -void SkyManager::RenderSky() +void SkyManager::RenderSky( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { -#if CONFIG2_GLES -#warning TODO: implement SkyManager::RenderSky for GLES -#else - if (!m_RenderSky) - return; + GPU_SCOPED_LABEL(deviceCommandContext, "Render sky"); - // Draw the sky as a small box around the map, with depth write enabled. - // This will be done before anything else is drawn so we'll be overlapped by - // everything else. + if (!m_SkyVisible) + return; // Do nothing unless SetSkySet was called - if (m_SkySet.empty()) + if (m_SkySet.empty() || !m_SkyTextureCube) return; - glDepthMask(GL_FALSE); + if (m_VertexArray.GetNumberOfVertices() == 0) + CreateSkyCube(); - const CCamera& camera = g_Renderer.GetViewCamera(); + const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); CShaderTechniquePtr skytech = g_Renderer.GetShaderManager().LoadEffect(str_sky_simple); - skytech->BeginPass(); - CShaderProgramPtr shader = skytech->GetShader(); - shader->BindTexture(str_baseTex, m_SkyCubeMap); + deviceCommandContext->SetGraphicsPipelineState( + skytech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = skytech->GetShader(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), m_SkyTextureCube->GetBackendTexture()); // Translate so the sky center is at the camera space origin. CMatrix3D translate; @@ -233,71 +240,109 @@ // each skymap, is in the direction of the sun from our light // environment. CMatrix3D rotate; - rotate.SetYRotation(M_PI + g_Renderer.GetLightEnv().GetRotation()); + rotate.SetYRotation(M_PI + g_Renderer.GetSceneRenderer().GetLightEnv().GetRotation()); - shader->Uniform( - str_transform, - camera.GetViewProjection() * translate * rotate * scale); - - std::vector vertexData; - // 6 sides of cube with 4 vertices with 6 floats (3 uv and 3 position). - vertexData.reserve(6 * 4 * 6); -#define ADD_VERTEX(U, V, W, X, Y, Z) \ + const CMatrix3D transform = camera.GetViewProjection() * translate * rotate * scale; + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + + m_VertexArray.PrepareForRendering(); + m_VertexArray.UploadIfNeeded(deviceCommandContext); + + const uint32_t stride = m_VertexArray.GetStride(); + const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, m_AttributePosition.format, + firstVertexOffset + m_AttributePosition.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, m_AttributeUV.format, + firstVertexOffset + m_AttributeUV.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); + + deviceCommandContext->Draw(0, m_VertexArray.GetNumberOfVertices()); + + deviceCommandContext->EndPass(); +} + +void SkyManager::CreateSkyCube() +{ + m_AttributePosition.format = Renderer::Backend::Format::R32G32B32_SFLOAT; + m_VertexArray.AddAttribute(&m_AttributePosition); + + m_AttributeUV.format = Renderer::Backend::Format::R32G32B32_SFLOAT; + m_VertexArray.AddAttribute(&m_AttributeUV); + + // 6 sides of cube with 6 vertices. + m_VertexArray.SetNumberOfVertices(6 * 6); + m_VertexArray.Layout(); + + VertexArrayIterator attrPosition = m_AttributePosition.GetIterator(); + VertexArrayIterator attrUV = m_AttributeUV.GetIterator(); + +#define ADD_VERTEX(U, V, W, VX, VY, VZ) \ STMT( \ - vertexData.push_back(X); \ - vertexData.push_back(Y); \ - vertexData.push_back(Z); \ - vertexData.push_back(U); \ - vertexData.push_back(V); \ - vertexData.push_back(W);) + attrPosition->X = VX; \ + attrPosition->Y = VY; \ + attrPosition->Z = VZ; \ + ++attrPosition; \ + attrUV->X = U; \ + attrUV->Y = V; \ + attrUV->Z = W; \ + ++attrUV;) - // GL_TEXTURE_CUBE_MAP_NEGATIVE_X + // Axis -X ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f); ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f); ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f); + ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f); + ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f); ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f); - // GL_TEXTURE_CUBE_MAP_POSITIVE_X + // Axis +X ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f); ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f); ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f); + ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f); + ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f); ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f); - // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y + // Axis -Y ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f); ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f); ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f); + ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f); + ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f); ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f); - // GL_TEXTURE_CUBE_MAP_POSITIVE_Y + // Axis +Y ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f); ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f); ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f); + ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f); + ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f); ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f); - // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + // Axis -Z ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f); ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f); ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f); + ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f); + ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f); ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f); - // GL_TEXTURE_CUBE_MAP_POSITIVE_Z + // Axis +Z ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f); ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f); ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f); + ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f); + ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f); ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f); #undef ADD_VERTEX - shader->VertexPointer(3, GL_FLOAT, sizeof(GLfloat) * 6, &vertexData[0]); - shader->TexCoordPointer( - GL_TEXTURE0, 3, GL_FLOAT, sizeof(GLfloat) * 6, &vertexData[3]); - shader->AssertPointersBound(); - - glDrawArrays(GL_QUADS, 0, 6 * 4); - - skytech->EndPass(); - - glDepthMask(GL_TRUE); - -#endif + m_VertexArray.Upload(); + m_VertexArray.FreeBackingStore(); } diff -Nru 0ad-0.0.25b/source/renderer/SkyManager.h 0ad-0.0.26/source/renderer/SkyManager.h --- 0ad-0.0.25b/source/renderer/SkyManager.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/SkyManager.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,7 +23,11 @@ #define INCLUDED_SKYMANAGER #include "graphics/Texture.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/ITexture.h" +#include "renderer/VertexArray.h" +#include #include /** @@ -37,7 +41,8 @@ /** * Render the sky. */ - void RenderSky(); + void RenderSky( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Return the currently selected sky set name. @@ -47,13 +52,10 @@ return m_SkySet; } - GLuint GetSkyCube() - { - return m_SkyCubeMap; - } + Renderer::Backend::ITexture* GetSkyCube(); /** - * Set the sky set name, potentially loading the textures. + * Set the sky set name. */ void SetSkySet(const CStrW& name); @@ -63,20 +65,26 @@ */ std::vector GetSkySets() const; - bool GetRenderSky() const + bool IsSkyVisible() const { - return m_RenderSky; + return m_SkyVisible; } - void SetRenderSky(bool value) + void SetSkyVisible(bool value) { - m_RenderSky = value; + m_SkyVisible = value; } + /** + * Load all sky textures from files and upload to GPU. + */ + void LoadAndUploadSkyTexturesIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + private: - void LoadSkyTextures(); + void CreateSkyCube(); - bool m_RenderSky; + bool m_SkyVisible = true; /// Name of current skyset (a directory within art/textures/skies) CStrW m_SkySet; @@ -94,8 +102,11 @@ // Sky textures CTexturePtr m_SkyTexture[NUMBER_OF_TEXTURES]; + CTexturePtr m_SkyTextureCube; - GLuint m_SkyCubeMap; + VertexArray m_VertexArray; + VertexArray::Attribute m_AttributePosition; + VertexArray::Attribute m_AttributeUV; }; diff -Nru 0ad-0.0.25b/source/renderer/TerrainOverlay.cpp 0ad-0.0.26/source/renderer/TerrainOverlay.cpp --- 0ad-0.0.25b/source/renderer/TerrainOverlay.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/TerrainOverlay.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,13 +24,15 @@ #include "graphics/ShaderProgram.h" #include "graphics/Terrain.h" #include "lib/bits.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "ps/CStrInternStatic.h" #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" +#include "renderer/backend/IDevice.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TerrainRenderer.h" #include "simulation2/system/SimContext.h" @@ -62,26 +64,30 @@ } -void ITerrainOverlay::RenderOverlaysBeforeWater() +void ITerrainOverlay::RenderOverlaysBeforeWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { if (g_TerrainOverlayList.empty()) return; PROFILE3_GPU("terrain overlays (before)"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain overlays before water"); for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i) - g_TerrainOverlayList[i].first->RenderBeforeWater(); + g_TerrainOverlayList[i].first->RenderBeforeWater(deviceCommandContext); } -void ITerrainOverlay::RenderOverlaysAfterWater(int cullGroup) +void ITerrainOverlay::RenderOverlaysAfterWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { if (g_TerrainOverlayList.empty()) return; PROFILE3_GPU("terrain overlays (after)"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain overlays after water"); for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i) - g_TerrainOverlayList[i].first->RenderAfterWater(cullGroup); + g_TerrainOverlayList[i].first->RenderAfterWater(deviceCommandContext, cullGroup); } ////////////////////////////////////////////////////////////////////////// @@ -108,28 +114,12 @@ max_i_inclusive = max_j_inclusive = m_Terrain->GetTilesPerSide()-1; } -void TerrainOverlay::RenderBeforeWater() +void TerrainOverlay::RenderBeforeWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { if (!m_Terrain) return; // should never happen, but let's play it safe -#if CONFIG2_GLES -#warning TODO: implement TerrainOverlay::RenderOverlays for GLES -#else - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(GL_FALSE); - // To ensure that outlines are drawn on top of the terrain correctly (and - // don't Z-fight and flicker nastily), draw them as QUADS with the LINE - // PolygonMode, and use PolygonOffset to pull them towards the camera. - // (See e.g. http://www.opengl.org/resources/faq/technical/polygonoffset.htm) - glPolygonOffset(-1.f, -1.f); - //glEnable(GL_POLYGON_OFFSET_LINE); - glEnable(GL_POLYGON_OFFSET_FILL); - - pglActiveTextureARB(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); - StartRender(); ssize_t min_i, min_j, max_i, max_j; @@ -144,47 +134,26 @@ for (m_j = min_j; m_j <= max_j; ++m_j) for (m_i = min_i; m_i <= max_i; ++m_i) - ProcessTile(m_i, m_j); + ProcessTile(deviceCommandContext, m_i, m_j); EndRender(); - - // Clean up state changes - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - //glDisable(GL_POLYGON_OFFSET_LINE); - glDisable(GL_POLYGON_OFFSET_FILL); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); -#endif } -void TerrainOverlay::RenderTile(const CColor& color, bool draw_hidden) +void TerrainOverlay::RenderTile( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden) { - RenderTile(color, draw_hidden, m_i, m_j); + RenderTile(deviceCommandContext, color, drawHidden, m_i, m_j); } -void TerrainOverlay::RenderTile(const CColor& color, bool draw_hidden, ssize_t i, ssize_t j) +void TerrainOverlay::RenderTile( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden, ssize_t i, ssize_t j) { // TODO: unnecessary computation calls has been removed but we should use // a vertex buffer or a vertex shader with a texture. // Not sure if it's possible on old OpenGL. - if (draw_hidden) - { - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - } - else - { - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - } - -#if CONFIG2_GLES -#warning TODO: implement TerrainOverlay::RenderTile for GLES -#else - CVector3D pos[2][2]; for (int di = 0; di < 2; ++di) for (int dj = 0; dj < 2; ++dj) @@ -220,51 +189,60 @@ CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - overlayTech->BeginPass(); - CShaderProgramPtr overlayShader = overlayTech->GetShader(); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + overlayTech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + pipelineStateDesc.rasterizationState.cullMode = + drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; + // To ensure that outlines are drawn on top of the terrain correctly (and + // don't Z-fight and flicker nastily), use detph bias to pull them towards + // the camera. + pipelineStateDesc.rasterizationState.depthBiasEnabled = true; + pipelineStateDesc.rasterizationState.depthBiasConstantFactor = -1.0f; + pipelineStateDesc.rasterizationState.depthBiasSlopeFactor = -1.0f; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - overlayShader->Bind(); - overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - overlayShader->Uniform(str_color, color); + Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); - overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); - overlayShader->AssertPointersBound(); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - overlayShader->Unbind(); - overlayTech->EndPass(); -#endif + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); + + deviceCommandContext->Draw(0, vertices.size() / 3); + + deviceCommandContext->EndPass(); } -void TerrainOverlay::RenderTileOutline(const CColor& color, int line_width, bool draw_hidden) +void TerrainOverlay::RenderTileOutline( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden) { - RenderTileOutline(color, line_width, draw_hidden, m_i, m_j); + RenderTileOutline(deviceCommandContext, color, drawHidden, m_i, m_j); } -void TerrainOverlay::RenderTileOutline(const CColor& color, int line_width, bool draw_hidden, ssize_t i, ssize_t j) +void TerrainOverlay::RenderTileOutline( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden, ssize_t i, ssize_t j) { - if (draw_hidden) - { - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - } - else - { - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - } - -#if CONFIG2_GLES -#warning TODO: implement TerrainOverlay::RenderTileOutline for GLES -#else - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - if (line_width != 1) - glLineWidth((float)line_width); - std::vector vertices; #define ADD(i, j) \ m_Terrain->CalcPosition(i, j, position); \ @@ -273,91 +251,106 @@ vertices.emplace_back(position.Z); CVector3D position; - ADD(i, j); - ADD(i+1, j); - ADD(i+1, j+1); - ADD(i, j+1); + ADD(i, j); + ADD(i + 1, j); + ADD(i + 1, j + 1); + ADD(i, j); + ADD(i + 1, j + 1); + ADD(i, j + 1); #undef ADD CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - overlayTech->BeginPass(); - CShaderProgramPtr overlayShader = overlayTech->GetShader(); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + overlayTech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + pipelineStateDesc.rasterizationState.cullMode = + drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - overlayShader->Bind(); - overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - overlayShader->Uniform(str_color, color); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); - overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); - overlayShader->AssertPointersBound(); + deviceCommandContext->Draw(0, vertices.size() / 3); - glDrawArrays(GL_QUADS, 0, vertices.size() / 3); - - overlayShader->Unbind(); - overlayTech->EndPass(); - - if (line_width != 1) - glLineWidth(1.0f); -#endif + deviceCommandContext->EndPass(); } ////////////////////////////////////////////////////////////////////////// TerrainTextureOverlay::TerrainTextureOverlay(float texelsPerTile, int priority) : - ITerrainOverlay(priority), m_TexelsPerTile(texelsPerTile), m_Texture(0), m_TextureW(0), m_TextureH(0) + ITerrainOverlay(priority), m_TexelsPerTile(texelsPerTile) { - glGenTextures(1, &m_Texture); } -TerrainTextureOverlay::~TerrainTextureOverlay() -{ - glDeleteTextures(1, &m_Texture); -} +TerrainTextureOverlay::~TerrainTextureOverlay() = default; -void TerrainTextureOverlay::RenderAfterWater(int cullGroup) +void TerrainTextureOverlay::RenderAfterWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); ssize_t w = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile); ssize_t h = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile); - pglActiveTextureARB(GL_TEXTURE0); + const uint32_t requiredWidth = round_up_to_pow2(w); + const uint32_t requiredHeight = round_up_to_pow2(h); // Recreate the texture with new size if necessary - if (round_up_to_pow2(w) != m_TextureW || round_up_to_pow2(h) != m_TextureH) + if (!m_Texture || m_Texture->GetWidth() != requiredWidth || m_Texture->GetHeight() != requiredHeight) { - m_TextureW = round_up_to_pow2(w); - m_TextureH = round_up_to_pow2(h); - - glBindTexture(GL_TEXTURE_2D, m_Texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureW, m_TextureH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_Texture = deviceCommandContext->GetDevice()->CreateTexture2D("TerrainOverlayTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, requiredWidth, requiredHeight, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::NEAREST, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); } u8* data = (u8*)calloc(w * h, 4); BuildTextureRGBA(data, w, h); - glBindTexture(GL_TEXTURE_2D, m_Texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data); + deviceCommandContext->UploadTextureRegion( + m_Texture.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, data, w * h * 4, 0, 0, w, h); free(data); CMatrix3D matrix; matrix.SetZero(); - matrix._11 = m_TexelsPerTile / (m_TextureW * TERRAIN_TILE_SIZE); - matrix._23 = m_TexelsPerTile / (m_TextureH * TERRAIN_TILE_SIZE); + matrix._11 = m_TexelsPerTile / (m_Texture->GetWidth() * TERRAIN_TILE_SIZE); + matrix._23 = m_TexelsPerTile / (m_Texture->GetHeight() * TERRAIN_TILE_SIZE); matrix._44 = 1; - g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(cullGroup, matrix, m_Texture); + g_Renderer.GetSceneRenderer().GetTerrainRenderer().RenderTerrainOverlayTexture( + deviceCommandContext, cullGroup, matrix, m_Texture.get()); } SColor4ub TerrainTextureOverlay::GetColor(size_t idx, u8 alpha) const { - static u8 colors[][3] = { + static u8 colors[][3] = + { { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, diff -Nru 0ad-0.0.25b/source/renderer/TerrainOverlay.h 0ad-0.0.26/source/renderer/TerrainOverlay.h --- 0ad-0.0.25b/source/renderer/TerrainOverlay.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/TerrainOverlay.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,7 +23,8 @@ #ifndef INCLUDED_TERRAINOVERLAY #define INCLUDED_TERRAINOVERLAY -#include "lib/ogl.h" +#include "renderer/backend/ITexture.h" +#include "renderer/backend/IDeviceCommandContext.h" struct CColor; struct SColor4ub; @@ -43,21 +44,24 @@ public: virtual ~ITerrainOverlay(); - virtual void RenderBeforeWater() { } + virtual void RenderBeforeWater(Renderer::Backend::IDeviceCommandContext* UNUSED(deviceCommandContext)) { } - virtual void RenderAfterWater(int UNUSED(cullGroup)) { } + virtual void RenderAfterWater( + Renderer::Backend::IDeviceCommandContext* UNUSED(deviceCommandContext), int UNUSED(cullGroup)) { } /** * Draw all ITerrainOverlay objects that exist * and that should be drawn before water. */ - static void RenderOverlaysBeforeWater(); + static void RenderOverlaysBeforeWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); /** * Draw all ITerrainOverlay objects that exist * and that should be drawn after water. */ - static void RenderOverlaysAfterWater(int cullGroup); + static void RenderOverlaysAfterWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup); protected: ITerrainOverlay(int priority); @@ -124,40 +128,51 @@ * @param i i coordinate of tile being processed * @param j j coordinate of tile being processed */ - virtual void ProcessTile(ssize_t i, ssize_t j) = 0; + virtual void ProcessTile( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + ssize_t i, ssize_t j) = 0; /** * Draw a filled quad on top of the current tile. * * @param color color to draw. May be transparent (alpha < 1) - * @param draw_hidden true if hidden tiles (i.e. those behind other tiles) + * @param drawHidden true if hidden tiles (i.e. those behind other tiles) * should be drawn */ - void RenderTile(const CColor& color, bool draw_hidden); + void RenderTile( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden); /** * Draw a filled quad on top of the given tile. */ - void RenderTile(const CColor& color, bool draw_hidden, ssize_t i, ssize_t j); + void RenderTile( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden, ssize_t i, ssize_t j); /** * Draw an outlined quad on top of the current tile. * * @param color color to draw. May be transparent (alpha < 1) - * @param line_width width of lines in pixels. 1 is a sensible value - * @param draw_hidden true if hidden tiles (i.e. those behind other tiles) + * @param lineWidth width of lines in pixels. 1 is a sensible value + * @param drawHidden true if hidden tiles (i.e. those behind other tiles) * should be drawn */ - void RenderTileOutline(const CColor& color, int line_width, bool draw_hidden); + void RenderTileOutline( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden); /** * Draw an outlined quad on top of the given tile. */ - void RenderTileOutline(const CColor& color, int line_width, bool draw_hidden, ssize_t i, ssize_t j); + void RenderTileOutline( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CColor& color, bool drawHidden, ssize_t i, ssize_t j); private: // Process all tiles - virtual void RenderBeforeWater(); + void RenderBeforeWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) override; // Temporary storage of tile coordinates, so ProcessTile doesn't need to // pass it to RenderTile/etc (and doesn't have a chance to get it wrong) @@ -176,7 +191,7 @@ public: TerrainTextureOverlay(float texelsPerTile, int priority = 100); - virtual ~TerrainTextureOverlay(); + ~TerrainTextureOverlay() override; protected: /** @@ -194,11 +209,11 @@ SColor4ub GetColor(size_t idx, u8 alpha) const; private: - void RenderAfterWater(int cullGroup); + void RenderAfterWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) override; float m_TexelsPerTile; - GLuint m_Texture; - GLsizei m_TextureW, m_TextureH; + std::unique_ptr m_Texture; }; #endif // INCLUDED_TERRAINOVERLAY diff -Nru 0ad-0.0.25b/source/renderer/TerrainRenderer.cpp 0ad-0.0.26/source/renderer/TerrainRenderer.cpp --- 0ad-0.0.25b/source/renderer/TerrainRenderer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/TerrainRenderer.cpp 2022-09-23 19:17:02.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,11 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * Terrain rendering (everything related to patches and water) is - * encapsulated in TerrainRenderer - */ - #include "precompiled.h" #include "renderer/TerrainRenderer.h" @@ -35,6 +30,7 @@ #include "graphics/ShaderManager.h" #include "graphics/TerritoryTexture.h" #include "graphics/TextRenderer.h" +#include "graphics/TextureManager.h" #include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" @@ -42,35 +38,23 @@ #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" +#include "renderer/backend/IDevice.h" #include "renderer/DecalRData.h" #include "renderer/PatchRData.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" #include "renderer/SkyManager.h" #include "renderer/VertexArray.h" #include "renderer/WaterManager.h" -namespace -{ - -CShaderProgramPtr GetDummyShader() -{ - const char* shaderName; - if (g_RenderingOptions.GetPreferGLSL()) - shaderName = "glsl/dummy"; - else - shaderName = "arb/dummy"; - return g_Renderer.GetShaderManager().LoadProgram(shaderName, CShaderDefines()); -} - -} // anonymous namespace - /** * TerrainRenderer keeps track of which phase it is in, to detect * when Submit, PrepareForRendering etc. are called in the wrong order. */ -enum Phase { +enum Phase +{ Phase_Submit, Phase_Render }; @@ -85,13 +69,13 @@ Phase phase; /// Patches that were submitted for this frame - std::vector visiblePatches[CRenderer::CULL_MAX]; + std::vector visiblePatches[CSceneRenderer::CULL_MAX]; /// Decals that were submitted for this frame - std::vector visibleDecals[CRenderer::CULL_MAX]; + std::vector visibleDecals[CSceneRenderer::CULL_MAX]; /// Fancy water shader - CShaderProgramPtr fancyWaterShader; + CShaderTechniquePtr fancyWaterTech; CSimulation2* simulation; }; @@ -167,7 +151,7 @@ { ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit); - for (int i = 0; i < CRenderer::CULL_MAX; ++i) + for (int i = 0; i < CSceneRenderer::CULL_MAX; ++i) { m->visiblePatches[i].clear(); m->visibleDecals[i].clear(); @@ -176,36 +160,31 @@ m->phase = Phase_Submit; } -void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix, GLuint texture) +void TerrainRenderer::RenderTerrainOverlayTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup, CMatrix3D& textureMatrix, + Renderer::Backend::ITexture* 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]; - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(0); - glDisable(GL_DEPTH_TEST); - 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); - - glEnable(GL_DEPTH_TEST); + deviceCommandContext->SetGraphicsPipelineState( + debugOverlayTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* debugOverlayShader = debugOverlayTech->GetShader(); + + deviceCommandContext->SetTexture( + debugOverlayShader->GetBindingSlot(str_baseTex), texture); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + debugOverlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + debugOverlayShader->GetBindingSlot(str_textureTransform), textureMatrix.AsFloatArray()); + CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, true); // To make the overlay visible over water, render an additional map-sized // water-height patch. @@ -215,28 +194,33 @@ if (!waterBounds.IsEmpty()) { // Add a delta to avoid z-fighting. - const float height = g_Renderer.GetWaterManager()->m_WaterHeight + 0.05f; - const float waterPos[] = { + const float height = g_Renderer.GetSceneRenderer().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 + waterBounds[1].X, height, waterBounds[1].Z, + waterBounds[0].X, height, waterBounds[0].Z, + waterBounds[1].X, height, waterBounds[1].Z, + waterBounds[0].X, height, waterBounds[1].Z }; - const GLsizei stride = sizeof(float) * 3; - debugOverlayShader->VertexPointer(3, GL_FLOAT, stride, waterPos); - debugOverlayShader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, waterPos); - debugOverlayShader->AssertPointersBound(); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } + deviceCommandContext->SetVertexBufferData( + 0, waterPos, std::size(waterPos) * sizeof(waterPos[0])); - debugOverlayShader->Unbind(); - debugOverlayTech->EndPass(); + deviceCommandContext->Draw(0, 6); + } - glDepthMask(1); - glDisable(GL_BLEND); -#endif + deviceCommandContext->EndPass(); } @@ -245,29 +229,52 @@ /** * Set up all the uniforms for a shader pass. */ -void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow) -{ - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->Uniform(str_cameraPos, g_Renderer.GetViewCamera().GetOrientation().GetTranslation()); +void TerrainRenderer::PrepareShader( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow) +{ + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); + + const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_cameraPos), + sceneRenderer.GetViewCamera().GetOrientation().GetTranslation().AsFloatArray()); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); if (shadow) - shadow->BindTo(shader); - - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTextureSmooth()); - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - - shader->Uniform(str_ambient, lightEnv.m_AmbientColor); - shader->Uniform(str_sunColor, lightEnv.m_SunColor); - shader->Uniform(str_sunDir, lightEnv.GetSunDir()); - - shader->Uniform(str_fogColor, lightEnv.m_FogColor); - shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); -} + shadow->BindTo(deviceCommandContext, shader); -void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) + CLOSTexture& los = sceneRenderer.GetScene().GetLOSTexture(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_ambient), + lightEnv.m_AmbientColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunColor), + lightEnv.m_SunColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunDir), + lightEnv.GetSunDir().AsFloatArray()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogColor), + lightEnv.m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogParams), + lightEnv.m_FogFactor, lightEnv.m_FogMax); +} + +void TerrainRenderer::RenderTerrainShader( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { ENSURE(m->phase == Phase_Render); @@ -278,39 +285,37 @@ // render the solid black sides of the map first CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_solid); - techSolid->BeginPass(); - CShaderProgramPtr shaderSolid = techSolid->GetShader(); - shaderSolid->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f); + Renderer::Backend::GraphicsPipelineStateDesc solidPipelineStateDesc = + techSolid->GetGraphicsPipelineStateDesc(); + solidPipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + deviceCommandContext->SetGraphicsPipelineState(solidPipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* shaderSolid = techSolid->GetShader(); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shaderSolid->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shaderSolid->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 1.0f); - CPatchRData::RenderSides(visiblePatches, shaderSolid); + CPatchRData::RenderSides(deviceCommandContext, visiblePatches); - techSolid->EndPass(); + deviceCommandContext->EndPass(); - CPatchRData::RenderBases(visiblePatches, context, shadow); - - // no need to write to the depth buffer a second time - glDepthMask(0); + CPatchRData::RenderBases(deviceCommandContext, visiblePatches, context, shadow); // render blend passes for each patch - CPatchRData::RenderBlends(visiblePatches, context, shadow); - - CDecalRData::RenderDecals(visibleDecals, context, shadow); + CPatchRData::RenderBlends(deviceCommandContext, visiblePatches, context, shadow); - // restore OpenGL state - g_Renderer.BindTexture(1, 0); - g_Renderer.BindTexture(2, 0); - g_Renderer.BindTexture(3, 0); - - glDepthMask(1); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_BLEND); + CDecalRData::RenderDecals(deviceCommandContext, visibleDecals, context, shadow); } - /////////////////////////////////////////////////////////////////// // Render un-textured patches as polygons -void TerrainRenderer::RenderPatches(int cullGroup, const CColor& color) +void TerrainRenderer::RenderPatches( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup, const CShaderDefines& defines, const CColor& color) { ENSURE(m->phase == Phase_Render); @@ -318,24 +323,32 @@ if (visiblePatches.empty()) return; -#if CONFIG2_GLES -#warning TODO: implement TerrainRenderer::RenderPatches for GLES -#else - CShaderProgramPtr dummyShader = GetDummyShader(); - dummyShader->Bind(); - dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - dummyShader->Uniform(str_color, color); + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain patches"); - CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS); + CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_terrain_solid, defines); + deviceCommandContext->SetGraphicsPipelineState( + solidTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* solidShader = solidTech->GetShader(); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + solidShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + solidShader->GetBindingSlot(str_color), color.AsFloatArray()); - dummyShader->Unbind(); -#endif + CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, false); + deviceCommandContext->EndPass(); } /////////////////////////////////////////////////////////////////// // Render outlines of submitted patches as lines -void TerrainRenderer::RenderOutlines(int cullGroup) +void TerrainRenderer::RenderOutlines( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup) { ENSURE(m->phase == Phase_Render); @@ -343,6 +356,8 @@ if (visiblePatches.empty()) return; + GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain outlines"); + for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderOutline(); } @@ -364,47 +379,50 @@ if (!waterBoundsInViewPort.IsEmpty()) scissor += waterBoundsInViewPort; } + if (scissor.IsEmpty()) + return scissor; return CBoundingBoxAligned( CVector3D(Clamp(scissor[0].X, -1.0f, 1.0f), Clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f), CVector3D(Clamp(scissor[1].X, -1.0f, 1.0f), Clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f)); } // Render fancy water -bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) +bool TerrainRenderer::RenderFancyWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { PROFILE3_GPU("fancy water"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render fancy water"); - WaterManager* WaterMgr = g_Renderer.GetWaterManager(); + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); + + WaterManager& waterManager = sceneRenderer.GetWaterManager(); CShaderDefines defines = context; // If we're using fancy water, make sure its shader is loaded - if (!m->fancyWaterShader || WaterMgr->m_NeedsReloading) + if (!m->fancyWaterTech || waterManager.m_NeedsReloading) { - if (WaterMgr->m_WaterRealDepth) + if (waterManager.m_WaterRealDepth) defines.Add(str_USE_REAL_DEPTH, str_1); - if (WaterMgr->m_WaterFancyEffects) + if (waterManager.m_WaterFancyEffects) defines.Add(str_USE_FANCY_EFFECTS, str_1); - if (WaterMgr->m_WaterRefraction) + if (waterManager.m_WaterRefraction) defines.Add(str_USE_REFRACTION, str_1); - if (WaterMgr->m_WaterReflection) + if (waterManager.m_WaterReflection) defines.Add(str_USE_REFLECTION, str_1); - // haven't updated the ARB shader yet so I'll always load the GLSL - /*if (!g_RenderingOptions.GetPreferGLSL() && !superFancy) - m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("arb/water_high", defines); - else*/ - m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("glsl/water_high", defines); + m->fancyWaterTech = g_Renderer.GetShaderManager().LoadEffect(str_water_high, defines); - if (!m->fancyWaterShader) + if (!m->fancyWaterTech) { - LOGERROR("Failed to load water shader. Falling back to fixed pipeline water.\n"); - WaterMgr->m_RenderWater = false; + LOGERROR("Failed to load water shader. Falling back to a simple water.\n"); + waterManager.m_RenderWater = false; return false; } - WaterMgr->m_NeedsReloading = false; + waterManager.m_NeedsReloading = false; } - CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& losTexture = sceneRenderer.GetScene().GetLOSTexture(); // Calculating the advanced informations about Foam and all if the quality calls for it. /*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)) @@ -413,210 +431,291 @@ WaterMgr->CreateSuperfancyInfo(); }*/ - double time = WaterMgr->m_WaterTexTimer; - double period = 8; - int curTex = (int)(time*60/period) % 60; - int nexTex = (curTex + 1) % 60; - - float repeatPeriod = WaterMgr->m_RepeatPeriod; - - // Render normals and foam to a framebuffer if we're in fancy effects - if (WaterMgr->m_WaterFancyEffects) - { - // Save the post-processing framebuffer. - GLint fbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo); - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, WaterMgr->m_FancyEffectsFBO); - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - glDisable(GL_CULL_FACE); - // Overwrite waves that would be behind the ground. - CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - dummyTech->BeginPass(); - CShaderProgramPtr dummyShader = dummyTech->GetShader(); - - dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); - std::vector& visiblePatches = m->visiblePatches[cullGroup]; - for (size_t i = 0; i < visiblePatches.size(); ++i) - { - CPatchRData* data = visiblePatches[i]; - data->RenderWater(dummyShader, true, true); - } - dummyTech->EndPass(); + const double time = waterManager.m_WaterTexTimer; + const float repeatPeriod = waterManager.m_RepeatPeriod; - glEnable(GL_CULL_FACE); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); + deviceCommandContext->SetGraphicsPipelineState( + m->fancyWaterTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader(); + + const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); - m->fancyWaterShader->Bind(); + const double period = 8.0; + // TODO: move uploading to a prepare function during loading. + const CTexturePtr& currentNormalTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]; + const CTexturePtr& nextNormalTexture = waterManager.m_NormalMap[waterManager.GetNextTextureIndex(period)]; - const CCamera& camera = g_Renderer.GetViewCamera(); + currentNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext); + nextNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext); - m->fancyWaterShader->BindTexture(str_normalMap, WaterMgr->m_NormalMap[curTex]); - m->fancyWaterShader->BindTexture(str_normalMap2, WaterMgr->m_NormalMap[nexTex]); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_normalMap), + currentNormalTexture->GetBackendTexture()); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_normalMap2), + nextNormalTexture->GetBackendTexture()); - if (WaterMgr->m_WaterFancyEffects) + if (waterManager.m_WaterFancyEffects) { - m->fancyWaterShader->BindTexture(str_waterEffectsTex, WaterMgr->m_FancyTexture); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_waterEffectsTex), + waterManager.m_FancyTexture.get()); } - if (WaterMgr->m_WaterRefraction && WaterMgr->m_WaterRealDepth) + if (waterManager.m_WaterRefraction && waterManager.m_WaterRealDepth) { - m->fancyWaterShader->BindTexture(str_depthTex, WaterMgr->m_RefrFboDepthTexture); - m->fancyWaterShader->Uniform(str_projInvTransform, WaterMgr->m_RefractionProjInvMatrix); - m->fancyWaterShader->Uniform(str_viewInvTransform, WaterMgr->m_RefractionViewInvMatrix); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_depthTex), + waterManager.m_RefrFboDepthTexture.get()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_projInvTransform), + waterManager.m_RefractionProjInvMatrix.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_viewInvTransform), + waterManager.m_RefractionViewInvMatrix.AsFloatArray()); } - if (WaterMgr->m_WaterRefraction) - m->fancyWaterShader->BindTexture(str_refractionMap, WaterMgr->m_RefractionTexture); - if (WaterMgr->m_WaterReflection) - m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture); - m->fancyWaterShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); + if (waterManager.m_WaterRefraction) + { + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_refractionMap), + waterManager.m_RefractionTexture.get()); + } + if (waterManager.m_WaterReflection) + { + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_reflectionMap), + waterManager.m_ReflectionTexture.get()); + } + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth()); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); - m->fancyWaterShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_transform), transform.AsFloatArray()); - m->fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_skyCube), + sceneRenderer.GetSkyManager().GetSkyCube()); // TODO: check that this rotates in the right direction. CMatrix3D skyBoxRotation; skyBoxRotation.SetIdentity(); skyBoxRotation.RotateY(M_PI + lightEnv.GetRotation()); - m->fancyWaterShader->Uniform(str_skyBoxRot, skyBoxRotation); - - if (WaterMgr->m_WaterRefraction) - m->fancyWaterShader->Uniform(str_refractionMatrix, WaterMgr->m_RefractionMatrix); - if (WaterMgr->m_WaterReflection) - m->fancyWaterShader->Uniform(str_reflectionMatrix, WaterMgr->m_ReflectionMatrix); - - m->fancyWaterShader->Uniform(str_ambient, lightEnv.m_AmbientColor); - m->fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir()); - m->fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor); - m->fancyWaterShader->Uniform(str_color, WaterMgr->m_WaterColor); - m->fancyWaterShader->Uniform(str_tint, WaterMgr->m_WaterTint); - m->fancyWaterShader->Uniform(str_waviness, WaterMgr->m_Waviness); - m->fancyWaterShader->Uniform(str_murkiness, WaterMgr->m_Murkiness); - m->fancyWaterShader->Uniform(str_windAngle, WaterMgr->m_WindAngle); - m->fancyWaterShader->Uniform(str_repeatScale, 1.0f / repeatPeriod); - m->fancyWaterShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); - - m->fancyWaterShader->Uniform(str_cameraPos, camera.GetOrientation().GetTranslation()); - - m->fancyWaterShader->Uniform(str_fogColor, lightEnv.m_FogColor); - m->fancyWaterShader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); - m->fancyWaterShader->Uniform(str_time, (float)time); - m->fancyWaterShader->Uniform(str_screenSize, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f); - - if (WaterMgr->m_WaterType == L"clap") - { - m->fancyWaterShader->Uniform(str_waveParams1, 30.0f,1.5f,20.0f,0.03f); - m->fancyWaterShader->Uniform(str_waveParams2, 0.5f,0.0f,0.0f,0.0f); - } - else if (WaterMgr->m_WaterType == L"lake") - { - m->fancyWaterShader->Uniform(str_waveParams1, 8.5f,1.5f,15.0f,0.03f); - m->fancyWaterShader->Uniform(str_waveParams2, 0.2f,0.0f,0.0f,0.07f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_skyBoxRot), + skyBoxRotation.AsFloatArray()); + + if (waterManager.m_WaterRefraction) + { + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_refractionMatrix), + waterManager.m_RefractionMatrix.AsFloatArray()); + } + if (waterManager.m_WaterReflection) + { + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_reflectionMatrix), + waterManager.m_ReflectionMatrix.AsFloatArray()); + } + + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_ambient), lightEnv.m_AmbientColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_sunDir), lightEnv.GetSunDir().AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_sunColor), lightEnv.m_SunColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_tint), waterManager.m_WaterTint.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waviness), waterManager.m_Waviness); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_murkiness), waterManager.m_Murkiness); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_windAngle), waterManager.m_WindAngle); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_repeatScale), 1.0f / repeatPeriod); + + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_losTransform), + losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_cameraPos), + camera.GetOrientation().GetTranslation().AsFloatArray()); + + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_fogColor), + lightEnv.m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_fogParams), + lightEnv.m_FogFactor, lightEnv.m_FogMax); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_time), static_cast(time)); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_screenSize), + static_cast(g_Renderer.GetWidth()), + static_cast(g_Renderer.GetHeight())); + + if (waterManager.m_WaterType == L"clap") + { + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams1), + 30.0f, 1.5f, 20.0f, 0.03f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams2), + 0.5f, 0.0f, 0.0f, 0.0f); + } + else if (waterManager.m_WaterType == L"lake") + { + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams1), + 8.5f, 1.5f, 15.0f, 0.03f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams2), + 0.2f, 0.0f, 0.0f, 0.07f); } else { - m->fancyWaterShader->Uniform(str_waveParams1, 15.0f,0.8f,10.0f,0.1f); - m->fancyWaterShader->Uniform(str_waveParams2, 0.3f,0.0f,0.1f,0.3f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams1), + 15.0f, 0.8f, 10.0f, 0.1f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams2), + 0.3f, 0.0f, 0.1f, 0.3f); } if (shadow) - shadow->BindTo(m->fancyWaterShader); + shadow->BindTo(deviceCommandContext, fancyWaterShader); - std::vector& visiblePatches = m->visiblePatches[cullGroup]; - for (size_t i = 0; i < visiblePatches.size(); ++i) + for (CPatchRData* data : m->visiblePatches[cullGroup]) { - CPatchRData* data = visiblePatches[i]; - data->RenderWater(m->fancyWaterShader); + data->RenderWaterSurface(deviceCommandContext, true); + if (waterManager.m_WaterFancyEffects) + data->RenderWaterShore(deviceCommandContext); } - m->fancyWaterShader->Unbind(); - - glDepthFunc(GL_LEQUAL); - glDisable(GL_BLEND); + deviceCommandContext->EndPass(); return true; } -void TerrainRenderer::RenderSimpleWater(int cullGroup) +void TerrainRenderer::RenderSimpleWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup) { -#if CONFIG2_GLES - UNUSED2(cullGroup); -#else PROFILE3_GPU("simple water"); + GPU_SCOPED_LABEL(deviceCommandContext, "Render Simple Water"); - WaterManager* WaterMgr = g_Renderer.GetWaterManager(); - CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); + CLOSTexture& losTexture = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); + const double time = waterManager.m_WaterTexTimer; - double time = WaterMgr->m_WaterTexTimer; - double period = 1.6f; - int curTex = (int)(time*60/period) % 60; + CShaderDefines context; + if (g_Renderer.GetSceneRenderer().GetWaterRenderMode() == WIREFRAME) + context.Add(str_MODE_WIREFRAME, str_1); 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_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); - waterSimpleShader->Uniform(str_time, static_cast(time)); - waterSimpleShader->Uniform(str_color, WaterMgr->m_WaterColor); + g_Renderer.GetShaderManager().LoadEffect(str_water_simple, context); + deviceCommandContext->SetGraphicsPipelineState( + waterSimpleTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* waterSimpleShader = waterSimpleTech->GetShader(); + + const CTexturePtr& waterTexture = waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)]; + waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext); + + deviceCommandContext->SetTexture( + waterSimpleShader->GetBindingSlot(str_baseTex), waterTexture->GetBackendTexture()); + deviceCommandContext->SetTexture( + waterSimpleShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth()); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_losTransform), + losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]); + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_time), static_cast(time)); + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; - data->RenderWater(waterSimpleShader, false, true); + data->RenderWaterSurface(deviceCommandContext, false); } - waterSimpleShader->Unbind(); - g_Renderer.BindTexture(1, 0); - - pglActiveTextureARB(GL_TEXTURE0_ARB); - glDisable(GL_TEXTURE_2D); - - waterSimpleTech->EndPass(); -#endif + deviceCommandContext->EndPass(); } /////////////////////////////////////////////////////////////////// // Render water that is part of the terrain -void TerrainRenderer::RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) +void TerrainRenderer::RenderWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { - WaterManager* WaterMgr = g_Renderer.GetWaterManager(); - - WaterMgr->UpdateQuality(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); - if (!WaterMgr->WillRenderFancyWater()) - RenderSimpleWater(cullGroup); + if (!waterManager.WillRenderFancyWater()) + RenderSimpleWater(deviceCommandContext, cullGroup); else - RenderFancyWater(context, cullGroup, shadow); + RenderFancyWater(deviceCommandContext, context, cullGroup, shadow); +} + +void TerrainRenderer::RenderWaterFoamOccluders( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup) +{ + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); + const WaterManager& waterManager = sceneRenderer.GetWaterManager(); + if (!waterManager.WillRenderFancyWater()) + return; + + GPU_SCOPED_LABEL(deviceCommandContext, "Render water foam occluders"); + + // Render normals and foam to a framebuffer if we're using fancy effects. + deviceCommandContext->SetFramebuffer(waterManager.m_FancyEffectsFramebuffer.get()); + + // Overwrite waves that would be behind the ground. + CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); + Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = + dummyTech->GetGraphicsPipelineStateDesc(); + pipelineStateDesc.depthStencilState.depthTestEnabled = true; + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); + + Renderer::Backend::IShaderProgram* dummyShader = dummyTech->GetShader(); + + const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + dummyShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + dummyShader->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 0.0f); + + for (CPatchRData* data : m->visiblePatches[cullGroup]) + data->RenderWaterShore(deviceCommandContext); + + deviceCommandContext->EndPass(); + + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } -void TerrainRenderer::RenderPriorities(int cullGroup) +void TerrainRenderer::RenderPriorities(CCanvas2D& canvas, int cullGroup) { PROFILE("priorities"); ENSURE(m->phase == Phase_Render); - CCanvas2D canvas; CTextRenderer textRenderer; textRenderer.SetCurrentFont(CStrIntern("mono-stroke-10")); textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 1.0f)); diff -Nru 0ad-0.0.25b/source/renderer/TerrainRenderer.h 0ad-0.0.26/source/renderer/TerrainRenderer.h --- 0ad-0.0.25b/source/renderer/TerrainRenderer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/TerrainRenderer.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,8 +25,12 @@ #include "graphics/Color.h" #include "maths/BoundingBoxAligned.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/ITexture.h" +#include "renderer/backend/IShaderProgram.h" class CCamera; +class CCanvas2D; class CMatrix3D; class CModelDecal; class CPatch; @@ -34,7 +38,6 @@ class CSimulation2; class ShadowMap; -class WaterManager; struct TerrainRendererInternals; @@ -96,9 +99,12 @@ * preconditions : PrepareForRendering must have been called this * frame before calling RenderTerrain. * + * @param deviceCommandContext A context to submit commands. * @param shadow A prepared shadow map, in case rendering with shadows is enabled. */ - void RenderTerrainShader(const CShaderDefines& context, int cullGroup, ShadowMap* shadow); + void RenderTerrainShader( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ShadowMap* shadow); /** * RenderPatches: Render all patches un-textured as polygons. @@ -109,7 +115,10 @@ * @param filtered If true then only render objects that passed CullPatches. * @param color Fill color of the patches. */ - void RenderPatches(int cullGroup, const CColor& color = CColor(0.0f, 0.0f, 0.0f, 1.0f)); + void RenderPatches( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup, const CShaderDefines& defines, + const CColor& color = CColor(0.0f, 0.0f, 0.0f, 1.0f)); /** * RenderOutlines: Render the outline of patches as lines. @@ -119,7 +128,9 @@ * * @param filtered If true then only render objects that passed CullPatches. */ - void RenderOutlines(int cullGroup); + void RenderOutlines( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup); /** * RenderWater: Render water for all patches that have been submitted @@ -128,7 +139,16 @@ * preconditions : PrepareForRendering must have been called this * frame before calling RenderWater. */ - void RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow); + void RenderWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ShadowMap* shadow); + + /** + * Renders terrain to a framebuffer to occlude shore foams. + */ + void RenderWaterFoamOccluders( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup); /** * Calculate a scissor rectangle for the visible water patches. @@ -138,14 +158,16 @@ /** * Render priority text for all submitted patches, for debugging. */ - void RenderPriorities(int cullGroup); + void RenderPriorities(CCanvas2D& canvas, int cullGroup); /** * Render texture unit 0 over the terrain mesh, with UV coords calculated * by the given texture matrix. * Intended for use by TerrainTextureOverlay. */ - void RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix, GLuint texture); + void RenderTerrainOverlayTexture( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup, CMatrix3D& textureMatrix, Renderer::Backend::ITexture* texture); private: TerrainRendererInternals* m; @@ -154,14 +176,20 @@ * RenderFancyWater: internal rendering method for fancy water. * Returns false if unable to render with fancy water. */ - bool RenderFancyWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow); + bool RenderFancyWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CShaderDefines& context, int cullGroup, ShadowMap* shadow); /** * RenderSimpleWater: internal rendering method for water */ - void RenderSimpleWater(int cullGroup); - - static void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow); + void RenderSimpleWater( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + int cullGroup); + + static void PrepareShader( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow); }; #endif // INCLUDED_TERRAINRENDERER diff -Nru 0ad-0.0.25b/source/renderer/TexturedLineRData.cpp 0ad-0.0.26/source/renderer/TexturedLineRData.cpp --- 0ad-0.0.25b/source/renderer/TexturedLineRData.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/TexturedLineRData.cpp 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,35 +35,50 @@ * because it allows you to work with variable amounts of vertices and indices more easily. New code should prefer * to use VertexArray where possible, though. */ -void CTexturedLineRData::Render(const SOverlayTexturedLine& line, const CShaderProgramPtr& shader) +void CTexturedLineRData::Render( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const SOverlayTexturedLine& line, Renderer::Backend::IShaderProgram* shader) { if (!m_VB || !m_VBIndices) return; // might have failed to allocate // -- render main line quad strip ---------------------- - const int streamFlags = shader->GetStreamFlags(); + line.m_TextureBase->UploadBackendTextureIfNeeded(deviceCommandContext); + line.m_TextureMask->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_baseTex, line.m_TextureBase->GetHandle()); - shader->BindTexture(str_maskTex, line.m_TextureMask->GetHandle()); - shader->Uniform(str_objectColor, line.m_Color); + m_VB->m_Owner->UploadIfNeeded(deviceCommandContext); + m_VBIndices->m_Owner->UploadIfNeeded(deviceCommandContext); - GLsizei stride = sizeof(CTexturedLineRData::SVertex); - CTexturedLineRData::SVertex* vertexBase = reinterpret_cast(m_VB->m_Owner->Bind()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), line.m_TextureBase->GetBackendTexture()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_maskTex), line.m_TextureMask->GetBackendTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_objectColor), line.m_Color.AsFloatArray()); + + const uint32_t stride = sizeof(CTexturedLineRData::SVertex); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(CTexturedLineRData::SVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(CTexturedLineRData::SVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(CTexturedLineRData::SVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - if (streamFlags & STREAM_POS) - shader->VertexPointer(3, GL_FLOAT, stride, &vertexBase->m_Position[0]); + deviceCommandContext->SetVertexBuffer(0, m_VB->m_Owner->GetBuffer()); - if (streamFlags & STREAM_UV0) - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, &vertexBase->m_UVs[0]); - - if (streamFlags & STREAM_UV1) - shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &vertexBase->m_UVs[0]); - - u8* indexBase = m_VBIndices->m_Owner->Bind(); - - shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, m_VBIndices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*m_VBIndices->m_Index); + deviceCommandContext->SetIndexBuffer(m_VBIndices->m_Owner->GetBuffer()); + deviceCommandContext->DrawIndexed(m_VBIndices->m_Index, m_VBIndices->m_Count, 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += m_VBIndices->m_Count/3; @@ -71,16 +86,8 @@ void CTexturedLineRData::Update(const SOverlayTexturedLine& line) { - if (m_VB) - { - g_VBMan.Release(m_VB); - m_VB = NULL; - } - if (m_VBIndices) - { - g_VBMan.Release(m_VBIndices); - m_VBIndices = NULL; - } + m_VBIndices.Reset(); + m_VB.Reset(); if (!line.m_SimContext) { @@ -164,8 +171,8 @@ // Push vertices and indices for each quad in GL_TRIANGLES order. The two triangles of each quad are indexed using // the winding orders (BR, BL, TR) and (TR, BL, TL) (where BR is bottom-right of this iteration's quad, TR top-right etc). - SVertex vertex1(p1 + b + norm*OverlayRenderer::OVERLAY_VOFFSET, 0.f, v); - SVertex vertex2(p1 - b + norm*OverlayRenderer::OVERLAY_VOFFSET, 1.f, v); + SVertex vertex1(p1 + b + norm * OverlayRenderer::OVERLAY_VOFFSET, CVector2D(0.f, v)); + SVertex vertex2(p1 - b + norm * OverlayRenderer::OVERLAY_VOFFSET, CVector2D(1.f, v)); vertices.push_back(vertex1); vertices.push_back(vertex2); @@ -242,8 +249,8 @@ else { // add two vertices to have the good UVs for the last quad - SVertex vertex1(vertices[0].m_Position, 0.f, 1.f); - SVertex vertex2(vertices[1].m_Position, 1.f, 1.f); + SVertex vertex1(vertices[0].m_Position, CVector2D(0.f, 1.f)); + SVertex vertex2(vertices[1].m_Position, CVector2D(1.f, 1.f)); vertices.push_back(vertex1); vertices.push_back(vertex2); @@ -307,23 +314,31 @@ indices.insert(indices.end(), capIndices.begin(), capIndices.end()); } - ENSURE(indices.size() % 3 == 0); // GL_TRIANGLES indices, so must be multiple of 3 + if (vertices.empty() || indices.empty()) + return; + + // Indices for triangles, so must be multiple of 3. + ENSURE(indices.size() % 3 == 0); m_BoundingBox = CBoundingBoxAligned(); for (const SVertex& vertex : vertices) m_BoundingBox += vertex.m_Position; - m_VB = g_VBMan.Allocate(sizeof(SVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); - if (m_VB) // allocation might fail (e.g. due to too many vertices) + m_VB = g_VBMan.AllocateChunk( + sizeof(SVertex), vertices.size(), Renderer::Backend::IBuffer::Type::VERTEX, false); + // Allocation might fail (e.g. due to too many vertices). + if (m_VB) { - m_VB->m_Owner->UpdateChunkVertices(m_VB, &vertices[0]); // copy data into VBO + // Copy data into backend buffer. + m_VB->m_Owner->UpdateChunkVertices(m_VB.Get(), &vertices[0]); for (size_t k = 0; k < indices.size(); ++k) indices[k] += static_cast(m_VB->m_Index); - m_VBIndices = g_VBMan.Allocate(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); + m_VBIndices = g_VBMan.AllocateChunk( + sizeof(u16), indices.size(), Renderer::Backend::IBuffer::Type::INDEX, false); if (m_VBIndices) - m_VBIndices->m_Owner->UpdateChunkVertices(m_VBIndices, &indices[0]); + m_VBIndices->m_Owner->UpdateChunkVertices(m_VBIndices.Get(), &indices[0]); } } @@ -351,7 +366,7 @@ float radius = line.m_Thickness; CVector3D centerPoint = (corner1 + corner2) * 0.5f; - SVertex centerVertex(centerPoint, 0.5f, 0.5f); + SVertex centerVertex(centerPoint, CVector2D(0.5f, 0.5f)); u16 indexOffset = static_cast(verticesOut.size()); // index offset in verticesOut from where we start adding our vertices switch (endCapType) @@ -360,7 +375,7 @@ { roundCapPoints = 3; // creates only one point directly ahead radius *= 1.5f; // make it a bit sharper (note that we don't use the radius for the butt-end corner points so it should be ok) - centerVertex.m_UVs[0] = 0.480f; // slight visual correction to make the texture match up better at the corner points + centerVertex.m_UV.X = 0.480f; // slight visual correction to make the texture match up better at the corner points } FALLTHROUGH; case SOverlayTexturedLine::LINECAP_ROUND: @@ -380,7 +395,7 @@ // Note that we're manually adding the corner vertices instead of having them be generated by the rotating vector. // This is because we want to support an overly large radius to make the sharp line ending look sharper. verticesOut.push_back(centerVertex); - verticesOut.push_back(SVertex(corner2, 0.f, 0.f)); + verticesOut.push_back(SVertex(corner2, CVector2D())); // Get the base vector that we will incrementally rotate in the cap plane to produce the radial sample points. // Normally corner2 - centerPoint would suffice for this since it is of radius length, but we want to support custom @@ -403,11 +418,11 @@ // of the texture around the edge of the semicircle) float u = 0.f; float v = Clamp((i / static_cast(roundCapPoints - 1)), 0.f, 1.f); // pos, u, v - verticesOut.push_back(SVertex(worldPos3D, u, v)); + verticesOut.push_back(SVertex(worldPos3D, CVector2D(u, v))); } // connect back to the other butt-end corner point to complete the semicircle - verticesOut.push_back(SVertex(corner1, 0.f, 1.f)); + verticesOut.push_back(SVertex(corner1, CVector2D(0.f, 1.f))); // now push indices in GL_TRIANGLES order; vertices[indexOffset] is the center vertex, vertices[indexOffset + 1] is the // first corner point, then a bunch of radial samples, and then at the end we have the other corner point again. So: @@ -427,10 +442,10 @@ // NOTE: The order in which the vertices are pushed out determines the visibility, as they // are rendered only one-sided; the wrong order of vertices will make the cap visible only from the bottom. verticesOut.push_back(centerVertex); - verticesOut.push_back(SVertex(corner2, 0.f, 0.f)); - verticesOut.push_back(SVertex(corner2 + (lineDirectionNormal * (line.m_Thickness)), 0.f, 0.33333f)); // extend butt corner point 2 along the normal vector - verticesOut.push_back(SVertex(corner1 + (lineDirectionNormal * (line.m_Thickness)), 0.f, 0.66666f)); // extend butt corner point 1 along the normal vector - verticesOut.push_back(SVertex(corner1, 0.f, 1.0f)); // push butt corner point 1 + verticesOut.push_back(SVertex(corner2, CVector2D())); + verticesOut.push_back(SVertex(corner2 + (lineDirectionNormal * (line.m_Thickness)), CVector2D(0.f, 0.33333f))); // extend butt corner point 2 along the normal vector + verticesOut.push_back(SVertex(corner1 + (lineDirectionNormal * (line.m_Thickness)), CVector2D(0.f, 0.66666f))); // extend butt corner point 1 along the normal vector + verticesOut.push_back(SVertex(corner1, CVector2D(0.f, 1.0f))); // push butt corner point 1 for (int i=1; i < 4; ++i) { diff -Nru 0ad-0.0.25b/source/renderer/TexturedLineRData.h 0ad-0.0.26/source/renderer/TexturedLineRData.h --- 0ad-0.0.25b/source/renderer/TexturedLineRData.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/TexturedLineRData.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,9 +20,10 @@ #include "graphics/Overlay.h" #include "graphics/RenderableObject.h" -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" #include "graphics/TextureManager.h" #include "maths/BoundingBoxAligned.h" +#include "renderer/backend/IDeviceCommandContext.h" #include "renderer/VertexBufferManager.h" class CFrustum; @@ -47,18 +48,12 @@ public: - CTexturedLineRData() : m_VB(NULL), m_VBIndices(NULL) { } - - ~CTexturedLineRData() - { - if (m_VB) - g_VBMan.Release(m_VB); - if (m_VBIndices) - g_VBMan.Release(m_VBIndices); - } + CTexturedLineRData() = default; + ~CTexturedLineRData() = default; void Update(const SOverlayTexturedLine& line); - void Render(const SOverlayTexturedLine& line, const CShaderProgramPtr& shader); + void Render(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const SOverlayTexturedLine& line, Renderer::Backend::IShaderProgram* shader); bool IsVisibleInFrustum(const CFrustum& frustum) const; @@ -66,10 +61,10 @@ struct SVertex { - SVertex(CVector3D pos, float u, float v) : m_Position(pos) { m_UVs[0] = u; m_UVs[1] = v; } + SVertex(const CVector3D& pos, const CVector2D& uv) : m_Position(pos), m_UV(uv) { } CVector3D m_Position; - GLfloat m_UVs[2]; - float _padding[3]; // get a pow2 struct size + CVector2D m_UV; + float padding[3]; // get a pow2 struct size }; cassert(sizeof(SVertex) == 32); @@ -93,8 +88,8 @@ return (v1.m_Position + v2.m_Position) * 0.5; } - CVertexBuffer::VBChunk* m_VB; - CVertexBuffer::VBChunk* m_VBIndices; + CVertexBufferManager::Handle m_VB; + CVertexBufferManager::Handle m_VBIndices; CBoundingBoxAligned m_BoundingBox; }; diff -Nru 0ad-0.0.25b/source/renderer/VertexArray.cpp 0ad-0.0.26/source/renderer/VertexArray.cpp --- 0ad-0.0.25b/source/renderer/VertexArray.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/VertexArray.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,6 @@ #include "precompiled.h" #include "lib/alignment.h" -#include "lib/ogl.h" #include "lib/sysdep/rtl.h" #include "maths/Vector3D.h" #include "maths/Vector4D.h" @@ -29,19 +28,52 @@ #include "renderer/VertexBuffer.h" #include "renderer/VertexBufferManager.h" +namespace +{ -VertexArray::VertexArray(GLenum usage, GLenum target) +size_t GetAttributeSize(const Renderer::Backend::Format format) +{ + switch (format) + { + case Renderer::Backend::Format::R8G8B8A8_UNORM: FALLTHROUGH; + case Renderer::Backend::Format::R8G8B8A8_UINT: + return sizeof(u8) * 4; + case Renderer::Backend::Format::A8_UNORM: + return sizeof(u8); + case Renderer::Backend::Format::R16_UNORM: FALLTHROUGH; + case Renderer::Backend::Format::R16_UINT: FALLTHROUGH; + case Renderer::Backend::Format::R16_SINT: + return sizeof(u16); + case Renderer::Backend::Format::R16G16_UNORM: FALLTHROUGH; + case Renderer::Backend::Format::R16G16_UINT: FALLTHROUGH; + case Renderer::Backend::Format::R16G16_SINT: + return sizeof(u16) * 2; + case Renderer::Backend::Format::R32_SFLOAT: + return sizeof(float); + case Renderer::Backend::Format::R32G32_SFLOAT: + return sizeof(float) * 2; + case Renderer::Backend::Format::R32G32B32_SFLOAT: + return sizeof(float) * 3; + case Renderer::Backend::Format::R32G32B32A32_SFLOAT: + return sizeof(float) * 4; + default: + break; + }; + return 0; +} + +} // anonymous namespace + +VertexArray::VertexArray( + const Renderer::Backend::IBuffer::Type type, const bool dynamic) + : m_Type(type), m_Dynamic(dynamic) { - m_Usage = usage; - m_Target = target; - m_NumVertices = 0; + m_NumberOfVertices = 0; - m_VB = 0; m_BackingStore = 0; m_Stride = 0; } - VertexArray::~VertexArray() { Free(); @@ -53,33 +85,24 @@ rtl_FreeAligned(m_BackingStore); m_BackingStore = 0; - if (m_VB) - { - g_VBMan.Release(m_VB); - m_VB = 0; - } + m_VB.Reset(); } - // Set the number of vertices stored in the array -void VertexArray::SetNumVertices(size_t num) +void VertexArray::SetNumberOfVertices(const size_t numberOfVertices) { - if (num == m_NumVertices) + if (numberOfVertices == m_NumberOfVertices) return; Free(); - m_NumVertices = num; + m_NumberOfVertices = numberOfVertices; } - // Add vertex attributes like Position, Normal, UV void VertexArray::AddAttribute(Attribute* attr) { - ENSURE( - (attr->type == GL_FLOAT || attr->type == GL_SHORT || attr->type == GL_UNSIGNED_SHORT || attr->type == GL_UNSIGNED_BYTE) - && "Unsupported attribute type" - ); - ENSURE(attr->elems >= 1 && attr->elems <= 4); + // Attribute is supported is its size is greater than zero. + ENSURE(GetAttributeSize(attr->format) > 0 && "Unsupported attribute."); attr->vertexArray = this; m_Attributes.push_back(attr); @@ -87,7 +110,6 @@ Free(); } - // Template specialization for GetIterator(). // We can put this into the source file because only a fixed set of types // is supported for type safety. @@ -95,8 +117,9 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_FLOAT); - ENSURE(elems >= 3); + ENSURE( + format == Renderer::Backend::Format::R32G32B32_SFLOAT || + format == Renderer::Backend::Format::R32G32B32A32_SFLOAT); return vertexArray->MakeIterator(this); } @@ -105,8 +128,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_FLOAT); - ENSURE(elems >= 4); + ENSURE(format == Renderer::Backend::Format::R32G32B32A32_SFLOAT); return vertexArray->MakeIterator(this); } @@ -115,28 +137,18 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_FLOAT); - ENSURE(elems >= 2); + ENSURE(format == Renderer::Backend::Format::R32G32_SFLOAT); return vertexArray->MakeIterator(this); } template<> -VertexArrayIterator VertexArray::Attribute::GetIterator() const -{ - ENSURE(vertexArray); - ENSURE(type == GL_UNSIGNED_BYTE); - ENSURE(elems >= 3); - - return vertexArray->MakeIterator(this); -} - -template<> VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_UNSIGNED_BYTE); - ENSURE(elems >= 4); + ENSURE( + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UINT); return vertexArray->MakeIterator(this); } @@ -145,8 +157,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_UNSIGNED_SHORT); - ENSURE(elems >= 1); + ENSURE(format == Renderer::Backend::Format::R16_UINT); return vertexArray->MakeIterator(this); } @@ -155,8 +166,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_UNSIGNED_SHORT); - ENSURE(elems >= 2); + ENSURE(format == Renderer::Backend::Format::R16G16_UINT); return vertexArray->MakeIterator(this); } @@ -165,8 +175,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_UNSIGNED_BYTE); - ENSURE(elems >= 1); + ENSURE(format == Renderer::Backend::Format::A8_UNORM); return vertexArray->MakeIterator(this); } @@ -175,8 +184,9 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_UNSIGNED_BYTE); - ENSURE(elems >= 4); + ENSURE( + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UINT); return vertexArray->MakeIterator(this); } @@ -185,8 +195,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_SHORT); - ENSURE(elems >= 1); + ENSURE(format == Renderer::Backend::Format::R16_SINT); return vertexArray->MakeIterator(this); } @@ -195,8 +204,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() const { ENSURE(vertexArray); - ENSURE(type == GL_SHORT); - ENSURE(elems >= 2); + ENSURE(format == Renderer::Backend::Format::R16G16_SINT); return vertexArray->MakeIterator(this); } @@ -217,116 +225,83 @@ // Re-layout by assigning offsets on a first-come first-serve basis, // then round up to a reasonable stride. -// Backing store is also created here, VBOs are created on upload. +// Backing store is also created here, backend buffers are created on upload. void VertexArray::Layout() { Free(); m_Stride = 0; - //debug_printf("Layouting VertexArray\n"); - for (ssize_t idx = m_Attributes.size()-1; idx >= 0; --idx) { Attribute* attr = m_Attributes[idx]; - - if (!attr->type || !attr->elems) + if (attr->format == Renderer::Backend::Format::UNDEFINED) continue; - size_t attrSize = 0; - switch(attr->type) - { - case GL_UNSIGNED_BYTE: - attrSize = sizeof(GLubyte); - break; - case GL_SHORT: - attrSize = sizeof(GLshort); - break; - case GL_UNSIGNED_SHORT: - attrSize = sizeof(GLushort); - break; - case GL_FLOAT: - attrSize = sizeof(GLfloat); - break; - default: - attrSize = 0; - debug_warn(L"Bad Attribute::type"); break; - } - - attrSize *= attr->elems; + const size_t attrSize = GetAttributeSize(attr->format); + ENSURE(attrSize > 0); attr->offset = m_Stride; m_Stride += attrSize; - if (m_Target == GL_ARRAY_BUFFER) + if (m_Type == Renderer::Backend::IBuffer::Type::VERTEX) m_Stride = Align<4>(m_Stride); - - //debug_printf("%i: offset: %u\n", idx, attr->offset); } - if (m_Target == GL_ARRAY_BUFFER) + if (m_Type == Renderer::Backend::IBuffer::Type::VERTEX) m_Stride = RoundStride(m_Stride); - //debug_printf("Stride: %u\n", m_Stride); - if (m_Stride) - m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumVertices, 16); + m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumberOfVertices, 16); } void VertexArray::PrepareForRendering() { - m_VB->m_Owner->PrepareForRendering(m_VB); + m_VB->m_Owner->PrepareForRendering(m_VB.Get()); } // (Re-)Upload the attributes. -// Create the VBO if necessary. +// Create the backend buffer if necessary. void VertexArray::Upload() { ENSURE(m_BackingStore); if (!m_VB) - m_VB = g_VBMan.Allocate(m_Stride, m_NumVertices, m_Usage, m_Target, m_BackingStore); + { + m_VB = g_VBMan.AllocateChunk( + m_Stride, m_NumberOfVertices, m_Type, m_Dynamic, m_BackingStore); + } if (!m_VB) { - LOGERROR("Failed to allocate VBO for vertex array"); + LOGERROR("Failed to allocate backend buffer for vertex array"); return; } - m_VB->m_Owner->UpdateChunkVertices(m_VB, m_BackingStore); + m_VB->m_Owner->UpdateChunkVertices(m_VB.Get(), m_BackingStore); } - -// Bind this array, returns the base address for calls to glVertexPointer etc. -u8* VertexArray::Bind() +void VertexArray::UploadIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - if (!m_VB) - return NULL; - - u8* base = m_VB->m_Owner->Bind(); - base += m_VB->m_Index*m_Stride; - return base; + m_VB->m_Owner->UploadIfNeeded(deviceCommandContext); } - // Free the backing store to save some memory void VertexArray::FreeBackingStore() { // In streaming modes, the backing store must be retained - ENSURE(!CVertexBuffer::UseStreaming(m_Usage)); + ENSURE(!CVertexBuffer::UseStreaming(m_Dynamic)); rtl_FreeAligned(m_BackingStore); m_BackingStore = 0; } - - -VertexIndexArray::VertexIndexArray(GLenum usage) : - VertexArray(usage, GL_ELEMENT_ARRAY_BUFFER) +VertexIndexArray::VertexIndexArray(const bool dynamic) : + VertexArray(Renderer::Backend::IBuffer::Type::INDEX, dynamic) { - m_Attr.type = GL_UNSIGNED_SHORT; - m_Attr.elems = 1; + m_Attr.format = Renderer::Backend::Format::R16_UINT; AddAttribute(&m_Attr); } diff -Nru 0ad-0.0.25b/source/renderer/VertexArray.h 0ad-0.0.26/source/renderer/VertexArray.h --- 0ad-0.0.25b/source/renderer/VertexArray.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/VertexArray.h 2022-09-23 19:17:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,12 @@ #ifndef INCLUDED_VERTEXARRAY #define INCLUDED_VERTEXARRAY -#include "renderer/VertexBuffer.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/IBuffer.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/VertexBufferManager.h" + +#include // Iterator template @@ -127,29 +132,26 @@ // This class chooses the vertex layout at runtime, based on the attributes // that are actually needed. // -// Note that this class will not allocate any OpenGL resources until one +// Note that this class will not allocate any backend resources until one // of the Upload functions is called. class VertexArray { public: struct Attribute { - // Data type. Currently supported: GL_FLOAT, GL_SHORT, GL_UNSIGNED_SHORT, GL_UNSIGNED_BYTE. - GLenum type; - // How many elements per vertex (e.g. 3 for RGB, 2 for UV) - GLuint elems; + Renderer::Backend::Format format = Renderer::Backend::Format::UNDEFINED; // Offset (in bytes) into a vertex structure (filled in by Layout()) - size_t offset; + size_t offset = 0; - VertexArray* vertexArray; + VertexArray* vertexArray = nullptr; - Attribute() : type(0), elems(0), offset(0), vertexArray(0) { } + Attribute() {} // Get an iterator over the backing store for the given attribute that // initially points at the first vertex. - // Supported types T: CVector3D, CVector4D, float[2], SColor3ub, SColor4ub, - // u16, u16[2], u8, u8[4], short, short[2]. + // Supported types T: CVector3D, CVector4D, float[2], SColor4ub, + // u16, u16[2], u8[4], short, short[2]. // This function verifies at runtime that the requested type T matches // the attribute definition passed to AddAttribute(). template @@ -157,15 +159,16 @@ }; public: - VertexArray(GLenum usage, GLenum target = GL_ARRAY_BUFFER); + VertexArray( + const Renderer::Backend::IBuffer::Type type, const bool dynamic); ~VertexArray(); // Set the number of vertices stored in the array - void SetNumVertices(size_t num); + void SetNumberOfVertices(const size_t numberOfVertices); // Add vertex attributes void AddAttribute(Attribute* attr); - size_t GetNumVertices() const { return m_NumVertices; } + size_t GetNumberOfVertices() const { return m_NumberOfVertices; } size_t GetStride() const { return m_Stride; } // Layout the vertex array format and create backing buffer in RAM. @@ -174,47 +177,49 @@ // All vertex data is lost when a vertex array is re-layouted. void Layout(); // (Re-)Upload the attributes of the vertex array from the backing store to - // the underlying VBO object. + // the underlying buffer. void Upload(); // Make this vertex array's data available for the next series of calls to Bind void PrepareForRendering(); - // Bind this array, returns the base address for calls to glVertexPointer etc. - u8* Bind(); + + void UploadIfNeeded(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); // If you know for certain that you'll never have to change the data again, // call this to free some memory. void FreeBackingStore(); + Renderer::Backend::IBuffer* GetBuffer() { return m_VB ? m_VB->m_Owner->GetBuffer() : nullptr; } + + uint32_t GetOffset() const { return m_VB ? m_VB->m_Index : 0; } + private: void Free(); template VertexArrayIterator MakeIterator(const Attribute* attr) { - ENSURE(attr->type && attr->elems); + ENSURE(attr->format != Renderer::Backend::Format::UNDEFINED); return VertexArrayIterator(m_BackingStore + attr->offset, m_Stride); } - GLenum m_Usage; - GLenum m_Target; - size_t m_NumVertices; + Renderer::Backend::IBuffer::Type m_Type; + bool m_Dynamic; + size_t m_NumberOfVertices; std::vector m_Attributes; - CVertexBuffer::VBChunk* m_VB; + CVertexBufferManager::Handle m_VB; size_t m_Stride; char* m_BackingStore; // 16-byte aligned, to allow fast SSE access }; /** * A VertexArray that is specialised to handle 16-bit array indices. - * Call Bind() and pass the return value to the indices parameter of - * glDrawElements/glDrawRangeElements/glMultiDrawElements. - * Use CVertexBuffer::Unbind() to unbind the array when done. + * Call UploadIfNeeded() before use in Draw/DrawIndexed. */ class VertexIndexArray : public VertexArray { public: - VertexIndexArray(GLenum usage); + VertexIndexArray(const bool dynamic); /// Gets the iterator over the (only) attribute in this array, i.e. a u16. VertexArrayIterator GetIterator() const; diff -Nru 0ad-0.0.25b/source/renderer/VertexBuffer.cpp 0ad-0.0.26/source/renderer/VertexBuffer.cpp --- 0ad-0.0.25b/source/renderer/VertexBuffer.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/VertexBuffer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,13 +19,15 @@ #include "VertexBuffer.h" -#include "lib/ogl.h" #include "lib/sysdep/cpu.h" -#include "Renderer.h" #include "ps/CLogger.h" #include "ps/Errors.h" +#include "ps/VideoMode.h" +#include "renderer/backend/IDevice.h" +#include "renderer/Renderer.h" #include +#include #include // Absolute maximum (bytewise) size of each GL vertex buffer object. @@ -34,32 +36,38 @@ // TODO: measure what influence this has on performance constexpr std::size_t MAX_VB_SIZE_BYTES = 4 * 1024 * 1024; -CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target) - : CVertexBuffer(vertexSize, usage, target, MAX_VB_SIZE_BYTES) +CVertexBuffer::CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::IBuffer::Type type, const bool dynamic) + : CVertexBuffer(name, vertexSize, type, dynamic, MAX_VB_SIZE_BYTES) { } -CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target, size_t maximumBufferSize) - : m_VertexSize(vertexSize), m_Handle(0), m_Usage(usage), m_Target(target), m_HasNeededChunks(false) +CVertexBuffer::CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::IBuffer::Type type, const bool dynamic, + const size_t maximumBufferSize) + : m_VertexSize(vertexSize), m_HasNeededChunks(false) { size_t size = maximumBufferSize; - if (target == GL_ARRAY_BUFFER) // vertex data buffer + if (type == Renderer::Backend::IBuffer::Type::VERTEX) { // We want to store 16-bit indices to any vertex in a buffer, so the // buffer must never be bigger than vertexSize*64K bytes since we can // address at most 64K of them with 16-bit indices - size = std::min(size, vertexSize*65536); + size = std::min(size, vertexSize * 65536); + } + else if (type == Renderer::Backend::IBuffer::Type::INDEX) + { + ENSURE(vertexSize == sizeof(u16)); } // store max/free vertex counts m_MaxVertices = m_FreeVertices = size / vertexSize; - // allocate raw buffer - pglGenBuffersARB(1, &m_Handle); - pglBindBufferARB(m_Target, m_Handle); - pglBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, 0, m_Usage); - pglBindBufferARB(m_Target, 0); + m_Buffer = g_VideoMode.GetBackendDevice()->CreateBuffer( + name, type, m_MaxVertices * m_VertexSize, dynamic); // create sole free chunk VBChunk* chunk = new VBChunk; @@ -74,46 +82,50 @@ // Must have released all chunks before destroying the buffer ENSURE(m_AllocList.empty()); - if (m_Handle) - pglDeleteBuffersARB(1, &m_Handle); + m_Buffer.reset(); for (VBChunk* const& chunk : m_FreeList) delete chunk; } - -bool CVertexBuffer::CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) const +bool CVertexBuffer::CompatibleVertexType( + const size_t vertexSize, const Renderer::Backend::IBuffer::Type type, + const bool dynamic) const { - return usage == m_Usage && target == m_Target && vertexSize == m_VertexSize; + ENSURE(m_Buffer); + return type == m_Buffer->GetType() && dynamic == m_Buffer->IsDynamic() && vertexSize == m_VertexSize; } /////////////////////////////////////////////////////////////////////////////// // Allocate: try to allocate a buffer of given number of vertices (each of // given size), with the given type, and using the given texture - return null // if no free chunks available -CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore) +CVertexBuffer::VBChunk* CVertexBuffer::Allocate( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::IBuffer::Type type, const bool dynamic, + void* backingStore) { // check this is the right kind of buffer - if (!CompatibleVertexType(vertexSize, usage, target)) + if (!CompatibleVertexType(vertexSize, type, dynamic)) return nullptr; - if (UseStreaming(usage)) + if (UseStreaming(dynamic)) ENSURE(backingStore != nullptr); // quick check there's enough vertices spare to allocate - if (numVertices > m_FreeVertices) + if (numberOfVertices > m_FreeVertices) return nullptr; // trawl free list looking for first free chunk with enough space std::vector::iterator best_iter = m_FreeList.end(); for (std::vector::iterator iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) { - if (numVertices == (*iter)->m_Count) + if (numberOfVertices == (*iter)->m_Count) { best_iter = iter; break; } - else if (numVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count)) + else if (numberOfVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count)) best_iter = iter; } @@ -131,17 +143,17 @@ // split chunk into two; - allocate a new chunk using all unused vertices in the // found chunk, and add it to the free list - if (chunk->m_Count > numVertices) + if (chunk->m_Count > numberOfVertices) { VBChunk* newchunk = new VBChunk; newchunk->m_Owner = this; - newchunk->m_Count = chunk->m_Count - numVertices; - newchunk->m_Index = chunk->m_Index + numVertices; + newchunk->m_Count = chunk->m_Count - numberOfVertices; + newchunk->m_Index = chunk->m_Index + numberOfVertices; m_FreeList.emplace_back(newchunk); m_FreeVertices += newchunk->m_Count; // resize given chunk - chunk->m_Count = numVertices; + chunk->m_Count = numberOfVertices; } // return found chunk @@ -195,38 +207,34 @@ // UpdateChunkVertices: update vertex data for given chunk void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk, void* data) { - ENSURE(m_Handle); - if (UseStreaming(m_Usage)) + ENSURE(m_Buffer); + if (UseStreaming(m_Buffer->IsDynamic())) { - // The VBO is now out of sync with the backing store + // The backend buffer is now out of sync with the backing store. chunk->m_Dirty = true; // Sanity check: Make sure the caller hasn't tried to reallocate - // their backing store + // their backing store. ENSURE(data == chunk->m_BackingStore); } else { - pglBindBufferARB(m_Target, m_Handle); - pglBufferSubDataARB(m_Target, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data); - pglBindBufferARB(m_Target, 0); + ENSURE(data); + g_Renderer.GetDeviceCommandContext()->UploadBufferRegion( + m_Buffer.get(), data, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize); } } -/////////////////////////////////////////////////////////////////////////////// -// Bind: bind to this buffer; return pointer to address required as parameter -// to glVertexPointer ( + etc) calls -u8* CVertexBuffer::Bind() +void CVertexBuffer::UploadIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - pglBindBufferARB(m_Target, m_Handle); - - if (UseStreaming(m_Usage)) + if (UseStreaming(m_Buffer->IsDynamic())) { if (!m_HasNeededChunks) - return nullptr; + return; - // If any chunks are out of sync with the current VBO, and are - // needed for rendering this frame, we'll need to re-upload the VBO + // If any chunks are out of sync with the current backend buffer, and are + // needed for rendering this frame, we'll need to re-upload the backend buffer. bool needUpload = false; for (VBChunk* const& chunk : m_AllocList) { @@ -239,49 +247,26 @@ if (needUpload) { - // Tell the driver that it can reallocate the whole VBO - pglBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, NULL, m_Usage); - - // (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used - // here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with - // current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do - // the explicit glBufferData.) - - while (true) + deviceCommandContext->UploadBuffer(m_Buffer.get(), [&](u8* mappedData) { - void* p = pglMapBufferARB(m_Target, GL_WRITE_ONLY); - if (p == NULL) - { - // This shouldn't happen unless we run out of virtual address space - LOGERROR("glMapBuffer failed"); - break; - } - #ifndef NDEBUG // To help detect bugs where PrepareForRendering() was not called, // force all not-needed data to 0, so things won't get rendered // with undefined (but possibly still correct-looking) data. - memset(p, 0, m_MaxVertices * m_VertexSize); + memset(mappedData, 0, m_MaxVertices * m_VertexSize); #endif // Copy only the chunks we need. (This condition is helpful when - // the VBO contains data for every unit in the world, but only a - // handful are visible on screen and we don't need to bother copying - // the rest.) + // the backend buffer contains data for every unit in the world, + // but only a handful are visible on screen and we don't need to + // bother copying the rest.) for (VBChunk* const& chunk : m_AllocList) if (chunk->m_Needed) - memcpy((u8 *)p + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize); - - if (pglUnmapBufferARB(m_Target) == GL_TRUE) - break; - - // Unmap might fail on e.g. resolution switches, so just try again - // and hope it will eventually succeed - debug_printf("glUnmapBuffer failed, trying again...\n"); - } + std::memcpy(mappedData + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize); + }); // Anything we just uploaded is clean; anything else is dirty - // since the rest of the VBO content is now undefined + // since the rest of the backend buffer content is now undefined for (VBChunk* const& chunk : m_AllocList) { if (chunk->m_Needed) @@ -302,14 +287,6 @@ m_HasNeededChunks = false; } - - return nullptr; -} - -void CVertexBuffer::Unbind() -{ - pglBindBufferARB(GL_ARRAY_BUFFER, 0); - pglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); } size_t CVertexBuffer::GetBytesReserved() const @@ -335,9 +312,9 @@ debug_printf("max size = %d\n", static_cast(maxSize)); } -bool CVertexBuffer::UseStreaming(GLenum usage) +bool CVertexBuffer::UseStreaming(const bool dynamic) { - return usage == GL_DYNAMIC_DRAW || usage == GL_STREAM_DRAW; + return dynamic; } void CVertexBuffer::PrepareForRendering(VBChunk* chunk) diff -Nru 0ad-0.0.25b/source/renderer/VertexBuffer.h 0ad-0.0.26/source/renderer/VertexBuffer.h --- 0ad-0.0.25b/source/renderer/VertexBuffer.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/VertexBuffer.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -16,39 +16,41 @@ */ /* - * encapsulation of VBOs with batching and sharing + * Encapsulation of backend buffers with batching and sharing. */ #ifndef INCLUDED_VERTEXBUFFER #define INCLUDED_VERTEXBUFFER -#include "lib/res/graphics/ogl_tex.h" +#include "renderer/backend/IBuffer.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include #include /** - * CVertexBuffer: encapsulation of ARB_vertex_buffer_object, also supplying + * CVertexBuffer: encapsulation of backend buffers, also supplying * some additional functionality for sharing buffers between multiple objects. * * The class can be used in two modes, depending on the usage parameter: * - * GL_STATIC_DRAW: Call Allocate() with backingStore = NULL. Then call + * Static buffer: Call Allocate() with backingStore = nullptr. Then call * UpdateChunkVertices() with any pointer - the data will be immediately copied - * to the VBO. This should be used for vertex data that rarely changes. + * to the buffer. This should be used for vertex data that rarely changes. * - * GL_DYNAMIC_DRAW, GL_STREAM_DRAW: Call Allocate() with backingStore pointing + * Dynamic buffer: Call Allocate() with backingStore pointing * at some memory that will remain valid for the lifetime of the CVertexBuffer. * This should be used for vertex data that may change every frame. * Rendering is expected to occur in two phases: * - "Prepare" phase: - * If this chunk is going to be used for rendering during the next Bind phase, + * If this chunk is going to be used for rendering during the next rendering phase, * you must call PrepareForRendering(). - * If the vertex data in backingStore has been modified since the last Bind phase, + * If the vertex data in backingStore has been modified since the last uploading phase, * you must call UpdateChunkVertices(). - * - "Bind" phase: - * Bind() can be called (multiple times). The vertex data will be uploaded + * - "Upload" phase: + * UploadedIfNeeded() can be called (multiple times). The vertex data will be uploaded * to the GPU if necessary. - * It is okay to have multiple prepare/bind cycles per frame (though slightly less + * It is okay to have multiple prepare/upload cycles per frame (though slightly less * efficient), but they must occur sequentially. */ class CVertexBuffer @@ -57,29 +59,30 @@ public: - /// VBChunk: describes a portion of this vertex buffer + // VBChunk: describes a portion of this vertex buffer struct VBChunk { - /// Owning (parent) vertex buffer + // Owning (parent) vertex buffer CVertexBuffer* m_Owner; - /// Start index of this chunk in owner + // Start index of this chunk in owner size_t m_Index; - /// Number of vertices used by chunk + // Number of vertices used by chunk size_t m_Count; - /// If UseStreaming() is true, points at the data for this chunk + // If UseStreaming() is true, points at the data for this chunk void* m_BackingStore; - /// If true, the VBO is not consistent with the chunk's backing store - /// (and will need to be re-uploaded before rendering with this chunk) + // If true, the backend buffer is not consistent with the chunk's + // backing store (and will need to be re-uploaded before rendering with + // this chunk). bool m_Dirty; - /// If true, we have been told this chunk is going to be used for - /// rendering in the next bind phase and will need to be uploaded + // If true, we have been told this chunk is going to be used for + // rendering in the next uploading phase and will need to be uploaded bool m_Needed; private: // Only CVertexBuffer can construct/delete these - // (Other people should use g_VBMan.Allocate, g_VBMan.Release) + // (Other people should use g_VBMan.AllocateChunk) friend class CVertexBuffer; VBChunk() {} ~VBChunk() {} @@ -87,18 +90,18 @@ public: // constructor, destructor - CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target); - CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target, size_t maximumBufferSize); + CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::IBuffer::Type type, const bool dynamic); + CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::IBuffer::Type type, const bool dynamic, + const size_t maximumBufferSize); ~CVertexBuffer(); - /// Bind to this buffer; return pointer to address required as parameter - /// to glVertexPointer ( + etc) calls - u8* Bind(); + void UploadIfNeeded(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); - /// Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it - static void Unbind(); - - /// Make the vertex data available for the next call to Bind() + /// Make the vertex data available for the next usage. void PrepareForRendering(VBChunk* chunk); /// Update vertex data for given chunk. Transfers the provided data to the actual OpenGL vertex buffer. @@ -109,7 +112,9 @@ size_t GetBytesAllocated() const; /// Returns true if this vertex buffer is compatible with the specified vertex type and intended usage. - bool CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) const; + bool CompatibleVertexType( + const size_t vertexSize, const Renderer::Backend::IBuffer::Type type, + const bool dynamic) const; void DumpStatus() const; @@ -120,23 +125,25 @@ * so we will re-upload the entire buffer every frame using glMapBuffer. * This requires the buffer's owner to hold onto its backing store. * - * If false, we assume it will change rarely, and use glSubBufferData to + * If false, we assume it will change rarely, and use direct upload to * update it incrementally. The backing store can be freed to save memory. */ - static bool UseStreaming(GLenum usage); + static bool UseStreaming(const bool dynamic); + + Renderer::Backend::IBuffer* GetBuffer() { return m_Buffer.get(); } -protected: +private: friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager /// Try to allocate a buffer of given number of vertices (each of given size), /// and with the given type - return null if no free chunks available - VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore); + VBChunk* Allocate( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::IBuffer::Type type, const bool dynamic, + void* backingStore); /// Return given chunk to this buffer void Release(VBChunk* chunk); - -private: - /// Vertex size of this vertex buffer size_t m_VertexSize; /// Number of vertices of above size in this buffer @@ -147,13 +154,10 @@ std::vector m_AllocList; /// Available free vertices - total of all free vertices in the free list size_t m_FreeVertices; - /// Handle to the actual GL vertex buffer object - GLuint m_Handle; - /// Usage type of the buffer (GL_STATIC_DRAW etc) - GLenum m_Usage; - /// Buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER) - GLenum m_Target; + + std::unique_ptr m_Buffer; + bool m_HasNeededChunks; }; -#endif +#endif // INCLUDED_VERTEXBUFFER diff -Nru 0ad-0.0.25b/source/renderer/VertexBufferManager.cpp 0ad-0.0.26/source/renderer/VertexBufferManager.cpp --- 0ad-0.0.25b/source/renderer/VertexBufferManager.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/VertexBufferManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,19 +15,60 @@ * along with 0 A.D. If not, see . */ -/* - * Allocate and destroy CVertexBuffers - */ - #include "precompiled.h" #include "VertexBufferManager.h" -#include "lib/ogl.h" #include "ps/CLogger.h" #define DUMP_VB_STATS 0 // for debugging +namespace +{ + +const char* GetBufferTypeName( + const Renderer::Backend::IBuffer::Type type) +{ + const char* name = "UnknownBuffer"; + switch (type) + { + case Renderer::Backend::IBuffer::Type::VERTEX: + name = "VertexBuffer"; + break; + case Renderer::Backend::IBuffer::Type::INDEX: + name = "IndexBuffer"; + break; + default: + debug_warn("Unknown buffer type"); + break; + } + return name; +} + +const char* GetGroupName( + const CVertexBufferManager::Group group) +{ + const char* name = "Unknown"; + switch (group) + { + case CVertexBufferManager::Group::DEFAULT: + name = "Default"; + break; + case CVertexBufferManager::Group::TERRAIN: + name = "Terrain"; + break; + case CVertexBufferManager::Group::WATER: + name = "Water"; + break; + default: + debug_warn("Unknown buffer group"); + break; + } + return name; +} + +} // anonymous namespace + CVertexBufferManager g_VBMan; CVertexBufferManager::Handle::Handle(Handle&& other) @@ -73,31 +114,22 @@ m_Buffers[group].clear(); } -CVertexBuffer::VBChunk* CVertexBufferManager::Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore) +/** + * AllocateChunk: try to allocate a buffer of given number of vertices (each of + * given size), with the given type, and using the given texture - return null + * if no free chunks available + */ +CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::IBuffer::Type type, + const bool dynamic, void* backingStore, Group group) { - return AllocateImpl(vertexSize, numVertices, usage, target, backingStore, Group::DEFAULT); -} + ENSURE(vertexSize > 0); + ENSURE(numberOfVertices > 0); -CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore, Group group) -{ - CVertexBuffer::VBChunk* chunk = AllocateImpl(vertexSize, numVertices, usage, target, backingStore, group); - if (!chunk) - return Handle(); - return Handle(chunk); -} - -// Allocate: try to allocate a buffer of given number of vertices (each of -// given size), with the given type, and using the given texture - return null -// if no free chunks available -CVertexBuffer::VBChunk* CVertexBufferManager::AllocateImpl(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore, Group group) -{ CVertexBuffer::VBChunk* result = nullptr; - ENSURE(usage == GL_STREAM_DRAW || usage == GL_STATIC_DRAW || usage == GL_DYNAMIC_DRAW); - - ENSURE(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER); - - if (CVertexBuffer::UseStreaming(usage)) + if (CVertexBuffer::UseStreaming(dynamic)) ENSURE(backingStore != NULL); // TODO, RC - run some sanity checks on allocation request @@ -108,7 +140,7 @@ debug_printf("\n============================\n# allocate vsize=%zu nverts=%zu\n\n", vertexSize, numVertices); for (const std::unique_ptr& buffer : buffers) { - if (buffer->CompatibleVertexType(vertexSize, usage, target)) + if (buffer->CompatibleVertexType(vertexSize, type, dynamic)) { debug_printf("%p\n", buffer.get()); buffer->DumpStatus(); @@ -120,25 +152,31 @@ // satisfy the allocation for (const std::unique_ptr& buffer : buffers) { - result = buffer->Allocate(vertexSize, numVertices, usage, target, backingStore); + result = buffer->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore); if (result) - return result; + return Handle(result); } + char bufferName[64] = {0}; + snprintf( + bufferName, std::size(bufferName), "%s (%s, %zu%s)", + GetBufferTypeName(type), GetGroupName(group), vertexSize, (dynamic ? ", dynamic" : "")); + // got this far; need to allocate a new buffer buffers.emplace_back( group == Group::DEFAULT - ? std::make_unique(vertexSize, usage, target) + ? std::make_unique(bufferName, vertexSize, type, dynamic) // Reduces the buffer size for not so frequent buffers. - : std::make_unique(vertexSize, usage, target, 1024 * 1024)); - result = buffers.back()->Allocate(vertexSize, numVertices, usage, target, backingStore); + : std::make_unique(bufferName, vertexSize, type, dynamic, 1024 * 1024)); + result = buffers.back()->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore); if (!result) { - LOGERROR("Failed to create VBOs (%zu*%zu)", vertexSize, numVertices); + LOGERROR("Failed to create backend buffer (%zu*%zu)", vertexSize, numberOfVertices); + return Handle(); } - return result; + return Handle(result); } void CVertexBufferManager::Release(CVertexBuffer::VBChunk* chunk) diff -Nru 0ad-0.0.25b/source/renderer/VertexBufferManager.h 0ad-0.0.26/source/renderer/VertexBufferManager.h --- 0ad-0.0.25b/source/renderer/VertexBufferManager.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/VertexBufferManager.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -80,23 +80,22 @@ * Try to allocate a vertex buffer of the given size and type. * * @param vertexSize size of each vertex in the buffer - * @param numVertices number of vertices in the buffer - * @param usage GL_STATIC_DRAW, GL_DYNAMIC_DRAW, GL_STREAM_DRAW - * @param target typically GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER - * @param backingStore if usage is STATIC, this is NULL; else for DYNAMIC/STREAM, + * @param numberOfVertices number of vertices in the buffer + * @param type buffer type + * @param dynamic will be buffer updated frequently or not + * @param backingStore if not dynamic, this is nullptr; else for dynamic, * this must be a copy of the vertex data that remains valid for the * lifetime of the VBChunk - * @return chunk, or NULL if no free chunks available + * @return chunk, or empty handle if no free chunks available */ - CVertexBuffer::VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore = nullptr); + Handle AllocateChunk( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::IBuffer::Type type, + const bool dynamic, void* backingStore = nullptr, Group group = Group::DEFAULT); /// Returns the given @p chunk to its owning buffer void Release(CVertexBuffer::VBChunk* chunk); - // Same as the Allocate function but returns Handle. Should be used instead - // of the Allocate. - Handle AllocateChunk(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore = nullptr, Group group = Group::DEFAULT); - size_t GetBytesReserved() const; size_t GetBytesAllocated() const; @@ -104,7 +103,6 @@ void Shutdown(); private: - CVertexBuffer::VBChunk* AllocateImpl(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore = nullptr, Group group = Group::DEFAULT); /// List of all known vertex buffers std::vector> m_Buffers[static_cast(Group::COUNT)]; diff -Nru 0ad-0.0.25b/source/renderer/WaterManager.cpp 0ad-0.0.26/source/renderer/WaterManager.cpp --- 0ad-0.0.25b/source/renderer/WaterManager.cpp 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/WaterManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,10 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * Water settings (speed, height) and texture management - */ - #include "precompiled.h" #include "graphics/Terrain.h" @@ -27,21 +23,23 @@ #include "graphics/ShaderProgram.h" #include "lib/bits.h" #include "lib/timer.h" -#include "lib/tex/tex.h" -#include "lib/res/graphics/ogl_tex.h" #include "maths/MathUtil.h" #include "maths/Vector2D.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" #include "ps/Game.h" +#include "ps/VideoMode.h" #include "ps/World.h" -#include "renderer/WaterManager.h" +#include "renderer/backend/IDevice.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" +#include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpWaterManager.h" #include "simulation2/components/ICmpRangeManager.h" +#include struct CoastalPoint { @@ -50,7 +48,8 @@ CVector2D position; }; -struct SWavesVertex { +struct SWavesVertex +{ // vertex position CVector3D m_BasePosition; CVector3D m_ApexPosition; @@ -67,7 +66,7 @@ struct WaveObject { - CVertexBuffer::VBChunk* m_VBvertices; + CVertexBufferManager::Handle m_VBVertices; CBoundingBoxAligned m_AABB; size_t m_Width; float m_TimeDiff; @@ -79,16 +78,8 @@ m_RenderWater = false; // disabled until textures are successfully loaded m_WaterHeight = 5.0f; - m_WaterCurrentTex = 0; - - m_ReflectionTexture = 0; - m_RefractionTexture = 0; m_RefTextureSize = 0; - m_ReflectionFbo = 0; - m_RefractionFbo = 0; - m_FancyEffectsFBO = 0; - m_WaterTexTimer = 0.0; m_WindAngle = 0.0f; @@ -98,12 +89,6 @@ m_Murkiness = 0.45f; m_RepeatPeriod = 16.0f; - m_DistanceHeightmap = NULL; - m_BlurredNormalMap = NULL; - m_WindStrength = NULL; - - m_ShoreWaves_VBIndices = NULL; - m_WaterEffects = true; m_WaterFancyEffects = false; m_WaterRealDepth = false; @@ -114,11 +99,6 @@ m_NeedsReloading = false; m_NeedInfoUpdate = true; - m_FancyTexture = 0; - m_FancyTextureDepth = 0; - m_ReflFboDepthTexture = 0; - m_RefrFboDepthTexture = 0; - m_MapSize = 0; m_updatei0 = 0; @@ -132,31 +112,20 @@ // Cleanup if the caller messed up UnloadWaterTextures(); - for (WaveObject* const& obj : m_ShoreWaves) - { - if (obj->m_VBvertices) - g_VBMan.Release(obj->m_VBvertices); - delete obj; - } - - if (m_ShoreWaves_VBIndices) - g_VBMan.Release(m_ShoreWaves_VBIndices); - - delete[] m_DistanceHeightmap; - delete[] m_BlurredNormalMap; - delete[] m_WindStrength; + m_ShoreWaves.clear(); + m_ShoreWavesVBIndices.Reset(); - if (!g_Renderer.GetCapabilities().m_PrettyWater) - return; + m_DistanceHeightmap.reset(); + m_WindStrength.reset(); - glDeleteTextures(1, &m_FancyTexture); - glDeleteTextures(1, &m_FancyTextureDepth); - glDeleteTextures(1, &m_ReflFboDepthTexture); - glDeleteTextures(1, &m_RefrFboDepthTexture); - - pglDeleteFramebuffersEXT(1, &m_FancyEffectsFBO); - pglDeleteFramebuffersEXT(1, &m_RefractionFbo); - pglDeleteFramebuffersEXT(1, &m_ReflectionFbo); + m_FancyEffectsFramebuffer.reset(); + m_RefractionFramebuffer.reset(); + m_ReflectionFramebuffer.reset(); + + m_FancyTexture.reset(); + m_FancyTextureDepth.reset(); + m_ReflFboDepthTexture.reset(); + m_RefrFboDepthTexture.reset(); } @@ -174,30 +143,24 @@ { swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/default/diffuse%02d.dds", (int)i+1); CTextureProperties textureProps(pathname); - textureProps.SetWrap(GL_REPEAT); + textureProps.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::REPEAT); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_WaterTexture[i] = texture; } - if (!g_Renderer.GetCapabilities().m_PrettyWater) - { - // Enable rendering, now that we've succeeded this far - m_RenderWater = true; - return 0; - } + m_RenderWater = true; -#if CONFIG2_GLES -#warning Fix WaterManager::LoadWaterTextures on GLES -#else // Load normalmaps (for fancy water) ReloadWaterNormalTextures(); // Load CoastalWaves { CTextureProperties textureProps(L"art/textures/terrain/types/water/coastalWave.png"); - textureProps.SetWrap(GL_REPEAT); + textureProps.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::REPEAT); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_WaveTex = texture; @@ -206,143 +169,127 @@ // Load Foam { CTextureProperties textureProps(L"art/textures/terrain/types/water/foam.png"); - textureProps.SetWrap(GL_REPEAT); + textureProps.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::REPEAT); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_FoamTex = texture; } - // Use screen-sized textures for minimum artifacts. - m_RefTextureSize = g_Renderer.GetHeight(); - - m_RefTextureSize = round_up_to_pow2(m_RefTextureSize); - - // Create reflection texture - glGenTextures(1, &m_ReflectionTexture); - glBindTexture(GL_TEXTURE_2D, m_ReflectionTexture); - 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_MIRRORED_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - // Create refraction texture - glGenTextures(1, &m_RefractionTexture); - glBindTexture(GL_TEXTURE_2D, m_RefractionTexture); - 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_MIRRORED_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - // Create depth textures - glGenTextures(1, &m_ReflFboDepthTexture); - glBindTexture(GL_TEXTURE_2D, m_ReflFboDepthTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); - - glGenTextures(1, &m_RefrFboDepthTexture); - glBindTexture(GL_TEXTURE_2D, m_RefrFboDepthTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - 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_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); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glGenTextures(1, &m_FancyTextureDepth); - glBindTexture(GL_TEXTURE_2D, m_FancyTextureDepth); - 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); - - glBindTexture(GL_TEXTURE_2D, 0); - - Resize(); - - // Create the water framebuffers - - GLint currentFbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, ¤tFbo); - - m_ReflectionFbo = 0; - pglGenFramebuffersEXT(1, &m_ReflectionFbo); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_ReflectionFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_ReflectionTexture, 0); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_ReflFboDepthTexture, 0); - - ogl_WarnIfError(); - - GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Reflection framebuffer object incomplete: 0x%04X", status); - g_RenderingOptions.SetWaterReflection(false); - UpdateQuality(); - } - - m_RefractionFbo = 0; - pglGenFramebuffersEXT(1, &m_RefractionFbo); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_RefractionFbo); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_RefractionTexture, 0); - pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_RefrFboDepthTexture, 0); - - ogl_WarnIfError(); - - status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Refraction framebuffer object incomplete: 0x%04X", status); - g_RenderingOptions.SetWaterRefraction(false); - UpdateQuality(); - } - - pglGenFramebuffersEXT(1, &m_FancyEffectsFBO); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); - 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(); - - status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Fancy Effects framebuffer object incomplete: 0x%04X", status); - g_RenderingOptions.SetWaterRefraction(false); - UpdateQuality(); - } - - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFbo); + RecreateOrLoadTexturesIfNeeded(); - // Enable rendering, now that we've succeeded this far - m_RenderWater = true; -#endif return 0; } - -/////////////////////////////////////////////////////////////////// -// Resize: Updates the fancy water textures. -void WaterManager::Resize() +void WaterManager::RecreateOrLoadTexturesIfNeeded() { - 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); + Renderer::Backend::IDevice* backendDevice = g_VideoMode.GetBackendDevice(); - glBindTexture(GL_TEXTURE_2D, m_FancyTextureDepth); - glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, (GLsizei)g_Renderer.GetWidth(), (GLsizei)g_Renderer.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + // Use screen-sized textures for minimum artifacts. + const size_t newRefTextureSize = round_up_to_pow2(g_Renderer.GetHeight()); - glBindTexture(GL_TEXTURE_2D, 0); + if (m_RefTextureSize != newRefTextureSize) + { + m_ReflectionFramebuffer.reset(); + m_ReflectionTexture.reset(); + m_ReflFboDepthTexture.reset(); + + m_RefractionFramebuffer.reset(); + m_RefractionTexture.reset(); + m_RefrFboDepthTexture.reset(); + + m_RefTextureSize = newRefTextureSize; + } + + // Create reflection textures. + const bool needsReflectionTextures = + g_RenderingOptions.GetWaterEffects() && + g_RenderingOptions.GetWaterReflection(); + if (needsReflectionTextures && !m_ReflectionTexture) + { + m_ReflectionTexture = backendDevice->CreateTexture2D("WaterReflectionTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, m_RefTextureSize, m_RefTextureSize, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::MIRRORED_REPEAT)); + + m_ReflFboDepthTexture = backendDevice->CreateTexture2D("WaterReflectionDepthTexture", + Renderer::Backend::Format::D32, m_RefTextureSize, m_RefTextureSize, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::NEAREST, + Renderer::Backend::Sampler::AddressMode::REPEAT)); + + m_ReflectionFramebuffer = backendDevice->CreateFramebuffer("ReflectionFramebuffer", + m_ReflectionTexture.get(), m_ReflFboDepthTexture.get(), CColor(0.5f, 0.5f, 1.0f, 0.0f)); + if (!m_ReflectionFramebuffer) + { + g_RenderingOptions.SetWaterReflection(false); + UpdateQuality(); + } + } + + // Create refraction textures. + const bool needsRefractionTextures = + g_RenderingOptions.GetWaterEffects() && + g_RenderingOptions.GetWaterRefraction(); + if (needsRefractionTextures && !m_RefractionTexture) + { + m_RefractionTexture = backendDevice->CreateTexture2D("WaterRefractionTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, m_RefTextureSize, m_RefTextureSize, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::MIRRORED_REPEAT)); + + m_RefrFboDepthTexture = backendDevice->CreateTexture2D("WaterRefractionDepthTexture", + Renderer::Backend::Format::D32, m_RefTextureSize, m_RefTextureSize, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::NEAREST, + Renderer::Backend::Sampler::AddressMode::REPEAT)); + + m_RefractionFramebuffer = backendDevice->CreateFramebuffer("RefractionFramebuffer", + m_RefractionTexture.get(), m_RefrFboDepthTexture.get(), CColor(1.0f, 0.0f, 0.0f, 0.0f)); + if (!m_RefractionFramebuffer) + { + g_RenderingOptions.SetWaterRefraction(false); + UpdateQuality(); + } + } + + const uint32_t newWidth = static_cast(g_Renderer.GetWidth()); + const uint32_t newHeight = static_cast(g_Renderer.GetHeight()); + if (m_FancyTexture && (m_FancyTexture->GetWidth() != newWidth || m_FancyTexture->GetHeight() != newHeight)) + { + m_FancyEffectsFramebuffer.reset(); + m_FancyTexture.reset(); + m_FancyTextureDepth.reset(); + } + + // Create the Fancy Effects textures. + const bool needsFancyTextures = + g_RenderingOptions.GetWaterEffects() && + g_RenderingOptions.GetWaterFancyEffects(); + if (needsFancyTextures && !m_FancyTexture) + { + m_FancyTexture = backendDevice->CreateTexture2D("WaterFancyTexture", + Renderer::Backend::Format::R8G8B8A8_UNORM, g_Renderer.GetWidth(), g_Renderer.GetHeight(), + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::REPEAT)); + + m_FancyTextureDepth = backendDevice->CreateTexture2D("WaterFancyDepthTexture", + Renderer::Backend::Format::D32, g_Renderer.GetWidth(), g_Renderer.GetHeight(), + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::REPEAT)); + + m_FancyEffectsFramebuffer = backendDevice->CreateFramebuffer("FancyEffectsFramebuffer", + m_FancyTexture.get(), m_FancyTextureDepth.get()); + if (!m_FancyEffectsFramebuffer) + { + g_RenderingOptions.SetWaterRefraction(false); + UpdateQuality(); + } + } } void WaterManager::ReloadWaterNormalTextures() @@ -352,8 +299,9 @@ { swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/%ls/normal00%02d.png", m_WaterType.c_str(), static_cast(i) + 1); CTextureProperties textureProps(pathname); - textureProps.SetWrap(GL_REPEAT); - textureProps.SetMaxAnisotropy(4); + textureProps.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::REPEAT); + textureProps.SetAnisotropicFilter(true); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); @@ -365,19 +313,16 @@ // Unload water textures void WaterManager::UnloadWaterTextures() { - for(size_t i = 0; i < ARRAY_SIZE(m_WaterTexture); i++) + for (size_t i = 0; i < ARRAY_SIZE(m_WaterTexture); i++) m_WaterTexture[i].reset(); - if (!g_Renderer.GetCapabilities().m_PrettyWater) - return; - - for(size_t i = 0; i < ARRAY_SIZE(m_NormalMap); i++) + for (size_t i = 0; i < ARRAY_SIZE(m_NormalMap); i++) m_NormalMap[i].reset(); - glDeleteTextures(1, &m_ReflectionTexture); - glDeleteTextures(1, &m_RefractionTexture); - pglDeleteFramebuffersEXT(1, &m_RefractionFbo); - pglDeleteFramebuffersEXT(1, &m_ReflectionFbo); + m_RefractionFramebuffer.reset(); + m_ReflectionFramebuffer.reset(); + m_ReflectionTexture.reset(); + m_RefractionTexture.reset(); } template @@ -438,10 +383,10 @@ // we want to look ahead some distance, but not too much (less efficient and not interesting). This is our lookahead. const size_t maxLevel = 5; - if (m_DistanceHeightmap == NULL) + if (!m_DistanceHeightmap) { - m_DistanceHeightmap = new float[SideSize*SideSize]; - std::fill(m_DistanceHeightmap, m_DistanceHeightmap + SideSize*SideSize, (float)maxLevel); + m_DistanceHeightmap = std::make_unique(SideSize * SideSize); + std::fill(m_DistanceHeightmap.get(), m_DistanceHeightmap.get() + SideSize * SideSize, static_cast(maxLevel)); } // Create a manhattan-distance heightmap. @@ -449,8 +394,8 @@ u16* heightmap = terrain->GetHeightMap(); - ComputeDirection(m_DistanceHeightmap, heightmap, m_WaterHeight, SideSize, maxLevel); - ComputeDirection(m_DistanceHeightmap, heightmap, m_WaterHeight, SideSize, maxLevel); + ComputeDirection(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); + ComputeDirection(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); } // This requires m_DistanceHeightmap to be defined properly. @@ -463,19 +408,8 @@ if (!terrain || !terrain->GetHeightMap()) return; - for (WaveObject* const& obj : m_ShoreWaves) - { - if (obj->m_VBvertices) - g_VBMan.Release(obj->m_VBvertices); - delete obj; - } m_ShoreWaves.clear(); - - if (m_ShoreWaves_VBIndices) - { - g_VBMan.Release(m_ShoreWaves_VBIndices); - m_ShoreWaves_VBIndices = NULL; - } + m_ShoreWavesVBIndices.Reset(); if (m_Waviness < 5.0f && m_WaterType != L"ocean") return; @@ -601,13 +535,13 @@ } // Fourth step: create waves themselves, using those chains. We basically create subchains. - GLushort waveSizes = 14; // maximal size in width. + u16 waveSizes = 14; // maximal size in width. // Construct indices buffer (we can afford one for all of them) - std::vector water_indices; - for (GLushort a = 0; a < waveSizes - 1; ++a) + std::vector water_indices; + for (u16 a = 0; a < waveSizes - 1; ++a) { - for (GLushort rect = 0; rect < 7; ++rect) + for (u16 rect = 0; rect < 7; ++rect) { water_indices.push_back(a * 9 + rect); water_indices.push_back(a * 9 + 9 + rect); @@ -618,11 +552,15 @@ } } // Generic indexes, max-length - m_ShoreWaves_VBIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); - m_ShoreWaves_VBIndices->m_Owner->UpdateChunkVertices(m_ShoreWaves_VBIndices, &water_indices[0]); + m_ShoreWavesVBIndices = g_VBMan.AllocateChunk( + sizeof(u16), water_indices.size(), + Renderer::Backend::IBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::WATER); + m_ShoreWavesVBIndices->m_Owner->UpdateChunkVertices(m_ShoreWavesVBIndices.Get(), &water_indices[0]); float diff = (rand() % 50) / 5.0f; + std::vector vertices, reversed; for (size_t i = 0; i < CoastalPointsChains.size(); ++i) { for (size_t j = 0; j < CoastalPointsChains[i].size()-waveSizes; ++j) @@ -630,14 +568,14 @@ if (CoastalPointsChains[i].size()- 1 - j < waveSizes) break; - GLushort width = waveSizes; + u16 width = waveSizes; // First pass to get some parameters out. float outmost = 0.0f; // how far to move on the shore. float avgDepth = 0.0f; int sign = 1; CVector2D firstPerp(0,0), perp(0,0), lastPerp(0,0); - for (GLushort a = 0; a < waveSizes;++a) + for (u16 a = 0; a < waveSizes;++a) { lastPerp = perp; perp = CVector2D(0,0); @@ -710,15 +648,15 @@ } // we passed the checks, we can create a wave of size "width". - WaveObject* shoreWave = new WaveObject; - std::vector vertices; - vertices.reserve(9*width); + std::unique_ptr shoreWave = std::make_unique(); + vertices.clear(); + vertices.reserve(9 * width); shoreWave->m_Width = width; shoreWave->m_TimeDiff = diff; diff += (rand() % 100) / 25.0f + 4.0f; - for (GLushort a = 0; a < width;++a) + for (u16 a = 0; a < width;++a) { perp = CVector2D(0,0); int nb = 0; @@ -824,98 +762,123 @@ if (sign == 1) { // Let's do some fancy reversing. - std::vector reversed; + reversed.clear(); reversed.reserve(vertices.size()); - for (int a = width-1; a >= 0; --a) + for (int a = width - 1; a >= 0; --a) { for (size_t t = 0; t < 9; ++t) - reversed.push_back(vertices[a*9+t]); + reversed.push_back(vertices[a * 9 + t]); } - vertices = reversed; + std::swap(vertices, reversed); } j += width/2-1; - shoreWave->m_VBvertices = g_VBMan.Allocate(sizeof(SWavesVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); - shoreWave->m_VBvertices->m_Owner->UpdateChunkVertices(shoreWave->m_VBvertices, &vertices[0]); + shoreWave->m_VBVertices = g_VBMan.AllocateChunk( + sizeof(SWavesVertex), vertices.size(), + Renderer::Backend::IBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::WATER); + shoreWave->m_VBVertices->m_Owner->UpdateChunkVertices(shoreWave->m_VBVertices.Get(), &vertices[0]); - m_ShoreWaves.push_back(shoreWave); + m_ShoreWaves.emplace_back(std::move(shoreWave)); } } } -void WaterManager::RenderWaves(const CFrustum& frustrum) +void WaterManager::RenderWaves( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CFrustum& frustrum) { -#if CONFIG2_GLES -#warning Fix WaterManager::RenderWaves on GLES -#else - if (g_Renderer.DoSkipSubmit() || !m_WaterFancyEffects) + GPU_SCOPED_LABEL(deviceCommandContext, "Render Waves"); + if (!m_WaterFancyEffects) return; - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); - - 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); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - - CShaderDefines none; - CShaderProgramPtr shader = g_Renderer.GetShaderManager().LoadProgram("glsl/waves", none); - - shader->Bind(); - - shader->BindTexture(str_waveTex, m_WaveTex); - shader->BindTexture(str_foamTex, m_FoamTex); - - shader->Uniform(str_time, (float)m_WaterTexTimer); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + deviceCommandContext->SetFramebuffer(m_FancyEffectsFramebuffer.get()); + deviceCommandContext->ClearFramebuffer(); + + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_water_waves); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + + m_WaveTex->UploadBackendTextureIfNeeded(deviceCommandContext); + m_FoamTex->UploadBackendTextureIfNeeded(deviceCommandContext); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_waveTex), m_WaveTex->GetBackendTexture()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_foamTex), m_FoamTex->GetBackendTexture()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_time), static_cast(m_WaterTexTimer)); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); for (size_t a = 0; a < m_ShoreWaves.size(); ++a) { if (!frustrum.IsBoxVisible(m_ShoreWaves[a]->m_AABB)) continue; - CVertexBuffer::VBChunk* VBchunk = m_ShoreWaves[a]->m_VBvertices; - SWavesVertex* base = (SWavesVertex*)VBchunk->m_Owner->Bind(); - - // setup data pointers - GLsizei stride = sizeof(SWavesVertex); - shader->VertexPointer(3, GL_FLOAT, stride, &base[VBchunk->m_Index].m_BasePosition); - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_UNSIGNED_BYTE, stride, &base[VBchunk->m_Index].m_UV); - // NormalPointer(gl_FLOAT, stride, &base[m_VBWater->m_Index].m_UV) - pglVertexAttribPointerARB(2, 2, GL_FLOAT, GL_FALSE, stride, &base[VBchunk->m_Index].m_PerpVect); // replaces commented above because my normal is vec2 - shader->VertexAttribPointer(str_a_apexPosition, 3, GL_FLOAT, false, stride, &base[VBchunk->m_Index].m_ApexPosition); - shader->VertexAttribPointer(str_a_splashPosition, 3, GL_FLOAT, false, stride, &base[VBchunk->m_Index].m_SplashPosition); - shader->VertexAttribPointer(str_a_retreatPosition, 3, GL_FLOAT, false, stride, &base[VBchunk->m_Index].m_RetreatPosition); - - shader->AssertPointersBound(); - - shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff); - shader->Uniform(str_width, (int)m_ShoreWaves[a]->m_Width); - - u8* indexBase = m_ShoreWaves_VBIndices->m_Owner->Bind(); - glDrawElements(GL_TRIANGLES, (GLsizei) (m_ShoreWaves[a]->m_Width-1)*(7*6), - GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_ShoreWaves_VBIndices->m_Index)); - - shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff + 6.0f); - - // TODO: figure out why this doesn't work. - //g_Renderer.m_Stats.m_DrawCalls++; - //g_Renderer.m_Stats.m_WaterTris += m_ShoreWaves_VBIndices->m_Count / 3; - - CVertexBuffer::Unbind(); - } - shader->Unbind(); - pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); -#endif + CVertexBuffer::VBChunk* VBchunk = m_ShoreWaves[a]->m_VBVertices.Get(); + VBchunk->m_Owner->UploadIfNeeded(deviceCommandContext); + m_ShoreWavesVBIndices->m_Owner->UploadIfNeeded(deviceCommandContext); + + const uint32_t stride = sizeof(SWavesVertex); + const uint32_t firstVertexOffset = VBchunk->m_Index * stride; + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + offsetof(SWavesVertex, m_BasePosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32_SFLOAT, + firstVertexOffset + offsetof(SWavesVertex, m_PerpVect), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R8G8_UINT, + firstVertexOffset + offsetof(SWavesVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + offsetof(SWavesVertex, m_ApexPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV2, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + offsetof(SWavesVertex, m_SplashPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV3, + Renderer::Backend::Format::R32G32B32_SFLOAT, + firstVertexOffset + offsetof(SWavesVertex, m_RetreatPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_translation), m_ShoreWaves[a]->m_TimeDiff); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_width), static_cast(m_ShoreWaves[a]->m_Width)); + + deviceCommandContext->SetVertexBuffer(0, VBchunk->m_Owner->GetBuffer()); + deviceCommandContext->SetIndexBuffer(m_ShoreWavesVBIndices->m_Owner->GetBuffer()); + + const uint32_t indexCount = (m_ShoreWaves[a]->m_Width - 1) * (7 * 6); + deviceCommandContext->DrawIndexed(m_ShoreWavesVBIndices->m_Index, indexCount, 0); + + g_Renderer.GetStats().m_DrawCalls++; + g_Renderer.GetStats().m_WaterTris += indexCount / 3; + } + deviceCommandContext->EndPass(); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } void WaterManager::RecomputeWaterData() @@ -935,8 +898,8 @@ if (m_MapSize <= 0) return; - if (m_WindStrength == nullptr) - m_WindStrength = new float[m_MapSize*m_MapSize]; + if (!m_WindStrength) + m_WindStrength = std::make_unique(m_MapSize * m_MapSize); CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); if (!terrain || !terrain->GetHeightMap()) @@ -1057,9 +1020,8 @@ m_updatej0 = 0; m_updatej1 = size; - SAFE_ARRAY_DELETE(m_DistanceHeightmap); - SAFE_ARRAY_DELETE(m_BlurredNormalMap); - SAFE_ARRAY_DELETE(m_WindStrength); + m_DistanceHeightmap.reset(); + m_WindStrength.reset(); } //////////////////////////////////////////////////////////////////////// @@ -1093,7 +1055,21 @@ } } -bool WaterManager::WillRenderFancyWater() +bool WaterManager::WillRenderFancyWater() const +{ + return + m_RenderWater && g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB && + g_RenderingOptions.GetWaterEffects(); +} + +size_t WaterManager::GetCurrentTextureIndex(const double& period) const +{ + ENSURE(period > 0.0); + return static_cast(m_WaterTexTimer * ARRAY_SIZE(m_WaterTexture) / period) % ARRAY_SIZE(m_WaterTexture); +} + +size_t WaterManager::GetNextTextureIndex(const double& period) const { - return m_RenderWater && g_RenderingOptions.GetWaterEffects() && g_Renderer.GetCapabilities().m_PrettyWater; + ENSURE(period > 0.0); + return (GetCurrentTextureIndex(period) + 1) % ARRAY_SIZE(m_WaterTexture); } diff -Nru 0ad-0.0.25b/source/renderer/WaterManager.h 0ad-0.0.26/source/renderer/WaterManager.h --- 0ad-0.0.25b/source/renderer/WaterManager.h 2021-07-27 21:57:02.000000000 +0000 +++ 0ad-0.0.26/source/renderer/WaterManager.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,15 +24,18 @@ #include "graphics/Color.h" #include "graphics/Texture.h" -#include "lib/ogl.h" #include "maths/Matrix3D.h" #include "maths/Vector2D.h" +#include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/ITexture.h" #include "renderer/VertexBufferManager.h" -class CSimulation2; +#include +#include + class CFrustum; -struct CoastalPoint; struct WaveObject; /** @@ -46,14 +49,16 @@ CTexturePtr m_WaterTexture[60]; CTexturePtr m_NormalMap[60]; - float* m_WindStrength; // How strong the waves are at point X. % of waviness. - float* m_DistanceHeightmap; // How far from the shore a point is. Manhattan - CVector3D* m_BlurredNormalMap; // Cache a slightly blurred map of the normals of the terrain. + // How strong the waves are at point X. % of waviness. + std::unique_ptr m_WindStrength; + // How far from the shore a point is. Manhattan. + std::unique_ptr m_DistanceHeightmap; // Waves vertex buffers - std::vector< WaveObject* > m_ShoreWaves; // TODO: once we get C++11, remove pointer + // TODO: measure storing value instead of pointer. + std::vector> m_ShoreWaves; // Waves indices buffer. Only one since All Wave Objects have the same. - CVertexBuffer::VBChunk* m_ShoreWaves_VBIndices; + CVertexBufferManager::Handle m_ShoreWavesVBIndices; size_t m_MapSize; ssize_t m_TexSize; @@ -61,10 +66,10 @@ CTexturePtr m_WaveTex; CTexturePtr m_FoamTex; - GLuint m_FancyTexture; - GLuint m_FancyTextureDepth; - GLuint m_ReflFboDepthTexture; - GLuint m_RefrFboDepthTexture; + std::unique_ptr m_FancyTexture; + std::unique_ptr m_FancyTextureDepth; + std::unique_ptr m_ReflFboDepthTexture; + std::unique_ptr m_RefrFboDepthTexture; // used to know what to update when updating parts of the terrain only. u32 m_updatei0; @@ -72,10 +77,9 @@ u32 m_updatei1; u32 m_updatej1; - int m_WaterCurrentTex; bool m_RenderWater; - // If disabled, force the use of the fixed function for rendering. + // If disabled, force the use of the simple water shader for rendering. bool m_WaterEffects; // Those variables register the current quality level. If there is a change, I have to recompile the shader. // Use real depth or use the fake precomputed one. @@ -97,14 +101,14 @@ float m_RepeatPeriod; // Reflection and refraction textures for fancy water - GLuint m_ReflectionTexture; - GLuint m_RefractionTexture; + std::unique_ptr m_ReflectionTexture; + std::unique_ptr m_RefractionTexture; size_t m_RefTextureSize; // framebuffer objects - GLuint m_RefractionFbo; - GLuint m_ReflectionFbo; - GLuint m_FancyEffectsFBO; + std::unique_ptr m_RefractionFramebuffer; + std::unique_ptr m_ReflectionFramebuffer; + std::unique_ptr m_FancyEffectsFramebuffer; // Model-view-projection matrices for reflected & refracted cameras // (used to let the vertex shader do projective texturing) @@ -135,10 +139,9 @@ int LoadWaterTextures(); /** - * Resize: Updates the fancy water textures so that water will render correctly - * with fancy water. + * Recreates/loads needed water textures. */ - void Resize(); + void RecreateOrLoadTexturesIfNeeded(); /** * ReloadWaterNormalTextures: Reload the normal textures so that changing @@ -186,9 +189,18 @@ * Returns true if fancy water shaders will be used (i.e. the hardware is capable * and it hasn't been configured off) */ - bool WillRenderFancyWater(); + bool WillRenderFancyWater() const; + + void RenderWaves( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + const CFrustum& frustrum); - void RenderWaves(const CFrustum& frustrum); + /** + * Returns an index of the current texture that should be used for rendering + * water. + */ + size_t GetCurrentTextureIndex(const double& period) const; + size_t GetNextTextureIndex(const double& period) const; }; diff -Nru 0ad-0.0.25b/source/scriptinterface/JSON.cpp 0ad-0.0.26/source/scriptinterface/JSON.cpp --- 0ad-0.0.25b/source/scriptinterface/JSON.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/scriptinterface/JSON.cpp 2022-08-21 12:45:46.000000000 +0000 @@ -21,12 +21,13 @@ #include "ps/CStr.h" #include "ps/Filesystem.h" -#include "ps/utf16string.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptExceptions.h" #include "scriptinterface/ScriptRequest.h" #include "scriptinterface/ScriptTypes.h" +#include + // Ignore warnings in SM headers. #if GCC_VERSION || CLANG_VERSION # pragma GCC diagnostic push @@ -47,8 +48,8 @@ bool Script::ParseJSON(const ScriptRequest& rq, const std::string& string_utf8, JS::MutableHandleValue out) { std::wstring attrsW = wstring_from_utf8(string_utf8); - utf16string string(attrsW.begin(), attrsW.end()); - if (JS_ParseJSON(rq.cx, reinterpret_cast(string.c_str()), (u32)string.size(), out)) + std::u16string string(attrsW.begin(), attrsW.end()); + if (JS_ParseJSON(rq.cx, string.c_str(), (u32)string.size(), out)) return true; ScriptException::CatchPending(rq); @@ -85,7 +86,7 @@ { static bool callback(const char16_t* buf, u32 len, void* data) { - utf16string str(buf, buf+len); + std::u16string str(buf, buf+len); std::wstring strw(str.begin(), str.end()); Status err; // ignore Unicode errors diff -Nru 0ad-0.0.25b/source/scriptinterface/ScriptConversions.cpp 0ad-0.0.26/source/scriptinterface/ScriptConversions.cpp --- 0ad-0.0.25b/source/scriptinterface/ScriptConversions.cpp 2021-07-27 21:56:58.000000000 +0000 +++ 0ad-0.0.26/source/scriptinterface/ScriptConversions.cpp 2022-08-21 12:45:45.000000000 +0000 @@ -24,10 +24,11 @@ #include "graphics/Entity.h" #include "lib/file/vfs/vfs_path.h" #include "maths/Vector2D.h" -#include "ps/utf16string.h" #include "ps/CLogger.h" #include "ps/CStr.h" +#include + // Catch the raised exception right away to ensure the stack trace gets printed. #define FAIL(msg) STMT(ScriptException::Raise(rq, msg); ScriptException::CatchPending(rq); return false) @@ -222,8 +223,8 @@ template<> void Script::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::wstring& val) { - utf16string utf16(val.begin(), val.end()); - JS::RootedString str(rq.cx, JS_NewUCStringCopyN(rq.cx, reinterpret_cast (utf16.c_str()), utf16.length())); + std::u16string utf16(val.begin(), val.end()); + JS::RootedString str(rq.cx, JS_NewUCStringCopyN(rq.cx, utf16.c_str(), utf16.length())); if (str) ret.setString(str); else diff -Nru 0ad-0.0.25b/source/scriptinterface/ScriptExceptions.cpp 0ad-0.0.26/source/scriptinterface/ScriptExceptions.cpp --- 0ad-0.0.25b/source/scriptinterface/ScriptExceptions.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/scriptinterface/ScriptExceptions.cpp 2022-08-21 12:45:45.000000000 +0000 @@ -89,10 +89,6 @@ } LOGERROR("%s", msg.str().c_str()); - - // When running under Valgrind, print more information in the error message - // VALGRIND_PRINTF_BACKTRACE("->"); - return true; } diff -Nru 0ad-0.0.25b/source/scriptinterface/ScriptInterface.cpp 0ad-0.0.26/source/scriptinterface/ScriptInterface.cpp --- 0ad-0.0.25b/source/scriptinterface/ScriptInterface.cpp 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/scriptinterface/ScriptInterface.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,7 +29,6 @@ #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/Profile.h" -#include "ps/utf16string.h" #include #include @@ -43,8 +42,6 @@ #include #include -#include "valgrind.h" - /** * @file * Abstractions of various SpiderMonkey features. @@ -54,7 +51,7 @@ struct ScriptInterface_impl { - ScriptInterface_impl(const char* nativeScopeName, const std::shared_ptr& context); + ScriptInterface_impl(const char* nativeScopeName, const std::shared_ptr& context, JS::Compartment* compartment); ~ScriptInterface_impl(); // Take care to keep this declaration before heap rooted members. Destructors of heap rooted @@ -302,7 +299,7 @@ return true; } -ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const std::shared_ptr& context) : +ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const std::shared_ptr& context, JS::Compartment* compartment) : m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetGeneralJSContext()), m_nativeScope(context->GetGeneralJSContext()) { JS::RealmCreationOptions creationOpt; @@ -310,6 +307,13 @@ creationOpt.setPreserveJitCode(true); // Enable uneval creationOpt.setToSourceEnabled(true); + + if (compartment) + creationOpt.setExistingCompartment(compartment); + else + // This is the default behaviour. + creationOpt.setNewCompartmentAndZone(); + JS::RealmOptions opt(creationOpt, JS::RealmBehaviors{}); m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt); @@ -343,7 +347,7 @@ } ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const std::shared_ptr& context) : - m(std::make_unique(nativeScopeName, context)) + m(std::make_unique(nativeScopeName, context, nullptr)) { // Profiler stats table isn't thread-safe, so only enable this on the main thread if (Threading::IsMainThread()) @@ -357,6 +361,24 @@ JS::SetRealmPrivate(JS::GetObjectRealmOrNull(rq.glob), (void*)&m_CmptPrivate); } +ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const ScriptInterface& neighbor) +{ + ScriptRequest nrq(neighbor); + JS::Compartment* comp = JS::GetCompartmentForRealm(JS::GetCurrentRealmOrNull(nrq.cx)); + m = std::make_unique(nativeScopeName, neighbor.GetContext(), comp); + + // Profiler stats table isn't thread-safe, so only enable this on the main thread + if (Threading::IsMainThread()) + { + if (g_ScriptStatsTable) + g_ScriptStatsTable->Add(this, debugName); + } + + ScriptRequest rq(this); + m_CmptPrivate.pScriptInterface = this; + JS::SetRealmPrivate(JS::GetObjectRealmOrNull(rq.glob), (void*)&m_CmptPrivate); +} + ScriptInterface::~ScriptInterface() { if (Threading::IsMainThread()) @@ -451,8 +473,11 @@ return; } - JS::RootedObject ctorObj(rq.cx, &ctor.toObject()); - out.setObjectOrNull(JS_New(rq.cx, ctorObj, argv)); + JS::RootedObject objOut(rq.cx); + if (!JS::Construct(rq.cx, ctor, argv, &objOut)) + out.setNull(); + else + out.setObjectOrNull(objOut); } void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) @@ -638,7 +663,6 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const { - ScriptRequest rq(this); if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); @@ -657,21 +681,7 @@ CStr code = file.DecodeUTF8(); // assume it's UTF-8 - uint lineNo = 1; - // CompileOptions does not copy the contents of the filename string pointer. - // Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. - std::string filenameStr = path.string8(); - - JS::RootedValue rval(rq.cx); - JS::CompileOptions opts(rq.cx); - opts.setFileAndLine(filenameStr.c_str(), lineNo); - JS::SourceText src; - ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed)); - if (JS::Evaluate(rq.cx, opts, src, &rval)) - return true; - - ScriptException::CatchPending(rq); - return false; + return LoadGlobalScript(path, code); } bool ScriptInterface::Eval(const char* code) const diff -Nru 0ad-0.0.25b/source/scriptinterface/ScriptInterface.h 0ad-0.0.26/source/scriptinterface/ScriptInterface.h --- 0ad-0.0.25b/source/scriptinterface/ScriptInterface.h 2021-07-27 21:56:57.000000000 +0000 +++ 0ad-0.0.26/source/scriptinterface/ScriptInterface.h 2022-08-21 12:45:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -85,6 +85,16 @@ */ ScriptInterface(const char* nativeScopeName, const char* debugName, const std::shared_ptr& context); + /** + * Alternate constructor. This creates the new Realm in the same Compartment as the neighbor scriptInterface. + * This means that data can be freely exchanged between these two script interfaces without cloning. + * @param nativeScopeName Name of global object that functions (via ScriptFunction::Register) will + * be placed into, as a scoping mechanism; typically "Engine" + * @param debugName Name of this interface for CScriptStats purposes. + * @param scriptInterface 'Neighbor' scriptInterface to share a compartment with. + */ + ScriptInterface(const char* nativeScopeName, const char* debugName, const ScriptInterface& neighbor); + ~ScriptInterface(); struct CmptPrivate diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpAIManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpAIManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpAIManager.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpAIManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -57,27 +57,24 @@ * AI is primarily scripted, and the CCmpAIManager component defined here * takes care of managing all the scripts. * - * To avoid slow AI scripts causing jerky rendering, they are run in a background - * thread (maintained by CAIWorker) so that it's okay if they take a whole simulation - * turn before returning their results (though preferably they shouldn't use nearly - * that much CPU). + * The original idea was to run CAIWorker in a separate thread to prevent + * slow AIs from impacting framerate. However, copying the game-state every turn + * proved difficult and rather slow itself (and isn't threadable, obviously). + * For these reasons, the design was changed to a single-thread, same-compartment, different-realm design. + * The AI can therefore directly use the simulation data via the 'Sim' & 'SimEngine' globals. + * As a result, a lof of the code is still designed to be "thread-ready", but this no longer matters. * - * CCmpAIManager grabs the world state after each turn (making use of AIInterface.js - * and AIProxy.js to decide what data to include) then passes it to CAIWorker. - * The AI scripts will then run asynchronously and return a list of commands to execute. - * Any attempts to read the command list (including indirectly via serialization) - * will block until it's actually completed, so the rest of the engine should avoid - * reading it for as long as possible. + * TODO: despite the above, it would still be useful to allow the AI to run tasks asynchronously (and off-thread). + * This could be implemented by having a separate JS runtime in a different thread, + * that runs tasks and returns after a distinct # of simulation turns (to maintain determinism). * - * JS::Values are passed between the game and AI threads using Script::StructuredClone. - * - * TODO: actually the thread isn't implemented yet, because performance hasn't been - * sufficiently problematic to justify the complexity yet, but the CAIWorker interface - * is designed to hopefully support threading when we want it. + * Note also that the RL Interface, by default, uses the 'AI representation'. + * This representation, alimented by the JS AIInterface/AIProxy tandem, is likely to grow smaller over time + * as the AI uses more sim data directly. */ /** - * Implements worker thread for CCmpAIManager. + * AI computation orchestator for CCmpAIManager. */ class CAIWorker { @@ -206,27 +203,43 @@ std::shared_ptr m_ScriptInterface; JS::PersistentRootedValue m_Obj; - std::vector m_Commands; + std::vector m_Commands; }; public: struct SCommandSets { player_id_t player; - std::vector commands; + std::vector commands; }; CAIWorker() : - m_ScriptInterface(new ScriptInterface("Engine", "AI", g_ScriptContext)), m_TurnNum(0), m_CommandsComputed(true), m_HasLoadedEntityTemplates(false), - m_HasSharedComponent(false), - m_EntityTemplates(g_ScriptContext->GetGeneralJSContext()), - m_SharedAIObj(g_ScriptContext->GetGeneralJSContext()), - m_PassabilityMapVal(g_ScriptContext->GetGeneralJSContext()), - m_TerritoryMapVal(g_ScriptContext->GetGeneralJSContext()) + m_HasSharedComponent(false) + { + } + + ~CAIWorker() + { + // Init will always be called. + JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this); + } + + void Init(const ScriptInterface& simInterface) { + // Create the script interface in the same compartment as the simulation interface. + // This will allow us to directly share data from the sim to the AI (and vice versa, should the need arise). + m_ScriptInterface = std::make_shared("Engine", "AI", simInterface); + + ScriptRequest rq(m_ScriptInterface); + + m_EntityTemplates.init(rq.cx); + m_SharedAIObj.init(rq.cx); + m_PassabilityMapVal.init(rq.cx); + m_TerritoryMapVal.init(rq.cx); + m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG); @@ -234,7 +247,15 @@ JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this); - ScriptRequest rq(m_ScriptInterface); + { + ScriptRequest simrq(simInterface); + // Register the sim globals for easy & explicit access. Mark it replaceable for hotloading. + JS::RootedValue global(rq.cx, simrq.globalValue()); + m_ScriptInterface->SetGlobal("Sim", global, true); + JS::RootedValue scope(rq.cx, JS::ObjectValue(*simrq.nativeScope.get())); + m_ScriptInterface->SetGlobal("SimEngine", scope, true); + } + #define REGISTER_FUNC_NAME(func, name) \ ScriptFunction::Register<&CAIWorker::func, ScriptInterface::ObjectFromCBData>(rq, name); @@ -249,15 +270,11 @@ #undef REGISTER_FUNC_NAME - JSI_VFS::RegisterScriptFunctions_Simulation(rq); + JSI_VFS::RegisterScriptFunctions_ReadOnlySimulation(rq); // Globalscripts may use VFS script functions m_ScriptInterface->LoadGlobalScripts(); - } - ~CAIWorker() - { - JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this); } bool HasLoadedEntityTemplates() const { return m_HasLoadedEntityTemplates; } @@ -814,10 +831,6 @@ } } - // Take care to keep this declaration before heap rooted members. Destructors of heap rooted - // members have to be called before the context destructor. - std::shared_ptr m_ScriptContext; - std::shared_ptr m_ScriptInterface; boost::rand48 m_RNG; u32 m_TurnNum; @@ -854,7 +867,7 @@ /** * Implementation of ICmpAIManager. */ -class CCmpAIManager : public ICmpAIManager +class CCmpAIManager final : public ICmpAIManager { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -868,18 +881,20 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { + m_Worker.Init(GetSimContext().GetScriptInterface()); + m_TerritoriesDirtyID = 0; m_TerritoriesDirtyBlinkingID = 0; m_JustDeserialized = false; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberU32_Unbounded("num ais", m_Worker.getPlayerSize()); @@ -891,7 +906,7 @@ m_Worker.Serialize(serialize.GetStream(), serialize.IsDebug()); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); @@ -905,7 +920,7 @@ m_JustDeserialized = true; } - virtual void AddPlayer(const std::wstring& id, player_id_t player, u8 difficulty, const std::wstring& behavior) + void AddPlayer(const std::wstring& id, player_id_t player, u8 difficulty, const std::wstring& behavior) override { LoadUsedEntityTemplates(); @@ -919,17 +934,17 @@ cmpRangeManager->SetLosRevealAll(player, true); } - virtual void SetRNGSeed(u32 seed) + void SetRNGSeed(u32 seed) override { m_Worker.SetRNGSeed(seed); } - virtual void TryLoadSharedComponent() + void TryLoadSharedComponent() override { m_Worker.TryLoadSharedComponent(); } - virtual void RunGamestateInit() + void RunGamestateInit() override { const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); ScriptRequest rq(scriptInterface); @@ -966,7 +981,7 @@ *passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); } - virtual void StartComputation() + void StartComputation() override { PROFILE("AI setup"); @@ -1025,7 +1040,7 @@ m_JustDeserialized = false; } - virtual void PushCommands() + void PushCommands() override { std::vector commands; m_Worker.GetCommands(commands); diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpCinemaManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpCinemaManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpCinemaManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpCinemaManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,7 +29,7 @@ #include "simulation2/Simulation2.h" -class CCmpCinemaManager : public ICmpCinemaManager +class CCmpCinemaManager final : public ICmpCinemaManager { public: static void ClassInit(CComponentManager& componentManager) @@ -44,7 +44,7 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_Enabled = false; m_MapRevealed = false; @@ -53,11 +53,11 @@ m_CurrentPathElapsedTime = fixed::Zero(); } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serializer) + void Serialize(ISerializer& serializer) override { serializer.Bool("Enabled", m_Enabled); serializer.NumberFixed_Unbounded("ElapsedTime", m_ElapsedTime); @@ -73,7 +73,7 @@ serializer.String("PathName", path.GetName(), 1, 128); } - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserializer) + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserializer) override { deserializer.Bool("Enabled", m_Enabled); deserializer.NumberFixed_Unbounded("ElapsedTime", m_ElapsedTime); @@ -107,7 +107,7 @@ SetEnabled(m_Enabled); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -146,7 +146,7 @@ } } - virtual void AddPath(const CCinemaPath& path) + void AddPath(const CCinemaPath& path) override { if (m_Paths.find(path.GetName()) != m_Paths.end()) { @@ -156,7 +156,7 @@ m_Paths[path.GetName()] = path; } - virtual void AddCinemaPathToQueue(const CStrW& name) + void AddCinemaPathToQueue(const CStrW& name) override { if (!HasPath(name)) { @@ -170,27 +170,27 @@ m_TotalTime += m_Paths[name].GetDuration(); } - virtual void Play() + void Play() override { SetEnabled(true); } - virtual void Stop() + void Stop() override { SetEnabled(false); } - virtual bool HasPath(const CStrW& name) const + bool HasPath(const CStrW& name) const override { return m_Paths.find(name) != m_Paths.end(); } - virtual void ClearQueue() + void ClearQueue() override { m_PathQueue.clear(); } - virtual void DeletePath(const CStrW& name) + void DeletePath(const CStrW& name) override { if (!HasPath(name)) { @@ -201,27 +201,27 @@ m_Paths.erase(name); } - virtual const std::map& GetPaths() const + const std::map& GetPaths() const override { return m_Paths; } - virtual void SetPaths(const std::map& newPaths) + void SetPaths(const std::map& newPaths) override { m_Paths = newPaths; } - virtual const std::list& GetQueue() const + const std::list& GetQueue() const override { return m_PathQueue; } - virtual bool IsEnabled() const + bool IsEnabled() const override { return m_Enabled; } - virtual void SetEnabled(bool enabled) + void SetEnabled(bool enabled) override { if (m_PathQueue.empty() && enabled) enabled = false; @@ -246,7 +246,7 @@ m_Enabled = enabled; } - virtual void PlayQueue(const float deltaRealTime, CCamera* camera) + void PlayQueue(const float deltaRealTime, CCamera* camera) override { if (m_PathQueue.empty()) return; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpCommandQueue.cpp 0ad-0.0.26/source/simulation2/components/CCmpCommandQueue.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpCommandQueue.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpCommandQueue.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ #include "scriptinterface/JSON.h" #include "simulation2/system/TurnManager.h" -class CCmpCommandQueue : public ICmpCommandQueue +class CCmpCommandQueue final : public ICmpCommandQueue { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -43,15 +43,15 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { ScriptRequest rq(GetSimContext().GetScriptInterface()); @@ -63,7 +63,7 @@ } } - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) override { ScriptRequest rq(GetSimContext().GetScriptInterface()); @@ -79,13 +79,13 @@ } } - virtual void PushLocalCommand(player_id_t player, JS::HandleValue cmd) + void PushLocalCommand(player_id_t player, JS::HandleValue cmd) override { ScriptRequest rq(GetSimContext().GetScriptInterface()); m_LocalQueue.emplace_back(SimulationCommand(player, rq.cx, cmd)); } - virtual void PostNetworkCommand(JS::HandleValue cmd1) + void PostNetworkCommand(JS::HandleValue cmd1) override { ScriptRequest rq(GetSimContext().GetScriptInterface()); @@ -100,7 +100,7 @@ g_Game->GetTurnManager()->PostCommand(cmd); } - virtual void FlushTurn(const std::vector& commands) + void FlushTurn(const std::vector& commands) override { const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); ScriptRequest rq(scriptInterface); diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpDecay.cpp 0ad-0.0.26/source/simulation2/components/CCmpDecay.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpDecay.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpDecay.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -44,7 +44,7 @@ * * Must not be used on network-synchronised entities, unless \ is present. */ -class CCmpDecay : public ICmpDecay +class CCmpDecay final : public ICmpDecay { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -89,7 +89,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_Active = paramNode.GetChild("Active").ToBool(); m_ShipSink = paramNode.GetChild("SinkingAnim").ToBool(); @@ -111,21 +111,21 @@ GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Interpolate, this, true); } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { // This component isn't network-synchronised, so don't serialize anything } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpFootprint.cpp 0ad-0.0.26/source/simulation2/components/CCmpFootprint.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpFootprint.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpFootprint.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,7 +31,7 @@ #include "simulation2/MessageTypes.h" #include "maths/FixedVector2D.h" -class CCmpFootprint : public ICmpFootprint +class CCmpFootprint final : public ICmpFootprint { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -92,7 +92,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { if (paramNode.GetChild("Square").IsOk()) { @@ -121,21 +121,21 @@ m_MaxSpawnDistance = entity_pos_t::FromInt(7); } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { // No dynamic state to serialize } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void GetShape(EShape& shape, entity_pos_t& size0, entity_pos_t& size1, entity_pos_t& height) const + void GetShape(EShape& shape, entity_pos_t& size0, entity_pos_t& size1, entity_pos_t& height) const override { shape = m_Shape; size0 = m_Size0; @@ -143,7 +143,7 @@ height = m_Height; } - virtual CFixedVector3D PickSpawnPoint(entity_id_t spawned) const + CFixedVector3D PickSpawnPoint(entity_id_t spawned) const override { PROFILE3("PickSpawnPoint"); @@ -269,7 +269,7 @@ return error; } - virtual CFixedVector3D PickSpawnPointBothPass(entity_id_t spawned) const + CFixedVector3D PickSpawnPointBothPass(entity_id_t spawned) const override { PROFILE3("PickSpawnPointBothPass"); diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpMinimap.cpp 0ad-0.0.26/source/simulation2/components/CCmpMinimap.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpMinimap.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpMinimap.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ #include "graphics/Color.h" -class CCmpMinimap : public ICmpMinimap +class CCmpMinimap final : public ICmpMinimap { public: static void ClassInit(CComponentManager& componentManager) @@ -57,6 +57,10 @@ double m_PingEndTime; bool m_IsPinging; + bool m_HasIcon = false; + std::string m_IconPath; + float m_IconSize = 16.0f; + static std::string GetSchema() { return @@ -84,14 +88,23 @@ "0255" "" "" + "" + "" + "" + "" + "0" + "" + "" + "" ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_Active = true; m_IsPinging = false; m_PingEndTime = 0.0; + m_HasIcon = false; const CParamNode& color = paramNode.GetChild("Color"); if (color.IsOk()) @@ -109,9 +122,21 @@ m_G = 0; m_B = 255; } + + const CParamNode& iconNode = paramNode.GetChild("Icon"); + if (iconNode.IsOk()) + { + const CParamNode& iconSizeNode = iconNode.GetChild("@size"); + if (iconSizeNode.IsOk()) + { + m_HasIcon = true; + m_IconPath = "art/textures/ui/session/icons/minimap/" + iconNode.ToString(); + m_IconSize = iconSizeNode.ToFloat(); + } + } } - virtual void Deinit() + void Deinit() override { } @@ -127,19 +152,19 @@ } } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { SerializeCommon(serialize); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); SerializeCommon(deserialize); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -182,7 +207,7 @@ } } - virtual bool GetRenderData(u8& r, u8& g, u8& b, entity_pos_t& x, entity_pos_t& z) const + bool GetRenderData(u8& r, u8& g, u8& b, entity_pos_t& x, entity_pos_t& z) const override { if (!m_Active) return false; @@ -195,7 +220,7 @@ return true; } - virtual bool CheckPing(double currentTime, double pingDuration) + bool CheckPing(double currentTime, double pingDuration) override { if (!m_Active || !m_IsPinging) return false; @@ -212,7 +237,7 @@ return m_IsPinging; } - virtual void UpdateColor() + void UpdateColor() override { if (!m_UsePlayerColor) return; @@ -238,6 +263,21 @@ m_G = (u8) (color.g * 255); m_B = (u8) (color.b * 255); } + + bool HasIcon() override + { + return m_HasIcon; + } + + std::string GetIconPath() override + { + return m_IconPath; + } + + float GetIconSize() override + { + return m_IconSize; + } }; REGISTER_COMPONENT_TYPE(Minimap) diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpMotionBall.cpp 0ad-0.0.26/source/simulation2/components/CCmpMotionBall.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpMotionBall.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpMotionBall.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,7 +25,7 @@ #include "graphics/Terrain.h" -class CCmpMotionBall : public ICmpMotion +class CCmpMotionBall final : public ICmpMotion { public: static void ClassInit(CComponentManager& componentManager) @@ -43,30 +43,30 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_SpeedX = 0; m_SpeedZ = 0; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberFloat_Unbounded("speed x", m_SpeedX); serialize.NumberFloat_Unbounded("speed z", m_SpeedZ); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); deserialize.NumberFloat_Unbounded("speed x", m_SpeedX); deserialize.NumberFloat_Unbounded("speed z", m_SpeedZ); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpObstruction.cpp 0ad-0.0.26/source/simulation2/components/CCmpObstruction.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpObstruction.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpObstruction.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -43,7 +43,7 @@ * Obstruction implementation. This keeps the ICmpPathfinder's model of the world updated when the * entities move and die, with shapes derived from ICmpFootprint. */ -class CCmpObstruction : public ICmpObstruction +class CCmpObstruction final : public ICmpObstruction { public: static void ClassInit(CComponentManager& componentManager) @@ -196,7 +196,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { // The minimum obstruction size is the navcell size * sqrt(2) // This is enforced in the schema as a minimum of 1.5 @@ -273,7 +273,7 @@ m_ControlGroup2 = INVALID_ENTITY; } - virtual void Deinit() + void Deinit() override { } @@ -292,19 +292,19 @@ serialize.NumberFixed_Unbounded("clearance", m_Clearance); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { SerializeCommon(serialize); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); SerializeCommon(deserialize); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -380,7 +380,7 @@ } } - virtual void SetActive(bool active) + void SetActive(bool active) override { if (active && !m_Active && !m_IsDestroyed) { @@ -446,7 +446,7 @@ // else we didn't change the active status } - virtual void SetDisableBlockMovementPathfinding(bool movementDisabled, bool pathfindingDisabled, int32_t shape) + void SetDisableBlockMovementPathfinding(bool movementDisabled, bool pathfindingDisabled, int32_t shape) override { flags_t *flags = NULL; if (shape == -1) @@ -476,27 +476,27 @@ } } - virtual bool GetBlockMovementFlag(bool templateOnly) const + bool GetBlockMovementFlag(bool templateOnly) const override { return m_Active && ((templateOnly ? m_TemplateFlags : m_Flags) & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT) != 0; } - virtual EObstructionType GetObstructionType() const + EObstructionType GetObstructionType() const override { return m_Type; } - virtual ICmpObstructionManager::tag_t GetObstruction() const + ICmpObstructionManager::tag_t GetObstruction() const override { return m_Tag; } - virtual bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) const + bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) const override { return GetObstructionSquare(out, true); } - virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) const + bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) const override { return GetObstructionSquare(out, false); } @@ -526,7 +526,7 @@ return true; } - virtual entity_pos_t GetSize() const + entity_pos_t GetSize() const override { if (m_Type == UNIT) return m_Clearance; @@ -534,12 +534,12 @@ return CFixedVector2D(m_Size0 / 2, m_Size1 / 2).Length(); } - virtual CFixedVector2D GetStaticSize() const + CFixedVector2D GetStaticSize() const override { return m_Type == STATIC ? CFixedVector2D(m_Size0, m_Size1) : CFixedVector2D(); } - virtual void SetUnitClearance(const entity_pos_t& clearance) + void SetUnitClearance(const entity_pos_t& clearance) override { // This doesn't send a MovementObstructionChanged message // because it's a just a workaround init order, and used in UnitMotion directly. @@ -547,12 +547,12 @@ m_Clearance = clearance; } - virtual bool IsControlPersistent() const + bool IsControlPersistent() const override { return m_ControlPersist; } - virtual bool CheckShorePlacement() const + bool CheckShorePlacement() const override { ICmpObstructionManager::ObstructionSquare s; if (!GetObstructionSquare(s)) @@ -571,12 +571,12 @@ cmpWaterManager->GetWaterLevel( back.X, back.Y) - cmpTerrain->GetGroundLevel( back.X, back.Y) < fixed::FromInt(2); } - virtual EFoundationCheck CheckFoundation(const std::string& className) const + EFoundationCheck CheckFoundation(const std::string& className) const override { return CheckFoundation(className, false); } - virtual EFoundationCheck CheckFoundation(const std::string& className, bool onlyCenterPoint) const + EFoundationCheck CheckFoundation(const std::string& className, bool onlyCenterPoint) const override { CmpPtr cmpPosition(GetEntityHandle()); if (!cmpPosition) @@ -613,7 +613,7 @@ return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass, onlyCenterPoint); } - virtual bool CheckDuplicateFoundation() const + bool CheckDuplicateFoundation() const override { CmpPtr cmpPosition(GetEntityHandle()); if (!cmpPosition) @@ -645,7 +645,7 @@ return !cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, NULL ); } - virtual std::vector GetEntitiesByFlags(flags_t flags) const + std::vector GetEntitiesByFlags(flags_t flags) const override { std::vector ret; @@ -668,22 +668,22 @@ return ret; } - virtual std::vector GetEntitiesBlockingMovement() const + std::vector GetEntitiesBlockingMovement() const override { return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); } - virtual std::vector GetEntitiesBlockingConstruction() const + std::vector GetEntitiesBlockingConstruction() const override { return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION); } - virtual std::vector GetEntitiesDeletedUponConstruction() const + std::vector GetEntitiesDeletedUponConstruction() const override { return GetEntitiesByFlags(ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION); } - virtual void SetMovingFlag(bool enabled) + void SetMovingFlag(bool enabled) override { m_Moving = enabled; @@ -695,24 +695,24 @@ } } - virtual void SetControlGroup(entity_id_t group) + void SetControlGroup(entity_id_t group) override { m_ControlGroup = group; UpdateControlGroups(); } - virtual void SetControlGroup2(entity_id_t group2) + void SetControlGroup2(entity_id_t group2) override { m_ControlGroup2 = group2; UpdateControlGroups(); } - virtual entity_id_t GetControlGroup() const + entity_id_t GetControlGroup() const override { return m_ControlGroup; } - virtual entity_id_t GetControlGroup2() const + entity_id_t GetControlGroup2() const override { return m_ControlGroup2; } @@ -744,7 +744,7 @@ } } - void ResolveFoundationCollisions() const + void ResolveFoundationCollisions() const override { if (m_Type == UNIT) return; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpObstructionManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpObstructionManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpObstructionManager.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpObstructionManager.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include "ICmpObstructionManager.h" #include "ICmpPosition.h" +#include "ICmpRangeManager.h" #include "simulation2/MessageTypes.h" #include "simulation2/helpers/Geometry.h" @@ -122,7 +123,7 @@ } }; -class CCmpObstructionManager : public ICmpObstructionManager +class CCmpObstructionManager final : public ICmpObstructionManager { public: static void ClassInit(CComponentManager& componentManager) @@ -159,7 +160,7 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_DebugOverlayEnabled = false; m_DebugOverlayDirty = true; @@ -179,7 +180,7 @@ ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024)); } - virtual void Deinit() + void Deinit() override { } @@ -204,7 +205,7 @@ serialize.NumberFixed_Unbounded("world z1", m_WorldZ1); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { // TODO: this could perhaps be optimised by not storing all the obstructions, // and instead regenerating them from the other entities on Deserialize @@ -212,7 +213,7 @@ SerializeCommon(serialize); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); @@ -222,7 +223,7 @@ m_UpdateInformations.dirtinessGrid = Grid(size, size); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -237,7 +238,7 @@ // NB: on deserialization, this function is not called after the component is reset. // So anything that happens here should be safely serialized. - virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) + void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) override { m_WorldX0 = x0; m_WorldZ0 = z0; @@ -277,7 +278,7 @@ } } - virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance, flags_t flags, entity_id_t group) + tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance, flags_t flags, entity_id_t group) override { UnitShape shape = { ent, x, z, clearance, flags, group }; u32 id = m_UnitShapeNext++; @@ -290,7 +291,7 @@ return UNIT_INDEX_TO_TAG(id); } - virtual tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 /* = INVALID_ENTITY */) + tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 /* = INVALID_ENTITY */) override { fixed s, c; sincos_approx(a, s, c); @@ -310,7 +311,7 @@ return STATIC_INDEX_TO_TAG(id); } - virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t clearance) const + ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t clearance) const override { CFixedVector2D u(entity_pos_t::FromInt(1), entity_pos_t::Zero()); CFixedVector2D v(entity_pos_t::Zero(), entity_pos_t::FromInt(1)); @@ -318,7 +319,7 @@ return o; } - virtual ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h) const + ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h) const override { fixed s, c; sincos_approx(a, s, c); @@ -329,7 +330,7 @@ return o; } - virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) + void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) override { ENSURE(TAG_IS_VALID(tag)); @@ -378,7 +379,7 @@ } } - virtual void SetUnitMovingFlag(tag_t tag, bool moving) + void SetUnitMovingFlag(tag_t tag, bool moving) override { ENSURE(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag)); @@ -394,7 +395,7 @@ } } - virtual void SetUnitControlGroup(tag_t tag, entity_id_t group) + void SetUnitControlGroup(tag_t tag, entity_id_t group) override { ENSURE(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag)); @@ -405,7 +406,7 @@ } } - virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) + void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) override { ENSURE(TAG_IS_VALID(tag) && TAG_IS_STATIC(tag)); @@ -417,7 +418,7 @@ } } - virtual void RemoveShape(tag_t tag) + void RemoveShape(tag_t tag) override { ENSURE(TAG_IS_VALID(tag)); @@ -446,7 +447,7 @@ } } - virtual ObstructionSquare GetObstruction(tag_t tag) const + ObstructionSquare GetObstruction(tag_t tag) const override { ENSURE(TAG_IS_VALID(tag)); @@ -466,30 +467,31 @@ } } - virtual fixed DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const; - virtual fixed MaxDistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const; - virtual fixed DistanceToTarget(entity_id_t ent, entity_id_t target) const; - virtual fixed MaxDistanceToTarget(entity_id_t ent, entity_id_t target) const; - virtual fixed DistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const; - virtual fixed MaxDistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const; - - virtual bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const; - virtual bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const; - virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const; - virtual bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const; - - virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits = false) const; - virtual bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector* out) const; - virtual bool TestUnitShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector* out) const; - - virtual void Rasterize(Grid& grid, const std::vector& passClasses, bool fullUpdate); - virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const; - virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const; - virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const; - virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter, bool strict = false) const; - virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter) const; + fixed DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const override; + fixed MaxDistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const override; + fixed DistanceToTarget(entity_id_t ent, entity_id_t target) const override; + fixed MaxDistanceToTarget(entity_id_t ent, entity_id_t target) const override; + fixed DistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const override; + fixed MaxDistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const override; + + bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const override; + bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const override; + bool IsInTargetParabolicRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, bool opposite) const override; + bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const override; + bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const override; + + bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits = false) const override; + bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector* out) const override; + bool TestUnitShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector* out) const override; + + void Rasterize(Grid& grid, const std::vector& passClasses, bool fullUpdate) override; + void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const override; + void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const override; + void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const override; + void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter, bool strict = false) const override; + void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter) const override; - virtual void SetPassabilityCircular(bool enabled) + void SetPassabilityCircular(bool enabled) override { m_PassabilityCircular = enabled; MakeDirtyAll(); @@ -498,12 +500,12 @@ GetSimContext().GetComponentManager().BroadcastMessage(msg); } - virtual bool GetPassabilityCircular() const + bool GetPassabilityCircular() const override { return m_PassabilityCircular; } - virtual void SetDebugOverlay(bool enabled) + void SetDebugOverlay(bool enabled) override { m_DebugOverlayEnabled = enabled; m_DebugOverlayDirty = true; @@ -513,7 +515,7 @@ void RenderSubmit(SceneCollector& collector); - virtual void UpdateInformations(GridUpdateInformation& informations) + void UpdateInformations(GridUpdateInformation& informations) override { if (!m_UpdateInformations.dirtinessGrid.blank()) informations.MergeAndClear(m_UpdateInformations); @@ -816,39 +818,43 @@ * to set the opposite bool false and use the edge to egde distance. * * We don't use squares because the are likely to overflow. + * TODO Avoid the overflows and use squares instead. * We use a 0.0001 margin to avoid rounding errors. */ bool CCmpObstructionManager::IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const { fixed dist = DistanceToPoint(ent, px, pz); - // Treat -1 max range as infinite - return dist != fixed::FromInt(-1) && - (dist <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange < fixed::Zero()) && + return maxRange != NEVER_IN_RANGE && dist != fixed::FromInt(-1) && + (dist <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange == ALWAYS_IN_RANGE) && (opposite ? MaxDistanceToPoint(ent, px, pz) : dist) >= minRange - fixed::FromFloat(0.0001f); } bool CCmpObstructionManager::IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const { fixed dist = DistanceToTarget(ent, target); - // Treat -1 max range as infinite - return dist != fixed::FromInt(-1) && - (dist <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange < fixed::Zero()) && + return maxRange != NEVER_IN_RANGE && dist != fixed::FromInt(-1) && + (dist <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange == ALWAYS_IN_RANGE) && (opposite ? MaxDistanceToTarget(ent, target) : dist) >= minRange - fixed::FromFloat(0.0001f); } + +bool CCmpObstructionManager::IsInTargetParabolicRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, bool opposite) const +{ + CmpPtr cmpRangeManager(GetSystemEntity()); + return IsInTargetRange(ent, target, minRange, cmpRangeManager->GetEffectiveParabolicRange(ent, target, maxRange, yOrigin), opposite); +} + bool CCmpObstructionManager::IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const { entity_pos_t distance = (CFixedVector2D(x, z) - CFixedVector2D(px, pz)).Length(); - // Treat -1 max range as infinite - return (distance <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange < fixed::Zero()) && + return maxRange != NEVER_IN_RANGE && (distance <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange == ALWAYS_IN_RANGE) && distance >= minRange - fixed::FromFloat(0.0001f); } bool CCmpObstructionManager::AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const { fixed dist = DistanceBetweenShapes(source, target); - // Treat -1 max range as infinite - return dist != fixed::FromInt(-1) && - (dist <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange < fixed::Zero()) && + return maxRange != NEVER_IN_RANGE && dist != fixed::FromInt(-1) && + (dist <= (maxRange + fixed::FromFloat(0.0001f)) || maxRange == ALWAYS_IN_RANGE) && (opposite ? MaxDistanceBetweenShapes(source, target) : dist) >= minRange - fixed::FromFloat(0.0001f); } diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpOverlayRenderer.cpp 0ad-0.0.26/source/simulation2/components/CCmpOverlayRenderer.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpOverlayRenderer.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpOverlayRenderer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ #include "ps/CLogger.h" #include "ps/Profile.h" -class CCmpOverlayRenderer : public ICmpOverlayRenderer +class CCmpOverlayRenderer final : public ICmpOverlayRenderer { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -54,27 +54,27 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { // TODO: should we do anything here? // or should we expect other components to reinitialise us // after deserialization? } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -107,7 +107,7 @@ GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, needRender); } - virtual void Reset() + void Reset() override { m_Sprites.clear(); m_SpriteOffsets.clear(); @@ -115,7 +115,7 @@ UpdateMessageSubscriptions(); } - virtual void AddSprite(const VfsPath& textureName, const CFixedVector2D& corner0, const CFixedVector2D& corner1, const CFixedVector3D& position, const std::string& color) + void AddSprite(const VfsPath& textureName, const CFixedVector2D& corner0, const CFixedVector2D& corner1, const CFixedVector3D& position, const std::string& color) override { CColor colorObj(1.0f, 1.0f, 1.0f, 1.0f); if (!colorObj.ParseString(color, 1)) diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpOwnership.cpp 0ad-0.0.26/source/simulation2/components/CCmpOwnership.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpOwnership.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpOwnership.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,7 +25,7 @@ /** * Basic ICmpOwnership implementation. */ -class CCmpOwnership : public ICmpOwnership +class CCmpOwnership final : public ICmpOwnership { public: static void ClassInit(CComponentManager& componentManager) @@ -45,26 +45,26 @@ ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_Owner = INVALID_PLAYER; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberI32_Unbounded("owner", m_Owner); } - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) override { deserialize.NumberI32_Unbounded("owner", m_Owner); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -77,12 +77,12 @@ } } - virtual player_id_t GetOwner() const + player_id_t GetOwner() const override { return m_Owner; } - virtual void SetOwner(player_id_t playerID) + void SetOwner(player_id_t playerID) override { if (playerID == m_Owner) return; @@ -94,7 +94,7 @@ GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); } - virtual void SetOwnerQuiet(player_id_t playerID) + void SetOwnerQuiet(player_id_t playerID) override { if (playerID != m_Owner) m_Owner = playerID; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpParticleManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpParticleManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpParticleManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpParticleManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,12 +20,12 @@ #include "simulation2/system/Component.h" #include "ICmpParticleManager.h" -#include "simulation2/MessageTypes.h" - #include "graphics/ParticleManager.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" +#include "simulation2/MessageTypes.h" -class CCmpParticleManager : public ICmpParticleManager +class CCmpParticleManager final : public ICmpParticleManager { public: static void ClassInit(CComponentManager& componentManager) @@ -42,25 +42,25 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { useSimTime = true; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -70,14 +70,14 @@ if (CRenderer::IsInitialised()) { float time = useSimTime ? msgData.deltaSimTime : msgData.deltaRealTime; - g_Renderer.GetParticleManager().Interpolate(time); + g_Renderer.GetSceneRenderer().GetParticleManager().Interpolate(time); } break; } } } - virtual void SetUseSimTime(bool flag) + void SetUseSimTime(bool flag) override { useSimTime = flag; } diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpPathfinder_Common.h 0ad-0.0.26/source/simulation2/components/CCmpPathfinder_Common.h --- 0ad-0.0.25b/source/simulation2/components/CCmpPathfinder_Common.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpPathfinder_Common.h 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -149,29 +149,29 @@ return ""; } - virtual void Init(const CParamNode& paramNode); + void Init(const CParamNode& paramNode) override; - virtual void Deinit(); + void Deinit() override; template void SerializeCommon(S& serialize); - virtual void Serialize(ISerializer& serialize); + void Serialize(ISerializer& serialize) override; - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize); + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override; - virtual void HandleMessage(const CMessage& msg, bool global); + void HandleMessage(const CMessage& msg, bool global) override; - virtual pass_class_t GetPassabilityClass(const std::string& name) const; + pass_class_t GetPassabilityClass(const std::string& name) const override; - virtual void GetPassabilityClasses(std::map& passClasses) const; - virtual void GetPassabilityClasses( + void GetPassabilityClasses(std::map& passClasses) const override; + void GetPassabilityClasses( std::map& nonPathfindingPassClasses, - std::map& pathfindingPassClasses) const; + std::map& pathfindingPassClasses) const override; const PathfinderPassability* GetPassabilityFromMask(pass_class_t passClass) const; - virtual entity_pos_t GetClearance(pass_class_t passClass) const + entity_pos_t GetClearance(pass_class_t passClass) const override { const PathfinderPassability* passability = GetPassabilityFromMask(passClass); if (!passability) @@ -180,7 +180,7 @@ return passability->m_Clearance; } - virtual entity_pos_t GetMaximumClearance() const + entity_pos_t GetMaximumClearance() const override { entity_pos_t max = fixed::Zero(); @@ -191,51 +191,51 @@ return max + Pathfinding::CLEARANCE_EXTENSION_RADIUS; } - virtual const Grid& GetPassabilityGrid(); + const Grid& GetPassabilityGrid() override; - virtual const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const + const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const override { return m_AIPathfinderDirtinessInformation; } - virtual void FlushAIPathfinderDirtinessInformation() + void FlushAIPathfinderDirtinessInformation() override { m_AIPathfinderDirtinessInformation.Clean(); } - virtual Grid ComputeShoreGrid(bool expandOnWater = false); + Grid ComputeShoreGrid(bool expandOnWater = false) override; - virtual void ComputePathImmediate(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret) const; + void ComputePathImmediate(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret) const override; - virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify); + u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify) override; - virtual WaypointPath ComputeShortPathImmediate(const ShortPathRequest& request) const; + WaypointPath ComputeShortPathImmediate(const ShortPathRequest& request) const override; - virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify); + u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify) override; - virtual bool IsGoalReachable(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass); + bool IsGoalReachable(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass) override; - virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass); + void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass) override; - virtual void SetDebugOverlay(bool enabled); + void SetDebugOverlay(bool enabled) override; - virtual void SetHierDebugOverlay(bool enabled); + void SetHierDebugOverlay(bool enabled) override; - virtual void GetDebugData(u32& steps, double& time, Grid& grid) const; + void GetDebugData(u32& steps, double& time, Grid& grid) const override; - virtual void SetAtlasOverlay(bool enable, pass_class_t passClass = 0); + void SetAtlasOverlay(bool enable, pass_class_t passClass = 0) override; - virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass) const; + bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass) const override; - virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass, bool onlyCenterPoint) const; + ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass, bool onlyCenterPoint) const override; - virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass) const; + ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass) const override; - virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint) const; + ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint) const override; - virtual void SendRequestedPaths(); + void SendRequestedPaths() override; - virtual void StartProcessingMoves(bool useMax); + void StartProcessingMoves(bool useMax) override; template std::vector GetMovesToProcess(std::vector& requests, bool useMax = false, size_t maxMoves = 0); @@ -246,7 +246,7 @@ /** * Regenerates the grid based on the current obstruction list, if necessary */ - virtual void UpdateGrid(); + void UpdateGrid() override; /** * Updates the terrain-only grid without updating the dirtiness informations. @@ -274,7 +274,7 @@ { } - virtual void BuildTextureRGBA(u8* data, size_t w, size_t h) + void BuildTextureRGBA(u8* data, size_t w, size_t h) override { // Render navcell passability, based on the terrain-only grid u8* p = data; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpPathfinder.cpp 0ad-0.0.26/source/simulation2/components/CCmpPathfinder.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpPathfinder.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpPathfinder.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -626,10 +626,10 @@ // We need to extend the boundaries by 1 tile, because slope and ground // level are calculated by multiple neighboring tiles. // TODO: add CTerrain constant instead of 1. - istart = Clamp(itile0 - 1, 0, m_GridSize); - iend = Clamp(itile1 + 1, 0, m_GridSize); - jstart = Clamp(jtile0 - 1, 0, m_GridSize); - jend = Clamp(jtile1 + 1, 0, m_GridSize); + istart = Clamp((itile0 - 1) * Pathfinding::NAVCELLS_PER_TERRAIN_TILE, 0, m_GridSize); + iend = Clamp((itile1 + 1) * Pathfinding::NAVCELLS_PER_TERRAIN_TILE, 0, m_GridSize); + jstart = Clamp((jtile0 - 1) * Pathfinding::NAVCELLS_PER_TERRAIN_TILE, 0, m_GridSize); + jend = Clamp((jtile1 + 1) * Pathfinding::NAVCELLS_PER_TERRAIN_TILE, 0, m_GridSize); } // Compute initial terrain-dependent passability diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpPosition.cpp 0ad-0.0.26/source/simulation2/components/CCmpPosition.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpPosition.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpPosition.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -40,7 +40,7 @@ /** * Basic ICmpPosition implementation. */ -class CCmpPosition : public ICmpPosition +class CCmpPosition final : public ICmpPosition { public: static void ClassInit(CComponentManager& componentManager) @@ -136,7 +136,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { const std::string& anchor = paramNode.GetChild("Anchor").ToString(); if (anchor == "pitch") @@ -171,11 +171,11 @@ m_EnabledMessageInterpolate = false; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.Bool("in world", m_InWorld); if (m_InWorld) @@ -232,7 +232,7 @@ Serializer(serialize, "turrets", m_Turrets); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); @@ -280,7 +280,7 @@ AdvertiseInterpolatedPositionChanges(); } - virtual void UpdateTurretPosition() + void UpdateTurretPosition() override { if (m_TurretParent == INVALID_ENTITY) return; @@ -308,12 +308,12 @@ } } - virtual std::set* GetTurrets() + std::set* GetTurrets() override { return &m_Turrets; } - virtual void SetTurretParent(entity_id_t id, const CFixedVector3D& offset) + void SetTurretParent(entity_id_t id, const CFixedVector3D& offset) override { entity_angle_t angle = GetRotation().Y; if (m_TurretParent != INVALID_ENTITY) @@ -336,17 +336,17 @@ UpdateTurretPosition(); } - virtual entity_id_t GetTurretParent() const + entity_id_t GetTurretParent() const override { return m_TurretParent; } - virtual bool IsInWorld() const + bool IsInWorld() const override { return m_InWorld; } - virtual void MoveOutOfWorld() + void MoveOutOfWorld() override { m_InWorld = false; @@ -354,7 +354,7 @@ AdvertiseInterpolatedPositionChanges(); } - virtual void MoveTo(entity_pos_t x, entity_pos_t z) + void MoveTo(entity_pos_t x, entity_pos_t z) override { m_X = x; m_Z = z; @@ -371,7 +371,7 @@ AdvertiseInterpolatedPositionChanges(); } - virtual void MoveAndTurnTo(entity_pos_t x, entity_pos_t z, entity_angle_t ry) + void MoveAndTurnTo(entity_pos_t x, entity_pos_t z, entity_angle_t ry) override { m_X = x; m_Z = z; @@ -390,7 +390,7 @@ AdvertiseInterpolatedPositionChanges(); } - virtual void JumpTo(entity_pos_t x, entity_pos_t z) + void JumpTo(entity_pos_t x, entity_pos_t z) override { m_LastX = m_PrevX = m_X = x; m_LastZ = m_PrevZ = m_Z = z; @@ -405,7 +405,7 @@ AdvertiseInterpolatedPositionChanges(); } - virtual void SetHeightOffset(entity_pos_t dy) + void SetHeightOffset(entity_pos_t dy) override { // subtract the offset and replace with a new offset m_LastYDifference = dy - GetHeightOffset(); @@ -413,7 +413,7 @@ AdvertiseInterpolatedPositionChanges(); } - virtual entity_pos_t GetHeightOffset() const + entity_pos_t GetHeightOffset() const override { if (m_RelativeToGround) return m_Y; @@ -433,7 +433,7 @@ return m_Y - baseY; } - virtual void SetHeightFixed(entity_pos_t y) + void SetHeightFixed(entity_pos_t y) override { // subtract the absolute height and replace it with a new absolute height m_LastYDifference = y - GetHeightFixed(); @@ -441,12 +441,12 @@ AdvertiseInterpolatedPositionChanges(); } - virtual entity_pos_t GetHeightFixed() const + entity_pos_t GetHeightFixed() const override { return GetHeightAtFixed(m_X, m_Z); } - virtual entity_pos_t GetHeightAtFixed(entity_pos_t x, entity_pos_t z) const + entity_pos_t GetHeightAtFixed(entity_pos_t x, entity_pos_t z) const override { if (!m_RelativeToGround) return m_Y; @@ -466,12 +466,12 @@ return m_Y + baseY; } - virtual bool IsHeightRelative() const + bool IsHeightRelative() const override { return m_RelativeToGround; } - virtual void SetHeightRelative(bool relative) + void SetHeightRelative(bool relative) override { // move y to use the right offset (from terrain or from map origin) m_Y = relative ? GetHeightOffset() : GetHeightFixed(); @@ -480,30 +480,30 @@ AdvertiseInterpolatedPositionChanges(); } - virtual bool CanFloat() const + bool CanFloat() const override { return m_Floating; } - virtual void SetFloating(bool flag) + void SetFloating(bool flag) override { m_Floating = flag; AdvertiseInterpolatedPositionChanges(); } - virtual void SetActorFloating(bool flag) + void SetActorFloating(bool flag) override { m_ActorFloating = flag; AdvertiseInterpolatedPositionChanges(); } - virtual void SetConstructionProgress(fixed progress) + void SetConstructionProgress(fixed progress) override { m_ConstructionProgress = progress; AdvertiseInterpolatedPositionChanges(); } - virtual CFixedVector3D GetPosition() const + CFixedVector3D GetPosition() const override { if (!m_InWorld) { @@ -514,7 +514,7 @@ return CFixedVector3D(m_X, GetHeightFixed(), m_Z); } - virtual CFixedVector2D GetPosition2D() const + CFixedVector2D GetPosition2D() const override { if (!m_InWorld) { @@ -525,7 +525,7 @@ return CFixedVector2D(m_X, m_Z); } - virtual CFixedVector3D GetPreviousPosition() const + CFixedVector3D GetPreviousPosition() const override { if (!m_InWorld) { @@ -536,7 +536,7 @@ return CFixedVector3D(m_PrevX, GetHeightAtFixed(m_PrevX, m_PrevZ), m_PrevZ); } - virtual CFixedVector2D GetPreviousPosition2D() const + CFixedVector2D GetPreviousPosition2D() const override { if (!m_InWorld) { @@ -547,12 +547,12 @@ return CFixedVector2D(m_PrevX, m_PrevZ); } - virtual fixed GetTurnRate() const + fixed GetTurnRate() const override { return m_RotYSpeed; } - virtual void TurnTo(entity_angle_t y) + void TurnTo(entity_angle_t y) override { if (m_TurretParent != INVALID_ENTITY) { @@ -566,7 +566,7 @@ UpdateMessageSubscriptions(); } - virtual void SetYRotation(entity_angle_t y) + void SetYRotation(entity_angle_t y) override { if (m_TurretParent != INVALID_ENTITY) { @@ -589,7 +589,7 @@ UpdateMessageSubscriptions(); } - virtual void SetXZRotation(entity_angle_t x, entity_angle_t z) + void SetXZRotation(entity_angle_t x, entity_angle_t z) override { m_RotX = x; m_RotZ = z; @@ -603,7 +603,7 @@ } } - virtual CFixedVector3D GetRotation() const + CFixedVector3D GetRotation() const override { entity_angle_t y = m_RotY; if (m_TurretParent != INVALID_ENTITY) @@ -615,7 +615,7 @@ return CFixedVector3D(m_RotX, y, m_RotZ); } - virtual fixed GetDistanceTravelled() const + fixed GetDistanceTravelled() const override { if (!m_InWorld) { @@ -656,7 +656,7 @@ return (m_ConstructionProgress.ToFloat() - 1.0f) * dy; } - virtual void GetInterpolatedPosition2D(float frameOffset, float& x, float& z, float& rotY) const + void GetInterpolatedPosition2D(float frameOffset, float& x, float& z, float& rotY) const override { if (!m_InWorld) { @@ -670,7 +670,7 @@ rotY = m_InterpolatedRotY; } - virtual CMatrix3D GetInterpolatedTransform(float frameOffset) const + CMatrix3D GetInterpolatedTransform(float frameOffset) const override { if (m_TurretParent != INVALID_ENTITY) { @@ -782,7 +782,7 @@ pos1.Y += GetConstructionProgressOffset(pos1); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpProjectileManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpProjectileManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpProjectileManager.cpp 2021-08-03 17:15:03.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpProjectileManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -41,7 +41,7 @@ // Time (in seconds) before projectiles that stuck in the ground are destroyed const static float PROJECTILE_DECAY_TIME = 30.f; -class CCmpProjectileManager : public ICmpProjectileManager +class CCmpProjectileManager final : public ICmpProjectileManager { public: static void ClassInit(CComponentManager& componentManager) @@ -57,20 +57,20 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_ActorSeed = 0; m_NextId = 1; } - virtual void Deinit() + void Deinit() override { for (size_t i = 0; i < m_Projectiles.size(); ++i) GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles[i].unit); m_Projectiles.clear(); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { // Because this is just graphical effects, and because it's all non-deterministic floating point, // we don't do much serialization here. @@ -80,7 +80,7 @@ serialize.NumberU32_Unbounded("next id", m_NextId); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); @@ -88,7 +88,7 @@ deserialize.NumberU32_Unbounded("next id", m_NextId); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -107,12 +107,12 @@ } } - virtual uint32_t LaunchProjectileAtPoint(const CFixedVector3D& launchPoint, const CFixedVector3D& target, fixed speed, fixed gravity, const std::wstring& actorName, const std::wstring& impactActorName, fixed impactAnimationLifetime) + uint32_t LaunchProjectileAtPoint(const CFixedVector3D& launchPoint, const CFixedVector3D& target, fixed speed, fixed gravity, const std::wstring& actorName, const std::wstring& impactActorName, fixed impactAnimationLifetime) override { return LaunchProjectile(launchPoint, target, speed, gravity, actorName, impactActorName, impactAnimationLifetime); } - virtual void RemoveProjectile(uint32_t); + void RemoveProjectile(uint32_t) override; void RenderModel(CModelAbstract& model, const CVector3D& position, SceneCollector& collector, const CFrustum& frustum, bool culling, const CLosQuerier& los, bool losRevealAll) const; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpRallyPointRenderer.cpp 0ad-0.0.26/source/simulation2/components/CCmpRallyPointRenderer.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpRallyPointRenderer.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpRallyPointRenderer.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -112,13 +112,17 @@ if (CRenderer::IsInitialised()) { CTextureProperties texturePropsBase(m_LineTexturePath); - texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsBase.SetMaxAnisotropy(4.f); + texturePropsBase.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsBase.SetAnisotropicFilter(true); m_Texture = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase); CTextureProperties texturePropsMask(m_LineTextureMaskPath); - texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsMask.SetMaxAnisotropy(4.f); + texturePropsMask.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsMask.SetAnisotropicFilter(true); m_TextureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask); } } @@ -269,13 +273,13 @@ if (!cmpPlayerManager) continue; - CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(ownerId)); - if (!cmpPlayer) + CmpPtr cmpIdentity(GetSimContext(), cmpPlayerManager->GetPlayerByID(ownerId)); + if (!cmpIdentity) continue; CmpPtr cmpVisualActor(GetSimContext(), m_MarkerEntityIds[i]); if (cmpVisualActor) - cmpVisualActor->SetVariant("civ", CStrW(cmpPlayer->GetCiv()).ToUTF8()); + cmpVisualActor->SetVariant("civ", CStrW(cmpIdentity->GetCiv()).ToUTF8()); } m_LastMarkerCount = m_RallyPoints.size() - 1; } diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpRallyPointRenderer.h 0ad-0.0.26/source/simulation2/components/CCmpRallyPointRenderer.h --- 0ad-0.0.25b/source/simulation2/components/CCmpRallyPointRenderer.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpRallyPointRenderer.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "renderer/Renderer.h" #include "simulation2/MessageTypes.h" #include "simulation2/components/ICmpFootprint.h" +#include "simulation2/components/ICmpIdentity.h" #include "simulation2/components/ICmpObstructionManager.h" #include "simulation2/components/ICmpOwnership.h" #include "simulation2/components/ICmpPathfinder.h" @@ -65,19 +66,19 @@ } }; -class CCmpRallyPointRenderer : public ICmpRallyPointRenderer +class CCmpRallyPointRenderer final : public ICmpRallyPointRenderer { public: static std::string GetSchema(); static void ClassInit(CComponentManager& componentManager); - virtual void Init(const CParamNode& paramNode); - virtual void Deinit(); + void Init(const CParamNode& paramNode) override; + void Deinit() override; - virtual void Serialize(ISerializer& UNUSED(serialize)); - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)); + void Serialize(ISerializer& UNUSED(serialize)) override; + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override; - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)); + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override; /* * Must be called whenever m_Displayed or the size of m_RallyPoints change, @@ -85,22 +86,22 @@ */ virtual void UpdateMessageSubscriptions(); - virtual void AddPosition_wrapper(const CFixedVector2D& pos); + void AddPosition_wrapper(const CFixedVector2D& pos) override; - virtual void SetPosition(const CFixedVector2D& pos); + void SetPosition(const CFixedVector2D& pos) override; - virtual void UpdatePosition(u32 rallyPointId, const CFixedVector2D& pos); + void UpdatePosition(u32 rallyPointId, const CFixedVector2D& pos) override; - virtual void SetDisplayed(bool displayed); + void SetDisplayed(bool displayed) override; - virtual void Reset(); + void Reset() override; - virtual void UpdateColor(); + void UpdateColor() override; /** * Returns true if at least one display rally point is set; i.e., if we have a point to render our marker/line at. */ - virtual bool IsSet() const; + bool IsSet() const override; DEFAULT_COMPONENT_ALLOCATOR(RallyPointRenderer) diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpRangeManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpRangeManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpRangeManager.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpRangeManager.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -158,7 +158,7 @@ CEntityHandle source; // TODO: this could crash if an entity is destroyed while a Query is still referencing it entity_pos_t minRange; entity_pos_t maxRange; - entity_pos_t elevationBonus; // Used for parabolas only. + entity_pos_t yOrigin; // Used for parabolas only. u32 ownersMask; i32 interface; u8 flagsMask; @@ -290,7 +290,7 @@ { serialize.NumberFixed_Unbounded("min range", value.minRange); serialize.NumberFixed_Unbounded("max range", value.maxRange); - serialize.NumberFixed_Unbounded("elevation bonus", value.elevationBonus); + serialize.NumberFixed_Unbounded("yOrigin", value.yOrigin); serialize.NumberU32_Unbounded("owners mask", value.ownersMask); serialize.NumberI32_Unbounded("interface", value.interface); Serializer(serialize, "last match", value.lastMatch); @@ -349,7 +349,7 @@ * (TODO: would be nice to make it cleverer, so e.g. mountains and walls * can block vision) */ -class CCmpRangeManager : public ICmpRangeManager +class CCmpRangeManager final : public ICmpRangeManager { public: static void ClassInit(CComponentManager& componentManager) @@ -436,7 +436,7 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_QueryNext = 1; @@ -462,7 +462,7 @@ m_LosVerticesPerSide = 0; } - virtual void Deinit() + void Deinit() override { } @@ -496,19 +496,19 @@ Serializer(serialize, "shared dirty visibility masks", m_SharedDirtyVisibilityMasks); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { SerializeCommon(serialize); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); SerializeCommon(deserialize); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -781,7 +781,7 @@ } } - virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) + void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) override { // Don't support rectangular looking maps. ENSURE(x1-x0 == z1-z0); @@ -794,7 +794,7 @@ ResetDerivedData(); } - virtual void Verify() + void Verify() override { // Ignore if map not initialised yet if (m_WorldX1.IsZero()) @@ -844,7 +844,7 @@ debug_warn(L"inconsistent los regions"); } - FastSpatialSubdivision* GetSubdivision() + FastSpatialSubdivision* GetSubdivision() override { return &m_Subdivision; } @@ -921,9 +921,9 @@ m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z), it->second.size); } - virtual tag_t CreateActiveQuery(entity_id_t source, + tag_t CreateActiveQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, - const std::vector& owners, int requiredInterface, u8 flags, bool accountForSize) + const std::vector& owners, int requiredInterface, u8 flags, bool accountForSize) override { tag_t id = m_QueryNext++; m_Queries[id] = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, flags, accountForSize); @@ -931,17 +931,17 @@ return id; } - virtual tag_t CreateActiveParabolicQuery(entity_id_t source, - entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus, - const std::vector& owners, int requiredInterface, u8 flags) + tag_t CreateActiveParabolicQuery(entity_id_t source, + entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, + const std::vector& owners, int requiredInterface, u8 flags) override { tag_t id = m_QueryNext++; - m_Queries[id] = ConstructParabolicQuery(source, minRange, maxRange, elevationBonus, owners, requiredInterface, flags, true); + m_Queries[id] = ConstructParabolicQuery(source, minRange, maxRange, yOrigin, owners, requiredInterface, flags, true); return id; } - virtual void DestroyActiveQuery(tag_t tag) + void DestroyActiveQuery(tag_t tag) override { if (m_Queries.find(tag) == m_Queries.end()) { @@ -952,7 +952,7 @@ m_Queries.erase(tag); } - virtual void EnableActiveQuery(tag_t tag) + void EnableActiveQuery(tag_t tag) override { std::map::iterator it = m_Queries.find(tag); if (it == m_Queries.end()) @@ -965,7 +965,7 @@ q.enabled = true; } - virtual void DisableActiveQuery(tag_t tag) + void DisableActiveQuery(tag_t tag) override { std::map::iterator it = m_Queries.find(tag); if (it == m_Queries.end()) @@ -978,7 +978,7 @@ q.enabled = false; } - virtual bool IsActiveQueryEnabled(tag_t tag) const + bool IsActiveQueryEnabled(tag_t tag) const override { std::map::const_iterator it = m_Queries.find(tag); if (it == m_Queries.end()) @@ -991,9 +991,9 @@ return q.enabled; } - virtual std::vector ExecuteQueryAroundPos(const CFixedVector2D& pos, + std::vector ExecuteQueryAroundPos(const CFixedVector2D& pos, entity_pos_t minRange, entity_pos_t maxRange, - const std::vector& owners, int requiredInterface, bool accountForSize) + const std::vector& owners, int requiredInterface, bool accountForSize) override { Query q = ConstructQuery(INVALID_ENTITY, minRange, maxRange, owners, requiredInterface, GetEntityFlagMask("normal"), accountForSize); std::vector r; @@ -1005,9 +1005,9 @@ return r; } - virtual std::vector ExecuteQuery(entity_id_t source, + std::vector ExecuteQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, - const std::vector& owners, int requiredInterface, bool accountForSize) + const std::vector& owners, int requiredInterface, bool accountForSize) override { PROFILE("ExecuteQuery"); @@ -1031,7 +1031,7 @@ return r; } - virtual std::vector ResetActiveQuery(tag_t tag) + std::vector ResetActiveQuery(tag_t tag) override { PROFILE("ResetActiveQuery"); @@ -1066,17 +1066,17 @@ return r; } - virtual std::vector GetEntitiesByPlayer(player_id_t player) const + std::vector GetEntitiesByPlayer(player_id_t player) const override { return GetEntitiesByMask(CalcOwnerMask(player)); } - virtual std::vector GetNonGaiaEntities() const + std::vector GetNonGaiaEntities() const override { return GetEntitiesByMask(~3u); // bit 0 for owner=-1 and bit 1 for gaia } - virtual std::vector GetGaiaAndNonGaiaEntities() const + std::vector GetGaiaAndNonGaiaEntities() const override { return GetEntitiesByMask(~1u); // bit 0 for owner=-1 } @@ -1095,7 +1095,7 @@ return entities; } - virtual void SetDebugOverlay(bool enabled) + void SetDebugOverlay(bool enabled) override { m_DebugOverlayEnabled = enabled; m_DebugOverlayDirty = true; @@ -1195,8 +1195,8 @@ void PerformQuery(const Query& q, std::vector& r, CFixedVector2D pos) { - // Special case: range -1.0 means check all entities ignoring distance - if (q.maxRange == entity_pos_t::FromInt(-1)) + // Special case: range is ALWAYS_IN_RANGE means check all entities ignoring distance. + if (q.maxRange == ALWAYS_IN_RANGE) { for (EntityMap::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) { @@ -1206,14 +1206,14 @@ r.push_back(it->first); } } - // Not the entire world, so check a parabolic range, or a regular range + // Not the entire world, so check a parabolic range, or a regular range. else if (q.parabolic) { - // elevationBonus is part of the 3D position, as the source is really that much heigher + // The yOrigin is part of the 3D position, as the source is really that much heigher. CmpPtr cmpSourcePosition(q.source); CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+ - CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ; - // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange + CFixedVector3D(entity_pos_t::Zero(), q.yOrigin, entity_pos_t::Zero()) ; + // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange. m_SubdivisionResults.clear(); m_Subdivision.GetNear(m_SubdivisionResults, pos, q.maxRange * 2); @@ -1279,12 +1279,35 @@ } } - virtual entity_pos_t GetElevationAdaptedRange(const CFixedVector3D& pos1, const CFixedVector3D& rot, entity_pos_t range, entity_pos_t elevationBonus, entity_pos_t angle) const + entity_pos_t GetEffectiveParabolicRange(entity_id_t source, entity_id_t target, entity_pos_t range, entity_pos_t yOrigin) const override + { + // For non-positive ranges, just return the range. + if (range < entity_pos_t::Zero()) + return range; + + CmpPtr cmpSourcePosition(GetSimContext(), source); + if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld()) + return NEVER_IN_RANGE; + + CmpPtr cmpTargetPosition(GetSimContext(), target); + if (!cmpTargetPosition || !cmpTargetPosition->IsInWorld()) + return NEVER_IN_RANGE; + + entity_pos_t heightDifference = cmpSourcePosition->GetHeightOffset() - cmpTargetPosition->GetHeightOffset() + yOrigin; + if (heightDifference < -range / 2) + return NEVER_IN_RANGE; + + entity_pos_t effectiveRange; + effectiveRange.SetInternalValue(static_cast(isqrt64(SQUARE_U64_FIXED(range) + static_cast(heightDifference.GetInternalValue()) * static_cast(range.GetInternalValue()) * 2))); + return effectiveRange; + } + + entity_pos_t GetElevationAdaptedRange(const CFixedVector3D& pos1, const CFixedVector3D& rot, entity_pos_t range, entity_pos_t yOrigin, entity_pos_t angle) const override { entity_pos_t r = entity_pos_t::Zero(); CFixedVector3D pos(pos1); - pos.Y += elevationBonus; + pos.Y += yOrigin; entity_pos_t orientation = rot.Y; entity_pos_t maxAngle = orientation + angle/2; @@ -1383,12 +1406,13 @@ entity_pos_t minRange, entity_pos_t maxRange, const std::vector& owners, int requiredInterface, u8 flagsMask, bool accountForSize) const { - // Min range must be non-negative + // Min range must be non-negative. if (minRange < entity_pos_t::Zero()) LOGWARNING("CCmpRangeManager: Invalid min range %f in query for entity %u", minRange.ToDouble(), source); - // Max range must be non-negative, or else -1 - if (maxRange < entity_pos_t::Zero() && maxRange != entity_pos_t::FromInt(-1)) + // Max range must be non-negative, or else ALWAYS_IN_RANGE. + // TODO add NEVER_IN_RANGE. + if (maxRange < entity_pos_t::Zero() && maxRange != ALWAYS_IN_RANGE) LOGWARNING("CCmpRangeManager: Invalid max range %f in query for entity %u", maxRange.ToDouble(), source); Query q; @@ -1397,10 +1421,10 @@ q.source = GetSimContext().GetComponentManager().LookupEntityHandle(source); q.minRange = minRange; q.maxRange = maxRange; - q.elevationBonus = entity_pos_t::Zero(); + q.yOrigin = entity_pos_t::Zero(); q.accountForSize = accountForSize; - if (q.accountForSize && q.source.GetId() != INVALID_ENTITY && q.maxRange != entity_pos_t::FromInt(-1)) + if (q.accountForSize && q.source.GetId() != INVALID_ENTITY && q.maxRange != ALWAYS_IN_RANGE) { u32 size = 0; if (ENTITY_IS_LOCAL(q.source.GetId())) @@ -1435,12 +1459,12 @@ } Query ConstructParabolicQuery(entity_id_t source, - entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus, + entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, const std::vector& owners, int requiredInterface, u8 flagsMask, bool accountForSize) const { Query q = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, flagsMask, accountForSize); q.parabolic = true; - q.elevationBonus = elevationBonus; + q.yOrigin = yOrigin; return q; } @@ -1475,9 +1499,9 @@ } else { - // elevation bonus is part of the 3D position. As if the unit is really that much higher + // yOrigin is part of the 3D position. As if the unit is really that much higher. CFixedVector3D pos3D = cmpSourcePosition->GetPosition(); - pos3D.Y += q.elevationBonus; + pos3D.Y += q.yOrigin; std::vector coords; @@ -1580,7 +1604,7 @@ collector.Submit(&m_DebugOverlayLines[i]); } - virtual u8 GetEntityFlagMask(const std::string& identifier) const + u8 GetEntityFlagMask(const std::string& identifier) const override { if (identifier == "normal") return FlagMasks::Normal; @@ -1591,7 +1615,7 @@ return FlagMasks::None; } - virtual void SetEntityFlag(entity_id_t ent, const std::string& identifier, bool value) + void SetEntityFlag(entity_id_t ent, const std::string& identifier, bool value) override { EntityMap::iterator it = m_EntityData.find(ent); @@ -1611,7 +1635,7 @@ // LOS implementation: - virtual CLosQuerier GetLosQuerier(player_id_t player) const + CLosQuerier GetLosQuerier(player_id_t player) const override { if (GetLosRevealAll(player)) return CLosQuerier(0xFFFFFFFFu, m_LosStateRevealed, m_LosVerticesPerSide); @@ -1619,7 +1643,7 @@ return CLosQuerier(GetSharedLosMask(player), m_LosState, m_LosVerticesPerSide); } - virtual void ActivateScriptedVisibility(entity_id_t ent, bool status) + void ActivateScriptedVisibility(entity_id_t ent, bool status) override { EntityMap::iterator it = m_EntityData.find(ent); if (it != m_EntityData.end()) @@ -1729,7 +1753,7 @@ return ComputeLosVisibility(handle, player); } - virtual LosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const + LosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const override { entity_id_t entId = ent.GetId(); @@ -1760,13 +1784,13 @@ return static_cast(GetPlayerVisibility(it->second.visibilities, player)); } - virtual LosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const + LosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const override { CEntityHandle handle = GetSimContext().GetComponentManager().LookupEntityHandle(ent); return GetLosVisibility(handle, player); } - virtual LosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const + LosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const override { int i = (x / LOS_TILE_SIZE).ToInt_RoundToNearest(); int j = (z / LOS_TILE_SIZE).ToInt_RoundToNearest(); @@ -1790,7 +1814,7 @@ return LosVisibility::HIDDEN; } - size_t GetVerticesPerSide() const + size_t GetVerticesPerSide() const override { return m_LosVerticesPerSide; } @@ -1862,7 +1886,7 @@ } } - virtual void RequestVisibilityUpdate(entity_id_t ent) + void RequestVisibilityUpdate(entity_id_t ent) override { if (std::find(m_ModifiedEntities.begin(), m_ModifiedEntities.end(), ent) == m_ModifiedEntities.end()) m_ModifiedEntities.push_back(ent); @@ -1892,7 +1916,7 @@ UpdateVisibility(ent, player); } - virtual void SetLosRevealAll(player_id_t player, bool enabled) + void SetLosRevealAll(player_id_t player, bool enabled) override { if (player == -1) m_LosRevealAll[MAX_LOS_PLAYER_ID+1] = enabled; @@ -1906,7 +1930,7 @@ m_GlobalVisibilityUpdate = true; } - virtual bool GetLosRevealAll(player_id_t player) const + bool GetLosRevealAll(player_id_t player) const override { // Special player value can force reveal-all for every player if (m_LosRevealAll[MAX_LOS_PLAYER_ID+1] || player == -1) @@ -1919,19 +1943,19 @@ return false; } - virtual void SetLosCircular(bool enabled) + void SetLosCircular(bool enabled) override { m_LosCircular = enabled; ResetDerivedData(); } - virtual bool GetLosCircular() const + bool GetLosCircular() const override { return m_LosCircular; } - virtual void SetSharedLos(player_id_t player, const std::vector& players) + void SetSharedLos(player_id_t player, const std::vector& players) override { m_SharedLosMasks[player] = CalcSharedLosMask(players); @@ -1953,12 +1977,12 @@ m_GlobalPlayerVisibilityUpdate[player-1] = 1; } - virtual u32 GetSharedLosMask(player_id_t player) const + u32 GetSharedLosMask(player_id_t player) const override { return m_SharedLosMasks[player]; } - void ExploreMap(player_id_t p) + void ExploreMap(player_id_t p) override { for (i32 j = 0; j < m_LosVerticesPerSide; ++j) for (i32 i = 0; i < m_LosVerticesPerSide; ++i) @@ -1973,7 +1997,7 @@ SeeExploredEntities(p); } - virtual void ExploreTerritories() + void ExploreTerritories() override { PROFILE3("ExploreTerritories"); @@ -2056,7 +2080,7 @@ } } - virtual void RevealShore(player_id_t p, bool enable) + void RevealShore(player_id_t p, bool enable) override { if (p <= 0 || p > MAX_LOS_PLAYER_ID) return; @@ -2470,12 +2494,12 @@ LosMove(i, visionRange, from, to); } - virtual u8 GetPercentMapExplored(player_id_t player) const + u8 GetPercentMapExplored(player_id_t player) const override { return m_ExploredVertices.at((u8)player) * 100 / m_TotalInworldVertices; } - virtual u8 GetUnionPercentMapExplored(const std::vector& players) const + u8 GetUnionPercentMapExplored(const std::vector& players) const override { u32 exploredVertices = 0; std::vector::const_iterator playerIt; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpRangeOverlayRenderer.cpp 0ad-0.0.26/source/simulation2/components/CCmpRangeOverlayRenderer.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpRangeOverlayRenderer.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpRangeOverlayRenderer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,7 +32,7 @@ #include -class CCmpRangeOverlayRenderer : public ICmpRangeOverlayRenderer +class CCmpRangeOverlayRenderer final : public ICmpRangeOverlayRenderer { public: static void ClassInit(CComponentManager& componentManager) @@ -56,31 +56,31 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_Enabled = m_LastEnabledState = false; UpdateMessageSubscriptions(); } - virtual void Deinit() { } + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - void ResetRangeOverlays() + void ResetRangeOverlays() override { m_RangeOverlayData.clear(); UpdateMessageSubscriptions(); m_Enabled = false; } - virtual void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness) + void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness) override { if (!CRenderer::IsInitialised()) return; @@ -98,7 +98,7 @@ UpdateMessageSubscriptions(); } - void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -135,7 +135,7 @@ std::unique_ptr line; }; - virtual void UpdateColor() + void UpdateColor() override { CmpPtr cmpOwnership(GetEntityHandle()); if (!cmpOwnership) diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpSelectable.cpp 0ad-0.0.26/source/simulation2/components/CCmpSelectable.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpSelectable.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpSelectable.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -50,7 +50,7 @@ // Desaturation value for unselected, always visible overlays (0.33 = 33% desaturated or 66% of original saturation) static const float RGB_DESATURATION = 0.333333f; -class CCmpSelectable : public ICmpSelectable +class CCmpSelectable final : public ICmpSelectable { public: enum EShape @@ -149,7 +149,7 @@ entity_pos_t m_Width; // width/radius entity_pos_t m_Height; // height/radius - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_EditorOnly = paramNode.GetChild("EditorOnly").IsOk(); @@ -215,23 +215,23 @@ UpdateMessageSubscriptions(); } - virtual void Deinit() { } + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { // Nothing to do here (the overlay object is not worth saving, it'll get // reconstructed by the GUI soon enough, I think) } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { // Need to call Init to reload the template properties Init(paramNode); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)); + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override; - virtual void SetSelectionHighlight(const CColor& color, bool selected) + void SetSelectionHighlight(const CColor& color, bool selected) override { m_Selected = selected; m_Color.r = color.r; @@ -257,7 +257,7 @@ SetSelectionHighlightAlpha(color.a); } - virtual void SetSelectionHighlightAlpha(float alpha) + void SetSelectionHighlightAlpha(float alpha) override { alpha = std::max(m_AlphaMin, alpha); @@ -269,13 +269,13 @@ UpdateMessageSubscriptions(); } - virtual void SetVisibility(bool visible) + void SetVisibility(bool visible) override { m_Visible = visible; UpdateMessageSubscriptions(); } - virtual bool IsEditorOnly() const + bool IsEditorOnly() const override { return m_EditorOnly; } @@ -309,7 +309,7 @@ /** * Set the color of the current owner. */ - virtual void UpdateColor(); + void UpdateColor() override; private: SOverlayDescriptor m_OverlayDescriptor; @@ -563,12 +563,16 @@ // Assuming we don't need the capability of swapping textures on-demand. CTextureProperties texturePropsBase(m_OverlayDescriptor.m_QuadTexture.c_str()); - texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsBase.SetMaxAnisotropy(4.f); + texturePropsBase.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsBase.SetAnisotropicFilter(true); CTextureProperties texturePropsMask(m_OverlayDescriptor.m_QuadTextureMask.c_str()); - texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsMask.SetMaxAnisotropy(4.f); + texturePropsMask.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsMask.SetAnisotropicFilter(true); m_UnitOverlay->m_Texture = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase); m_UnitOverlay->m_TextureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask); diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpSoundManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpSoundManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpSoundManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpSoundManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ #include "soundmanager/ISoundManager.h" -class CCmpSoundManager : public ICmpSoundManager +class CCmpSoundManager final : public ICmpSoundManager { public: static void ClassInit(CComponentManager& UNUSED(componentManager) ) @@ -41,26 +41,26 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { // Do nothing here - sounds are purely local, and don't need to be preserved across saved games etc // (If we add music support in here then we might want to save the music state, though) } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void PlaySoundGroup(const std::wstring& name, entity_id_t source) + void PlaySoundGroup(const std::wstring& name, entity_id_t source) override { if (!g_SoundManager || (source == INVALID_ENTITY)) return; @@ -84,21 +84,21 @@ g_SoundManager->PlayAsGroup(name, sourcePos, source, playerOwned); } - virtual void PlaySoundGroupAtPosition(const std::wstring& name, const CFixedVector3D& sourcePos) + void PlaySoundGroupAtPosition(const std::wstring& name, const CFixedVector3D& sourcePos) override { if (!g_SoundManager) return; g_SoundManager->PlayAsGroup(name, CVector3D(sourcePos), INVALID_ENTITY, false); } - virtual void PlaySoundGroupForPlayer(const VfsPath& groupPath, const player_id_t playerId) const + void PlaySoundGroupForPlayer(const VfsPath& groupPath, const player_id_t playerId) const override { if (!g_SoundManager) return; g_SoundManager->PlayAsGroup(groupPath, CVector3D(0.f, 0.f, 0.f), INVALID_ENTITY, GetSimContext().GetCurrentDisplayedPlayer() == playerId); } - virtual void StopMusic() + void StopMusic() override { if (!g_SoundManager) return; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpTemplateManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpTemplateManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpTemplateManager.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpTemplateManager.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include "ps/TemplateLoader.h" #include "ps/XML/RelaxNG.h" -class CCmpTemplateManager : public ICmpTemplateManager +class CCmpTemplateManager final : public ICmpTemplateManager { public: static void ClassInit(CComponentManager& componentManager) @@ -43,7 +43,7 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_DisableValidation = false; @@ -52,11 +52,11 @@ // TODO: support hotloading changes to the grammar } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { std::map> templateMap; @@ -67,7 +67,7 @@ Serializer(serialize, "templates", templateMap); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); @@ -78,7 +78,7 @@ m_LatestTemplates[id] = mapEl.first; } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -94,28 +94,30 @@ } } - virtual void DisableValidation() + void DisableValidation() override { m_DisableValidation = true; } - virtual const CParamNode* LoadTemplate(entity_id_t ent, const std::string& templateName); + const CParamNode* LoadTemplate(entity_id_t ent, const std::string& templateName) override; - virtual const CParamNode* GetTemplate(const std::string& templateName); + const CParamNode* GetTemplate(const std::string& templateName) override; - virtual const CParamNode* GetTemplateWithoutValidation(const std::string& templateName); + const CParamNode* GetTemplateWithoutValidation(const std::string& templateName) override; - virtual bool TemplateExists(const std::string& templateName) const; + bool TemplateExists(const std::string& templateName) const override; - virtual const CParamNode* LoadLatestTemplate(entity_id_t ent); + const CParamNode* LoadLatestTemplate(entity_id_t ent) override; - virtual std::string GetCurrentTemplateName(entity_id_t ent) const; + std::string GetCurrentTemplateName(entity_id_t ent) const override; - virtual std::vector FindAllTemplates(bool includeActors) const; + std::vector FindAllTemplates(bool includeActors) const override; - virtual std::vector FindUsedTemplates() const; + std::vector> GetCivData() override; - virtual std::vector GetEntitiesUsingTemplate(const std::string& templateName) const; + std::vector FindUsedTemplates() const override; + + std::vector GetEntitiesUsingTemplate(const std::string& templateName) const override; private: // Template loader @@ -215,6 +217,23 @@ return m_templateLoader.FindTemplates("", true, templatesType); } +std::vector> CCmpTemplateManager::GetCivData() +{ + std::vector> data; + + std::vector names = m_templateLoader.FindTemplatesUnrestricted("special/players/", false); + data.reserve(names.size()); + for (const std::string& name : names) + { + const CParamNode& identity = GetTemplate(name)->GetChild("Identity"); + data.push_back(std::vector { + identity.GetChild("Civ").ToWString(), + identity.GetChild("GenericName").ToWString() + }); + } + return data; +} + std::vector CCmpTemplateManager::FindUsedTemplates() const { std::vector usedTemplates; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpTerrain.cpp 0ad-0.0.26/source/simulation2/components/CCmpTerrain.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpTerrain.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpTerrain.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,16 +20,16 @@ #include "simulation2/system/Component.h" #include "ICmpTerrain.h" -#include "ICmpObstructionManager.h" -#include "ICmpRangeManager.h" -#include "simulation2/MessageTypes.h" - #include "graphics/Terrain.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "maths/Vector3D.h" +#include "simulation2/components/ICmpObstructionManager.h" +#include "simulation2/components/ICmpRangeManager.h" +#include "simulation2/MessageTypes.h" -class CCmpTerrain : public ICmpTerrain +class CCmpTerrain final : public ICmpTerrain { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -45,54 +45,54 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_Terrain = &GetSimContext().GetTerrain(); } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual bool IsLoaded() const + bool IsLoaded() const override { return m_Terrain->GetVerticesPerSide() != 0; } - virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) const + CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) const override { CFixedVector3D normal; m_Terrain->CalcNormalFixed((x / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), (z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), normal); return normal; } - virtual CVector3D CalcExactNormal(float x, float z) const + CVector3D CalcExactNormal(float x, float z) const override { return m_Terrain->CalcExactNormal(x, z); } - virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) const + entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) const override { // TODO: this can crash if the terrain heightmap isn't initialised yet return m_Terrain->GetExactGroundLevelFixed(x, z); } - virtual float GetExactGroundLevel(float x, float z) const + float GetExactGroundLevel(float x, float z) const override { return m_Terrain->GetExactGroundLevel(x, z); } - virtual u16 GetTilesPerSide() const + u16 GetTilesPerSide() const override { ssize_t tiles = m_Terrain->GetTilesPerSide(); @@ -102,24 +102,24 @@ return (u16)tiles; } - virtual u32 GetMapSize() const + u32 GetMapSize() const override { return GetTilesPerSide() * TERRAIN_TILE_SIZE; } - virtual u16 GetVerticesPerSide() const + u16 GetVerticesPerSide() const override { ssize_t vertices = m_Terrain->GetVerticesPerSide(); ENSURE(1 <= vertices && vertices <= 65535); return (u16)vertices; } - virtual CTerrain* GetCTerrain() + CTerrain* GetCTerrain() override { return m_Terrain; } - virtual void ReloadTerrain(bool ReloadWater) + void ReloadTerrain(bool ReloadWater) override { // TODO: should refactor this code to be nicer @@ -144,13 +144,13 @@ if (ReloadWater && CRenderer::IsInitialised()) { - g_Renderer.GetWaterManager()->SetMapSize(vertices); - g_Renderer.GetWaterManager()->RecomputeWaterData(); + g_Renderer.GetSceneRenderer().GetWaterManager().SetMapSize(vertices); + g_Renderer.GetSceneRenderer().GetWaterManager().RecomputeWaterData(); } MakeDirty(0, 0, tiles+1, tiles+1); } - virtual void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1) + void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1) override { CMessageTerrainChanged msg(i0, j0, i1, j1); GetSimContext().GetComponentManager().BroadcastMessage(msg); diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpTerritoryInfluence.cpp 0ad-0.0.26/source/simulation2/components/CCmpTerritoryInfluence.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpTerritoryInfluence.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpTerritoryInfluence.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,7 +24,7 @@ #include "simulation2/components/ICmpPlayerManager.h" #include "simulation2/components/ICmpValueModificationManager.h" -class CCmpTerritoryInfluence : public ICmpTerritoryInfluence +class CCmpTerritoryInfluence final : public ICmpTerritoryInfluence { public: static void ClassInit(CComponentManager& UNUSED(componentManager)) @@ -53,27 +53,27 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_Root = paramNode.GetChild("Root").ToBool(); m_Weight = (u16)paramNode.GetChild("Weight").ToInt(); m_Radius = paramNode.GetChild("Radius").ToInt(); } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual bool IsRoot() const + bool IsRoot() const override { CmpPtr cmpValueModificationManager(GetSystemEntity()); if (!cmpValueModificationManager) @@ -82,7 +82,7 @@ return cmpValueModificationManager->ApplyModifications(L"TerritoryInfluence/Root", m_Root, GetEntityId()); } - virtual u16 GetWeight() const + u16 GetWeight() const override { CmpPtr cmpValueModificationManager(GetSystemEntity()); if (!cmpValueModificationManager) @@ -91,7 +91,7 @@ return cmpValueModificationManager->ApplyModifications(L"TerritoryInfluence/Weight", m_Weight, GetEntityId()); } - virtual u32 GetRadius() const + u32 GetRadius() const override { CmpPtr cmpValueModificationManager(GetSystemEntity()); if (!cmpValueModificationManager) diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpTerritoryManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpTerritoryManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpTerritoryManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpTerritoryManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -45,14 +45,14 @@ class CCmpTerritoryManager; -class TerritoryOverlay : public TerrainTextureOverlay +class TerritoryOverlay final : public TerrainTextureOverlay { NONCOPYABLE(TerritoryOverlay); public: CCmpTerritoryManager& m_TerritoryManager; TerritoryOverlay(CCmpTerritoryManager& manager); - virtual void BuildTextureRGBA(u8* data, size_t w, size_t h); + void BuildTextureRGBA(u8* data, size_t w, size_t h) override; }; class CCmpTerritoryManager : public ICmpTerritoryManager @@ -117,7 +117,7 @@ bool m_EnableLineDebugOverlays; ///< Enable node debugging overlays for boundary lines? std::vector m_DebugBoundaryLineNodes; - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_Territories = NULL; m_CostGrid = NULL; @@ -148,26 +148,26 @@ m_BorderSeparation = externalParamNode.GetChild("TerritoryManager").GetChild("BorderSeparation").ToFixed().ToFloat(); } - virtual void Deinit() + void Deinit() override { SAFE_DELETE(m_Territories); SAFE_DELETE(m_CostGrid); SAFE_DELETE(m_DebugOverlay); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { // Territory state can be recomputed as required, so we don't need to serialize any of it. serialize.Bool("trigger event", m_TriggerEvent); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); deserialize.Bool("trigger event", m_TriggerEvent); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -237,19 +237,19 @@ MakeDirty(); } - virtual const Grid& GetTerritoryGrid() + const Grid& GetTerritoryGrid() override { CalculateTerritories(); ENSURE(m_Territories); return *m_Territories; } - virtual player_id_t GetOwner(entity_pos_t x, entity_pos_t z); - virtual std::vector GetNeighbours(entity_pos_t x, entity_pos_t z, bool filterConnected); - virtual bool IsConnected(entity_pos_t x, entity_pos_t z); + player_id_t GetOwner(entity_pos_t x, entity_pos_t z) override; + std::vector GetNeighbours(entity_pos_t x, entity_pos_t z, bool filterConnected) override; + bool IsConnected(entity_pos_t x, entity_pos_t z) override; - virtual void SetTerritoryBlinking(entity_pos_t x, entity_pos_t z, bool enable); - virtual bool IsTerritoryBlinking(entity_pos_t x, entity_pos_t z); + void SetTerritoryBlinking(entity_pos_t x, entity_pos_t z, bool enable) override; + bool IsTerritoryBlinking(entity_pos_t x, entity_pos_t z) override; // To support lazy updates of territory render data, // we maintain a DirtyID here and increment it whenever territories change; @@ -269,7 +269,7 @@ m_TriggerEvent = true; } - virtual bool NeedUpdateTexture(size_t* dirtyID) + bool NeedUpdateTexture(size_t* dirtyID) override { if (*dirtyID == m_DirtyID && !m_ColorChanged) return false; @@ -279,7 +279,7 @@ return true; } - virtual bool NeedUpdateAI(size_t* dirtyID, size_t* dirtyBlinkingID) const + bool NeedUpdateAI(size_t* dirtyID, size_t* dirtyBlinkingID) const override { if (*dirtyID == m_DirtyID && *dirtyBlinkingID == m_DirtyBlinkingID) return false; @@ -293,7 +293,7 @@ void CalculateTerritories(); - u8 GetTerritoryPercentage(player_id_t player); + u8 GetTerritoryPercentage(player_id_t player) override; std::vector ComputeBoundaries(); @@ -303,12 +303,12 @@ void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling); - void SetVisibility(bool visible) + void SetVisibility(bool visible) override { m_Visible = visible; } - void UpdateColors(); + void UpdateColors() override; private: @@ -607,13 +607,17 @@ std::vector boundaries = ComputeBoundaries(); CTextureProperties texturePropsBase("art/textures/misc/territory_border.png"); - texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsBase.SetMaxAnisotropy(2.f); + texturePropsBase.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsBase.SetAnisotropicFilter(true); CTexturePtr textureBase = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase); CTextureProperties texturePropsMask("art/textures/misc/territory_border_mask.png"); - texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); - texturePropsMask.SetMaxAnisotropy(2.f); + texturePropsMask.SetAddressMode( + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + texturePropsMask.SetAnisotropicFilter(true); CTexturePtr textureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask); CmpPtr cmpPlayerManager(GetSystemEntity()); diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpTest.cpp 0ad-0.0.26/source/simulation2/components/CCmpTest.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpTest.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpTest.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -42,7 +42,7 @@ return ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { if (paramNode.GetChild("x").IsOk()) m_x = paramNode.GetChild("x").ToInt(); @@ -50,26 +50,26 @@ m_x = 11000; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberI32_Unbounded("x", m_x); } - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) override { deserialize.NumberI32_Unbounded("x", m_x); } - virtual int GetX() + int GetX() override { return m_x; } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -109,31 +109,31 @@ return ""; } - virtual void Init(const CParamNode&) + void Init(const CParamNode&) override { m_x = 12000; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberI32_Unbounded("x", m_x); } - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) override { deserialize.NumberI32_Unbounded("x", m_x); } - virtual int GetX() + int GetX() override { return m_x; } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -170,31 +170,31 @@ return ""; } - virtual void Init(const CParamNode&) + void Init(const CParamNode&) override { m_x = 21000; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberI32_Unbounded("x", m_x); } - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) override { deserialize.NumberI32_Unbounded("x", m_x); } - virtual int GetX() + int GetX() override { return m_x; } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -220,7 +220,7 @@ public: DEFAULT_SCRIPT_WRAPPER(Test1Scripted) - virtual int GetX() + int GetX() override { return m_Script.Call ("GetX"); } @@ -235,7 +235,7 @@ public: DEFAULT_SCRIPT_WRAPPER(Test2Scripted) - virtual int GetX() + int GetX() override { return m_Script.Call ("GetX"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpUnitMotion.h 0ad-0.0.26/source/simulation2/components/CCmpUnitMotion.h --- 0ad-0.0.25b/source/simulation2/components/CCmpUnitMotion.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpUnitMotion.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -42,6 +42,8 @@ #include "ps/Profile.h" #include "renderer/Scene.h" +#include + // NB: this implementation of ICmpUnitMotion is very tightly coupled with UnitMotionManager. // As such, both are compiled in the same TU. @@ -153,7 +155,7 @@ bool m_IsFormationController; - fixed m_TemplateWalkSpeed, m_TemplateRunMultiplier; + fixed m_TemplateWalkSpeed, m_TemplateRunMultiplier, m_TemplateAcceleration, m_TemplateWeight; pass_class_t m_PassClass; std::string m_PassClassName; @@ -225,8 +227,15 @@ // This caches the resulting speed from m_WalkSpeed * m_SpeedMultiplier for convenience. fixed m_Speed; - // Current mean speed (over the last turn). - fixed m_CurSpeed; + // Mean speed over the last turn. + fixed m_LastTurnSpeed; + + // The speed achieved at the end of the current turn. + fixed m_CurrentSpeed; + + fixed m_InstantTurnAngle; + + fixed m_Acceleration; // Currently active paths (storing waypoints in reverse order). // The last item in each path is the point we're currently heading towards. @@ -244,17 +253,26 @@ "" "" "" - "" + "" "" "" "" - "" + "" "" "" "" - "" + "" + "" + "" + "" + "" + "" + "" "" "" + "" + "" + "" "" "" "" @@ -262,7 +280,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_IsFormationController = paramNode.GetChild("FormationController").ToBool(); @@ -270,39 +288,38 @@ m_WalkSpeed = m_TemplateWalkSpeed = m_Speed = paramNode.GetChild("WalkSpeed").ToFixed(); m_SpeedMultiplier = fixed::FromInt(1); - m_CurSpeed = fixed::Zero(); + m_LastTurnSpeed = m_CurrentSpeed = fixed::Zero(); m_RunMultiplier = m_TemplateRunMultiplier = fixed::FromInt(1); if (paramNode.GetChild("RunMultiplier").IsOk()) m_RunMultiplier = m_TemplateRunMultiplier = paramNode.GetChild("RunMultiplier").ToFixed(); - CmpPtr cmpPathfinder(GetSystemEntity()); - if (cmpPathfinder) - { - m_PassClassName = paramNode.GetChild("PassabilityClass").ToString(); - m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName); - m_Clearance = cmpPathfinder->GetClearance(m_PassClass); + m_InstantTurnAngle = paramNode.GetChild("InstantTurnAngle").ToFixed(); - CmpPtr cmpObstruction(GetEntityHandle()); - if (cmpObstruction) - { - cmpObstruction->SetUnitClearance(m_Clearance); - m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true); - } - } + m_Acceleration = m_TemplateAcceleration = paramNode.GetChild("Acceleration").ToFixed(); + + m_TemplateWeight = paramNode.GetChild("Weight").ToFixed(); + + m_PassClassName = paramNode.GetChild("PassabilityClass").ToString(); + SetPassabilityData(m_PassClassName); + + CmpPtr cmpObstruction(GetEntityHandle()); + if (cmpObstruction) + m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true); SetParticipateInPushing(!paramNode.GetChild("DisablePushing").IsOk() || !paramNode.GetChild("DisablePushing").ToBool()); m_DebugOverlayEnabled = false; } - virtual void Deinit() + void Deinit() override { } template void SerializeCommon(S& serialize) { + // m_Clearance and m_PassClass are constructed from this. serialize.StringASCII("pass class", m_PassClassName, 0, 64); serialize.NumberU32_Unbounded("ticket", m_ExpectedPathTicket.m_Ticket); @@ -322,7 +339,12 @@ serialize.NumberFixed_Unbounded("speed multiplier", m_SpeedMultiplier); - serialize.NumberFixed_Unbounded("current speed", m_CurSpeed); + serialize.NumberFixed_Unbounded("last turn speed", m_LastTurnSpeed); + serialize.NumberFixed_Unbounded("current speed", m_CurrentSpeed); + + serialize.NumberFixed_Unbounded("instant turn angle", m_InstantTurnAngle); + + serialize.NumberFixed_Unbounded("acceleration", m_Acceleration); serialize.Bool("facePointAfterMove", m_FacePointAfterMove); serialize.Bool("pushing", m_Pushing); @@ -331,27 +353,25 @@ Serializer(serialize, "short path", m_ShortPath.m_Waypoints); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { SerializeCommon(serialize); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); SerializeCommon(deserialize); - CmpPtr cmpPathfinder(GetSystemEntity()); - if (cmpPathfinder) - m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName); + SetPassabilityData(m_PassClassName); CmpPtr cmpObstruction(GetEntityHandle()); if (cmpObstruction) m_BlockMovement = cmpObstruction->GetBlockMovementFlag(false); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -402,8 +422,6 @@ case MT_Deserialized: { OnValueModification(); - if (!ENTITY_IS_LOCAL(GetEntityId())) - CmpPtr(GetSystemEntity())->Register(this, GetEntityId(), m_IsFormationController); break; } } @@ -415,38 +433,38 @@ GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, needRender); } - virtual bool IsMoveRequested() const + bool IsMoveRequested() const override { return m_MoveRequest.m_Type != MoveRequest::NONE; } - virtual fixed GetSpeedMultiplier() const + fixed GetSpeedMultiplier() const override { return m_SpeedMultiplier; } - virtual void SetSpeedMultiplier(fixed multiplier) + void SetSpeedMultiplier(fixed multiplier) override { m_SpeedMultiplier = std::min(multiplier, m_RunMultiplier); m_Speed = m_SpeedMultiplier.Multiply(GetWalkSpeed()); } - virtual fixed GetSpeed() const + fixed GetSpeed() const override { return m_Speed; } - virtual fixed GetWalkSpeed() const + fixed GetWalkSpeed() const override { return m_WalkSpeed; } - virtual fixed GetRunMultiplier() const + fixed GetRunMultiplier() const override { return m_RunMultiplier; } - virtual CFixedVector2D EstimateFuturePosition(const fixed dt) const + CFixedVector2D EstimateFuturePosition(const fixed dt) const override { CmpPtr cmpPosition(GetEntityHandle()); if (!cmpPosition || !cmpPosition->IsInWorld()) @@ -456,85 +474,102 @@ CFixedVector2D pos = cmpPosition->GetPosition2D(); entity_angle_t angle = cmpPosition->GetRotation().Y; - + fixed speed = m_CurrentSpeed; // Copy the path so we don't change it. WaypointPath shortPath = m_ShortPath; WaypointPath longPath = m_LongPath; - PerformMove(dt, cmpPosition->GetTurnRate(), shortPath, longPath, pos, angle); + PerformMove(dt, cmpPosition->GetTurnRate(), shortPath, longPath, pos, speed, angle, 0); return pos; } - virtual pass_class_t GetPassabilityClass() const + fixed GetAcceleration() const override + { + return m_Acceleration; + } + + void SetAcceleration(fixed acceleration) override + { + m_Acceleration = acceleration; + } + + virtual entity_pos_t GetWeight() const + { + return m_TemplateWeight; + } + + pass_class_t GetPassabilityClass() const override { return m_PassClass; } - virtual std::string GetPassabilityClassName() const + std::string GetPassabilityClassName() const override { return m_PassClassName; } - virtual void SetPassabilityClassName(const std::string& passClassName) + void SetPassabilityClassName(const std::string& passClassName) override { - m_PassClassName = passClassName; - CmpPtr cmpPathfinder(GetSystemEntity()); - if (cmpPathfinder) - m_PassClass = cmpPathfinder->GetPassabilityClass(passClassName); + if (!m_IsFormationController) + { + LOGWARNING("Only formation controllers can change their passability class"); + return; + } + SetPassabilityData(passClassName); } - virtual fixed GetCurrentSpeed() const + fixed GetCurrentSpeed() const override { - return m_CurSpeed; + return m_CurrentSpeed; } - virtual void SetFacePointAfterMove(bool facePointAfterMove) + void SetFacePointAfterMove(bool facePointAfterMove) override { m_FacePointAfterMove = facePointAfterMove; } - virtual bool GetFacePointAfterMove() const + bool GetFacePointAfterMove() const override { return m_FacePointAfterMove; } - virtual void SetDebugOverlay(bool enabled) + void SetDebugOverlay(bool enabled) override { m_DebugOverlayEnabled = enabled; UpdateMessageSubscriptions(); } - virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) + bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) override { return MoveTo(MoveRequest(CFixedVector2D(x, z), minRange, maxRange)); } - virtual bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) + bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) override { return MoveTo(MoveRequest(target, minRange, maxRange)); } - virtual void MoveToFormationOffset(entity_id_t controller, entity_pos_t x, entity_pos_t z) + void MoveToFormationOffset(entity_id_t controller, entity_pos_t x, entity_pos_t z) override { // Pass the controller to the move request anyways. MoveTo(MoveRequest(controller, CFixedVector2D(x, z))); } - virtual void SetMemberOfFormation(entity_id_t controller) + void SetMemberOfFormation(entity_id_t controller) override { m_FormationController = controller; } - virtual bool IsTargetRangeReachable(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange); + bool IsTargetRangeReachable(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) override; - virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z); + void FaceTowardsPoint(entity_pos_t x, entity_pos_t z) override; /** * Clears the current MoveRequest - the unit will stop and no longer try and move. * This should never be called from UnitMotion, since MoveToX orders are given * by other components - these components should also decide when to stop. */ - virtual void StopMoving() + void StopMoving() override { if (m_FacePointAfterMove) { @@ -553,7 +588,7 @@ m_ShortPath.m_Waypoints.clear(); } - virtual entity_pos_t GetUnitClearance() const + entity_pos_t GetUnitClearance() const override { return m_Clearance; } @@ -586,6 +621,21 @@ m_Pushing = pushing && cmpUnitMotionManager->IsPushingActivated(); } + void SetPassabilityData(const std::string& passClassName) + { + m_PassClassName = passClassName; + CmpPtr cmpPathfinder(GetSystemEntity()); + if (cmpPathfinder) + { + m_PassClass = cmpPathfinder->GetPassabilityClass(passClassName); + m_Clearance = cmpPathfinder->GetClearance(m_PassClass); + + CmpPtr cmpObstruction(GetEntityHandle()); + if (cmpObstruction) + cmpObstruction->SetUnitClearance(m_Clearance); + } + } + /** * Warns other components that our current movement will likely fail (e.g. we won't be able to reach our target) * This should only be called before the actual movement in a given turn, or units might both move and try to do things @@ -721,13 +771,13 @@ * This does not send actually change the position. * @returns true if the move was obstructed. */ - bool PerformMove(fixed dt, const fixed& turnRate, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos, entity_angle_t& angle) const; + bool PerformMove(fixed dt, const fixed& turnRate, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos, fixed& speed, entity_angle_t& angle, uint8_t pushingPressure) const; /** * Update other components on our speed. * (For performance, this should try to avoid sending messages). */ - void UpdateMovementState(entity_pos_t speed); + void UpdateMovementState(entity_pos_t speed, entity_pos_t meanSpeed); /** * React if our move was obstructed. @@ -993,7 +1043,7 @@ // If we were idle and will still be, no need for an update. state.needUpdate = state.cmpPosition->IsInWorld() && - (m_CurSpeed != fixed::Zero() || m_MoveRequest.m_Type != MoveRequest::NONE); + (m_CurrentSpeed != fixed::Zero() || m_LastTurnSpeed != fixed::Zero() || m_MoveRequest.m_Type != MoveRequest::NONE); if (!m_BlockMovement) return; @@ -1017,7 +1067,7 @@ // to it, then throw away our current path and go straight to it. state.wentStraight = TryGoingStraightToTarget(state.initialPos, true); - state.wasObstructed = PerformMove(dt, state.cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, state.pos, state.angle); + state.wasObstructed = PerformMove(dt, state.cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, state.pos, state.speed, state.angle, state.pushingPressure); } void CCmpUnitMotion::PostMove(CCmpUnitMotionManager::MotionState& state, fixed dt) @@ -1027,21 +1077,16 @@ { if (state.angle != state.initialAngle) state.cmpPosition->TurnTo(state.angle); - UpdateMovementState(fixed::Zero()); + UpdateMovementState(fixed::Zero(), fixed::Zero()); } else { // Update the Position component after our movement (if we actually moved anywhere) CFixedVector2D offset = state.pos - state.initialPos; - // When moving always set the angle in the direction of the movement, - // if we are not trying to move, assume this is pushing-related movement, - // and maintain the current angle instead. - if (IsMoveRequested()) - state.angle = atan2_approx(offset.X, offset.Y); state.cmpPosition->MoveAndTurnTo(state.pos.X, state.pos.Y, state.angle); // Calculate the mean speed over this past turn. - UpdateMovementState(offset.Length() / dt); + UpdateMovementState(state.speed, offset.Length() / dt); } if (state.wasObstructed && HandleObstructedMove(state.pos != state.initialPos)) @@ -1094,7 +1139,7 @@ return false; } -bool CCmpUnitMotion::PerformMove(fixed dt, const fixed& turnRate, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos, entity_angle_t& angle) const +bool CCmpUnitMotion::PerformMove(fixed dt, const fixed& turnRate, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos, fixed& speed, entity_angle_t& angle, uint8_t pushingPressure) const { // If there are no waypoint, behave as though we were obstructed and let HandleObstructedMove handle it. if (shortPath.m_Waypoints.empty() && longPath.m_Waypoints.empty()) @@ -1106,11 +1151,6 @@ while (angle < -entity_angle_t::Pi()) angle += entity_angle_t::Pi() * 2; - // TODO: there's some asymmetry here when units look at other - // units' positions - the result will depend on the order of execution. - // Maybe we should split the updates into multiple phases to minimise - // that problem. - CmpPtr cmpPathfinder(GetSystemEntity()); ENSURE(cmpPathfinder); @@ -1119,13 +1159,30 @@ if (IsMovingAsFormation()) basicSpeed = m_Speed.Multiply(m_RunMultiplier); - // Find the speed factor of the underlying terrain. - // (We only care about the tile we start on - it doesn't matter if we're moving - // partially onto a much slower/faster tile). - // TODO: Terrain-dependent speeds are not currently supported. - fixed terrainSpeed = fixed::FromInt(1); + // If pushing pressure is applied, slow the unit down. + if (pushingPressure) + { + // Values below this pressure don't slow the unit down (avoids slowing groups down). + constexpr int pressureMinThreshold = 10; + + // Lower speed up to a floor to prevent units from getting stopped. + // This helped pushing particularly for fast units, since they'll end up slowing down. + constexpr int maxPressure = CCmpUnitMotionManager::MAX_PRESSURE - pressureMinThreshold - 80; + constexpr entity_pos_t floorSpeed = entity_pos_t::FromFraction(3, 2); + static_assert(maxPressure > 0); + + uint8_t slowdown = maxPressure - std::min(maxPressure, std::max(0, pushingPressure - pressureMinThreshold)); + basicSpeed = basicSpeed.Multiply(fixed::FromInt(slowdown) / maxPressure); + // NB: lowering this too much will make the units behave a lot like viscous fluid + // when the density becomes extreme. While perhaps realistic (and kind of neat), + // it's not very helpful for gameplay. Empirically, a value of 1.5 avoids most of the effect + // while still slowing down movement significantly, and seems like a good balance. + // Min with the template speed to allow units that are explicitly absurdly slow. + basicSpeed = std::max(std::min(m_TemplateWalkSpeed, floorSpeed), basicSpeed); + } - fixed maxSpeed = basicSpeed.Multiply(terrainSpeed); + // TODO: would be nice to support terrain-dependent speed again. + fixed maxSpeed = basicSpeed; fixed timeLeft = dt; fixed zero = fixed::Zero(); @@ -1151,21 +1208,27 @@ target = CFixedVector2D(shortPath.m_Waypoints.back().x, shortPath.m_Waypoints.back().z); CFixedVector2D offset = target - pos; + if (turnRate > zero && !offset.IsZero()) { - fixed maxRotation = turnRate.Multiply(timeLeft); fixed angleDiff = angle - atan2_approx(offset.X, offset.Y); - if (angleDiff != zero) + fixed absoluteAngleDiff = angleDiff.Absolute(); + if (absoluteAngleDiff > entity_angle_t::Pi()) + absoluteAngleDiff = entity_angle_t::Pi() * 2 - absoluteAngleDiff; + + // We only rotate to the instantTurnAngle angle. The rest we rotate during movement. + if (absoluteAngleDiff > m_InstantTurnAngle) { - fixed absoluteAngleDiff = angleDiff.Absolute(); - if (absoluteAngleDiff > entity_angle_t::Pi()) - absoluteAngleDiff = entity_angle_t::Pi() * 2 - absoluteAngleDiff; + // Stop moving when rotating this far. + speed = zero; + + fixed maxRotation = turnRate.Multiply(timeLeft); // Figure out whether rotating will increase or decrease the angle, and how far we need to rotate in that direction. int direction = (entity_angle_t::Zero() < angleDiff && angleDiff <= entity_angle_t::Pi()) || angleDiff < -entity_angle_t::Pi() ? -1 : 1; // Can't rotate far enough, just rotate in the correct direction. - if (absoluteAngleDiff > maxRotation) + if (absoluteAngleDiff - m_InstantTurnAngle > maxRotation) { angle += maxRotation * direction; if (angle * direction > entity_angle_t::Pi()) @@ -1174,13 +1237,22 @@ } // Rotate towards the next waypoint and continue moving. angle = atan2_approx(offset.X, offset.Y); - // Give some 'free' rotation for angles below 0.5 radians. - timeLeft = (std::min(maxRotation, maxRotation - absoluteAngleDiff + fixed::FromInt(1)/2)) / turnRate; + timeLeft = std::min(maxRotation, maxRotation - absoluteAngleDiff + m_InstantTurnAngle) / turnRate; + } + else + { + // Modify the speed depending on the angle difference. + fixed sin, cos; + sincos_approx(angleDiff, sin, cos); + speed = speed.Multiply(cos); + angle = atan2_approx(offset.X, offset.Y); } } // Work out how far we can travel in timeLeft. - fixed maxdist = maxSpeed.Multiply(timeLeft); + fixed accelTime = std::min(timeLeft, (maxSpeed - speed) / m_Acceleration); + fixed accelDist = speed.Multiply(accelTime) + accelTime.Square().Multiply(m_Acceleration) / 2; + fixed maxdist = accelDist + maxSpeed.Multiply(timeLeft - accelTime); // If the target is close, we can move there directly. fixed offsetLength = offset.Length(); @@ -1191,7 +1263,20 @@ pos = target; // Spend the rest of the time heading towards the next waypoint. - timeLeft = (maxdist - offsetLength) / maxSpeed; + // Either we still need to accelerate after, or we have reached maxSpeed. + // The former is much less likely than the latter: usually we can reach + // maxSpeed within one waypoint. So the Sqrt is not too bad. + if (offsetLength <= accelDist) + { + fixed requiredTime = (-speed + (speed.Square() + offsetLength.Multiply(m_Acceleration).Multiply(fixed::FromInt(2))).Sqrt()) / m_Acceleration; + timeLeft -= requiredTime; + speed += m_Acceleration.Multiply(requiredTime); + } + else + { + timeLeft -= accelTime + (offsetLength - accelDist) / maxSpeed; + speed = maxSpeed; + } if (shortPath.m_Waypoints.empty()) longPath.m_Waypoints.pop_back(); @@ -1212,6 +1297,8 @@ offset.Normalize(maxdist); target = pos + offset; + speed = std::min(maxSpeed, speed + m_Acceleration.Multiply(timeLeft)); + if (cmpPathfinder->CheckMovement(GetObstructionFilter(specificIgnore), pos.X, pos.Y, target.X, target.Y, m_Clearance, m_PassClass)) pos = target; else @@ -1223,18 +1310,19 @@ return false; } -void CCmpUnitMotion::UpdateMovementState(entity_pos_t speed) +void CCmpUnitMotion::UpdateMovementState(entity_pos_t speed, entity_pos_t meanSpeed) { CmpPtr cmpVisual(GetEntityHandle()); if (cmpVisual) { - if (speed == fixed::Zero()) + if (meanSpeed == fixed::Zero()) cmpVisual->SelectMovementAnimation("idle", fixed::FromInt(1)); else - cmpVisual->SelectMovementAnimation(speed > (m_WalkSpeed / 2).Multiply(m_RunMultiplier + fixed::FromInt(1)) ? "run" : "walk", speed); + cmpVisual->SelectMovementAnimation(meanSpeed > (m_WalkSpeed / 2).Multiply(m_RunMultiplier + fixed::FromInt(1)) ? "run" : "walk", meanSpeed); } - m_CurSpeed = speed; + m_LastTurnSpeed = meanSpeed; + m_CurrentSpeed = speed; } bool CCmpUnitMotion::HandleObstructedMove(bool moved) @@ -1731,7 +1819,7 @@ } m_ExpectedPathTicket.m_Type = Ticket::SHORT_PATH; - m_ExpectedPathTicket.m_Ticket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Clearance, searchRange, goal, m_PassClass, true, GetGroup(), GetEntityId()); + m_ExpectedPathTicket.m_Ticket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Clearance, searchRange, goal, m_PassClass, ShouldCollideWithMovingUnits(), GetGroup(), GetEntityId()); } bool CCmpUnitMotion::MoveTo(MoveRequest request) diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpUnitMotionManager.h 0ad-0.0.26/source/simulation2/components/CCmpUnitMotionManager.h --- 0ad-0.0.25b/source/simulation2/components/CCmpUnitMotionManager.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpUnitMotionManager.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,28 +28,29 @@ class CCmpUnitMotion; -class CCmpUnitMotionManager : public ICmpUnitMotionManager +class CCmpUnitMotionManager final : public ICmpUnitMotionManager { public: - static void ClassInit(CComponentManager& componentManager) - { - componentManager.SubscribeToMessageType(MT_TerrainChanged); - componentManager.SubscribeToMessageType(MT_TurnStart); - componentManager.SubscribeToMessageType(MT_Update_Final); - componentManager.SubscribeToMessageType(MT_Update_MotionUnit); - componentManager.SubscribeToMessageType(MT_Update_MotionFormation); - } + static void ClassInit(CComponentManager& componentManager); DEFAULT_COMPONENT_ALLOCATOR(UnitMotionManager) + /** + * Maximum value for pushing pressure. + */ + static constexpr int MAX_PRESSURE = 255; + // Persisted state for each unit. struct MotionState { - MotionState(CmpPtr cmpPos, CCmpUnitMotion* cmpMotion); + MotionState(ICmpPosition* cmpPos, CCmpUnitMotion* cmpMotion); // Component references - these must be kept alive for the duration of motion. - // NB: this is generally not something one should do, but because of the tight coupling here it's doable. - CmpPtr cmpPosition; + // NB: this is generally a super dangerous thing to do, + // but the tight coupling with CCmpUnitMotion makes it workable. + // NB: this assumes that components do _not_ move in memory, + // which is currently a fair assumption but might change in the future. + ICmpPosition* cmpPosition; CCmpUnitMotion* cmpUnitMotion; // Position before units start moving @@ -60,6 +61,8 @@ // Accumulated "pushing" from nearby units. CFixedVector2D push; + fixed speed; + fixed initialAngle; fixed angle; @@ -67,6 +70,11 @@ // (this is required because formations may be tight and large units may end up never settling. entity_id_t controlGroup = INVALID_ENTITY; + // This is a ad-hoc counter to store under how much pushing 'pressure' an entity is. + // More pressure will slow the unit down and make it harder to push, + // which effectively bogs down groups of colliding units. + uint8_t pushingPressure = 0; + // Meta-flag -> this entity won't push nor be pushed. // (used for entities that have their obstruction disabled). bool ignore = false; @@ -83,14 +91,25 @@ // "Template" state, not serialized (cannot be changed mid-game). - // Multiplier for the pushing radius. Pre-multiplied by the circle-square correction factor. - entity_pos_t m_PushingRadius; - // Additive modifiers to the pushing radius for moving units and idle units respectively. + // The maximal distance at which units push each other is the combined unit clearances, multipled by this factor, + // itself pre-multiplied by the circle-square correction factor. + entity_pos_t m_PushingRadiusMultiplier; + // Additive modifiers to the maximum pushing distance for moving units and idle units respectively. entity_pos_t m_MovingPushExtension; entity_pos_t m_StaticPushExtension; + // Multiplier for the pushing 'spread'. + // This should be understand as the % of the maximum distance where pushing will be "in full force". + entity_pos_t m_MovingPushingSpread; + entity_pos_t m_StaticPushingSpread; + // Pushing forces below this value are ignored - this prevents units moving forever by very small increments. entity_pos_t m_MinimalPushing; + // Multiplier for pushing pressure strength. + entity_pos_t m_PushingPressureStrength; + // Per-turn reduction in pushing pressure. + entity_pos_t m_PushingPressureDecay; + // These vectors are reconstructed on deserialization. EntityMap m_Units; @@ -106,71 +125,32 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)); - - virtual void Deinit() - { - } + void Init(const CParamNode& UNUSED(paramNode)) override; - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Deinit() override { } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) - { - Init(paramNode); - ResetSubdivisions(); - } + void Serialize(ISerializer& serialize) override; + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override; - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) - { - switch (msg.GetType()) - { - case MT_TerrainChanged: - { - CmpPtr cmpTerrain(GetSystemEntity()); - if (cmpTerrain->GetVerticesPerSide() != m_MovingUnits.width()) - ResetSubdivisions(); - break; - } - case MT_TurnStart: - { - OnTurnStart(); - break; - } - case MT_Update_MotionFormation: - { - fixed dt = static_cast(msg).turnLength; - m_ComputingMotion = true; - MoveFormations(dt); - m_ComputingMotion = false; - break; - } - case MT_Update_MotionUnit: - { - fixed dt = static_cast(msg).turnLength; - m_ComputingMotion = true; - MoveUnits(dt); - m_ComputingMotion = false; - break; - } - } - } + void HandleMessage(const CMessage& msg, bool global) override; - virtual void Register(CCmpUnitMotion* component, entity_id_t ent, bool formationController); - virtual void Unregister(entity_id_t ent); + void Register(CCmpUnitMotion* component, entity_id_t ent, bool formationController) override; + void Unregister(entity_id_t ent) override; - virtual bool ComputingMotion() const + bool ComputingMotion() const override { return m_ComputingMotion; } - virtual bool IsPushingActivated() const + bool IsPushingActivated() const override { - return m_PushingRadius != entity_pos_t::Zero(); + return m_PushingRadiusMultiplier != entity_pos_t::Zero(); } private: + void OnDeserialized(); void ResetSubdivisions(); void OnTurnStart(); @@ -181,17 +161,6 @@ void Push(EntityMap::value_type& a, EntityMap::value_type& b, fixed dt); }; -void CCmpUnitMotionManager::ResetSubdivisions() -{ - CmpPtr cmpTerrain(GetSystemEntity()); - if (!cmpTerrain) - return; - - size_t size = cmpTerrain->GetMapSize(); - u16 gridSquareSize = static_cast(size / 20 + 1); - m_MovingUnits.resize(gridSquareSize, gridSquareSize); -} - REGISTER_COMPONENT_TYPE(UnitMotionManager) #endif // INCLUDED_CCMPUNITMOTIONMANAGER diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpUnitMotion_System.cpp 0ad-0.0.26/source/simulation2/components/CCmpUnitMotion_System.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpUnitMotion_System.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpUnitMotion_System.cpp 2022-08-21 12:45:40.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,7 +24,14 @@ #include "ps/CLogger.h" #include "ps/Profile.h" +#include +#include #include +#include + +#define DEBUG_STATS 0 +#define DEBUG_RENDER 0 +#define DEBUG_RENDER_ALL_PUSH 0 // NB: this TU contains the CCmpUnitMotion/CCmpUnitMotionManager couple. // In practice, UnitMotionManager functions need access to the full implementation of UnitMotion, @@ -32,38 +39,144 @@ // To avoid inclusion issues, implementation of UnitMotionManager that uses UnitMotion is here. namespace { - /** - * Units push only within their own grid square. This is the size of each square (in arbitrary units). - * TODO: check other values. - */ - static const int PUSHING_GRID_SIZE = 20; - - /** - * For pushing, treat the clearances as a circle - they're defined as squares, - * so we'll take the circumscribing square (approximately). - * Clerances are also full-width instead of half, so we want to divide by two. sqrt(2)/2 is about 0.71 < 5/7. - */ - static const entity_pos_t PUSHING_CORRECTION = entity_pos_t::FromInt(5) / 7; - - /** - * Arbitrary constant used to reduce pushing to levels that won't break physics for our turn length. - */ - static const int PUSHING_REDUCTION_FACTOR = 2; - - /** - * Maximum distance multiplier. - * NB: this value interacts with the "minimal pushing" force, - * as two perfectly overlapping units exert MAX_DISTANCE_FACTOR * Turn length in ms / REDUCTION_FACTOR - * of force on each other each turn. If this is below the minimal pushing force, any 2 units can entirely overlap. - */ - static const entity_pos_t MAX_DISTANCE_FACTOR = entity_pos_t::FromInt(5) / 2; +/** + * Units push within their square and neighboring squares (except diagonals). This is the size of each square (in meters). + * I have tested grid sizes from 10 up to 80 and overall it made little difference to the performance, + * mostly, I suspect, because pushing is generally dwarfed by regular motion costs. + * However, the algorithm remains n^2 in comparisons so it's probably best to err on the side of smaller grids, which will have lower spikes. + * The balancing act is between comparisons, unordered_set insertions and unordered_set iterations. + * For these reasons, a value of 20 which is rather small but not overly so was chosen. + */ +constexpr int PUSHING_GRID_SIZE = 20; + +/** + * For pushing, treat the clearances as a circle - they're defined as squares, + * so we'll take the circumscribing square (approximately). + * Clerances are also full-width instead of half, so we want to divide by two. sqrt(2)/2 is about 0.71 < 5/7. + */ +constexpr entity_pos_t PUSHING_CORRECTION = entity_pos_t::FromFraction(5, 7); + +/** + * Arbitrary constant used to reduce pushing to levels that won't break physics for our turn length. + */ +constexpr int PUSHING_REDUCTION_FACTOR = 2; + +/** + * Maximum distance-related multiplier. + * NB: this value interacts with the "minimal pushing" force, + * as two perfectly overlapping units exert MAX_DISTANCE_FACTOR * Turn length in ms / REDUCTION_FACTOR + * of force on each other each turn. If this is below the minimal pushing force, any 2 units can entirely overlap. + */ +constexpr entity_pos_t MAX_DISTANCE_FACTOR = entity_pos_t::FromFraction(5, 2); + +/** + * Maximum pushing multiplier for a single push calculation. + * This exists for numerical stability of the system between a lightweight and a heavy unit. + */ +constexpr int MAX_PUSHING_MULTIPLIER = 4; + +/** + * When two units collide, if their movement dot product is below this value, give them a perpendicular nudge instead of trying to push in the regular way. + */ +constexpr entity_pos_t PERPENDICULAR_NUDGE_THRESHOLD = entity_pos_t::FromFraction(-1, 10); + +/** + * Pushing is dampened by pushing pressure, but this is capped so that units still get pushed. + */ +constexpr int MAX_PUSH_DAMPING_PRESSURE = 160; +static_assert(MAX_PUSH_DAMPING_PRESSURE < CCmpUnitMotionManager::MAX_PRESSURE); + +/** + * When units are obstructed because they're being pushed away from where they want to go, + * raise the pushing pressure to at least this value. + */ +constexpr int MIN_PRESSURE_IF_OBSTRUCTED = 80; + +/** + * These two numbers are used to calculate pushing pressure between two units. + */ +constexpr entity_pos_t PRESSURE_STATIC_FACTOR = entity_pos_t::FromInt(2); +constexpr int PRESSURE_DISTANCE_FACTOR = 5; } -CCmpUnitMotionManager::MotionState::MotionState(CmpPtr cmpPos, CCmpUnitMotion* cmpMotion) +#if DEBUG_RENDER +#include "maths/Frustum.h" + +void RenderDebugOverlay(SceneCollector& collector, const CFrustum& frustum, bool culling); + +struct SDebugData { + std::vector m_Spheres; + std::vector m_Lines; + std::vector m_Quads; +} debugDataMotionMgr; +#endif + +CCmpUnitMotionManager::MotionState::MotionState(ICmpPosition* cmpPos, CCmpUnitMotion* cmpMotion) : cmpPosition(cmpPos), cmpUnitMotion(cmpMotion) { + static_assert(MAX_PRESSURE <= std::numeric_limits::max(), "MAX_PRESSURE is higher than the maximum value of the underlying type."); +} + +void CCmpUnitMotionManager::ClassInit(CComponentManager& componentManager) +{ + componentManager.SubscribeToMessageType(MT_Deserialized); + componentManager.SubscribeToMessageType(MT_TerrainChanged); + componentManager.SubscribeToMessageType(MT_TurnStart); + componentManager.SubscribeToMessageType(MT_Update_Final); + componentManager.SubscribeToMessageType(MT_Update_MotionUnit); + componentManager.SubscribeToMessageType(MT_Update_MotionFormation); +#if DEBUG_RENDER + componentManager.SubscribeToMessageType(MT_RenderSubmit); +#endif } +void CCmpUnitMotionManager::HandleMessage(const CMessage& msg, bool UNUSED(global)) +{ + switch (msg.GetType()) + { + case MT_TerrainChanged: + { + CmpPtr cmpTerrain(GetSystemEntity()); + if (cmpTerrain->GetVerticesPerSide() != m_MovingUnits.width()) + ResetSubdivisions(); + break; + } + case MT_TurnStart: + { + OnTurnStart(); + break; + } + case MT_Update_MotionFormation: + { + fixed dt = static_cast(msg).turnLength; + m_ComputingMotion = true; + MoveFormations(dt); + m_ComputingMotion = false; + break; + } + case MT_Update_MotionUnit: + { + fixed dt = static_cast(msg).turnLength; + m_ComputingMotion = true; + MoveUnits(dt); + m_ComputingMotion = false; + break; + } + case MT_Deserialized: + { + OnDeserialized(); + break; + } +#if DEBUG_RENDER + case MT_RenderSubmit: + { + const CMessageRenderSubmit& msgData = static_cast (msg); + RenderDebugOverlay(msgData.collector, msgData.frustum, msgData.culling); + break; + } +#endif + } +} void CCmpUnitMotionManager::Init(const CParamNode&) { // Load some data - see CCmpPathfinder.xml. @@ -76,19 +189,43 @@ // NB: all values are given sane default, but they are not treated as optional in the schema, // so the XML file is the reference. + { + const CParamNode spread = pushingNode.GetChild("MovingSpread"); + if (spread.IsOk()) + { + m_MovingPushingSpread = Clamp(spread.ToFixed(), entity_pos_t::Zero(), entity_pos_t::FromInt(1)); + if (m_MovingPushingSpread != spread.ToFixed()) + LOGWARNING("Moving pushing spread was clamped to the 0-1 range."); + } + else + m_MovingPushingSpread = entity_pos_t::FromInt(5) / 8; + } + + { + const CParamNode spread = pushingNode.GetChild("StaticSpread"); + if (spread.IsOk()) + { + m_StaticPushingSpread = Clamp(spread.ToFixed(), entity_pos_t::Zero(), entity_pos_t::FromInt(1)); + if (m_StaticPushingSpread != spread.ToFixed()) + LOGWARNING("Static pushing spread was clamped to the 0-1 range."); + } + else + m_StaticPushingSpread = entity_pos_t::FromInt(5) / 8; + } + const CParamNode radius = pushingNode.GetChild("Radius"); if (radius.IsOk()) { - m_PushingRadius = radius.ToFixed(); - if (m_PushingRadius < entity_pos_t::Zero()) + m_PushingRadiusMultiplier = radius.ToFixed(); + if (m_PushingRadiusMultiplier < entity_pos_t::Zero()) { - LOGWARNING("Pushing radius cannot be below 0. De-activating pushing but 'pathfinder.xml' should be updated."); - m_PushingRadius = entity_pos_t::Zero(); + LOGWARNING("Pushing radius multiplier cannot be below 0. De-activating pushing but 'pathfinder.xml' should be updated."); + m_PushingRadiusMultiplier = entity_pos_t::Zero(); } // No upper value, but things won't behave sanely if values are too high. } else - m_PushingRadius = entity_pos_t::FromInt(8) / 5; + m_PushingRadiusMultiplier = entity_pos_t::FromInt(8) / 5; const CParamNode minForce = pushingNode.GetChild("MinimalForce"); if (minForce.IsOk()) @@ -108,11 +245,126 @@ m_MovingPushExtension = entity_pos_t::FromInt(5) / 2; m_StaticPushExtension = entity_pos_t::FromInt(2); } + + const CParamNode pressureStrength = pushingNode.GetChild("PressureStrength"); + if (pressureStrength.IsOk()) + { + m_PushingPressureStrength = pressureStrength.ToFixed(); + if (m_PushingPressureStrength < entity_pos_t::Zero()) + { + LOGWARNING("Pushing pressure strength cannot be below 0. 'pathfinder.xml' should be updated."); + m_PushingPressureStrength = entity_pos_t::Zero(); + } + // No upper value, but things won't behave sanely if values are too high. + } + else + m_PushingPressureStrength = entity_pos_t::FromInt(1); + + const CParamNode pushingPressure = pushingNode.GetChild("PressureDecay"); + if (pushingPressure.IsOk()) + { + m_PushingPressureDecay = Clamp(pushingPressure.ToFixed(), entity_pos_t::Zero(), entity_pos_t::FromInt(1)); + if (m_PushingPressureDecay != pushingPressure.ToFixed()) + LOGWARNING("Pushing pressure decay was clamped to the 0-1 range."); + } + else + m_PushingPressureDecay = entity_pos_t::FromInt(6) / 10; + +} + +template<> +struct SerializeHelper +{ + template + void operator()(S& serialize, const char* UNUSED(name), Serialize::qualify value) + { + Serializer(serialize, "pushing pressure", value.pushingPressure); + } +}; + +template<> +struct SerializeHelper> +{ + void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap& value) + { + // Serialize manually, we don't have a default-constructor for deserialization. + Serializer(serialize, "size", static_cast(value.size())); + for (EntityMap::iterator it = value.begin(); it != value.end(); ++it) + { + Serializer(serialize, "ent id", it->first); + Serializer(serialize, "state", it->second); + } + } + + void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap& value) + { + u32 units = 0; + Serializer(deserialize, "size", units); + for (u32 i = 0; i < units; ++i) + { + entity_id_t ent = INVALID_ENTITY; + Serializer(deserialize, "ent id", ent); + // Insert an invalid motion state, will be cleared up in MT_Deserialized. + CCmpUnitMotionManager::MotionState state(nullptr, nullptr); + Serializer(deserialize, "state", state); + value.insert(ent, state); + } + } +}; + +void CCmpUnitMotionManager::Serialize(ISerializer& serialize) +{ + Serializer(serialize, "m_Units", m_Units); + Serializer(serialize, "m_FormationControllers", m_FormationControllers); +} + +void CCmpUnitMotionManager::Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) +{ + Init(paramNode); + ResetSubdivisions(); + Serializer(deserialize, "m_Units", m_Units); + Serializer(deserialize, "m_FormationControllers", m_FormationControllers); +} + +/** + * This deserialization process is rather ugly, but it's required to store some data in the motion states. + * Ideally, the motion state would actually be CCmpUnitMotion themselves, but for data locality + * (because our components are stored randomly on the heap right now) they're not. + * If we ever change the simulation so that components could be registered by their managers and exposed, + * then we could just use CCmpUnitMotion directly and clean this code uglyness. + */ +void CCmpUnitMotionManager::OnDeserialized() +{ + // Fetch the components now that they exist. + // The rest of the data was already deserialized or will be reconstructed. + for (EntityMap::iterator it = m_Units.begin(); it != m_Units.end(); ++it) + { + it->second.cmpPosition = static_cast(QueryInterface(GetSimContext(), it->first, IID_Position)); + // We can know for a fact that these are CCmpUnitMotion because those are the ones registering with us + // (and to ensure that they pass a CCmpUnitMotion pointer when registering). + it->second.cmpUnitMotion = static_cast(static_cast(QueryInterface(GetSimContext(), it->first, IID_UnitMotion))); + } + for (EntityMap::iterator it = m_FormationControllers.begin(); it != m_FormationControllers.end(); ++it) + { + it->second.cmpPosition = static_cast(QueryInterface(GetSimContext(), it->first, IID_Position)); + it->second.cmpUnitMotion = static_cast(static_cast(QueryInterface(GetSimContext(), it->first, IID_UnitMotion))); + } +} + +void CCmpUnitMotionManager::ResetSubdivisions() +{ + CmpPtr cmpTerrain(GetSystemEntity()); + if (!cmpTerrain) + return; + + size_t size = cmpTerrain->GetMapSize(); + u16 gridSquareSize = static_cast(size / PUSHING_GRID_SIZE + 1); + m_MovingUnits.resize(gridSquareSize, gridSquareSize); } void CCmpUnitMotionManager::Register(CCmpUnitMotion* component, entity_id_t ent, bool formationController) { - MotionState state(CmpPtr(GetSimContext(), ent), component); + MotionState state(static_cast(QueryInterface(GetSimContext(), ent, IID_Position)), component); if (!formationController) m_Units.insert(ent, state); else @@ -153,6 +405,16 @@ void CCmpUnitMotionManager::Move(EntityMap& ents, fixed dt) { +#if DEBUG_RENDER + debugDataMotionMgr.m_Spheres.clear(); + debugDataMotionMgr.m_Lines.clear(); + debugDataMotionMgr.m_Quads.clear(); +#endif +#if DEBUG_STATS + int comparisons = 0; + double start = timer_Time(); +#endif + PROFILE2("MotionMgr_Move"); std::unordered_set::iterator>*> assigned; for (EntityMap::iterator it = ents.begin(); it != ents.end(); ++it) @@ -167,6 +429,7 @@ it->second.initialPos = it->second.cmpPosition->GetPosition2D(); it->second.initialAngle = it->second.cmpPosition->GetRotation().Y; it->second.pos = it->second.initialPos; + it->second.speed = it->second.cmpUnitMotion->GetCurrentSpeed(); it->second.angle = it->second.initialAngle; ENSURE(it->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE < m_MovingUnits.width() && it->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE < m_MovingUnits.height()); @@ -179,33 +442,108 @@ } for (std::vector::iterator>* vec : assigned) + { +#if DEBUG_RENDER + { + SOverlayLine gridL; + auto it = (*vec)[0]; + gridL.PushCoords(CVector3D(it->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE, + it->second.cmpPosition->GetHeightFixed().ToDouble() + 2.f, + it->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE)); + gridL.PushCoords(CVector3D(it->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE + PUSHING_GRID_SIZE, + it->second.cmpPosition->GetHeightFixed().ToDouble() + 2.f, + it->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE)); + gridL.PushCoords(CVector3D(it->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE + PUSHING_GRID_SIZE, + it->second.cmpPosition->GetHeightFixed().ToDouble() + 2.f, + it->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE + PUSHING_GRID_SIZE)); + gridL.PushCoords(CVector3D(it->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE, + it->second.cmpPosition->GetHeightFixed().ToDouble() + 2.f, + it->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE + PUSHING_GRID_SIZE)); + gridL.PushCoords(CVector3D(it->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE, + it->second.cmpPosition->GetHeightFixed().ToDouble() + 2.f, + it->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE * PUSHING_GRID_SIZE)); + gridL.m_Color = CColor(1, 1, 0, 1); + debugDataMotionMgr.m_Lines.push_back(gridL); + } +#endif for (EntityMap::iterator& it : *vec) + { if (it->second.needUpdate) it->second.cmpUnitMotion->Move(it->second, dt); + // Decay pressure after moving so we can get the full 0-MAX_PRESSURE range of values. + it->second.pushingPressure = (m_PushingPressureDecay * it->second.pushingPressure).ToInt_RoundToZero(); + } + } // Skip pushing entirely if the radius is 0 - if (&ents == &m_Units && m_PushingRadius != entity_pos_t::Zero()) + if (&ents == &m_Units && IsPushingActivated()) { PROFILE2("MotionMgr_Pushing"); for (std::vector::iterator>* vec : assigned) { ENSURE(!vec->empty()); + std::vector< std::vector::iterator>* > consider = { vec }; - std::vector::iterator>::iterator cit1 = vec->begin(); - do + int x = (*vec)[0]->second.pos.X.ToInt_RoundToZero() / PUSHING_GRID_SIZE; + int z = (*vec)[0]->second.pos.Y.ToInt_RoundToZero() / PUSHING_GRID_SIZE; + if (x + 1 < m_MovingUnits.width()) + consider.push_back(&m_MovingUnits.get(x + 1, z)); + if (x > 0) + consider.push_back(&m_MovingUnits.get(x - 1, z)); + if (z + 1 < m_MovingUnits.height()) + consider.push_back(&m_MovingUnits.get(x, z + 1)); + if (z > 0) + consider.push_back(&m_MovingUnits.get(x, z - 1)); + + for (EntityMap::iterator& it : *vec) { - if ((*cit1)->second.ignore) + if (it->second.ignore) continue; - std::vector::iterator>::iterator cit2 = cit1; - while(++cit2 != vec->end()) - if (!(*cit2)->second.ignore) - Push(**cit1, **cit2, dt); + +#if DEBUG_RENDER + // Plop a sphere at the unit end-pos. + { + SOverlaySphere sph; + sph.m_Center = CVector3D(it->second.pos.X.ToDouble(), it->second.cmpPosition->GetHeightFixed().ToDouble() + 13.f, it->second.pos.Y.ToDouble()); + sph.m_Radius = it->second.cmpUnitMotion->m_Clearance.Multiply(PUSHING_CORRECTION).ToDouble(); + // Color the sphere: the redder, the more 'bogged down' it is. + sph.m_Color = CColor(it->second.pushingPressure / static_cast(MAX_PRESSURE), 0, 0, 1); + debugDataMotionMgr.m_Spheres.push_back(sph); + } + /* Show the pushing sphere, kinda unreadable. + { + SOverlaySphere sph; + sph.m_Center = CVector3D(it->second.pos.X.ToDouble(), it->second.cmpPosition->GetHeightFixed().ToDouble() + 13.f, it->second.pos.Y.ToDouble()); + sph.m_Radius = (it->second.cmpUnitMotion->m_Clearance.Multiply(PUSHING_CORRECTION).Multiply(m_PushingRadiusMultiplier) + (it->second.isMoving ? m_StaticPushExtension : m_MovingPushExtension)).ToDouble(); + // Color the sphere: the redder, the more 'bogged down' it is. + sph.m_Color = CColor(it->second.pushingPressure / static_cast(MAX_PRESSURE), 0, 0, 0.1); + debugDataMotionMgr.m_Spheres.push_back(sph); + }*/ + // Show the travel over this turn. + SOverlayLine line; + line.PushCoords(CVector3D(it->second.initialPos.X.ToDouble(), + it->second.cmpPosition->GetHeightFixed().ToDouble() + 13.f, + it->second.initialPos.Y.ToDouble())); + line.PushCoords(CVector3D(it->second.pos.X.ToDouble(), + it->second.cmpPosition->GetHeightFixed().ToDouble() + 13.f, + it->second.pos.Y.ToDouble())); + line.m_Color = CColor(1, 0, 1, 0.5); + debugDataMotionMgr.m_Lines.push_back(line); +#endif + for (std::vector::iterator>* vec2 : consider) + for (EntityMap::iterator& it2 : *vec2) + if (it->first < it2->first && !it2->second.ignore) + { +#if DEBUG_STATS + ++comparisons; +#endif + Push(*it, *it2, dt); + } } - while(++cit1 != vec->end()); } } - if (m_PushingRadius != entity_pos_t::Zero()) + if (IsPushingActivated()) { PROFILE2("MotionMgr_PushAdjust"); CmpPtr cmpPathfinder(GetSystemEntity()); @@ -217,6 +555,50 @@ if (!it->second.needUpdate || it->second.ignore) continue; +#if DEBUG_RENDER + SOverlayLine line; + line.PushCoords(CVector3D(it->second.pos.X.ToDouble(), + it->second.cmpPosition->GetHeightFixed().ToDouble() + 15.1f , + it->second.pos.Y.ToDouble())); + line.PushCoords(CVector3D(it->second.pos.X.ToDouble() + it->second.push.X.ToDouble() * 10.f, + it->second.cmpPosition->GetHeightFixed().ToDouble() + 15.1f , + it->second.pos.Y.ToDouble() + it->second.push.Y.ToDouble() * 10.f)); + line.m_Thickness = 0.05f; +#endif + + // Only apply pushing if the effect is significant enough. + if (it->second.push.CompareLength(m_MinimalPushing) <= 0) + { +#if DEBUG_RENDER + line.m_Color = CColor(1, 1, 0, 0.6); + debugDataMotionMgr.m_Lines.push_back(line); +#endif + it->second.push = CFixedVector2D(); + continue; + } + + // If there was an attempt at movement, and we're getting pushed significantly and + // away from where we'd like to go (measured by a low dot product) + // then mark the unit as obstructed, but push anyways. + // (this helps units stop earlier in many situations in a realistic-ish manner). + if (it->second.pos != it->second.initialPos + && (it->second.pos - it->second.initialPos).Dot(it->second.pos + it->second.push - it->second.initialPos) < entity_pos_t::FromInt(1)/2 && it->second.pushingPressure > 30) + { + it->second.wasObstructed = true; + it->second.pushingPressure = std::max(MIN_PRESSURE_IF_OBSTRUCTED, it->second.pushingPressure); + // Push anyways. + } +#if DEBUG_RENDER + if (it->second.wasObstructed) + line.m_Color = CColor(1, 0, 0, 1); + else + line.m_Color = CColor(0, 1, 0, 1); + debugDataMotionMgr.m_Lines.push_back(line); +#endif + // Dampen the pushing by the current pushing pressure + // (but prevent full dampening so that clumped units still get unclumped). + it->second.push = it->second.push * (MAX_PRESSURE - std::min(MAX_PUSH_DAMPING_PRESSURE, it->second.pushingPressure)) / MAX_PRESSURE; + // Prevent pushed units from crossing uncrossable boundaries // (we can assume that normal movement didn't push units into impassable terrain). if ((it->second.push.X != entity_pos_t::Zero() || it->second.push.Y != entity_pos_t::Zero()) && @@ -231,22 +613,9 @@ it->second.wasObstructed = true; it->second.wentStraight = false; it->second.push = CFixedVector2D(); + continue; } - // Only apply pushing if the effect is significant enough. - if (it->second.push.CompareLength(m_MinimalPushing) > 0) - { - // If there was an attempt at movement, and the pushed movement is in a sufficiently different direction - // (measured by an extremely arbitrary dot product) - // then mark the unit as obstructed still. - if (it->second.pos != it->second.initialPos && - (it->second.pos - it->second.initialPos).Dot(it->second.pos + it->second.push - it->second.initialPos) < entity_pos_t::FromInt(1)/2) - { - it->second.wasObstructed = true; - it->second.wentStraight = false; - // Push anyways. - } - it->second.pos += it->second.push; - } + it->second.pos += it->second.push; it->second.push = CFixedVector2D(); } } @@ -260,6 +629,14 @@ data.second.cmpUnitMotion->PostMove(data.second, dt); } } +#if DEBUG_STATS + int size = 0; + for (std::vector::iterator>* vec : assigned) + size += vec->size(); + double time = timer_Time() - start; + if (comparisons > 0) + printf(">> %i comparisons over %li grids, %f units per grid in %f secs\n", comparisons, assigned.size(), size / (float)(assigned.size()), time); +#endif for (std::vector::iterator>* vec : assigned) vec->clear(); } @@ -286,44 +663,81 @@ entity_pos_t combinedClearance = (a.second.cmpUnitMotion->m_Clearance + b.second.cmpUnitMotion->m_Clearance).Multiply(PUSHING_CORRECTION); entity_pos_t maxDist = combinedClearance; if (!sameControlGroup) - maxDist = combinedClearance.Multiply(m_PushingRadius) + (movingPush ? m_MovingPushExtension : m_StaticPushExtension); + maxDist = combinedClearance.Multiply(m_PushingRadiusMultiplier) + (movingPush ? m_MovingPushExtension : m_StaticPushExtension); + combinedClearance = maxDist.Multiply(movingPush ? m_MovingPushingSpread : m_StaticPushingSpread); - CFixedVector2D offset = a.second.pos - b.second.pos; + // Compare the average position of the two units over the turn - this makes overall behaviour better, + // as we really care more about units that end up either crossing paths or staying together. + CFixedVector2D offset = ((a.second.pos + a.second.initialPos) - (b.second.pos + b.second.initialPos)) / 2; + +#if DEBUG_RENDER + SOverlayLine line; + line.PushCoords(CVector3D(a.second.pos.X.ToDouble(), + a.second.cmpPosition->GetHeightFixed().ToDouble() + 8, + a.second.pos.Y.ToDouble())); + line.PushCoords(CVector3D(b.second.pos.X.ToDouble(), + b.second.cmpPosition->GetHeightFixed().ToDouble() + 8, + b.second.pos.Y.ToDouble())); + if (offset.CompareLength(maxDist) > 0) + { +#if DEBUG_RENDER_ALL_PUSH + line.m_Thickness = 0.01f; + line.m_Color = CColor(0, 0, 1, 0.4); + debugDataMotionMgr.m_Lines.push_back(line); + // then will return +#endif + } +#endif if (offset.CompareLength(maxDist) > 0) return; - entity_pos_t offsetLength = offset.Length(); - // If the offset is small enough that precision would be problematic, pick an arbitrary vector instead. - if (offsetLength <= entity_pos_t::Epsilon() * 10) - { - // Throw in some 'randomness' so that clumped units unclump more naturally. - bool dir = a.first % 2; - offset.X = entity_pos_t::FromInt(dir ? 1 : 0); - offset.Y = entity_pos_t::FromInt(dir ? 0 : 1); - offsetLength = entity_pos_t::Epsilon() * 10; + entity_pos_t offsetLength; + + // If the units appear to have crossed paths, give them a strong perpendicular nudge. + // Ideally, this will make them look like they avoided each other. + // Worst case, either the collision detection isn't picked up or they'll end up bogged down. + // NB: the dot product mostly works because we used average positions earlier. + // NB: this kinda works only because our turn lengths are large enough to make this relevant. + // In an ideal world, we'd anticipate here instead. + // Turn it off for formations - our current 'reforming' code is bad and leads to bad behaviour. + if (!sameControlGroup && (a.second.pos - b.second.pos).Dot(a.second.initialPos - b.second.initialPos) < PERPENDICULAR_NUDGE_THRESHOLD) + { + CFixedVector2D posDelta = (a.second.pos - b.second.pos) - (a.second.initialPos - b.second.initialPos); + CFixedVector2D perp = posDelta.Perpendicular(); + // Pick the best direction to avoid the target. + if (offset.Dot(perp) < (-offset).Dot(perp)) + offset = -perp; + else + offset = perp; + offsetLength = offset.Length(); + if (offsetLength > entity_pos_t::Epsilon() * 10) + { + // This needs to be a strong effect or it won't really work. + offset.X = offset.X / offsetLength * 3; + offset.Y = offset.Y / offsetLength * 3; + } + offsetLength = entity_pos_t::Zero(); } else { - offset.X = offset.X / offsetLength; - offset.Y = offset.Y / offsetLength; - } - - // If the units are moving in opposite direction, check if they might have phased through each other. - // If it looks like yes, move them perpendicularily so it looks like they avoid each other. - // NB: this isn't very precise, nor will it catch 100% of intersections - it's meant as a cheap improvement. - if (movingPush && (a.second.pos - a.second.initialPos).Dot(b.second.pos - b.second.initialPos) < entity_pos_t::Zero()) - // Perform some finer checking. - if (Geometry::TestRayAASquare(a.second.initialPos - b.second.initialPos, a.second.pos - b.second.initialPos, - CFixedVector2D(combinedClearance, combinedClearance)) - || - Geometry::TestRayAASquare(a.second.initialPos - b.second.pos, a.second.pos - b.second.pos, - CFixedVector2D(combinedClearance, combinedClearance))) + offsetLength = offset.Length(); + // If the offset is small enough that precision would be problematic, pick an arbitrary vector instead. + if (offsetLength <= entity_pos_t::Epsilon() * 10) { - offset = offset.Perpendicular(); - offsetLength = fixed::Zero(); + // Throw in some 'randomness' so that clumped units unclump more naturaslly. + bool dir = a.first % 2; + offset.X = entity_pos_t::FromInt(dir ? 1 : 0); + offset.Y = entity_pos_t::FromInt(dir ? 0 : 1); + offsetLength = entity_pos_t::Epsilon() * 10; } + else + { + offset.X = offset.X / offsetLength; + offset.Y = offset.Y / offsetLength; + } + } - // The pushing distance factor is 1 if the edges are touching, >1 up to MAX if the units overlap, < 1 otherwise. + // The pushing distance factor is 1 at the spread-modified combined clearance, >1 up to MAX if the units 'overlap', < 1 otherwise. entity_pos_t distanceFactor = maxDist - combinedClearance; // Force units that overlap a lot to have the maximum factor. if (distanceFactor <= entity_pos_t::Zero() || offsetLength < combinedClearance / 2) @@ -337,7 +751,46 @@ CFixedVector2D pushingDir = offset.Multiply(distanceFactor); - // Divide by an arbitrary constant to avoid pushing too much. - a.second.push += pushingDir.Multiply(dt / PUSHING_REDUCTION_FACTOR); - b.second.push -= pushingDir.Multiply(dt / PUSHING_REDUCTION_FACTOR); + // These cannot be zero, checked in the schema. + entity_pos_t aWeight = a.second.cmpUnitMotion->GetWeight(); + entity_pos_t bWeight = b.second.cmpUnitMotion->GetWeight(); + + // Final corrections: + // - divide by an arbitrary constant to avoid pushing too much. + // - multiply by the weight ratio (limiting the maximum positive push for numerical accuracy). + entity_pos_t timeFactor = dt / PUSHING_REDUCTION_FACTOR; + entity_pos_t maxPushing = timeFactor * MAX_PUSHING_MULTIPLIER; + a.second.push += pushingDir.Multiply(std::min(bWeight.MulDiv(timeFactor, aWeight), maxPushing)); + b.second.push -= pushingDir.Multiply(std::min(aWeight.MulDiv(timeFactor, bWeight), maxPushing)); + + // Use a constant factor to get a more general slowdown in crowded area. + // The distance factor heavily dampens units that are overlapping. + int addedPressure = std::max(0, (PRESSURE_STATIC_FACTOR + (distanceFactor + entity_pos_t::FromInt(-2)/3) * PRESSURE_DISTANCE_FACTOR).Multiply(m_PushingPressureStrength).ToInt_RoundToZero()); + a.second.pushingPressure = std::min(MAX_PRESSURE, a.second.pushingPressure + addedPressure); + b.second.pushingPressure = std::min(MAX_PRESSURE, b.second.pushingPressure + addedPressure); + +#if DEBUG_RENDER + // Make the lines thicker if the force is stronger. + line.m_Thickness = distanceFactor.ToDouble() / 10.0; + line.m_Color = CColor(1, addedPressure / 20.f, 0, 0.8); + debugDataMotionMgr.m_Lines.push_back(line); +#endif } + +#if DEBUG_RENDER +void RenderDebugOverlay(SceneCollector& collector, const CFrustum& frustum, bool UNUSED(culling)) +{ + for (SOverlaySphere& sph: debugDataMotionMgr.m_Spheres) + if (frustum.IsSphereVisible(sph.m_Center, sph.m_Radius)) + collector.Submit(&sph); + for (SOverlayLine& l: debugDataMotionMgr.m_Lines) + if (frustum.IsPointVisible(l.m_Coords[0]) || frustum.IsPointVisible(l.m_Coords[1])) + collector.Submit(&l); + for (SOverlayQuad& quad: debugDataMotionMgr.m_Quads) + collector.Submit(&quad); +} +#endif + +#undef DEBUG_STATS +#undef DEBUG_RENDER +#undef DEBUG_RENDER_ALL_PUSH diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpUnitRenderer.cpp 0ad-0.0.26/source/simulation2/components/CCmpUnitRenderer.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpUnitRenderer.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpUnitRenderer.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -61,7 +61,7 @@ * interpolated position and terrain. So we store a bounding sphere, which * is rotation-independent, instead of a bounding box. */ -class CCmpUnitRenderer : public ICmpUnitRenderer +class CCmpUnitRenderer final : public ICmpUnitRenderer { public: struct SUnit @@ -138,27 +138,27 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { m_FrameNumber = 0; m_FrameOffset = 0.0f; m_EnableDebugOverlays = false; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -189,7 +189,7 @@ return &m_Units[tag.n - 1]; } - virtual tag_t AddUnit(CEntityHandle entity, CUnit* actor, const CBoundingSphere& boundsApprox, int flags) + tag_t AddUnit(CEntityHandle entity, CUnit* actor, const CBoundingSphere& boundsApprox, int flags) override { ENSURE(actor != NULL); @@ -218,7 +218,7 @@ return tag; } - virtual void RemoveUnit(tag_t tag) + void RemoveUnit(tag_t tag) override { SUnit* unit = LookupUnit(tag); unit->actor = NULL; @@ -235,7 +235,7 @@ unit->sweptBounds = CBoundingSphere(mid, radius); } - virtual void UpdateUnit(tag_t tag, CUnit* actor, const CBoundingSphere& boundsApprox) + void UpdateUnit(tag_t tag, CUnit* actor, const CBoundingSphere& boundsApprox) override { SUnit* unit = LookupUnit(tag); unit->actor = actor; @@ -243,7 +243,7 @@ RecomputeSweptBounds(unit); } - virtual void UpdateUnitPos(tag_t tag, bool inWorld, const CVector3D& pos0, const CVector3D& pos1) + void UpdateUnitPos(tag_t tag, bool inWorld, const CVector3D& pos0, const CVector3D& pos1) override { SUnit* unit = LookupUnit(tag); unit->inWorld = inWorld; @@ -259,17 +259,17 @@ void UpdateVisibility(SUnit& unit) const; - virtual float GetFrameOffset() const + float GetFrameOffset() const override { return m_FrameOffset; } - virtual void SetDebugOverlay(bool enabled) + void SetDebugOverlay(bool enabled) override { m_EnableDebugOverlays = enabled; } - virtual void PickAllEntitiesAtPoint(std::vector >& outEntities, const CVector3D& origin, const CVector3D& dir, bool allowEditorSelectables) const + void PickAllEntitiesAtPoint(std::vector >& outEntities, const CVector3D& origin, const CVector3D& dir, bool allowEditorSelectables) const override { // First, make a rough test with the worst-case bounding boxes to pick all // entities/models that could possibly be hit by the ray. diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpVision.cpp 0ad-0.0.26/source/simulation2/components/CCmpVision.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpVision.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpVision.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,7 +25,7 @@ #include "simulation2/components/ICmpRangeManager.h" #include "simulation2/components/ICmpValueModificationManager.h" -class CCmpVision : public ICmpVision +class CCmpVision final : public ICmpVision { public: static void ClassInit(CComponentManager& componentManager) @@ -58,7 +58,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_BaseRange = m_Range = paramNode.GetChild("Range").ToFixed(); @@ -68,21 +68,21 @@ m_RevealShore = false; } - virtual void Deinit() + void Deinit() override { } - virtual void Serialize(ISerializer& UNUSED(serialize)) + void Serialize(ISerializer& UNUSED(serialize)) override { // No dynamic state to serialize } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) + void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override { Init(paramNode); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -130,12 +130,12 @@ GetSimContext().GetComponentManager().BroadcastMessage(msg); } - virtual entity_pos_t GetRange() const + entity_pos_t GetRange() const override { return m_Range; } - virtual bool GetRevealShore() const + bool GetRevealShore() const override { return m_RevealShore; } diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpVisualActor.cpp 0ad-0.0.26/source/simulation2/components/CCmpVisualActor.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpVisualActor.cpp 2021-08-03 17:15:04.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpVisualActor.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -51,7 +51,7 @@ #include "ps/GameSetup/Config.h" #include "renderer/Scene.h" -class CCmpVisualActor : public ICmpVisual +class CCmpVisualActor final : public ICmpVisual { public: static void ClassInit(CComponentManager& componentManager) @@ -59,7 +59,6 @@ componentManager.SubscribeToMessageType(MT_InterpolatedPositionChanged); componentManager.SubscribeToMessageType(MT_OwnershipChanged); componentManager.SubscribeToMessageType(MT_ValueModification); - componentManager.SubscribeToMessageType(MT_TerrainChanged); componentManager.SubscribeToMessageType(MT_Create); componentManager.SubscribeToMessageType(MT_Destroy); } @@ -192,7 +191,7 @@ ""; } - virtual void Init(const CParamNode& paramNode) + void Init(const CParamNode& paramNode) override { m_Unit = NULL; m_R = m_G = m_B = fixed::FromInt(1); @@ -221,7 +220,7 @@ InitSelectionShapeDescriptor(paramNode); } - virtual void Deinit() + void Deinit() override { if (m_Unit) { @@ -253,7 +252,7 @@ // TODO: store actor variables? } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { // TODO: store the actor name, if !debug and it differs from the template @@ -265,7 +264,7 @@ SerializeCommon(serialize); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); @@ -289,7 +288,7 @@ } } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -305,15 +304,6 @@ break; } - case MT_TerrainChanged: - { - if (!m_Unit) - break; - - const CMessageTerrainChanged& msgData = static_cast (msg); - m_Unit->GetModel().SetTerrainDirty(msgData.i0, msgData.j0, msgData.i1, msgData.j1); - break; - } case MT_ValueModification: { // Mirages don't respond to technology modifications. @@ -359,40 +349,40 @@ } } - virtual CBoundingBoxAligned GetBounds() const + CBoundingBoxAligned GetBounds() const override { if (!m_Unit) return CBoundingBoxAligned::EMPTY; return m_Unit->GetModel().GetWorldBounds(); } - virtual CUnit* GetUnit() + CUnit* GetUnit() override { return m_Unit; } - virtual CBoundingBoxOriented GetSelectionBox() const + CBoundingBoxOriented GetSelectionBox() const override { if (!m_Unit) return CBoundingBoxOriented::EMPTY; return m_Unit->GetModel().GetSelectionBox(); } - virtual CVector3D GetPosition() const + CVector3D GetPosition() const override { if (!m_Unit) return CVector3D(0, 0, 0); return m_Unit->GetModel().GetTransform().GetTranslation(); } - virtual std::wstring GetProjectileActor() const + std::wstring GetProjectileActor() const override { if (!m_Unit) return L""; return m_Unit->GetObject().m_ProjectileModelName; } - virtual CFixedVector3D GetProjectileLaunchPoint() const + CFixedVector3D GetProjectileLaunchPoint() const override { if (!m_Unit) return CFixedVector3D(); @@ -421,7 +411,7 @@ return CFixedVector3D(); } - virtual void SetVariant(const CStr& key, const CStr& selection) + void SetVariant(const CStr& key, const CStr& selection) override { if (m_VariantSelections[key] == selection) return; @@ -436,12 +426,12 @@ } } - virtual std::string GetAnimationName() const + std::string GetAnimationName() const override { return m_AnimName; } - virtual void SelectAnimation(const std::string& name, bool once = false, fixed speed = fixed::FromInt(1)) + void SelectAnimation(const std::string& name, bool once = false, fixed speed = fixed::FromInt(1)) override { m_AnimName = name; m_AnimOnce = once; @@ -463,7 +453,7 @@ m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed.ToFloat(), m_AnimDesync.ToFloat(), m_SoundGroup.c_str()); } - virtual void SelectMovementAnimation(const std::string& name, fixed speed) + void SelectMovementAnimation(const std::string& name, fixed speed) override { ENSURE(name == "idle" || name == "walk" || name == "run"); if (m_AnimName != "idle" && m_AnimName != "walk" && m_AnimName != "run") @@ -473,7 +463,7 @@ SelectAnimation(name, false, speed); } - virtual void SetAnimationSyncRepeat(fixed repeattime) + void SetAnimationSyncRepeat(fixed repeattime) override { m_AnimSyncRepeatTime = repeattime; @@ -481,7 +471,7 @@ m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime.ToFloat()); } - virtual void SetAnimationSyncOffset(fixed actiontime) + void SetAnimationSyncOffset(fixed actiontime) override { m_AnimSyncOffsetTime = actiontime; @@ -489,7 +479,7 @@ m_Unit->GetAnimation()->SetAnimationSyncOffset(m_AnimSyncOffsetTime.ToFloat()); } - virtual void SetShadingColor(fixed r, fixed g, fixed b, fixed a) + void SetShadingColor(fixed r, fixed g, fixed b, fixed a) override { m_R = r; m_G = g; @@ -503,18 +493,18 @@ } } - virtual void SetVariable(const std::string& name, float value) + void SetVariable(const std::string& name, float value) override { if (m_Unit) m_Unit->GetModel().SetEntityVariable(name, value); } - virtual u32 GetActorSeed() const + u32 GetActorSeed() const override { return m_Seed; } - virtual void SetActorSeed(u32 seed) + void SetActorSeed(u32 seed) override { if (seed == m_Seed) return; @@ -523,7 +513,7 @@ ReloadActor(); } - virtual void RecomputeActorName() + void RecomputeActorName() override { CmpPtr cmpValueModificationManager(GetSystemEntity()); std::wstring newActorName; @@ -539,12 +529,12 @@ } } - virtual bool HasConstructionPreview() const + bool HasConstructionPreview() const override { return m_ConstructionPreview; } - virtual void Hotload(const VfsPath& name) + void Hotload(const VfsPath& name) override { if (!m_Unit) return; diff -Nru 0ad-0.0.25b/source/simulation2/components/CCmpWaterManager.cpp 0ad-0.0.26/source/simulation2/components/CCmpWaterManager.cpp --- 0ad-0.0.25b/source/simulation2/components/CCmpWaterManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/CCmpWaterManager.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,12 +23,12 @@ #include "graphics/RenderableObject.h" #include "graphics/Terrain.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/MessageTypes.h" - #include "tools/atlas/GameInterface/GameLoop.h" -class CCmpWaterManager : public ICmpWaterManager +class CCmpWaterManager final : public ICmpWaterManager { public: static void ClassInit(CComponentManager& componentManager) @@ -49,35 +49,35 @@ return ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + void Init(const CParamNode& UNUSED(paramNode)) override { } - virtual void Deinit() + void Deinit() override { // Clear the map size & data. if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager()->SetMapSize(0); + g_Renderer.GetSceneRenderer().GetWaterManager().SetMapSize(0); } - virtual void Serialize(ISerializer& serialize) + void Serialize(ISerializer& serialize) override { serialize.NumberFixed_Unbounded("height", m_WaterHeight); } - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override { Init(paramNode); deserialize.NumberFixed_Unbounded("height", m_WaterHeight); if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager()->SetMapSize(GetSimContext().GetTerrain().GetVerticesPerSide()); + g_Renderer.GetSceneRenderer().GetWaterManager().SetMapSize(GetSimContext().GetTerrain().GetVerticesPerSide()); RecomputeWaterData(); } - virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) + void HandleMessage(const CMessage& msg, bool UNUSED(global)) override { switch (msg.GetType()) { @@ -85,7 +85,7 @@ { const CMessageInterpolate& msgData = static_cast (msg); if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager()->m_WaterTexTimer += msgData.deltaSimTime; + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterTexTimer += msgData.deltaSimTime; break; } case MT_TerrainChanged: @@ -101,19 +101,19 @@ } } - virtual void RecomputeWaterData() + void RecomputeWaterData() override { if (CRenderer::IsInitialised()) { - g_Renderer.GetWaterManager()->RecomputeWaterData(); - g_Renderer.GetWaterManager()->m_WaterHeight = m_WaterHeight.ToFloat(); + g_Renderer.GetSceneRenderer().GetWaterManager().RecomputeWaterData(); + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight = m_WaterHeight.ToFloat(); } // Tell the terrain it'll need to recompute its cached render data GetSimContext().GetTerrain().MakeDirty(RENDERDATA_UPDATE_VERTICES); } - virtual void SetWaterLevel(entity_pos_t h) + void SetWaterLevel(entity_pos_t h) override { if (m_WaterHeight == h) return; @@ -126,12 +126,12 @@ GetSimContext().GetComponentManager().BroadcastMessage(msg); } - virtual entity_pos_t GetWaterLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const + entity_pos_t GetWaterLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const override { return m_WaterHeight; } - virtual float GetExactWaterLevel(float UNUSED(x), float UNUSED(z)) const + float GetExactWaterLevel(float UNUSED(x), float UNUSED(z)) const override { return m_WaterHeight.ToFloat(); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpAIInterface.cpp 0ad-0.0.26/source/simulation2/components/ICmpAIInterface.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpAIInterface.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpAIInterface.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,11 +30,11 @@ public: DEFAULT_SCRIPT_WRAPPER(AIInterfaceScripted) - virtual void GetRepresentation(JS::MutableHandleValue ret) + void GetRepresentation(JS::MutableHandleValue ret) override { m_Script.CallRef("GetRepresentation", ret); } - virtual void GetFullRepresentation(JS::MutableHandleValue ret, bool flushEvents = false) + void GetFullRepresentation(JS::MutableHandleValue ret, bool flushEvents = false) override { m_Script.CallRef("GetFullRepresentation", ret, flushEvents); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpAttack.cpp 0ad-0.0.26/source/simulation2/components/ICmpAttack.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpAttack.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpAttack.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,12 +31,12 @@ public: DEFAULT_SCRIPT_WRAPPER(AttackScripted) - virtual float GetRepeatTime(const std::string& type) const + float GetRepeatTime(const std::string& type) const override { return m_Script.Call("GetRepeatTime", type); } - virtual std::vector GetAttackTypes() const + std::vector GetAttackTypes() const override { return m_Script.Call>("GetAttackTypes"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpFogging.cpp 0ad-0.0.26/source/simulation2/components/ICmpFogging.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpFogging.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpFogging.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,22 +30,22 @@ public: DEFAULT_SCRIPT_WRAPPER(FoggingScripted) - virtual bool IsActivated() + bool IsActivated() override { return m_Script.Call("IsActivated"); } - virtual bool WasSeen(player_id_t player) + bool WasSeen(player_id_t player) override { return m_Script.Call("WasSeen", player); } - virtual bool IsMiraged(player_id_t player) + bool IsMiraged(player_id_t player) override { return m_Script.Call("IsMiraged", player); } - virtual void ForceMiraging(player_id_t player) + void ForceMiraging(player_id_t player) override { return m_Script.CallVoid("ForceMiraging", player); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpGarrisonHolder.cpp 0ad-0.0.26/source/simulation2/components/ICmpGarrisonHolder.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpGarrisonHolder.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpGarrisonHolder.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,12 +30,12 @@ public: DEFAULT_SCRIPT_WRAPPER(GarrisonHolderScripted) - virtual std::vector GetEntities() const + std::vector GetEntities() const override { return m_Script.Call>("GetEntities"); } - virtual void SetInitEntities(std::vector&& entities) + void SetInitEntities(std::vector&& entities) override { m_Script.CallVoid("SetInitGarrison", entities); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpGuiInterface.cpp 0ad-0.0.26/source/simulation2/components/ICmpGuiInterface.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpGuiInterface.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpGuiInterface.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ public: DEFAULT_SCRIPT_WRAPPER(GuiInterfaceScripted) - virtual void ScriptCall(int player, const std::wstring& cmd, JS::HandleValue data, JS::MutableHandleValue ret) + void ScriptCall(int player, const std::wstring& cmd, JS::HandleValue data, JS::MutableHandleValue ret) override { m_Script.CallRef("ScriptCall", ret, player, cmd, data); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpGuiInterface.h 0ad-0.0.26/source/simulation2/components/ICmpGuiInterface.h --- 0ad-0.0.25b/source/simulation2/components/ICmpGuiInterface.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpGuiInterface.h 2022-08-21 12:45:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,8 +20,6 @@ #include "simulation2/system/Interface.h" -struct CColor; - class ICmpGuiInterface : public IComponent { public: diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpIdentity.cpp 0ad-0.0.26/source/simulation2/components/ICmpIdentity.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpIdentity.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpIdentity.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,15 +31,20 @@ public: DEFAULT_SCRIPT_WRAPPER(IdentityScripted) - virtual std::string GetSelectionGroupName() + std::string GetSelectionGroupName() override { return m_Script.Call("GetSelectionGroupName"); } - virtual std::wstring GetPhenotype() + std::wstring GetPhenotype() override { return m_Script.Call("GetPhenotype"); } + + std::wstring GetCiv() override + { + return m_Script.Call("GetCiv"); + } }; REGISTER_COMPONENT_SCRIPT_WRAPPER(IdentityScripted) diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpIdentity.h 0ad-0.0.26/source/simulation2/components/ICmpIdentity.h --- 0ad-0.0.25b/source/simulation2/components/ICmpIdentity.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpIdentity.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,6 +31,8 @@ virtual std::wstring GetPhenotype() = 0; + virtual std::wstring GetCiv() = 0; + DECLARE_INTERFACE_TYPE(Identity) }; diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpMinimap.h 0ad-0.0.26/source/simulation2/components/ICmpMinimap.h --- 0ad-0.0.25b/source/simulation2/components/ICmpMinimap.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpMinimap.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,6 +22,8 @@ #include "simulation2/helpers/Position.h" +#include + /** * Per-unit minimap data. */ @@ -45,6 +47,18 @@ */ virtual void UpdateColor() = 0; + /** + * Returns true if a minimap should have icon of this entity. + */ + virtual bool HasIcon() = 0; + + /** + * Returns a path to icon of this entity. + */ + virtual std::string GetIconPath() = 0; + + virtual float GetIconSize() = 0; + DECLARE_INTERFACE_TYPE(Minimap) }; diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpMirage.cpp 0ad-0.0.26/source/simulation2/components/ICmpMirage.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpMirage.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpMirage.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ public: DEFAULT_SCRIPT_WRAPPER(MirageScripted) - virtual player_id_t GetPlayer() + player_id_t GetPlayer() override { return m_Script.Call("GetPlayer"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpObstructionManager.cpp 0ad-0.0.26/source/simulation2/components/ICmpObstructionManager.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpObstructionManager.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpObstructionManager.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,5 +30,6 @@ DEFINE_INTERFACE_METHOD("MaxDistanceToTarget", ICmpObstructionManager, MaxDistanceToTarget) DEFINE_INTERFACE_METHOD("IsInPointRange", ICmpObstructionManager, IsInPointRange) DEFINE_INTERFACE_METHOD("IsInTargetRange", ICmpObstructionManager, IsInTargetRange) +DEFINE_INTERFACE_METHOD("IsInTargetParabolicRange", ICmpObstructionManager, IsInTargetParabolicRange) DEFINE_INTERFACE_METHOD("IsPointInPointRange", ICmpObstructionManager, IsPointInPointRange) END_INTERFACE_WRAPPER(ObstructionManager) diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpObstructionManager.h 0ad-0.0.26/source/simulation2/components/ICmpObstructionManager.h --- 0ad-0.0.25b/source/simulation2/components/ICmpObstructionManager.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpObstructionManager.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -208,25 +208,31 @@ /** * Check if the given entity is in range of the other point given those parameters. - * @param maxRange - if -1, treated as infinite. + * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE. */ virtual bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0; /** * Check if the given entity is in range of the target given those parameters. - * @param maxRange - if -1, treated as infinite. + * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE. */ virtual bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0; /** + * Check if the given entity is in parabolic range of the target given those parameters. + * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE. + */ + virtual bool IsInTargetParabolicRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, bool opposite) const = 0; + + /** * Check if the given point is in range of the other point given those parameters. - * @param maxRange - if -1, treated as infinite. + * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE. */ virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const = 0; /** * Check if the given shape is in range of the target shape given those parameters. - * @param maxRange - if -1, treated as infinite. + * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE. */ virtual bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0; diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpPathfinder.cpp 0ad-0.0.26/source/simulation2/components/ICmpPathfinder.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpPathfinder.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpPathfinder.cpp 2022-09-23 19:17:10.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ BEGIN_INTERFACE_WRAPPER(Pathfinder) DEFINE_INTERFACE_METHOD("SetDebugOverlay", ICmpPathfinder, SetDebugOverlay) DEFINE_INTERFACE_METHOD("SetHierDebugOverlay", ICmpPathfinder, SetHierDebugOverlay) +DEFINE_INTERFACE_METHOD("GetClearance", ICmpPathfinder, GetClearance) DEFINE_INTERFACE_METHOD("GetPassabilityClass", ICmpPathfinder, GetPassabilityClass) DEFINE_INTERFACE_METHOD("UpdateGrid", ICmpPathfinder, UpdateGrid) END_INTERFACE_WRAPPER(Pathfinder) diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpPlayer.cpp 0ad-0.0.26/source/simulation2/components/ICmpPlayer.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpPlayer.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpPlayer.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,32 +32,27 @@ public: DEFAULT_SCRIPT_WRAPPER(PlayerScripted) - virtual CColor GetDisplayedColor() + CColor GetDisplayedColor() override { return m_Script.Call("GetDisplayedColor"); } - virtual std::wstring GetCiv() - { - return m_Script.Call("GetCiv"); - } - - virtual CFixedVector3D GetStartingCameraPos() + CFixedVector3D GetStartingCameraPos() override { return m_Script.Call("GetStartingCameraPos"); } - virtual CFixedVector3D GetStartingCameraRot() + CFixedVector3D GetStartingCameraRot() override { return m_Script.Call("GetStartingCameraRot"); } - virtual bool HasStartingCamera() + bool HasStartingCamera() override { return m_Script.Call("HasStartingCamera"); } - virtual std::string GetState() + std::string GetState() override { return m_Script.Call("GetState"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpPlayer.h 0ad-0.0.26/source/simulation2/components/ICmpPlayer.h --- 0ad-0.0.25b/source/simulation2/components/ICmpPlayer.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpPlayer.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -33,7 +33,6 @@ { public: virtual CColor GetDisplayedColor() = 0; - virtual std::wstring GetCiv() = 0; virtual CFixedVector3D GetStartingCameraPos() = 0; virtual CFixedVector3D GetStartingCameraRot() = 0; diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpPlayerManager.cpp 0ad-0.0.26/source/simulation2/components/ICmpPlayerManager.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpPlayerManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpPlayerManager.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,17 +30,12 @@ public: DEFAULT_SCRIPT_WRAPPER(PlayerManagerScripted) - virtual void AddPlayer(entity_id_t ent) - { - m_Script.CallVoid("AddPlayer", (int)ent); - } - - virtual int32_t GetNumPlayers() + int32_t GetNumPlayers() override { return m_Script.Call("GetNumPlayers"); } - virtual entity_id_t GetPlayerByID(int32_t id) + entity_id_t GetPlayerByID(int32_t id) override { return m_Script.Call("GetPlayerByID", (int)id); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpPlayerManager.h 0ad-0.0.26/source/simulation2/components/ICmpPlayerManager.h --- 0ad-0.0.25b/source/simulation2/components/ICmpPlayerManager.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpPlayerManager.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,8 +26,6 @@ class ICmpPlayerManager : public IComponent { public: - virtual void AddPlayer(entity_id_t ent) = 0; - virtual int32_t GetNumPlayers() = 0; virtual entity_id_t GetPlayerByID(int32_t id) = 0; diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpRallyPoint.cpp 0ad-0.0.26/source/simulation2/components/ICmpRallyPoint.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpRallyPoint.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpRallyPoint.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,12 +31,12 @@ public: DEFAULT_SCRIPT_WRAPPER(RallyPointScripted) - virtual bool HasPositions() + bool HasPositions() override { return m_Script.Call("HasPositions"); } - virtual CFixedVector2D GetFirstPosition() + CFixedVector2D GetFirstPosition() override { return m_Script.Call("GetFirstPosition"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpRallyPointRenderer.cpp 0ad-0.0.26/source/simulation2/components/ICmpRallyPointRenderer.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpRallyPointRenderer.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpRallyPointRenderer.cpp 2022-08-21 12:45:38.000000000 +0000 @@ -20,8 +20,6 @@ #include "ICmpRallyPointRenderer.h" #include "simulation2/system/InterfaceScripted.h" -class CFixedVector2D; - BEGIN_INTERFACE_WRAPPER(RallyPointRenderer) DEFINE_INTERFACE_METHOD("SetDisplayed", ICmpRallyPointRenderer, SetDisplayed) DEFINE_INTERFACE_METHOD("SetPosition", ICmpRallyPointRenderer, SetPosition) diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpRangeManager.cpp 0ad-0.0.26/source/simulation2/components/ICmpRangeManager.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpRangeManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpRangeManager.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -64,6 +64,7 @@ DEFINE_INTERFACE_METHOD("ExploreTerritories", ICmpRangeManager, ExploreTerritories) DEFINE_INTERFACE_METHOD("SetLosRevealAll", ICmpRangeManager, SetLosRevealAll) DEFINE_INTERFACE_METHOD("GetLosRevealAll", ICmpRangeManager, GetLosRevealAll) +DEFINE_INTERFACE_METHOD("GetEffectiveParabolicRange", ICmpRangeManager, GetEffectiveParabolicRange) DEFINE_INTERFACE_METHOD("GetElevationAdaptedRange", ICmpRangeManager, GetElevationAdaptedRange) DEFINE_INTERFACE_METHOD("ActivateScriptedVisibility", ICmpRangeManager, ActivateScriptedVisibility) DEFINE_INTERFACE_METHOD("GetLosVisibility", ICmpRangeManager, GetLosVisibility_wrapper) diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpRangeManager.h 0ad-0.0.26/source/simulation2/components/ICmpRangeManager.h --- 0ad-0.0.25b/source/simulation2/components/ICmpRangeManager.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpRangeManager.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,6 +30,18 @@ class FastSpatialSubdivision; /** + * Value assigned to a range we will always be in (caused by out of world or "too high" in parabolic ranges). + * TODO Add this for minRanges too. + */ +const entity_pos_t ALWAYS_IN_RANGE = entity_pos_t::FromInt(-1); + +/** + * Value assigned to a range we will never be in (caused by out of world or "too high" in parabolic ranges). + * TODO Add this to range queries too. + */ +const entity_pos_t NEVER_IN_RANGE = entity_pos_t::FromInt(-2); + +/** * Since GetVisibility queries are run by the range manager * other code using these must include ICmpRangeManager.h anyways, * so define this enum here (Ideally, it'd be in its own header file, @@ -156,25 +168,35 @@ * @param minRange non-negative minimum horizontal distance in metres (inclusive). MinRange doesn't do parabolic checks. * @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation; * or -1.0 to ignore distance. - * For units on a different elevation, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them - * @param elevationBonus extra bonus so the source can be placed higher and shoot further + * For units on a different height positions, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them + * @param yOrigin extra bonus so the source can be placed higher and shoot further * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner. * @param requiredInterface if non-zero, an interface ID that matching entities must implement. * @param flags if a entity in range has one of the flags set it will show up. * NB: this one has no accountForSize parameter (assumed true), because we currently can only have 7 arguments for JS functions. * @return unique non-zero identifier of query. */ - virtual tag_t CreateActiveParabolicQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus, + virtual tag_t CreateActiveParabolicQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, const std::vector& owners, int requiredInterface, u8 flags) = 0; /** + * Get the effective range in a parablic range query. + * @param source The entity id at the origin of the query. + * @param target A target entity id. + * @param range The distance to compare terrain height with. + * @param yOrigin Height the source gains over the target by default. + * @return a fixed number representing the effective range correcting parabolicly for the height difference. Returns -1 when the target is too high compared to the source to be in range. + */ + virtual entity_pos_t GetEffectiveParabolicRange(entity_id_t source, entity_id_t target, entity_pos_t range, entity_pos_t yOrigin) const = 0; + + /** * Get the average elevation over 8 points on distance range around the entity * @param id the entity id to look around * @param range the distance to compare terrain height with * @return a fixed number representing the average difference. It's positive when the entity is on average higher than the terrain surrounding it. */ - virtual entity_pos_t GetElevationAdaptedRange(const CFixedVector3D& pos, const CFixedVector3D& rot, entity_pos_t range, entity_pos_t elevationBonus, entity_pos_t angle) const = 0; + virtual entity_pos_t GetElevationAdaptedRange(const CFixedVector3D& pos, const CFixedVector3D& rot, entity_pos_t range, entity_pos_t yOrigin, entity_pos_t angle) const = 0; /** * Destroy a query and clean up resources. This must be called when an entity no longer needs its diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpSound.cpp 0ad-0.0.26/source/simulation2/components/ICmpSound.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpSound.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpSound.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ public: DEFAULT_SCRIPT_WRAPPER(SoundScripted) - virtual std::wstring GetSoundGroup(const std::wstring& soundName) const + std::wstring GetSoundGroup(const std::wstring& soundName) const override { return m_Script.Call("GetSoundGroup", soundName); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpTemplateManager.cpp 0ad-0.0.26/source/simulation2/components/ICmpTemplateManager.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpTemplateManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpTemplateManager.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,5 +27,6 @@ DEFINE_INTERFACE_METHOD("TemplateExists", ICmpTemplateManager, TemplateExists) DEFINE_INTERFACE_METHOD("GetCurrentTemplateName", ICmpTemplateManager, GetCurrentTemplateName) DEFINE_INTERFACE_METHOD("FindAllTemplates", ICmpTemplateManager, FindAllTemplates) +DEFINE_INTERFACE_METHOD("GetCivData", ICmpTemplateManager, GetCivData) DEFINE_INTERFACE_METHOD("GetEntitiesUsingTemplate", ICmpTemplateManager, GetEntitiesUsingTemplate) END_INTERFACE_WRAPPER(TemplateManager) diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpTemplateManager.h 0ad-0.0.26/source/simulation2/components/ICmpTemplateManager.h --- 0ad-0.0.25b/source/simulation2/components/ICmpTemplateManager.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpTemplateManager.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -104,6 +104,12 @@ virtual std::vector FindAllTemplates(bool includeActors) const = 0; /** + * Returns some data of the civs from the templates. + * Intended for use by the map editor. + */ + virtual std::vector> GetCivData() = 0; + + /** * Returns a list of strings that could be validly passed as @c templateName to LoadTemplate. * Intended for use by the AI manager. */ diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpTerritoryDecayManager.cpp 0ad-0.0.26/source/simulation2/components/ICmpTerritoryDecayManager.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpTerritoryDecayManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpTerritoryDecayManager.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ public: DEFAULT_SCRIPT_WRAPPER(TerritoryDecayManagerScripted) - virtual void SetBlinkingEntities() + void SetBlinkingEntities() override { return m_Script.CallVoid("SetBlinkingEntities"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpTurretHolder.cpp 0ad-0.0.26/source/simulation2/components/ICmpTurretHolder.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpTurretHolder.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpTurretHolder.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,7 +34,7 @@ * @return - Correlation between garrisoned turrets (their ID) and which * turret point they occupy (name). */ - virtual std::vector > GetTurrets() const + std::vector > GetTurrets() const override { std::vector > turrets; std::vector entities = m_Script.Call>("GetEntities"); @@ -50,7 +50,7 @@ /** * Correlation between entities (ID) and the turret point they ought to occupy (name). */ - virtual void SetInitEntities(std::vector>&& entities) + void SetInitEntities(std::vector>&& entities) override { for (const std::pair& p : entities) m_Script.CallVoid("SetInitEntity", p.first, p.second); diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpUnitMotion.cpp 0ad-0.0.26/source/simulation2/components/ICmpUnitMotion.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpUnitMotion.cpp 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpUnitMotion.cpp 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -37,7 +37,10 @@ DEFINE_INTERFACE_METHOD("GetRunMultiplier", ICmpUnitMotion, GetRunMultiplier) DEFINE_INTERFACE_METHOD("EstimateFuturePosition", ICmpUnitMotion, EstimateFuturePosition) DEFINE_INTERFACE_METHOD("SetSpeedMultiplier", ICmpUnitMotion, SetSpeedMultiplier) +DEFINE_INTERFACE_METHOD("GetAcceleration", ICmpUnitMotion, GetAcceleration) +DEFINE_INTERFACE_METHOD("SetAcceleration", ICmpUnitMotion, SetAcceleration) DEFINE_INTERFACE_METHOD("GetPassabilityClassName", ICmpUnitMotion, GetPassabilityClassName) +DEFINE_INTERFACE_METHOD("SetPassabilityClassName", ICmpUnitMotion, SetPassabilityClassName) DEFINE_INTERFACE_METHOD("GetUnitClearance", ICmpUnitMotion, GetUnitClearance) DEFINE_INTERFACE_METHOD("SetFacePointAfterMove", ICmpUnitMotion, SetFacePointAfterMove) DEFINE_INTERFACE_METHOD("GetFacePointAfterMove", ICmpUnitMotion, GetFacePointAfterMove) @@ -49,107 +52,122 @@ public: DEFAULT_SCRIPT_WRAPPER(UnitMotionScripted) - virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) + bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) override { return m_Script.Call("MoveToPointRange", x, z, minRange, maxRange); } - virtual bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) + bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) override { return m_Script.Call("MoveToTargetRange", target, minRange, maxRange); } - virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z) + void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z) override { m_Script.CallVoid("MoveToFormationOffset", target, x, z); } - virtual void SetMemberOfFormation(entity_id_t controller) + void SetMemberOfFormation(entity_id_t controller) override { m_Script.CallVoid("SetMemberOfFormation", controller); } - virtual bool IsTargetRangeReachable(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) + bool IsTargetRangeReachable(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) override { return m_Script.Call("IsTargetRangeReachable", target, minRange, maxRange); } - virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z) + void FaceTowardsPoint(entity_pos_t x, entity_pos_t z) override { m_Script.CallVoid("FaceTowardsPoint", x, z); } - virtual void StopMoving() + void StopMoving() override { m_Script.CallVoid("StopMoving"); } - virtual fixed GetCurrentSpeed() const + fixed GetCurrentSpeed() const override { return m_Script.Call("GetCurrentSpeed"); } - virtual bool IsMoveRequested() const + bool IsMoveRequested() const override { return m_Script.Call("IsMoveRequested"); } - virtual fixed GetSpeed() const + fixed GetSpeed() const override { return m_Script.Call("GetSpeed"); } - virtual fixed GetWalkSpeed() const + fixed GetWalkSpeed() const override { return m_Script.Call("GetWalkSpeed"); } - virtual fixed GetRunMultiplier() const + fixed GetRunMultiplier() const override { return m_Script.Call("GetRunMultiplier"); } - virtual void SetSpeedMultiplier(fixed multiplier) + void SetSpeedMultiplier(fixed multiplier) override { m_Script.CallVoid("SetSpeedMultiplier", multiplier); } - virtual fixed GetSpeedMultiplier() const + fixed GetSpeedMultiplier() const override { return m_Script.Call("GetSpeedMultiplier"); } - virtual CFixedVector2D EstimateFuturePosition(const fixed dt) const + CFixedVector2D EstimateFuturePosition(const fixed dt) const override { return m_Script.Call("EstimateFuturePosition", dt); } - virtual void SetFacePointAfterMove(bool facePointAfterMove) + fixed GetAcceleration() const override + { + return m_Script.Call("GetAcceleration"); + } + + void SetAcceleration(fixed acceleration) override + { + m_Script.CallVoid("SetAcceleration", acceleration); + } + + void SetFacePointAfterMove(bool facePointAfterMove) override { m_Script.CallVoid("SetFacePointAfterMove", facePointAfterMove); } - virtual bool GetFacePointAfterMove() const + bool GetFacePointAfterMove() const override { return m_Script.Call("GetFacePointAfterMove"); } - virtual pass_class_t GetPassabilityClass() const + pass_class_t GetPassabilityClass() const override { return m_Script.Call("GetPassabilityClass"); } - virtual std::string GetPassabilityClassName() const + std::string GetPassabilityClassName() const override { return m_Script.Call("GetPassabilityClassName"); } - virtual entity_pos_t GetUnitClearance() const + void SetPassabilityClassName(const std::string& passClassName) override + { + return m_Script.CallVoid("SetPassabilityClassName", passClassName); + } + + entity_pos_t GetUnitClearance() const override { return m_Script.Call("GetUnitClearance"); } - virtual void SetDebugOverlay(bool enabled) + void SetDebugOverlay(bool enabled) override { m_Script.CallVoid("SetDebugOverlay", enabled); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpUnitMotion.h 0ad-0.0.26/source/simulation2/components/ICmpUnitMotion.h --- 0ad-0.0.25b/source/simulation2/components/ICmpUnitMotion.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpUnitMotion.h 2022-09-23 19:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -87,7 +87,7 @@ virtual void StopMoving() = 0; /** - * Get the distance travelled over the last turn. + * Get the speed at the end of the current turn. */ virtual fixed GetCurrentSpeed() const = 0; @@ -130,6 +130,17 @@ virtual CFixedVector2D EstimateFuturePosition(const fixed dt) const = 0; /** + * Get the current acceleration. + */ + virtual fixed GetAcceleration() const = 0; + + /** + * Set the current acceleration. + * @param acceleration The acceleration. + */ + virtual void SetAcceleration(fixed acceleration) = 0; + + /** * Set whether the unit will turn to face the target point after finishing moving. */ virtual void SetFacePointAfterMove(bool facePointAfterMove) = 0; @@ -147,6 +158,11 @@ virtual std::string GetPassabilityClassName() const = 0; /** + * Sets the passability class name (as defined in pathfinder.xml) + */ + virtual void SetPassabilityClassName(const std::string& passClassName) = 0; + + /** * Get the unit clearance (used by the Obstruction component) */ virtual entity_pos_t GetUnitClearance() const = 0; diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpValueModificationManager.cpp 0ad-0.0.26/source/simulation2/components/ICmpValueModificationManager.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpValueModificationManager.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpValueModificationManager.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,27 +30,27 @@ public: DEFAULT_SCRIPT_WRAPPER(ValueModificationManagerScripted) - virtual fixed ApplyModifications(std::wstring valueName, fixed currentValue, entity_id_t entity) const + fixed ApplyModifications(std::wstring valueName, fixed currentValue, entity_id_t entity) const override { return m_Script.Call("ApplyModifications", valueName, currentValue, entity); } - virtual u32 ApplyModifications(std::wstring valueName, u32 currentValue, entity_id_t entity) const + u32 ApplyModifications(std::wstring valueName, u32 currentValue, entity_id_t entity) const override { return m_Script.Call("ApplyModifications", valueName, currentValue, entity); } - virtual u16 ApplyModifications(std::wstring valueName, u16 currentValue, entity_id_t entity) const + u16 ApplyModifications(std::wstring valueName, u16 currentValue, entity_id_t entity) const override { return m_Script.Call("ApplyModifications", valueName, currentValue, entity); } - virtual std::wstring ApplyModifications(std::wstring valueName, std::wstring currentValue, entity_id_t entity) const + std::wstring ApplyModifications(std::wstring valueName, std::wstring currentValue, entity_id_t entity) const override { return m_Script.Call("ApplyModifications", valueName, currentValue, entity); } - virtual bool ApplyModifications(std::wstring valueName, bool currentValue, entity_id_t entity) const + bool ApplyModifications(std::wstring valueName, bool currentValue, entity_id_t entity) const override { return m_Script.Call("ApplyModifications", valueName, currentValue, entity); } diff -Nru 0ad-0.0.25b/source/simulation2/components/ICmpVisibility.cpp 0ad-0.0.26/source/simulation2/components/ICmpVisibility.cpp --- 0ad-0.0.25b/source/simulation2/components/ICmpVisibility.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/ICmpVisibility.cpp 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,12 +30,12 @@ public: DEFAULT_SCRIPT_WRAPPER(VisibilityScripted) - virtual bool IsActivated() + bool IsActivated() override { return m_Script.Call("IsActivated"); } - virtual LosVisibility GetVisibility(player_id_t player, bool isVisible, bool isExplored) + LosVisibility GetVisibility(player_id_t player, bool isVisible, bool isExplored) override { int visibility = m_Script.Call("GetVisibility", player, isVisible, isExplored); @@ -53,12 +53,12 @@ } } - virtual bool GetRetainInFog() + bool GetRetainInFog() override { return m_Script.Call("GetRetainInFog"); } - virtual bool GetAlwaysVisible() + bool GetAlwaysVisible() override { return m_Script.Call("GetAlwaysVisible"); } diff -Nru 0ad-0.0.25b/source/simulation2/components/tests/test_ObstructionManager.h 0ad-0.0.26/source/simulation2/components/tests/test_ObstructionManager.h --- 0ad-0.0.25b/source/simulation2/components/tests/test_ObstructionManager.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/tests/test_ObstructionManager.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,32 +26,32 @@ DEFAULT_MOCK_COMPONENT() ICmpObstructionManager::ObstructionSquare obstruction; - virtual ICmpObstructionManager::tag_t GetObstruction() const { return ICmpObstructionManager::tag_t(); } - virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) const { out = obstruction; return true; } - virtual bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare& UNUSED(out)) const { return true; } - virtual entity_pos_t GetSize() const { return entity_pos_t::Zero(); } - virtual CFixedVector2D GetStaticSize() const { return CFixedVector2D(); } - virtual EObstructionType GetObstructionType() const { return ICmpObstruction::STATIC; } - virtual void SetUnitClearance(const entity_pos_t& UNUSED(clearance)) { } - virtual bool IsControlPersistent() const { return true; } - virtual bool CheckShorePlacement() const { return true; } - virtual EFoundationCheck CheckFoundation(const std::string& UNUSED(className)) const { return EFoundationCheck(); } - virtual EFoundationCheck CheckFoundation(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const { return EFoundationCheck(); } - virtual std::string CheckFoundation_wrapper(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const { return std::string(); } - virtual bool CheckDuplicateFoundation() const { return true; } - virtual std::vector GetEntitiesByFlags(ICmpObstructionManager::flags_t UNUSED(flags)) const { return std::vector(); } - virtual std::vector GetEntitiesBlockingMovement() const { return std::vector(); } - virtual std::vector GetEntitiesBlockingConstruction() const { return std::vector(); } - virtual std::vector GetEntitiesDeletedUponConstruction() const { return std::vector(); } - virtual void ResolveFoundationCollisions() const { } - virtual void SetActive(bool UNUSED(active)) { } - virtual void SetMovingFlag(bool UNUSED(enabled)) { } - virtual void SetDisableBlockMovementPathfinding(bool UNUSED(movementDisabled), bool UNUSED(pathfindingDisabled), int32_t UNUSED(shape)) { } - virtual bool GetBlockMovementFlag(bool) const { return true; } - virtual void SetControlGroup(entity_id_t UNUSED(group)) { } - virtual entity_id_t GetControlGroup() const { return INVALID_ENTITY; } - virtual void SetControlGroup2(entity_id_t UNUSED(group2)) { } - virtual entity_id_t GetControlGroup2() const { return INVALID_ENTITY; } + ICmpObstructionManager::tag_t GetObstruction() const override { return ICmpObstructionManager::tag_t(); } + bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) const override { out = obstruction; return true; } + bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare& UNUSED(out)) const override { return true; } + entity_pos_t GetSize() const override { return entity_pos_t::Zero(); } + CFixedVector2D GetStaticSize() const override { return CFixedVector2D(); } + EObstructionType GetObstructionType() const override { return ICmpObstruction::STATIC; } + void SetUnitClearance(const entity_pos_t& UNUSED(clearance)) override { } + bool IsControlPersistent() const override { return true; } + bool CheckShorePlacement() const override { return true; } + EFoundationCheck CheckFoundation(const std::string& UNUSED(className)) const override { return EFoundationCheck(); } + EFoundationCheck CheckFoundation(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const override { return EFoundationCheck(); } + std::string CheckFoundation_wrapper(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const override { return std::string(); } + bool CheckDuplicateFoundation() const override { return true; } + std::vector GetEntitiesByFlags(ICmpObstructionManager::flags_t UNUSED(flags)) const override { return std::vector(); } + std::vector GetEntitiesBlockingMovement() const override { return std::vector(); } + std::vector GetEntitiesBlockingConstruction() const override { return std::vector(); } + std::vector GetEntitiesDeletedUponConstruction() const override { return std::vector(); } + void ResolveFoundationCollisions() const override { } + void SetActive(bool UNUSED(active)) override { } + void SetMovingFlag(bool UNUSED(enabled)) override { } + void SetDisableBlockMovementPathfinding(bool UNUSED(movementDisabled), bool UNUSED(pathfindingDisabled), int32_t UNUSED(shape)) override { } + bool GetBlockMovementFlag(bool) const override { return true; } + void SetControlGroup(entity_id_t UNUSED(group)) override { } + entity_id_t GetControlGroup() const override { return INVALID_ENTITY; } + void SetControlGroup2(entity_id_t UNUSED(group2)) override { } + entity_id_t GetControlGroup2() const override { return INVALID_ENTITY; } }; class TestCmpObstructionManager : public CxxTest::TestSuite diff -Nru 0ad-0.0.25b/source/simulation2/components/tests/test_Pathfinder.h 0ad-0.0.26/source/simulation2/components/tests/test_Pathfinder.h --- 0ad-0.0.25b/source/simulation2/components/tests/test_Pathfinder.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/tests/test_Pathfinder.h 2022-08-21 12:45:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,6 +32,7 @@ #include "simulation2/Simulation2.h" #include +#include class TestCmpPathfinder : public CxxTest::TestSuite { @@ -44,16 +45,10 @@ TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); CXeromyces::Startup(); - - // Need some stuff for terrain movement costs: - // (TODO: this ought to be independent of any graphics code) - new CTerrainTextureManager; - g_TexMan.LoadTerrainTextures(); } void tearDown() { - delete &g_TexMan; CXeromyces::Terminate(); g_VFS.reset(); DeleteDirectory(DataDir()/"_testcache"); @@ -177,13 +172,15 @@ double t = timer_Time(); - srand(1234); + std::mt19937 engine(42); + std::uniform_int_distribution distribution511(0, 511); + std::uniform_int_distribution distribution63(0, 63); for (size_t j = 0; j < 1024*2; ++j) { - entity_pos_t x0 = entity_pos_t::FromInt(rand() % 512); - entity_pos_t z0 = entity_pos_t::FromInt(rand() % 512); - entity_pos_t x1 = x0 + entity_pos_t::FromInt(rand() % 64); - entity_pos_t z1 = z0 + entity_pos_t::FromInt(rand() % 64); + entity_pos_t x0 = entity_pos_t::FromInt(distribution511(engine)); + entity_pos_t z0 = entity_pos_t::FromInt(distribution511(engine)); + entity_pos_t x1 = x0 + entity_pos_t::FromInt(distribution63(engine)); + entity_pos_t z1 = z0 + entity_pos_t::FromInt(distribution63(engine)); PathGoal goal = { PathGoal::POINT, x1, z1 }; WaypointPath path; @@ -208,11 +205,12 @@ CmpPtr cmpObstructionMan(sim2, SYSTEM_ENTITY); CmpPtr cmpPathfinder(sim2, SYSTEM_ENTITY); - srand(0); + std::mt19937 engine(42); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); for (size_t i = 0; i < 200; ++i) { - fixed x = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX); - fixed z = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX); + fixed x = fixed::FromFloat(1.5f*range.ToFloat() * distribution01(engine)); + fixed z = fixed::FromFloat(1.5f*range.ToFloat() * distribution01(engine)); // printf("# %f %f\n", x.ToFloat(), z.ToFloat()); cmpObstructionMan->AddUnitShape(INVALID_ENTITY, x, z, fixed::FromInt(2), 0, INVALID_ENTITY); } diff -Nru 0ad-0.0.25b/source/simulation2/components/tests/test_Position.h 0ad-0.0.26/source/simulation2/components/tests/test_Position.h --- 0ad-0.0.25b/source/simulation2/components/tests/test_Position.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/tests/test_Position.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,21 +26,21 @@ public: DEFAULT_MOCK_COMPONENT() - virtual entity_pos_t GetWaterLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const + entity_pos_t GetWaterLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const override { return entity_pos_t::FromInt(100); } - virtual float GetExactWaterLevel(float UNUSED(x), float UNUSED(z)) const + float GetExactWaterLevel(float UNUSED(x), float UNUSED(z)) const override { return 100.f; } - virtual void RecomputeWaterData() + void RecomputeWaterData() override { } - virtual void SetWaterLevel(entity_pos_t UNUSED(h)) + void SetWaterLevel(entity_pos_t UNUSED(h)) override { } }; diff -Nru 0ad-0.0.25b/source/simulation2/components/tests/test_RangeManager.h 0ad-0.0.26/source/simulation2/components/tests/test_RangeManager.h --- 0ad-0.0.25b/source/simulation2/components/tests/test_RangeManager.h 2021-07-27 21:56:42.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/components/tests/test_RangeManager.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,8 +30,8 @@ public: DEFAULT_MOCK_COMPONENT() - virtual entity_pos_t GetRange() const { return entity_pos_t::FromInt(66); } - virtual bool GetRevealShore() const { return false; } + entity_pos_t GetRange() const override { return entity_pos_t::FromInt(66); } + bool GetRevealShore() const override { return false; } }; class MockPositionRgm : public ICmpPosition @@ -39,38 +39,38 @@ public: DEFAULT_MOCK_COMPONENT() - virtual void SetTurretParent(entity_id_t UNUSED(id), const CFixedVector3D& UNUSED(pos)) {} - virtual entity_id_t GetTurretParent() const {return INVALID_ENTITY;} - virtual void UpdateTurretPosition() {} - virtual std::set* GetTurrets() { return NULL; } - virtual bool IsInWorld() const { return true; } - virtual void MoveOutOfWorld() { } - virtual void MoveTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { } - virtual void MoveAndTurnTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z), entity_angle_t UNUSED(a)) { } - virtual void JumpTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { } - virtual void SetHeightOffset(entity_pos_t UNUSED(dy)) { } - virtual entity_pos_t GetHeightOffset() const { return entity_pos_t::Zero(); } - virtual void SetHeightFixed(entity_pos_t UNUSED(y)) { } - virtual entity_pos_t GetHeightFixed() const { return entity_pos_t::Zero(); } - virtual entity_pos_t GetHeightAtFixed(entity_pos_t, entity_pos_t) const { return entity_pos_t::Zero(); } - virtual bool IsHeightRelative() const { return true; } - virtual void SetHeightRelative(bool UNUSED(relative)) { } - virtual bool CanFloat() const { return false; } - virtual void SetFloating(bool UNUSED(flag)) { } - virtual void SetActorFloating(bool UNUSED(flag)) { } - virtual void SetConstructionProgress(fixed UNUSED(progress)) { } - virtual CFixedVector3D GetPosition() const { return m_Pos; } - virtual CFixedVector2D GetPosition2D() const { return CFixedVector2D(m_Pos.X, m_Pos.Z); } - virtual CFixedVector3D GetPreviousPosition() const { return CFixedVector3D(); } - virtual CFixedVector2D GetPreviousPosition2D() const { return CFixedVector2D(); } - virtual fixed GetTurnRate() const { return fixed::Zero(); } - virtual void TurnTo(entity_angle_t UNUSED(y)) { } - virtual void SetYRotation(entity_angle_t UNUSED(y)) { } - virtual void SetXZRotation(entity_angle_t UNUSED(x), entity_angle_t UNUSED(z)) { } - virtual CFixedVector3D GetRotation() const { return CFixedVector3D(); } - virtual fixed GetDistanceTravelled() const { return fixed::Zero(); } - virtual void GetInterpolatedPosition2D(float UNUSED(frameOffset), float& x, float& z, float& rotY) const { x = z = rotY = 0; } - virtual CMatrix3D GetInterpolatedTransform(float UNUSED(frameOffset)) const { return CMatrix3D(); } + void SetTurretParent(entity_id_t UNUSED(id), const CFixedVector3D& UNUSED(pos)) override {} + entity_id_t GetTurretParent() const override {return INVALID_ENTITY;} + void UpdateTurretPosition() override {} + std::set* GetTurrets() override { return nullptr; } + bool IsInWorld() const override { return true; } + void MoveOutOfWorld() override { } + void MoveTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) override { } + void MoveAndTurnTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z), entity_angle_t UNUSED(a)) override { } + void JumpTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) override { } + void SetHeightOffset(entity_pos_t UNUSED(dy)) override { } + entity_pos_t GetHeightOffset() const override { return entity_pos_t::Zero(); } + void SetHeightFixed(entity_pos_t UNUSED(y)) override { } + entity_pos_t GetHeightFixed() const override { return entity_pos_t::Zero(); } + entity_pos_t GetHeightAtFixed(entity_pos_t, entity_pos_t) const override { return entity_pos_t::Zero(); } + bool IsHeightRelative() const override { return true; } + void SetHeightRelative(bool UNUSED(relative)) override { } + bool CanFloat() const override { return false; } + void SetFloating(bool UNUSED(flag)) override { } + void SetActorFloating(bool UNUSED(flag)) override { } + void SetConstructionProgress(fixed UNUSED(progress)) override { } + CFixedVector3D GetPosition() const override { return m_Pos; } + CFixedVector2D GetPosition2D() const override { return CFixedVector2D(m_Pos.X, m_Pos.Z); } + CFixedVector3D GetPreviousPosition() const override { return CFixedVector3D(); } + CFixedVector2D GetPreviousPosition2D() const override { return CFixedVector2D(); } + fixed GetTurnRate() const override { return fixed::Zero(); } + void TurnTo(entity_angle_t UNUSED(y)) override { } + void SetYRotation(entity_angle_t UNUSED(y)) override { } + void SetXZRotation(entity_angle_t UNUSED(x), entity_angle_t UNUSED(z)) override { } + CFixedVector3D GetRotation() const override { return CFixedVector3D(); } + fixed GetDistanceTravelled() const override { return fixed::Zero(); } + void GetInterpolatedPosition2D(float UNUSED(frameOffset), float& x, float& z, float& rotY) const override { x = z = rotY = 0; } + CMatrix3D GetInterpolatedTransform(float UNUSED(frameOffset)) const override { return CMatrix3D(); } CFixedVector3D m_Pos; }; @@ -82,32 +82,32 @@ MockObstructionRgm(entity_pos_t s) : m_Size(s) {}; - virtual ICmpObstructionManager::tag_t GetObstruction() const { return {}; }; - virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare&) const { return false; }; - virtual bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare&) const { return false; }; - virtual entity_pos_t GetSize() const { return m_Size; }; - virtual CFixedVector2D GetStaticSize() const { return {}; }; - virtual EObstructionType GetObstructionType() const { return {}; }; - virtual void SetUnitClearance(const entity_pos_t&) {}; - virtual bool IsControlPersistent() const { return {}; }; - virtual bool CheckShorePlacement() const { return {}; }; - virtual EFoundationCheck CheckFoundation(const std::string&) const { return {}; }; - virtual EFoundationCheck CheckFoundation(const std::string& , bool) const { return {}; }; - virtual std::string CheckFoundation_wrapper(const std::string&, bool) const { return {}; }; - virtual bool CheckDuplicateFoundation() const { return {}; }; - virtual std::vector GetEntitiesByFlags(ICmpObstructionManager::flags_t) const { return {}; }; - virtual std::vector GetEntitiesBlockingMovement() const { return {}; }; - virtual std::vector GetEntitiesBlockingConstruction() const { return {}; }; - virtual std::vector GetEntitiesDeletedUponConstruction() const { return {}; }; - virtual void ResolveFoundationCollisions() const {}; - virtual void SetActive(bool) {}; - virtual void SetMovingFlag(bool) {}; - virtual void SetDisableBlockMovementPathfinding(bool, bool, int32_t) {}; - virtual bool GetBlockMovementFlag(bool) const { return {}; }; - virtual void SetControlGroup(entity_id_t) {}; - virtual entity_id_t GetControlGroup() const { return {}; }; - virtual void SetControlGroup2(entity_id_t) {}; - virtual entity_id_t GetControlGroup2() const { return {}; }; + ICmpObstructionManager::tag_t GetObstruction() const override { return {}; }; + bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare&) const override { return false; }; + bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare&) const override { return false; }; + entity_pos_t GetSize() const override { return m_Size; }; + CFixedVector2D GetStaticSize() const override { return {}; }; + EObstructionType GetObstructionType() const override { return {}; }; + void SetUnitClearance(const entity_pos_t&) override {}; + bool IsControlPersistent() const override { return {}; }; + bool CheckShorePlacement() const override { return {}; }; + EFoundationCheck CheckFoundation(const std::string&) const override { return {}; }; + EFoundationCheck CheckFoundation(const std::string& , bool) const override { return {}; }; + std::string CheckFoundation_wrapper(const std::string&, bool) const override { return {}; }; + bool CheckDuplicateFoundation() const override { return {}; }; + std::vector GetEntitiesByFlags(ICmpObstructionManager::flags_t) const override { return {}; }; + std::vector GetEntitiesBlockingMovement() const override { return {}; }; + std::vector GetEntitiesBlockingConstruction() const override { return {}; }; + std::vector GetEntitiesDeletedUponConstruction() const override { return {}; }; + void ResolveFoundationCollisions() const override {}; + void SetActive(bool) override {}; + void SetMovingFlag(bool) override {}; + void SetDisableBlockMovementPathfinding(bool, bool, int32_t) override {}; + bool GetBlockMovementFlag(bool) const override { return {}; }; + void SetControlGroup(entity_id_t) override {}; + entity_id_t GetControlGroup() const override { return {}; }; + void SetControlGroup2(entity_id_t) override {}; + entity_id_t GetControlGroup2() const override { return {}; }; private: entity_pos_t m_Size; }; @@ -268,4 +268,46 @@ TS_ASSERT_EQUALS(nearby, std::vector{}); } + + void test_IsInTargetParabolicRange() + { + ComponentTestHelper test(g_ScriptContext); + ICmpRangeManager* cmp = test.Add(CID_RangeManager, "", SYSTEM_ENTITY); + const entity_id_t source = 200; + const entity_id_t target = 201; + entity_pos_t range = fixed::FromInt(-3); + entity_pos_t yOrigin = fixed::FromInt(-20); + + // Invalid range. + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range); + + // No source ICmpPosition. + range = fixed::FromInt(10); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), NEVER_IN_RANGE); + + // No target ICmpPosition. + MockPositionRgm cmpSourcePosition; + test.AddMock(source, IID_Position, cmpSourcePosition); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), NEVER_IN_RANGE); + + // Too much height difference. + MockPositionRgm cmpTargetPosition; + test.AddMock(target, IID_Position, cmpTargetPosition); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), NEVER_IN_RANGE); + + // If no offset we get the range. + range = fixed::FromInt(20); + yOrigin = fixed::Zero(); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, fixed::Zero(), yOrigin), fixed::Zero()); + + // Normal case. + yOrigin = fixed::FromInt(5); + range = fixed::FromInt(10); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), fixed::FromFloat(14.142136f)); + + // Big range. + range = fixed::FromInt(260); + TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), fixed::FromFloat(264.952820f)); + } }; diff -Nru 0ad-0.0.25b/source/simulation2/helpers/Pathfinding.h 0ad-0.0.26/source/simulation2/helpers/Pathfinding.h --- 0ad-0.0.25b/source/simulation2/helpers/Pathfinding.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/helpers/Pathfinding.h 2022-08-21 12:45:40.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -192,8 +192,7 @@ /* * For efficient pathfinding we want to try hard to minimise the per-tile search cost, - * so we precompute the tile passability flags and movement costs for the various different - * types of unit. + * so we precompute the tile passability flags for the various different types of unit. * We also want to minimise memory usage (there can easily be 100K tiles so we don't want * to store many bytes for each). * diff -Nru 0ad-0.0.25b/source/simulation2/MessageTypes.h 0ad-0.0.26/source/simulation2/MessageTypes.h --- 0ad-0.0.25b/source/simulation2/MessageTypes.h 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/MessageTypes.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -41,7 +41,7 @@ class SceneCollector; class CFrustum; -class CMessageTurnStart : public CMessage +class CMessageTurnStart final : public CMessage { public: DEFAULT_MESSAGE_IMPL(TurnStart) @@ -58,7 +58,7 @@ /** * Generic per-turn update message, for things that don't care much about ordering. */ -class CMessageUpdate : public CMessage +class CMessageUpdate final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Update) @@ -75,7 +75,7 @@ * Update phase for formation controller movement (must happen before individual * units move to follow their formation). */ -class CMessageUpdate_MotionFormation : public CMessage +class CMessageUpdate_MotionFormation final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Update_MotionFormation) @@ -91,7 +91,7 @@ /** * Update phase for non-formation-controller unit movement. */ -class CMessageUpdate_MotionUnit : public CMessage +class CMessageUpdate_MotionUnit final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Update_MotionUnit) @@ -107,7 +107,7 @@ /** * Final update phase, after all other updates. */ -class CMessageUpdate_Final : public CMessage +class CMessageUpdate_Final final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Update_Final) @@ -123,7 +123,7 @@ /** * Prepare for rendering a new frame (set up model positions etc). */ -class CMessageInterpolate : public CMessage +class CMessageInterpolate final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Interpolate) @@ -146,7 +146,7 @@ * Add renderable objects to the scene collector. * Called after CMessageInterpolate. */ -class CMessageRenderSubmit : public CMessage +class CMessageRenderSubmit final : public CMessage { public: DEFAULT_MESSAGE_IMPL(RenderSubmit) @@ -172,7 +172,7 @@ * In some situations these messages will never be sent - components must ensure they * load all their data themselves before using it in that case. */ -class CMessageProgressiveLoad : public CMessage +class CMessageProgressiveLoad final : public CMessage { public: DEFAULT_MESSAGE_IMPL(ProgressiveLoad) @@ -195,7 +195,7 @@ * in the deserialization process, may be done in response to this message * instead. */ -class CMessageDeserialized : public CMessage +class CMessageDeserialized final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Deserialized) @@ -210,7 +210,7 @@ * This is sent immediately after a new entity's components have all been created * and initialised. */ -class CMessageCreate : public CMessage +class CMessageCreate final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Create) @@ -230,7 +230,7 @@ * It's possible for this message to be sent multiple times for one entity, but all its components * will have been deleted after the first time. */ -class CMessageDestroy : public CMessage +class CMessageDestroy final : public CMessage { public: DEFAULT_MESSAGE_IMPL(Destroy) @@ -243,7 +243,7 @@ entity_id_t entity; }; -class CMessageOwnershipChanged : public CMessage +class CMessageOwnershipChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(OwnershipChanged) @@ -265,7 +265,7 @@ * If @c inWorld is false, then the other fields are invalid and meaningless. * Otherwise they represent the current position. */ -class CMessagePositionChanged : public CMessage +class CMessagePositionChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(PositionChanged) @@ -285,7 +285,7 @@ * Sent by CCmpPosition whenever anything has changed that will affect the * return value of GetInterpolatedTransform() */ -class CMessageInterpolatedPositionChanged : public CMessage +class CMessageInterpolatedPositionChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(InterpolatedPositionChanged) @@ -302,7 +302,7 @@ }; /*Sent whenever the territory type (neutral,own,enemy) differs from the former type*/ -class CMessageTerritoryPositionChanged : public CMessage +class CMessageTerritoryPositionChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(TerritoryPositionChanged) @@ -319,7 +319,7 @@ /** * Sent by CCmpUnitMotion during Update if an event happened that might interest other components. */ -class CMessageMotionUpdate : public CMessage +class CMessageMotionUpdate final : public CMessage { public: DEFAULT_MESSAGE_IMPL(MotionUpdate) @@ -344,7 +344,7 @@ /** * Sent when water height has been changed. */ -class CMessageWaterChanged : public CMessage +class CMessageWaterChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(WaterChanged) @@ -357,7 +357,7 @@ /** * Sent when terrain (texture or elevation) has been changed. */ -class CMessageTerrainChanged : public CMessage +class CMessageTerrainChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(TerrainChanged) @@ -373,7 +373,7 @@ /** * Sent, at most once per turn, when the visibility of an entity changed */ -class CMessageVisibilityChanged : public CMessage +class CMessageVisibilityChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(VisibilityChanged) @@ -393,7 +393,7 @@ * Sent when then obstruction of an entity has changed in a manner * that changes 'block movement' properties. */ -class CMessageMovementObstructionChanged : public CMessage +class CMessageMovementObstructionChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(MovementObstructionChanged) @@ -407,7 +407,7 @@ * Sent when ObstructionManager's view of the shape of the world has changed * (changing the TILE_OUTOFBOUNDS tiles returned by Rasterise). */ -class CMessageObstructionMapShapeChanged : public CMessage +class CMessageObstructionMapShapeChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(ObstructionMapShapeChanged) @@ -420,7 +420,7 @@ /** * Sent when territory assignments have changed. */ -class CMessageTerritoriesChanged : public CMessage +class CMessageTerritoriesChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(TerritoriesChanged) @@ -434,7 +434,7 @@ * Sent by CCmpRangeManager at most once per turn, when an active range query * has had matching units enter/leave the range since the last RangeUpdate. */ -class CMessageRangeUpdate : public CMessage +class CMessageRangeUpdate final : public CMessage { public: DEFAULT_MESSAGE_IMPL(RangeUpdate) @@ -476,7 +476,7 @@ /** * Sent by CCmpPathfinder after async path requests. */ -class CMessagePathResult : public CMessage +class CMessagePathResult final : public CMessage { public: DEFAULT_MESSAGE_IMPL(PathResult) @@ -493,7 +493,7 @@ /** * Sent by aura manager when a value of a certain entity's component is changed */ -class CMessageValueModification : public CMessage +class CMessageValueModification final : public CMessage { public: DEFAULT_MESSAGE_IMPL(ValueModification) @@ -513,7 +513,7 @@ /** * Sent by atlas if the playercolor has been changed. */ -class CMessagePlayerColorChanged : public CMessage +class CMessagePlayerColorChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(PlayerColorChanged) @@ -529,7 +529,7 @@ /** * Sent by aura and tech managers when a value of a certain template's component is changed */ -class CMessageTemplateModification : public CMessage +class CMessageTemplateModification final : public CMessage { public: DEFAULT_MESSAGE_IMPL(TemplateModification) @@ -549,7 +549,7 @@ /** * Sent by CCmpVision when an entity's vision range changes. */ -class CMessageVisionRangeChanged : public CMessage +class CMessageVisionRangeChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(VisionRangeChanged) @@ -567,7 +567,7 @@ /** * Sent by CCmpVision when an entity's vision sharing changes. */ -class CMessageVisionSharingChanged : public CMessage +class CMessageVisionSharingChanged final : public CMessage { public: DEFAULT_MESSAGE_IMPL(VisionSharingChanged) @@ -585,7 +585,7 @@ /** * Sent when an entity pings the minimap */ -class CMessageMinimapPing : public CMessage +class CMessageMinimapPing final : public CMessage { public: DEFAULT_MESSAGE_IMPL(MinimapPing) @@ -599,7 +599,7 @@ * Cinematics events */ -class CMessageCinemaPathEnded : public CMessage +class CMessageCinemaPathEnded final : public CMessage { public: DEFAULT_MESSAGE_IMPL(CinemaPathEnded) @@ -612,7 +612,7 @@ CStrW name; }; -class CMessageCinemaQueueEnded : public CMessage +class CMessageCinemaQueueEnded final : public CMessage { public: DEFAULT_MESSAGE_IMPL(CinemaQueueEnded) diff -Nru 0ad-0.0.25b/source/simulation2/scripting/EngineScriptConversions.cpp 0ad-0.0.26/source/simulation2/scripting/EngineScriptConversions.cpp --- 0ad-0.0.25b/source/simulation2/scripting/EngineScriptConversions.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/scripting/EngineScriptConversions.cpp 2022-08-21 12:45:40.000000000 +0000 @@ -27,7 +27,6 @@ #include "maths/FixedVector3D.h" #include "maths/Rect.h" #include "ps/CLogger.h" -#include "ps/utf16string.h" #include "simulation2/helpers/CinemaPath.h" #include "simulation2/helpers/Grid.h" #include "simulation2/system/IComponent.h" diff -Nru 0ad-0.0.25b/source/simulation2/scripting/ScriptComponent.h 0ad-0.0.26/source/simulation2/scripting/ScriptComponent.h --- 0ad-0.0.25b/source/simulation2/scripting/ScriptComponent.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/scripting/ScriptComponent.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -102,31 +102,31 @@ { \ return ""; \ } \ - virtual void Init(const CParamNode& paramNode) \ + void Init(const CParamNode& paramNode) override \ { \ m_Script.Init(paramNode, GetEntityId()); \ } \ - virtual void Deinit() \ + void Deinit() override \ { \ m_Script.Deinit(); \ } \ - virtual void HandleMessage(const CMessage& msg, bool global) \ + void HandleMessage(const CMessage& msg, bool global) override \ { \ m_Script.HandleMessage(msg, global); \ } \ - virtual void Serialize(ISerializer& serialize) \ + void Serialize(ISerializer& serialize) override \ { \ m_Script.Serialize(serialize); \ } \ - virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) \ + void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override \ { \ m_Script.Deserialize(paramNode, deserialize, GetEntityId()); \ } \ - virtual JS::Value GetJSInstance() const \ + JS::Value GetJSInstance() const override \ { \ return m_Script.GetInstance(); \ } \ - virtual int GetComponentTypeId() const \ + int GetComponentTypeId() const override \ { \ return CID_##cname; \ } \ diff -Nru 0ad-0.0.25b/source/simulation2/serialization/StdDeserializer.cpp 0ad-0.0.26/source/simulation2/serialization/StdDeserializer.cpp --- 0ad-0.0.25b/source/simulation2/serialization/StdDeserializer.cpp 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/serialization/StdDeserializer.cpp 2022-08-21 12:45:41.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -214,14 +214,14 @@ ReadStringLatin1("prop name", propname); JS::RootedValue propval(rq.cx, ReadScriptVal("prop value", nullptr)); - utf16string prp(propname.begin(), propname.end());; + std::u16string prp(propname.begin(), propname.end());; // TODO: Should ask upstream about getting a variant of JS_SetProperty with a length param. if (!JS_SetUCProperty(rq.cx, obj, (const char16_t*)prp.data(), prp.length(), propval)) throw PSERROR_Deserialize_ScriptError(); } else { - utf16string propname; + std::u16string propname; ReadStringUTF16("prop name", propname); JS::RootedValue propval(rq.cx, ReadScriptVal("prop value", nullptr)); @@ -278,9 +278,10 @@ JS::RootedObject ctorobj(rq.cx); if (!JS_GetClassObject(rq.cx, JSProto_Number, &ctorobj)) throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); + JS::RootedValue protoval(rq.cx, JS::ObjectOrNullValue(ctorobj)); - JS::RootedObject obj(rq.cx, JS_New(rq.cx, ctorobj, JS::HandleValueArray(val))); - if (!obj) + JS::RootedObject obj(rq.cx); + if (!JS::Construct(rq.cx, protoval, JS::HandleValueArray(val), &obj)) throw PSERROR_Deserialize_ScriptError("JS_New failed"); AddScriptBackref(obj); return JS::ObjectValue(*obj); @@ -296,9 +297,10 @@ JS::RootedObject ctorobj(rq.cx); if (!JS_GetClassObject(rq.cx, JSProto_String, &ctorobj)) throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); + JS::RootedValue protoval(rq.cx, JS::ObjectOrNullValue(ctorobj)); - JS::RootedObject obj(rq.cx, JS_New(rq.cx, ctorobj, JS::HandleValueArray(val))); - if (!obj) + JS::RootedObject obj(rq.cx); + if (!JS::Construct(rq.cx, protoval, JS::HandleValueArray(val), &obj)) throw PSERROR_Deserialize_ScriptError("JS_New failed"); AddScriptBackref(obj); return JS::ObjectValue(*obj); @@ -312,9 +314,10 @@ JS::RootedObject ctorobj(rq.cx); if (!JS_GetClassObject(rq.cx, JSProto_Boolean, &ctorobj)) throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); + JS::RootedValue protoval(rq.cx, JS::ObjectOrNullValue(ctorobj)); - JS::RootedObject obj(rq.cx, JS_New(rq.cx, ctorobj, JS::HandleValueArray(val))); - if (!obj) + JS::RootedObject obj(rq.cx); + if (!JS::Construct(rq.cx, protoval, JS::HandleValueArray(val), &obj)) throw PSERROR_Deserialize_ScriptError("JS_New failed"); AddScriptBackref(obj); return JS::ObjectValue(*obj); @@ -441,7 +444,7 @@ Get(name, (u8*)str.data(), len); } -void CStdDeserializer::ReadStringUTF16(const char* name, utf16string& str) +void CStdDeserializer::ReadStringUTF16(const char* name, std::u16string& str) { uint32_t len; NumberU32_Unbounded("string length", len); @@ -471,7 +474,7 @@ } else { - utf16string str; + std::u16string str; ReadStringUTF16(name, str); out.set(JS_NewUCStringCopyN(rq.cx, (const char16_t*)str.data(), str.length())); diff -Nru 0ad-0.0.25b/source/simulation2/serialization/StdDeserializer.h 0ad-0.0.26/source/simulation2/serialization/StdDeserializer.h --- 0ad-0.0.25b/source/simulation2/serialization/StdDeserializer.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/serialization/StdDeserializer.h 2022-08-21 12:45:40.000000000 +0000 @@ -20,8 +20,7 @@ #include "IDeserializer.h" -#include "ps/utf16string.h" - +#include #include class CStdDeserializer : public IDeserializer @@ -48,7 +47,7 @@ private: JS::Value ReadScriptVal(const char* name, JS::HandleObject preexistingObject); void ReadStringLatin1(const char* name, std::vector& str); - void ReadStringUTF16(const char* name, utf16string& str); + void ReadStringUTF16(const char* name, std::u16string& str); virtual void AddScriptBackref(JS::HandleObject obj); virtual void GetScriptBackref(size_t tag, JS::MutableHandleObject ret); diff -Nru 0ad-0.0.25b/source/simulation2/Simulation2.cpp 0ad-0.0.26/source/simulation2/Simulation2.cpp --- 0ad-0.0.25b/source/simulation2/Simulation2.cpp 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/Simulation2.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -510,11 +510,6 @@ if (m_EnableOOSLog) DumpState(); - // Start computing AI for the next turn - CmpPtr cmpAIManager(m_SimContext, SYSTEM_ENTITY); - if (cmpAIManager) - cmpAIManager->StartComputation(); - ++m_TurnNumber; } @@ -535,10 +530,6 @@ componentManager.BroadcastMessage(msgTurnStart); } - // Push AI commands onto the queue before we use them - CmpPtr cmpAIManager(simContext, SYSTEM_ENTITY); - if (cmpAIManager) - cmpAIManager->PushCommands(); CmpPtr cmpCommandQueue(simContext, SYSTEM_ENTITY); if (cmpCommandQueue) @@ -583,6 +574,14 @@ // Clean up any entities destroyed during the simulation update componentManager.FlushDestroyedComponents(); + // Compute AI immediately at turn's end. + CmpPtr cmpAIManager(simContext, SYSTEM_ENTITY); + if (cmpAIManager) + { + cmpAIManager->StartComputation(); + cmpAIManager->PushCommands(); + } + // Process all remaining moves if (cmpPathfinder) { @@ -946,11 +945,6 @@ return GetJSONData(L"maps/random/"); } -std::vector CSimulation2::GetCivData() -{ - return GetJSONData(L"simulation/data/civs/"); -} - std::vector CSimulation2::GetVictoryConditiondData() { return GetJSONData(L"simulation/data/settings/victory_conditions/"); diff -Nru 0ad-0.0.25b/source/simulation2/Simulation2.h 0ad-0.0.26/source/simulation2/Simulation2.h --- 0ad-0.0.25b/source/simulation2/Simulation2.h 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/Simulation2.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -249,13 +249,6 @@ std::vector GetRMSData(); /** - * Get civilization data - * - * @return vector of strings containing JSON format data - */ - std::vector GetCivData(); - - /** * Get victory condition data * * @return vector of strings containing JSON format data diff -Nru 0ad-0.0.25b/source/simulation2/system/Component.h 0ad-0.0.26/source/simulation2/system/Component.h --- 0ad-0.0.25b/source/simulation2/system/Component.h 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/system/Component.h 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,26 +39,26 @@ #define DEFAULT_COMPONENT_ALLOCATOR(cname) \ static IComponent* Allocate(const ScriptInterface&, JS::HandleValue) { return new CCmp##cname(); } \ static void Deallocate(IComponent* cmp) { delete static_cast (cmp); } \ - virtual int GetComponentTypeId() const \ + int GetComponentTypeId() const override \ { \ return CID_##cname; \ } #define DEFAULT_MOCK_COMPONENT() \ - virtual int GetComponentTypeId() const \ + int GetComponentTypeId() const override \ { \ return -1; \ } \ - virtual void Init(const CParamNode& UNUSED(paramNode)) \ + void Init(const CParamNode& UNUSED(paramNode)) override \ { \ } \ - virtual void Deinit() \ + void Deinit() override \ { \ } \ - virtual void Serialize(ISerializer& UNUSED(serialize)) \ + void Serialize(ISerializer& UNUSED(serialize)) override \ { \ } \ - virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& UNUSED(deserialize)) \ + void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& UNUSED(deserialize)) override \ { \ } \ diff -Nru 0ad-0.0.25b/source/simulation2/system/ComponentManager.cpp 0ad-0.0.26/source/simulation2/system/ComponentManager.cpp --- 0ad-0.0.25b/source/simulation2/system/ComponentManager.cpp 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/system/ComponentManager.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,7 +35,7 @@ /** * Used for script-only message types. */ -class CMessageScripted : public CMessage +class CMessageScripted final : public CMessage { public: virtual int GetType() const { return mtid; } @@ -68,7 +68,7 @@ // these functions, so we skip registering them here in those cases if (!skipScriptFunctions) { - JSI_VFS::RegisterScriptFunctions_Simulation(m_ScriptInterface); + JSI_VFS::RegisterScriptFunctions_ReadOnlySimulation(m_ScriptInterface); ScriptRequest rq(m_ScriptInterface); constexpr ScriptFunction::ObjectGetter Getter = &ScriptInterface::ObjectFromCBData; ScriptFunction::Register<&CComponentManager::Script_RegisterComponentType, Getter>(rq, "RegisterComponentType"); @@ -86,6 +86,8 @@ ScriptFunction::Register<&CComponentManager::QueryInterface, Getter>(rq, "QueryInterface"); ScriptFunction::Register<&CComponentManager::DestroyComponentsSoon, Getter>(rq, "DestroyEntity"); ScriptFunction::Register<&CComponentManager::FlushDestroyedComponents, Getter>(rq, "FlushDestroyedEntities"); + ScriptFunction::Register<&CComponentManager::Script_GetTemplate, Getter>(rq, "GetTemplate"); + } // Globalscripts may use VFS script functions @@ -382,6 +384,23 @@ m_ScriptInterface.SetGlobal(name.c_str(), value, m_CurrentlyHotloading); } +const CParamNode& CComponentManager::Script_GetTemplate(const std::string& templateName) +{ + static CParamNode nullNode(false); + + ICmpTemplateManager* cmpTemplateManager = static_cast (QueryInterface(SYSTEM_ENTITY, IID_TemplateManager)); + if (!cmpTemplateManager) + { + LOGERROR("Template manager is not loaded"); + return nullNode; + } + + const CParamNode* tmpl = cmpTemplateManager->GetTemplate(templateName); + if (!tmpl) + return nullNode; + return *tmpl; +} + std::vector CComponentManager::Script_GetEntitiesWithInterface(int iid) { std::vector ret; @@ -728,6 +747,7 @@ } // Construct the new component + // NB: The unit motion manager relies on components not moving in memory once constructed. IComponent* component = ct.alloc(m_ScriptInterface, obj); ENSURE(component); diff -Nru 0ad-0.0.25b/source/simulation2/system/ComponentManager.h 0ad-0.0.26/source/simulation2/system/ComponentManager.h --- 0ad-0.0.25b/source/simulation2/system/ComponentManager.h 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/system/ComponentManager.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -286,6 +286,7 @@ void Script_BroadcastMessage(int mtid, JS::HandleValue data); int Script_AddEntity(const std::wstring& templateName); int Script_AddLocalEntity(const std::wstring& templateName); + const CParamNode& Script_GetTemplate(const std::string& templateName); CMessage* ConstructMessage(int mtid, JS::HandleValue data); void SendGlobalMessage(entity_id_t ent, const CMessage& msg); diff -Nru 0ad-0.0.25b/source/simulation2/system/ComponentTest.h 0ad-0.0.26/source/simulation2/system/ComponentTest.h --- 0ad-0.0.25b/source/simulation2/system/ComponentTest.h 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/system/ComponentTest.h 2022-09-23 19:17:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -193,56 +193,56 @@ public: DEFAULT_MOCK_COMPONENT() - virtual bool IsLoaded() const + bool IsLoaded() const override { return true; } - virtual CFixedVector3D CalcNormal(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const + CFixedVector3D CalcNormal(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const override { return CFixedVector3D(fixed::FromInt(0), fixed::FromInt(1), fixed::FromInt(0)); } - virtual CVector3D CalcExactNormal(float UNUSED(x), float UNUSED(z)) const + CVector3D CalcExactNormal(float UNUSED(x), float UNUSED(z)) const override { return CVector3D(0.f, 1.f, 0.f); } - virtual entity_pos_t GetGroundLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const + entity_pos_t GetGroundLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const override { return entity_pos_t::FromInt(50); } - virtual float GetExactGroundLevel(float UNUSED(x), float UNUSED(z)) const + float GetExactGroundLevel(float UNUSED(x), float UNUSED(z)) const override { return 50.f; } - virtual u16 GetTilesPerSide() const + u16 GetTilesPerSide() const override { return 16; } - virtual u32 GetMapSize() const + u32 GetMapSize() const override { return GetTilesPerSide() * TERRAIN_TILE_SIZE; } - virtual u16 GetVerticesPerSide() const + u16 GetVerticesPerSide() const override { return 17; } - virtual CTerrain* GetCTerrain() + CTerrain* GetCTerrain() override { - return NULL; + return nullptr; } - virtual void MakeDirty(i32 UNUSED(i0), i32 UNUSED(j0), i32 UNUSED(i1), i32 UNUSED(j1)) + void MakeDirty(i32 UNUSED(i0), i32 UNUSED(j0), i32 UNUSED(i1), i32 UNUSED(j1)) override { } - virtual void ReloadTerrain(bool UNUSED(ReloadWater)) + void ReloadTerrain(bool UNUSED(ReloadWater)) override { } }; diff -Nru 0ad-0.0.25b/source/simulation2/system/ParamNode.cpp 0ad-0.0.26/source/simulation2/system/ParamNode.cpp --- 0ad-0.0.25b/source/simulation2/system/ParamNode.cpp 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/system/ParamNode.cpp 2022-08-21 12:45:40.000000000 +0000 @@ -411,8 +411,8 @@ // If the node has a string too, add that as an extra property if (!m_Value.empty()) { - utf16string text(m_Value.begin(), m_Value.end()); - JS::RootedString str(rq.cx, JS_AtomizeAndPinUCStringN(rq.cx, reinterpret_cast(text.data()), text.length())); + std::u16string text(m_Value.begin(), m_Value.end()); + JS::RootedString str(rq.cx, JS_AtomizeAndPinUCStringN(rq.cx, text.c_str(), text.length())); if (!str) { ret.setUndefined(); diff -Nru 0ad-0.0.25b/source/simulation2/tests/test_Serializer.h 0ad-0.0.26/source/simulation2/tests/test_Serializer.h --- 0ad-0.0.25b/source/simulation2/tests/test_Serializer.h 2021-07-27 21:56:44.000000000 +0000 +++ 0ad-0.0.26/source/simulation2/tests/test_Serializer.h 2022-08-21 12:45:40.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include "graphics/MapReader.h" #include "graphics/Terrain.h" #include "graphics/TerrainTextureManager.h" +#include "lib/config2.h" #include "lib/timer.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" @@ -35,7 +36,9 @@ #include "ps/XML/Xeromyces.h" #include "simulation2/Simulation2.h" -#include "callgrind.h" +#if CONFIG2_VALGRIND +# include "callgrind.h" +#endif #include @@ -882,11 +885,6 @@ TS_ASSERT_OK(g_VFS->Mount(L"", DataDir() / "mods" / "public" / "", VFS_MOUNT_MUST_EXIST)); TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); - // Need some stuff for terrain movement costs: - // (TODO: this ought to be independent of any graphics code) - new CTerrainTextureManager; - g_TexMan.LoadTerrainTextures(); - CTerrain terrain; CSimulation2 sim2(NULL, g_ScriptContext, &terrain); @@ -919,19 +917,22 @@ } double t = timer_Time(); +#if CONFIG2_VALGRIND CALLGRIND_START_INSTRUMENTATION; +#endif size_t reps = 128; for (size_t i = 0; i < reps; ++i) { std::string hash; sim2.ComputeStateHash(hash, false); } +#if CONFIG2_VALGRIND CALLGRIND_STOP_INSTRUMENTATION; +#endif t = timer_Time() - t; debug_printf("# time = %f (%f/%d)\n", t/reps, t, (int)reps); // Shut down the world - delete &g_TexMan; g_VFS.reset(); DeleteDirectory(DataDir()/"_testcache"); CXeromyces::Terminate(); diff -Nru 0ad-0.0.25b/source/soundmanager/ISoundManager.h 0ad-0.0.26/source/soundmanager/ISoundManager.h --- 0ad-0.0.25b/source/soundmanager/ISoundManager.h 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/soundmanager/ISoundManager.h 2022-08-21 12:45:45.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,9 +20,9 @@ #include "lib/config2.h" #include "lib/file/vfs/vfs_path.h" +#include "ps/CStr.h" #include "simulation2/system/Entity.h" -class CStr8; class CVector3D; class ISoundManager diff -Nru 0ad-0.0.25b/source/soundmanager/items/CSoundBase.cpp 0ad-0.0.26/source/soundmanager/items/CSoundBase.cpp --- 0ad-0.0.25b/source/soundmanager/items/CSoundBase.cpp 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/soundmanager/items/CSoundBase.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -177,7 +177,7 @@ if ( m_ALSource ) { std::lock_guard lock(m_ItemMutex); - alSourcefv(m_ALSource, AL_DIRECTION, direction.GetFloatArray()); + alSourcefv(m_ALSource, AL_DIRECTION, direction.AsFloatArray().data()); AL_CHECK; } } @@ -212,7 +212,7 @@ if ( m_ALSource != 0 ) { std::lock_guard lock(m_ItemMutex); - alSourcefv(m_ALSource,AL_POSITION, position.GetFloatArray()); + alSourcefv(m_ALSource,AL_POSITION, position.AsFloatArray().data()); AL_CHECK; } } diff -Nru 0ad-0.0.25b/source/soundmanager/scripting/SoundGroup.cpp 0ad-0.0.26/source/soundmanager/scripting/SoundGroup.cpp --- 0ad-0.0.25b/source/soundmanager/scripting/SoundGroup.cpp 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/soundmanager/scripting/SoundGroup.cpp 2022-09-23 19:17:13.000000000 +0000 @@ -253,7 +253,7 @@ if (err == ERR::AGAIN) return; - LOGERROR("%s: pathname=%s, error=%s", utf8_from_wstring(message), pathname.string8(), utf8_from_wstring(ErrorString(err))); + LOGERROR("%s: pathname=%s, error=%s", utf8_from_wstring(message), pathname.string8(), GetStatusAsString(err).c_str()); } void CSoundGroup::PlayNext(const CVector3D& position, entity_id_t source) diff -Nru 0ad-0.0.25b/source/soundmanager/scripting/SoundGroup.h 0ad-0.0.26/source/soundmanager/scripting/SoundGroup.h --- 0ad-0.0.25b/source/soundmanager/scripting/SoundGroup.h 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/soundmanager/scripting/SoundGroup.h 2022-08-21 12:45:45.000000000 +0000 @@ -27,7 +27,6 @@ #include class CVector3D; -class ISoundItem; enum eSndGrpFlags { diff -Nru 0ad-0.0.25b/source/soundmanager/SoundManager.h 0ad-0.0.26/source/soundmanager/SoundManager.h --- 0ad-0.0.25b/source/soundmanager/SoundManager.h 2021-07-27 21:57:03.000000000 +0000 +++ 0ad-0.0.26/source/soundmanager/SoundManager.h 2022-08-21 12:45:45.000000000 +0000 @@ -29,6 +29,7 @@ #include "lib/external_libraries/openal.h" #include "lib/file/vfs/vfs_path.h" +#include "ps/CStr.h" #include "ps/Profiler2.h" #include "simulation2/system/Entity.h" @@ -36,8 +37,6 @@ #include #include -class CStr8; - #define AL_CHECK CSoundManager::al_check(__func__, __LINE__) struct ALSourceHolder diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp 2021-07-27 21:56:47.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -343,8 +343,6 @@ ID_BigScreenshot, ID_JavaScript, ID_CameraReset, - ID_RenderPathShaderARB, - ID_RenderPathShaderGLSL, ID_DumpState, ID_DumpBinaryState, @@ -379,8 +377,6 @@ EVT_MENU(ID_CameraReset, ScenarioEditor::OnCameraReset) EVT_MENU(ID_DumpState, ScenarioEditor::OnDumpState) EVT_MENU(ID_DumpBinaryState, ScenarioEditor::OnDumpState) - EVT_MENU(ID_RenderPathShaderARB, ScenarioEditor::OnRenderPath) - EVT_MENU(ID_RenderPathShaderGLSL, ScenarioEditor::OnRenderPath) EVT_MENU(ID_Manual, ScenarioEditor::OnHelp) EVT_MENU(ID_ReportBug, ScenarioEditor::OnHelp) @@ -499,11 +495,6 @@ menuMisc->AppendSubMenu(menuSS, _("Si&mulation state")); menuSS->Append(ID_DumpState, _("&Dump to disk")); menuSS->Append(ID_DumpBinaryState, _("Dump &binary to disk")); - - wxMenu *menuRP = new wxMenu; - menuMisc->AppendSubMenu(menuRP, _("Render &path")); - menuRP->Append(ID_RenderPathShaderARB, _("Shader &ARB")); - menuRP->Append(ID_RenderPathShaderGLSL, _("&Shader GLSL (default)")); } wxMenu *menuHelp = new wxMenu; @@ -672,6 +663,10 @@ m_FileHistory.SaveToSubDir(*wxConfigBase::Get()); + // We notify all clients that might interact with the game after its + // shutdown to prevent accessing invalid state. + m_SectionLayout.OnShutdown(); + POST_MESSAGE(Shutdown, ()); qExit().Post(); @@ -937,10 +932,10 @@ switch (event.GetId()) { case ID_BigScreenshot: - POST_MESSAGE(Screenshot, (true, 10)); + POST_MESSAGE(Screenshot, (true)); break; case ID_Screenshot: - POST_MESSAGE(Screenshot, (false, 0)); + POST_MESSAGE(Screenshot, (false)); break; } } @@ -958,21 +953,6 @@ POST_MESSAGE(CameraReset, ()); } -void ScenarioEditor::OnRenderPath(wxCommandEvent& event) -{ - switch (event.GetId()) - { - case ID_RenderPathShaderARB: - POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"shader")); - POST_MESSAGE(SetViewParamB, (eRenderView::GAME, L"preferGLSL", false)); - break; - case ID_RenderPathShaderGLSL: - POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"shader")); - POST_MESSAGE(SetViewParamB, (eRenderView::GAME, L"preferGLSL", true)); - break; - } -} - void ScenarioEditor::OnDumpState(wxCommandEvent& event) { wxDateTime time = wxDateTime::Now(); diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h 2021-07-27 21:56:47.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -57,7 +57,6 @@ void OnMediaPlayer(wxCommandEvent& event); void OnJavaScript(wxCommandEvent& event); void OnCameraReset(wxCommandEvent& event); - void OnRenderPath(wxCommandEvent& event); void OnDumpState(wxCommandEvent& event); void OnSelectedObjectsChange(const std::vector& selectedObjects); diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp 2021-07-27 21:56:47.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -184,6 +184,12 @@ m_Pages[i].bar->OnMapReload(); } + void OnShutdown() + { + for (size_t i = 0; i < m_Pages.size(); ++i) + m_Pages[i].bar->OnShutdown(); + } + protected: void OnPageChanged(SidebarPage oldPage, SidebarPage newPage) @@ -312,3 +318,8 @@ { m_SidebarBook->OnMapReload(); } + +void SectionLayout::OnShutdown() +{ + m_SidebarBook->OnShutdown(); +} diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.h 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.h --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.h 2021-07-27 21:56:47.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.h 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -52,6 +52,7 @@ void SelectPage(const wxString& classname); void OnMapReload(); + void OnShutdown(); private: SidebarBook* m_SidebarBook; diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Common/Sidebar.h 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Common/Sidebar.h --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Common/Sidebar.h 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Common/Sidebar.h 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,6 +32,8 @@ virtual void OnMapReload() {} + virtual void OnShutdown() {} + protected: ScenarioEditor& m_ScenarioEditor; diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,8 +29,6 @@ static Observable g_EnvironmentSettings; -const float M_PIf = 3.14159265f; - ////////////////////////////////////////////////////////////////////////// class VariableSliderBox : public wxPanel @@ -85,12 +83,15 @@ : wxPanel(parent), m_Var(var) { - m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableListBox::OnSettingsChange, this); + m_Conn = g_EnvironmentSettings.RegisterObserver( + 0, &VariableListBox::OnSettingsChange, this); m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label); SetSizer(m_Sizer); - m_Combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxArrayString(), wxCB_READONLY), + m_Combo = new wxComboBox( + this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxArrayString(), wxCB_READONLY), m_Sizer->Add(m_Combo, wxSizerFlags().Expand()); } @@ -206,8 +207,9 @@ POST_COMMAND(SetEnvironmentSettings, (settings)); } -EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) -: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer) +EnvironmentSidebar::EnvironmentSidebar( + ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) + : Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer) { wxSizer* scrollSizer = new wxBoxSizer(wxVERTICAL); wxScrolledWindow* scrolledWindow = new wxScrolledWindow(this); @@ -217,15 +219,24 @@ wxSizer* waterSizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _T("Water settings")); scrollSizer->Add(waterSizer, wxSizerFlags().Expand()); - waterSizer->Add(new wxButton(scrolledWindow, ID_RecomputeWaterData, _("Reset Water Data")), wxSizerFlags().Expand()); - waterSizer->Add(m_WaterTypeList = new VariableListBox(scrolledWindow, _("Water Type"), g_EnvironmentSettings.watertype), wxSizerFlags().Expand()); - waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Water height"), g_EnvironmentSettings.waterheight, 0.f, 1.2f), wxSizerFlags().Expand()); - waterSizer->Add(new wxButton(scrolledWindow, ID_PickWaterHeight, _("Pick Water Height")), wxSizerFlags().Expand()); - waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0.f, 10.f), wxSizerFlags().Expand()); - waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Water murkiness"), g_EnvironmentSettings.watermurkiness, 0.f, 1.f), wxSizerFlags().Expand()); - waterSizer->Add(new VariableSliderBox(scrolledWindow, _("Wind angle"), g_EnvironmentSettings.windangle, -M_PIf, M_PIf), wxSizerFlags().Expand()); - waterSizer->Add(new VariableColorBox(scrolledWindow, _("Water color"), g_EnvironmentSettings.watercolor), wxSizerFlags().Expand()); - waterSizer->Add(new VariableColorBox(scrolledWindow, _("Water tint"), g_EnvironmentSettings.watertint), wxSizerFlags().Expand()); + waterSizer->Add(new wxButton( + scrolledWindow, ID_RecomputeWaterData, _("Reset Water Data")), wxSizerFlags().Expand()); + waterSizer->Add(m_WaterTypeList = new VariableListBox( + scrolledWindow, _("Water Type"), g_EnvironmentSettings.watertype), wxSizerFlags().Expand()); + waterSizer->Add(new VariableSliderBox( + scrolledWindow, _("Water height"), g_EnvironmentSettings.waterheight, 0.f, 1.2f), wxSizerFlags().Expand()); + waterSizer->Add(new wxButton( + scrolledWindow, ID_PickWaterHeight, _("Pick Water Height")), wxSizerFlags().Expand()); + waterSizer->Add(new VariableSliderBox( + scrolledWindow, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0.f, 10.f), wxSizerFlags().Expand()); + waterSizer->Add(new VariableSliderBox( + scrolledWindow, _("Water murkiness"), g_EnvironmentSettings.watermurkiness, 0.f, 1.f), wxSizerFlags().Expand()); + waterSizer->Add(new VariableSliderBox( + scrolledWindow, _("Wind angle"), g_EnvironmentSettings.windangle, -static_cast(M_PI), static_cast(M_PI)), wxSizerFlags().Expand()); + waterSizer->Add(new VariableColorBox( + scrolledWindow, _("Water color"), g_EnvironmentSettings.watercolor), wxSizerFlags().Expand()); + waterSizer->Add(new VariableColorBox( + scrolledWindow, _("Water tint"), g_EnvironmentSettings.watertint), wxSizerFlags().Expand()); std::vector list; list.push_back(L"ocean"); list.push_back(L"lake"); list.push_back(L"clap"); @@ -235,25 +246,40 @@ wxSizer* sunSizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _T("Sun / lighting settings")); scrollSizer->Add(sunSizer, wxSizerFlags().Expand().Border(wxTOP, 8)); - sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -M_PIf, M_PIf), wxSizerFlags().Expand()); - sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -M_PIf/2, M_PIf/2), wxSizerFlags().Expand()); - sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Sun overbrightness"), g_EnvironmentSettings.sunoverbrightness, 1.0f, 3.0f), wxSizerFlags().Expand()); - sunSizer->Add(new LightControl(scrolledWindow, wxSize(150, 150), g_EnvironmentSettings)); - sunSizer->Add(new VariableColorBox(scrolledWindow, _("Sun color"), g_EnvironmentSettings.suncolor), wxSizerFlags().Expand()); - sunSizer->Add(m_SkyList = new VariableListBox(scrolledWindow, _("Sky set"), g_EnvironmentSettings.skyset), wxSizerFlags().Expand()); - sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Fog Factor"), g_EnvironmentSettings.fogfactor, 0.0f, 0.01f), wxSizerFlags().Expand()); - sunSizer->Add(new VariableSliderBox(scrolledWindow, _("Fog Thickness"), g_EnvironmentSettings.fogmax, 0.5f, 0.0f), wxSizerFlags().Expand()); - sunSizer->Add(new VariableColorBox(scrolledWindow, _("Fog color"), g_EnvironmentSettings.fogcolor), wxSizerFlags().Expand()); - sunSizer->Add(new VariableColorBox(scrolledWindow, _("Ambient color"), g_EnvironmentSettings.ambientcolor), wxSizerFlags().Expand()); + sunSizer->Add(new VariableSliderBox( + scrolledWindow, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -static_cast(M_PI), static_cast(M_PI)), wxSizerFlags().Expand()); + sunSizer->Add(new VariableSliderBox( + scrolledWindow, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -static_cast(M_PI) / 2.0f, static_cast(M_PI) / 2.0f), wxSizerFlags().Expand()); + sunSizer->Add(new VariableSliderBox( + scrolledWindow, _("Sun overbrightness"), g_EnvironmentSettings.sunoverbrightness, 1.0f, 3.0f), wxSizerFlags().Expand()); + sunSizer->Add(new LightControl( + scrolledWindow, wxSize(150, 150), g_EnvironmentSettings)); + sunSizer->Add(new VariableColorBox( + scrolledWindow, _("Sun color"), g_EnvironmentSettings.suncolor), wxSizerFlags().Expand()); + sunSizer->Add(m_SkyList = new VariableListBox( + scrolledWindow, _("Sky set"), g_EnvironmentSettings.skyset), wxSizerFlags().Expand()); + sunSizer->Add(new VariableSliderBox( + scrolledWindow, _("Fog Factor"), g_EnvironmentSettings.fogfactor, 0.0f, 0.01f), wxSizerFlags().Expand()); + sunSizer->Add(new VariableSliderBox( + scrolledWindow, _("Fog Thickness"), g_EnvironmentSettings.fogmax, 0.5f, 0.0f), wxSizerFlags().Expand()); + sunSizer->Add(new VariableColorBox( + scrolledWindow, _("Fog color"), g_EnvironmentSettings.fogcolor), wxSizerFlags().Expand()); + sunSizer->Add(new VariableColorBox( + scrolledWindow, _("Ambient color"), g_EnvironmentSettings.ambientcolor), wxSizerFlags().Expand()); wxSizer* postProcSizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _T("Post-processing settings")); scrollSizer->Add(postProcSizer, wxSizerFlags().Expand().Border(wxTOP, 8)); - postProcSizer->Add(m_PostEffectList = new VariableListBox(scrolledWindow, _("Post Effect"), g_EnvironmentSettings.posteffect), wxSizerFlags().Expand()); - postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Brightness"), g_EnvironmentSettings.brightness, -0.5f, 0.5f), wxSizerFlags().Expand()); - postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Contrast (HDR)"), g_EnvironmentSettings.contrast, 0.5f, 1.5f), wxSizerFlags().Expand()); - postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Saturation"), g_EnvironmentSettings.saturation, 0.0f, 2.0f), wxSizerFlags().Expand()); - postProcSizer->Add(new VariableSliderBox(scrolledWindow, _("Bloom"), g_EnvironmentSettings.bloom, 0.2f, 0.0f), wxSizerFlags().Expand()); + postProcSizer->Add(m_PostEffectList = new VariableListBox( + scrolledWindow, _("Post Effect"), g_EnvironmentSettings.posteffect), wxSizerFlags().Expand()); + postProcSizer->Add(new VariableSliderBox( + scrolledWindow, _("Brightness"), g_EnvironmentSettings.brightness, -0.5f, 0.5f), wxSizerFlags().Expand()); + postProcSizer->Add(new VariableSliderBox( + scrolledWindow, _("Contrast (HDR)"), g_EnvironmentSettings.contrast, 0.5f, 1.5f), wxSizerFlags().Expand()); + postProcSizer->Add(new VariableSliderBox( + scrolledWindow, _("Saturation"), g_EnvironmentSettings.saturation, 0.0f, 2.0f), wxSizerFlags().Expand()); + postProcSizer->Add(new VariableSliderBox( + scrolledWindow, _("Bloom"), g_EnvironmentSettings.bloom, 0.2f, 0.0f), wxSizerFlags().Expand()); m_Conn = g_EnvironmentSettings.RegisterObserver(0, &SendToGame); } diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,6 +27,8 @@ #include "ScenarioEditor/Tools/Common/Tools.h" #include +#include +#include #include #include @@ -39,6 +41,7 @@ ID_MapName, ID_MapDescription, ID_MapReveal, + ID_MapAlly, ID_MapType, ID_MapPreview, ID_MapTeams, @@ -169,6 +172,7 @@ gridSizer->Add(Tooltipped(new wxTextCtrl(this, ID_MapPreview, wxEmptyString), _("Texture used for map preview")), wxSizerFlags().Expand()); CREATE_CHECKBOX(this, gridSizer, "Reveal map", "If checked, players won't need to explore", ID_MapReveal); + CREATE_CHECKBOX(this, gridSizer, "Ally view", "If checked, players will be able to see what their teammates see and won't need to research cartography", ID_MapAlly); CREATE_CHECKBOX(this, gridSizer, "Lock teams", "If checked, teams will be locked", ID_MapTeams); sizer->Add(gridSizer, wxSizerFlags().Expand()); @@ -233,6 +237,9 @@ // reveal map wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->SetValue(wxString::FromUTF8(m_MapSettings["RevealMap"]) == "true"); + // ally view + wxDynamicCast(FindWindow(ID_MapAlly), wxCheckBox)->SetValue(wxString::FromUTF8(m_MapSettings["AllyView"]) == "true"); + // victory conditions m_MapSettingsVictoryConditions.clear(); for (AtIter victoryCondition = m_MapSettings["VictoryConditions"]["item"]; victoryCondition.defined(); ++victoryCondition) @@ -364,6 +371,9 @@ // reveal map m_MapSettings.setBool("RevealMap", wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->GetValue()); + // ally view + m_MapSettings.setBool("AllyView", wxDynamicCast(FindWindow(ID_MapAlly), wxCheckBox)->GetValue()); + // victory conditions #define INSERT_VICTORY_CONDITION_CHECKBOX(name, ID) \ if (wxDynamicCast(FindWindow(ID), wxCheckBox)->GetValue()) \ @@ -661,9 +671,12 @@ void MapSidebar::OnRandomReseed(wxCommandEvent& WXUNUSED(evt)) { + std::mt19937 engine(std::time(nullptr)); + std::uniform_int_distribution distribution(0, 10000); + // Pick a shortish randomish value wxString seed; - seed << (int)floor((rand() / (float)RAND_MAX) * 10000.f); + seed << distribution(engine); wxDynamicCast(FindWindow(ID_RandomSeed), wxTextCtrl)->SetValue(seed); } diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -84,7 +84,6 @@ bool m_ViewerMove; bool m_ViewerGround; bool m_ViewerWater; - bool m_ViewerShadows; bool m_ViewerPolyCount; bool m_ViewerBoundingBox; bool m_ViewerAxesMarker; @@ -523,7 +522,6 @@ m_ViewerMove = false; m_ViewerGround = true; m_ViewerWater = false; - m_ViewerShadows = true; m_ViewerPolyCount = false; m_ViewerBoundingBox = false; m_ViewerAxesMarker = false; @@ -701,7 +699,6 @@ POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"ground", m_ViewerGround)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"water", m_ViewerWater)); - POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", m_ViewerShadows)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"stats", m_ViewerPolyCount)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"bounding_box", m_ViewerBoundingBox)); POST_MESSAGE(SetViewParamI, (AtlasMessage::eRenderView::ACTOR, L"prop_points", m_ViewerPropPointsMode)); @@ -734,8 +731,7 @@ POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"water", m_ViewerWater)); break; case ID_ViewerShadows: - m_ViewerShadows = !m_ViewerShadows; - POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", m_ViewerShadows)); + POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", true)); break; case ID_ViewerPolyCount: m_ViewerPolyCount = !m_ViewerPolyCount; diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp 2022-09-23 19:16:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -583,12 +583,11 @@ wxArrayString civCodes; AtlasMessage::qGetCivData qryCiv; qryCiv.Post(); - std::vector civData = *qryCiv.data; - for (size_t i = 0; i < civData.size(); ++i) + std::vector> civData = *qryCiv.data; + for (const std::vector& civ : civData) { - AtObj civ = AtlasObject::LoadFromJSON(civData[i]); - civNames.Add(wxString::FromUTF8(civ["Name"])); - civCodes.Add(wxString::FromUTF8(civ["Code"])); + civCodes.Add(civ[0]); + civNames.Add(civ[1]); } // Load AI data diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,8 @@ #include "GameInterface/Messages.h" +#include +#include #include #include #include @@ -33,6 +35,15 @@ #include #include +namespace +{ + +const int PREVIEW_RELOAD_DELAY_MILLISECONDS = 2000; +const int PREVIEW_RELOAD_TIMEOUT_DELAY_MILLISECONDS = 200; +const float PREVIEW_RELOAD_TIMEOUT_THRESHOLD_SECONDS = 0.1f; + +} // anonymous namespace + class TextureNotebook; class TerrainBottomBar : public wxPanel @@ -40,6 +51,7 @@ public: TerrainBottomBar(ScenarioEditor& scenarioEditor, wxWindow* parent); void LoadTerrain(); + void OnShutdown(); private: TextureNotebook* m_Textures; }; @@ -130,7 +142,7 @@ } else if (!preview.loaded && !m_Timer.IsRunning()) { - m_Timer.Start(2000); + m_Timer.Start(PREVIEW_RELOAD_DELAY_MILLISECONDS); } } @@ -249,6 +261,11 @@ m_BottomBar = new TerrainBottomBar(scenarioEditor, bottomBarContainer); } +void TerrainSidebar::OnShutdown() +{ + static_cast(m_BottomBar)->OnShutdown(); +} + void TerrainSidebar::OnFirstDisplay() { AtlasMessage::qGetTerrainPassabilityClasses qry; @@ -314,66 +331,114 @@ wxBusyInfo busy (_("Loading terrain previews")); + AtlasMessage::qGetTerrainGroupTextures query((std::wstring)m_Name.wc_str()); + query.Post(); + m_Textures = *query.names; + + LayoutButtons(); ReloadPreviews(); } - void ReloadPreviews() + void LayoutButtons() { Freeze(); m_ScrolledPanel->DestroyChildren(); m_ItemSizer->Clear(); - m_LastTerrainSelection = NULL; // clear any reference to deleted button - - AtlasMessage::qGetTerrainGroupPreviews qry((std::wstring)m_Name.wc_str(), imageWidth, imageHeight); - qry.Post(); - - std::vector previews = *qry.previews; - - bool allLoaded = true; + m_LastTerrainSelection = nullptr; // clear any reference to deleted button - for (size_t i = 0; i < previews.size(); ++i) + for (const std::wstring& textureName : m_Textures) { - if (!previews[i].loaded) - allLoaded = false; - - wxString name = previews[i].name.c_str(); - // Construct the wrapped-text label - wxStaticText* label = new wxStaticText(m_ScrolledPanel, wxID_ANY, FormatTextureName(name), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER); + wxStaticText* label = new wxStaticText(m_ScrolledPanel, wxID_ANY, FormatTextureName(textureName), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER); label->Wrap(imageWidth); - unsigned char* buf = (unsigned char*)(malloc(previews[i].imageData.GetSize())); - // imagedata.GetBuffer() gives a Shareable*, which - // is stored the same as a unsigned char*, so we can just copy it. - memcpy(buf, previews[i].imageData.GetBuffer(), previews[i].imageData.GetSize()); - wxImage img (imageWidth, imageHeight, buf); + wxImage image(imageWidth, imageHeight); + wxBitmapButton* button = new wxBitmapButton(m_ScrolledPanel, wxID_ANY, wxBitmap(image)); - wxButton* button = new wxBitmapButton(m_ScrolledPanel, wxID_ANY, wxBitmap(img)); // Store the texture name in the clientdata slot - button->SetClientObject(new wxStringClientData(name)); + button->SetClientObject(new wxStringClientData(textureName)); wxSizer* imageSizer = new wxBoxSizer(wxVERTICAL); imageSizer->Add(button, wxSizerFlags().Center()); imageSizer->Add(label, wxSizerFlags().Proportion(1).Center()); m_ItemSizer->Add(imageSizer, wxSizerFlags().Expand()); + + m_PreviewButtons.emplace(textureName, PreviewButton{button, false}); } m_ScrolledPanel->Fit(); Layout(); Thaw(); + } + + void ReloadPreviews() + { + bool allLoaded = true; + bool timeout = false; + const std::chrono::high_resolution_clock::time_point reloadingStart = + std::chrono::high_resolution_clock::now(); + for (const std::wstring& textureName : m_Textures) + { + const auto it = m_PreviewButtons.find(textureName); + if (it == m_PreviewButtons.end() || it->second.loaded) + continue; + + if (timeout) + { + // Mark allLoaded only in case we have a real not loaded texture, and not + // because we have an exceeded timeout. + allLoaded = false; + continue; + } + + AtlasMessage::qGetTerrainTexturePreview previewQuery(textureName, imageWidth, imageHeight); + previewQuery.Post(); + AtlasMessage::sTerrainTexturePreview preview = previewQuery.preview; + + if (!preview.loaded) + allLoaded = false; + else + it->second.loaded = true; + + if (preview.imageData.GetSize()) + { + unsigned char* buffer = reinterpret_cast(malloc(preview.imageData.GetSize())); + // imagedata.GetBuffer() gives a Shareable*, which + // is stored the same as a unsigned char*, so we can just copy it. + memcpy(buffer, preview.imageData.GetBuffer(), preview.imageData.GetSize()); + wxImage image(imageWidth, imageHeight, buffer); + it->second.button->SetBitmap(wxBitmap(image)); + } + + // We need to load at least one preview so check for timeout inside real + // loading. + const std::chrono::high_resolution_clock::time_point now = + std::chrono::high_resolution_clock::now(); + const std::chrono::duration delta = now - reloadingStart; + if (delta.count() > PREVIEW_RELOAD_TIMEOUT_THRESHOLD_SECONDS) + timeout = true; + } // If not all textures were loaded yet, run a timer to reload the previews - // every so often until they've all finished + // every so often until they've all finished. if (allLoaded && m_Timer.IsRunning()) { m_Timer.Stop(); + m_PreviewButtons.clear(); } - else if (!allLoaded && !m_Timer.IsRunning()) + else if (!allLoaded) { - m_Timer.Start(2000); + if (timeout) + { + // In case we didn't have enough time to load all previews + // start after a minimum delay to not freeze the whole UI. + m_Timer.Start(PREVIEW_RELOAD_TIMEOUT_DELAY_MILLISECONDS); + } + else + m_Timer.Start(PREVIEW_RELOAD_DELAY_MILLISECONDS); } } @@ -409,6 +474,12 @@ ReloadPreviews(); } + void OnShutdown() + { + if (m_Timer.IsRunning()) + m_Timer.Stop(); + } + private: ScenarioEditor& m_ScenarioEditor; bool m_Loaded; @@ -418,6 +489,14 @@ wxGridSizer* m_ItemSizer; wxButton* m_LastTerrainSelection; // button that was last selected, so we can undo its coloring + std::vector m_Textures; + struct PreviewButton + { + wxBitmapButton* button; + bool loaded; + }; + std::unordered_map m_PreviewButtons; + DECLARE_EVENT_TABLE(); }; @@ -466,6 +545,12 @@ } } + void OnShutdown() + { + for (size_t index = 0; index < GetPageCount(); ++index) + static_cast(GetPage(index))->OnShutdown(); + } + protected: void OnPageChanged(wxNotebookEvent& event) { @@ -502,3 +587,8 @@ { m_Textures->LoadTerrain(); } + +void TerrainBottomBar::OnShutdown() +{ + m_Textures->OnShutdown(); +} diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,8 +24,10 @@ public: TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer); + void OnShutdown() override; + protected: - virtual void OnFirstDisplay(); + void OnFirstDisplay() override; private: void OnPassabilityChoice(wxCommandEvent& evt); diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PickWaterHeight.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PickWaterHeight.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PickWaterHeight.cpp 2021-07-27 21:56:47.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PickWaterHeight.cpp 2022-09-23 19:16:46.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,13 +29,8 @@ { DECLARE_DYNAMIC_CLASS(PickWaterHeight); - // Uses a workaround to notify the environment settings directly, because - // we don't have any way to update them on the engine state change. - EnvironmentSidebar* m_Sidebar; - public: PickWaterHeight() - : m_Sidebar(nullptr) { SetState(&Waiting); } @@ -45,22 +40,20 @@ StateDrivenTool::Init(initData, scenarioEditor); wxASSERT(initData); - m_Sidebar = static_cast(initData); - } - - void OnDisable() - { - if (m_Sidebar) - m_Sidebar->UpdateEnvironmentSettings(); + Waiting.m_Sidebar = static_cast(initData); } struct sWaiting : public State { + // Uses a workaround to notify the environment settings directly, because + // we don't have any way to update them on the engine state change. + EnvironmentSidebar* m_Sidebar = nullptr; bool OnMouse(PickWaterHeight* WXUNUSED(obj), wxMouseEvent& evt) { - if (evt.LeftDown()) + if (evt.LeftDown() && m_Sidebar) { POST_COMMAND(PickWaterHeight, (evt.GetPosition())); + m_Sidebar->UpdateEnvironmentSettings(); return true; } return false; diff -Nru 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp --- 0ad-0.0.25b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp 2021-07-27 21:56:47.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,6 +24,9 @@ #include "Common/ObjectSettings.h" #include "GameInterface/Messages.h" +#include +#include + using AtlasMessage::Position; static float g_DefaultAngle = (float)(M_PI*3.0/4.0); @@ -145,7 +148,9 @@ void RandomizeActorSeed() { - m_ActorSeed = (unsigned int)floor((rand() / (float)RAND_MAX) * 65535.f); + std::mt19937 engine(std::time(nullptr)); + std::uniform_int_distribution distribution(0, 65535); + m_ActorSeed = distribution(engine); } struct sWaiting : public State diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/ActorViewer.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/ActorViewer.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/ActorViewer.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/ActorViewer.cpp 2022-09-23 19:16:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include "View.h" +#include "graphics/Canvas2D.h" #include "graphics/ColladaManager.h" #include "graphics/LOSTexture.h" #include "graphics/MiniMapTexture.h" @@ -45,6 +46,7 @@ #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/Scene.h" +#include "renderer/SceneRenderer.h" #include "renderer/SkyManager.h" #include "renderer/WaterManager.h" #include "scriptinterface/ScriptContext.h" @@ -97,8 +99,6 @@ bool AxesMarkerEnabled; int PropPointsMode; // 0 disabled, 1 for point markers, 2 for point markers + axes - SColor4ub Background; - CTerrain Terrain; CColladaManager ColladaManager; @@ -267,7 +267,6 @@ m.SelectionBoxEnabled = false; m.AxesMarkerEnabled = false; m.PropPointsMode = 0; - m.Background = SColor4ub(0, 0, 0, 255); // Create a tiny empty piece of terrain, just so we can put shadows // on it without having to think too hard @@ -356,7 +355,7 @@ } // Clear particles associated with deleted entity - g_Renderer.GetParticleManager().ClearUnattachedEmitters(); + g_Renderer.GetSceneRenderer().GetParticleManager().ClearUnattachedEmitters(); // If there's no actor to display, return with nothing loaded if (id.empty()) @@ -448,27 +447,21 @@ m.OldShadows = g_RenderingOptions.GetShadows(); SetShadowsEnabled(m.ShadowsEnabled); - m.OldSky = g_Renderer.GetSkyManager()->GetRenderSky(); - g_Renderer.GetSkyManager()->SetRenderSky(false); + m.OldSky = g_Renderer.GetSceneRenderer().GetSkyManager().IsSkyVisible(); + g_Renderer.GetSceneRenderer().GetSkyManager().SetSkyVisible(false); - m.OldWater = g_Renderer.GetWaterManager()->m_RenderWater; - g_Renderer.GetWaterManager()->m_RenderWater = m.WaterEnabled; + m.OldWater = g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater; + g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater = m.WaterEnabled; } else { // Restore the old renderer state SetShadowsEnabled(m.OldShadows); - g_Renderer.GetSkyManager()->SetRenderSky(m.OldSky); - g_Renderer.GetWaterManager()->m_RenderWater = m.OldWater; + g_Renderer.GetSceneRenderer().GetSkyManager().SetSkyVisible(m.OldSky); + g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater = m.OldWater; } } -void ActorViewer::SetBackgroundColor(const SColor4ub& color) -{ - m.Background = color; - m.Terrain.SetBaseColor(color); -} - void ActorViewer::SetWalkEnabled(bool enabled) { m.WalkEnabled = enabled; } void ActorViewer::SetGroundEnabled(bool enabled) { m.GroundEnabled = enabled; } void ActorViewer::SetWaterEnabled(bool enabled) @@ -484,6 +477,10 @@ g_RenderingOptions.SetShadows(enabled); m.ShadowsEnabled = enabled; } +void ActorViewer::ToggleShadows() +{ + SetShadowsEnabled(!m.ShadowsEnabled); +} void ActorViewer::SetBoundingBoxesEnabled(bool enabled) { m.SelectionBoxEnabled = enabled; } void ActorViewer::SetAxesMarkerEnabled(bool enabled) { m.AxesMarkerEnabled = enabled; } void ActorViewer::SetPropPointsMode(int mode) { m.PropPointsMode = mode; } @@ -507,14 +504,10 @@ void ActorViewer::Render() { - m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR); - - g_Renderer.SetClearColor(m.Background); + // TODO: ActorViewer should reuse CRenderer code and not duplicate it. // Set simulation context for rendering purposes - g_Renderer.SetSimulation(&m.Simulation2); - - g_Renderer.BeginFrame(); + g_Renderer.GetSceneRenderer().SetSimulation(&m.Simulation2); // Find the centre of the interesting region, in the middle of the patch // and half way up the model (assuming there is one) @@ -530,18 +523,19 @@ camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z); camera.UpdateFrustum(); - g_Renderer.SetSceneCamera(camera, camera); + g_Renderer.GetSceneRenderer().SetSceneCamera(camera, camera); - g_Renderer.RenderScene(m); + g_Renderer.BeginFrame(); - glDisable(GL_DEPTH_TEST); - g_Logger->Render(); - g_ProfileViewer.RenderProfile(); - glEnable(GL_DEPTH_TEST); + g_Renderer.GetSceneRenderer().RenderScene(g_Renderer.GetDeviceCommandContext(), m); - g_Renderer.EndFrame(); + { + CCanvas2D canvas(g_Renderer.GetDeviceCommandContext()); + g_Logger->Render(canvas); + g_ProfileViewer.RenderProfile(canvas); + } - ogl_WarnIfError(); + g_Renderer.EndFrame(); } void ActorViewer::Update(float simFrameLength, float realFrameLength) diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/ActorViewer.h 0ad-0.0.26/source/tools/atlas/GameInterface/ActorViewer.h --- 0ad-0.0.25b/source/tools/atlas/GameInterface/ActorViewer.h 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/ActorViewer.h 2022-09-23 19:16:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,14 +18,13 @@ #ifndef INCLUDED_ACTORVIEWER #define INCLUDED_ACTORVIEWER +#include "ps/CStrForward.h" #include "simulation2/helpers/Player.h" #include "simulation2/system/Entity.h" struct ActorViewerImpl; struct SColor4ub; class CSimulation2; -class CStr8; -class CStrW; class ActorViewer { @@ -39,11 +38,11 @@ void SetActor(const CStrW& id, const CStr8& animation, player_id_t playerID); void SetEnabled(bool enabled); void UnloadObjects(); - void SetBackgroundColor(const SColor4ub& color); void SetWalkEnabled(bool enabled); void SetGroundEnabled(bool enabled); void SetWaterEnabled(bool enabled); void SetShadowsEnabled(bool enabled); + void ToggleShadows(); void SetStatsEnabled(bool enabled); void SetBoundingBoxesEnabled(bool enabled); void SetAxesMarkerEnabled(bool enabled); diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Brushes.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Brushes.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Brushes.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Brushes.cpp 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ #include "graphics/Color.h" #include "graphics/Terrain.h" -#include "lib/ogl.h" #include "maths/MathUtil.h" #include "ps/Game.h" #include "ps/World.h" @@ -29,6 +28,8 @@ #include "simulation2/Simulation2.h" #include "simulation2/system/SimContext.h" +#include + using namespace AtlasMessage; class BrushTerrainOverlay : public TerrainOverlay @@ -52,7 +53,9 @@ --max_j_inclusive; } - void ProcessTile(ssize_t i, ssize_t j) + void ProcessTile( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + ssize_t i, ssize_t j) { ssize_t i0, j0; m_Brush->GetBottomLeft(i0, j0); @@ -61,9 +64,9 @@ m_Brush->Get(i-i0, j-j0) + m_Brush->Get(i-i0+1, j-j0) + m_Brush->Get(i-i0, j-j0+1) + m_Brush->Get(i-i0+1, j-j0+1) ) / 4.f; - RenderTile(CColor(0, 1, 0, avg*0.8f), false); + RenderTile(deviceCommandContext, CColor(0, 1, 0, avg*0.8f), false); if (avg > 0.1f) - RenderTileOutline(CColor(1, 1, 1, std::min(0.4f, avg-0.1f)), 1, true); + RenderTileOutline(deviceCommandContext, CColor(1, 1, 1, std::min(0.4f, avg-0.1f)), true); } const AtlasMessage::Brush* m_Brush; diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Brushes.h 0ad-0.0.26/source/tools/atlas/GameInterface/Brushes.h --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Brushes.h 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Brushes.h 2022-08-21 12:45:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,10 +24,12 @@ class TerrainOverlay; -namespace AtlasMessage { +namespace AtlasMessage +{ -struct Brush +class Brush { +public: Brush(); ~Brush(); @@ -56,6 +58,6 @@ extern Brush g_CurrentBrush; -} +} // namespace AtlasMessage #endif // INCLUDED_BRUSHES diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/GameLoop.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/GameLoop.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/GameLoop.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/GameLoop.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -126,10 +126,6 @@ RegisterHandlers(); - // Disable the game's cursor rendering - extern CStrW g_CursorName; - g_CursorName = L""; - state.args = args; state.running = true; state.view = AtlasView::GetView_None(); diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,12 +32,12 @@ #include "maths/Quaternion.h" #include "maths/Vector2D.h" #include "maths/Vector3D.h" -#include "lib/res/graphics/ogl_tex.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpCinemaManager.h" -namespace AtlasMessage { +namespace AtlasMessage +{ const float MINIMAL_SCREEN_DISTANCE = 5.f; @@ -541,4 +541,4 @@ g_AtlasGameLoop->view->SetParam(L"movetool", false); } -} +} // namespace AtlasMessage diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,12 +21,13 @@ #include "../CommandProc.h" +#include "graphics/RenderableObject.h" #include "graphics/Terrain.h" +#include "graphics/UnitManager.h" #include "ps/CStr.h" #include "ps/Game.h" #include "ps/World.h" #include "maths/MathUtil.h" -#include "graphics/RenderableObject.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpTerrain.h" @@ -111,6 +112,7 @@ void MakeDirty() { g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); + g_Game->GetWorld()->GetUnitManager().MakeTerrainDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); CmpPtr cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); if (cmpTerrain) cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1); @@ -193,6 +195,7 @@ void MakeDirty() { g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); + g_Game->GetWorld()->GetUnitManager().MakeTerrainDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); CmpPtr cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); if (cmpTerrain) cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1); @@ -305,6 +308,7 @@ void MakeDirty() { g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); + g_Game->GetWorld()->GetUnitManager().MakeTerrainDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); CmpPtr cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); if (cmpTerrain) cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1); @@ -379,6 +383,7 @@ void MakeDirty() { g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); + g_Game->GetWorld()->GetUnitManager().MakeTerrainDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES); CmpPtr cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); if (cmpTerrain) cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1); diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,6 +29,7 @@ #include "ps/World.h" #include "renderer/PostprocManager.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/SkyManager.h" #include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" @@ -45,16 +46,16 @@ s.waterheight = cmpWaterManager->GetExactWaterLevel(0, 0) / (65536.f * HEIGHT_SCALE); - WaterManager* wm = g_Renderer.GetWaterManager(); - s.watertype = wm->m_WaterType; - s.waterwaviness = wm->m_Waviness; - s.watermurkiness = wm->m_Murkiness; - s.windangle = wm->m_WindAngle; + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); + s.watertype = waterManager.m_WaterType; + s.waterwaviness = waterManager.m_Waviness; + s.watermurkiness = waterManager.m_Murkiness; + s.windangle = waterManager.m_WindAngle; // CColor colors #define COLOR(A, B) A = Color((int)(B.r*255), (int)(B.g*255), (int)(B.b*255)) - COLOR(s.watercolor, wm->m_WaterColor); - COLOR(s.watertint, wm->m_WaterTint); + COLOR(s.watercolor, waterManager.m_WaterColor); + COLOR(s.watertint, waterManager.m_WaterTint); #undef COLOR float sunrotation = g_LightEnv.GetRotation(); @@ -65,7 +66,7 @@ s.posteffect = g_Renderer.GetPostprocManager().GetPostEffect(); - s.skyset = g_Renderer.GetSkyManager()->GetSkySet(); + s.skyset = g_Renderer.GetSceneRenderer().GetSkyManager().GetSkySet(); s.fogfactor = g_LightEnv.m_FogFactor; s.fogmax = g_LightEnv.m_FogMax; @@ -99,19 +100,19 @@ cmpWaterManager->SetWaterLevel(entity_pos_t::FromFloat(s.waterheight * (65536.f * HEIGHT_SCALE))); - WaterManager* wm = g_Renderer.GetWaterManager(); - wm->m_Waviness = s.waterwaviness; - wm->m_Murkiness = s.watermurkiness; - wm->m_WindAngle = s.windangle; - if (wm->m_WaterType != *s.watertype) + WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); + waterManager.m_Waviness = s.waterwaviness; + waterManager.m_Murkiness = s.watermurkiness; + waterManager.m_WindAngle = s.windangle; + if (waterManager.m_WaterType != *s.watertype) { - wm->m_WaterType = *s.watertype; - wm->ReloadWaterNormalTextures(); + waterManager.m_WaterType = *s.watertype; + waterManager.ReloadWaterNormalTextures(); } #define COLOR(A, B) B = CColor(A->r/255.f, A->g/255.f, A->b/255.f, 1.f) - COLOR(s.watercolor, wm->m_WaterColor); - COLOR(s.watertint, wm->m_WaterTint); + COLOR(s.watercolor, waterManager.m_WaterColor); + COLOR(s.watertint, waterManager.m_WaterTint); #undef COLOR g_LightEnv.SetRotation(s.sunrotation); @@ -125,7 +126,7 @@ CStrW skySet = *s.skyset; if (skySet.length() == 0) skySet = L"default"; - g_Renderer.GetSkyManager()->SetSkySet(skySet); + g_Renderer.GetSceneRenderer().GetSkyManager().SetSkySet(skySet); g_LightEnv.m_FogFactor = s.fogfactor; g_LightEnv.m_FogMax = s.fogmax; @@ -241,7 +242,7 @@ QUERYHANDLER(GetSkySets) { - std::vector skies = g_Renderer.GetSkyManager()->GetSkySets(); + std::vector skies = g_Renderer.GetSceneRenderer().GetSkyManager().GetSkySets(); msg->skysets = std::vector(skies.begin(), skies.end()); } diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp 2022-09-23 19:16:45.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,10 +28,10 @@ #include "graphics/ObjectManager.h" #include "gui/GUIManager.h" #include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" #include "lib/timer.h" #include "maths/MathUtil.h" #include "ps/CConsole.h" +#include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/Profile.h" #include "ps/Profiler2.h" @@ -40,6 +40,7 @@ #include "ps/GameSetup/Config.h" #include "ps/GameSetup/GameSetup.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #if OS_WIN // We don't include wutil header directly to prevent including Windows headers. @@ -56,7 +57,7 @@ double last_user_activity; // see comment in GameLoop.cpp about ah_display_error before using INIT_HAVE_DISPLAY_ERROR -const int g_InitFlags = INIT_HAVE_VMODE|INIT_NO_GUI; +const int g_InitFlags = INIT_HAVE_VMODE | INIT_NO_GUI; MESSAGEHANDLER(Init) { @@ -65,7 +66,7 @@ g_Quickstart = true; // Mount mods if there are any specified as command line parameters - if (!Init(g_AtlasGameLoop->args, g_InitFlags | INIT_MODS|INIT_MODS_PUBLIC)) + if (!Init(g_AtlasGameLoop->args, g_InitFlags | INIT_MODS| INIT_MODS_PUBLIC)) { // There are no mods specified on the command line, // but there are in the config file, so mount those. @@ -97,30 +98,27 @@ // When running in Atlas, we skip the SDL video initialisation code // which loads the library, and so SDL_GL_GetProcAddress fails (in // ogl.cpp importExtensionFunctions). - // (TODO: I think this is meant to be context-independent, i.e. it - // doesn't matter that we're getting extensions from SDL-initialised - // GL stuff instead of from the wxWidgets-initialised GL stuff, but that - // should be checked.) // So, make sure it's loaded: SDL_InitSubSystem(SDL_INIT_VIDEO); - SDL_GL_LoadLibrary(NULL); // NULL = use default - // (it shouldn't hurt if this is called multiple times, I think) + // wxWidgets doesn't use a proper approach to dynamically load functions and + // doesn't provide GetProcAddr-like function. Technically we need to call + // SDL_GL_LoadLibrary inside GL device creation, but that might lead to a + // crash on Windows because of a wrong order of initialization between SDL + // and wxWidgets context management. So leave the call as is while it works. + // Refs: + // http://trac.wxwidgets.org/ticket/9213 + // http://trac.wxwidgets.org/ticket/9215 + if (SDL_GL_LoadLibrary(nullptr) && g_Logger) + LOGERROR("SDL failed to load GL library: '%s'", SDL_GetError()); } MESSAGEHANDLER(InitGraphics) { UNUSED2(msg); - ogl_Init(); + g_VideoMode.CreateBackendDevice(false); InitGraphics(g_AtlasGameLoop->args, g_InitFlags, {}); - -#if OS_WIN - // HACK (to stop things looking very ugly when scrolling) - should - // use proper config system. - if(ogl_HaveExtension("WGL_EXT_swap_control")) - pwglSwapIntervalEXT(1); -#endif } @@ -263,10 +261,10 @@ MESSAGEHANDLER(RenderStyle) { - 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); + g_Renderer.GetSceneRenderer().SetTerrainRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetWaterRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetModelRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetOverlayRenderMode(msg->wireframe ? EDGED_FACES : SOLID); } } // namespace AtlasMessage diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -42,6 +42,7 @@ #include "ps/Loader.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "scriptinterface/Object.h" #include "scriptinterface/JSON.h" @@ -225,7 +226,7 @@ VfsPath pathname = VfsPath(*msg->filename).ChangeExtension(L".pmp"); writer.SaveMap(pathname, g_Game->GetWorld()->GetTerrain(), - g_Renderer.GetWaterManager(), g_Renderer.GetSkyManager(), + &g_Renderer.GetSceneRenderer().GetWaterManager(), &g_Renderer.GetSceneRenderer().GetSkyManager(), &g_LightEnv, g_Game->GetView()->GetCamera(), g_Game->GetView()->GetCinema(), &g_Renderer.GetPostprocManager(), g_Game->GetSimulation2()); @@ -297,7 +298,7 @@ ssize_t w = dimension; ssize_t h = dimension; - float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight; + const float waterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight; for (ssize_t j = 0; j < h; ++j) { diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,16 +22,12 @@ #include "../GameLoop.h" #include "../View.h" -#include "graphics/CinemaManager.h" #include "graphics/GameView.h" #include "gui/GUIManager.h" #include "gui/CGUI.h" #include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" -#include "lib/sysdep/cpu.h" #include "maths/MathUtil.h" #include "ps/Game.h" -#include "ps/Util.h" #include "ps/GameSetup/Config.h" #include "ps/GameSetup/GameSetup.h" #include "renderer/Renderer.h" @@ -41,7 +37,8 @@ extern void (*Atlas_GLSwapBuffers)(void* context); -namespace AtlasMessage { +namespace AtlasMessage +{ MESSAGEHANDLER(MessageTrace) { @@ -51,72 +48,9 @@ MESSAGEHANDLER(Screenshot) { if (msg->big) - WriteBigScreenshot(L".bmp", msg->tiles); + g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::BIG); else - WriteScreenshot(L".png"); -} - -QUERYHANDLER(CinemaRecord) -{ - const int w = msg->width, h = msg->height; - - { - g_Renderer.Resize(w, h); - SViewPort vp = { 0, 0, w, h }; - g_Game->GetView()->SetViewport(vp); - } - - unsigned char* img = new unsigned char [w*h*3]; - unsigned char* temp = new unsigned char[w*3]; - - int num_frames = msg->framerate * msg->duration; - - AtlasView::GetView_Game()->SaveState(L"cinema_record"); - - // Set it to update the simulation at normal speed - AtlasView::GetView_Game()->SetSpeedMultiplier(1.f); - - for (int frame = 0; frame < num_frames; ++frame) - { - AtlasView::GetView_Game()->Update(1.f / msg->framerate); - - Render(); - Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas); - - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, img); - - // Swap the rows around, else the image will be upside down -//* // TODO: BGR24 output doesn't need flipping, YUV420 and RGBA32 do - for (int y = 0; y < h/2; ++y) - { - memcpy(temp, &img[y*w*3], w*3); - memcpy(&img[y*w*3], &img[(h-1-y)*w*3], w*3); - memcpy(&img[(h-1-y)*w*3], temp, w*3); - } -//*/ - - // Call the user-supplied function with this data, so they can - // store it as a video - sCinemaRecordCB cbdata = { img }; - msg->cb.Call(cbdata); - } - - // Pause the game once we've finished - AtlasView::GetView_Game()->SetSpeedMultiplier(0.f); - - AtlasView::GetView_Game()->RestoreState(L"cinema_record"); - // TODO: delete the saved state now that we don't need it any more - - delete[] img; - delete[] temp; - - // Restore viewport - { - g_Renderer.Resize(g_xres, g_yres); - SViewPort vp = { 0, 0, g_xres, g_yres }; - g_Game->GetView()->SetViewport(vp); - } - + g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::DEFAULT); } QUERYHANDLER(Ping) @@ -217,4 +151,4 @@ in_dispatch_event(&ev); } -} +} // namespace AtlasMessage diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,7 +32,6 @@ #include "graphics/ObjectManager.h" #include "graphics/Terrain.h" #include "graphics/Unit.h" -#include "lib/ogl.h" #include "lib/utf8.h" #include "maths/MathUtil.h" #include "maths/Matrix3D.h" @@ -53,7 +52,8 @@ #include "simulation2/helpers/Selection.h" #include "ps/XML/XMLWriter.h" -namespace AtlasMessage { +namespace AtlasMessage +{ namespace { @@ -61,7 +61,7 @@ { return wcscmp(a.name.c_str(), b.name.c_str()) < 0; } -} +} // anonymous namespace // Helpers for object constraints bool CheckEntityObstruction(entity_id_t ent) @@ -1128,4 +1128,5 @@ std::sort(names.begin(), names.end()); msg->names = names; } -} + +} // namespace AtlasMessage diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/PlayerHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/PlayerHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/PlayerHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/PlayerHandlers.cpp 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,13 +21,14 @@ #include "ps/Game.h" #include "simulation2/Simulation2.h" - +#include "simulation2/components/ICmpTemplateManager.h" namespace AtlasMessage { QUERYHANDLER(GetCivData) { - msg->data = g_Game->GetSimulation2()->GetCivData(); + CmpPtr cmpTemplateManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); + msg->data = cmpTemplateManager->GetCivData(); } QUERYHANDLER(GetPlayerDefaults) diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,10 +25,11 @@ #include "graphics/TerrainTextureManager.h" #include "graphics/TerrainTextureEntry.h" #include "graphics/Terrain.h" +#include "graphics/TextureManager.h" #include "ps/Game.h" #include "ps/World.h" -#include "lib/ogl.h" -#include "lib/res/graphics/ogl_tex.h" +#include "lib/tex/tex.h" +#include "ps/Filesystem.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpPathfinder.h" #include "simulation2/components/ICmpTerrain.h" @@ -40,83 +41,122 @@ #include -namespace AtlasMessage { +namespace AtlasMessage +{ -QUERYHANDLER(GetTerrainGroups) +namespace { - const CTerrainTextureManager::TerrainGroupMap &groups = g_TexMan.GetGroups(); - std::vector groupNames; - for (CTerrainTextureManager::TerrainGroupMap::const_iterator it = groups.begin(); it != groups.end(); ++it) - groupNames.push_back(it->first.FromUTF8()); - msg->groupNames = groupNames; + +sTerrainTexturePreview MakeEmptyTerrainTexturePreview() +{ + sTerrainTexturePreview preview{}; + preview.name = std::wstring(); + preview.loaded = false; + preview.imageHeight = 0; + preview.imageWidth = 0; + preview.imageData = {}; + return preview; } -static bool CompareTerrain(const sTerrainTexturePreview& a, const sTerrainTexturePreview& b) +bool CompareTerrain(const sTerrainTexturePreview& a, const sTerrainTexturePreview& b) { return (wcscmp(a.name.c_str(), b.name.c_str()) < 0); } -static sTerrainTexturePreview GetPreview(CTerrainTextureEntry* tex, int width, int height) +sTerrainTexturePreview GetPreview(CTerrainTextureEntry* tex, size_t width, size_t height) { sTerrainTexturePreview preview; preview.name = tex->GetTag().FromUTF8(); - std::vector buf (width*height*3); + const size_t previewBPP = 3; + std::vector buffer(width * height * previewBPP); -#if !CONFIG2_GLES // It's not good to shrink the entire texture to fit the small preview // window, since it's the fine details in the texture that are // interesting; so just go down one mipmap level, then crop a chunk // out of the middle. - // Read the size of the texture. (Usually loads the texture from - // disk, which is slow.) - tex->GetTexture()->Bind(); - int level = 1; // level 0 is the original size - int w = std::max(1, (int)tex->GetTexture()->GetWidth() >> level); - int h = std::max(1, (int)tex->GetTexture()->GetHeight() >> level); - - if (w >= width && h >= height) - { - // Read the whole texture into a new buffer - unsigned char* texdata = new unsigned char[w*h*3]; - glGetTexImage(GL_TEXTURE_2D, level, GL_RGB, GL_UNSIGNED_BYTE, texdata); - + std::shared_ptr fileData; + size_t fileSize; + Tex texture; + const bool canUsePreview = + !tex->GetDiffuseTexturePath().empty() && + g_VFS->LoadFile(tex->GetDiffuseTexturePath(), fileData, fileSize) == INFO::OK && + texture.decode(fileData, fileSize) == INFO::OK && + // Check that we can fit the texture into the preview size before any transform. + texture.m_Width >= width && texture.m_Height >= height && + // Transform to a single format that we can process. + texture.transform_to((texture.m_Flags | TEX_MIPMAPS) & ~(TEX_DXT | TEX_GREY | TEX_BGR)) == INFO::OK && + (texture.m_Bpp == 24 || texture.m_Bpp == 32); + if (canUsePreview) + { + size_t level = 0; + while ((texture.m_Width >> (level + 1)) >= width && (texture.m_Height >> (level + 1)) >= height && level < texture.GetMIPLevels().size()) + ++level; // Extract the middle section (as a representative preview), - // and copy into buf - unsigned char* texdata_ptr = texdata + (w*(h - height)/2 + (w - width)/2) * 3; - unsigned char* buf_ptr = &buf[0]; - for (ssize_t y = 0; y < height; ++y) - { - memcpy(buf_ptr, texdata_ptr, width*3); - buf_ptr += width*3; - texdata_ptr += w*3; - } - - delete[] texdata; + // and copy into buffer. + u8* data = texture.GetMIPLevels()[level].data; + ENSURE(data); + const size_t levelWidth = texture.m_Width >> level; + const size_t levelHeight = texture.m_Height >> level; + const size_t dataShiftX = (levelWidth - width) / 2; + const size_t dataShiftY = (levelHeight - height) / 2; + for (size_t y = 0; y < height; ++y) + for (size_t x = 0; x < width; ++x) + { + const size_t bufferOffset = (y * width + x) * previewBPP; + const size_t dataOffset = ((y + dataShiftY) * levelWidth + x + dataShiftX) * texture.m_Bpp / 8; + buffer[bufferOffset + 0] = data[dataOffset + 0]; + buffer[bufferOffset + 1] = data[dataOffset + 1]; + buffer[bufferOffset + 2] = data[dataOffset + 2]; + } + preview.loaded = true; } else -#endif { - // Too small to preview, or glGetTexImage not supported (on GLES) - // Just use a flat color instead - u32 c = tex->GetBaseColor(); - for (ssize_t i = 0; i < width*height; ++i) - { - buf[i*3+0] = (c>>16) & 0xff; - buf[i*3+1] = (c>>8) & 0xff; - buf[i*3+2] = (c>>0) & 0xff; + // Too small to preview. Just use a flat color instead. + const u32 baseColor = tex->GetBaseColor(); + for (size_t i = 0; i < width * height; ++i) + { + buffer[i * previewBPP + 0] = (baseColor >> 16) & 0xff; + buffer[i * previewBPP + 1] = (baseColor >> 8) & 0xff; + buffer[i * previewBPP + 2] = (baseColor >> 0) & 0xff; } + preview.loaded = tex->GetTexture()->IsLoaded(); } - preview.loaded = tex->GetTexture()->IsLoaded(); preview.imageWidth = width; preview.imageHeight = height; - preview.imageData = buf; + preview.imageData = buffer; return preview; } +} // anonymous namespace + +QUERYHANDLER(GetTerrainGroups) +{ + const CTerrainTextureManager::TerrainGroupMap &groups = g_TexMan.GetGroups(); + std::vector groupNames; + for (CTerrainTextureManager::TerrainGroupMap::const_iterator it = groups.begin(); it != groups.end(); ++it) + groupNames.push_back(it->first.FromUTF8()); + msg->groupNames = groupNames; +} + +QUERYHANDLER(GetTerrainGroupTextures) +{ + std::vector names; + + CTerrainGroup* group = g_TexMan.FindGroup(CStrW(*msg->groupName).ToUTF8()); + if (group) + { + for (std::vector::const_iterator it = group->GetTerrains().begin(); it != group->GetTerrains().end(); ++it) + names.emplace_back((*it)->GetTag().FromUTF8()); + } + std::sort(names.begin(), names.end()); + msg->names = names; +} + QUERYHANDLER(GetTerrainGroupPreviews) { std::vector previews; @@ -170,23 +210,15 @@ { CTerrainTextureEntry* tex = g_TexMan.FindTexture(CStrW(*msg->name).ToUTF8()); if (tex) - { msg->preview = GetPreview(tex, msg->imageWidth, msg->imageHeight); - } else - { - sTerrainTexturePreview noPreview{}; - noPreview.name = std::wstring(); - noPreview.loaded = false; - noPreview.imageHeight = 0; - noPreview.imageWidth = 0; - msg->preview = noPreview; - } + msg->preview = MakeEmptyTerrainTexturePreview(); } ////////////////////////////////////////////////////////////////////////// -namespace { +namespace +{ struct TerrainTile { @@ -368,9 +400,6 @@ void MakeDirty() { g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_INDICES); - CmpPtr cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); - if (cmpTerrain) - cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1); } void Do() @@ -447,9 +476,6 @@ void MakeDirty() { g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_INDICES); - CmpPtr cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); - if (cmpTerrain) - cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1); } void Do() @@ -546,4 +572,4 @@ }; END_COMMAND(FillTerrain) -} +} // namespace AtlasMessage diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/Messages.h 0ad-0.0.26/source/tools/atlas/GameInterface/Messages.h --- 0ad-0.0.25b/source/tools/atlas/GameInterface/Messages.h 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/Messages.h 2022-09-23 19:16:45.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -243,7 +243,7 @@ QUERY(GetCivData, , - ((std::vector, data)) + ((std::vector>, data)) ); QUERY(GetVictoryConditionData, @@ -273,27 +273,8 @@ MESSAGE(Screenshot, ((bool, big)) - ((int, tiles)) // For big screenshots: the final image will be (640*tiles)x(480*tiles) ); -#ifndef MESSAGES_SKIP_STRUCTS -struct sCinemaRecordCB -{ - unsigned char* buffer; -}; -SHAREABLE_STRUCT(sCinemaRecordCB); -#endif - -QUERY(CinemaRecord, - ((std::wstring, path)) - ((int, framerate)) - ((float, duration)) - ((int, width)) - ((int, height)) - ((Callback, cb)) - , - ); - ////////////////////////////////////////////////////////////////////////// MESSAGE(Brush, @@ -315,6 +296,11 @@ ((std::vector, groupNames)) ); +QUERY(GetTerrainGroupTextures, + ((std::wstring, groupName)), + ((std::vector, names)) + ); + #ifndef MESSAGES_SKIP_STRUCTS struct sTerrainTexturePreview { @@ -322,7 +308,7 @@ Shareable loaded; Shareable imageWidth; Shareable imageHeight; - Shareable > imageData; // RGB*width*height + Shareable> imageData; // RGB*width*height }; SHAREABLE_STRUCT(sTerrainTexturePreview); #endif diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/View.cpp 0ad-0.0.26/source/tools/atlas/GameInterface/View.cpp --- 0ad-0.0.25b/source/tools/atlas/GameInterface/View.cpp 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/View.cpp 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,23 +24,26 @@ #include "Messages.h" #include "SimState.h" +#include "graphics/Canvas2D.h" #include "graphics/CinemaManager.h" #include "graphics/GameView.h" #include "graphics/ParticleManager.h" -#include "graphics/SColor.h" #include "graphics/UnitManager.h" #include "lib/timer.h" #include "lib/utf8.h" #include "maths/MathUtil.h" #include "ps/Game.h" #include "ps/GameSetup/GameSetup.h" +#include "ps/VideoMode.h" #include "ps/World.h" +#include "renderer/backend/IDevice.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" -#include "simulation2/Simulation2.h" +#include "renderer/SceneRenderer.h" #include "simulation2/components/ICmpObstructionManager.h" #include "simulation2/components/ICmpParticleManager.h" #include "simulation2/components/ICmpPathfinder.h" +#include "simulation2/Simulation2.h" #include "soundmanager/ISoundManager.h" extern void (*Atlas_GLSwapBuffers)(void* context); @@ -135,7 +138,7 @@ void AtlasViewActor::SetParam(const std::wstring& name, bool value) { if (name == L"wireframe") - g_Renderer.SetModelRenderMode(value ? WIREFRAME : SOLID); + g_Renderer.GetSceneRenderer().SetModelRenderMode(value ? WIREFRAME : SOLID); else if (name == L"walk") m_ActorViewer->SetWalkEnabled(value); else if (name == L"ground") @@ -146,7 +149,7 @@ //else if (name == L"water") //m_ActorViewer->SetWaterEnabled(value); else if (name == L"shadows") - m_ActorViewer->SetShadowsEnabled(value); + m_ActorViewer->ToggleShadows(); else if (name == L"stats") m_ActorViewer->SetStatsEnabled(value); else if (name == L"bounding_box") @@ -161,12 +164,8 @@ m_ActorViewer->SetPropPointsMode(value); } -void AtlasViewActor::SetParam(const std::wstring& name, const AtlasMessage::Color& value) +void AtlasViewActor::SetParam(const std::wstring& UNUSED(name), const AtlasMessage::Color& UNUSED(value)) { - if (name == L"background") - { - m_ActorViewer->SetBackgroundColor(SColor4ub(value.r, value.g, value.b, 255)); - } } @@ -230,9 +229,11 @@ camera.SetProjectionFromCamera(*g_Game->GetView()->GetCamera()); camera.UpdateFrustum(); - ::Render(); + g_Renderer.RenderFrame(false); Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas); - g_Renderer.OnSwapBuffers(); + // In case of atlas the device's present will do only internal stuff + // without calling a real backbuffer swap. + g_VideoMode.GetBackendDevice()->Present(); } void AtlasViewGame::DrawCinemaPathTool() @@ -246,64 +247,47 @@ const float axisLength = scale / 10.0f; const float lineWidth = scale / 1e3f; - glDisable(GL_DEPTH_TEST); - g_Renderer.GetDebugRenderer().DrawLine(focus, focus + CVector3D(axisLength, 0, 0), CColor(1.0f, 0.0f, 0.0f, 1.0f), lineWidth); - g_Renderer.GetDebugRenderer().DrawLine(focus, focus + CVector3D(0, axisLength, 0), CColor(0.0f, 1.0f, 0.0f, 1.0f), lineWidth); - g_Renderer.GetDebugRenderer().DrawLine(focus, focus + CVector3D(0, 0, axisLength), CColor(0.0f, 0.0f, 1.0f, 1.0f), lineWidth); - glEnable(GL_DEPTH_TEST); + g_Renderer.GetDebugRenderer().DrawLine( + focus, focus + CVector3D(axisLength, 0, 0), + CColor(1.0f, 0.0f, 0.0f, 1.0f), lineWidth, false); + g_Renderer.GetDebugRenderer().DrawLine( + focus, focus + CVector3D(0, axisLength, 0), + CColor(0.0f, 1.0f, 0.0f, 1.0f), lineWidth, false); + g_Renderer.GetDebugRenderer().DrawLine( + focus, focus + CVector3D(0, 0, axisLength), + CColor(0.0f, 0.0f, 1.0f, 1.0f), lineWidth, false); } -void AtlasViewGame::DrawOverlays() -{ -#if CONFIG2_GLES -#warning TODO: implement Atlas game overlays for GLES -#else - if (m_BandboxArray.empty()) +void AtlasViewGame::DrawOverlays(CCanvas2D& canvas) +{ + if (m_Bandbox.left >= m_Bandbox.right || m_Bandbox.top >= m_Bandbox.bottom) return; - // Set up transform for overlays - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - CMatrix3D transform; - transform.SetIdentity(); - transform.Scale(1.0f, -1.f, 1.0f); - transform.Translate(0.0f, (float)g_yres, -1000.0f); - CMatrix3D proj; - proj.SetOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f); - transform = proj * transform; - glLoadMatrixf(&transform._11); - - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - - // Render bandbox as array of lines - glVertexPointer(2, GL_FLOAT, sizeof(SBandboxVertex), &m_BandboxArray[0].x); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SBandboxVertex), &m_BandboxArray[0].r); - - glDrawArrays(GL_LINES, 0, m_BandboxArray.size()); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -#endif + const std::vector outerPoints = { + m_Bandbox.TopLeft() + CVector2D(-1.0f, -1.0f), + m_Bandbox.TopRight() + CVector2D(1.0f, -1.0f), + m_Bandbox.BottomRight() + CVector2D(1.0f, 1.0f), + m_Bandbox.BottomLeft() + CVector2D(-1.0f, 1.0f), + m_Bandbox.TopLeft() + CVector2D(-1.0f, -1.0f) + }; + canvas.DrawLine(outerPoints, 1.5f, CColor(0.0f, 0.0f, 0.0f, 1.0f)); + + const std::vector innerPoints = { + m_Bandbox.TopLeft(), + m_Bandbox.TopRight(), + m_Bandbox.BottomRight(), + m_Bandbox.BottomLeft(), + m_Bandbox.TopLeft() + }; + canvas.DrawLine(innerPoints, 1.5f, CColor(1.0f, 1.0f, 1.0f, 1.0f)); } void AtlasViewGame::SetParam(const std::wstring& name, bool value) { if (name == L"priorities") - g_Renderer.SetDisplayTerrainPriorities(value); + g_Renderer.GetSceneRenderer().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) @@ -331,10 +315,6 @@ cmpPathfinder->SetAtlasOverlay(false); } } - else if (name == L"renderpath") - { - g_RenderingOptions.SetRenderPath(RenderPathEnum::FromString(CStrW(value).ToUTF8())); - } } CCamera& AtlasViewGame::GetCamera() @@ -413,8 +393,6 @@ void AtlasViewGame::SetBandbox(bool visible, float x0, float y0, float x1, float y1) { - m_BandboxArray.clear(); - if (visible) { // Make sure corners are arranged in correct order @@ -423,24 +401,11 @@ if (y0 > y1) std::swap(y0, y1); - // Bandbox is draw as lines comprising two rectangles - SBandboxVertex vert[] = { - // Black - outer rectangle - SBandboxVertex(x0, y0, 0, 0, 0, 255), SBandboxVertex(x1, y0, 0, 0, 0, 255), SBandboxVertex(x1, y1, 0, 0, 0, 255), SBandboxVertex(x0, y1, 0, 0, 0, 255), - // White - inner rectangle - SBandboxVertex(x0+1.0f, y0+1.0f, 255, 255, 255, 255), SBandboxVertex(x1-1.0f, y0+1.0f, 255, 255, 255, 255), SBandboxVertex(x1-1.0f, y1-1.0f, 255, 255, 255, 255), SBandboxVertex(x0+1.0f, y1-1.0f, 255, 255, 255, 255) - }; - - for (size_t i = 0; i < 4; ++i) - { - m_BandboxArray.push_back(vert[i]); - m_BandboxArray.push_back(vert[(i+1)%4]); - } - for (size_t i = 0; i < 4; ++i) - { - m_BandboxArray.push_back(vert[i+4]); - m_BandboxArray.push_back(vert[(i+1)%4+4]); - } + m_Bandbox = CRect(x0, y0, x1, y1); + } + else + { + m_Bandbox = CRect{}; } } diff -Nru 0ad-0.0.25b/source/tools/atlas/GameInterface/View.h 0ad-0.0.26/source/tools/atlas/GameInterface/View.h --- 0ad-0.0.25b/source/tools/atlas/GameInterface/View.h 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/atlas/GameInterface/View.h 2022-08-21 12:45:27.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,10 +21,12 @@ #include #include "graphics/Camera.h" +#include "maths/Rect.h" #include "Messages.h" #include "simulation2/system/Entity.h" +class CCanvas2D; class CUnit; class CSimulation2; @@ -41,7 +43,7 @@ virtual void Update(float UNUSED(realFrameLength)) { }; virtual void Render() { }; virtual void DrawCinemaPathTool() { }; - virtual void DrawOverlays() { }; + virtual void DrawOverlays(CCanvas2D& UNUSED(canvas)) { }; virtual CCamera& GetCamera() = 0; virtual CSimulation2* GetSimulation2() { return NULL; } virtual entity_id_t GetEntityId(AtlasMessage::ObjectID obj) { return (entity_id_t)obj; } @@ -89,7 +91,7 @@ virtual void Update(float realFrameLength); virtual void Render(); virtual void DrawCinemaPathTool(); - virtual void DrawOverlays(); + virtual void DrawOverlays(CCanvas2D& canvas); virtual CCamera& GetCamera(); virtual CSimulation2* GetSimulation2(); virtual bool WantsHighFramerate(); @@ -111,14 +113,7 @@ std::map m_SavedStates; std::string m_DisplayPassability; - typedef struct SBandboxVertex - { - SBandboxVertex(float x, float y, u8 r, u8 g, u8 b, u8 a) : x(x), y(y), r(r), g(g), b(b), a(a) {} - u8 r, g, b, a; - float x, y; - } SBandboxVertex; - - std::vector m_BandboxArray; + CRect m_Bandbox; bool m_DrawMoveTool; CVector3D m_MoveTool; }; diff -Nru 0ad-0.0.25b/source/tools/dist/0ad.nsi 0ad-0.0.26/source/tools/dist/0ad.nsi --- 0ad-0.0.25b/source/tools/dist/0ad.nsi 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/dist/0ad.nsi 2022-09-23 19:16:43.000000000 +0000 @@ -85,7 +85,7 @@ ;-------------------------------- ;Languages -; Keep in sync with remove-incomplete-translations.sh +;Keep in sync with build-archives.sh. !insertmacro MUI_LANGUAGE "English" ; The first language is the default language !insertmacro MUI_LANGUAGE "Asturian" @@ -133,7 +133,7 @@ File /r "${CHECKOUTPATH}\binaries\system\*.txt" ; Copy logs for writable root - SetOutPath "$INSTDIR\binaries\logs" + SetOutPath "$INSTDIR\binaries" File /r "${CHECKOUTPATH}\binaries\logs" !ifdef ARCHIVE_PATH @@ -152,7 +152,7 @@ SetOutPath "$INSTDIR" CreateShortCut "$INSTDIR\0 A.D..lnk" "$INSTDIR\binaries\system\pyrogenesis.exe" "" CreateShortCut "$INSTDIR\Map editor.lnk" "$INSTDIR\binaries\system\pyrogenesis.exe" "-editor" "$INSTDIR\binaries\data\tools\atlas\icons\ScenarioEditor.ico" - WriteINIStr "$INSTDIR\Web site.url" "InternetShortcut" "URL" "http://play0ad.com/" + WriteINIStr "$INSTDIR\Web site.url" "InternetShortcut" "URL" "https://play0ad.com/" ;Store installation folder WriteRegStr SHCTX "Software\0 A.D." "" $INSTDIR @@ -170,7 +170,7 @@ WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "InstallLocation" "$\"$INSTDIR$\"" WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" - WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "URLInfoAbout" "http://play0ad.com" + WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "URLInfoAbout" "https://play0ad.com" WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "NoModify" 1 WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\0 A.D." "NoRepair" 1 @@ -184,7 +184,7 @@ SetOutPath "$INSTDIR" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Open logs folder.lnk" "$INSTDIR\OpenLogsFolder.bat" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe" - WriteINIStr "$SMPROGRAMS\$StartMenuFolder\Web site.url" "InternetShortcut" "URL" "http://play0ad.com/" + WriteINIStr "$SMPROGRAMS\$StartMenuFolder\Web site.url" "InternetShortcut" "URL" "https://play0ad.com/" !insertmacro MUI_STARTMENU_WRITE_END diff -Nru 0ad-0.0.25b/source/tools/dist/build-archives.sh 0ad-0.0.26/source/tools/dist/build-archives.sh --- 0ad-0.0.25b/source/tools/dist/build-archives.sh 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/dist/build-archives.sh 2022-08-21 12:45:26.000000000 +0000 @@ -16,7 +16,7 @@ # Included languages # CJK languages are excluded, as they are in mods. # Note: Needs to be edited manually at each release. -# Keep in sync with source/tools/i18n/creditTranslators.py and with the installer languages in 0ad.nsi +# Keep in sync with the installer languages in 0ad.nsi. LANGS=("ast" "ca" "cs" "de" "el" "en_GB" "es" "eu" "fi" "fr" "gd" "hu" "id" "it" "nl" "pl" "pt_BR" "ru" "sk" "sv" "tr" "uk") REGEX=$(printf "\|%s" "${LANGS[@]}") diff -Nru 0ad-0.0.25b/source/tools/dist/build-osx-executable.sh 0ad-0.0.26/source/tools/dist/build-osx-executable.sh --- 0ad-0.0.25b/source/tools/dist/build-osx-executable.sh 2021-08-25 12:40:06.000000000 +0000 +++ 0ad-0.0.26/source/tools/dist/build-osx-executable.sh 2022-09-23 19:16:43.000000000 +0000 @@ -2,8 +2,7 @@ # Build the Pyrogenesis executable, used to create the bundle and run the archiver. -# TODO: is there anything to do for ARM support? -export ARCH=${ARCH:="x86_64"} +export ARCH=${ARCH:=$(uname -m)} # Set mimimum required OS X version, SDK location and tools # Old SDKs can be found at https://github.com/phracker/MacOSX-SDKs diff -Nru 0ad-0.0.25b/source/tools/entity/checkrefs.pl 0ad-0.0.26/source/tools/entity/checkrefs.pl --- 0ad-0.0.25b/source/tools/entity/checkrefs.pl 2021-07-27 21:56:49.000000000 +0000 +++ 0ad-0.0.26/source/tools/entity/checkrefs.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,717 +0,0 @@ -use strict; -use warnings; -use Data::Dumper; -use File::Find; -use XML::Simple; -use JSON; -use Getopt::Long qw(GetOptions); - -use lib "."; -use Entity; - -GetOptions ( - '--check-unused' => \(my $checkUnused = 0), - '--check-map-xml' => \(my $checkMapXml = 0), - '--validate-templates' => \(my $validateTemplates = 0), - '--mod-to-check=s' => \(my $modToCheck = "public") -); - -my @files; -my @roots; -my @deps; - -# Force and checkMapXml if checkUnused is enabled to avoid false positives. -$checkMapXml |= $checkUnused; -my $vfsroot = '../../../binaries/data/mods'; -my $supportedTextureFormats = 'dds|png'; -my $mods = get_mod_dependencies_string($modToCheck); -my $mod_list_string = $modToCheck; -if ($mods ne "") -{ - $mod_list_string = $mod_list_string."|$mods"; -} -$mod_list_string = $mod_list_string."|mod"; -print("Checking $modToCheck\'s integrity. \n"); -print("The following mod(s) will be loaded: $mod_list_string. \n"); -my @mods_list = split(/\|/, "$mod_list_string"); - -sub get_mod_dependencies -{ - my ($mod) = @_; - my $modjson = parse_json_file_full_path("$vfsroot/$mod/mod.json"); - my $modjsondeps = $modjson->{'dependencies'}; - for my $dep (@{$modjsondeps}) - { - # 0ad's folder isn't named like the mod. - if(index($dep, "0ad") != -1) - { - $dep = "public"; - } - } - - return $modjsondeps; -} - -sub get_mod_dependencies_string -{ - my ($mod) = @_; - return join( '|',@{get_mod_dependencies($mod)}); -} - -sub vfs_to_physical -{ - my ($vfsPath) = @_; - my $fn = vfs_to_relative_to_mods($vfsPath); - return "$vfsroot/$fn"; -} - -sub vfs_to_relative_to_mods -{ - my ($vfsPath) = @_; - - for my $dep (@mods_list) - { - my $fn = "$dep/$vfsPath"; - - if (-e "$vfsroot/$fn") - { - return $fn; - } - } -} - -sub find_files -{ - my ($vfsPath, $extn) = @_; - my @files; - my $find_process = sub { - return $File::Find::prune = 1 if $_ eq '.svn'; - my $n = $File::Find::name; - return if /~$/; - return unless -f $_; - return unless /\.($extn)$/; - $n =~ s~\Q$vfsroot\E/($mod_list_string)/~~; - push @files, $n; - }; - - for my $dep (@mods_list) - { - find({ wanted => $find_process },"$vfsroot/$dep/$vfsPath") if -d "$vfsroot/$dep/$vfsPath"; - } - - return @files; -} - -sub parse_json_file_full_path -{ - my ($vfspath) = @_; - open my $fh, $vfspath or die "Failed to open '$vfspath': $!"; - # decode_json expects a UTF-8 string and doesn't handle BOMs, so we strip those - # (see http://trac.wildfiregames.com/ticket/1556) - return decode_json(do { local $/; my $file = <$fh>; $file =~ s/^\xEF\xBB\xBF//; $file }); -} - -sub parse_json_file -{ - my ($vfspath) = @_; - return parse_json_file_full_path(vfs_to_physical($vfspath)) -} - -sub add_entities -{ - print "Loading entities...\n"; - - my @entfiles = find_files('simulation/templates', 'xml'); - s~^simulation/templates/(.*)\.xml$~$1~ for @entfiles; - - for my $f (sort @entfiles) - { - my $path = "simulation/templates/$f.xml"; - push @files, $path; - my $ent = Entity::load_inherited($f, "$mod_list_string"); - - if ($ent->{Entity}{'@parent'}) - { - my @parents = split(/\|/, $ent->{Entity}{'@parent'}{' content'}); - for my $parentPath (@parents) - { - push @deps, [ $path, "simulation/templates/" . $parentPath . ".xml" ]; - } - } - - if ($f !~ /^template_/) - { - push @roots, $path; - if ($ent->{Entity}{VisualActor} and $ent->{Entity}{VisualActor}{Actor}) - { - my $phenotypes = $ent->{Entity}{Identity}{Phenotype}{' content'} || "default"; - my @phenotypes = split /\s/,$phenotypes; - - for my $phenotype (@phenotypes) - { - # See simulation2/components/CCmpVisualActor.cpp and Identity.js for explanation. - my $actorPath = $ent->{Entity}{VisualActor}{Actor}{' content'}; - $actorPath =~ s/{phenotype}/$phenotype/g; - push @deps, [ $path, "art/actors/" . $actorPath ]; - } - - push @deps, [ $path, "art/actors/" . $ent->{Entity}{VisualActor}{FoundationActor}{' content'} ] if $ent->{Entity}{VisualActor}{FoundationActor}; - } - - if ($ent->{Entity}{Sound}) - { - my $phenotypes = $ent->{Entity}{Identity}{Phenotype}{' content'} || "default"; - my $lang = $ent->{Entity}{Identity}{Lang}{' content'} || "greek"; - - my @phenotypes = split /\s/,$phenotypes; - - for my $phenotype (@phenotypes) - { - for (grep ref($_), values %{$ent->{Entity}{Sound}{SoundGroups}}) - { - # see simulation/components/Sound.js and Identity.js for explanation - my $soundPath = $_->{' content'}; - $soundPath =~ s/{phenotype}/$phenotype/g; - $soundPath =~ s/{lang}/$lang/g; - push @deps, [ $path, "audio/" . $soundPath ]; - } - } - } - - if ($ent->{Entity}{Identity}) - { - push @deps, [ $path, "art/textures/ui/session/portraits/" . $ent->{Entity}{Identity}{Icon}{' content'} ] if $ent->{Entity}{Identity}{Icon} and $ent->{Entity}{Identity}{Icon}{' content'} ne ''; - } - - if ($ent->{Entity}{Heal} and $ent->{Entity}{Heal}{RangeOverlay}) - { - push @deps, [ $path, "art/textures/selection/" . $ent->{Entity}{Heal}{RangeOverlay}{LineTexture}{' content'} ] if $ent->{Entity}{Heal}{RangeOverlay}{LineTexture} and $ent->{Entity}{Heal}{RangeOverlay}{LineTexture}{' content'} ne ''; - push @deps, [ $path, "art/textures/selection/" . $ent->{Entity}{Heal}{RangeOverlay}{LineTextureMask}{' content'} ] if $ent->{Entity}{Heal}{RangeOverlay}{LineTextureMask} and $ent->{Entity}{Heal}{RangeOverlay}{LineTextureMask}{' content'} ne ''; - } - - if ($ent->{Entity}{Selectable} and $ent->{Entity}{Selectable}{Overlay} and $ent->{Entity}{Selectable}{Overlay}{Texture}) - { - push @deps, [ $path, "art/textures/selection/" . $ent->{Entity}{Selectable}{Overlay}{Texture}{MainTexture}{' content'} ] if $ent->{Entity}{Selectable}{Overlay}{Texture}{MainTexture} and $ent->{Entity}{Selectable}{Overlay}{Texture}{MainTexture}{' content'} ne ''; - push @deps, [ $path, "art/textures/selection/" . $ent->{Entity}{Selectable}{Overlay}{Texture}{MainTextureMask}{' content'} ] if $ent->{Entity}{Selectable}{Overlay}{Texture}{MainTextureMask} and $ent->{Entity}{Selectable}{Overlay}{Texture}{MainTextureMask}{' content'} ne ''; - } - - if ($ent->{Entity}{Formation}) - { - push @deps, [ $path, "art/textures/ui/session/icons/" . $ent->{Entity}{Formation}{Icon}{' content'} ] if $ent->{Entity}{Formation}{Icon} and $ent->{Entity}{Formation}{Icon}{' content'} ne ''; - } - } - } -} - -sub push_variant_dependencies -{ - my ($variant, $f) = @_; - push @deps, [ $f, "art/variants/$variant->{file}" ] if $variant->{file}; - push @deps, [ $f, "art/meshes/$variant->{mesh}" ] if $variant->{mesh}; - push @deps, [ $f, "art/particles/$variant->{particles}{file}" ] if $variant->{particles}{file}; - for my $tex (@{$variant->{textures}{texture}}) - { - push @deps, [ $f, "art/textures/skins/$tex->{file}" ] if $tex->{file}; - } - for my $prop (@{$variant->{props}{prop}}) - { - push @deps, [ $f, "art/actors/$prop->{actor}" ] if $prop->{actor}; - } - for my $anim (@{$variant->{animations}{animation}}) - { - push @deps, [ $f, "art/animation/$anim->{file}" ] if $anim->{file}; - } -} - -sub add_actors -{ - print "Loading actors...\n"; - - my @actorfiles = find_files('art/actors', 'xml'); - for my $f (sort @actorfiles) - { - push @files, $f; - push @roots, $f; - - my $actor = XMLin(vfs_to_physical($f), ForceArray => [qw(group variant texture prop animation)], KeyAttr => []) or die "Failed to parse '$f': $!"; - - for my $group (@{$actor->{group}}) - { - for my $variant (@{$group->{variant}}) - { - push_variant_dependencies($variant, $f); - } - } - - push @deps, [ $f, "art/materials/$actor->{material}" ] if $actor->{material}; - } -} - - -sub add_variants -{ - print "Loading variants...\n"; - my @variantfiles = find_files('art/variants', 'xml'); - - for my $f (sort @variantfiles) - { - push @files, $f; - push @roots, $f; - my $variant = XMLin(vfs_to_physical($f), ForceArray => [qw(texture prop animation)], KeyAttr => []) or die "Failed to parse '$f': $!"; - push_variant_dependencies($variant, $f); - } -} - -sub add_art -{ - print "Loading art files...\n"; - push @files, find_files('art/textures/particles', $supportedTextureFormats); - push @files, find_files('art/textures/terrain', $supportedTextureFormats); - push @files, find_files('art/textures/skins', $supportedTextureFormats); - push @files, find_files('art/meshes', 'pmd|dae'); - push @files, find_files('art/animation', 'psa|dae'); -} - -sub add_materials -{ - print "Loading materials...\n"; - my @materialfiles = find_files('art/materials', 'xml'); - for my $f (sort @materialfiles) - { - push @files, $f; - - my $material = XMLin(vfs_to_physical($f), ForceArray => [qw(alternative)], KeyAttr => []); - for my $alternative (@{$material->{alternative}}) - { - push @deps, [ $f, "art/materials/$alternative->{material}" ] if $alternative->{material}; - } - } -} - -sub add_particles -{ - print "Loading particles...\n"; - my @particlefiles = find_files('art/particles', 'xml'); - for my $f (sort @particlefiles) - { - push @files, $f; - - my $particle = XMLin(vfs_to_physical($f)); - push @deps, [ $f, "$particle->{texture}" ] if $particle->{texture}; - } -} - -sub add_maps_xml -{ - print "Loading maps XML...\n"; - my @mapfiles = find_files('maps/scenarios', 'xml'); - push @mapfiles, find_files('maps/skirmishes', 'xml'); - push @mapfiles, find_files('maps/tutorials', 'xml'); - for my $f (sort @mapfiles) - { - push @files, $f; - push @roots, $f; - - my $map = XMLin(vfs_to_physical($f), ForceArray => [qw(Entity)], KeyAttr => []) or die "Failed to parse '$f': $!"; - - my %used; - for my $entity (@{$map->{Entities}{Entity}}) - { - $used{$entity->{Template}} = 1; - } - - for my $template (keys %used) - { - if ($template =~ /^actor\|(.*)$/) - { - # Handle special 'actor|' case - push @deps, [ $f, "art/actors/$1" ]; - } - else - { - if ($template =~ /^resource\|(.*)$/) - { - # Handle special 'resource|' case - $template = $1; - } - push @deps, [ $f, "simulation/templates/$template.xml" ]; - } - } - - # Map previews - my $settings = decode_json($map->{ScriptSettings}); - push @deps, [ $f, "art/textures/ui/session/icons/mappreview/" . $settings->{Preview} ] if $settings->{Preview}; - } -} - -sub add_maps_pmp -{ - print "Loading maps PMP...\n"; - - # Need to generate terrain texture filename=>path lookup first - my %terrains; - for my $f (find_files('art/terrains', 'xml')) - { - $f =~ /([^\/]+)\.xml/ or die; - - # ignore terrains.xml - if ($f !~ /terrains.xml$/) - { - warn "Duplicate terrain name '$1' (from '$terrains{$1}' and '$f')\n" if $terrains{$1}; - $terrains{$1} = $f; - } - } - - my @mapfiles = find_files('maps/scenarios', 'pmp'); - push @mapfiles, find_files('maps/skirmishes', 'pmp'); - for my $f (sort @mapfiles) - { - push @files, $f; - - push @roots, $f; - - open my $fh, vfs_to_physical($f) or die "Failed to open '$f': $!"; - binmode $fh; - - my $buf; - - read $fh, $buf, 4; - die "Invalid PMP header ($buf) in '$f'" unless $buf eq "PSMP"; - - read $fh, $buf, 4; - my $version = unpack 'V', $buf; - die "Invalid PMP version ($version) in '$f'" unless $version == 7; - - read $fh, $buf, 4; - my $datasize = unpack 'V', $buf; - - read $fh, $buf, 4; - my $mapsize = unpack 'V', $buf; - - seek $fh, 2 * ($mapsize*16+1)*($mapsize*16+1), 1; # heightmap - - read $fh, $buf, 4; - my $numtexs = unpack 'V', $buf; - - for (0..$numtexs-1) - { - read $fh, $buf, 4; - my $len = unpack 'V', $buf; - my $str; - read $fh, $str, $len; - - push @deps, [ $f, $terrains{$str} || "art/terrains/(unknown)/$str" ]; - } - - # ignore patches data - } -} - -sub add_soundgroups -{ - print "Loading sound groups...\n"; - my @soundfiles = find_files('audio', 'xml'); - for my $f (sort @soundfiles) - { - push @files, $f; - push @roots, $f; - - my $sound = XMLin(vfs_to_physical($f), ForceArray => [qw(Sound)], KeyAttr => []) or die "Failed to parse '$f': $!"; - - my $path = $sound->{Path}; - $path =~ s/\/$//; # strip optional trailing slash - - for (@{$sound->{Sound}}) - { - push @deps, [$f, "$path/$_" ]; - } - } -} - -sub add_audio -{ - print "Loading audio files...\n"; - push @files, find_files('audio', 'ogg'); -} - -sub add_gui_xml -{ - print "Loading GUI XML...\n"; - my @guifiles = find_files('gui', 'xml'); - for my $f (sort @guifiles) - { - push @files, $f; - - # GUI page definitions are assumed to be named page[_something].xml and alone in that. - if ($f =~ /\/page(_[^.\/]+)?\.xml$/) - { - push @roots, $f; - my $xml = XMLin(vfs_to_physical($f), ForceArray => [qw(include)], KeyAttr => []) or die "Failed to parse '$f': $!"; - - for my $include (@{$xml->{include}}) - { - # If including an entire directory, find all the *.xml files - if ($include =~ /\/$/) - { - push @deps, [ $f, $_ ] for find_files("gui/$include", 'xml'); - } - else - { - push @deps, [ $f, "gui/$include" ]; - } - } - } - else - { - my $xml = XMLin(vfs_to_physical($f), ForceArray => [qw(object script action sprite image)], KeyAttr => [], KeepRoot => 1) or die "Failed to parse '$f': $!"; - my $name = (keys %$xml)[0]; - if ($name eq 'objects' or $name eq 'object') - { - for (grep ref $_ , @{$xml->{objects}{script}}) - { - push @deps, [ $f, $_->{file} ] if $_->{file}; - if ($_->{directory}) - { - # If including an entire directory, find all the *.js files - push @deps, [ $f, $_ ] for find_files($_->{directory}, 'js') - } - } - my $add_objects; - $add_objects = sub - { - my ($parent) = @_; - for my $obj (@{$parent->{object}}) - { - # TODO: look at sprites, styles, etc - $add_objects->($obj); - } - }; - $add_objects->($xml->{objects}); - } - elsif ($name eq 'setup') - { - # TODO: look at sprites, styles, etc - } - elsif ($name eq 'styles') - { - # TODO: look at sprites, styles, etc - } - elsif ($name eq 'sprites') - { - for my $sprite (@{$xml->{sprites}{sprite}}) - { - for my $image (@{$sprite->{image}}) - { - push @deps, [ $f, "art/textures/ui/$image->{texture}" ] if $image->{texture}; - } - } - } - else - { - print "Unexpected GUI XML root element '$name':\n" . Dumper $xml; - exit; - } - } - } -} - -sub add_gui_data -{ - print "Loading GUI data...\n"; - push @files, find_files('gui', 'js'); - push @files, find_files('art/textures/ui', $supportedTextureFormats); - push @files, find_files('art/textures/selection', $supportedTextureFormats); -} - -sub add_civs -{ - print "Loading civs...\n"; - - my @civfiles = find_files('simulation/data/civs', 'json'); - for my $f (sort @civfiles) - { - push @files, $f; - - push @roots, $f; - - my $civ = parse_json_file($f); - - push @deps, [ $f, "art/textures/ui/" . $civ->{Emblem} ] if $civ->{Emblem}; - - push @deps, [ $f, "audio/music/" . $_->{File} ] for @{$civ->{Music}}; - } -} - -sub add_rms -{ - print "Loading random maps...\n"; - - push @files, find_files('maps/random', 'js'); - my @rmsdefs = find_files('maps/random', 'json'); - - for my $f (sort @rmsdefs) - { - next if $f =~ /^maps\/random\/rmbiome/; - - push @files, $f; - - push @roots, $f; - - my $rms = parse_json_file($f); - push @deps, [ $f, "maps/random/" . $rms->{settings}{Script} ] if $rms->{settings}{Script}; - - # Map previews - push @deps, [ $f, "art/textures/ui/session/icons/mappreview/" . $rms->{settings}{Preview} ] if $rms->{settings}{Preview}; - } -} - -sub add_techs -{ - print "Loading techs...\n"; - - my @techfiles = find_files('simulation/data/technologies', 'json'); - for my $f (sort @techfiles) - { - push @files, $f; - push @roots, $f; - - my $tech = parse_json_file($f); - - push @deps, [ $f, "art/textures/ui/session/portraits/technologies/" . $tech->{icon} ] if $tech->{icon}; - push @deps, [ $f, "simulation/data/technologies/" . $tech->{supersedes} . ".json" ] if $tech->{supersedes}; - } -} - -sub add_auras -{ - print "Loading auras...\n"; - - my @aurafiles = find_files('simulation/data/auras', 'json'); - for my $f (sort @aurafiles) - { - push @files, $f; - push @roots, $f; - - my $aura = parse_json_file($f); - - push @deps, [ $f, $aura->{overlayIcon} ] if $aura->{overlayIcon}; - - if($aura->{rangeOverlay}) - { - push @deps, [ $f, "art/textures/selection/" . $aura->{rangeOverlay}{lineTexture} ] if $aura->{rangeOverlay}{lineTexture}; - push @deps, [ $f, "art/textures/selection/" . $aura->{rangeOverlay}{lineTextureMask} ] if $aura->{rangeOverlay}{lineTextureMask}; - } - } -} - -sub add_terrains -{ - print "Loading terrains...\n"; - - my @terrains = find_files('art/terrains', 'xml'); - for my $f (sort @terrains) - { - # ignore terrains.xml - if ($f !~ /terrains.xml$/) - { - push @files, $f; - push @roots, $f; - - my $terrain = XMLin(vfs_to_physical($f), ForceArray => [qw(texture)], KeyAttr => []) or die "Failed to parse '$f': $!"; - - for my $texture (@{$terrain->{textures}{texture}}) - { - push @deps, [ $f, "art/textures/terrain/$texture->{file}" ] if $texture->{file}; - } - push @deps, [ $f, "art/materials/$terrain->{material}" ] if $terrain->{material}; - } - } -} - - -sub check_deps -{ - my %files; - @files{@files} = (); - - my %lcfiles; - @lcfiles{map lc($_), @files} = @files; - - my %revdeps; - for my $d (@deps) - { - push @{$revdeps{$d->[1]}}, $d->[0]; - } - - for my $f (sort keys %revdeps) - { - if ($f =~ /simulation\/templates\//) - { - next if exists $files{$f =~ s/templates\//templates\/special\/filter\//r}; - next if exists $files{$f =~ s/templates\//templates\/mixins\//r}; - } - next if exists $files{$f}; - warn "Missing file '$f' referenced by: " . (join ', ', map "'$_'", map vfs_to_relative_to_mods($_), sort @{$revdeps{$f}}) . "\n"; - - if (exists $lcfiles{lc $f}) - { - warn "### Case-insensitive match (found '$lcfiles{lc $f}')\n"; - } - } -} - -sub check_unused -{ - my %reachable; - @reachable{@roots} = (); - - my %deps; - for my $d (@deps) - { - push @{$deps{$d->[0]}}, $d->[1]; - } - - while (1) - { - my @newreachable; - for my $r (keys %reachable) - { - push @newreachable, grep { not exists $reachable{$_} } @{$deps{$r}}; - } - last if @newreachable == 0; - @reachable{@newreachable} = (); - } - - for my $f (sort @files) - { - next if exists $reachable{$f} - || index($f, "art/terrains/") != -1 - || index($f, "maps/random/") != -1 - || index($f, "art/materials/") != -1; - warn "Unused file '" . vfs_to_relative_to_mods($f) . "'\n"; - } -} - - -add_maps_xml() if $checkMapXml; -add_maps_pmp(); -add_entities(); -add_actors(); -add_variants(); -add_art(); -add_materials(); -add_particles(); -add_soundgroups(); -add_audio(); -add_gui_xml(); -add_gui_data(); -add_civs(); -add_rms(); -add_techs(); -add_terrains(); -add_auras(); - -check_deps(); -check_unused() if $checkUnused; -print "\n" if $checkUnused; -system("perl ../xmlvalidator/validate.pl") if $validateTemplates; diff -Nru 0ad-0.0.25b/source/tools/entity/checkrefs.py 0ad-0.0.26/source/tools/entity/checkrefs.py --- 0ad-0.0.25b/source/tools/entity/checkrefs.py 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/tools/entity/checkrefs.py 2022-09-23 19:16:45.000000000 +0000 @@ -0,0 +1,672 @@ +#!/usr/bin/env python3 +from argparse import ArgumentParser +from io import BytesIO +from json import load, loads +from pathlib import Path +from re import split, match +from struct import unpack, calcsize +from os.path import sep, exists, basename +from xml.etree import ElementTree +import sys +from scriptlib import SimulTemplateEntity, find_files +from logging import WARNING, getLogger, StreamHandler, INFO, Formatter, Filter + +class SingleLevelFilter(Filter): + def __init__(self, passlevel, reject): + self.passlevel = passlevel + self.reject = reject + + def filter(self, record): + if self.reject: + return (record.levelno != self.passlevel) + else: + return (record.levelno == self.passlevel) + +class CheckRefs: + def __init__(self): + # list of relative root file:str + self.files = [] + # list of relative file:str + self.roots = [] + # list of tuple (parent_file:str, dep_file:str) + self.deps = [] + self.vfs_root = Path(__file__).resolve().parents[3] / 'binaries' / 'data' / 'mods' + self.supportedTextureFormats = ('dds', 'png') + self.supportedMeshesFormats = ('pmd', 'dae') + self.supportedAnimationFormats = ('psa', 'dae') + self.supportedAudioFormats = ('ogg') + self.mods = [] + self.__init_logger + + @property + def __init_logger(self): + logger = getLogger(__name__) + logger.setLevel(INFO) + # create a console handler, seems nicer to Windows and for future uses + ch = StreamHandler(sys.stdout) + ch.setLevel(INFO) + ch.setFormatter(Formatter('%(levelname)s - %(message)s')) + f1 = SingleLevelFilter(INFO, False) + ch.addFilter(f1) + logger.addHandler(ch) + errorch = StreamHandler(sys.stderr) + errorch.setLevel(WARNING) + errorch.setFormatter(Formatter('%(levelname)s - %(message)s')) + logger.addHandler(errorch) + self.logger = logger + + def main(self): + ap = ArgumentParser(description="Checks the game files for missing dependencies, unused files," + " and for file integrity.") + ap.add_argument('-u', '--check-unused', action='store_true', + help="check for all the unused files in the given mods and their dependencies." + " Implies --check-map-xml. Currently yields a lot of false positives.") + ap.add_argument('-x', '--check-map-xml', action='store_true', + help="check maps for missing actor and templates.") + ap.add_argument('-a', '--validate-actors', action='store_true', + help="run the validator.py script to check if the actors files have extra or missing textures." + " This currently only works for the public mod.") + ap.add_argument('-t', '--validate-templates', action='store_true', + help="run the validator.py script to check if the xml files match their (.rng) grammar file.") + ap.add_argument('-m', '--mods', metavar="MOD", dest='mods', nargs='+', default=['public'], + help="specify which mods to check. Default to public.") + args = ap.parse_args() + # force check_map_xml if check_unused is used to avoid false positives. + args.check_map_xml |= args.check_unused + # ordered uniq mods (dict maintains ordered keys from python 3.6) + self.mods = list(dict.fromkeys([*args.mods, *self.get_mod_dependencies(*args.mods), 'mod']).keys()) + self.logger.info(f"Checking {'|'.join(args.mods)}'s integrity.") + self.logger.info(f"The following mods will be loaded: {'|'.join(self.mods)}.") + if args.check_map_xml: + self.add_maps_xml() + self.add_maps_pmp() + self.add_entities() + self.add_actors() + self.add_variants() + self.add_art() + self.add_materials() + self.add_particles() + self.add_soundgroups() + self.add_audio() + self.add_gui_xml() + self.add_gui_data() + self.add_civs() + self.add_rms() + self.add_techs() + self.add_terrains() + self.add_auras() + self.add_tips() + self.check_deps() + if args.check_unused: + self.check_unused() + if args.validate_templates: + sys.path.append("../xmlvalidator/") + from validate_grammar import RelaxNGValidator + validate = RelaxNGValidator(self.vfs_root, self.mods) + validate.run() + if args.validate_actors: + sys.path.append("../xmlvalidator/") + from validator import Validator + validator = Validator(self.vfs_root, self.mods) + validator.run() + + def get_mod_dependencies(self, *mods): + modjsondeps = [] + for mod in mods: + mod_json_path = self.vfs_root / mod / 'mod.json' + if not exists(mod_json_path): + continue + + with open(mod_json_path, encoding='utf-8') as f: + modjson = load(f) + # 0ad's folder isn't named like the mod. + modjsondeps.extend(['public' if '0ad' in dep else dep for dep in modjson.get('dependencies', [])]) + return modjsondeps + + def vfs_to_relative_to_mods(self, vfs_path): + for dep in self.mods: + fn = Path(dep) / vfs_path + if (self.vfs_root / fn).exists(): + return fn + return None + + def vfs_to_physical(self, vfs_path): + fn = self.vfs_to_relative_to_mods(vfs_path) + return self.vfs_root / fn + + def find_files(self, vfs_path, *ext_list): + return find_files(self.vfs_root, self.mods, vfs_path, *ext_list) + + def add_maps_xml(self): + self.logger.info("Loading maps XML...") + mapfiles = self.find_files('maps/scenarios', 'xml') + mapfiles.extend(self.find_files('maps/skirmishes', 'xml')) + mapfiles.extend(self.find_files('maps/tutorials', 'xml')) + actor_prefix = 'actor|' + resource_prefix = 'resource|' + for (fp, ffp) in sorted(mapfiles): + self.files.append(str(fp)) + self.roots.append(str(fp)) + et_map = ElementTree.parse(ffp).getroot() + entities = et_map.find('Entities') + used = {entity.find('Template').text.strip() for entity in entities.findall('Entity')} if entities is not None else {} + for template in used: + if template.startswith(actor_prefix): + self.deps.append((str(fp), f'art/actors/{template[len(actor_prefix):]}')) + elif template.startswith(resource_prefix): + self.deps.append((str(fp), f'simulation/templates/{template[len(resource_prefix):]}.xml')) + else: + self.deps.append((str(fp), f'simulation/templates/{template}.xml')) + # Map previews + settings = loads(et_map.find('ScriptSettings').text) + if settings.get('Preview', None): + self.deps.append((str(fp), f'art/textures/ui/session/icons/mappreview/{settings["Preview"]}')) + + def add_maps_pmp(self): + self.logger.info("Loading maps PMP...") + # Need to generate terrain texture filename=>relative path lookup first + terrains = dict() + for (fp, ffp) in self.find_files('art/terrains', 'xml'): + name = fp.stem + # ignore terrains.xml + if name != 'terrains': + if name in terrains: + self.logger.warning(f"Duplicate terrain name '{name}' (from '{terrains[name]}' and '{ffp}')") + terrains[name] = str(fp) + mapfiles = self.find_files('maps/scenarios', 'pmp') + mapfiles.extend(self.find_files('maps/skirmishes', 'pmp')) + for (fp, ffp) in sorted(mapfiles): + self.files.append(str(fp)) + self.roots.append(str(fp)) + with open(ffp, 'rb') as f: + expected_header = b'PSMP' + header = f.read(len(expected_header)) + if header != expected_header: + raise ValueError(f"Invalid PMP header {header} in '{ffp}'") + int_fmt = ' {builder}") + dot_f.write(f'"{f}" -> "{builder}" [color=green];\n') + if entity.find('TrainingQueue') is not None and entity.find('TrainingQueue').find('Entities') is not None: + entities = entity.find('TrainingQueue').find('Entities').text.replace('{civ}', entity.find('Identity').find('Civ').text) + training_queues = split(r'\s+', entities.strip()) + for training_queue in training_queues: + if Path(training_queue) in files: + warn(f"Invalid TrainingQueue reference: {f} -> {training_queue}") + dot_f.write(f'"{f}" -> "{training_queue}" [color=blue];\n') + dot_f.write('}\n') + if run(['dot', '-V'], capture_output=True).returncode == 0: + exit(run(['dot', '-Tpng', 'creation.dot', '-o', 'creation.png'], text=True).returncode) + + +if __name__ == '__main__': + chdir(Path(__file__).resolve().parent) + main() diff -Nru 0ad-0.0.25b/source/tools/entity/Entity.pm 0ad-0.0.26/source/tools/entity/Entity.pm --- 0ad-0.0.25b/source/tools/entity/Entity.pm 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/entity/Entity.pm 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -package Entity; - -use strict; -use warnings; - -use XML::Parser; -use Data::Dumper; -use File::Find; - -my $vfsroot = '../../../binaries/data/mods'; - -sub get_filename -{ - my ($vfspath, $mod) = @_; - my $fn = "$vfsroot/$mod/simulation/templates/special/filter/$vfspath.xml"; - if (not -e $fn) { - $fn = "$vfsroot/$mod/simulation/templates/mixins/$vfspath.xml"; - } - if (not -e $fn) { - $fn = "$vfsroot/$mod/simulation/templates/$vfspath.xml"; - } - return $fn; -} - -sub get_file -{ - my ($vfspath, $mod) = @_; - my $fn = get_filename($vfspath, $mod); - open my $f, $fn or die "Error loading $fn: $!"; - local $/; - return <$f>; -} - -sub trim -{ - my ($t) = @_; - return '' if not defined $t; - $t =~ /^\s*(.*?)\s*$/s; - return $1; -} - -sub load_xml -{ - my ($vfspath, $file) = @_; - my $root = {}; - my @stack = ($root); - my $p = new XML::Parser(Handlers => { - Start => sub { - my ($e, $n, %a) = @_; - my $t = {}; - die "Duplicate child node '$n'" if exists $stack[-1]{$n}; - $stack[-1]{$n} = $t; - for (keys %a) { - $t->{'@'.$_}{' content'} = trim($a{$_}); - } - push @stack, $t; - }, - End => sub { - my ($e, $n) = @_; - $stack[-1]{' content'} = trim($stack[-1]{' content'}); - pop @stack; - }, - Char => sub { - my ($e, $str) = @_; - $stack[-1]{' content'} .= $str; - }, - }); - eval { - $p->parse($file); - }; - if ($@) { - die "Error parsing $vfspath: $@"; - } - return $root; -} - -sub apply_layer -{ - my ($base, $new) = @_; - if ($new->{'@datatype'} and $new->{'@datatype'}{' content'} eq 'tokens') { - my @old = split /\s+/, ($base->{' content'} || ''); - my @new = split /\s+/, ($new->{' content'} || ''); - my @t = @old; - for my $n (@new) { - if ($n =~ /^-(.*)/) { - @t = grep $_ ne $1, @t; - } else { - push @t, $n if not grep $_ eq $n, @t; - } - } - $base->{' content'} = join ' ', @t; - } elsif ($new->{'@op'}) { - my $op = $new->{'@op'}{' content'}; - my $op1 = $base->{' content'}; - my $op2 = $new->{' content'}; - if ($op eq 'add') { - $base->{' content'} = $op1 + $op2; - } - elsif ($op eq 'mul') { - $base->{' content'} = $op1 * $op2; - } - elsif ($op eq 'mul_round') { - # This is incorrect (floors instead of rounding) - # but for schema purposes it ought be fine. - $base->{' content'} = int($op1 * $op2); - } - else { - die "Invalid operator '$op'"; - } - } else { - $base->{' content'} = $new->{' content'}; - } - for my $k (grep $_ ne ' content', keys %$new) { - if ($new->{$k}{'@disable'}) { - delete $base->{$k}; - } else { - if ($new->{$k}{'@replace'}) { - delete $base->{$k}; - } - $base->{$k} ||= {}; - apply_layer($base->{$k}, $new->{$k}); - delete $base->{$k}{'@replace'}; - } - } -} - -sub get_main_mod -{ - my ($vfspath, $mods) = @_; - my @mods_list = split(/\|/, $mods); - my $main_mod = $mods_list[0]; - my $fn = "$vfsroot/$main_mod/simulation/templates/$vfspath.xml"; - if (not -e $fn) - { - for my $dep (@mods_list) - { - $fn = "$vfsroot/$dep/simulation/templates/$vfspath.xml"; - if (-e $fn) - { - $main_mod = $dep; - last; - } - } - } - return $main_mod; -} - -sub load_inherited -{ - my ($vfspath, $mods, $base) = @_; - if ($vfspath =~ /\|/) { - my @paths = split(/\|/, $vfspath, 2); - $base = load_inherited($paths[1], $mods, $base); - $base = load_inherited($paths[0], $mods, $base); - return $base - } - my $main_mod = get_main_mod($vfspath, $mods); - my $layer = load_xml($vfspath, get_file($vfspath, $main_mod)); - - if ($layer->{Entity}{'@parent'}) { - my $parent = load_inherited($layer->{Entity}{'@parent'}{' content'}, $mods, $base); - apply_layer($parent->{Entity}, $layer->{Entity}); - return $parent; - } else { - if (not $base) { - return $layer; - } - else { - apply_layer($base->{Entity}, $layer->{Entity}); - return $base - } - } -} - -sub find_entities -{ - my ($modName) = @_; - my @files; - my $find_process = sub { - return $File::Find::prune = 1 if $_ eq '.svn'; - my $n = $File::Find::name; - return if /~$/; - return unless -f $_; - $n =~ s~\Q$vfsroot\E/$modName/simulation/templates/~~; - $n =~ s/\.xml$//; - push @files, $n; - }; - find({ wanted => $find_process }, "$vfsroot/$modName/simulation/templates"); - - return @files; -} diff -Nru 0ad-0.0.25b/source/tools/entity/entvalidate.py 0ad-0.0.26/source/tools/entity/entvalidate.py --- 0ad-0.0.25b/source/tools/entity/entvalidate.py 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/tools/entity/entvalidate.py 2022-09-23 19:16:43.000000000 +0000 @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +from os import chdir +from pathlib import Path +from subprocess import run, CalledProcessError +from sys import exit +from xml.etree import ElementTree +from scriptlib import warn, SimulTemplateEntity, find_files + + +def main(): + root = Path(__file__).resolve().parents[3] + relaxng_schema = root / 'binaries' / 'system' / 'entity.rng' + if not relaxng_schema.exists(): + warn(f"""Relax NG schema non existant. +Please create the file {relaxng_schema.relative_to(root)} +You can do that by running 'pyrogenesis -dumpSchema' in the 'system' directory""") + exit(1) + if run(['xmllint', '--version'], capture_output=True).returncode != 0: + warn("xmllint not found in your PATH, please install it (usually in libxml2 package)") + exit(2) + vfs_root = root / 'binaries' / 'data' / 'mods' + simul_templates_path = Path('simulation/templates') + simul_template_entity = SimulTemplateEntity(vfs_root) + count = 0 + failed = 0 + for fp, _ in sorted(find_files(vfs_root, ['public'], 'simulation/templates', 'xml')): + if fp.stem.startswith('template_'): + continue + print(f"# {fp}...") + count += 1 + entity = simul_template_entity.load_inherited(simul_templates_path, str(fp.relative_to(simul_templates_path)), ['public']) + xmlcontent = ElementTree.tostring(entity, encoding='unicode') + try: + run(['xmllint', '--relaxng', str(relaxng_schema.resolve()), '-'], input=xmlcontent, capture_output=True, text=True, check=True) + except CalledProcessError as e: + failed += 1 + print(e.stderr) + print(e.stdout) + print(f"\nTotal: {count}; failed: {failed}") + + +if __name__ == '__main__': + chdir(Path(__file__).resolve().parent) + main() diff -Nru 0ad-0.0.25b/source/tools/entity/readme.md 0ad-0.0.26/source/tools/entity/readme.md --- 0ad-0.0.25b/source/tools/entity/readme.md 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/entity/readme.md 2022-09-23 19:16:43.000000000 +0000 @@ -1,4 +1,4 @@ -# Checkrefs.pl +# Checkrefs.py ## Description @@ -6,24 +6,27 @@ ## Requirements -- Perl interpreter installed -- Dependencies: - - XML::Parser - - XML::Simple - - Getopt::Long - - File::Find - - Data::Dumper - - JSON +- Python 3.6+ interpreter installed +- lxml for the -a option. ## Usage -- cd in source/tools/entity and run the script. +- cd in `source/tools/entity` and run the script. ``` -Usage: perl checkrefs.pl [OPTION]... +usage: checkrefs.py [-h] [-u] [-x] [-a] [-t] [-m MOD [MOD ...]] + Checks the game files for missing dependencies, unused files, and for file integrity. - --check-unused check for all the unused files in the given mods and their dependencies. Implies --check-map-xml. Currently yields a lot of false positives. - --check-map-xml check maps for missing actor and templates. - --validate-templates run the validate.pl script to check if the xml files match their (.rng) grammar file. This currently only works for the public mod. - --mod-to-check=mods specify which mods to check. 'mods' should be a list of mods separated by '|'. Default value: 'public|mod'. + +options: + -h, --help show this help message and exit + -u, --check-unused check for all the unused files in the given mods and their dependencies. Implies --check-map- + xml. Currently yields a lot of false positives. + -x, --check-map-xml check maps for missing actor and templates. + -a, --validate-actors + run the validator.py script to check if the actors files have extra or missing textures. + -t, --validate-templates + run the validator.py script to check if the xml files match their (.rng) grammar file. + -m MOD [MOD ...], --mods MOD [MOD ...] + specify which mods to check. Default to public. ``` diff -Nru 0ad-0.0.25b/source/tools/entity/scriptlib/__init__.py 0ad-0.0.26/source/tools/entity/scriptlib/__init__.py --- 0ad-0.0.25b/source/tools/entity/scriptlib/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/tools/entity/scriptlib/__init__.py 2022-09-23 19:16:45.000000000 +0000 @@ -0,0 +1,128 @@ +from collections import Counter +from decimal import Decimal +from re import split +from sys import stderr +from xml.etree import ElementTree +from os.path import exists + +class SimulTemplateEntity: + def __init__(self, vfs_root, logger): + self.vfs_root = vfs_root + self.logger = logger + + def get_file(self, base_path, vfs_path, mod): + default_path = self.vfs_root / mod / base_path + file = (default_path/ "special" / "filter" / vfs_path).with_suffix('.xml') + if not exists(file): + file = (default_path / "mixins" / vfs_path).with_suffix('.xml') + if not exists(file): + file = (default_path / vfs_path).with_suffix('.xml') + return file + + def get_main_mod(self, base_path, vfs_path, mods): + for mod in mods: + fp = self.get_file(base_path, vfs_path, mod) + if fp.exists(): + main_mod = mod + break + else: + # default to first mod + # it should then not exist + # it will raise an exception when trying to read it + main_mod = mods[0] + return main_mod + + def apply_layer(self, base_tag, tag): + """ + apply tag layer to base_tag + """ + if tag.get('datatype') == 'tokens': + base_tokens = split(r'\s+', base_tag.text or '') + tokens = split(r'\s+', tag.text or '') + final_tokens = base_tokens.copy() + for token in tokens: + if token.startswith('-'): + token_to_remove = token[1:] + if token_to_remove in final_tokens: + final_tokens.remove(token_to_remove) + elif token not in final_tokens: + final_tokens.append(token) + base_tag.text = ' '.join(final_tokens) + elif tag.get('op'): + op = tag.get('op') + op1 = Decimal(base_tag.text or '0') + op2 = Decimal(tag.text or '0') + if op == 'add': + base_tag.text = str(op1 + op2) + elif op == 'mul': + base_tag.text = str(op1 * op2) + elif op == 'mul_round': + base_tag.text = str(round(op1 * op2)) + else: + raise ValueError(f"Invalid operator '{op}'") + else: + base_tag.text = tag.text + for child in tag: + base_child = base_tag.find(child.tag) + if 'disable' in child.attrib: + if base_child is not None: + base_tag.remove(base_child) + else: + if 'replace' in child.attrib and base_child is not None: + base_tag.remove(base_child) + if base_child is None: + base_child = ElementTree.Element(child.tag) + base_tag.append(base_child) + self.apply_layer(base_child, child) + if 'replace' in base_child.attrib: + del base_child.attrib['replace'] + + def load_inherited(self, base_path, vfs_path, mods, base = None): + """ + vfs_path should be relative to base_path in a mod + """ + if '|' in vfs_path: + paths = vfs_path.split("|", 2) + base = self.load_inherited(base_path, paths[1], mods, base); + base = self.load_inherited(base_path, paths[0], mods, base); + return base + + main_mod = self.get_main_mod(base_path, vfs_path, mods) + fp = self.get_file(base_path, vfs_path, main_mod) + layer = ElementTree.parse(fp).getroot() + for el in layer.iter(): + children = [x.tag for x in el] + duplicates = [x for x, c in Counter(children).items() if c > 1] + if duplicates: + for dup in duplicates: + self.logger.warning(f"Duplicate child node '{dup}' in tag {el.tag} of {fp}") + if layer.get('parent'): + parent = self.load_inherited(base_path, layer.get('parent'), mods) + self.apply_layer(parent, layer) + return parent + else: + if not base: + return layer + else: + self.apply_layer(base, layer) + return base + + +def find_files(vfs_root, mods, vfs_path, *ext_list): + """ + returns a list of 2-size tuple with: + - Path relative to the mod base + - full Path + """ + full_exts = ['.' + ext for ext in ext_list] + + def find_recursive(dp, base): + """(relative Path, full Path) generator""" + if dp.is_dir(): + if dp.name != '.svn' and dp.name != '.git' and not dp.name.endswith('~'): + for fp in dp.iterdir(): + yield from find_recursive(fp, base) + elif dp.suffix in full_exts: + relative_file_path = dp.relative_to(base) + yield (relative_file_path, dp.resolve()) + return [(rp, fp) for mod in mods for (rp, fp) in find_recursive(vfs_root / mod / vfs_path, vfs_root / mod)] diff -Nru 0ad-0.0.25b/source/tools/i18n/checkDiff.py 0ad-0.0.26/source/tools/i18n/checkDiff.py --- 0ad-0.0.25b/source/tools/i18n/checkDiff.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/checkDiff.py 2022-08-21 12:45:30.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 Wildfire Games. +# Copyright (C) 2021 Wildfire Games. # This file is part of 0 A.D. # # 0 A.D. is free software: you can redistribute it and/or modify @@ -60,10 +60,10 @@ if l[0] != '-' and l[0] != '+': l = diff.readline() continue - if l[1] == '\n' or l[1] == '#': + if l[1] == '\n' or (l[1] == '#' and l[2] == ":"): l = diff.readline() continue - if "POT-Creation-Date:" in l or "PO-Revision-Date" in l or "Last-Translator" in l: + if "# Copyright (C)" in l or "POT-Creation-Date:" in l or "PO-Revision-Date" in l or "Last-Translator" in l: l = diff.readline() continue # We've hit a real line diff -Nru 0ad-0.0.25b/source/tools/i18n/checkTranslations.py 0ad-0.0.26/source/tools/i18n/checkTranslations.py --- 0ad-0.0.25b/source/tools/i18n/checkTranslations.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/checkTranslations.py 2022-09-23 19:16:41.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 Wildfire Games. +# Copyright (C) 2022 Wildfire Games. # This file is part of 0 A.D. # # 0 A.D. is free software: you can redistribute it and/or modify @@ -16,17 +16,12 @@ # You should have received a copy of the GNU General Public License # along with 0 A.D. If not, see . -import os -import re -import sys -import multiprocessing +import sys, os, re, multiprocessing -from i18n_helper import projectRootDirectory +from i18n_helper import l10nFolderName, projectRootDirectory from i18n_helper.catalog import Catalog from i18n_helper.globber import getCatalogs -l10nFolderName = "l10n" - VERBOSE = 0 @@ -65,6 +60,16 @@ f'Found unknown {self.human_name} {", ".join(["`" + x + "`" for x in unknown_patterns])} in the translation ' f'which do not match any of the URLs in the template: {", ".join(["`" + x + "`" for x in patterns])}') + if templateMessage.pluralizable and translationMessage.pluralizable: + for indx, val in enumerate(translationMessage.string): + if indx == 0: + continue + translatedPatternsMulti = set(self.regex.findall(val)) + unknown_patterns_multi = translatedPatternsMulti.difference(pluralUrls) + if unknown_patterns_multi: + print(f'{inputFilePath} - {translationCatalog.locale}: ' + f'Found unknown {self.human_name} {", ".join(["`" + x + "`" for x in unknown_patterns_multi])} in the pluralised translation ' + f'which do not match any of the URLs in the template: {", ".join(["`" + x + "`" for x in pluralUrls])}') def check_translations(inputFilePath): if VERBOSE: @@ -100,7 +105,7 @@ foundPots = 0 for root, folders, filenames in os.walk(projectRootDirectory): for filename in filenames: - if len(filename) > 4 and filename[-4:] == ".pot" and os.path.basename(root) == "l10n": + if len(filename) > 4 and filename[-4:] == ".pot" and os.path.basename(root) == l10nFolderName: foundPots += 1 multiprocessing.Process( target=check_translations, diff -Nru 0ad-0.0.25b/source/tools/i18n/cleanTranslationFiles.py 0ad-0.0.26/source/tools/i18n/cleanTranslationFiles.py --- 0ad-0.0.25b/source/tools/i18n/cleanTranslationFiles.py 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/cleanTranslationFiles.py 2022-09-23 19:16:45.000000000 +0000 @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 Wildfire Games. +# This file is part of 0 A.D. +# +# 0 A.D. is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# 0 A.D. is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with 0 A.D. If not, see . + +""" +This file removes unneeded personal data from the translators. Most notably +the e-mail addresses. We need to translators' nicks for the credits, but no +more data is required. + +TODO: ideally we don't even pull the e-mail addresses in the .po files. +However that needs to be fixed on the transifex side, see rP25896. For now +strip the e-mails using this script. +""" + +import sys, os, glob, re, fileinput + +from i18n_helper import l10nFolderName, transifexClientFolder, projectRootDirectory + +def main(): + # Prepare some regexes. + commentMatch = re.compile('#.*') + translatorMatch = re.compile("(# [^,<]*)(?: <.*>)?(?:, [0-9,-]{4,9})") + lastTranslatorMatch = re.compile("(\"Last-Translator: [^,<]*)(?: <.*>)?( ?\\\\n\")") + + for root, folders, filenames in os.walk(projectRootDirectory): + for folder in folders: + if folder == l10nFolderName: + if os.path.exists(os.path.join(root, folder, transifexClientFolder)): + path = os.path.join(root, folder, "*.po") + files = glob.glob(path) + for file in files: + usernames = [] + reached = False + for line in fileinput.input(file.replace("\\", "/"), inplace=1): + if reached: + if line == "# \n": + line = "" + m = translatorMatch.match(line) + if m: + if m.group(1) in usernames: + line = "" + else: + line = m.group(1) + "\n" + usernames.append(m.group(1)) + m2 = lastTranslatorMatch.match(line) + if m2: + line = m2.group(1) + "\\n\"\n" + elif line.strip() == "# Translators:": + reached = True + sys.stdout.write(line) + +if __name__ == "__main__": + main() diff -Nru 0ad-0.0.25b/source/tools/i18n/creditTranslators.py 0ad-0.0.26/source/tools/i18n/creditTranslators.py --- 0ad-0.0.25b/source/tools/i18n/creditTranslators.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/creditTranslators.py 2022-09-23 19:16:41.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 Wildfire Games. +# Copyright (C) 2022 Wildfire Games. # This file is part of 0 A.D. # # 0 A.D. is free software: you can redistribute it and/or modify @@ -31,6 +31,8 @@ import json, os, glob, re +from i18n_helper import l10nFolderName, transifexClientFolder, projectRootDirectory + # We credit everyone that helps translating even if the translations don't # make it into the game. # Note: Needs to be edited manually when new languages are added on Transifex. @@ -110,14 +112,14 @@ 'zh': '中文, 汉语, 漢語 (Chinese)', 'zh_TW': '臺灣話 Chinese (Taiwan)'} -root = '../../../' - -poLocations = [ - 'binaries/data/l10n/', - 'binaries/data/mods/public/l10n/', - 'binaries/data/mods/mod/l10n/'] +poLocations = [] +for root, folders, filenames in os.walk(projectRootDirectory): + for folder in folders: + if folder == l10nFolderName: + if os.path.exists(os.path.join(root, folder, transifexClientFolder)): + poLocations.append(os.path.join(root, folder)) -creditsLocation = 'binaries/data/mods/public/gui/credits/texts/translators.json' +creditsLocation = os.path.join(projectRootDirectory, 'binaries', 'data', 'mods', 'public', 'gui', 'credits', 'texts', 'translators.json') # This dictionnary will hold creditors lists for each language, indexed by code langsLists = {} @@ -128,8 +130,7 @@ # Now go through the list of languages and search the .po files for people # Prepare some regexes -commentMatch = re.compile('#.*') -translatorMatch = re.compile('# ([^,<]*)(?: <.*>)?, [0-9,-]{4,9}') +translatorMatch = re.compile('# (.*)') deletedUsernameMatch = re.compile('[0-9a-f]{32}') # Search @@ -138,19 +139,19 @@ langsLists[lang] = [] for location in poLocations: - files = glob.glob(root + location + lang + '.*.po') + files = glob.glob(os.path.join(location, lang + '.*.po')) for file in files: poFile = open(file.replace('\\', '/'), encoding='utf-8') reached = False for line in poFile: if reached: - if not commentMatch.match(line): - break m = translatorMatch.match(line) - if m: - username = m.group(1) - if not deletedUsernameMatch.match(username): - langsLists[lang].append(m.group(1)) + if not m: + break + + username = m.group(1) + if not deletedUsernameMatch.match(username): + langsLists[lang].append(username) if line.strip() == '# Translators:': reached = True poFile.close() @@ -166,6 +167,6 @@ newJSONData['Content'][-1]['List'].append({'name': name}) # Save the JSON data to the credits file -creditsFile = open(root + creditsLocation, 'w', encoding='utf-8') +creditsFile = open(creditsLocation, 'w', encoding='utf-8') json.dump(newJSONData, creditsFile, indent=4) creditsFile.close() diff -Nru 0ad-0.0.25b/source/tools/i18n/extractors/extractors.py 0ad-0.0.26/source/tools/i18n/extractors/extractors.py --- 0ad-0.0.25b/source/tools/i18n/extractors/extractors.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/extractors/extractors.py 2022-09-23 19:16:41.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 Wildfire Games. +# Copyright (C) 2022 Wildfire Games. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the @@ -326,20 +326,20 @@ def extractFromFile(self, filepath): with codecs.open(filepath, "r", 'utf-8') as fileObject: - for message, breadcrumbs in self.extractFromString(fileObject.read()): - yield message, None, self.context, self.formatBreadcrumbs(breadcrumbs), None, self.comments + for message, context, breadcrumbs in self.extractFromString(fileObject.read()): + yield message, None, context, self.formatBreadcrumbs(breadcrumbs), None, self.comments def extractFromString(self, string): self.breadcrumbs = [] jsonDocument = jsonParser.loads(string) if isinstance(jsonDocument, list): - for message, breadcrumbs in self.parseList(jsonDocument): + for message, context, breadcrumbs in self.parseList(jsonDocument): if message: # Skip empty strings. - yield message, breadcrumbs + yield message, context, breadcrumbs elif isinstance(jsonDocument, dict): - for message, breadcrumbs in self.parseDictionary(jsonDocument): + for message, context, breadcrumbs in self.parseDictionary(jsonDocument): if message: # Skip empty strings. - yield message, breadcrumbs + yield message, context, breadcrumbs else: raise Exception("Unexpected JSON document parent structure (not a list or a dictionary). You must extend the JSON extractor to support it.") @@ -348,11 +348,11 @@ for listItem in itemsList: self.breadcrumbs.append(index) if isinstance(listItem, list): - for message, breadcrumbs in self.parseList(listItem): - yield message, breadcrumbs + for message, context, breadcrumbs in self.parseList(listItem): + yield message, context, breadcrumbs elif isinstance(listItem, dict): - for message, breadcrumbs in self.parseDictionary(listItem): - yield message, breadcrumbs + for message, context, breadcrumbs in self.parseDictionary(listItem): + yield message, context, breadcrumbs del self.breadcrumbs[-1] index += 1 @@ -361,35 +361,79 @@ self.breadcrumbs.append(keyword) if keyword in self.keywords: if isinstance(dictionary[keyword], str): - yield dictionary[keyword], self.breadcrumbs + yield self.extractString(dictionary[keyword], keyword) elif isinstance(dictionary[keyword], list): - for message, breadcrumbs in self.extractList(dictionary[keyword]): - yield message, breadcrumbs + for message, context, breadcrumbs in self.extractList(dictionary[keyword], keyword): + yield message, context, breadcrumbs elif isinstance(dictionary[keyword], dict): - for message, breadcrumbs in self.extractDictionary(dictionary[keyword]): - yield message, breadcrumbs + extract = None + if "extractFromInnerKeys" in self.keywords[keyword] and self.keywords[keyword]["extractFromInnerKeys"]: + for message, context, breadcrumbs in self.extractDictionaryInnerKeys(dictionary[keyword], keyword): + yield message, context, breadcrumbs + else: + extract = self.extractDictionary(dictionary[keyword], keyword) + if extract: + yield extract elif isinstance(dictionary[keyword], list): - for message, breadcrumbs in self.parseList(dictionary[keyword]): - yield message, breadcrumbs + for message, context, breadcrumbs in self.parseList(dictionary[keyword]): + yield message, context, breadcrumbs elif isinstance(dictionary[keyword], dict): - for message, breadcrumbs in self.parseDictionary(dictionary[keyword]): - yield message, breadcrumbs + for message, context, breadcrumbs in self.parseDictionary(dictionary[keyword]): + yield message, context, breadcrumbs del self.breadcrumbs[-1] - def extractList(self, itemsList): + def extractString(self, string, keyword): + context = None + if "tagAsContext" in self.keywords[keyword]: + context = keyword + elif "customContext" in self.keywords[keyword]: + context = self.keywords[keyword]["customContext"] + else: + context = self.context + return string, context, self.breadcrumbs + + def extractList(self, itemsList, keyword): index = 0 for listItem in itemsList: self.breadcrumbs.append(index) if isinstance(listItem, str): - yield listItem, self.breadcrumbs + yield self.extractString(listItem, keyword) + elif isinstance(listItem, dict): + extract = self.extractDictionary(dictionary[keyword], keyword) + if extract: + yield extract del self.breadcrumbs[-1] index += 1 - def extractDictionary(self, dictionary): - for keyword in dictionary: - self.breadcrumbs.append(keyword) - if isinstance(dictionary[keyword], str): - yield dictionary[keyword], self.breadcrumbs + def extractDictionary(self, dictionary, keyword): + message = dictionary.get("_string", None) + self.breadcrumbs.append("_string") + if message and isinstance(message, str): + context = None + if "context" in dictionary: + context = str(dictionary["context"]) + elif "tagAsContext" in self.keywords[keyword]: + context = keyword + elif "customContext" in self.keywords[keyword]: + context = self.keywords[keyword]["customContext"] + else: + context = self.context + return message, context, self.breadcrumbs + del self.breadcrumbs[-1] + return None + + def extractDictionaryInnerKeys(self, dictionary, keyword): + for innerKeyword in dictionary: + self.breadcrumbs.append(innerKeyword) + if isinstance(dictionary[innerKeyword], str): + yield self.extractString(dictionary[innerKeyword], keyword) + elif isinstance(dictionary[innerKeyword], list): + for message, context, breadcrumbs in self.extractList(dictionary[innerKeyword], keyword): + yield message, context, breadcrumbs + elif isinstance(dictionary[innerKeyword], dict): + extract = self.extractDictionary(dictionary[innerKeyword], keyword) + if extract: + yield extract del self.breadcrumbs[-1] @@ -416,14 +460,14 @@ for element in xmlDocument.iter(keyword): position = element.sourceline if element.text is not None: - context = None comments = [] if "extractJson" in self.keywords[keyword]: jsonExtractor = self.getJsonExtractor() jsonExtractor.setOptions(self.keywords[keyword]["extractJson"]) - for message, breadcrumbs in jsonExtractor.extractFromString(element.text): + for message, context, breadcrumbs in jsonExtractor.extractFromString(element.text): yield message, None, context, json.formatBreadcrumbs(breadcrumbs), position, comments else: + context = None breadcrumb = None if "locationAttributes" in self.keywords[keyword]: attributes = [element.get(attribute) for attribute in self.keywords[keyword]["locationAttributes"] if attribute in element.attrib] diff -Nru 0ad-0.0.25b/source/tools/i18n/generateDebugTranslation.py 0ad-0.0.26/source/tools/i18n/generateDebugTranslation.py --- 0ad-0.0.25b/source/tools/i18n/generateDebugTranslation.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/generateDebugTranslation.py 2022-09-23 19:16:41.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 Wildfire Games. +# Copyright (C) 2022 Wildfire Games. # This file is part of 0 A.D. # # 0 A.D. is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ import sys import multiprocessing -from i18n_helper import projectRootDirectory +from i18n_helper import l10nFolderName, projectRootDirectory from i18n_helper.catalog import Catalog from i18n_helper.globber import getCatalogs @@ -142,7 +142,7 @@ found_pot_files = 0 for root, _, filenames in os.walk(projectRootDirectory): for filename in filenames: - if len(filename) > 4 and filename[-4:] == ".pot" and os.path.basename(root) == "l10n": + if len(filename) > 4 and filename[-4:] == ".pot" and os.path.basename(root) == l10nFolderName: found_pot_files += 1 if args.debug: multiprocessing.Process( diff -Nru 0ad-0.0.25b/source/tools/i18n/i18n_helper/catalog.py 0ad-0.0.26/source/tools/i18n/i18n_helper/catalog.py --- 0ad-0.0.25b/source/tools/i18n/i18n_helper/catalog.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/i18n_helper/catalog.py 2022-08-21 12:45:30.000000000 +0000 @@ -38,7 +38,7 @@ @staticmethod def readFrom(file_path, locale = None): - return read_po(open(file_path, "r+"), locale=locale) + return read_po(open(file_path, "r+",encoding="utf-8"), locale=locale) def writeTo(self, file_path): return write_po( diff -Nru 0ad-0.0.25b/source/tools/i18n/i18n_helper/__init__.py 0ad-0.0.26/source/tools/i18n/i18n_helper/__init__.py --- 0ad-0.0.25b/source/tools/i18n/i18n_helper/__init__.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/i18n_helper/__init__.py 2022-09-23 19:16:41.000000000 +0000 @@ -1,4 +1,6 @@ import os +l10nFolderName = "l10n" +transifexClientFolder = ".tx" l10nToolsDirectory = os.path.dirname(os.path.realpath(__file__)) projectRootDirectory = os.path.abspath(os.path.join(l10nToolsDirectory, os.pardir, os.pardir, os.pardir, os.pardir)) diff -Nru 0ad-0.0.25b/source/tools/i18n/maintenanceTasks.sh 0ad-0.0.26/source/tools/i18n/maintenanceTasks.sh --- 0ad-0.0.25b/source/tools/i18n/maintenanceTasks.sh 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/maintenanceTasks.sh 2022-08-21 12:45:30.000000000 +0000 @@ -20,6 +20,9 @@ # Pre-Commit Cleanup ######################################################### +echo ":: Removing unneeded data from the .po files…" +python3 "${SCRIPT_PATH}/cleanTranslationFiles.py" + echo ":: Reverting unnecessary changes…" python3 "${SCRIPT_PATH}/checkDiff.py" diff -Nru 0ad-0.0.25b/source/tools/i18n/pullTranslations.py 0ad-0.0.26/source/tools/i18n/pullTranslations.py --- 0ad-0.0.25b/source/tools/i18n/pullTranslations.py 2021-07-27 21:56:45.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/pullTranslations.py 2022-09-23 19:16:41.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 Wildfire Games. +# Copyright (C) 2022 Wildfire Games. # This file is part of 0 A.D. # # 0 A.D. is free software: you can redistribute it and/or modify @@ -20,12 +20,9 @@ from txclib.project import Project -from i18n_helper import l10nToolsDirectory, projectRootDirectory +from i18n_helper import l10nFolderName, transifexClientFolder, projectRootDirectory def main(): - l10nFolderName = "l10n" - transifexClientFolder = ".tx" - for root, folders, filenames in os.walk(projectRootDirectory): for folder in folders: if folder == l10nFolderName: @@ -33,7 +30,7 @@ path = os.path.join(root, folder) os.chdir(path) project = Project(path) - project.pull(fetchall=True, force=True) + project.pull(fetchall=True, force=True, parallel=True) if __name__ == "__main__": diff -Nru 0ad-0.0.25b/source/tools/i18n/updateTemplates.py 0ad-0.0.26/source/tools/i18n/updateTemplates.py --- 0ad-0.0.25b/source/tools/i18n/updateTemplates.py 2021-07-27 21:56:46.000000000 +0000 +++ 0ad-0.0.26/source/tools/i18n/updateTemplates.py 2022-09-23 19:16:45.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 Wildfire Games. +# Copyright (C) 2022 Wildfire Games. # This file is part of 0 A.D. # # 0 A.D. is free software: you can redistribute it and/or modify @@ -22,11 +22,9 @@ from lxml import etree -from i18n_helper import l10nToolsDirectory, projectRootDirectory +from i18n_helper import l10nFolderName, projectRootDirectory from i18n_helper.catalog import Catalog from extractors import extractors - -l10nFolderName = "l10n" messagesFilename = "messages.json" diff -Nru 0ad-0.0.25b/source/tools/LICENSE.txt 0ad-0.0.26/source/tools/LICENSE.txt --- 0ad-0.0.25b/source/tools/LICENSE.txt 2021-07-27 21:56:50.000000000 +0000 +++ 0ad-0.0.26/source/tools/LICENSE.txt 2022-09-23 19:16:41.000000000 +0000 @@ -67,6 +67,3 @@ xmlvalidator MIT - - lobbybots - GPL version 2 (or later) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/ejabberd_example.yml 0ad-0.0.26/source/tools/lobbybots/ejabberd_example.yml --- 0ad-0.0.25b/source/tools/lobbybots/ejabberd_example.yml 2021-07-27 21:56:49.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/ejabberd_example.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,855 +0,0 @@ -### -###' ejabberd configuration file -### -### - -### The parameters used in this configuration file are explained in more detail -### in the ejabberd Installation and Operation Guide. -### Please consult the Guide in case of doubts, it is included with -### your copy of ejabberd, and is also available online at -### http://www.process-one.net/en/ejabberd/docs/ - -### The configuration file is written in YAML. -### Refer to http://en.wikipedia.org/wiki/YAML for the brief description. -### However, ejabberd treats different literals as different types: -### -### - unquoted or single-quoted strings. They are called "atoms". -### Example: dog, 'Jupiter', '3.14159', YELLOW -### -### - numeric literals. Example: 3, -45.0, .0 -### -### - quoted or folded strings. -### Examples of quoted string: "Lizzard", "orange". -### Example of folded string: -### > Art thou not Romeo, -### and a Montague? ---- -###. ======= -###' LOGGING - -## -## loglevel: Verbosity of log files generated by ejabberd. -## 0: No ejabberd log at all (not recommended) -## 1: Critical -## 2: Error -## 3: Warning -## 4: Info -## 5: Debug -## -loglevel: 4 - -## -## rotation: Disable ejabberd's internal log rotation, as the Debian package -## uses logrotate(8). -log_rotate_size: 0 -log_rotate_date: "" - -## -## overload protection: If you want to limit the number of messages per second -## allowed from error_logger, which is a good idea if you want to avoid a flood -## of messages when system is overloaded, you can set a limit. -## 100 is ejabberd's default. -log_rate_limit: 100 - -## -## watchdog_admins: Only useful for developers: if an ejabberd process -## consumes a lot of memory, send live notifications to these XMPP -## accounts. -## -## watchdog_admins: -## - "bob@example.com" - -###. =============== -###' NODE PARAMETERS - -## -## net_ticktime: Specifies net_kernel tick time in seconds. This options must have -## identical value on all nodes, and in most cases shouldn't be changed at all from -## default value. -## -## net_ticktime: 60 - -###. ================ -###' SERVED HOSTNAMES - -## -## hosts: Domains served by ejabberd. -## You can define one or several, for example: -## hosts: -## - "example.net" -## - "example.com" -## - "example.org" -## -hosts: - - "localhost" - -## -## route_subdomains: Delegate subdomains to other XMPP servers. -## For example, if this ejabberd serves example.org and you want -## to allow communication with an XMPP server called im.example.org. -## -## route_subdomains: s2s - -###. ============ -###' Certificates - -## List all available PEM files containing certificates for your domains, -## chains of certificates or certificate keys. Full chains will be built -## automatically by ejabberd. -## -certfiles: - - "/etc/ejabberd/ejabberd.pem" - -## If your system provides only a single CA file (CentOS/FreeBSD): -## ca_file: "/etc/ssl/certs/ca-bundle.pem" - -###. ================= -###' TLS configuration - -## Note that the following configuration is the default -## configuration of the TLS driver, so you don't need to -## uncomment it. -## -define_macro: - 'TLS_CIPHERS': "HIGH:!aNULL:!eNULL:!3DES:@STRENGTH" - 'TLS_OPTIONS': - - "no_sslv2" - - "no_sslv3" - - "no_tlsv1" - - "cipher_server_preference" - - "no_compression" - ## 'DH_FILE': "/path/to/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 2048 - -## c2s_dhfile: 'DH_FILE' -## s2s_dhfile: 'DH_FILE' -c2s_ciphers: 'TLS_CIPHERS' -s2s_ciphers: 'TLS_CIPHERS' -c2s_protocol_options: 'TLS_OPTIONS' -s2s_protocol_options: 'TLS_OPTIONS' - -###. =============== -###' LISTENING PORTS - -## -## listen: The ports ejabberd will listen on, which service each is handled -## by and what options to start it with. -## -listen: - - - port: 5222 - ip: "0.0.0.0" - module: ejabberd_c2s - starttls: true - starttls_required: false - protocol_options: 'TLS_OPTIONS' - max_stanza_size: 1048576 - shaper: c2s_shaper - access: c2s - - ## port: 5269 - ## ip: "::" - ## module: ejabberd_s2s_in - - - - port: 5280 - ip: "127.0.0.1" - module: ejabberd_http - request_handlers: - "/ws": ejabberd_http_ws - "/bosh": mod_bosh - "/api": mod_http_api - ## "/pub/archive": mod_http_fileserver - web_admin: true - ## register: true - ## captcha: true - tls: true - protocol_options: 'TLS_OPTIONS' - - ## - ## ejabberd_service: Interact with external components (transports, ...) - ## - ## - - ## port: 8888 - ## ip: "::" - ## module: ejabberd_service - ## access: all - ## shaper_rule: fast - ## ip: "127.0.0.1" - ## privilege_access: - ## roster: "both" - ## message: "outgoing" - ## presence: "roster" - ## delegations: - ## "urn:xmpp:mam:1": - ## filtering: ["node"] - ## "http://jabber.org/protocol/pubsub": - ## filtering: [] - ## hosts: - ## "icq.example.org": - ## password: "secret" - ## "sms.example.org": - ## password: "secret" - - ## - ## ejabberd_stun: Handles STUN Binding requests - ## - - - port: 3478 - transport: udp - module: ejabberd_stun - - ## - ## To handle XML-RPC requests that provide admin credentials: - ## - ## - - ## port: 4560 - ## ip: "::" - ## module: ejabberd_xmlrpc - ## maxsessions: 10 - ## timeout: 5000 - ## access_commands: - ## admin: - ## commands: all - ## options: [] - - ## - ## To enable secure http upload - ## - ## - - ## port: 5444 - ## ip: "::" - ## module: ejabberd_http - ## request_handlers: - ## "": mod_http_upload - ## tls: true - ## protocol_options: 'TLS_OPTIONS' - ## dhfile: 'DH_FILE' - ## ciphers: 'TLS_CIPHERS' - -## Disabling digest-md5 SASL authentication. digest-md5 requires plain-text -## password storage (see auth_password_format option). -disable_sasl_mechanisms: "digest-md5" - -###. ================== -###' S2S GLOBAL OPTIONS - -## -## s2s_use_starttls: Enable STARTTLS for S2S connections. -## Allowed values are: false, optional or required -## You must specify 'certfiles' option -## -s2s_use_starttls: required - -## -## S2S whitelist or blacklist -## -## Default s2s policy for undefined hosts. -## -## s2s_access: s2s - -## -## Outgoing S2S options -## -## Preferred address families (which to try first) and connect timeout -## in seconds. -## -## outgoing_s2s_families: -## - ipv4 -## - ipv6 -## outgoing_s2s_timeout: 190 - -###. ============== -###' AUTHENTICATION - -## -## auth_method: Method used to authenticate the users. -## The default method is the internal. -## If you want to use a different method, -## comment this line and enable the correct ones. -## -auth_method: internal - -## -## Store the plain passwords or hashed for SCRAM: -## auth_password_format: plain -auth_password_format: scram -## -## Define the FQDN if ejabberd doesn't detect it: -## fqdn: "server3.example.com" - -## -## Authentication using external script -## Make sure the script is executable by ejabberd. -## -## auth_method: external -## extauth_program: "/path/to/authentication/script" - -## -## Authentication using SQL -## Remember to setup a database in the next section. -## -## auth_method: sql - -## -## Authentication using PAM -## -## auth_method: pam -## pam_service: "pamservicename" - -## -## Authentication using LDAP -## -## auth_method: ldap -## -## List of LDAP servers: -## ldap_servers: -## - "lw" -## -## Encryption of connection to LDAP servers: -## ldap_encrypt: none -## ldap_encrypt: tls -## -## Port to connect to on LDAP servers: -## ldap_port: 389 -## ldap_port: 636 -## -## LDAP manager: -## ldap_rootdn: "dc=example,dc=com" -## -## Password of LDAP manager: -## ldap_password: "******" -## -## Search base of LDAP directory: -## ldap_base: "dc=example,dc=com" -## -## LDAP attribute that holds user ID: -## ldap_uids: -## - "mail": "%u@mail.example.org" -## -## LDAP filter: -## ldap_filter: "(objectClass=shadowAccount)" - -## -## Anonymous login support: -## auth_method: anonymous -## anonymous_protocol: sasl_anon | login_anon | both -## allow_multiple_connections: true | false -## -## host_config: -## "public.example.org": -## auth_method: anonymous -## allow_multiple_connections: false -## anonymous_protocol: sasl_anon -## -## To use both anonymous and internal authentication: -## -## host_config: -## "public.example.org": -## auth_method: -## - internal -## - anonymous - -###. ============== -###' DATABASE SETUP - -## ejabberd by default uses the internal Mnesia database, -## so you do not necessarily need this section. -## This section provides configuration examples in case -## you want to use other database backends. -## Please consult the ejabberd Guide for details on database creation. - -## -## MySQL server: -## -## sql_type: mysql -## sql_server: "server" -## sql_database: "database" -## sql_username: "username" -## sql_password: "password" -## -## If you want to specify the port: -## sql_port: 1234 - -## -## PostgreSQL server: -## -## sql_type: pgsql -## sql_server: "server" -## sql_database: "database" -## sql_username: "username" -## sql_password: "password" -## -## If you want to specify the port: -## sql_port: 1234 -## -## If you use PostgreSQL, have a large database, and need a -## faster but inexact replacement for "select count(*) from users" -## -## pgsql_users_number_estimate: true - -## -## SQLite: -## -## sql_type: sqlite -## sql_database: "/path/to/database.db" - -## -## ODBC compatible or MSSQL server: -## -## sql_type: odbc -## sql_server: "DSN=ejabberd;UID=ejabberd;PWD=ejabberd" - -## -## Number of connections to open to the database for each virtual host -## -## sql_pool_size: 10 - -## -## Interval to make a dummy SQL request to keep the connections to the -## database alive. Specify in seconds: for example 28800 means 8 hours -## -## sql_keepalive_interval: undefined - -###. =============== -###' TRAFFIC SHAPERS - -shaper: - ## - ## The "normal" shaper limits traffic speed to 1000 B/s - ## - normal: 1000 - - ## - ## The "fast" shaper limits traffic speed to 50000 B/s - ## - fast: 50000 - -## -## This option specifies the maximum number of elements in the queue -## of the FSM. Refer to the documentation for details. -## -max_fsm_queue: 10000 - -###. ==================== -###' ACCESS CONTROL LISTS -acl: - ## - ## The 'admin' ACL grants administrative privileges to XMPP accounts. - ## You can put here as many accounts as you want. - ## - admin: - user: - - "admin@localhost" - - ## Don't use a regex, to prevent others from obtaining permissions after registering such an account. - bots: - - user: "echelon23@localhost" - - user: "wfgbot23@localhost" - - # Keep playernames short and easily typeable for everyone - validname: - user_regexp: "^[0-9A-Za-z._-]{1,20}$" - - ## - ## Blocked users - ## - ## blocked: - ## user: - ## - "baduser@example.org" - ## - "test" - - ## Local users: don't modify this. - ## - local: - user_regexp: "" - - ## - ## More examples of ACLs - ## - ## jabberorg: - ## server: - ## - "jabber.org" - ## aleksey: - ## user: - ## - "aleksey@jabber.ru" - ## test: - ## user_regexp: "^test" - ## user_glob: "test*" - - ## - ## Loopback network - ## - loopback: - ip: - - "127.0.0.0/8" - - "::1/128" - - "::FFFF:127.0.0.1/128" - - ## - ## Bad XMPP servers - ## - ## bad_servers: - ## server: - ## - "xmpp.zombie.org" - ## - "xmpp.spam.com" - -## -## Define specific ACLs in a virtual host. -## -## host_config: -## "localhost": -## acl: -## admin: -## user: -## - "bob-local@localhost" - -###. ============ -###' SHAPER RULES - -shaper_rules: - ## Maximum number of simultaneous sessions allowed for a single user: - max_user_sessions: 10 - ## Maximum number of offline messages that users can have: - max_user_offline_messages: - - 5000: admin - - 100 - ## For C2S connections, all users except admins use the "normal" shaper - c2s_shaper: - - none: admin - - none: bots - - normal - ## All S2S connections use the "fast" shaper - s2s_shaper: fast - -###. ============ -###' ACCESS RULES -access_rules: - ## This rule allows access only for local users: - local: - - allow: local - ## Only non-blocked users can use c2s connections: - c2s: - - deny: blocked - - allow - ## Only admins can send announcement messages: - announce: - - allow: admin - ## Only admins can use the configuration interface: - configure: - - allow: admin - ## Expected by the ipstamp module for XpartaMuPP - ipbots: - - allow: bots - muc_admin: - - allow: admin - ## Bots must be able to create nodes for games, ratings and boards lists - pubsub_createnode: - - allow: admin - - allow: bots - ## In-band registration allows registration of any possible username. - ## To disable in-band registration, replace 'allow' with 'deny'. - register: - - deny: blocked - - allow: validname - ## Only allow to register from localhost - trusted_network: - - allow: loopback - ## Do not establish S2S connections with bad servers - ## If you enable this you also have to uncomment "s2s_access: s2s" - ## s2s: - ## - deny: - ## - ip: "XXX.XXX.XXX.XXX/32" - ## - deny: - ## - ip: "XXX.XXX.XXX.XXX/32" - ## - allow - -## =============== -## API PERMISSIONS -## =============== -## -## This section allows you to define who and using what method -## can execute commands offered by ejabberd. -## -## By default "console commands" section allow executing all commands -## issued using ejabberdctl command, and "admin access" section allows -## users in admin acl that connect from 127.0.0.1 to execute all -## commands except start and stop with any available access method -## (ejabberdctl, http-api, xmlrpc depending what is enabled on server). -## -## If you remove "console commands" there will be one added by -## default allowing executing all commands, but if you just change -## permissions in it, version from config file will be used instead -## of default one. -## -api_permissions: - "console commands": - from: - - ejabberd_ctl - who: all - what: "*" - "admin access": - who: - - access: - - allow: - - acl: loopback - - acl: admin - - oauth: - - scope: "ejabberd:admin" - - access: - - allow: - - acl: loopback - - acl: admin - what: - - "*" - - "!stop" - - "!start" - "public commands": - who: - - ip: "127.0.0.1/8" - what: - - "status" - - "connected_users_number" - -## By default the frequency of account registrations from the same IP -## is limited to 1 account every 10 minutes. To disable, specify: infinity -registration_timeout: 3600 - -## -## Define specific Access Rules in a virtual host. -## -## host_config: -## "localhost": -## access: -## c2s: -## - allow: admin -## - deny -## register: -## - deny - -###. ================ -###' DEFAULT LANGUAGE - -## -## language: Default language used for server messages. -## -language: "en" - -## -## Set a different default language in a virtual host. -## -## host_config: -## "localhost": -## language: "ru" - -###. ======= -###' CAPTCHA - -## -## Full path to a script that generates the image. -## -## captcha_cmd: "/usr/share/ejabberd/captcha.sh" - -## -## Host for the URL and port where ejabberd listens for CAPTCHA requests. -## -## captcha_host: "example.org:5280" - -## -## Limit CAPTCHA calls per minute for JID/IP to avoid DoS. -## -## captcha_limit: 5 - -###. ==== -###' ACME -## -## In order to use the acme certificate acquiring through "Let's Encrypt" -## an http listener has to be configured to listen to port 80 so that -## the authorization challenges posed by "Let's Encrypt" can be solved. -## -## A simple way of doing this would be to add the following in the listening -## section and to configure port forwarding from 80 to 5281 either via NAT -## (for ipv4 only) or using frontends such as haproxy/nginx/sslh/etc. -## - -## port: 5281 -## ip: "::" -## module: ejabberd_http - -acme: - - ## A contact mail that the ACME Certificate Authority can contact in case of - ## an authorization issue, such as a server-initiated certificate revocation. - ## It is not mandatory to provide an email address but it is highly suggested. - contact: "mailto:example-admin@example.com" - - - ## The ACME Certificate Authority URL. - ## This could either be: - ## - https://acme-v01.api.letsencrypt.org - (Default) for the production CA - ## - https://acme-staging.api.letsencrypt.org - for the staging CA - ## - http://localhost:4000 - for a local version of the CA - ca_url: "https://acme-v01.api.letsencrypt.org" - -###. ======= -###' MODULES - -## -## Modules enabled in all ejabberd virtual hosts. -## -modules: - mod_adhoc: {} - mod_admin_extra: {} - mod_announce: # recommends mod_adhoc - access: announce - mod_blocking: {} # requires mod_privacy - mod_caps: {} - mod_carboncopy: {} - mod_client_state: {} - mod_configure: {} # requires mod_adhoc - ## mod_delegation: {} # for xep0356 - mod_disco: {} - ## mod_echo: {} - ## ipstamp module used by XpartaMuPP to insert IP addresses into the gamelist - mod_ipstamp: {} - ## mod_irc: {} - mod_bosh: {} - ## mod_http_fileserver: - ## docroot: "/var/www" - ## accesslog: "/var/log/ejabberd/access.log" - ## mod_http_upload: - ## # docroot: "@HOME@/upload" - ## put_url: "https://@HOST@:5444" - ## thumbnail: false # otherwise needs the identify command from ImageMagick installed - ## mod_http_upload_quota: - ## max_days: 30 - mod_last: {} - ## XEP-0313: Message Archive Management - ## You might want to setup a SQL backend for MAM because the mnesia database is - ## limited to 2GB which might be exceeded on large servers - ## mod_mam: {} # for xep0313, mnesia is limited to 2GB, better use an SQL backend - mod_muc: - ## host: "conference.@HOST@" - access: - - allow - access_admin: muc_admin - access_create: muc_admin - access_persistent: muc_admin - max_users: 5000 - default_room_options: - allow_change_subj: false - logging: true - max_users: 1000 - persistent: true - mod_muc_admin: {} - mod_muc_log: - outdir: "/lobby/logs" - dirtype: plain - file_format: plaintext - timezone: universal - ## mod_multicast: {} - mod_offline: - access_max_user_messages: max_user_offline_messages - mod_ping: - send_pings: true - ## mod_pres_counter: - ## count: 5 - ## interval: 60 - mod_privacy: {} - mod_private: {} - ## mod_proxy65: {} - mod_pubsub: - access_createnode: pubsub_createnode - ## reduces resource comsumption, but XEP incompliant - ignore_pep_from_offline: true - ## XEP compliant, but increases resource comsumption - ## ignore_pep_from_offline: false - last_item_cache: false - plugins: - - "flat" - - "hometree" - - "pep" # pep requires mod_caps - mod_push: {} - mod_push_keepalive: {} - mod_register: - ## - ## Protect In-Band account registrations with CAPTCHA. - ## - ## captcha_protected: true - ## - ## Set the minimum informational entropy for passwords. - ## - ## password_strength: 32 - ## - ## After successful registration, the user receives - ## a message with this subject and body. - ## - ## welcome_message: - ## subject: "Welcome!" - ## body: |- - ## Hi. - ## Welcome to this XMPP server. - ## - ## When a user registers, send a notification to - ## these XMPP accounts. - ## - ## registration_watchers: - ## - "admin1@example.org" - ## - ## Only clients in the server machine can register accounts - ## - ## ip_access: trusted_network - ## - ## Local c2s or remote s2s users cannot register accounts - ## - ## access_from: deny - access: register - mod_roster: - versioning: true - ## mod_shared_roster: {} - mod_stats: {} - mod_time: {} - ## mod_vcard: - ## search: false - ## mod_vcard_xupdate: {} - ## Convert all avatars posted by Android clients from WebP to JPEG - ## mod_avatar: # this module needs compile option --enable-graphics - ## convert: - ## webp: jpeg - mod_version: {} - mod_stream_mgmt: - resend_on_timeout: if_offline - ## Non-SASL Authentication (XEP-0078) is now disabled by default - ## because it's obsoleted and is used mostly by abandoned - ## client software - ## mod_legacy_auth: {} - ## The module for S2S dialback (XEP-0220). Please note that you cannot - ## rely solely on dialback if you want to federate with other servers, - ## because a lot of servers have dialback disabled and instead rely on - ## PKIX authentication. Make sure you have proper certificates installed - ## and check your accessibility at https://check.messaging.one/ - mod_s2s_dialback: {} - mod_http_api: {} - -## -## Enable modules with custom options in a specific virtual host -## -## host_config: -## "localhost": -## modules: -## mod_echo: -## host: "mirror.localhost" - -## -## Enable modules management via ejabberdctl for installation and -## uninstallation of public/private contributed modules -## (enabled by default) -## - -allow_contrib_modules: true - -###. -###' -### Local Variables: -### mode: yaml -### End: -### vim: set filetype=yaml tabstop=8 foldmarker=###',###. foldmethod=marker: - diff -Nru 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/COPYING 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/COPYING --- 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/COPYING 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/COPYING 1970-01-01 00:00:00.000000000 +0000 @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff -Nru 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/mod_ipstamp.spec 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/mod_ipstamp.spec --- 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/mod_ipstamp.spec 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/mod_ipstamp.spec 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -author: "Wildfire Games" -category: "log" -summary: "Add senders IP address to game registration stanzas for 0ad" -home: "undefined" -url: "https://play0ad.com" diff -Nru 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/README.txt 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/README.txt --- 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/README.txt 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/README.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -mod_ipstamp -=========== - -mod_ipstamp is an ejabberd module for 0ad which adds ip addresses of a -game host to game registration stanzas. - -For it to work the 0ad XMPP bots need to have the ACL "ipbots". diff -Nru 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/src/mod_ipstamp.erl 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/src/mod_ipstamp.erl --- 0ad-0.0.25b/source/tools/lobbybots/mod_ipstamp/src/mod_ipstamp.erl 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/mod_ipstamp/src/mod_ipstamp.erl 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -%% Copyright (C) 2018 Wildfire Games. -%% This file is part of 0 A.D. -%% -%% 0 A.D. is free software: you can redistribute it and/or modify -%% it under the terms of the GNU General Public License as published by -%% the Free Software Foundation, either version 2 of the License, or -%% (at your option) any later version. -%% -%% 0 A.D. is distributed in the hope that it will be useful, -%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -%% GNU General Public License for more details. -%% -%% You should have received a copy of the GNU General Public License -%% along with 0 A.D. If not, see . - --module(mod_ipstamp). - --behaviour(gen_mod). - --include("ejabberd.hrl"). --include("logger.hrl"). --include("xmpp.hrl"). - --export([start/2, - stop/1, - depends/2, - mod_opt_type/1, - reload/3, - on_filter_packet/1]). - -start(_Host, _Opts) -> - ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 50). - -stop(_Host) -> - ejabberd_hooks:delete(filter_packet, global, ?MODULE, on_filter_packet, 50). - -depends(_Host, _Opts) -> []. - -mod_opt_type(_) -> []. - -reload(_Host, _NewOpts, _OldOpts) -> ok. - --spec on_filter_packet(Input :: iq()) -> iq() | drop. -on_filter_packet(#iq{type = set, to = To, sub_els = [SubEl]} = Input) -> - % We only want to do something for the bots - case acl:match_rule(global, ipbots, To) of - allow -> - NS = xmpp:get_ns(SubEl), - if NS == <<"jabber:iq:gamelist">> -> - SCommand = fxml:get_path_s(SubEl, [{elem, <<"command">>}, cdata]), - if SCommand == <<"register">> -> - % Get the sender's IP. - Ip = xmpp:get_meta(Input, ip), - SIp = inet_parse:ntoa(Ip), - ?INFO_MSG(string:concat("Inserting IP into game registration " - "stanza: ", SIp), []), - Game = fxml:get_subtag(SubEl, <<"game">>), - GameWithIp = fxml:replace_tag_attr(<<"ip">>, SIp, Game), - SubEl2 = fxml:replace_subtag(GameWithIp, SubEl), - xmpp:set_els(Input, [SubEl2]); - true -> - Input - end; - true -> - Input - end; - _ -> Input - end; - -on_filter_packet(Input) -> - Input. diff -Nru 0ad-0.0.25b/source/tools/lobbybots/README.md 0ad-0.0.26/source/tools/lobbybots/README.md --- 0ad-0.0.25b/source/tools/lobbybots/README.md 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,641 +0,0 @@ -# 0 A.D. / Pyrogenesis Multiplayer Lobby Setup - -This README explains how to setup a custom Pyrogenesis Multiplayer Lobby server that can be used with the Pyrogenesis game. - -## Service description -The Pyrogenesis Multiplayer Lobby consists of three components: - -* **XMPP server: ejabberd**: - The XMPP server provides the platform where users can register accounts, chat in a public room, and can interact with lobby bots. - ejabberd is recommended. - -* **Gamelist bot: XpartaMuPP**: - This bot allows players to host and join online multiplayer matches. - -* **Rating bot: EcheLOn**: - This bot allows players to gain a rating that reflects their skill based on online multiplayer matches. - It is by no means necessary for the operation of a lobby in terms of match-making and chatting. - -## Service choices -Before installing the service, you have to make some decisions: - -#### Choice: Domain Name -Decide on a domain name where the service will be provided. -This document will use `lobby.wildfiregames.com` as an example. -If you intend to use the server only for local testing, you may choose `localhost`. - -#### Choice: Rating service -Decide whether or not you want to employ the rating service. -If you decide to not provide the rating service, you may skip the instructions for the rating bot in this document. - -#### Choice: Pyrogenesis version compatibility -Decide whether you want to support serving multiple Pyrogenesis versions. - -Serving multiple versions of Pyrogenesis allows for seamless version upgrading on the backend and -allows players that don't have the most recent version of Pyrogenesis yet to continue to play until -the new release is available for their platform (applies mostly to linux distributions). - -If you decide to do so, you should use a naming pattern that includes the targetted Pyrogenesis version. -For example to provide a Multiplayer Lobby for Pyrogenesis Alpha 23 "Ken Wood", -name the lobby room `arena23` instead of `arena` and use `xpartamupp23` and `echelon23` as lobby bot names. -Then when a version 24 of Pyrogenesis is employed, you can easily add `arena24`, `xpartamupp24` and `echelon24`. -If you only want to use the service for local testing, you can stick to a single room and a single gamelist and rating bot. - -## 1. Install dependencies - -This section explains how to install the required software on a Debian-based linux distribution. -For other operating systems, use the according package manager or consult the official documentation of the software. - -### 1.1 Install ejabberd - -The version requirement for ejabberd is 17.03 or later (due to the ipstamp module format). - -* Install `ejabberd` using the following command. Alternatively see . - - ``` - $ apt-get install ejabberd - ``` - -* Confirm that the ejabberd version you installed is the one mentioned above or later: - - ``` - $ ejabberdctl status - ``` - -* Configure ejabberd by setting the domain name of your choice and add an `admin` user.: - - ``` - $ dpkg-reconfigure ejabberd - ```` - -You should now be able to connect to this XMPP server using any XMPP client. - -### 1.2 Install python3 and SleekXmpp - -* The lobby bots are programmed in python3 and use SleekXMPP to connect to the lobby. Install these dependencies using: - - ``` - $ apt-get install python3 python3-sleekxmpp - ``` - -* Confirm that the SleekXmpp version is 1.3.1 or later: - - ``` - pip3 show sleekxmpp - ``` - -* If you would like to run the rating bot, you will need to install SQLAlchemy for python3: - - ``` - $ apt-get install python3-sqlalchemy - ``` - -## 2 (Optional) Install ejabberd ipstamp module - -### 2.1 Copy mod_ipstamp files. - -The ejabberd ipstamp module is used as a fallback for users without STUN capabilities. -It inserts the IP to GameList "register" stanzas, which XpartMuPP sends back to the host. -STUN-enabled users do not require it to host, so this is optional. - -* Adjust `/etc/ejabberd/ejabberdctl.cfg` and set `CONTRIB_MODULES_PATH` to the directory where you want to store `mod_ipstamp`: - - ``` - CONTRIB_MODULES_PATH=/opt/ejabberd-modules - ``` - -* Ensure the target directory is readable by ejabberd. -* Copy the `mod_ipstamp` directory from `XpartaMuPP/` to `CONTRIB_MODULES_PATH/sources/`. -* Check that the module is available and compatible with your ejabberd: - - ``` - $ ejabberdctl modules_available - $ ejabberdctl module_check mod_ipstamp - ``` - -* Install `mod_ipstamp`: - - ``` - $ ejabberdctl module_install mod_ipstamp - ``` - -## 2.2. Configure ejabberd mod_ipstamp - -The ejabberd configuration in the remainder of this document is performed by editing `/etc/ejabberd/ejabberd.yml`. -The directory containing this README includes a preconfigured `ejabberd_example.yml` that only needs few setting changes to work with your setup. -For a full documentation of the ejabberd configuration, see . -If something goes wrong with ejabberd, check `/var/log/ejabberd/ejabberd.log` - -* Add `mod_ipstamp` to the modules ejabberd should load: - - ``` - modules: - mod_ipstamp: {} - ``` - -* Reload the ejabberd config. - This should be done every few steps, so that configuration errors can be identified as soon as possible. - - ``` - $ ejabberdctl reload_config - ``` - -## 3. Configure ejabberd connectivity - -The settings in this section ensure that connections can be built where intended, and only where intended. - -### 3.1 Disable IPv6 -* Since the enet library which Pyrogenesis uses for multiplayer mode does not support IPv6, ejabberd must be configured to not use IPv6: - - ``` - listen: - ip: "0.0.0.0" - ``` - -### 3.2 Enable STUN -* ejabberd and Pyrogenesis support the STUN protocol. This allows players to connect to each others games even if the host did not configure the router and forward the UDP port. -0 A.D. uses STUN to let hosts find their IP. - - ``` - listen: - - - port: 3478 - transport: udp - module: ejabberd_stun - ``` - -### 3.3 Enable keep-alive - -* This helps with users becoming disconnected: - - ``` - modules: - mod_ping: - send_pings: true - ``` - -### 3.3 Disable unused services - -* Disable the currently unused server-to-server communication: - - ``` - listen: - ## - - ## port: 5269 - ## ip: "::" - ## module: ejabberd_s2s_in - ``` - -* Protect the administrative webinterface at from external access by disabling or restriction to `localhost`: - - ``` - listen: - - - port: 5280 - ip: "127.0.0.1" - ``` - -* Disable some unused modules: - - ``` - modules: - ## mod_echo: {} - ## mod_irc: {} - ## mod_shared_roster: {} - ## mod_vcard: {} - ## mod_vcard_xupdate: {} - ``` - -### 3.4 Setup TLS encryption - -Depending on whether you use the server for a player audience or only for local testing, -you may have to either obtain and install a certificate with ejabberd or disable TLS encryption. - -#### Choice A: No encryption -* If you intend to use the server solely for local testing, you may disable TLS encryption in the ejabberd config: - - ``` - listen: - starttls_required: false - ``` - -#### Choice B: Self-signed certificate - -If you want to use the server for local testing only, you may use a self-signed certificate to test encryption. -Notice the lobby bots currently reject self-signed certificates. - -* Enable TLS over the default port: - ``` - listen: - starttls: true - ``` - -* Create the key file for certificate: - - ``` - openssl genrsa -out key.pem 2048 - ``` -* Create the certificate file. “common name” should match the domainname. - - ``` - openssl req -new -key key.pem -out request.pem - ``` - -* Sign the certificate: - - ``` - openssl x509 -req -days 900 -in request.pem -signkey key.pem -out certificate.pem - ``` - -* Store it as the ejabberd certificate: - - ``` - $ cat key.pem request.pem > /etc/ejabberd/ejabberd.pem - ``` - -#### Choice C: Let's Encrypt certificate -To secure user authentication and communication with modern encryption and to comply with privacy laws, -ejabberd should be configured to use TLS with a proper, trusted certificate. - -* A free, valid, and trusted TLS certificate may be obtained from some certificate authorites, such as Let's Encrypt: - - - -* Enable TLS over the default port: - ``` - listen: - starttls: true - ``` - -* Setup the contact address if Let's Encrypt found an authentication issue: - - ``` - acme: - contact: "mailto:admin@example.com" - ``` - -* Ensure old, vulnerable SSL/TLS protocols are disabled: - - ``` - define_macro: - 'TLS_OPTIONS': - - "no_sslv2" - - "no_sslv3" - - "no_tlsv1" - ``` - -## 3. Configure ejabberd use policy - -The settings in this section grant or restrict user access rights. - -* Prevent the rooms from being destroyed if the last client leaves it: - - ``` - access_rules: - muc_admin: - - allow: admin - modules: - mod_muc: - access_persistent: muc_admin - default_room_options: - persistent: true - ``` - -* Allow users to create accounts using the game via in-band registration. - ``` - access_rules: - register: - - all: allow - ``` - -### Optional use policies - -* (Optional) It is recommended to restrict usernames to alphanumeric characters (so that playernames are easily typeable for every participant). - The username may be restricted in length (because very long usernames are uncomfortably time-consuming to read and may not fit into the playername fields). - Notice the username regex below is also used by the 0 A.D. client to indicate invalid names to the user. - ``` - acl: - validname: - user_regexp: "^[0-9A-Za-z._-]{1,20}$" - - access_rules: - register: - - allow: validname - - modules: - mod_register: - access: register - ``` - -* (Optional) Prevent users from creating new rooms: - - ``` - modules: - mod_muc: - access_create: muc_admin - ``` - -* (Optional) Increase the maximum number of users from the default 200: - - ``` - mod_muc: - max_users: 5000 - default_room_options: - max_users: 1000 - ``` - -* (Optional) Prevent users from sending too large stanzas. - Notice the bots can send large stanzas as well, so don't restrict it too much. - - ``` - max_stanza_size: 1048576 - ``` - - -* (Optional) Prevent users from changing the room topic: - - ``` - mod_muc: - default_room_options: - allow_change_subj: false - ``` - -* (Optional) Prevent malicious users from registering new accounts quickly if they were banned. - Notice this also prevents players using the same internet router from registering for that time if they want to play together. - - ``` - registration_timeout: 3600 - ``` - -* (Optional) Enable room chatlogging. - Make sure to mention this collection and the purposes in the Terms and Conditions to comply with personal data laws. - Ensure that ejabberd has write access to the given folder. - Notice that `ejabberd.service` by default prevents write access to some directories (PrivateTmp, ProtectHome, ProtectSystem). - - ``` - modules: - mod_muc_log: - outdir: "/lobby/logs" - file_format: plaintext - timezone: universal - mod_muc: - default_room_options: - logging: true - ``` - -* (Optional) Grant specific moderators administrator rights to see the IP address of a user: - See also `https://xmpp.org/extensions/xep-0133.html#get-user-stats`. - - ``` - acl: - admin: - user: - - "username@lobby.wildfiregames.com" - ``` - -* (Optional) Grant specific moderators to : - See also `https://xmpp.org/extensions/xep-0133.html#get-user-stats`. - - ``` - modules: - mod_muc: - access_admin: muc_admin - ``` - -* (Optional) Ban specific IP addresses or subnet masks for persons that create new accounts after having been banned from the room: - - ``` - acl: - blocked: - ip: - - "12.34.56.78" - - "12.34.56.0/8" - - "12.34.0.0/16" - ... - access_rules: - c2s: - - deny: blocked - - allow - register: - - deny: blocked - - allow - ``` - -## 4. Setup lobby bots - -### 4.1 Register lobby bot accounts - -* Check list of registered users: - - ``` - $ ejabberdctl registered_users lobby.wildfiregames.com - ``` - -* Register the accounts of the lobby bots. - The rating account is only needed if you decided to enable the rating service. - - ``` - $ ejabberdctl register echelon23 lobby.wildfiregames.com secure_password - $ ejabberdctl register xpartamupp23 lobby.wildfiregames.com secure_password - ``` - -### 4.2 Authorize lobby bots to see real JIDs - -* The bots need to be able to see real JIDs of users. - So either the room must be configured as non-anonymous, i.e. real JIDs are visible to all users of the room, - or the bots need to receive muc administrator rights. - -#### Choice A: Non-anonymous room -* (Recommended) This method has the advantage that bots do not gain administrative access that they don't use. - The only possible downside is that room users may not hide their username behind arbitrary nicknames anymore. - - ``` - modules: - mod_muc: - default_room_options: - anonymous: false - ``` - -#### Choice B: Non-anonymous room -* If you for any reason wish to configure the room as semi-anonymous (only muc administrators can see real JIDs), - then the bots need to be authorized as muc administrators: - - ``` - access_rules: - muc_admin: - - allow: bots - - modules: - mod_muc: - access_admin: muc_admin - ``` - -### 4.3 Authorize lobby bots with ejabberd - -* The bots need an ACL to be able to get the IPs of users hosting a match (which is what `mod_ipstamp` does). - - ``` - acl: - ## Don't use a regex, to prevent others from obtaining permissions after registering such an account. - bots: - - user: "xpartamupp23@lobby.wildfiregames.com" - - user: "echelon23@lobby.wildfiregames.com" - ``` - -* Add an access rule for `ipbots` and a rule allowing bots to create PubSub nodes: - - ``` - access_rules: - ## Expected by the ipstamp module for XpartaMuPP - ipbots: - - allow: bots - - pubsub_createnode: - - allow: bots - ``` - -* Due to the amount of traffic the bot may process, give the group containing bots either unlimited or a very high traffic shaper: - - ``` - shaper_rules: - c2s_shaper: - - none: admin, bots - - normal - ``` - -* Finally reload ejabberd's configuration: - - ``` - $ ejabberdctl reload_config - ``` - -### 4.4 Running XpartaMuPP - XMPP Multiplayer Game Manager - -* Execute the following command to run the gamelist bot: - - ``` - $ python3 XpartaMuPP.py --domain lobby.wildfiregames.com --login xpartamupp23 --password XXXXXX --nickname GamelistBot --room arena --elo echelon23 - ``` - -If you want to run XpartaMuPP without a rating bot, the `--elo` argument should be omitted. -Pass `--disable-tls` if you did not setup valid TLS encryption on the server. -Run `python3 XpartaMuPP.py --help` for the full list of options - -* If the connection and authentication succeeded, you should see the following messages in the console: - - ``` - INFO JID set to: xpartamupp23@lobby.wildfiregames.com/CC - INFO XpartaMuPP started - ``` - -### 4.5 Running EcheLOn - XMPP Multiplayer Rating Manager - -This bot can be thought of as a module of XpartaMuPP in that IQs stanzas sent to XpartaMuPP are -forwarded onto EcheLOn if its corresponding EcheLOn is online and ignored otherwise. -EcheLOn handles all aspects of operation related to ELO, the chess rating system invented by Arpad Elo. -Players gain a rating after a rated 1v1 match. -The score difference after a completed match is relative to the rating difference of the players. - -* (Optional) Some constants of the algorithm may be edited by experienced administrators at the head of `ELO.py`: - - ``` - # Difference between two ratings such that it is - # regarded as a "sure win" for the higher player. - # No points are gained or lost for such a game. - elo_sure_win_difference = 600.0 - - # Lower ratings "move faster" and change more - # dramatically than higher ones. Anything rating above - # this value moves at the same rate as this value. - elo_k_factor_constant_rating = 2200.0 - ``` - -* To initialize the `lobby_rankings.sqlite3` database, execute the following command: - - ``` - $ python3 LobbyRanking.py - ``` - -* Execute the following command to run the rating bot: - - ``` - $ python3 EcheLOn.py --domain lobby.wildfiregames.com --login echelon23 --password XXXXXX --nickname RatingBot --room arena23 - ``` - -Run `python3 EcheLOn.py --help` for the full list of options - -## 5. Configure Pyrogenesis for the new Multiplayer Lobby - -The Pyrogenesis client is now going to be configured to become able to connect to the new Multiplayer Lobby. - -The Pyrogenesis documentation of configuration files can be found at . -Available Pyrogenesis configuration settings are specified in `default.cfg`, see . - -### 5.1 Local Configuration - - * Visit to identify the local user's Pyrogenesis configuration path depending on the operating system. - - * Create or open `local.cfg` in the configuration path. - - * Add the following settings that determine the lobby server connection: - - ``` - lobby.room = "arena23" ; Default MUC room to join - lobby.server = "lobby.wildfiregames.com" ; Address of lobby server - lobby.stun.server = "lobby.wildfiregames.com" ; Address of the STUN server. - lobby.require_tls = true ; Whether to reject connecting to the lobby if TLS encryption is unavailable. - lobby.verify_certificate = true ; Whether to reject connecting to the lobby if the TLS certificate is invalid. - lobby.xpartamupp = "xpartamupp23" ; Name of the server-side XMPP-account that manage games - lobby.echelon = "echelon23" ; Name of the server-side XMPP-account that manages ratings - ``` - - If you disabled TLS encryption, set `require_tls` to `false`. - If you employed a self-signed certificate, set `verify_certificate` to `false`. - -### 5.2 Test the Multiplayer Lobby - -You should now be able to join the new multiplayer lobby with the Pyrogenesis client and play multiplayer matches. - -* To confirm that the match hosting works as intended, create two user accounts, host a game with one, join the game with the other account. - -* To confirm that the rating service works as intended, resign a rated 1v1 match with two accounts. - -### 5.3 Terms and Conditions - -Players joining public servers are subject to Terms and Conditions of the service provider and subject to privacy laws such as GDPR. -If you intend to use the server only for local testing, you may skip this step. - -* The following files should be created by the service provider: - - `Terms_of_Service.txt` to explain the service and the contract. - `Terms_of_Use.txt` to explain what the user should and should not do. - `Privacy_Policy.txt` to explain how personal data is handled. - -* To use Wildfire Games Terms as a template, obtain our Terms from a copy of the game or from or from - - -* Replace all occurrences of `Wildfire Games` in the files with the one providing the new server. - -* Update the `Terms_of_Use.txt` depending on which behavior you would like to (not) see on your service. - -* Update the `Privacy_Policy.txt` depending on the user data processing in relation to the usage policies. -Make sure to not violate privacy laws such as GDPR or COPPA while doing so. - -* The retention times of ejabberd logs are relevant to GDPR. -Visit for details. - -* The terms should be published online, so users can save and print them. - Add to your `local.cfg`: - - ``` - lobby.terms_url = "https://lobby.wildfiregames.com/terms/"; Allows the user to save the text and print the terms - ``` - -### 5.4 Distribute the configuration - -To make this a public server, distribute your `local.cfg`, `Terms_of_Service.txt`, `Terms_of_Use.txt`, `Privacy_Policy.txt`. - -It may be advisable to create a mod with a modified `default.cfg` and the new terms documents, -see . - -Congratulations, you are now running a custom Pyrogenesis Multiplayer Lobby! diff -Nru 0ad-0.0.25b/source/tools/lobbybots/requirements.txt 0ad-0.0.26/source/tools/lobbybots/requirements.txt --- 0ad-0.0.25b/source/tools/lobbybots/requirements.txt 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/requirements.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -dnspython -sleekxmpp -sqlalchemy diff -Nru 0ad-0.0.25b/source/tools/lobbybots/setup.py 0ad-0.0.26/source/tools/lobbybots/setup.py --- 0ad-0.0.25b/source/tools/lobbybots/setup.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/setup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 - -"""setup.py for 0ad XMPP lobby bots.""" - -from setuptools import find_packages, setup - -setup( - name='XpartaMuPP', - version='0.24', - description='Multiplayer lobby bots for 0ad', - packages=find_packages(), - entry_points={ - 'console_scripts': [ - 'echelon=xpartamupp.echelon:main', - 'xpartamupp=xpartamupp.xpartamupp:main', - 'echelon-db=xpartamupp.lobby_ranking:main', - ] - }, - install_requires=[ - 'dnspython', - 'sleekxmpp', - 'sqlalchemy', - ], - tests_require=[ - 'coverage', - 'hypothesis', - 'parameterized', - ], - classifiers=[ - 'Development Status :: 3 - Alpha', - 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Games/Entertainment', - 'Topic :: Internet :: XMPP', - ], - zip_safe=False, - test_suite='tests', -) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/tests/test_echelon.py 0ad-0.0.26/source/tools/lobbybots/tests/test_echelon.py --- 0ad-0.0.25b/source/tools/lobbybots/tests/test_echelon.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/tests/test_echelon.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,176 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -# pylint: disable=no-self-use - -"""Tests for EcheLOn.""" - -import sys - -from argparse import Namespace -from unittest import TestCase -from unittest.mock import Mock, call, patch - -from parameterized import parameterized -from sleekxmpp.jid import JID -from sqlalchemy import create_engine - -from xpartamupp.echelon import main, parse_args, Leaderboard -from xpartamupp.lobby_ranking import Base - - -class TestLeaderboard(TestCase): - """Test Leaderboard functionality.""" - - def setUp(self): - """Set up a leaderboard instance.""" - db_url = 'sqlite://' - engine = create_engine(db_url) - Base.metadata.create_all(engine) - with patch('xpartamupp.echelon.create_engine') as create_engine_mock: - create_engine_mock.return_value = engine - self.leaderboard = Leaderboard(db_url) - - def test_create_player(self): - """Test creating a new player.""" - player = self.leaderboard.get_or_create_player(JID('john@localhost')) - self.assertEqual(player.id, 1) - self.assertEqual(player.jid, 'john@localhost') - self.assertEqual(player.rating, -1) - self.assertEqual(player.highest_rating, None) - self.assertEqual(player.games, []) - self.assertEqual(player.games_info, []) - self.assertEqual(player.games_won, []) - - def test_get_profile_no_player(self): - """Test profile retrieval fro not existing player.""" - profile = self.leaderboard.get_profile(JID('john@localhost')) - self.assertEqual(profile, dict()) - - def test_get_profile_player_without_games(self): - """Test profile retrieval for existing player.""" - self.leaderboard.get_or_create_player(JID('john@localhost')) - profile = self.leaderboard.get_profile(JID('john@localhost')) - self.assertDictEqual(profile, {'highestRating': None, 'losses': 0, 'totalGamesPlayed': 0, - 'wins': 0}) - - -class TestReportManager(TestCase): - """Test ReportManager functionality.""" - - pass - - -class TestArgumentParsing(TestCase): - """Test handling of parsing command line parameters.""" - - @parameterized.expand([ - ([], Namespace(domain='lobby.wildfiregames.com', login='EcheLOn', log_level=30, xserver=None, xdisabletls=False, - nickname='RatingsBot', password='XXXXXX', room='arena', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['--debug'], - Namespace(domain='lobby.wildfiregames.com', login='EcheLOn', log_level=10, xserver=None,xdisabletls=False, - nickname='RatingsBot', password='XXXXXX', room='arena', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['--quiet'], - Namespace(domain='lobby.wildfiregames.com', login='EcheLOn', log_level=40, xserver=None,xdisabletls=False, - nickname='RatingsBot', password='XXXXXX', room='arena', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['--verbose'], - Namespace(domain='lobby.wildfiregames.com', login='EcheLOn', log_level=20, xserver=None, xdisabletls=False, - nickname='RatingsBot', password='XXXXXX', room='arena', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['-m', 'lobby.domain.tld'], - Namespace(domain='lobby.domain.tld', login='EcheLOn', log_level=30, nickname='RatingsBot', xserver=None, xdisabletls=False, - password='XXXXXX', room='arena', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['--domain=lobby.domain.tld'], - Namespace(domain='lobby.domain.tld', login='EcheLOn', log_level=30, nickname='RatingsBot', xserver=None, xdisabletls=False, - password='XXXXXX', room='arena', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['-m' 'lobby.domain.tld', '-l', 'bot', '-p', '123456', '-n', 'Bot', '-r', 'arena123', - '-v'], - Namespace(domain='lobby.domain.tld', login='bot', log_level=20, nickname='Bot', xserver=None, xdisabletls=False, - password='123456', room='arena123', - database_url='sqlite:///lobby_rankings.sqlite3')), - (['--domain=lobby.domain.tld', '--login=bot', '--password=123456', '--nickname=Bot', - '--room=arena123', '--database-url=sqlite:////tmp/db.sqlite3', '--verbose'], - Namespace(domain='lobby.domain.tld', login='bot', log_level=20, nickname='Bot', xserver=None, xdisabletls=False, - password='123456', room='arena123', - database_url='sqlite:////tmp/db.sqlite3')), - ]) - def test_valid(self, cmd_args, expected_args): - """Test valid parameter combinations.""" - self.assertEqual(parse_args(cmd_args), expected_args) - - @parameterized.expand([ - (['-f'],), - (['--foo'],), - (['--debug', '--quiet'],), - (['--quiet', '--verbose'],), - (['--debug', '--verbose'],), - (['--debug', '--quiet', '--verbose'],), - ]) - def test_invalid(self, cmd_args): - """Test invalid parameter combinations.""" - with self.assertRaises(SystemExit): - parse_args(cmd_args) - - -class TestMain(TestCase): - """Test main method.""" - - def test_success(self): - """Test successful execution.""" - with patch('xpartamupp.echelon.parse_args') as args_mock, \ - patch('xpartamupp.echelon.Leaderboard') as leaderboard_mock, \ - patch('xpartamupp.echelon.EcheLOn') as xmpp_mock: - args_mock.return_value = Mock(log_level=30, login='EcheLOn', - domain='lobby.wildfiregames.com', password='XXXXXX', - room='arena', nickname='RatingsBot', - database_url='sqlite:///lobby_rankings.sqlite3', - xserver=None, xdisabletls=False) - main() - args_mock.assert_called_once_with(sys.argv[1:]) - leaderboard_mock.assert_called_once_with('sqlite:///lobby_rankings.sqlite3') - xmpp_mock().register_plugin.assert_has_calls([call('xep_0004'), call('xep_0030'), - call('xep_0045'), call('xep_0060'), - call('xep_0199', {'keepalive': True})], - any_order=True) - xmpp_mock().connect.assert_called_once_with(None, True, True) - xmpp_mock().process.assert_called_once_with() - - def test_failing_connect(self): - """Test failing connect to XMPP server.""" - with patch('xpartamupp.echelon.parse_args') as args_mock, \ - patch('xpartamupp.echelon.Leaderboard') as leaderboard_mock, \ - patch('xpartamupp.echelon.EcheLOn') as xmpp_mock: - args_mock.return_value = Mock(log_level=30, login='EcheLOn', - domain='lobby.wildfiregames.com', password='XXXXXX', - room='arena', nickname='RatingsBot', - database_url='sqlite:///lobby_rankings.sqlite3', - xserver=None, xdisabletls=False) - - xmpp_mock().connect.return_value = False - main() - args_mock.assert_called_once_with(sys.argv[1:]) - leaderboard_mock.assert_called_once_with('sqlite:///lobby_rankings.sqlite3') - xmpp_mock().register_plugin.assert_has_calls([call('xep_0004'), call('xep_0030'), - call('xep_0045'), call('xep_0060'), - call('xep_0199', {'keepalive': True})], - any_order=True) - xmpp_mock().connect.assert_called_once_with(None, True, True) - xmpp_mock().process.assert_not_called() diff -Nru 0ad-0.0.25b/source/tools/lobbybots/tests/test_elo.py 0ad-0.0.26/source/tools/lobbybots/tests/test_elo.py --- 0ad-0.0.25b/source/tools/lobbybots/tests/test_elo.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/tests/test_elo.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""Tests for the ELO-implementation.""" - -from unittest import TestCase - -from hypothesis import assume, example, given -from hypothesis import strategies as st -from parameterized import parameterized - -from xpartamupp.elo import (get_rating_adjustment, ANTI_INFLATION, ELO_K_FACTOR_CONSTANT_RATING, - ELO_SURE_WIN_DIFFERENCE, VOLATILITY_CONSTANT) - - -class TestELO(TestCase): - """Test behavior of ELO calculation.""" - - @parameterized.expand([ - ([1000, 1000, 0, 0, 1], 82), - ([1000, 1000, 0, 0, -1], -83), - ([1000, 1000, 0, 0, 0], 0), - ([1200, 1200, 0, 0, 1], 78), - ([1200, 1200, 0, 0, -1], -78), - ([1200, 1200, 0, 0, 0], 0), - ([1200, 1200, 1, 0, 1], 65), - ([1200, 1200, 1, 0, 0], 0), - ([1200, 1200, 1, 0, -1], -65), - ([1200, 1200, 100, 0, 1], 16), - ([1200, 1200, 100, 0, 0], 0), - ([1200, 1200, 100, 0, -1], -16), - ([1200, 1200, 1000, 0, 1], 16), - ([1200, 1200, 1000, 0, 0], 0), - ([1200, 1200, 1000, 0, -1], -16), - ([1200, 1200, 0, 1, 1], 78), - ([1200, 1200, 0, 1, 0], 0), - ([1200, 1200, 0, 1, -1], -78), - ([1200, 1200, 0, 100, 1], 78), - ([1200, 1200, 0, 100, 0], 0), - ([1200, 1200, 0, 100, -1], -78), - ([1200, 1200, 0, 1000, 1], 78), - ([1200, 1200, 0, 1000, 0], 0), - ([1200, 1200, 0, 1000, -1], -78), - ([1400, 1000, 0, 0, 1], 24), - ([1400, 1000, 0, 0, 0], -49), - ([1400, 1000, 0, 0, -1], -122), - ([1000, 1400, 0, 0, 1], 137), - ([1000, 1400, 0, 0, 0], 55), - ([1000, 1400, 0, 0, -1], -28), - ([2200, 2300, 0, 0, 1], 70), - ([2200, 2300, 0, 0, 0], 10), - ([2200, 2300, 0, 0, -1], -50), - ]) - def test_valid_adjustments(self, args, expected_adjustment): - """Test correctness of valid rating adjustments.""" - self.assertEqual(get_rating_adjustment(*args), expected_adjustment) - - @given(st.integers(min_value=ELO_K_FACTOR_CONSTANT_RATING), - st.integers(min_value=-2099, max_value=ELO_SURE_WIN_DIFFERENCE - 1), st.integers(), - st.integers(), - st.integers(min_value=-1, max_value=1)) - @example(ELO_K_FACTOR_CONSTANT_RATING + 300, 0, 0, 0, 1) - def test_constant_rating(self, rating_player1, difference_player2, played_games_player1, - played_games_player2, result): - """Test that points gained are constant above a threshold.""" - volatility = 50.0 * (min(max(0, played_games_player1), VOLATILITY_CONSTANT) / - VOLATILITY_CONSTANT + 0.25) / 1.25 - rating_adjustment = (difference_player2 + result * ELO_SURE_WIN_DIFFERENCE) / volatility \ - - ANTI_INFLATION - if result == 1: - expected_adjustment = max(0.0, rating_adjustment) - elif result == -1: - expected_adjustment = min(0.0, rating_adjustment) - else: - expected_adjustment = rating_adjustment - - self.assertEqual(get_rating_adjustment(rating_player1, rating_player1 + difference_player2, - played_games_player1, played_games_player2, result), - round(expected_adjustment)) - - @given(st.data()) - def test_sure_win(self, data): - """Test behavior if winning player 1 has >600 points more. - - In this case the winning player shouldn't gain points, as it - was a "sure win" and the loosing player shouldn't loose - points. - """ - rating_player1 = data.draw(st.integers(min_value=-1599)) - difference_player2 = data.draw(st.integers(min_value=ELO_SURE_WIN_DIFFERENCE)) - assume(rating_player1 - difference_player2 > -2200) - played_games_player1 = data.draw(st.integers()) - played_games_player2 = data.draw(st.integers()) - - self.assertEqual(get_rating_adjustment(rating_player1, - rating_player1 - difference_player2, - played_games_player1, played_games_player2, 1), - 0) - self.assertEqual(get_rating_adjustment(rating_player1 - difference_player2, - rating_player1, played_games_player2, - played_games_player1, -1), 0) - - @given(st.integers(min_value=-2199), st.integers(min_value=ELO_SURE_WIN_DIFFERENCE), - st.integers(), - st.integers()) - @example(1000, ELO_SURE_WIN_DIFFERENCE, 0, 0) - def test_sure_loss(self, rating_player1, difference_player2, played_games_player1, - played_games_player2): - """Test behavior if winning player 2 has >600 points more. - - In this case the winning player shouldn't gain points, as it - was a "sure win" and the loosing player shouldn't loose - points. - """ - self.assertEqual(get_rating_adjustment(rating_player1, - rating_player1 - difference_player2 * -1, - played_games_player1, played_games_player2, -1), - 0) - self.assertEqual(get_rating_adjustment(rating_player1 - difference_player2 * -1, - rating_player1, played_games_player2, - played_games_player1, 1), 0) - - @given(st.integers(max_value=-2200), st.integers(), - st.integers(), - st.integers(), - st.one_of(st.just(1), st.just(-1))) - @example(-2200, 2000, 0, 0, 1) - @example(2000, -2200, 0, 0, 1) - def test_minus_2200_bug_workaround(self, rating_player1, rating_player2, - played_games_player1, played_games_player2, result): - """Test workaround for -2200 bug.""" - with self.assertRaises(ValueError): - get_rating_adjustment(rating_player1, rating_player2, played_games_player1, - played_games_player2, result) - with self.assertRaises(ValueError): - get_rating_adjustment(rating_player2, rating_player1, played_games_player1, - played_games_player2, result) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/tests/test_lobby_ranking.py 0ad-0.0.26/source/tools/lobbybots/tests/test_lobby_ranking.py --- 0ad-0.0.25b/source/tools/lobbybots/tests/test_lobby_ranking.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/tests/test_lobby_ranking.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -# pylint: disable=no-self-use - -"""Tests for the database schema.""" - -import sys - -from argparse import Namespace -from unittest import TestCase -from unittest.mock import Mock, patch - -from parameterized import parameterized - -from xpartamupp.lobby_ranking import main, parse_args - - -class TestArgumentParsing(TestCase): - """Test handling of parsing command line parameters.""" - - @parameterized.expand([ - (['create'], Namespace(action='create', database_url='sqlite:///lobby_rankings.sqlite3')), - (['--database-url', 'sqlite:////tmp/db.sqlite3', 'create'], - Namespace(action='create', database_url='sqlite:////tmp/db.sqlite3')), - ]) - def test_valid(self, cmd_args, expected_args): - """Test valid parameter combinations.""" - self.assertEqual(parse_args(cmd_args), expected_args) - - @parameterized.expand([ - ([],), - (['--database-url=sqlite:////tmp/db.sqlite3'],), - ]) - def test_missing_action(self, cmd_args): - """Test invalid parameter combinations.""" - with self.assertRaises(SystemExit): - parse_args(cmd_args) - - -class TestMain(TestCase): - """Test main method.""" - - def test_success(self): - """Test successful execution.""" - with patch('xpartamupp.lobby_ranking.parse_args') as args_mock, \ - patch('xpartamupp.lobby_ranking.create_engine') as create_engine_mock, \ - patch('xpartamupp.lobby_ranking.Base') as declarative_base_mock: - args_mock.return_value = Mock(action='create', - database_url='sqlite:///lobby_rankings.sqlite3') - engine_mock = Mock() - create_engine_mock.return_value = engine_mock - main() - args_mock.assert_called_once_with(sys.argv[1:]) - create_engine_mock.assert_called_once_with( - 'sqlite:///lobby_rankings.sqlite3') - declarative_base_mock.metadata.create_all.assert_any_call(engine_mock) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/tests/test_utils.py 0ad-0.0.26/source/tools/lobbybots/tests/test_utils.py --- 0ad-0.0.25b/source/tools/lobbybots/tests/test_utils.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/tests/test_utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""Tests for utility functions.""" - -from unittest import TestCase - -from hypothesis import given -from hypothesis import strategies as st - -from xpartamupp.utils import LimitedSizeDict - - -class TestLimitedSizeDict(TestCase): - """Test limited size dict.""" - - @given(st.integers(min_value=2, max_value=2**10)) - def test_max_items(self, size_limit): - """Test max items of dicts. - - Test that the dict doesn't grow indefinitely and that the - oldest entries are removed first. - """ - test_dict = LimitedSizeDict(size_limit=size_limit) - for i in range(size_limit): - test_dict[i] = i - self.assertEqual(size_limit, len(test_dict)) - test_dict[size_limit + 1] = size_limit + 1 - self.assertEqual(size_limit, len(test_dict)) - self.assertFalse(0 in test_dict.values()) - self.assertTrue(1 in test_dict.values()) - self.assertTrue(size_limit + 1 in test_dict.values()) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/tests/test_xpartamupp.py 0ad-0.0.26/source/tools/lobbybots/tests/test_xpartamupp.py --- 0ad-0.0.25b/source/tools/lobbybots/tests/test_xpartamupp.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/tests/test_xpartamupp.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -# pylint: disable=no-self-use - -"""Tests for XPartaMuPP.""" - -import sys - -from argparse import Namespace -from unittest import TestCase -from unittest.mock import Mock, call, patch - -from parameterized import parameterized -from sleekxmpp.jid import JID - -from xpartamupp.xpartamupp import Games, main, parse_args - - -class TestGames(TestCase): - """Test Games class responsible for holding active games.""" - - def test_add(self): - """Test successfully adding a game.""" - games = Games() - jid = JID(jid='player1@domain.tld') - # TODO: Check how the real format of data looks like - game_data = {'players': ['player1', 'player2'], 'nbp': 'foo', 'state': 'init'} - self.assertTrue(games.add_game(jid, game_data)) - all_games = games.get_all_games() - game_data.update({'players-init': game_data['players'], 'nbp-init': game_data['nbp'], - 'state': game_data['state']}) - self.assertDictEqual(all_games, {jid: game_data}) - - @parameterized.expand([ - ('', {}), - ('player1@domain.tld', {}), - ('player1@domain.tld', None), - ('player1@domain.tld', ''), - ]) - def test_add_invalid(self, jid, game_data): - """Test trying to add games with invalid data.""" - games = Games() - self.assertFalse(games.add_game(jid, game_data)) - - def test_remove(self): - """Test removal of games.""" - games = Games() - jid1 = JID(jid='player1@domain.tld') - jid2 = JID(jid='player3@domain.tld') - # TODO: Check how the real format of data looks like - game_data1 = {'players': ['player1', 'player2'], 'nbp': 'foo', 'state': 'init'} - games.add_game(jid1, game_data1) - game_data2 = {'players': ['player3', 'player4'], 'nbp': 'bar', 'state': 'init'} - games.add_game(jid2, game_data2) - game_data1.update({'players-init': game_data1['players'], 'nbp-init': game_data1['nbp'], - 'state': game_data1['state']}) - game_data2.update({'players-init': game_data2['players'], 'nbp-init': game_data2['nbp'], - 'state': game_data2['state']}) - self.assertDictEqual(games.get_all_games(), {jid1: game_data1, jid2: game_data2}) - games.remove_game(jid1) - self.assertDictEqual(games.get_all_games(), {jid2: game_data2}) - games.remove_game(jid2) - self.assertDictEqual(games.get_all_games(), dict()) - - def test_remove_unknown(self): - """Test removal of a game, which doesn't exist.""" - games = Games() - jid = JID(jid='player1@domain.tld') - # TODO: Check how the real format of data looks like - game_data = {'players': ['player1', 'player2'], 'nbp': 'foo', 'state': 'init'} - games.add_game(jid, game_data) - self.assertFalse(games.remove_game(JID('foo@bar.tld'))) - - def test_change_state(self): - """Test state changes of a games.""" - pass - # slightly unknown how to do that properly, as some data structures aren't known - - -class TestArgumentParsing(TestCase): - """Test handling of parsing command line parameters.""" - - @parameterized.expand([ - ([], Namespace(domain='lobby.wildfiregames.com', login='xpartamupp', log_level=30, xserver=None, xdisabletls=False, - nickname='WFGBot', password='XXXXXX', room='arena')), - (['--debug'], - Namespace(domain='lobby.wildfiregames.com', login='xpartamupp', log_level=10, xserver=None, xdisabletls=False, - nickname='WFGBot', password='XXXXXX', room='arena')), - (['--quiet'], - Namespace(domain='lobby.wildfiregames.com', login='xpartamupp', log_level=40, xserver=None, xdisabletls=False, - nickname='WFGBot', password='XXXXXX', room='arena')), - (['--verbose'], - Namespace(domain='lobby.wildfiregames.com', login='xpartamupp', log_level=20, xserver=None, xdisabletls=False, - nickname='WFGBot', password='XXXXXX', room='arena')), - (['-m', 'lobby.domain.tld'], - Namespace(domain='lobby.domain.tld', login='xpartamupp', log_level=30, nickname='WFGBot', xserver=None, xdisabletls=False, - password='XXXXXX', room='arena')), - (['--domain=lobby.domain.tld'], - Namespace(domain='lobby.domain.tld', login='xpartamupp', log_level=30, nickname='WFGBot', xserver=None, xdisabletls=False, - password='XXXXXX', room='arena')), - (['-m' 'lobby.domain.tld', '-l', 'bot', '-p', '123456', '-n', 'Bot', '-r', 'arena123', - '-v'], - Namespace(domain='lobby.domain.tld', login='bot', log_level=20, xserver=None, xdisabletls=False, - nickname='Bot', password='123456', room='arena123')), - (['--domain=lobby.domain.tld', '--login=bot', '--password=123456', '--nickname=Bot', - '--room=arena123', '--verbose'], - Namespace(domain='lobby.domain.tld', login='bot', log_level=20, xserver=None, xdisabletls=False, - nickname='Bot', password='123456', room='arena123')), - ]) - def test_valid(self, cmd_args, expected_args): - """Test valid parameter combinations.""" - self.assertEqual(parse_args(cmd_args), expected_args) - - @parameterized.expand([ - (['-f'],), - (['--foo'],), - (['--debug', '--quiet'],), - (['--quiet', '--verbose'],), - (['--debug', '--verbose'],), - (['--debug', '--quiet', '--verbose'],), - ]) - def test_invalid(self, cmd_args): - """Test invalid parameter combinations.""" - with self.assertRaises(SystemExit): - parse_args(cmd_args) - - -class TestMain(TestCase): - """Test main method.""" - - def test_success(self): - """Test successful execution.""" - with patch('xpartamupp.xpartamupp.parse_args') as args_mock, \ - patch('xpartamupp.xpartamupp.XpartaMuPP') as xmpp_mock: - args_mock.return_value = Mock(log_level=30, login='xpartamupp', - domain='lobby.wildfiregames.com', password='XXXXXX', - room='arena', nickname='WFGBot', - xserver=None, xdisabletls=False) - main() - args_mock.assert_called_once_with(sys.argv[1:]) - xmpp_mock().register_plugin.assert_has_calls([call('xep_0004'), call('xep_0030'), - call('xep_0045'), call('xep_0060'), - call('xep_0199', {'keepalive': True})], - any_order=True) - xmpp_mock().connect.assert_called_once_with(None, True, True) - xmpp_mock().process.assert_called_once_with() - - def test_failing_connect(self): - """Test failing connect to XMPP server.""" - with patch('xpartamupp.xpartamupp.parse_args') as args_mock, \ - patch('xpartamupp.xpartamupp.XpartaMuPP') as xmpp_mock: - args_mock.return_value = Mock(log_level=30, login='xpartamupp', - domain='lobby.wildfiregames.com', password='XXXXXX', - room='arena', nickname='WFGBot', - xserver=None, xdisabletls=False) - - xmpp_mock().connect.return_value = False - main() - args_mock.assert_called_once_with(sys.argv[1:]) - xmpp_mock().register_plugin.assert_has_calls([call('xep_0004'), call('xep_0030'), - call('xep_0045'), call('xep_0060'), - call('xep_0199', {'keepalive': True})], - any_order=True) - xmpp_mock().connect.assert_called_once_with(None, True, True) - xmpp_mock().process.assert_not_called() diff -Nru 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/echelon.py 0ad-0.0.26/source/tools/lobbybots/xpartamupp/echelon.py --- 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/echelon.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/xpartamupp/echelon.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,803 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""0ad XMPP-bot responsible for managing game ratings.""" - -import argparse -import difflib -import logging -import sys -from collections import deque - -import sleekxmpp -from sleekxmpp.stanza import Iq -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream.stanzabase import register_stanza_plugin -from sqlalchemy import create_engine, func -from sqlalchemy.orm import scoped_session, sessionmaker - -from xpartamupp.elo import get_rating_adjustment -from xpartamupp.lobby_ranking import Game, Player, PlayerInfo -from xpartamupp.stanzas import (BoardListXmppPlugin, GameReportXmppPlugin, ProfileXmppPlugin) -from xpartamupp.utils import LimitedSizeDict - -# Rating that new players should be inserted into the -# database with, before they've played any games. -LEADERBOARD_DEFAULT_RATING = 1200 - - -class Leaderboard(object): - """Class that provides and manages leaderboard data.""" - - def __init__(self, db_url): - """Initialize the leaderboard.""" - self.rating_messages = deque() - - engine = create_engine(db_url) - session_factory = sessionmaker(bind=engine) - self.db = scoped_session(session_factory) - - def get_or_create_player(self, jid): - """Get a player from the leaderboard database. - - Get player information from the leaderboard database and - create him first, if he doesn't exist yet. - - Arguments: - jid (sleekxmpp.jid.JID): JID of the player to get - - Returns: - Player instance representing the player specified by the - supplied JID - - """ - player = self.db.query(Player).filter(Player.jid.ilike(str(jid))).first() - if player: - return player - - player = Player(jid=str(jid), rating=-1) - self.db.add(player) - self.db.commit() - logging.debug("Created player %s", jid) - return player - - def get_profile(self, jid): - """Get the leaderboard profile for the specified player. - - Arguments: - jid (sleekxmpp.jid.JID): JID of the player to retrieve the - profile for - - Returns: - dict with statistics about the requested player or None if - the player isn't known - - """ - stats = {} - player = self.db.query(Player).filter(Player.jid.ilike(str(jid))).first() - - if not player: - logging.debug("Couldn't find profile for player %s", jid) - return {} - - if player.rating != -1: - stats['rating'] = player.rating - rank = self.db.query(Player).filter(Player.rating >= player.rating).count() - stats['rank'] = rank - - if player.highest_rating != -1: - stats['highestRating'] = player.highest_rating - - games_played = self.db.query(PlayerInfo).filter_by(player_id=player.id).count() - wins = self.db.query(Game).filter_by(winner_id=player.id).count() - stats['totalGamesPlayed'] = games_played - stats['wins'] = wins - stats['losses'] = games_played - wins - return stats - - def _add_game(self, game_report): # pylint: disable=too-many-locals - """Add a game to the database. - - Add a game to the database and update the data on a - player from game results. - - Arguments: - game_report (dict): a report about a game - - Returns: - Game object for the created game or None if the creation - failed for any reason. - - """ - # Discard any games still in progress. We shouldn't get - # reports from those games anyway. - if 'active' in dict.values(game_report['playerStates']): - logging.warning("Received a game report for an unfinished game") - return None - - players = self.db.query(Player).filter(func.lower(Player.jid).in_( - dict.keys(game_report['playerStates']))) - - winning_jid = [jid for jid, state in game_report['playerStates'].items() - if state == 'won'][0] - - # single_stats = {'timeElapsed', 'mapName', 'teamsLocked', 'matchID'} - total_score_stats = {'economyScore', 'militaryScore', 'totalScore'} - resource_stats = {'foodGathered', 'foodUsed', 'woodGathered', 'woodUsed', 'stoneGathered', - 'stoneUsed', 'metalGathered', 'metalUsed', 'vegetarianFoodGathered', - 'treasuresCollected', 'lootCollected', 'tributesSent', - 'tributesReceived'} - units_stats = {'totalUnitsTrained', 'totalUnitsLost', 'enemytotalUnitsKilled', - 'infantryUnitsTrained', 'infantryUnitsLost', 'enemyInfantryUnitsKilled', - 'workerUnitsTrained', 'workerUnitsLost', 'enemyWorkerUnitsKilled', - 'femaleCitizenUnitsTrained', 'femaleCitizenUnitsLost', - 'enemyFemaleCitizenUnitsKilled', 'cavalryUnitsTrained', 'cavalryUnitsLost', - 'enemyCavalryUnitsKilled', 'championUnitsTrained', 'championUnitsLost', - 'enemyChampionUnitsKilled', 'heroUnitsTrained', 'heroUnitsLost', - 'enemyHeroUnitsKilled', 'shipUnitsTrained', 'shipUnitsLost', - 'enemyShipUnitsKilled', 'traderUnitsTrained', 'traderUnitsLost', - 'enemyTraderUnitsKilled'} - buildings_stats = {'totalBuildingsConstructed', 'totalBuildingsLost', - 'enemytotalBuildingsDestroyed', 'civCentreBuildingsConstructed', - 'civCentreBuildingsLost', 'enemyCivCentreBuildingsDestroyed', - 'houseBuildingsConstructed', 'houseBuildingsLost', - 'enemyHouseBuildingsDestroyed', 'economicBuildingsConstructed', - 'economicBuildingsLost', 'enemyEconomicBuildingsDestroyed', - 'outpostBuildingsConstructed', 'outpostBuildingsLost', - 'enemyOutpostBuildingsDestroyed', 'militaryBuildingsConstructed', - 'militaryBuildingsLost', 'enemyMilitaryBuildingsDestroyed', - 'fortressBuildingsConstructed', 'fortressBuildingsLost', - 'enemyFortressBuildingsDestroyed', 'wonderBuildingsConstructed', - 'wonderBuildingsLost', 'enemyWonderBuildingsDestroyed'} - market_stats = {'woodBought', 'foodBought', 'stoneBought', 'metalBought', 'tradeIncome'} - misc_stats = {'civs', 'teams', 'percentMapExplored'} - - stats = total_score_stats | resource_stats | units_stats | buildings_stats | market_stats \ - | misc_stats - - player_infos = [] - for player in players: - player_jid = sleekxmpp.jid.JID(player.jid) - player_info = PlayerInfo(player=player) - for report_name in stats: - setattr(player_info, report_name, game_report[report_name][player_jid]) - player_infos.append(player_info) - - game = Game(map=game_report['mapName'], duration=int(game_report['timeElapsed']), - teamsLocked=bool(game_report['teamsLocked']), matchID=game_report['matchID']) - game.player_info.extend(player_infos) - game.winner = self.db.query(Player).filter(Player.jid.ilike(str(winning_jid))).first() - self.db.add(game) - self.db.commit() - return game - - @staticmethod - def _verify_game(game_report): - """Check whether or not the game should be rated. - - The criteria for rated games can be specified here. - - Arguments: - game_report (dict): a report about a game - - Returns: - True if the game should be rated, false otherwise. - - """ - winning_jids = [jid for jid, state in game_report['playerStates'].items() - if state == 'won'] - # We only support 1v1s right now. - if len(winning_jids) > 1 or len(dict.keys(game_report['playerStates'])) != 2: - return False - return True - - def _rate_game(self, game): - """Update player ratings based on game outcome. - - Take a game with 2 players and alters their ratings based on - the result of the game. - - Adjusts the players ratings in the database. - - Arguments: - game (Game): game to rate - """ - player1 = game.players[0] - player2 = game.players[1] - # Since it's impossible to draw in the game currently, the - # database model, and therefore this code, requires a winner. - # The Elo implementation does not, however. - result = 1 if player1 == game.winner else -1 - # Player's ratings are -1 unless they have played a rated game. - if player1.rating == -1: - player1.rating = LEADERBOARD_DEFAULT_RATING - if player2.rating == -1: - player2.rating = LEADERBOARD_DEFAULT_RATING - - try: - rating_adjustment1 = int(get_rating_adjustment(player1.rating, player2.rating, - len(player1.games), len(player2.games), - result)) - rating_adjustment2 = int(get_rating_adjustment(player2.rating, player1.rating, - len(player2.games), len(player1.games), - result * -1)) - except ValueError: - rating_adjustment1 = 0 - rating_adjustment2 = 0 - - if result == 1: - result_qualitative = 'won' - elif result == 0: - result_qualitative = 'drew' - else: - result_qualitative = 'lost' - name1 = sleekxmpp.jid.JID(player1.jid).local - name2 = sleekxmpp.jid.JID(player2.jid).local - self.rating_messages.append("A rated game has ended. %s %s against %s. Rating " - "Adjustment: %s (%s -> %s) and %s (%s -> %s)." % - (name1, result_qualitative, name2, name1, player1.rating, - player1.rating + rating_adjustment1, name2, player2.rating, - player2.rating + rating_adjustment2)) - player1.rating += rating_adjustment1 - player2.rating += rating_adjustment2 - if not player1.highest_rating: - player1.highest_rating = -1 - if not player2.highest_rating: - player2.highest_rating = -1 - player1.highest_rating = max(player1.rating, player1.highest_rating) - player2.highest_rating = max(player2.rating, player2.highest_rating) - self.db.commit() - - def get_rating_messages(self): - """Get messages announcing rated games. - - Returns: - list with the a messages about rated games - - """ - return self.rating_messages - - def add_and_rate_game(self, game_report): - """Add and rate a game. - - If the game has only two players, rate the game. - - Arguments: - game_report (dict): a report about a game - - Returns: - Game object - - """ - game = self._add_game(game_report) - if game and self._verify_game(game_report): - self._rate_game(game) - return game - - def get_board(self, limit=100): - """Return the ratings of the highest ranked players. - - Arguments: - limit (int): Number of players to return - - Returns: - dict with player JIDs, nicks and ratings - - """ - ratings = {} - players = self.db.query(Player).filter(Player.rating != -1) \ - .order_by(Player.rating.desc()).limit(limit) - for player in players: - ratings[player.jid] = {'name': sleekxmpp.jid.JID(player.jid).local, - 'rating': player.rating} - return ratings - - def get_rating_list(self, nicks): - """Return the ratings of all online players. - - The returned dictionary is by nick because the client can't - link JID to nick conveniently. - - Arguments: - nicks (dict): Players currently online - - Returns: - dict with player JIDs, nicks and ratings - - """ - ratings = {} - if nicks: - player_filter = func.lower(Player.jid).in_([str(jid).lower() for jid in list(nicks)]) - players = self.db.query(Player.jid, Player.rating).filter(player_filter) - for player in players: - rating = str(player.rating) if player.rating != -1 else '' - for jid in list(nicks): - if jid == sleekxmpp.jid.JID(player.jid): - ratings[nicks[str(jid)]] = {'name': nicks[jid], 'rating': rating} - break - return ratings - - -class ReportManager(object): - """Class which manages different game reports from clients. - - Calls leaderboard functions as appropriate. - """ - - def __init__(self, leaderboard): - """Initialize the report manager. - - Arguments: - leaderboard (Leaderboard): Leaderboard the manager is for - - """ - self.leaderboard = leaderboard - self.interim_report_tracker = LimitedSizeDict(size_limit=2**12) - - def add_report(self, jid, raw_game_report): - """Add a game to the interface between a raw report and the leaderboard database. - - Arguments: - jid (sleekxmpp.jid.JID): JID of the player who submitted - the report - raw_game_report (dict): Game report generated by 0ad - - """ - player_index = int(raw_game_report['playerID']) - 1 - del raw_game_report['playerID'] - match_id = raw_game_report['matchID'] - if match_id not in self.interim_report_tracker: - self.interim_report_tracker[match_id] = { - 'report': raw_game_report, - 'jids': {player_index: str(jid)} - } - else: - current_match = self.interim_report_tracker[match_id] - if raw_game_report != current_match['report']: - report_diff = self._get_report_diff(raw_game_report, current_match['report']) - logging.warning("Retrieved reports for match %s differ:\n %s", match_id, - report_diff) - return - - player_jids = current_match['jids'] - if player_index in player_jids: - if player_jids[player_index] == jid: - logging.warning("Received a report for match %s from player %s twice.", - match_id, jid) - else: - logging.warning("Retrieved a report for match %s for the same player twice, " - "but from two different XMPP accounts: %s vs. %s", match_id, - player_jids[player_index], jid) - return - else: - player_jids[player_index] = str(jid) - - num_players = self._get_num_players(raw_game_report) - num_retrieved_reports = len(player_jids) - if num_retrieved_reports == num_players: - try: - self.leaderboard.add_and_rate_game(self._expand_report( - current_match)) - except Exception: - logging.exception("Failed to add and rate a game.") - del current_match - elif num_retrieved_reports < num_players: - logging.warning("Haven't received all reports for the game yet. %i/%i", - num_retrieved_reports, num_players) - elif num_retrieved_reports > num_players: - logging.warning("Retrieved more reports than players. This shouldn't happen.") - - @staticmethod - def _expand_report(game_report): - """Re-formats a game report into Python data structures. - - Player specific values from the report are replaced with a - dict where the JID of the player is the key. - - Arguments: - game_report (dict): wrapped game report from 0ad - - Returns a processed gameReport of type dict. - """ - processed_game_report = {} - for key, value in game_report['report'].items(): - if ',' not in value: - processed_game_report[key] = value - else: - stat_to_jid = {} - for i, part in enumerate(game_report['report'][key].split(",")[:-1]): - stat_to_jid[game_report['jids'][i]] = part - processed_game_report[key] = stat_to_jid - return processed_game_report - - @staticmethod - def _get_num_players(raw_game_report): - """Compute the number of players from a raw game report. - - Get the number of players who played a game from the - playerStates field in a raw game report. - - Arguments: - raw_game_report (dict): Game report generated by 0ad - - Returns: - int with the number of players in the game - - Raises: - ValueError if the number of players couldn't be determined - - """ - if 'playerStates' in raw_game_report and ',' in raw_game_report['playerStates']: - return len(list(filter(None, raw_game_report['playerStates'].split(",")))) - raise ValueError() - - @staticmethod - def _get_report_diff(report1, report2): - """Get differences between two reports. - - Arguments: - report1 (dict): Game report - report2 (dict): Game report - - Returns: - str with a textual representation of the differences - between the two reports - - """ - report1_list = ['{ %s: %s }' % (key, value) for key, value in report1.items()] - report2_list = ['{ %s: %s }' % (key, value) for key, value in report2.items()] - return '\n'.join(difflib.ndiff(report1_list, report2_list)) - - -class EcheLOn(sleekxmpp.ClientXMPP): - """Main class which handles IQ data and sends new data.""" - - def __init__(self, sjid, password, room, nick, leaderboard): - """Initialize EcheLOn.""" - sleekxmpp.ClientXMPP.__init__(self, sjid, password) - self.whitespace_keepalive = False - - self.sjid = sleekxmpp.jid.JID(sjid) - self.room = room - self.nick = nick - - self.leaderboard = leaderboard - self.report_manager = ReportManager(self.leaderboard) - - register_stanza_plugin(Iq, BoardListXmppPlugin) - register_stanza_plugin(Iq, GameReportXmppPlugin) - register_stanza_plugin(Iq, ProfileXmppPlugin) - - self.register_handler(Callback('Iq Boardlist', StanzaPath('iq@type=get/boardlist'), - self._iq_board_list_handler)) - self.register_handler(Callback('Iq GameReport', StanzaPath('iq@type=set/gamereport'), - self._iq_game_report_handler)) - self.register_handler(Callback('Iq Profile', StanzaPath('iq@type=get/profile'), - self._iq_profile_handler)) - - self.add_event_handler('session_start', self._session_start) - self.add_event_handler('muc::%s::got_online' % self.room, self._muc_online) - self.add_event_handler('muc::%s::got_offline' % self.room, self._muc_offline) - self.add_event_handler('groupchat_message', self._muc_message) - - def _session_start(self, event): # pylint: disable=unused-argument - """Join MUC channel and announce presence. - - Arguments: - event (dict): empty dummy dict - - """ - self.plugin['xep_0045'].joinMUC(self.room, self.nick) - self.send_presence() - self.get_roster() - logging.info("EcheLOn started") - - def _muc_online(self, presence): - """Add joining players to the list of players. - - Arguments: - presence (sleekxmpp.stanza.presence.Presence): Received - presence stanza. - - """ - nick = str(presence['muc']['nick']) - jid = sleekxmpp.jid.JID(presence['muc']['jid']) - - if nick == self.nick: - return - - if jid.resource != '0ad': - return - - self.leaderboard.get_or_create_player(jid) - - self._broadcast_rating_list() - - logging.debug("Client '%s' connected with a nick of '%s'.", jid, nick) - - def _muc_offline(self, presence): - """Remove leaving players from the list of players. - - Arguments: - presence (sleekxmpp.stanza.presence.Presence): Received - presence stanza. - - """ - nick = str(presence['muc']['nick']) - jid = sleekxmpp.jid.JID(presence['muc']['jid']) - - if nick == self.nick: - return - - logging.debug("Client '%s' with nick '%s' disconnected", jid, nick) - - def _muc_message(self, msg): - """Process messages in the MUC room. - - Respond to messages highlighting the bots name with an - informative message. - - Arguments: - msg (sleekxmpp.stanza.message.Message): Received MUC - message - """ - if msg['mucnick'] != self.nick and self.nick.lower() in msg['body'].lower(): - self.send_message(mto=msg['from'].bare, - mbody="I am just a bot and provide the rating functionality for " - "this lobby. Please don't disturb me, calculating these " - "ratings is already difficult enough.", - mtype='groupchat') - - def _iq_board_list_handler(self, iq): - """Handle incoming leaderboard list requests. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): Received IQ stanza - - """ - if iq['from'].resource not in ['0ad']: - return - - command = iq['boardlist']['command'] - self.leaderboard.get_or_create_player(iq['from']) - if command == 'getleaderboard': - try: - self._send_leaderboard(iq) - except Exception: - logging.exception("Failed to process get leaderboard request from %s", - iq['from'].bare) - elif command == 'getratinglist': - try: - self._send_rating_list(iq) - except Exception: - logging.exception("Failed to send the rating list to %s", iq['from']) - - def _iq_game_report_handler(self, iq): - """Handle end of game reports from clients. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): Received IQ stanza - - """ - if iq['from'].resource not in ['0ad']: - return - - try: - self.report_manager.add_report(iq['from'], iq['gamereport']['game']) - except Exception: - logging.exception("Failed to update game statistics for %s", iq['from'].bare) - - rating_messages = self.leaderboard.get_rating_messages() - if rating_messages: - while rating_messages: - message = rating_messages.popleft() - self.send_message(mto=self.room, mbody=message, mtype='groupchat', mnick=self.nick) - self._broadcast_rating_list() - - def _iq_profile_handler(self, iq): - """Handle profile requests from clients. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): Received IQ stanza - - """ - if iq['from'].resource not in ['0ad']: - return - - try: - self._send_profile(iq, iq['profile']['command']) - except Exception: - logging.exception("Failed to send profile about %s to %s", iq['profile']['command'], - iq['from'].bare) - - def _send_leaderboard(self, iq): - """Send the whole leaderboard. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): IQ stanza to reply to - - """ - ratings = self.leaderboard.get_board() - - iq = iq.reply(clear=True) - stanza = BoardListXmppPlugin() - stanza.add_command('boardlist') - for player in ratings.values(): - stanza.add_item(player['name'], player['rating']) - iq.set_payload(stanza) - - try: - iq.send(block=False) - except Exception: - logging.exception("Failed to send leaderboard to %s", iq['to']) - - def _send_rating_list(self, iq): - """Send the ratings of all online players. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): IQ stanza to reply to - - """ - nicks = {} - for nick in self.plugin['xep_0045'].getRoster(self.room): - if nick == self.nick: - continue - jid_str = self.plugin['xep_0045'].getJidProperty(self.room, nick, 'jid') - jid = sleekxmpp.jid.JID(jid_str) - nicks[jid] = nick - ratings = self.leaderboard.get_rating_list(nicks) - - iq = iq.reply(clear=True) - stanza = BoardListXmppPlugin() - stanza.add_command('ratinglist') - for player in ratings.values(): - stanza.add_item(player['name'], player['rating']) - iq.set_payload(stanza) - - try: - iq.send(block=False) - except Exception: - logging.exception("Failed to send rating list to %s", iq['to']) - - def _broadcast_rating_list(self): - """Broadcast the ratings of all online players.""" - nicks = {} - for nick in self.plugin['xep_0045'].getRoster(self.room): - if nick == self.nick: - continue - jid_str = self.plugin['xep_0045'].getJidProperty(self.room, nick, 'jid') - jid = sleekxmpp.jid.JID(jid_str) - nicks[jid] = nick - ratings = self.leaderboard.get_rating_list(nicks) - - stanza = BoardListXmppPlugin() - stanza.add_command('ratinglist') - for player in ratings.values(): - stanza.add_item(player['name'], player['rating']) - - for jid in nicks: - iq = self.make_iq_result(ito=jid) - iq.set_payload(stanza) - try: - iq.send(block=False) - except Exception: - logging.exception("Failed to send rating list to %s", jid) - - def _send_profile(self, iq, player_nick): - """Send the player profile to a specified target. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): IQ stanza to reply to - player_nick (str): The nick of the player to get the - profile for - - """ - jid_str = self.plugin['xep_0045'].getJidProperty(self.room, player_nick, 'jid') - player_jid = sleekxmpp.jid.JID(jid_str) if jid_str else None - - # The player the profile got requested for is not online, so - # let's assume the JID contains the nick as local part. - if not player_jid: - player_jid = sleekxmpp.jid.JID('%s@%s/%s' % (player_nick, self.sjid.domain, '0ad')) - - try: - stats = self.leaderboard.get_profile(player_jid) - except Exception: - logging.exception("Failed to get leaderboard profile for player %s", player_jid) - stats = {} - - iq = iq.reply(clear=True) - stanza = ProfileXmppPlugin() - if stats: - stanza.add_item(player_nick, stats['rating'], stats['highestRating'], - stats['rank'], stats['totalGamesPlayed'], stats['wins'], - stats['losses']) - else: - stanza.add_item(player_nick, -2) - stanza.add_command(player_nick) - iq.set_payload(stanza) - - try: - iq.send(block=False) - except Exception: - logging.exception("Failed to send profile to %s", iq['to']) - - -def parse_args(args): - """Parse command line arguments. - - Arguments: - args (dict): Raw command line arguments given to the script - - Returns: - Parsed command line arguments - - """ - parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description="EcheLOn - XMPP Rating Bot") - - log_settings = parser.add_mutually_exclusive_group() - log_settings.add_argument('-q', '--quiet', help="only log errors", action='store_const', - dest='log_level', const=logging.ERROR) - log_settings.add_argument('-d', '--debug', help="log debug messages", action='store_const', - dest='log_level', const=logging.DEBUG) - log_settings.add_argument('-v', '--verbose', help="log more informative messages", - action='store_const', dest='log_level', const=logging.INFO) - log_settings.set_defaults(log_level=logging.WARNING) - - parser.add_argument('-m', '--domain', help="XMPP server to connect to", - default='lobby.wildfiregames.com') - parser.add_argument('-l', '--login', help="username for login", default='EcheLOn') - parser.add_argument('-p', '--password', help="password for login", default='XXXXXX') - parser.add_argument('-n', '--nickname', help="nickname shown to players", default='RatingsBot') - parser.add_argument('-r', '--room', help="XMPP MUC room to join", default='arena') - parser.add_argument('--database-url', help="URL for the leaderboard database", - default='sqlite:///lobby_rankings.sqlite3') - parser.add_argument('-s', '--server', help='address of the ejabberd server', - action='store', dest='xserver', default=None) - parser.add_argument('-t', '--disable-tls', help='Pass this argument to connect without TLS encryption', - action='store_true', dest='xdisabletls', default=False) - - return parser.parse_args(args) - -def main(): - """Entry point a console script.""" - args = parse_args(sys.argv[1:]) - - logging.basicConfig(level=args.log_level, - format='%(asctime)s %(levelname)-8s %(message)s', - datefmt='%Y-%m-%d %H:%M:%S') - - leaderboard = Leaderboard(args.database_url) - xmpp = EcheLOn(sleekxmpp.jid.JID('%s@%s/%s' % (args.login, args.domain, 'CC')), args.password, - args.room + '@conference.' + args.domain, args.nickname, leaderboard) - xmpp.register_plugin('xep_0030') # Service Discovery - xmpp.register_plugin('xep_0004') # Data Forms - xmpp.register_plugin('xep_0045') # Multi-User Chat - xmpp.register_plugin('xep_0060') # Publish-Subscribe - xmpp.register_plugin('xep_0199', {'keepalive': True}) # XMPP Ping - - if xmpp.connect((args.xserver, 5222) if args.xserver else None, True, not args.xdisabletls): - xmpp.process() - else: - logging.error("Unable to connect") - - -if __name__ == '__main__': - main() diff -Nru 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/elo.py 0ad-0.0.26/source/tools/lobbybots/xpartamupp/elo.py --- 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/elo.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/xpartamupp/elo.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""Implementation of the ELO-rating algorithm for 0ad games.""" - -# Difference between two ratings such that it is regarded as a "sure -# win" for the higher player. No points are gained or lost for such a -# game. -ELO_SURE_WIN_DIFFERENCE = 600 - -# Lower ratings "move faster" and change more -# dramatically than higher ones. Anything rating above -# this value moves at the same rate as this value. -ELO_K_FACTOR_CONSTANT_RATING = 2200 - -# This preset number of games is the number of games where a player is -# considered "stable". Rating volatility is constant after this number. -VOLATILITY_CONSTANT = 20 - -# Fair rating adjustment loses against inflation. -# This constant will battle inflation. -# NOTE: This can be adjusted as needed by a bot/server administrator -ANTI_INFLATION = 0.015 - - -def get_rating_adjustment(rating, opponent_rating, games_played, - opponent_games_played, result): # pylint: disable=unused-argument - """Calculate the rating adjustment after rated 1v1 games. - - The rating adjustment is calculated using a simplified - ELO-algorithm. - - The given implementation doesn't work for negative ratings below - -2199. This is a known limitation which is currently considered - to be not relevant in day-to-day use. - - Arguments: - rating (int): Rating of the first player before the game. - opponent_rating (int): Rating of the second player before the - game. - games_played (int): Number of games the first player has played - before this game. - opponent_games_played (int): Number of games the second player - has played before this game. - result (int): 1 if the first player won, 0 if draw or -1 if the - second player won. - - Returns: - int: the adjustment which should be applied to the rating of - the first player - - """ - if rating < -2199 or opponent_rating < -2199: - raise ValueError('Too small rating given: rating: %i, opponent rating: %i' % - (rating, opponent_rating)) - - rating_k_factor = 50.0 * (min(rating, ELO_K_FACTOR_CONSTANT_RATING) / - ELO_K_FACTOR_CONSTANT_RATING + 1.0) / 2.0 - player_volatility = (min(max(0, games_played), VOLATILITY_CONSTANT) / - VOLATILITY_CONSTANT + 0.25) / 1.25 - volatility = rating_k_factor * player_volatility - rating_difference = opponent_rating - rating - rating_adjustment = (rating_difference + result * ELO_SURE_WIN_DIFFERENCE) / volatility - \ - ANTI_INFLATION - if result == 1: - return round(max(0.0, rating_adjustment)) - elif result == -1: - return round(min(0.0, rating_adjustment)) - return round(rating_adjustment) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/lobby_ranking.py 0ad-0.0.26/source/tools/lobbybots/xpartamupp/lobby_ranking.py --- 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/lobby_ranking.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/xpartamupp/lobby_ranking.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""Database schema used by the XMPP bots to store game information.""" - -import argparse -import sys - -from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, create_engine -from sqlalchemy.orm import relationship -from sqlalchemy.ext.declarative import declarative_base - -Base = declarative_base() - - -class Player(Base): - """Model representing players.""" - - __tablename__ = 'players' - - id = Column(Integer, primary_key=True) - jid = Column(String(255)) - rating = Column(Integer) - highest_rating = Column(Integer) - games = relationship('Game', secondary='players_info') - # These two relations really only exist to satisfy the linkage - # between PlayerInfo and Player and Game and player. - games_info = relationship('PlayerInfo', backref='player') - games_won = relationship('Game', backref='winner') - - -class PlayerInfo(Base): - """Model representing game results.""" - - __tablename__ = 'players_info' - - id = Column(Integer, primary_key=True) - player_id = Column(Integer, ForeignKey('players.id')) - game_id = Column(Integer, ForeignKey('games.id')) - civs = Column(String(20)) - teams = Column(Integer) - economyScore = Column(Integer) - militaryScore = Column(Integer) - totalScore = Column(Integer) - foodGathered = Column(Integer) - foodUsed = Column(Integer) - woodGathered = Column(Integer) - woodUsed = Column(Integer) - stoneGathered = Column(Integer) - stoneUsed = Column(Integer) - metalGathered = Column(Integer) - metalUsed = Column(Integer) - vegetarianFoodGathered = Column(Integer) - treasuresCollected = Column(Integer) - lootCollected = Column(Integer) - tributesSent = Column(Integer) - tributesReceived = Column(Integer) - totalUnitsTrained = Column(Integer) - totalUnitsLost = Column(Integer) - enemytotalUnitsKilled = Column(Integer) - infantryUnitsTrained = Column(Integer) - infantryUnitsLost = Column(Integer) - enemyInfantryUnitsKilled = Column(Integer) - workerUnitsTrained = Column(Integer) - workerUnitsLost = Column(Integer) - enemyWorkerUnitsKilled = Column(Integer) - femaleCitizenUnitsTrained = Column(Integer) - femaleCitizenUnitsLost = Column(Integer) - enemyFemaleCitizenUnitsKilled = Column(Integer) - cavalryUnitsTrained = Column(Integer) - cavalryUnitsLost = Column(Integer) - enemyCavalryUnitsKilled = Column(Integer) - championUnitsTrained = Column(Integer) - championUnitsLost = Column(Integer) - enemyChampionUnitsKilled = Column(Integer) - heroUnitsTrained = Column(Integer) - heroUnitsLost = Column(Integer) - enemyHeroUnitsKilled = Column(Integer) - shipUnitsTrained = Column(Integer) - shipUnitsLost = Column(Integer) - enemyShipUnitsKilled = Column(Integer) - traderUnitsTrained = Column(Integer) - traderUnitsLost = Column(Integer) - enemyTraderUnitsKilled = Column(Integer) - totalBuildingsConstructed = Column(Integer) - totalBuildingsLost = Column(Integer) - enemytotalBuildingsDestroyed = Column(Integer) - civCentreBuildingsConstructed = Column(Integer) - civCentreBuildingsLost = Column(Integer) - enemyCivCentreBuildingsDestroyed = Column(Integer) - houseBuildingsConstructed = Column(Integer) - houseBuildingsLost = Column(Integer) - enemyHouseBuildingsDestroyed = Column(Integer) - economicBuildingsConstructed = Column(Integer) - economicBuildingsLost = Column(Integer) - enemyEconomicBuildingsDestroyed = Column(Integer) - outpostBuildingsConstructed = Column(Integer) - outpostBuildingsLost = Column(Integer) - enemyOutpostBuildingsDestroyed = Column(Integer) - militaryBuildingsConstructed = Column(Integer) - militaryBuildingsLost = Column(Integer) - enemyMilitaryBuildingsDestroyed = Column(Integer) - fortressBuildingsConstructed = Column(Integer) - fortressBuildingsLost = Column(Integer) - enemyFortressBuildingsDestroyed = Column(Integer) - wonderBuildingsConstructed = Column(Integer) - wonderBuildingsLost = Column(Integer) - enemyWonderBuildingsDestroyed = Column(Integer) - woodBought = Column(Integer) - foodBought = Column(Integer) - stoneBought = Column(Integer) - metalBought = Column(Integer) - tradeIncome = Column(Integer) - percentMapExplored = Column(Integer) - - -class Game(Base): - """Model representing games.""" - - __tablename__ = 'games' - - id = Column(Integer, primary_key=True) - map = Column(String(80)) - duration = Column(Integer) - teamsLocked = Column(Boolean) - matchID = Column(String(20)) - winner_id = Column(Integer, ForeignKey('players.id')) - player_info = relationship('PlayerInfo', backref='game') - players = relationship('Player', secondary='players_info') - - -def parse_args(args): - """Parse command line arguments. - - Arguments: - args (dict): Raw command line arguments given to the script - - Returns: - Parsed command line arguments - - """ - parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description="Helper command for database creation") - parser.add_argument('action', help='Action to apply to the database', - choices=['create']) - parser.add_argument('--database-url', help='URL for the leaderboard database', - default='sqlite:///lobby_rankings.sqlite3') - return parser.parse_args(args) - - -def main(): - """Entry point a console script.""" - args = parse_args(sys.argv[1:]) - engine = create_engine(args.database_url) - if args.action == 'create': - Base.metadata.create_all(engine) - - -if __name__ == '__main__': - main() diff -Nru 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/stanzas.py 0ad-0.0.26/source/tools/lobbybots/xpartamupp/stanzas.py --- 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/stanzas.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/xpartamupp/stanzas.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""0ad-specific XMPP-stanzas.""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class BoardListXmppPlugin(ElementBase): - """Class for custom boardlist and ratinglist stanza extension.""" - - name = 'query' - namespace = 'jabber:iq:boardlist' - interfaces = {'board', 'command'} - sub_interfaces = interfaces - plugin_attrib = 'boardlist' - - def add_command(self, command): - """Add a command to the extension. - - Arguments: - command (str): Command to add - """ - self.xml.append(ET.fromstring('%s' % command)) - - def add_item(self, name, rating): - """Add an item to the extension. - - Arguments: - name (str): Name of the player to add - rating (int): Rating of the player to add - """ - self.xml.append(ET.Element('board', {'name': name, 'rating': str(rating)})) - - -class GameListXmppPlugin(ElementBase): - """Class for custom gamelist stanza extension.""" - - name = 'query' - namespace = 'jabber:iq:gamelist' - interfaces = {'game', 'command'} - sub_interfaces = interfaces - plugin_attrib = 'gamelist' - - def add_game(self, data): - """Add a game to the extension. - - Arguments: - data (dict): game data to add - """ - try: del data['ip'] # Don't send the IP address with the gamelist. - except: pass - - self.xml.append(ET.Element('game', data)) - - def get_game(self): - """Get game from stanza. - - Required to parse incoming stanzas with this extension. - - Returns: - dict with game data - - """ - game = self.xml.find('{%s}game' % self.namespace) - data = {} - - if game is not None: - for key, item in game.items(): - data[key] = item - return data - - -class GameReportXmppPlugin(ElementBase): - """Class for custom gamereport stanza extension.""" - - name = 'report' - namespace = 'jabber:iq:gamereport' - plugin_attrib = 'gamereport' - interfaces = 'game' - sub_interfaces = interfaces - - def add_game(self, game_report): - """Add a game to the extension. - - Arguments: - game_report (dict): a report about a game - - """ - self.xml.append(ET.fromstring(str(game_report)).find('{%s}game' % self.namespace)) - - def get_game(self): - """Get game from stanza. - - Required to parse incoming stanzas with this extension. - - Returns: - dict with game information - - """ - game = self.xml.find('{%s}game' % self.namespace) - data = {} - - if game is not None: - for key, item in game.items(): - data[key] = item - return data - - -class ProfileXmppPlugin(ElementBase): - """Class for custom profile.""" - - name = 'query' - namespace = 'jabber:iq:profile' - interfaces = {'profile', 'command'} - sub_interfaces = interfaces - plugin_attrib = 'profile' - - def add_command(self, player_nick): - """Add a command to the extension. - - Arguments: - player_nick (str): the nick of the player the profile is about - - """ - self.xml.append(ET.fromstring('%s' % player_nick)) - - def add_item(self, player, rating, highest_rating=0, # pylint: disable=too-many-arguments - rank=0, total_games_played=0, wins=0, losses=0): - """Add an item to the extension. - - Arguments: - player (str): Name of the player - rating (int): Current rating of the player - highest_rating (int): Highest rating the player had - rank (int): Rank of the player - total_games_played (int): Total number of games the player - played - wins (int): Number of won games the player had - losses (int): Number of lost games the player had - """ - item_xml = ET.Element('profile', {'player': player, 'rating': str(rating), - 'highestRating': str(highest_rating), 'rank': str(rank), - 'totalGamesPlayed': str(total_games_played), - 'wins': str(wins), 'losses': str(losses)}) - self.xml.append(item_xml) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/utils.py 0ad-0.0.26/source/tools/lobbybots/xpartamupp/utils.py --- 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/utils.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/xpartamupp/utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""Collection of utility functions used by the XMPP-bots.""" - -from collections import OrderedDict - - -class LimitedSizeDict(OrderedDict): - """Dictionary with limited size and FIFO characteristics.""" - - def __init__(self, *args, **kwargs): - """Initialize the dictionary. - - Set the limit to which size the dict should be able to grow. - """ - self.size_limit = kwargs.pop('size_limit', None) - OrderedDict.__init__(self, *args, **kwargs) - self._check_size_limit() - - def __setitem__(self, key, value): # pylint: disable=signature-differs - """Overwrite default method to add size limit check.""" - OrderedDict.__setitem__(self, key, value) - self._check_size_limit() - - def _check_size_limit(self): - """Ensure dict is not larger than the size limit. - - Compares the current size of the dict with the size limit and - removes items from the dict until the size is equal the size - limit. - """ - if self.size_limit: - while len(self) > self.size_limit: - self.popitem(last=False) diff -Nru 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/xpartamupp.py 0ad-0.0.26/source/tools/lobbybots/xpartamupp/xpartamupp.py --- 0ad-0.0.25b/source/tools/lobbybots/xpartamupp/xpartamupp.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/lobbybots/xpartamupp/xpartamupp.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2021 Wildfire Games. -# This file is part of 0 A.D. -# -# 0 A.D. is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# 0 A.D. is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 0 A.D. If not, see . - -"""0ad XMPP-bot responsible for managing game listings.""" - -import argparse -import logging -import time -import sys - -import sleekxmpp -from sleekxmpp.stanza import Iq -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream.stanzabase import register_stanza_plugin - -from xpartamupp.stanzas import GameListXmppPlugin -from xpartamupp.utils import LimitedSizeDict - - -class Games(object): - """Class to tracks all games in the lobby.""" - - def __init__(self): - """Initialize with empty games.""" - self.games = LimitedSizeDict(size_limit=2**7) - - def add_game(self, jid, data): - """Add a game. - - Arguments: - jid (sleekxmpp.jid.JID): JID of the player who started the - game - data (dict): information about the game - - Returns: - True if adding the game succeeded, False if not - - """ - try: - data['players-init'] = data['players'] - data['nbp-init'] = data['nbp'] - data['state'] = 'init' - except (KeyError, TypeError, ValueError): - logging.warning("Received invalid data for add game from 0ad: %s", data) - return False - else: - self.games[jid] = data - return True - - def remove_game(self, jid): - """Remove a game attached to a JID. - - Arguments: - jid (sleekxmpp.jid.JID): JID of the player whose game to - remove. - - Returns: - True if removing the game succeeded, False if not - - """ - try: - del self.games[jid] - except KeyError: - logging.warning("Game for jid %s didn't exist", jid) - return False - else: - return True - - def get_all_games(self): - """Return all games. - - Returns: - dict containing all games with the JID of the player who - started the game as key. - - """ - return self.games - - def change_game_state(self, jid, data): - """Switch game state between running and waiting. - - Arguments: - jid (sleekxmpp.jid.JID): JID of the player whose game to - change - data (dict): information about the game - - Returns: - True if changing the game state succeeded, False if not - - """ - if jid not in self.games: - logging.warning("Tried to change state for non-existent game %s", jid) - return False - - try: - if self.games[jid]['nbp-init'] > data['nbp']: - logging.debug("change game (%s) state from %s to %s", jid, - self.games[jid]['state'], 'waiting') - self.games[jid]['state'] = 'waiting' - else: - logging.debug("change game (%s) state from %s to %s", jid, - self.games[jid]['state'], 'running') - self.games[jid]['state'] = 'running' - self.games[jid]['nbp'] = data['nbp'] - self.games[jid]['players'] = data['players'] - except (KeyError, ValueError): - logging.warning("Received invalid data for change game state from 0ad: %s", data) - return False - else: - if 'startTime' not in self.games[jid]: - self.games[jid]['startTime'] = str(round(time.time())) - return True - - -class XpartaMuPP(sleekxmpp.ClientXMPP): - """Main class which handles IQ data and sends new data.""" - - def __init__(self, sjid, password, room, nick): - """Initialize XpartaMuPP. - - Arguments: - sjid (sleekxmpp.jid.JID): JID to use for authentication - password (str): password to use for authentication - room (str): XMPP MUC room to join - nick (str): Nick to use in MUC - - """ - sleekxmpp.ClientXMPP.__init__(self, sjid, password) - self.whitespace_keepalive = False - - self.room = room - self.nick = nick - - self.games = Games() - - register_stanza_plugin(Iq, GameListXmppPlugin) - - self.register_handler(Callback('Iq Gamelist', StanzaPath('iq@type=set/gamelist'), - self._iq_game_list_handler)) - - self.add_event_handler('session_start', self._session_start) - self.add_event_handler('muc::%s::got_online' % self.room, self._muc_online) - self.add_event_handler('muc::%s::got_offline' % self.room, self._muc_offline) - self.add_event_handler('groupchat_message', self._muc_message) - - def _session_start(self, event): # pylint: disable=unused-argument - """Join MUC channel and announce presence. - - Arguments: - event (dict): empty dummy dict - - """ - self.plugin['xep_0045'].joinMUC(self.room, self.nick) - self.send_presence() - self.get_roster() - logging.info("XpartaMuPP started") - - def _muc_online(self, presence): - """Add joining players to the list of players. - - Also send a list of games to them, so they see which games - are currently there. - - Arguments: - presence (sleekxmpp.stanza.presence.Presence): Received - presence stanza. - - """ - nick = str(presence['muc']['nick']) - jid = sleekxmpp.jid.JID(presence['muc']['jid']) - - if nick == self.nick: - return - - if jid.resource not in ['0ad', 'CC']: - return - - self._send_game_list(jid) - - logging.debug("Client '%s' connected with a nick '%s'.", jid, nick) - - def _muc_offline(self, presence): - """Remove leaving players from the list of players. - - Also remove the potential game this player was hosting, so we - don't end up with stale games. - - Arguments: - presence (sleekxmpp.stanza.presence.Presence): Received - presence stanza. - - """ - nick = str(presence['muc']['nick']) - jid = sleekxmpp.jid.JID(presence['muc']['jid']) - - if nick == self.nick: - return - - if self.games.remove_game(jid): - self._send_game_list() - - logging.debug("Client '%s' with nick '%s' disconnected", jid, nick) - - def _muc_message(self, msg): - """Process messages in the MUC room. - - Respond to messages highlighting the bots name with an - informative message. - - Arguments: - msg (sleekxmpp.stanza.message.Message): Received MUC - message - """ - if msg['mucnick'] != self.nick and self.nick.lower() in msg['body'].lower(): - self.send_message(mto=msg['from'].bare, - mbody="I am just a bot and I'm responsible to ensure that your're" - "able to see the list of games in here. Aside from that I'm" - "just chilling.", - mtype='groupchat') - - def _iq_game_list_handler(self, iq): - """Handle game state change requests. - - Arguments: - iq (sleekxmpp.stanza.iq.IQ): Received IQ stanza - - """ - if iq['from'].resource != '0ad': - return - - success = False - - command = iq['gamelist']['command'] - if command == 'register': - success = self.games.add_game(iq['from'], iq['gamelist']['game']) - elif command == 'unregister': - success = self.games.remove_game(iq['from']) - elif command == 'changestate': - success = self.games.change_game_state(iq['from'], iq['gamelist']['game']) - else: - logging.info('Received unknown game command: "%s"', command) - - iq.reply(clear=not success) - if not success: iq['error']['condition'] = "undefined-condition" - iq.send() - - if success: - try: - self._send_game_list() - except Exception: - logging.exception('Failed to send game list after "%s" command', command) - - def _send_game_list(self, to=None): - """Send a massive stanza with the whole game list. - - If no target is passed the gamelist is broadcasted to all - clients. - - Arguments: - to (sleekxmpp.jid.JID): Player to send the game list to. - If None, the game list will be broadcasted - """ - games = self.games.get_all_games() - - stanza = GameListXmppPlugin() - for jid in games: - stanza.add_game(games[jid]) - - if not to: - for nick in self.plugin['xep_0045'].getRoster(self.room): - if nick == self.nick: - continue - jid_str = self.plugin['xep_0045'].getJidProperty(self.room, nick, 'jid') - jid = sleekxmpp.jid.JID(jid_str) - iq = self.make_iq_result(ito=jid) - iq.set_payload(stanza) - try: - iq.send(block=False) - except Exception: - logging.exception("Failed to send game list to %s", jid) - else: - iq = self.make_iq_result(ito=to) - iq.set_payload(stanza) - try: - iq.send(block=False) - except Exception: - logging.exception("Failed to send game list to %s", to) - - -def parse_args(args): - """Parse command line arguments. - - Arguments: - args (dict): Raw command line arguments given to the script - - Returns: - Parsed command line arguments - - """ - parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description="XpartaMuPP - XMPP Multiplayer Game Manager") - - log_settings = parser.add_mutually_exclusive_group() - log_settings.add_argument('-q', '--quiet', help="only log errors", action='store_const', - dest='log_level', const=logging.ERROR) - log_settings.add_argument('-d', '--debug', help="log debug messages", action='store_const', - dest='log_level', const=logging.DEBUG) - log_settings.add_argument('-v', '--verbose', help="log more informative messages", - action='store_const', dest='log_level', const=logging.INFO) - log_settings.set_defaults(log_level=logging.WARNING) - - parser.add_argument('-m', '--domain', help="XMPP server to connect to", - default='lobby.wildfiregames.com') - parser.add_argument('-l', '--login', help="username for login", default='xpartamupp') - parser.add_argument('-p', '--password', help="password for login", default='XXXXXX') - parser.add_argument('-n', '--nickname', help="nickname shown to players", default='WFGBot') - parser.add_argument('-r', '--room', help="XMPP MUC room to join", default='arena') - parser.add_argument('-s', '--server', help='address of the ejabberd server', - action='store', dest='xserver', default=None) - parser.add_argument('-t', '--disable-tls', help='Pass this argument to connect without TLS encryption', - action='store_true', dest='xdisabletls', default=False) - - return parser.parse_args(args) - - -def main(): - """Entry point a console script.""" - args = parse_args(sys.argv[1:]) - - logging.basicConfig(level=args.log_level, - format='%(asctime)s %(levelname)-8s %(message)s', - datefmt='%Y-%m-%d %H:%M:%S') - - xmpp = XpartaMuPP(sleekxmpp.jid.JID('%s@%s/%s' % (args.login, args.domain, 'CC')), - args.password, args.room + '@conference.' + args.domain, args.nickname) - xmpp.register_plugin('xep_0030') # Service Discovery - xmpp.register_plugin('xep_0004') # Data Forms - xmpp.register_plugin('xep_0045') # Multi-User Chat - xmpp.register_plugin('xep_0060') # Publish-Subscribe - xmpp.register_plugin('xep_0199', {'keepalive': True}) # XMPP Ping - - if xmpp.connect((args.xserver, 5222) if args.xserver else None, True, not args.xdisabletls): - xmpp.process() - else: - logging.error("Unable to connect") - - -if __name__ == '__main__': - main() diff -Nru 0ad-0.0.25b/source/tools/templatesanalyzer/Readme.md 0ad-0.0.26/source/tools/templatesanalyzer/Readme.md --- 0ad-0.0.25b/source/tools/templatesanalyzer/Readme.md 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/tools/templatesanalyzer/Readme.md 2022-09-23 19:16:43.000000000 +0000 @@ -0,0 +1,69 @@ +## Template Analyzer + +This python tool has been written by wraitii and updated to 0ad A25 by hyiltiz. +Its purpose is to help with unit and civ balancing by allowing quick comparison +between important template data. + +Run it using `python unitTables.py` or `pypy unitTables.py` (if you have pypy +installed). The output will be located in an HTML file called +`unit_summary_table.html` in this folder. + +The script generates 3 informative tables: +- A comparison table of generic templates; +- A comparison table of civilization units (it shows the differences with the + generic templates); +- A comparison of civilization rosters. + +You can customize the script by changing the units to include (loading all units +might make it slightly unreadable). To change this, change the +`LoadTemplatesIfParent` variable. You can also consider only some civilizations. +You may also filter some templates based on their name, if you want to remove +specific templates. By default it loads all citizen soldiers and all champions, +and ignores non-interesting units for the comparison/efficienicy table (2nd +table). + +The HTML page comes with a JavaScript extension that allows to filter and sort +in-place, to help with comparisons. You can disable this by disabling javascript +or by changing the `AddSortingOverlay` parameter in the script. This JS +extension, called TableFilter, is released under the MIT license. The version +used can be found at https://github.com/koalyptus/TableFilter/ + +All contents of this folder are under the MIT License. + + +## Contributing + +The script intentionally only relies on Python 3 Standard Library to avoid +installing 3rd party libraries as dependencies. However, you might want to +install a few packages to make hacking around easier. + +### Debugging +IPython can be used as a good REPL and to easily insert a debug break point. +Install it with: + + pip3 install ipython + +then to insert a break point, simply insert the following line to the script where +you want execution to pause: + + import IPython; IPython.embed() + +Then, run the script as normal. Once you hit the breakpoint, you can use IPython +as a normal REPL. A useful IPython magic is `whos`, which shows all local +variables. + +### Exploration +To understand the internal logic, generating a function call dependency graph +can be helpful by providing a quick visual overview. Use the following code to +create the function call dependency graph. It is dynamic, and allows quickly +getting familiarized with the analyzer. Note that you'll need `dot` engine provided +by the `graphviz` package. You can install `graphviz` using your system's package manager. + + pip3 install pyan3==1.1.1 + python3 -m pyan unitTables.py --uses --no-defines --colored --grouped --annotated --html > fundeps.html + +Alternatively, only create the `.dot` file using the following line, and render it with an online renderer like http://viz-js.com/ + + python3 -m pyan unitTables.py --uses --no-defines --colored --grouped --annotated --dot > fundeps.dot + +Enjoy! diff -Nru 0ad-0.0.25b/source/tools/templatesanalyzer/Readme.txt 0ad-0.0.26/source/tools/templatesanalyzer/Readme.txt --- 0ad-0.0.25b/source/tools/templatesanalyzer/Readme.txt 2021-07-27 21:56:49.000000000 +0000 +++ 0ad-0.0.26/source/tools/templatesanalyzer/Readme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -Template Analyzer. - -This python tool has been written by wraitii. Its purpose is to help with unit and civ balancing by allowing quick comparison between important template data. - -Run it using "python unitTables.py" or "pypy unitTables.py" if you have pypy installed. - -The output will be located in an HTML file called "unit_summary_table.html" in this folder. - - -The script gives 3 informations: --A comparison table of generic templates. --A comparison table of civilization units (it shows the differences with the generic templates) --A comparison of civilization rosters. - -The script can be customized to change the units that are considered, since loading all units make sit slightly unreadable. -By default it loads all citizen soldiers and all champions. - -To change this, change the "LoadTemplatesIfParent" variable. -You can also consider only some civilizations. -You may also filter some templates based on their name, if you want to remove specific templates. - - -The HTML page comes with a JS extension that allows to filter and sort in-place, to help with comparisons. You can disable this by disabling javascript or by changing the "AddSortingOverlay" parameter in the script. - -This extension, called TableFilter, is released under the MIT license. The version I used was the one found at https://github.com/koalyptus/TableFilter/ - -All contents of this folder are under the MIT License. - -Enjoy! diff -Nru 0ad-0.0.25b/source/tools/templatesanalyzer/unitTables.py 0ad-0.0.26/source/tools/templatesanalyzer/unitTables.py --- 0ad-0.0.25b/source/tools/templatesanalyzer/unitTables.py 2021-07-27 21:56:50.000000000 +0000 +++ 0ad-0.0.26/source/tools/templatesanalyzer/unitTables.py 2022-09-23 19:16:43.000000000 +0000 @@ -1,17 +1,18 @@ #!/usr/bin/env python3 - -# Copyright (C) 2015 Wildfire Games. -# +# -*- mode: python-mode; python-indent-offset: 4; -*- +# +# Copyright (C) 2022 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 @@ -20,549 +21,1053 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. + + import xml.etree.ElementTree as ET import os import glob -AttackTypes = ["Hack","Pierce","Crush"] +# TODO: Add other damage types. +AttackTypes = ["Hack", "Pierce", "Crush"] Resources = ["food", "wood", "stone", "metal"] # Generic templates to load # The way this works is it tries all generic templates # But only loads those who have one of the following parents # EG adding "template_unit.xml" will load all units. -LoadTemplatesIfParent = ["template_unit_infantry.xml", "template_unit_cavalry.xml", "template_unit_champion.xml", "template_unit_hero.xml"] +LoadTemplatesIfParent = [ + "template_unit_infantry.xml", + "template_unit_cavalry.xml", + "template_unit_champion.xml", + "template_unit_hero.xml", +] # Those describe Civs to analyze. -# The script will load all entities that derive (to the nth degree) from one of the above templates. -Civs = ["athen", "brit", "cart", "gaul", "iber", "kush", "mace", "maur", "pers", "ptol", "rome", "sele", "spart"] +# The script will load all entities that derive (to the nth degree) from one of +# the above templates. +Civs = [ + "athen", + "brit", + "cart", + "gaul", + "iber", + "kush", + "mace", + "maur", + "pers", + "ptol", + "rome", + "sele", + "spart", + # "gaia", +] # Remote Civ templates with those strings in their name. FilterOut = ["marian", "thureophoros", "thorakites", "kardakes"] +# In the Civilization specific units table, do you want to only show the units +# that are different from the generic templates? +showChangedOnly = True + # Sorting parameters for the "roster variety" table ComparativeSortByCav = True ComparativeSortByChamp = True -SortTypes = ["Support", "Pike", "Spear", "Sword", "Archer", "Javelin", "Sling", "Elephant"] # Classes +ClassesUsedForSort = [ + "Support", + "Pike", + "Spear", + "Sword", + "Archer", + "Javelin", + "Sling", + "Elephant", +] -# Disable if you want the more compact basic data. Enable to allow filtering and sorting in-place. +# Disable if you want the more compact basic data. Enable to allow filtering and +# sorting in-place. AddSortingOverlay = True -# This is the path to the /templates/ folder to consider. Change this for mod support. -basePath = os.path.realpath(__file__).replace("unitTables.py","") + "../../../binaries/data/mods/public/simulation/templates/" +# This is the path to the /templates/ folder to consider. Change this for mod +# support. +basePath = ( + os.path.realpath(__file__).replace("unitTables.py", "") + + "../../../binaries/data/mods/public/simulation/templates/" +) # For performance purposes, cache opened templates files. globalTemplatesList = {} -def htbout(file, balise, value): - file.write("<" + balise + ">" + value + "\n" ) -def htout(file, value): - file.write("

" + value + "

\n" ) -def fastParse(templateName): - if templateName in globalTemplatesList: - return globalTemplatesList[templateName] - globalTemplatesList[templateName] = ET.parse(templateName) - return globalTemplatesList[templateName] +def showChild(root): + """root is of ElementTree.getroot() type""" + # Not used; use it for debugging + print("---------------- Children: ----------------") + [print(child.tag, child.attrib) for child in root] -# This function checks that a template has the given parent. -def hasParentTemplate(UnitName, parentName): - Template = fastParse(UnitName) + print("\n-------------- Neighbours: --------------") + [print(neighbor.attrib) for neighbor in root.iter("neighbor")] - found = False - Name = UnitName - while found != True and Template.getroot().get("parent") != None: - Name = Template.getroot().get("parent") + ".xml" - if Name == parentName: - return True - Template = ET.parse(Name) - return False +def htbout(file, balise, value): + file.write("<" + balise + ">" + value + "\n") -def NumericStatProcess(unitValue, templateValue): - if not "op" in templateValue.attrib: - return float(templateValue.text) - if (templateValue.attrib["op"] == "add"): - unitValue += float(templateValue.text) - elif (templateValue.attrib["op"] == "sub"): - unitValue -= float(templateValue.text) - elif (templateValue.attrib["op"] == "mul"): - unitValue *= float(templateValue.text) - elif (templateValue.attrib["op"] == "div"): - unitValue /= float(templateValue.text) - return unitValue - - -# This function parses the entity values manually. -def CalcUnit(UnitName, existingUnit = None): - unit = { 'HP' : "0", "BuildTime" : "0", "Cost" : { 'food' : "0", "wood" : "0", "stone" : "0", "metal" : "0", "population" : "0"}, - 'Attack' : { "Melee" : { "Hack" : 0, "Pierce" : 0, "Crush" : 0 }, "Ranged" : { "Hack" : 0, "Pierce" : 0, "Crush" : 0 } }, - 'RepeatRate' : {"Melee" : "0", "Ranged" : "0"},'PrepRate' : {"Melee" : "0", "Ranged" : "0"}, "Armour" : { "Hack" : 0, "Pierce" : 0, "Crush" : 0}, - "Ranged" : False, "Classes" : [], "AttackBonuses" : {}, "Restricted" : [], "WalkSpeed" : 0, "Range" : 0, "Spread" : 0, - "Civ" : None } - - if (existingUnit != None): - unit = existingUnit - - Template = fastParse(UnitName) - - # Recursively get data from our parent which we'll override. - if (Template.getroot().get("parent") != None): - unit = CalcUnit(Template.getroot().get("parent") + ".xml", unit) - unit["Parent"] = Template.getroot().get("parent") + ".xml" - - if (Template.find("./Identity/Civ") != None): - unit['Civ'] = Template.find("./Identity/Civ").text - - if (Template.find("./Health/Max") != None): - unit['HP'] = NumericStatProcess(unit['HP'], Template.find("./Health/Max")) - - if (Template.find("./Cost/BuildTime") != None): - unit['BuildTime'] = NumericStatProcess(unit['BuildTime'], Template.find("./Cost/BuildTime")) - - if (Template.find("./Cost/Resources") != None): - for type in list(Template.find("./Cost/Resources")): - unit['Cost'][type.tag] = NumericStatProcess(unit['Cost'][type.tag], type) - - if (Template.find("./Cost/Population") != None): - unit['Cost']["population"] = NumericStatProcess(unit['Cost']["population"], Template.find("./Cost/Population")) - - if (Template.find("./Attack/Melee") != None): - if (Template.find("./Attack/Melee/RepeatTime") != None): - unit['RepeatRate']["Melee"] = NumericStatProcess(unit['RepeatRate']["Melee"], Template.find("./Attack/Melee/RepeatTime")) - if (Template.find("./Attack/Melee/PrepareTime") != None): - unit['PrepRate']["Melee"] = NumericStatProcess(unit['PrepRate']["Melee"], Template.find("./Attack/Melee/PrepareTime")) - for atttype in AttackTypes: - if (Template.find("./Attack/Melee/"+atttype) != None): - unit['Attack']['Melee'][atttype] = NumericStatProcess(unit['Attack']['Melee'][atttype], Template.find("./Attack/Melee/"+atttype)) - if (Template.find("./Attack/Melee/Bonuses") != None): - for Bonus in Template.find("./Attack/Melee/Bonuses"): - Against = [] - CivAg = [] - if (Bonus.find("Classes") != None and Bonus.find("Classes").text != None): - Against = Bonus.find("Classes").text.split(" ") - if (Bonus.find("Civ") != None and Bonus.find("Civ").text != None): - CivAg = Bonus.find("Civ").text.split(" ") - Val = float(Bonus.find("Multiplier").text) - unit["AttackBonuses"][Bonus.tag] = {"Classes" : Against, "Civs" : CivAg, "Multiplier" : Val} - if (Template.find("./Attack/Melee/RestrictedClasses") != None): - newClasses = Template.find("./Attack/Melee/RestrictedClasses").text.split(" ") - for elem in newClasses: - if (elem.find("-") != -1): - newClasses.pop(newClasses.index(elem)) - if elem in unit["Restricted"]: - unit["Restricted"].pop(newClasses.index(elem)) - unit["Restricted"] += newClasses - - - if (Template.find("./Attack/Ranged") != None): - unit['Ranged'] = True - if (Template.find("./Attack/Ranged/MaxRange") != None): - unit['Range'] = NumericStatProcess(unit['Range'], Template.find("./Attack/Ranged/MaxRange")) - if (Template.find("./Attack/Ranged/Spread") != None): - unit['Spread'] = NumericStatProcess(unit['Spread'], Template.find("./Attack/Ranged/Spread")) - if (Template.find("./Attack/Ranged/RepeatTime") != None): - unit['RepeatRate']["Ranged"] = NumericStatProcess(unit['RepeatRate']["Ranged"], Template.find("./Attack/Ranged/RepeatTime")) - if (Template.find("./Attack/Ranged/PrepareTime") != None): - unit['PrepRate']["Ranged"] = NumericStatProcess(unit['PrepRate']["Ranged"], Template.find("./Attack/Ranged/PrepareTime")) - for atttype in AttackTypes: - if (Template.find("./Attack/Ranged/"+atttype) != None): - unit['Attack']['Ranged'][atttype] = NumericStatProcess(unit['Attack']['Ranged'][atttype], Template.find("./Attack/Ranged/"+atttype)) - if (Template.find("./Attack/Ranged/Bonuses") != None): - for Bonus in Template.find("./Attack/Ranged/Bonuses"): - Against = [] - CivAg = [] - if (Bonus.find("Classes") != None and Bonus.find("Classes").text != None): - Against = Bonus.find("Classes").text.split(" ") - if (Bonus.find("Civ") != None and Bonus.find("Civ").text != None): - CivAg = Bonus.find("Civ").text.split(" ") - Val = float(Bonus.find("Multiplier").text) - unit["AttackBonuses"][Bonus.tag] = {"Classes" : Against, "Civs" : CivAg, "Multiplier" : Val} - if (Template.find("./Attack/Melee/RestrictedClasses") != None): - newClasses = Template.find("./Attack/Melee/RestrictedClasses").text.split(" ") - for elem in newClasses: - if (elem.find("-") != -1): - newClasses.pop(newClasses.index(elem)) - if elem in unit["Restricted"]: - unit["Restricted"].pop(newClasses.index(elem)) - unit["Restricted"] += newClasses - - if (Template.find("./Armour") != None): - for atttype in AttackTypes: - if (Template.find("./Armour/"+atttype) != None): - unit['Armour'][atttype] = NumericStatProcess(unit['Armour'][atttype], Template.find("./Armour/"+atttype)) - - if (Template.find("./UnitMotion") != None): - if (Template.find("./UnitMotion/WalkSpeed") != None): - unit['WalkSpeed'] = NumericStatProcess(unit['WalkSpeed'], Template.find("./UnitMotion/WalkSpeed")) - - if (Template.find("./Identity/VisibleClasses") != None): - newClasses = Template.find("./Identity/VisibleClasses").text.split(" ") - for elem in newClasses: - if (elem.find("-") != -1): - newClasses.pop(newClasses.index(elem)) - if elem in unit["Classes"]: - unit["Classes"].pop(newClasses.index(elem)) - unit["Classes"] += newClasses - - if (Template.find("./Identity/Classes") != None): - newClasses = Template.find("./Identity/Classes").text.split(" ") - for elem in newClasses: - if (elem.find("-") != -1): - newClasses.pop(newClasses.index(elem)) - if elem in unit["Classes"]: - unit["Classes"].pop(newClasses.index(elem)) - unit["Classes"] += newClasses +def htout(file, value): + file.write("

" + value + "

\n") - return unit -def WriteUnit(Name, UnitDict): - ret = "" +def fastParse(templateName): + """Run ET.parse() with memoising in a global table.""" + if templateName in globalTemplatesList: + return globalTemplatesList[templateName] + globalTemplatesList[templateName] = ET.parse(templateName) + return globalTemplatesList[templateName] - ret += "" + Name + "" - ret += "" + str(int(UnitDict["HP"])) + "" - - ret += "" +str("%.0f" % float(UnitDict["BuildTime"])) + "" - - ret += "" + str("%.1f" % float(UnitDict["WalkSpeed"])) + "" - - for atype in AttackTypes: - PercentValue = 1.0 - (0.9 ** float(UnitDict["Armour"][atype])) - ret += "" + str("%.0f" % float(UnitDict["Armour"][atype])) + " / " + str("%.0f" % (PercentValue*100.0)) + "%" - - attType = ("Ranged" if UnitDict["Ranged"] == True else "Melee") - if UnitDict["RepeatRate"][attType] != "0": - for atype in AttackTypes: - repeatTime = float(UnitDict["RepeatRate"][attType])/1000.0 - ret += "" + str("%.1f" % (float(UnitDict["Attack"][attType][atype])/repeatTime)) + "" - - ret += "" + str("%.1f" % (float(UnitDict["RepeatRate"][attType])/1000.0)) + "" - else: - for atype in AttackTypes: - ret += " - " - ret += " - " - - if UnitDict["Ranged"] == True and UnitDict["Range"] > 0: - ret += "" + str("%.1f" % float(UnitDict["Range"])) + "" - spread = float(UnitDict["Spread"]) - ret += "" + str("%.1f" % spread) + "" - else: - ret += " - - " - - for rtype in Resources: - ret += "" + str("%.0f" % float(UnitDict["Cost"][rtype])) + "" - - ret += "" + str("%.0f" % float(UnitDict["Cost"]["population"])) + "" - - ret += "" - for Bonus in UnitDict["AttackBonuses"]: - ret += "[" - for classe in UnitDict["AttackBonuses"][Bonus]["Classes"]: - ret += classe + " " - ret += ': ' + str(UnitDict["AttackBonuses"][Bonus]["Multiplier"]) + "] " - ret += "" +# This function checks that a template has the given parent. +def hasParentTemplate(UnitName, parentName): + Template = fastParse(UnitName) - ret += "\n" - return ret + found = False + Name = UnitName -# Sort the templates dictionary. -def SortFn(A): - sortVal = 0 - for classe in SortTypes: - sortVal += 1 - if classe in A[1]["Classes"]: - break - if ComparativeSortByChamp == True and A[0].find("champion") == -1: - sortVal -= 20 - if ComparativeSortByCav == True and A[0].find("cavalry") == -1: - sortVal -= 10 - if A[1]["Civ"] != None and A[1]["Civ"] in Civs: - sortVal += 100 * Civs.index(A[1]["Civ"]) - return sortVal - -# helper to write coloured text. -def WriteColouredDiff(file, diff, PositOrNegat): - - def cleverParse(diff): - if float(diff) - int(diff) < 0.001: - return str(int(diff)) - else: - return str("%.1f" % float(diff)) - - if (PositOrNegat == "positive"): - file.write(" 0 else "0,150,0")) + ");\">" + cleverParse(diff) + "") - elif (PositOrNegat == "negative"): - file.write("" + cleverParse(diff) + "") - else: - complain + # parent_str = 'parent ' + while found != True and Template.getroot().get("parent") != None: + longName = Template.getroot().get("parent") + ".xml" + # 0ad started using unit class/category prefixed to the unit name + # separated by |, known as mixins since A25 (rP25223) + # + # We strip these categories for now. The | syntax + # gives a unit its "category" (like merc_cav, merc_inf, hoplite, + # builder, shrine, civ/athen). This can be used later for + # classification + + Name = longName.split("|")[-1] + + mixins = {x.replace('civ/', '') for x in longName.split("|")[0:-1]} + civ = set(Civs).intersection(mixins) + if len(civ) > 0: + # mixin category contains a civ name + # we honor mixin civ hierarchy + # This assumes a unit only belongs to a single civ parent + unit_civ = list(civ)[0] + '.xml' + # unit_civ is not used in this function for now + if Name == parentName: + return True -############################################################ -############################################################ -# Create the HTML file + Template = ET.parse(Name) -f = open(os.path.realpath(__file__).replace("unitTables.py","") + 'unit_summary_table.html', 'w') + # parent_str += 'parent ' -f.write("\n\n\n Unit Tables\n \n\n") -htbout(f,"h1","Unit Summary Table") -f.write("\n") + return False -os.chdir(basePath) -############################################################ -# Load generic templates +def NumericStatProcess(unitValue, templateValue): + val = float(templateValue.text) + if not "op" in templateValue.attrib: + return val + if templateValue.attrib["op"] == "add": + unitValue += val + elif templateValue.attrib["op"] == "sub": + unitValue -= val + elif templateValue.attrib["op"] == "mul": + unitValue *= val + elif templateValue.attrib["op"] == "mul_round": + unitValue = round(unitValue * val) + elif templateValue.attrib["op"] == "div": + unitValue /= val + return unitValue + + +def CalcUnit(UnitName, existingUnit=None): + """Parse the entity values recursively through fastParse().""" + unit = { + "HP": "0", + "BuildTime": "0", + "Cost": { + "food": "0", + "wood": "0", + "stone": "0", + "metal": "0", + "population": "0", + }, + "Attack": { + "Melee": {"Hack": 0, "Pierce": 0, "Crush": 0}, + "Ranged": {"Hack": 0, "Pierce": 0, "Crush": 0}, + }, + "RepeatRate": {"Melee": "0", "Ranged": "0"}, + "PrepRate": {"Melee": "0", "Ranged": "0"}, + "Resistance": {"Hack": 0, "Pierce": 0, "Crush": 0}, + "Ranged": False, + "Classes": [], + "AttackBonuses": {}, + "Restricted": [], + "WalkSpeed": 0, + "Range": 0, + "Spread": 0, + "Civ": None, + } + + if existingUnit != None: + unit = existingUnit + + Template = fastParse(UnitName) + + # Recursively get data from our parent which we'll override. + unit_civ = None + if Template.getroot().get("parent") != None: + # 0ad started using unit class/category prefixed to the unit name + # separated by |, known as mixins since A25 (rP25223) + # We strip these categories for now + # This can be used later for classification + longName = Template.getroot().get("parent") + Name = longName.split("|")[-1] + ".xml" + + mixins = {x.replace('civ/', '') for x in longName.split("|")[0:-1]} + civ = set(Civs).intersection(mixins) + if len(civ) > 0: + # mixin category contains a civ name + # we honor mixin civ hierarchy + # This assumes a unit only belongs to a single civ parent + unit_civ = list(civ)[0] + + + unit = CalcUnit(Name, unit) + unit["Parent"] = Name + + if unit_civ: + unit["Civ"] = unit_civ + elif Template.find("./Identity/Civ") != None: + unit["Civ"] = Template.find("./Identity/Civ").text + + + + if Template.find("./Health/Max") != None: + unit["HP"] = NumericStatProcess( + unit["HP"], Template.find("./Health/Max")) + + if Template.find("./Cost/BuildTime") != None: + unit["BuildTime"] = NumericStatProcess( + unit["BuildTime"], Template.find("./Cost/BuildTime") + ) + + if Template.find("./Cost/Resources") != None: + for type in list(Template.find("./Cost/Resources")): + unit["Cost"][type.tag] = NumericStatProcess( + unit["Cost"][type.tag], type) + + if Template.find("./Cost/Population") != None: + unit["Cost"]["population"] = NumericStatProcess( + unit["Cost"]["population"], Template.find("./Cost/Population") + ) + + if Template.find("./Attack/Melee") != None: + if Template.find("./Attack/Melee/RepeatTime") != None: + unit["RepeatRate"]["Melee"] = NumericStatProcess( + unit["RepeatRate"]["Melee"], + Template.find("./Attack/Melee/RepeatTime") + ) + if Template.find("./Attack/Melee/PrepareTime") != None: + unit["PrepRate"]["Melee"] = NumericStatProcess( + unit["PrepRate"]["Melee"], + Template.find("./Attack/Melee/PrepareTime") + ) + for atttype in AttackTypes: + if Template.find("./Attack/Melee/Damage/" + atttype) != None: + unit["Attack"]["Melee"][atttype] = NumericStatProcess( + unit["Attack"]["Melee"][atttype], + Template.find("./Attack/Melee/Damage/" + atttype), + ) + if Template.find("./Attack/Melee/Bonuses") != None: + for Bonus in Template.find("./Attack/Melee/Bonuses"): + Against = [] + CivAg = [] + if Bonus.find("Classes") != None \ + and Bonus.find("Classes").text != None: + Against = Bonus.find("Classes").text.split(" ") + if Bonus.find("Civ") != None and Bonus.find("Civ").text != None: + CivAg = Bonus.find("Civ").text.split(" ") + Val = float(Bonus.find("Multiplier").text) + unit["AttackBonuses"][Bonus.tag] = { + "Classes": Against, + "Civs": CivAg, + "Multiplier": Val, + } + if Template.find("./Attack/Melee/RestrictedClasses") != None: + newClasses = Template.find("./Attack/Melee/RestrictedClasses")\ + .text.split(" ") + for elem in newClasses: + if elem.find("-") != -1: + newClasses.pop(newClasses.index(elem)) + if elem in unit["Restricted"]: + unit["Restricted"].pop(newClasses.index(elem)) + unit["Restricted"] += newClasses + + if Template.find("./Attack/Ranged") != None: + unit["Ranged"] = True + if Template.find("./Attack/Ranged/MaxRange") != None: + unit["Range"] = NumericStatProcess( + unit["Range"], Template.find("./Attack/Ranged/MaxRange") + ) + if Template.find("./Attack/Ranged/Spread") != None: + unit["Spread"] = NumericStatProcess( + unit["Spread"], Template.find("./Attack/Ranged/Spread") + ) + if Template.find("./Attack/Ranged/RepeatTime") != None: + unit["RepeatRate"]["Ranged"] = NumericStatProcess( + unit["RepeatRate"]["Ranged"], + Template.find("./Attack/Ranged/RepeatTime"), + ) + if Template.find("./Attack/Ranged/PrepareTime") != None: + unit["PrepRate"]["Ranged"] = NumericStatProcess( + unit["PrepRate"]["Ranged"], + Template.find("./Attack/Ranged/PrepareTime") + ) + for atttype in AttackTypes: + if Template.find("./Attack/Ranged/Damage/" + atttype) != None: + unit["Attack"]["Ranged"][atttype] = NumericStatProcess( + unit["Attack"]["Ranged"][atttype], + Template.find("./Attack/Ranged/Damage/" + atttype), + ) + if Template.find("./Attack/Ranged/Bonuses") != None: + for Bonus in Template.find("./Attack/Ranged/Bonuses"): + Against = [] + CivAg = [] + if Bonus.find("Classes") != None \ + and Bonus.find("Classes").text != None: + Against = Bonus.find("Classes").text.split(" ") + if Bonus.find("Civ") != None and Bonus.find("Civ").text != None: + CivAg = Bonus.find("Civ").text.split(" ") + Val = float(Bonus.find("Multiplier").text) + unit["AttackBonuses"][Bonus.tag] = { + "Classes": Against, + "Civs": CivAg, + "Multiplier": Val, + } + if Template.find("./Attack/Melee/RestrictedClasses") != None: + newClasses = Template.find("./Attack/Melee/RestrictedClasses")\ + .text.split(" ") + for elem in newClasses: + if elem.find("-") != -1: + newClasses.pop(newClasses.index(elem)) + if elem in unit["Restricted"]: + unit["Restricted"].pop(newClasses.index(elem)) + unit["Restricted"] += newClasses + + if Template.find("Resistance") != None: + # Resistance lives insdie a new node Entity, e.g. + # list(ET.parse('template_unit_cavalry.xml').find('Resistance/Entity/Damage')) + + for atttype in AttackTypes: + extracted_resistance = Template.find( + "./Resistance/Entity/Damage/" + atttype + ) + if extracted_resistance != None: + unit["Resistance"][atttype] = NumericStatProcess( + unit["Resistance"][atttype], extracted_resistance + ) + + if Template.find("./UnitMotion") != None: + if Template.find("./UnitMotion/WalkSpeed") != None: + unit["WalkSpeed"] = NumericStatProcess( + unit["WalkSpeed"], Template.find("./UnitMotion/WalkSpeed") + ) + + if Template.find("./Identity/VisibleClasses") != None: + newClasses = Template.find("./Identity/VisibleClasses").text.split(" ") + for elem in newClasses: + if elem.find("-") != -1: + newClasses.pop(newClasses.index(elem)) + if elem in unit["Classes"]: + unit["Classes"].pop(newClasses.index(elem)) + unit["Classes"] += newClasses + + if Template.find("./Identity/Classes") != None: + newClasses = Template.find("./Identity/Classes").text.split(" ") + for elem in newClasses: + if elem.find("-") != -1: + newClasses.pop(newClasses.index(elem)) + if elem in unit["Classes"]: + unit["Classes"].pop(newClasses.index(elem)) + unit["Classes"] += newClasses -templates = {} + return unit -htbout(f,"h2", "Units") -f.write("\n") -f.write("") -f.write("\n") -f.write("") -f.write("\n\n") - -for template in list(glob.glob('template_*.xml')): - if os.path.isfile(template): - found = False - for possParent in LoadTemplatesIfParent: - if hasParentTemplate(template, possParent): - found = True - break - if found == True: - templates[template] = CalcUnit(template) - f.write(WriteUnit(template, templates[template])) +def WriteUnit(Name, UnitDict): + ret = "" + ret += '" + ret += "" + ret += "" + ret += "" + + for atype in AttackTypes: + PercentValue = 1.0 - (0.9 ** float(UnitDict["Resistance"][atype])) + ret += ( + "" + ) + + attType = "Ranged" if UnitDict["Ranged"] == True else "Melee" + if UnitDict["RepeatRate"][attType] != "0": + for atype in AttackTypes: + repeatTime = float(UnitDict["RepeatRate"][attType]) / 1000.0 + ret += ( + "" + ) + + ret += ( + "" + ) + else: + for atype in AttackTypes: + ret += "" + ret += "" + + if UnitDict["Ranged"] == True and UnitDict["Range"] > 0: + ret += "" + spread = float(UnitDict["Spread"]) + ret += "" + else: + ret += "" + + for rtype in Resources: + ret += "" + + ret += "" + + ret += '" -f.write("
HP BuildTime Speed(walk) Armour Attack (DPS) Costs Efficient Against
HPC HPCRateRangeSpread\n(/100m) FWSMP
' + Name + "" + str(int(UnitDict["HP"])) + "" + str("%.0f" % float(UnitDict["BuildTime"])) + "" + str("%.1f" % float(UnitDict["WalkSpeed"])) + "" + + str("%.0f" % float(UnitDict["Resistance"][atype])) + + " / " + + str("%.0f" % (PercentValue * 100.0)) + + "%" + + str("%.1f" % ( + float(UnitDict["Attack"][attType][atype]) / repeatTime + )) + "" + + str("%.1f" % (float(UnitDict["RepeatRate"][attType]) / 1000.0)) + + " - - " + str("%.1f" % float(UnitDict["Range"])) + "" + str("%.1f" % spread) + " - - " + str("%.0f" % + float(UnitDict["Cost"][rtype])) + "" + str("%.0f" % + float(UnitDict["Cost"]["population"])) + "' + for Bonus in UnitDict["AttackBonuses"]: + ret += "[" + for classe in UnitDict["AttackBonuses"][Bonus]["Classes"]: + ret += classe + " " + ret += ": %s] " % UnitDict["AttackBonuses"][Bonus]["Multiplier"] + ret += "
") + ret += "\n" + return ret -############################################################ -# Load Civ specific templates -CivTemplates = {} +# Sort the templates dictionary. +def SortFn(A): + sortVal = 0 + for classe in ClassesUsedForSort: + sortVal += 1 + if classe in A[1]["Classes"]: + break + if ComparativeSortByChamp == True and A[0].find("champion") == -1: + sortVal -= 20 + if ComparativeSortByCav == True and A[0].find("cavalry") == -1: + sortVal -= 10 + if A[1]["Civ"] != None and A[1]["Civ"] in Civs: + sortVal += 100 * Civs.index(A[1]["Civ"]) + return sortVal + + +def WriteColouredDiff(file, diff, isChanged): + """helper to write coloured text. + diff value must always be computed as a unit_spec - unit_generic. + A positive imaginary part represents advantageous trait. + """ + + def cleverParse(diff): + if float(diff) - int(diff) < 0.001: + return str(int(diff)) + else: + return str("%.1f" % float(diff)) + + isAdvantageous = diff.imag > 0 + diff = diff.real + if diff != 0: + isChanged = True + else: + # do not change its value if one parameter is not changed (yet) + # some other parameter might be different + pass + + if diff == 0: + rgb_str = "200,200,200" + elif isAdvantageous and diff > 0: + rgb_str = "180,0,0" + elif (not isAdvantageous) and diff < 0: + rgb_str = "180,0,0" + else: + rgb_str = "0,150,0" + + file.write( + """{} + """.format( + rgb_str, cleverParse(diff) + ) + ) + return isChanged + + +def computeUnitEfficiencyDiff(TemplatesByParent, Civs): + efficiency_table = {} + for parent in TemplatesByParent: + TemplatesByParent[parent].sort(key=lambda x: Civs.index(x[1]["Civ"])) + + for tp in TemplatesByParent[parent]: + # HP + diff = -1j + (int(tp[1]["HP"]) - int(templates[parent]["HP"])) + efficiency_table[(parent, tp[0], "HP")] = diff + efficiency_table[(parent, tp[0], "HP")] = diff + + # Build Time + diff = +1j + (int(tp[1]["BuildTime"]) - + int(templates[parent]["BuildTime"])) + efficiency_table[(parent, tp[0], "BuildTime")] = diff + + # walk speed + diff = -1j + ( + float(tp[1]["WalkSpeed"]) - + float(templates[parent]["WalkSpeed"]) + ) + efficiency_table[(parent, tp[0], "WalkSpeed")] = diff + + # Resistance + for atype in AttackTypes: + diff = -1j + ( + float(tp[1]["Resistance"][atype]) + - float(templates[parent]["Resistance"][atype]) + ) + efficiency_table[(parent, tp[0], "Resistance/" + atype)] = diff + + # Attack types (DPS) and rate. + attType = "Ranged" if tp[1]["Ranged"] == True else "Melee" + if tp[1]["RepeatRate"][attType] != "0": + for atype in AttackTypes: + myDPS = float(tp[1]["Attack"][attType][atype]) / ( + float(tp[1]["RepeatRate"][attType]) / 1000.0 + ) + parentDPS = float( + templates[parent]["Attack"][attType][atype]) / ( + float(templates[parent]["RepeatRate"][attType]) / 1000.0 + ) + diff = -1j + (myDPS - parentDPS) + efficiency_table[ + (parent, tp[0], "Attack/" + attType + "/" + atype) + ] = diff + diff = -1j + ( + float(tp[1]["RepeatRate"][attType]) / 1000.0 + - float(templates[parent]["RepeatRate"][attType]) / 1000.0 + ) + efficiency_table[ + (parent, tp[0], "Attack/" + attType + "/" + atype + + "/RepeatRate") + ] = diff + # range and spread + if tp[1]["Ranged"] == True: + diff = -1j + ( + float(tp[1]["Range"]) - + float(templates[parent]["Range"]) + ) + efficiency_table[ + (parent, tp[0], "Attack/" + attType + "/Ranged/Range") + ] = diff + + diff = (float(tp[1]["Spread"]) - + float(templates[parent]["Spread"])) + efficiency_table[ + (parent, tp[0], "Attack/" + attType + "/Ranged/Spread") + ] = diff + + for rtype in Resources: + diff = +1j + ( + float(tp[1]["Cost"][rtype]) + - float(templates[parent]["Cost"][rtype]) + ) + efficiency_table[(parent, tp[0], "Resources/" + rtype)] = diff + + diff = +1j + ( + float(tp[1]["Cost"]["population"]) + - float(templates[parent]["Cost"]["population"]) + ) + efficiency_table[(parent, tp[0], "Population")] = diff + + return efficiency_table + + +def computeTemplates(LoadTemplatesIfParent): + """Loops over template XMLs and selectively insert into templates dict.""" + pwd = os.getcwd() + os.chdir(basePath) + templates = {} + for template in list(glob.glob("template_*.xml")): + if os.path.isfile(template): + found = False + for possParent in LoadTemplatesIfParent: + if hasParentTemplate(template, possParent): + found = True + break + if found == True: + templates[template] = CalcUnit(template) + # f.write(WriteUnit(template, templates[template])) + os.chdir(pwd) + return templates + + +def computeCivTemplates(template: dict, Civs: list): + """Load Civ specific templates""" + # NOTE: whether a Civ can train a certain unit is not recorded in the unit + # .xml files, and hence we have to get that info elsewhere, e.g. from the + # Civ tree. This should be delayed until this whole parser is based on the + # Civ tree itself. + + # This function must always ensure that Civ unit parenthood works as + # intended, i.e. a unit in a Civ indeed has a 'Civ' field recording its + # loyalty to that Civ. Check this when upgrading this script to keep + # up with the game engine. + pwd = os.getcwd() + os.chdir(basePath) + + CivTemplates = {} + + for Civ in Civs: + CivTemplates[Civ] = {} + # Load all templates that start with that civ indicator + # TODO: consider adding mixin/civs here too + civ_list = list(glob.glob("units/" + Civ + "/*.xml")) + for template in civ_list: + if os.path.isfile(template): + + # filter based on FilterOut + breakIt = False + for filter in FilterOut: + if template.find(filter) != -1: + breakIt = True + if breakIt: + continue + + # filter based on loaded generic templates + breakIt = True + for possParent in LoadTemplatesIfParent: + if hasParentTemplate(template, possParent): + breakIt = False + break + if breakIt: + continue + + unit = CalcUnit(template) + + # Remove variants for now + if unit["Parent"].find("template_") == -1: + continue + + # load template + CivTemplates[Civ][template] = unit + + os.chdir(pwd) + return CivTemplates + + +def computeTemplatesByParent(templates: dict, Civs: list, CivTemplates: dict): + """Get them in the array""" + # Civs:list -> CivTemplates:dict -> templates:dict -> TemplatesByParent + TemplatesByParent = {} + for Civ in Civs: + for CivUnitTemplate in CivTemplates[Civ]: + parent = CivTemplates[Civ][CivUnitTemplate]["Parent"] + + # We have the following constant equality + # templates[*]["Civ"] === gaia + # if parent in templates and templates[parent]["Civ"] == None: + if parent in templates: + if parent not in TemplatesByParent: + TemplatesByParent[parent] = [] + TemplatesByParent[parent].append( + (CivUnitTemplate, CivTemplates[Civ][CivUnitTemplate]) + ) -for Civ in Civs: - CivTemplates[Civ] = {} - # Load all templates that start with that civ indicator - for template in list(glob.glob('units/' + Civ + '_*.xml')): - if os.path.isfile(template): - - # filter based on FilterOut - breakIt = False - for filter in FilterOut: - if template.find(filter) != -1: breakIt = True - if breakIt: continue - - # filter based on loaded generic templates - breakIt = True - for possParent in LoadTemplatesIfParent: - if hasParentTemplate(template, possParent): - breakIt = False - break - if breakIt: continue - - unit = CalcUnit(template) - - # Remove variants for now - if unit["Parent"].find("template_") == -1: - continue + # debug after CivTemplates are non-empty + return TemplatesByParent - # load template - CivTemplates[Civ][template] = unit ############################################################ -f.write("\n\n

Units Specializations

\n") -f.write("

This table compares each template to its parent, showing the differences between the two.
Note that like any table, you can copy/paste this in Excel (or Numbers or ...) and sort it.

") +## Pre-compute all tables +templates = computeTemplates(LoadTemplatesIfParent) +CivTemplates = computeCivTemplates(templates, Civs) +TemplatesByParent = computeTemplatesByParent(templates, Civs, CivTemplates) + +# Not used; use it for your own custom analysis +efficiencyTable = computeUnitEfficiencyDiff( + TemplatesByParent, Civs +) + -TemplatesByParent = {} +############################################################ +def writeHTML(): + """Create the HTML file""" + f = open( + os.path.realpath(__file__).replace("unitTables.py", "") + + "unit_summary_table.html", + "w", + ) + + f.write( + """ + + + + Unit Tables + + + + """ + ) + htbout(f, "h1", "Unit Summary Table") + f.write("\n") + + # Write generic templates + htbout(f, "h2", "Units") + f.write( + """ + + + + + + + + + + + + + + + + + + + """ + ) + for template in templates: + f.write(WriteUnit(template, templates[template])) + f.write("
HP BuildTime Speed(walk) Resistance Attack (DPS) Costs Efficient Against
H P C H P C Rate Range Spread (/100m) F W S M P
") + + # Write unit specialization + # Sort them by civ and write them in a table. + # + # TODO: pre-compute the diffs then render, filtering out the non-interesting + # ones + # + f.write( + """ +

Units Specializations +

+ +

This table compares each template to its parent, showing the +differences between the two. +
Note that like any table, you can copy/paste this in Excel (or Numbers or + ...) and sort it. +

+ + + + + + + + + + + + + + + + + + + + + """ + ) + for parent in TemplatesByParent: + TemplatesByParent[parent].sort(key=lambda x: Civs.index(x[1]["Civ"])) + for tp in TemplatesByParent[parent]: + isChanged = False + ff = open( + os.path.realpath(__file__).replace("unitTables.py", "") + + ".cache", "w" + ) + + ff.write("") + ff.write( + "" + ) + ff.write( + '" + ) + + # HP + diff = -1j + (int(tp[1]["HP"]) - int(templates[parent]["HP"])) + isChanged = WriteColouredDiff(ff, diff, isChanged) + + # Build Time + diff = +1j + (int(tp[1]["BuildTime"]) - + int(templates[parent]["BuildTime"])) + isChanged = WriteColouredDiff(ff, diff, isChanged) + + # walk speed + diff = -1j + ( + float(tp[1]["WalkSpeed"]) - + float(templates[parent]["WalkSpeed"]) + ) + isChanged = WriteColouredDiff(ff, diff, isChanged) + + # Resistance + for atype in AttackTypes: + diff = -1j + ( + float(tp[1]["Resistance"][atype]) + - float(templates[parent]["Resistance"][atype]) + ) + isChanged = WriteColouredDiff(ff, diff, isChanged) + + # Attack types (DPS) and rate. + attType = "Ranged" if tp[1]["Ranged"] == True else "Melee" + if tp[1]["RepeatRate"][attType] != "0": + for atype in AttackTypes: + myDPS = float(tp[1]["Attack"][attType][atype]) / ( + float(tp[1]["RepeatRate"][attType]) / 1000.0 + ) + parentDPS = float( + templates[parent]["Attack"][attType][atype]) / ( + float(templates[parent]["RepeatRate"][attType]) / 1000.0 + ) + isChanged = WriteColouredDiff( + ff, -1j + (myDPS - parentDPS), isChanged + ) + isChanged = WriteColouredDiff( + ff, + -1j + + ( + float(tp[1]["RepeatRate"][attType]) / 1000.0 + - float(templates[parent]["RepeatRate"][attType]) / 1000.0 + ), + isChanged, + ) + # range and spread + if tp[1]["Ranged"] == True: + isChanged = WriteColouredDiff( + ff, + -1j + + (float(tp[1]["Range"]) - + float(templates[parent]["Range"])), + isChanged, + ) + mySpread = float(tp[1]["Spread"]) + parentSpread = float(templates[parent]["Spread"]) + isChanged = WriteColouredDiff( + ff, +1j + (mySpread - parentSpread), isChanged + ) + else: + ff.write("") + else: + ff.write("") + + for rtype in Resources: + isChanged = WriteColouredDiff( + ff, + +1j + + ( + float(tp[1]["Cost"][rtype]) + - float(templates[parent]["Cost"][rtype]) + ), + isChanged, + ) + + isChanged = WriteColouredDiff( + ff, + +1j + + ( + float(tp[1]["Cost"]["population"]) + - float(templates[parent]["Cost"]["population"]) + ), + isChanged, + ) + + ff.write("") + ff.write("\n") + + ff.close() # to actually write into the file + with open( + os.path.realpath(__file__).replace("unitTables.py", "") + + ".cache", "r" + ) as ff: + unitStr = ff.read() + + if showChangedOnly: + if isChanged: + f.write(unitStr) + else: + # print the full table if showChangedOnly is false + f.write(unitStr) + + f.write("
HP BuildTime Speed (/100m) Resistance Attack Costs Civ
H P C H P C Rate Range Spread F W S M P
" + + parent.replace(".xml", "").replace("template_", "") + + "' + + tp[0].replace(".xml", "").replace("units/", "") + + "" + tp[1]["Civ"] + "
") + + # Table of unit having or not having some units. + f.write( + """ +

Roster Variety +

+ +

This table show which civilizations have units who derive from +each loaded generic template. +
Grey means the civilization has no unit derived from a generic template; +
dark green means 1 derived unit, mid-tone green means 2, bright green + means 3 or more. +
The total is the total number of loaded units for this civ, which may be + more than the total of units inheriting from loaded templates. +

+
+ + +""" + ) + for civ in Civs: + f.write('\n") + f.write("\n") + + sortedDict = sorted(templates.items(), key=SortFn) + + for tp in sortedDict: + if tp[0] not in TemplatesByParent: + continue + f.write("\n") + for civ in Civs: + found = 0 + for temp in TemplatesByParent[tp[0]]: + if temp[1]["Civ"] == civ: + found += 1 + if found == 1: + f.write('') + elif found == 2: + f.write('') + elif found >= 3: + f.write('') + else: + f.write('') + f.write("\n") + f.write( + '\ + \n' + ) + for civ in Civs: + count = 0 + for units in CivTemplates[civ]: + count += 1 + f.write('\n") + + f.write("\n") + + f.write("
Template ' + civ + "
" + tp[0] + "
Total:' + str(count) + "
") + + # Add a simple script to allow filtering on sorting directly in the HTML + # page. + if AddSortingOverlay: + f.write( + """ + + + """ + ) -#Get them in the array -for Civ in Civs: - for CivUnitTemplate in CivTemplates[Civ]: - parent = CivTemplates[Civ][CivUnitTemplate]["Parent"] - if parent in templates and templates[parent]["Civ"] == None: - if parent not in TemplatesByParent: - TemplatesByParent[parent] = [] - TemplatesByParent[parent].append( (CivUnitTemplate,CivTemplates[Civ][CivUnitTemplate])) - -#Sort them by civ and write them in a table. -f.write("
\n") -f.write("") -f.write("\n") -f.write("") -f.write("\n") -for parent in TemplatesByParent: - TemplatesByParent[parent].sort(key=lambda x : Civs.index(x[1]["Civ"])) - for tp in TemplatesByParent[parent]: - f.write("") - - f.write("") - - # HP - diff = int(tp[1]["HP"]) - int(templates[parent]["HP"]) - WriteColouredDiff(f, diff, "negative") - - # Build Time - diff = int(tp[1]["BuildTime"]) - int(templates[parent]["BuildTime"]) - WriteColouredDiff(f, diff, "positive") - - # walk speed - diff = float(tp[1]["WalkSpeed"]) - float(templates[parent]["WalkSpeed"]) - WriteColouredDiff(f, diff, "negative") - - # Armor - for atype in AttackTypes: - diff = float(tp[1]["Armour"][atype]) - float(templates[parent]["Armour"][atype]) - WriteColouredDiff(f, diff, "negative") - - # Attack types (DPS) and rate. - attType = ("Ranged" if tp[1]["Ranged"] == True else "Melee") - if tp[1]["RepeatRate"][attType] != "0": - for atype in AttackTypes: - myDPS = float(tp[1]["Attack"][attType][atype]) / (float(tp[1]["RepeatRate"][attType])/1000.0) - parentDPS = float(templates[parent]["Attack"][attType][atype]) / (float(templates[parent]["RepeatRate"][attType])/1000.0) - WriteColouredDiff(f, myDPS - parentDPS, "negative") - WriteColouredDiff(f, float(tp[1]["RepeatRate"][attType])/1000.0 - float(templates[parent]["RepeatRate"][attType])/1000.0, "negative") - # range and spread - if tp[1]["Ranged"] == True: - WriteColouredDiff(f, float(tp[1]["Range"]) - float(templates[parent]["Range"]), "negative") - mySpread = float(tp[1]["Spread"]) - parentSpread = float(templates[parent]["Spread"]) - WriteColouredDiff(f, mySpread - parentSpread, "positive") - else: - f.write("") - else: - f.write("") - - for rtype in Resources: - WriteColouredDiff(f, float(tp[1]["Cost"][rtype]) - float(templates[parent]["Cost"][rtype]), "positive") - - WriteColouredDiff(f, float(tp[1]["Cost"]["population"]) - float(templates[parent]["Cost"]["population"]), "positive") - - f.write("") - - f.write("\n") -f.write("
HP BuildTime Speed Armour Attack Costs Civ
HPC HPCRateRangeSpread FWSMP
" + parent.replace(".xml","").replace("template_","") + "" + tp[0].replace(".xml","").replace("units/","") + "" + tp[1]["Civ"] + "
") - -# Table of unit having or not having some units. -f.write("\n\n

Roster Variety

\n") -f.write("

This table show which civilizations have units who derive from each loaded generic template.
Green means 1 deriving unit, blue means 2, black means 3 or more.
The total is the total number of loaded units for this civ, which may be more than the total of units inheriting from loaded templates.

") -f.write("
\n") -f.write("\n") -for civ in Civs: - f.write("\n") -f.write("\n") - -sortedDict = sorted(templates.items(), key=SortFn) - -for tp in sortedDict: - if tp[0] not in TemplatesByParent: - continue - f.write("\n") - for civ in Civs: - found = 0 - for temp in TemplatesByParent[tp[0]]: - if temp[1]["Civ"] == civ: - found += 1 - if found == 1: - f.write("") - elif found == 2: - f.write("") - elif found >= 3: - f.write("") - else: - f.write("") - f.write("\n") -f.write("\n") -for civ in Civs: - count = 0 - for units in CivTemplates[civ]: count += 1 - f.write("\n") - -f.write("\n") - -f.write("
Template" + civ + "
" + tp[0] +"
Total:" + str(count) + "
") - -# Add a simple script to allow filtering on sorting directly in the HTML page. -if AddSortingOverlay: - f.write("\n\ - \n\ - \n") + f.write("\n") -f.write("\n") +if __name__ == "__main__": + writeHTML() diff -Nru 0ad-0.0.25b/source/tools/xmlvalidator/validate_grammar.py 0ad-0.0.26/source/tools/xmlvalidator/validate_grammar.py --- 0ad-0.0.25b/source/tools/xmlvalidator/validate_grammar.py 1970-01-01 00:00:00.000000000 +0000 +++ 0ad-0.0.26/source/tools/xmlvalidator/validate_grammar.py 2022-09-23 19:16:44.000000000 +0000 @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 +from argparse import ArgumentParser +from pathlib import Path +from os.path import sep, join, realpath, exists, basename, dirname +from json import load, loads +from re import split, match +from logging import getLogger, StreamHandler, INFO, WARNING, Filter, Formatter +import lxml.etree +import sys + +class SingleLevelFilter(Filter): + def __init__(self, passlevel, reject): + self.passlevel = passlevel + self.reject = reject + + def filter(self, record): + if self.reject: + return (record.levelno != self.passlevel) + else: + return (record.levelno == self.passlevel) + +class VFS_File: + def __init__(self, mod_name, vfs_path): + self.mod_name = mod_name + self.vfs_path = vfs_path + +class RelaxNGValidator: + def __init__(self, vfs_root, mods=None, verbose=False): + self.mods = mods if mods is not None else [] + self.vfs_root = Path(vfs_root) + self.__init_logger + self.verbose = verbose + + @property + def __init_logger(self): + logger = getLogger(__name__) + logger.setLevel(INFO) + # create a console handler, seems nicer to Windows and for future uses + ch = StreamHandler(sys.stdout) + ch.setLevel(INFO) + ch.setFormatter(Formatter('%(levelname)s - %(message)s')) + f1 = SingleLevelFilter(INFO, False) + ch.addFilter(f1) + logger.addHandler(ch) + errorch = StreamHandler(sys.stderr) + errorch.setLevel(WARNING) + errorch.setFormatter(Formatter('%(levelname)s - %(message)s')) + logger.addHandler(errorch) + self.logger = logger + + def run (self): + self.validate_actors() + self.validate_variants() + self.validate_guis() + self.validate_maps() + self.validate_materials() + self.validate_particles() + self.validate_simulation() + self.validate_soundgroups() + self.validate_terrains() + self.validate_textures() + + def main(self): + """ Program entry point, parses command line arguments and launches the validation """ + # ordered uniq mods (dict maintains ordered keys from python 3.6) + self.logger.info(f"Checking {'|'.join(self.mods)}'s integrity.") + self.logger.info(f"The following mods will be loaded: {'|'.join(self.mods)}.") + self.run() + + def find_files(self, vfs_root, mods, vfs_path, *ext_list): + """ + returns a list of 2-size tuple with: + - Path relative to the mod base + - full Path + """ + full_exts = ['.' + ext for ext in ext_list] + + def find_recursive(dp, base): + """(relative Path, full Path) generator""" + if dp.is_dir(): + if dp.name != '.svn' and dp.name != '.git' and not dp.name.endswith('~'): + for fp in dp.iterdir(): + yield from find_recursive(fp, base) + elif dp.suffix in full_exts: + relative_file_path = dp.relative_to(base) + yield (relative_file_path, dp.resolve()) + return [(rp, fp) for mod in mods for (rp, fp) in find_recursive(vfs_root / mod / vfs_path, vfs_root / mod)] + + def validate_actors(self): + self.logger.info('Validating actors...') + files = self.find_files(self.vfs_root, self.mods, 'art/actors/', 'xml') + self.validate_files('actors', files, 'art/actors/actor.rng') + + def validate_variants(self): + self.logger.info("Validating variants...") + files = self.find_files(self.vfs_root, self.mods, 'art/variants/', 'xml') + self.validate_files('variant', files, 'art/variants/variant.rng') + + def validate_guis(self): + self.logger.info("Validating gui files...") + pages = [file for file in self.find_files(self.vfs_root, self.mods, 'gui/', 'xml') if match(r".*[\\\/]page(_[^.\/\\]+)?\.xml$", str(file[0]))] + self.validate_files('gui page', pages, 'gui/gui_page.rng') + xmls = [file for file in self.find_files(self.vfs_root, self.mods, 'gui/', 'xml') if not match(r".*[\\\/]page(_[^.\/\\]+)?\.xml$", str(file[0]))] + self.validate_files('gui xml', xmls, 'gui/gui.rng') + + def validate_maps(self): + self.logger.info("Validating maps...") + files = self.find_files(self.vfs_root, self.mods, 'maps/scenarios/', 'xml') + self.validate_files('map', files, 'maps/scenario.rng') + files = self.find_files(self.vfs_root, self.mods, 'maps/skirmishes/', 'xml') + self.validate_files('map', files, 'maps/scenario.rng') + + def validate_materials(self): + self.logger.info("Validating materials...") + files = self.find_files(self.vfs_root, self.mods, 'art/materials/', 'xml') + self.validate_files('material', files, 'art/materials/material.rng') + + def validate_particles(self): + self.logger.info("Validating particles...") + files = self.find_files(self.vfs_root, self.mods, 'art/particles/', 'xml') + self.validate_files('particle', files, 'art/particles/particle.rng') + + def validate_simulation(self): + self.logger.info("Validating simulation...") + file = self.find_files(self.vfs_root, self.mods, 'simulation/data/pathfinder', 'xml') + self.validate_files('pathfinder', file, 'simulation/data/pathfinder.rng') + file = self.find_files(self.vfs_root, self.mods, 'simulation/data/territorymanager', 'xml') + self.validate_files('territory manager', file, 'simulation/data/territorymanager.rng') + + def validate_soundgroups(self): + self.logger.info("Validating soundgroups...") + files = self.find_files(self.vfs_root, self.mods, 'audio/', 'xml') + self.validate_files('sound group', files, 'audio/sound_group.rng') + + def validate_terrains(self): + self.logger.info("Validating terrains...") + terrains = [file for file in self.find_files(self.vfs_root, self.mods, 'art/terrains/', 'xml') if 'terrains.xml' in str(file[0])] + self.validate_files('terrain', terrains, 'art/terrains/terrain.rng') + terrains_textures = [file for file in self.find_files(self.vfs_root, self.mods, 'art/terrains/', 'xml') if 'terrains.xml' not in str(file[0])] + self.validate_files('terrain texture', terrains_textures, 'art/terrains/terrain_texture.rng') + + def validate_textures(self): + self.logger.info("Validating textures...") + files = [file for file in self.find_files(self.vfs_root, self.mods, 'art/textures/', 'xml') if 'textures.xml' in str(file[0])] + self.validate_files('texture', files, 'art/textures/texture.rng') + + def get_physical_path(self, mod_name, vfs_path): + return realpath(join(self.vfs_root, mod_name, vfs_path)) + + def get_relaxng_file(self, schemapath): + """We look for the highest priority mod relax NG file""" + for mod in self.mods: + relax_ng_path = self.get_physical_path(mod, schemapath) + if exists(relax_ng_path): + return relax_ng_path + + return "" + + def validate_files(self, name, files, schemapath): + relax_ng_path = self.get_relaxng_file(schemapath) + if relax_ng_path == "": + self.logger.warning(f"Could not find {schemapath}") + return + + data = lxml.etree.parse(relax_ng_path) + relaxng = lxml.etree.RelaxNG(data) + error_count = 0 + for file in sorted(files): + try: + doc = lxml.etree.parse(str(file[1])) + relaxng.assertValid(doc) + except Exception as e: + error_count = error_count + 1 + self.logger.error(f"{file[1]}: " + str(e)) + + if self.verbose: + self.logger.info(f"{error_count} {name} validation errors") + elif error_count > 0: + self.logger.error(f"{error_count} {name} validation errors") + + +def get_mod_dependencies(vfs_root, *mods): + modjsondeps = [] + for mod in mods: + mod_json_path = Path(vfs_root) / mod / 'mod.json' + if not exists(mod_json_path): + continue + + with open(mod_json_path, encoding='utf-8') as f: + modjson = load(f) + # 0ad's folder isn't named like the mod. + modjsondeps.extend(['public' if '0ad' in dep else dep for dep in modjson.get('dependencies', [])]) + return modjsondeps + +if __name__ == '__main__': + script_dir = dirname(realpath(__file__)) + default_root = join(script_dir, '..', '..', '..', 'binaries', 'data', 'mods') + ap = ArgumentParser(description="Validates XML files againt their Relax NG schemas") + ap.add_argument('-r', '--root', action='store', dest='root', default=default_root) + ap.add_argument('-v', '--verbose', action='store_true', default=True, + help="Log validation errors.") + ap.add_argument('-m', '--mods', metavar="MOD", dest='mods', nargs='+', default=['public'], + help="specify which mods to check. Default to public and mod.") + args = ap.parse_args() + mods = list(dict.fromkeys([*args.mods, *get_mod_dependencies(args.root, *args.mods), 'mod']).keys()) + relax_ng_validator = RelaxNGValidator(args.root, mods=mods, verbose=args.verbose) + relax_ng_validator.main() \ No newline at end of file diff -Nru 0ad-0.0.25b/source/tools/xmlvalidator/validator.py 0ad-0.0.26/source/tools/xmlvalidator/validator.py --- 0ad-0.0.25b/source/tools/xmlvalidator/validator.py 2021-07-27 21:56:48.000000000 +0000 +++ 0ad-0.0.26/source/tools/xmlvalidator/validator.py 2022-09-23 19:16:46.000000000 +0000 @@ -1,11 +1,21 @@ #!/usr/bin/env python3 import argparse import os -import re import sys -import time +import re import xml.etree.ElementTree +from logging import getLogger, StreamHandler, INFO, WARNING, Formatter, Filter +class SingleLevelFilter(Filter): + def __init__(self, passlevel, reject): + self.passlevel = passlevel + self.reject = reject + + def filter(self, record): + if self.reject: + return (record.levelno != self.passlevel) + else: + return (record.levelno == self.passlevel) class Actor: def __init__(self, mod_name, vfs_path): @@ -14,20 +24,45 @@ self.name = os.path.basename(vfs_path) self.textures = [] self.material = '' + self.logger = getLogger(__name__) def read(self, physical_path): try: tree = xml.etree.ElementTree.parse(physical_path) except xml.etree.ElementTree.ParseError as err: - sys.stderr.write('Error in "%s": %s\n' % (physical_path, err.msg)) + self.logger.error('"%s": %s' % (physical_path, err.msg)) return False root = tree.getroot() + # Special case: particles don't need a diffuse texture. + if len(root.findall('.//particles')) > 0: + self.textures.append("baseTex") + for element in root.findall('.//material'): self.material = element.text for element in root.findall('.//texture'): self.textures.append(element.get('name')) + for element in root.findall('.//variant'): + file = element.get('file') + if file: + self.read_variant(physical_path, os.path.join('art', 'variants', file)) return True + def read_variant(self, actor_physical_path, relative_path): + physical_path = actor_physical_path.replace(self.vfs_path, relative_path) + try: + tree = xml.etree.ElementTree.parse(physical_path) + except xml.etree.ElementTree.ParseError as err: + self.logger.error('"%s": %s' % (physical_path, err.msg)) + return False + + root = tree.getroot() + file = root.get('file') + if file: + self.read_variant(actor_physical_path, os.path.join('art', 'variants', file)) + + for element in root.findall('.//texture'): + self.textures.append(element.get('name')) + class Material: def __init__(self, mod_name, vfs_path): @@ -40,7 +75,7 @@ try: root = xml.etree.ElementTree.parse(physical_path).getroot() except xml.etree.ElementTree.ParseError as err: - sys.stderr.write('Error in "%s": %s\n' % (physical_path, err.msg)) + self.logger.error('"%s": %s' % (physical_path, err.msg)) return False for element in root.findall('.//required_texture'): texture_name = element.get('name') @@ -58,6 +93,27 @@ self.materials = {} self.invalid_materials = {} self.actors = [] + self.__init_logger + + @property + def __init_logger(self): + logger = getLogger(__name__) + logger.setLevel(INFO) + # create a console handler, seems nicer to Windows and for future uses + ch = StreamHandler(sys.stdout) + ch.setLevel(INFO) + ch.setFormatter(Formatter('%(levelname)s - %(message)s')) + f1 = SingleLevelFilter(INFO, False) + ch.addFilter(f1) + logger.addHandler(ch) + errorch = StreamHandler(sys.stderr) + errorch.setLevel(WARNING) + errorch.setFormatter(Formatter('%(levelname)s - %(message)s')) + logger.addHandler(errorch) + self.logger = logger + + def get_mod_path(self, mod_name, vfs_path): + return os.path.join(mod_name, vfs_path) def get_physical_path(self, mod_name, vfs_path): return os.path.realpath(os.path.join(self.vfs_root, mod_name, vfs_path)) @@ -88,6 +144,7 @@ return result def find_materials(self, vfs_path): + self.logger.info('Collecting materials...') material_files = self.find_all_mods_files(vfs_path, re.compile(r'.*\.xml')) for material_file in material_files: material_name = os.path.basename(material_file['vfs_path']) @@ -100,6 +157,8 @@ self.invalid_materials[material_name] = material def find_actors(self, vfs_path): + self.logger.info('Collecting actors...') + actor_files = self.find_all_mods_files(vfs_path, re.compile(r'.*\.xml')) for actor_file in actor_files: actor = Actor(actor_file['mod_name'], actor_file['vfs_path']) @@ -107,44 +166,38 @@ self.actors.append(actor) def run(self): - start_time = time.time() - - sys.stdout.write('Collecting list of files to check\n') - self.find_materials(os.path.join('art', 'materials')) self.find_actors(os.path.join('art', 'actors')) + self.logger.info('Validating textures...') for actor in self.actors: if not actor.material: continue if actor.material not in self.materials and actor.material not in self.invalid_materials: - sys.stderr.write('Error in "%s": unknown material "%s"' % ( - self.get_physical_path(actor.mod_name, actor.vfs_path), + self.logger.error('"%s": unknown material "%s"' % ( + self.get_mod_path(actor.mod_name, actor.vfs_path), actor.material )) if actor.material not in self.materials: continue material = self.materials[actor.material] - for required_texture in material.required_textures: - if required_texture in actor.textures: - continue - sys.stderr.write('Error in "%s": actor does not contain required texture "%s" from "%s"\n' % ( - self.get_physical_path(actor.mod_name, actor.vfs_path), - required_texture, + + missing_textures = ', '.join(set([required_texture for required_texture in material.required_textures if required_texture not in actor.textures])) + if len(missing_textures) > 0: + self.logger.error('"%s": actor does not contain required texture(s) "%s" from "%s"' % ( + self.get_mod_path(actor.mod_name, actor.vfs_path), + missing_textures, material.name )) - for texture in actor.textures: - if texture in material.required_textures: - continue - sys.stderr.write('Warning in "%s": actor contains unnecessary texture "%s" from "%s"\n' % ( - self.get_physical_path(actor.mod_name, actor.vfs_path), - texture, + + extra_textures = ', '.join(set([extra_texture for extra_texture in actor.textures if extra_texture not in material.required_textures])) + if len(extra_textures) > 0: + self.logger.warning('"%s": actor contains unnecessary texture(s) "%s" from "%s"' % ( + self.get_mod_path(actor.mod_name, actor.vfs_path), + extra_textures, material.name )) - finish_time = time.time() - sys.stdout.write('Total execution time: %.3f seconds.\n' % (finish_time - start_time)) - if __name__ == '__main__': script_dir = os.path.dirname(os.path.realpath(__file__)) default_root = os.path.join(script_dir, '..', '..', '..', 'binaries', 'data', 'mods')