{"id":3575,"date":"2024-07-16T15:01:26","date_gmt":"2024-07-16T12:01:26","guid":{"rendered":"https:\/\/demensdeum.com\/blog\/?p=3575"},"modified":"2024-12-16T22:32:13","modified_gmt":"2024-12-16T19:32:13","slug":"surreal-engine-cpp-webassembly-port","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/fr\/2024\/07\/16\/surreal-engine-cpp-webassembly-port\/","title":{"rendered":"Portage du Surreal Engine C++ vers WebAssembly"},"content":{"rendered":"<p>Dans cet article, je d\u00e9crirai comment j&#8217;ai port\u00e9 le moteur de jeu Surreal Engine vers WebAssembly.<br \/>\n<a href=\"https:\/\/demensdeum.com\/demos\/SurrealEngine\/\" rel=\"noopener\" target=\"_blank\"><\/a><\/p>\n<p>Moteur surr\u00e9aliste\u00a0&#038;#8211\u00a0; un moteur de jeu qui impl\u00e9mente la plupart des fonctionnalit\u00e9s de l&#8217;Unreal Engine 1, des jeux c\u00e9l\u00e8bres sur ce moteur &#8211; Unreal Tournament 99, Unreal, Deus Ex, Undying. Il fait r\u00e9f\u00e9rence aux moteurs classiques qui fonctionnaient principalement dans un environnement d&#8217;ex\u00e9cution monothread.<\/p>\n<p>Au d\u00e9part, j&#8217;ai eu l&#8217;id\u00e9e de me lancer dans un projet que je ne pouvais pas r\u00e9aliser dans un d\u00e9lai raisonnable, montrant ainsi \u00e0 mes abonn\u00e9s Twitch qu&#8217;il y a des projets que m\u00eame moi je ne peux pas r\u00e9aliser. Lors de mon premier stream, j&#8217;ai soudainement r\u00e9alis\u00e9 que la t\u00e2che de porter Surreal Engine C++ vers WebAssembly \u00e0 l&#8217;aide d&#8217;Emscripten \u00e9tait r\u00e9alisable.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot_20240716_162120.png\" alt=\"Surreal Engine Emscripten Demo\" width=\"737\" height=\"364\" class=\"alignnone wp-image-3581\" srcset=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot_20240716_162120.png 1555w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot_20240716_162120-300x148.png 300w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot_20240716_162120-1024x505.png 1024w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot_20240716_162120-768x379.png 768w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot_20240716_162120-1536x758.png 1536w\" sizes=\"auto, (max-width: 737px) 100vw, 737px\" \/><\/p>\n<p>Apr\u00e8s un mois, je peux faire une d\u00e9monstration de mon ensemble fourche et moteur sur WebAssembly\u00a0:<br \/>\n<a href=\"https:\/\/demensdeum.com\/demos\/SurrealEngine\/\" target=\"_blank\" rel=\"noopener\">https:\/\/demensdeum.com\/demos\/SurrealEngine\/<\/a><\/p>\n<p>Le contr\u00f4le, comme dans l&#8217;original, s&#8217;effectue \u00e0 l&#8217;aide des fl\u00e8ches du clavier. Ensuite, je pr\u00e9vois de l&#8217;adapter au contr\u00f4le mobile (tachi), en ajoutant un \u00e9clairage correct et d&#8217;autres fonctionnalit\u00e9s graphiques du rendu Unreal Tournament 99.<\/p>\n<h3>Par o\u00f9 commencer\u00a0?<\/h3>\n<p>La premi\u00e8re chose que je veux dire est que n&#8217;importe quel projet peut \u00eatre port\u00e9 de C++ vers WebAssembly en utilisant Emscripten, la seule question est de savoir dans quelle mesure la fonctionnalit\u00e9 sera compl\u00e8te. Choisissez un projet dont les ports de biblioth\u00e8que sont d\u00e9j\u00e0 disponibles pour Emscripten ; dans le cas de Surreal Engine, vous avez beaucoup de chance, car le moteur utilise les biblioth\u00e8ques SDL 2, OpenAL &#8211; ils sont tous deux port\u00e9s sur Emscripten. Cependant, Vulkan est utilis\u00e9 comme API graphique, qui n&#8217;est actuellement pas disponible pour HTML5, des travaux sont en cours pour impl\u00e9menter WebGPU, mais il est \u00e9galement au stade de projet, et on ne sait pas non plus \u00e0 quel point le port ult\u00e9rieur de Vulkan vers WebGPU sera simple. , une fois qu&#8217;il est enti\u00e8rement standardis\u00e9. Par cons\u00e9quent, j&#8217;ai d\u00fb \u00e9crire mon propre rendu de base OpenGL-ES\/WebGL pour Surreal Engine.<\/p>\n<h3>Construire le projet<\/h3>\n<p>Construire un syst\u00e8me dans Surreal Engine &#8211; CMake, qui simplifie \u00e9galement le portage, car Emscripten fournit \u00e0 ses constructeurs natifs &#8211; emcmake, emmake.<br \/>\nLe portage de Surreal Engine \u00e9tait bas\u00e9 sur le code de mon dernier jeu en WebGL\/OpenGL ES et C++ appel\u00e9 Death-Mask, de ce fait le d\u00e9veloppement \u00e9tait beaucoup plus simple, j&#8217;avais tous les indicateurs de build n\u00e9cessaires avec moi et des exemples de code.<\/p >\n<p>L&#8217;un des points les plus importants de CMakeLists.txt concerne les indicateurs de build pour Emscripten. Vous trouverez ci-dessous un exemple tir\u00e9 du fichier de projet\u00a0:<\/p>\n<div class=\"hcb_wrap\">\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>\n-s MAX_WEBGL_VERSION=2 \\\n\n-s EXCEPTION_DEBUG \\\n\n-fexceptions \\\n\n--preload-file UnrealTournament\/ \\\n\n--preload-file SurrealEngine.pk3 \\\n\n--bind \\\n\n--use-preload-plugins \\\n\n-Wall \\\n\n-Wextra \\\n\n-Werror=return-type \\\n\n-s USE_SDL=2 \\\n\n-s ASSERTIONS=1 \\\n\n-w \\\n\n-g4 \\\n\n-s DISABLE_EXCEPTION_CATCHING=0 \\\n\n-O3 \\\n\n--no-heap-copy \\\n\n-s ALLOW_MEMORY_GROWTH=1 \\\n\n-s EXIT_RUNTIME=1\")\n\n<\/code><\/pre>\n<\/div>\n<\/div>\n<p>Le script de build lui-m\u00eame\u00a0:<\/p>\n<div class=\"hcb_wrap\">\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>\nemmake make -j 16\n\ncp SurrealEngine.data \/srv\/http\/SurrealEngine\/SurrealEngine.data\n\ncp SurrealEngine.js \/srv\/http\/SurrealEngine\/SurrealEngine.js\n\ncp SurrealEngine.wasm \/srv\/http\/SurrealEngine\/SurrealEngine.wasm\n\ncp ..\/buildScripts\/Emscripten\/index.html \/srv\/http\/SurrealEngine\/index.html\n\ncp ..\/buildScripts\/Emscripten\/background.png \/srv\/http\/SurrealEngine\/background.png\n\n<\/code><\/pre>\n<\/div>\n<\/div>\n<p>Ensuite, nous pr\u00e9parerons l&#8217;<a href=\"https:\/\/github.com\/demensdeum\/SurrealEngine-Emscripten\/blob\/master\/buildScripts\/Emscripten\/index.html\" target=\"_blank\" rel=\"noopener\">index .html <\/a>, qui inclut le pr\u00e9chargeur du syst\u00e8me de fichiers du projet. Pour t\u00e9l\u00e9charger sur le Web, j&#8217;ai utilis\u00e9 Unreal Tournament Demo version 338. Comme vous pouvez le voir sur le fichier CMake, le dossier du jeu d\u00e9compress\u00e9 a \u00e9t\u00e9 ajout\u00e9 au r\u00e9pertoire de construction et li\u00e9 en tant que fichier de pr\u00e9chargement pour Emscripten.<\/p>\n<h3>Modifications du code principal<\/h3>\n<p>Ensuite, il a fallu changer la boucle de jeu du jeu, vous ne pouvez pas ex\u00e9cuter une boucle sans fin, cela conduit au gel du navigateur, vous devez plut\u00f4t utiliser emscripten_set_main_loop, j&#8217;ai \u00e9crit \u00e0 propos de cette fonctionnalit\u00e9 dans ma note de 2017 \u00ab < a href=\"https:\/\/demensdeum.com \/blog\/ru\/2017\/03\/29\/porting-sdl-c-game-to-html5-emscripten\/\" rel=\"noopener\" target=\"_blank\">Porter le jeu SDL C++ vers HTML5 (Emscripten)<\/a>\u201d<br \/>\nNous modifions le code pour quitter la boucle while en if, puis nous affichons la classe principale du moteur de jeu, qui contient la boucle de jeu, dans la port\u00e9e globale, et \u00e9crivons une fonction globale qui appellera l&#8217;\u00e9tape de boucle de jeu \u00e0 partir de l&#8217;objet global :<\/p>\n<div class=\"hcb_wrap\">\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>\n#include &lt;emscripten.h&gt;\n\nEngine *EMSCRIPTEN_GLOBAL_GAME_ENGINE = nullptr;\n\nvoid emscripten_game_loop_step() {\n\n\tEMSCRIPTEN_GLOBAL_GAME_ENGINE-&gt;Run();\n\n}\n\n#endif\n\n<\/code><\/pre>\n<\/div>\n<\/div>\n<p>Apr\u00e8s cela, vous devez vous assurer qu&#8217;il n&#8217;y a pas de threads d&#8217;arri\u00e8re-plan dans l&#8217;application\u00a0; s&#8217;il y en a, pr\u00e9parez-vous \u00e0 les r\u00e9\u00e9crire pour une ex\u00e9cution monothread, ou utilisez la biblioth\u00e8que phtread dans Emscripten.<br \/>\nLe fil d&#8217;arri\u00e8re-plan dans Surreal Engine est utilis\u00e9 pour lire de la musique, les donn\u00e9es proviennent du fil du moteur principal concernant la piste en cours, la n\u00e9cessit\u00e9 de jouer de la musique ou son absence, puis le fil d&#8217;arri\u00e8re-plan re\u00e7oit un nouvel \u00e9tat via un mutex et commence \u00e0 jouer de la nouvelle musique. , ou le met en pause. Le flux d&#8217;arri\u00e8re-plan est \u00e9galement utilis\u00e9 pour mettre la musique en m\u00e9moire tampon pendant la lecture.<br \/>\nMes tentatives de cr\u00e9ation de Surreal Engine pour Emscripten avec pthread ont \u00e9chou\u00e9, car les ports SDL2 et OpenAL ont \u00e9t\u00e9 construits sans le support de pthread, et je ne voulais pas les reconstruire pour le plaisir de la musique. Par cons\u00e9quent, j&#8217;ai transf\u00e9r\u00e9 la fonctionnalit\u00e9 du flux de musique de fond vers une ex\u00e9cution monothread \u00e0 l&#8217;aide d&#8217;une boucle. En supprimant les appels pthread du code C++, j&#8217;ai d\u00e9plac\u00e9 la mise en m\u00e9moire tampon et la lecture de musique vers le thread principal, afin qu&#8217;il n&#8217;y ait pas de retard, j&#8217;ai augment\u00e9 la m\u00e9moire tampon de quelques secondes.<\/p>\n<p>Ensuite, je d\u00e9crirai des impl\u00e9mentations sp\u00e9cifiques des graphiques et du son.<\/p>\n<h3>Vulkan n&#8217;est pas pris en charge\u00a0!<\/h3>\n<p>Oui, Vulkan n&#8217;est pas pris en charge en HTML5, bien que toutes les brochures marketing pr\u00e9sentent le support multiplateforme et large plate-forme comme le principal avantage de Vulkan. Pour cette raison, j&#8217;ai d\u00fb \u00e9crire mon propre moteur de rendu graphique de base pour un type OpenGL simplifi\u00e9 &#8211; &#8211; ES, il est utilis\u00e9 sur les appareils mobiles, parfois il ne contient pas les fonctionnalit\u00e9s \u00e0 la mode de l&#8217;OpenGL moderne, mais il se porte tr\u00e8s bien sur WebGL, ce qui est exactement ce qu&#8217;Emscripten impl\u00e9mente. L&#8217;\u00e9criture du rendu de tuiles de base, du rendu bsp, pour l&#8217;affichage GUI le plus simple et du rendu des mod\u00e8les + cartes a \u00e9t\u00e9 achev\u00e9e en deux semaines. C&#8217;\u00e9tait peut-\u00eatre la partie la plus difficile du projet. Il reste encore beaucoup de travail \u00e0 faire pour impl\u00e9menter toutes les fonctionnalit\u00e9s du rendu Surreal Engine, donc toute aide des lecteurs est la bienvenue sous forme de code et de demandes d&#8217;extraction.<\/p>\n<h3>OpenAL pris en charge\u00a0!<\/h3>\n<p>La grande chance est que Surreal Engine utilise OpenAL pour la sortie audio. Apr\u00e8s avoir \u00e9crit un simple hello world dans OpenAL et l&#8217;avoir assembl\u00e9 dans WebAssembly \u00e0 l&#8217;aide d&#8217;Emscripten, il m&#8217;est devenu clair \u00e0 quel point tout \u00e9tait simple et j&#8217;ai d\u00e9cid\u00e9 de porter le son.<br \/>\nApr\u00e8s plusieurs heures de d\u00e9bogage, il est devenu \u00e9vident que l&#8217;impl\u00e9mentation OpenAL d&#8217;Emscripten avait plusieurs bugs, par exemple, lors de l&#8217;initialisation de la lecture du nombre de canaux mono, la m\u00e9thode a renvoy\u00e9 un nombre infini, et apr\u00e8s avoir essay\u00e9 d&#8217;initialiser un vecteur de taille infinie, C++ plante avec l&#8217;exception vector::length_error.<br \/>\nNous avons r\u00e9ussi \u00e0 contourner ce probl\u00e8me en codant en dur le nombre de canaux mono \u00e0 2\u00a0048\u00a0:<\/p>\n<div class=\"hcb_wrap\">\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>\n\t\talcGetIntegerv(alDevice, ALC_STEREO_SOURCES, 1, &amp;stereoSources);\n\n\n\n#if __EMSCRIPTEN__\n\n\t\tmonoSources = 2048; \/\/ for some reason Emscripten's OpenAL gives infinite monoSources count, bug?\n\n#endif\n\n\n\n<\/code><\/pre>\n<\/div>\n<\/div>\n<h3>Y a-t-il un r\u00e9seau\u00a0?<\/h3>\n<p>Surreal Engine ne prend actuellement pas en charge le jeu en ligne, jouer avec des robots est pris en charge, mais nous avons besoin de quelqu&#8217;un pour \u00e9crire l&#8217;IA pour ces robots. Th\u00e9oriquement, vous pouvez impl\u00e9menter un jeu en r\u00e9seau sur WebAssembly\/Emscripten \u00e0 l&#8217;aide de Websockets.<\/p>\n<h3>Conclusion<\/h3>\n<p>En conclusion, je voudrais dire que le portage de Surreal Engine s&#8217;est av\u00e9r\u00e9 assez fluide gr\u00e2ce \u00e0 l&#8217;utilisation de biblioth\u00e8ques pour lesquelles il existe des ports Emscripten, ainsi que mon exp\u00e9rience pass\u00e9e dans l&#8217;impl\u00e9mentation d&#8217;un jeu en C++ pour WebAssembly. sur Emscripten. Vous trouverez ci-dessous des liens vers des sources de connaissances et des r\u00e9f\u00e9rentiels sur le sujet.<br \/>\n<strong>M-M-M-MONSTER KILL\u00a0!<\/strong><\/p>\n<p>De plus, si vous souhaitez aider le projet, de pr\u00e9f\u00e9rence avec le code de rendu WebGL\/OpenGL ES, alors \u00e9crivez-moi dans Telegram\u00a0:<br \/>\n<a href=\"https:\/\/t.me\/demenscave\" target=\"_blank\" rel=\"noopener\">https:\/\/t.me\/demenscave<\/a><\/p>\n<h3>Liens<\/h3>\n<p><a href=\"https:\/\/demensdeum.com\/demos\/SurrealEngine\/\" target=\"_blank\" rel=\"noopener\">https:\/\/demensdeum.com\/demos\/SurrealEngine\/<\/a><br \/>\n<a href=\"https:\/\/github.com\/demensdeum\/SurrealEngine-Emscripten\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/demensdeum\/SurrealEngine-Emscripten<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/dpjudas\/SurrealEngine\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/dpjudas\/SurrealEngine<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dans cet article, je d\u00e9crirai comment j&#8217;ai port\u00e9 le moteur de jeu Surreal Engine vers WebAssembly. Moteur surr\u00e9aliste\u00a0&#038;#8211\u00a0; un moteur de jeu qui impl\u00e9mente la plupart des fonctionnalit\u00e9s de l&#8217;Unreal Engine 1, des jeux c\u00e9l\u00e8bres sur ce moteur &#8211; Unreal Tournament 99, Unreal, Deus Ex, Undying. Il fait r\u00e9f\u00e9rence aux moteurs classiques qui fonctionnaient principalement<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/fr\/2024\/07\/16\/surreal-engine-cpp-webassembly-port\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Portage du Surreal Engine C++ vers WebAssembly&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[81,61,52],"tags":[231,119],"class_list":["post-3575","post","type-post","status-publish","format-standard","hentry","category-demos","category-techie","category-tutorials","tag-ut99","tag-emscripten","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"fr","enabled_languages":["en","ru","zh","de","fr","ja","pt"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts\/3575","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/comments?post=3575"}],"version-history":[{"count":24,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts\/3575\/revisions"}],"predecessor-version":[{"id":3862,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts\/3575\/revisions\/3862"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/media?parent=3575"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/categories?post=3575"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/tags?post=3575"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}