Adds a self-contained browser playground (editor + canvas + console + REPL) around the Emscripten WebGPU build, plus the engine fixes required to render: - JS<->Squirrel bridge (apply/eval/read/pause) and Emscripten 6 exports - soft hot-reload via load.nut handle_change with __pg state preservation - fix Uint16 index buffer byte sizes in SetIndexBuffer calls - fix dangling GbufferSlot/SceneColorSlot gpuHandle pointers (std::move bug) - fallback shadow depth texture when no shadow map is configured - fix WGSL syntax (mod/ivec2) and default shadow sampler maxAnisotropy - serve_webgpu.py COOP/COEP server and playground docs/demos/assets
76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Serve the EVEngine WebGPU build directory with cross-origin isolation.
|
|
|
|
The Emscripten build runs the engine on pthreads and needs SharedArrayBuffer,
|
|
so the page MUST be served with COOP/COEP headers -- opening eve.html via
|
|
file:// will not work. This server adds those headers plus no-store caching so
|
|
rebuilt eve.js / eve.wasm / eve.data are always picked up.
|
|
|
|
Usage (from the repo root):
|
|
python scripts/serve_webgpu.py # serves build/webgpu-web/src/engine :8090
|
|
python scripts/serve_webgpu.py <engine-dir> [port]
|
|
"""
|
|
|
|
import argparse
|
|
import http.server
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
class PlaygroundHandler(http.server.SimpleHTTPRequestHandler):
|
|
def end_headers(self):
|
|
# Required for Emscripten pthreads / SharedArrayBuffer.
|
|
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
|
|
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
|
|
# The engine files are regenerated on every build; never cache them.
|
|
self.send_header("Cache-Control", "no-store")
|
|
super().end_headers()
|
|
|
|
def log_message(self, fmt, *args):
|
|
sys.stderr.write("[serve] %s\n" % (fmt % args))
|
|
|
|
|
|
def main():
|
|
default_dir = (
|
|
Path(__file__).resolve().parent.parent
|
|
/ "build" / "webgpu-web" / "src" / "engine"
|
|
)
|
|
parser = argparse.ArgumentParser(
|
|
description="Serve the EVEngine WebGPU build (COOP/COEP)."
|
|
)
|
|
parser.add_argument(
|
|
"engine_dir",
|
|
nargs="?",
|
|
type=Path,
|
|
default=default_dir,
|
|
help="Directory containing eve.html (default: %(default)s)",
|
|
)
|
|
parser.add_argument("port", nargs="?", type=int, default=8090,
|
|
help="Port (default: 8090)")
|
|
args = parser.parse_args()
|
|
|
|
engine_dir = args.engine_dir.resolve()
|
|
if not (engine_dir / "eve.html").is_file():
|
|
print("error: %s does not contain eve.html" % engine_dir)
|
|
print(
|
|
"Build first:\n"
|
|
" emcmake cmake -B build/webgpu-web -G Ninja -DCMAKE_BUILD_TYPE=Release\n"
|
|
" cmake --build build/webgpu-web"
|
|
)
|
|
return 1
|
|
|
|
os.chdir(engine_dir)
|
|
httpd = http.server.ThreadingHTTPServer(("127.0.0.1", args.port), PlaygroundHandler)
|
|
print("Serving %s" % engine_dir)
|
|
print("Open http://127.0.0.1:%d/eve.html in Chrome/Edge 113+ (WebGPU enabled)." % args.port)
|
|
try:
|
|
httpd.serve_forever()
|
|
except KeyboardInterrupt:
|
|
pass
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|