#!/usr/bin/env bash # Compila o Open Surge do fredygames.com: o jogo de plataforma e motor de jogos de Alexandre Martins # (Open Surge Engine; codigo GPL-3.0-or-later, scripts em SurgeScript sob MIT, imagens, sons e musicas # com licencas por arquivo listadas em src/misc/copyright_data.csv) em WebAssembly, com o Emscripten # 6.0.10 e as portas SDL2 2.32.10, FreeType, libpng, libjpeg, zlib, libogg e libvorbis dele. Este # script e os patches fazem parte do codigo-fonte publicado junto do jogo. # # source /emsdk_env.sh # emsdk install 6.0.10 && emsdk activate 6.0.10 # src/FredGames.Bundler/Builds/build-open-surge.sh # precisa tambem de cmake e make # # Fontes (tarballs conferidos pelo SHA-256, guardados em artifacts/cache/opensurge/): # - alemart/opensurge no commit 61975c2 (2026-10-08); # - alemart/surgescript no commit 24c0067 (Apache-2.0; a linguagem dos scripts do jogo); # - Allegro 5.2.11.3 (zlib-like, giftware nas imagens de abertura, que o jogo nao usa aqui), compilada # com o backend SDL2 (experimental, o caminho oficial dele para o Emscripten); # - PhysicsFS 3.2.0 (zlib). # # open-surge-fredygames.patch (nos fontes do jogo): # - o SurgeScript carrega no mesmo fio (o navegador nao tem threads); # - caixas de dialogo nativas, escolha de arquivo/pasta, links externos e modos de importacao ficam fora; # - os arquivos de dados sem licenca livre ficam de fora da pasta de dados (ver abaixo). # # Saida: artifacts/build/open-surge-61975c2/open-surge.{js,wasm,data}, que o bundle.yaml do jogo confere # pelo SHA-256. set -euo pipefail OS_COMMIT=61975c23e7e877a55dfcab0e10f035907ae4ecb4 OS_SHA256=335242032884ada49daecb3bd9a4cdcebacc07d9ae983b07a6c8731e6f0e659f SS_COMMIT=24c0067ba100dc495c76ceedc4a471c5d6af3f24 SS_SHA256=246126814d8285f43022d2805e06fc825bb43802e964d2f5feb34a58d79928d8 A5=5.2.11.3 A5_SHA256=aba4679a5b1f2bf62482eba6e8814a94de7ffc86de5f8587ba199fcc61b4a04f PHYSFS=3.2.0 PHYSFS_SHA256=1991500eaeb8d5325e3a8361847ff3bf8e03ec89252b7915e1f25b3f8ab5d560 EMSCRIPTEN=6.0.10 here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" root="$(git -C "$here" rev-parse --show-toplevel 2>/dev/null || pwd)" out="$root/artifacts/build/open-surge-${OS_COMMIT:0:7}" cache="$root/artifacts/cache/opensurge" if ! emcc --version 2>/dev/null | head -1 | grep -q " $EMSCRIPTEN "; then echo "Precisa do Emscripten $EMSCRIPTEN no PATH (source /emsdk_env.sh)." >&2 exit 1 fi for tool in cmake make; do command -v "$tool" >/dev/null || { echo "Precisa do $tool no PATH." >&2; exit 1; } done # Arquivo auxiliar: em open-surge/ (repositorio) ou ao lado do script (pasta de fontes do site). aux() { if [ -f "$here/open-surge/$1" ]; then echo "$here/open-surge/$1"; else echo "$here/$1"; fi } # Tarball ao lado do script, no cache ou baixado do endereco original; confere o SHA-256. fetch() { local name="$1" url="$2" sha="$3" file if [ -f "$here/$name" ]; then file="$here/$name" else file="$cache/$name" if [ ! -f "$file" ]; then mkdir -p "$cache" curl -fsSL -o "$file.part" "$url" mv "$file.part" "$file" fi fi echo "$sha $file" | shasum -a 256 -c - >&2 echo "$file" } os_tar="$(fetch "opensurge-${OS_COMMIT:0:7}.tar.gz" "https://github.com/alemart/opensurge/archive/$OS_COMMIT.tar.gz" "$OS_SHA256")" ss_tar="$(fetch "surgescript-${SS_COMMIT:0:7}.tar.gz" "https://github.com/alemart/surgescript/archive/$SS_COMMIT.tar.gz" "$SS_SHA256")" a5_tar="$(fetch "allegro-$A5.tar.gz" "https://github.com/liballeg/allegro5/releases/download/$A5/allegro-$A5.tar.gz" "$A5_SHA256")" pf_tar="$(fetch "physfs-$PHYSFS.tar.gz" "https://github.com/icculus/physfs/archive/refs/tags/release-$PHYSFS.tar.gz" "$PHYSFS_SHA256")" # OPEN_SURGE_KEEP_LIBS=1 (so para desenvolver o patch): reaproveita as bibliotecas ja compiladas. keep=${OPEN_SURGE_KEEP_LIBS:-0} if [ "$keep" = 1 ] && [ -f "$out/prefix/lib/libsurgescript-static.a" ]; then rm -rf "$out/opensurge" "$out/obj" "$out/gen" "$out"/open-surge.* else keep=0 rm -rf "$out" fi mkdir -p "$out/prefix" cd "$out" tar xzf "$os_tar"; mv "opensurge-$OS_COMMIT" opensurge if [ "$keep" = 0 ]; then tar xzf "$ss_tar"; mv "surgescript-$SS_COMMIT" surgescript tar xzf "$a5_tar" tar xzf "$pf_tar" patch -d "allegro-$A5" -p1 --no-backup-if-mismatch < "$(aux allegro-fredygames.patch)" fi if [ -f "$(aux open-surge-fredygames.patch)" ]; then patch -d opensurge -p1 --no-backup-if-mismatch < "$(aux open-surge-fredygames.patch)" fi L="$EMSDK/upstream/emscripten/cache/sysroot" ports=(-sUSE_SDL=2 -sUSE_FREETYPE=1 -sUSE_VORBIS=1 -sUSE_OGG=1 -sUSE_LIBJPEG=1 -sUSE_LIBPNG=1 -sUSE_ZLIB=1) cflags=(-O2 -ffile-prefix-map="$out/=" -w "${ports[@]}") if [ "$keep" = 0 ]; then # PhysicsFS: so a biblioteca estatica; sem os formatos de arquivo que o jogo nao usa. emcmake cmake -S "physfs-release-$PHYSFS" -B build-physfs -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_C_FLAGS="${cflags[*]}" -DCMAKE_INSTALL_PREFIX=/usr \ -DPHYSFS_BUILD_SHARED=OFF -DPHYSFS_BUILD_STATIC=ON -DPHYSFS_BUILD_TEST=OFF -DPHYSFS_BUILD_DOCS=OFF \ -DPHYSFS_ARCHIVE_7Z=OFF -DPHYSFS_ARCHIVE_GRP=OFF -DPHYSFS_ARCHIVE_WAD=OFF -DPHYSFS_ARCHIVE_HOG=OFF \ -DPHYSFS_ARCHIVE_MVL=OFF -DPHYSFS_ARCHIVE_QPAK=OFF -DPHYSFS_ARCHIVE_SLB=OFF \ -DPHYSFS_ARCHIVE_ISO9660=OFF -DPHYSFS_ARCHIVE_VDF=OFF >/dev/null cmake --build build-physfs -j6 >/dev/null cmake --install build-physfs --prefix "$out/prefix" >/dev/null # Allegro 5 sobre SDL2 (ALLEGRO_SDL), sem threads: o relogio dos timers roda dentro do laco de eventos # (WANT_WAIT_EVENT_SLEEP). Sem OpenAL (o audio sai pelo SDL), sem os dialogos nativos. emcmake cmake -S "allegro-$A5" -B build-allegro -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="${cflags[*]} -I$out/prefix/include" -DCMAKE_CXX_FLAGS="${cflags[*]} -I$out/prefix/include" \ -DCMAKE_INSTALL_PREFIX=/usr -DALLEGRO_SDL=ON -DSHARED=OFF -DWANT_MONOLITH=OFF -DWANT_ALLOW_SSE=OFF \ -DWANT_DOCS=OFF -DWANT_TESTS=OFF -DWANT_EXAMPLES=OFF -DWANT_DEMO=OFF -DWANT_OPENAL=OFF \ -DWANT_WAIT_EVENT_SLEEP=ON -DWANT_NATIVE_IMAGE_LOADER=OFF -DWANT_VIDEO=OFF -DWANT_FLAC=OFF \ -DWANT_OPUS=OFF -DWANT_DUMB=OFF -DWANT_NATIVE_DIALOG=OFF -DWANT_PHYSFS=ON \ -DSDL2_INCLUDE_DIR="$L/include/SDL2" \ -DVORBIS_LIBRARY="$L/lib/wasm32-emscripten/libvorbis.a" -DVORBISFILE_LIBRARY="$L/lib/wasm32-emscripten/libvorbis.a" \ -DOGG_LIBRARY="$L/lib/wasm32-emscripten/libogg.a" -DVORBIS_INCLUDE_DIR="$L/include" \ -DPHYSFS_INCLUDE_DIR="$out/prefix/include" -DPHYSFS_LIBRARY="$out/prefix/lib/libphysfs.a" >/dev/null cmake --build build-allegro -j6 >/dev/null cmake --install build-allegro --prefix "$out/prefix" >/dev/null # SurgeScript: so a biblioteca. emcmake cmake -S surgescript -B build-surgescript -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="${cflags[*]}" -DCMAKE_INSTALL_PREFIX=/usr -DWANT_SHARED=OFF -DWANT_STATIC=ON \ -DWANT_EXECUTABLE=OFF >/dev/null cmake --build build-surgescript -j6 >/dev/null cmake --install build-surgescript --prefix "$out/prefix" >/dev/null fi # Open Surge: os mesmos .c que o srcs.cmake lista, mais a tela de creditos gerada da tabela de licencas. cd opensurge srcs=$(grep -o 'src/[A-Za-z0-9_/]*\.c' src/misc/cmake/srcs.cmake | LC_ALL=C sort -u) mkdir -p ../obj ../gen python3 -I - <<'PY' import re csv = open('src/misc/copyright_data.csv', encoding='utf-8').read().splitlines() cstr = ''.join('\n"%s\\n"' % l for l in csv) t = open('src/misc/credits.c.in', encoding='utf-8').read().replace('@COPYRIGHT_DATA_CSV@', cstr) open('../gen/credits.c', 'w', encoding='utf-8').write(t) PY defs=(-DWANT_BETTER_GAMEPAD=1 -DWANT_GLES=1 -DGAME_USERDIRNAME='"opensurge"' -DGAME_DATADIR='"/usr/share/games/opensurge"' -DGAME_BUILD_VERSION='"fredygames"') inc=(-I"$out/prefix/include" -I"$out/prefix/include/surgescript" -I"$out/allegro-$A5/addons/native_dialog") for f in $srcs; do # sem o FastDraw (al_draw_indexed_prim com indices de 32 bits nao existe no WebGL 1) case "$f" in src/misc/credits.c|src/third_party/fast_draw.c) continue;; esac emcc "${cflags[@]}" -std=gnu99 "${defs[@]}" "${inc[@]}" -c "$f" -o "../obj/$(echo "${f%.c}" | tr / _).o" done emcc "${cflags[@]}" -std=gnu99 "${defs[@]}" "${inc[@]}" -c ../gen/credits.c -o ../obj/src_misc_credits.o emcc "${cflags[@]}" "${inc[@]}" -c "$(aux native_dialog_stub.c)" -o ../obj/native_dialog_stub.o cd "$out/opensurge" # Os dados, como o assets.cmake os instala, menos o que nao tem licenca livre ou nao serve aqui: # - as duas imagens Giftware do Allegro (tela de abertura "Allegro" e logo) e tudo que as usa; # - o desenho "tux concept art" (CC BY 4.0, mas o jogo nao o usa); # - o poster surge.png, o logo e os arquivos de projeto (README, CONTRIBUTING, CHANGELOG). d="$out/data-root/usr/share/games/opensurge" mkdir -p "$d" for f in LICENSE surge.cfg; do cp "$f" "$d/"; done for dir in characters scripts sprites images levels musics quests samples themes languages fonts inputs licenses; do cp -R "$dir" "$d/" done ( cd "$d" rm -f "images/scenes/allegro_splash.png" "images/liballeg.png" "images/tux concept art.png" \ "images/tux_concept_art.png" "licenses/Giftware-license.txt" \ levels/scenes/allegro_splash.lev levels/scenes/allegro.lev \ themes/scenes/allegro_splash.bg themes/scenes/allegro.bg \ scripts/setup/scenes/allegro_splash.ss sprites/legacy/cutscenes/allegro.spr \ scripts/legacy/cutscenes/allegro.obj musics/allegro.ogg grep -v 'allegro_splash.lev' quests/intro.qst > quests/intro.qst.new mv quests/intro.qst.new quests/intro.qst ) # Liga tudo; o laco do jogo espera os eventos em al_wait_for_event, que devolve a vez ao navegador # (Asyncify). A pilha padrao (64 KB) e curta para o SurgeScript. libs=(-L"$out/prefix/lib" -lallegro_image-static -lallegro_primitives-static -lallegro_color-static -lallegro_font-static -lallegro_ttf-static -lallegro_acodec-static -lallegro_audio-static -lallegro_memfile-static -lallegro_physfs-static -lallegro-static -lphysfs -lsurgescript-static) cd "$out" emcc "${cflags[@]}" $(LC_ALL=C ls obj/*.o) "${libs[@]}" -lm -lidbfs.js \ -sFULL_ES2=1 -sMIN_WEBGL_VERSION=1 -sMAX_WEBGL_VERSION=2 \ -sASYNCIFY -sASYNCIFY_STACK_SIZE=65536 -sALLOW_MEMORY_GROWTH -sINITIAL_MEMORY=128MB -sSTACK_SIZE=4MB \ -sENVIRONMENT=web -sEXIT_RUNTIME=1 -sEXPORTED_RUNTIME_METHODS=FS,ENV,addRunDependency,removeRunDependency \ -sEXPORTED_FUNCTIONS=_main \ --preload-file "data-root/usr@/usr" ${OPEN_SURGE_LDEXTRA:-} \ -o open-surge.js shasum -a 256 "$out/open-surge.js" "$out/open-surge.wasm" "$out/open-surge.data"