Skip to content

Commit

Permalink
Merge PR 'Added Webassembly support and fixed GLES2 (somewhat)'
Browse files Browse the repository at this point in the history
Webassembly version doesn’t work online and screen flashes on GLES2 are
opaque.

See DarkPlacesEngine/DarkPlaces#169

---------

Signed-off-by: bones_was_here <[email protected]>
Co-authored-by: James O'Neill <[email protected]>
Co-authored-by: bones_was_here <[email protected]>
  • Loading branch information
3 people authored Aug 11, 2024
1 parent 5772ed2 commit 558f167
Show file tree
Hide file tree
Showing 21 changed files with 890 additions and 79 deletions.
58 changes: 55 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ on:
pull_request:

jobs:
build:

sdl-release:
runs-on: ubuntu-latest
container:
image: debian:latest
Expand All @@ -26,7 +25,7 @@ jobs:
# make `git describe` show the correct commit hash
fetch-depth: '0'

- name: Compile DP
- name: Compile
run: |
# prevent git complaining about dubious ownership of the repo
chown -R root:root .
Expand All @@ -43,3 +42,56 @@ jobs:
path: |
darkplaces-sdl
wasm-release:
runs-on: ubuntu-latest
container:
image: debian:latest
steps:
- name: Install dependencies
run: |
apt update
apt install --yes build-essential python3-certifi
- name: Fetch repository
uses: actions/[email protected]
with:
# make `git describe` show the correct commit hash
fetch-depth: '0'

- uses: actions/setup-python@v5
with:
python-version: '3'

- name: Install emsdk
uses: actions/[email protected]
with:
repository: emscripten-core/emsdk
path: emsdk

- name: Compile
shell: bash
run: |
cd emsdk
# Download and install the latest SDK tools.
./emsdk install latest
# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./emsdk activate latest
# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
cd ..
# fail if there's any warnings
#export CC="cc"
make emscripten-release
- name: Upload WASM artifacts
uses: actions/upload-artifact@v4
with:
name: Wasm
path: |
darkplaces-wasm.js
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ ChangeLog
darkplaces-agl
darkplaces-glx
darkplaces-sdl
darkplaces-wasm.html
darkplaces-wasm.js
darkplaces-dedicated
gmon.out
*.ncb
Expand All @@ -41,3 +43,10 @@ Makefile.win
*.pdb
*.lib
*.exp

# emscripten
build-obj/
emsdk/
docs/output/
wasm/preload/*
!wasm/preload/runhere
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,29 @@ The Release build crashes. The Debug x64 build doesn't crash (but is rather slow
To get a build suitable for playing you'll need to use MinGW GCC, or download the autobuild from Xonotic (see above).


### Web-Assembly (Emscripten)

Note that this requires a linux device or WSL2.

1. Install the [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended)
1. After activating and sourcing emsdk, compile DarkPlaces for wasm using;
```shell
make emscripten-release
```
1. Copy `darkplaces-wasm.js`, `wasm/index.html`, and `wasm/autoexec.cfg` files to your web server
1. Copy the Quake `pak0.pak` and any other files into the same web server directory

For the standalone version (single HTML file containing engine and data):
1. Before compiling, copy game data and .cfg files to the appropriate gamedir in `wasm/preload` (for example, pak0 from Quake would be in `wasm/preload/id1/pak0.pak`)
1. After activating and sourcing emsdk, compile DarkPlaces for wasm using;
```shell
make emscripten-standalone
```
1. To start DP you must click somewhere in the window!
1. If you want to upload files into the game filesystem, use `em_upload` in the darkplaces console (upload to /save if you want it to save across restarts)
1. To save the stuff you uploaded to /save, use `em_save` (note that if you embedded the game, you won't be able to save changes to `/save/games`)


## Contributing

[DarkPlaces Contributing Guidelines](CONTRIBUTING.md)
Expand Down
4 changes: 4 additions & 0 deletions fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,10 @@ void FS_Init_Commands(void)
Cmd_AddCommand(CF_SHARED, "ls", FS_Ls_f, "list files in searchpath matching an * filename pattern, multiple per line");
Cmd_AddCommand(CF_SHARED, "which", FS_Which_f, "accepts a file name as argument and reports where the file is taken from");

#ifdef __EMSCRIPTEN__
Sys_EM_Register_Commands();
#endif

if (com_startupgamegroup == GAME_NORMAL)
Cmd_AddCommand(CF_SHARED, "game", FS_GameDir_f, "alias of gamedir, for compatibility with some Quake mod READMEs");
}
Expand Down
11 changes: 10 additions & 1 deletion gl_backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ cvar_t gl_printcheckerror = {CF_CLIENT, "gl_printcheckerror", "0", "prints all O
cvar_t r_render = {CF_CLIENT, "r_render", "1", "enables rendering 3D views (you want this on!)"};
cvar_t r_renderview = {CF_CLIENT, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
cvar_t r_waterwarp = {CF_CLIENT | CF_ARCHIVE, "r_waterwarp", "1", "warp view while underwater"};
#ifdef USE_GLES2
cvar_t gl_polyblend = {CF_CLIENT | CF_ARCHIVE, "gl_polyblend", "0", "tints view while underwater, hurt, etc"};
#else
cvar_t gl_polyblend = {CF_CLIENT | CF_ARCHIVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
#endif

cvar_t v_flipped = {CF_CLIENT, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
qbool v_flipped_state = false;
Expand Down Expand Up @@ -966,8 +970,12 @@ int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colorte
case RENDERPATH_GLES2:
CHECKGLERROR
qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);

#ifndef USE_GLES2
R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL); // This breaks GLES2.
// GL_ARB_framebuffer_object (GL3-class hardware) - depth stencil attachment
#endif

#ifdef USE_GLES2
// FIXME: separate stencil attachment on GLES
if (depthtexture && depthtexture->texnum ) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR }
Expand All @@ -984,6 +992,7 @@ int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colorte
if (depthtexture->glisdepthstencil) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR }
}
#endif

if (colortexture && colortexture->texnum ) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR }
if (colortexture2 && colortexture2->texnum) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR }
if (colortexture3 && colortexture3->texnum) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR }
Expand Down
68 changes: 10 additions & 58 deletions host.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ void Host_SaveConfig(const char *file)

Key_WriteBindings (f);
Cvar_WriteVariables (&cvars_all, f);

#ifdef __EMSCRIPTEN__
js_syncFS(false);
#endif
FS_Close (f);
}
}
Expand Down Expand Up @@ -371,7 +373,7 @@ void Host_UnlockSession(void)
Host_Init
====================
*/
static void Host_Init (void)
void Host_Init (void)
{
int i;
char vabuf[1024];
Expand All @@ -388,6 +390,9 @@ static void Host_Init (void)

host.state = host_init;

host.realtime = 0;
host.dirtytime = Sys_DirtyTime();

if (setjmp(host.abortframe)) // Huh?!
Sys_Error("Engine initialization failed. Check the console (if available) for additional information.\n");

Expand Down Expand Up @@ -567,10 +572,10 @@ static void Host_Init (void)
===============
Host_Shutdown
Cleanly shuts down after the main loop exits.
Cleanly shuts down, Host_Frame() must not be called again after this.
===============
*/
static void Host_Shutdown(void)
void Host_Shutdown(void)
{
if (Sys_CheckParm("-profilegameonly"))
Sys_AllowProfiling(false);
Expand Down Expand Up @@ -617,7 +622,7 @@ Host_Frame
Runs all active servers
==================
*/
static double Host_Frame(double time)
double Host_Frame(double time)
{
double cl_wait, sv_wait;

Expand Down Expand Up @@ -655,56 +660,3 @@ static double Host_Frame(double time)
else
return min(cl_wait, sv_wait); // listen server or singleplayer
}

// Cloudwalk: Most overpowered function declaration...
static inline double Host_UpdateTime (double newtime, double oldtime)
{
double time = newtime - oldtime;

if (time < 0)
{
// warn if it's significant
if (time < -0.01)
Con_Printf(CON_WARN "Host_UpdateTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, time);
time = 0;
}
else if (time >= 1800)
{
Con_Printf(CON_WARN "Host_UpdateTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, time);
time = 0;
}

return time;
}

void Host_Main(void)
{
double time, oldtime, sleeptime;

Host_Init(); // Start!

host.realtime = 0;
oldtime = Sys_DirtyTime();

// Main event loop
while(host.state < host_shutdown) // see Sys_HandleCrash() comments
{
// Something bad happened, or the server disconnected
if (setjmp(host.abortframe))
{
host.state = host_active; // In case we were loading
continue;
}

host.dirtytime = Sys_DirtyTime();
host.realtime += time = Host_UpdateTime(host.dirtytime, oldtime);
oldtime = host.dirtytime;

sleeptime = Host_Frame(time);
++host.framecount;
sleeptime -= Sys_DirtyTime() - host.dirtytime; // execution time
host.sleeptime = Sys_Sleep(sleeptime);
}

Host_Shutdown();
}
5 changes: 3 additions & 2 deletions host.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ typedef struct host_static_s
} host_static_t;

extern host_static_t host;

void Host_Main(void);
void Host_Error(const char *error, ...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN;
void Host_UpdateVersion(void);
void Host_LockSession(void);
void Host_UnlockSession(void);
void Host_AbortCurrentFrame(void) DP_FUNC_NORETURN;
void Host_SaveConfig(const char *file);
void Host_Init(void);
double Host_Frame(double time);
void Host_Shutdown(void);

#endif
29 changes: 29 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,35 @@ ifeq ($(DP_MAKE_TARGET), linux)
DP_LINK_XMP?=dlopen
endif

ifeq ($(DP_MAKE_TARGET), wasm)
MAKE=emmake make
# CFLAGS_EXTRA+=--use-port=sdl2 \
# --use-port=libpng \
# --use-port=libjpeg \
# --use-port=zlib \
# -DNOSUPPORTIPV6 \
# -DUSE_GLES2
CFLAGS_EXTRA+=-s USE_SDL=2 \
-s USE_LIBPNG=1 \
-s USE_LIBJPEG=1 \
-s USE_ZLIB=1 \
-DNOSUPPORTIPV6 \
-DUSE_GLES2

SDLCONFIG_CFLAGS=$(SDLCONFIG_UNIXCFLAGS) $(SDLCONFIG_UNIXCFLAGS_X11)
SDLCONFIG_LIBS=$(SDLCONFIG_UNIXLIBS) $(SDLCONFIG_UNIXLIBS_X11)
SDLCONFIG_STATICLIBS=$(SDLCONFIG_UNIXSTATICLIBS) $(SDLCONFIG_UNIXSTATICLIBS_X11)
DP_SSE=0

DP_LINK_SDL?=shared
DP_LINK_ZLIB?=shared
DP_LINK_JPEG?=dlopen
DP_LINK_ODE?=
DP_LINK_CRYPTO?=dlopen
DP_LINK_CRYPTO_RIJNDAEL?=dlopen
DP_LINK_XMP?=dlopen
endif

# Mac OS X configuration
ifeq ($(DP_MAKE_TARGET), macosx)
OBJ_ICON=
Expand Down
Loading

0 comments on commit 558f167

Please sign in to comment.