diff --git a/Makefile b/Makefile index f90c785c..57e471c5 100644 --- a/Makefile +++ b/Makefile @@ -1042,6 +1042,38 @@ ifeq ($(PLATFORM),sunos) else # ifeq sunos +############################################################################# +# SETUP AND BUILD -- emscripten +############################################################################# + +ifeq ($(PLATFORM),emscripten) + + # 1. Create "baseq3" directory in the same directory as this Makefile. + # 2. Copy pak[0-8].pk3 into the created "baseq3" directory. + # 3. Run `/path/to/emsdk.sh` + # 4. Run `make PLATFORM=emscripten` + # 5. Serve the build/release-emscripten-wasm32/ioquake3_opengl2.{html,js,wasm,data} from a web server. + # 6. Load ioquake3_opengl2.html in a web browser. + + CC=emcc + ARCH=wasm32 + + # LDFLAGS+=-s MAIN_MODULE is needed for dlopen() in client/server but it causes compile errors + USE_RENDERER_DLOPEN=0 + + BASE_CFLAGS=-fPIC -s USE_SDL=2 + LDFLAGS=-s TOTAL_MEMORY=256mb -s MAX_WEBGL_VERSION=2 --preload-file baseq3 + OPTIMIZEVM = -O3 + OPTIMIZE = $(OPTIMIZEVM) + + FULLBINEXT=.html + + SHLIBEXT=wasm + SHLIBCFLAGS=-fPIC + SHLIBLDFLAGS=-s SIDE_MODULE + +else # ifeq emscripten + ############################################################################# # SETUP AND BUILD -- GENERIC ############################################################################# @@ -1060,6 +1092,7 @@ endif #OpenBSD endif #NetBSD endif #IRIX endif #SunOS +endif #emscripten ifndef CC CC=gcc @@ -1085,18 +1118,37 @@ endif ifneq ($(BUILD_SERVER),0) TARGETS += $(B)/$(SERVERBIN)$(FULLBINEXT) + + ifeq ($(PLATFORM),emscripten) + EMSCRIPTENOBJ += $(B)/$(SERVERBIN).js \ + $(B)/$(SERVERBIN).wasm \ + $(B)/$(SERVERBIN).data + endif endif ifneq ($(BUILD_CLIENT),0) + TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) + + ifeq ($(PLATFORM),emscripten) + EMSCRIPTENOBJ += $(B)/$(CLIENTBIN).js \ + $(B)/$(CLIENTBIN).wasm \ + $(B)/$(CLIENTBIN).data + endif + ifneq ($(USE_RENDERER_DLOPEN),0) - TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) $(B)/renderer_opengl1_$(SHLIBNAME) + TARGETS += $(B)/renderer_opengl1_$(SHLIBNAME) ifneq ($(BUILD_RENDERER_OPENGL2),0) TARGETS += $(B)/renderer_opengl2_$(SHLIBNAME) endif else - TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) ifneq ($(BUILD_RENDERER_OPENGL2),0) TARGETS += $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT) + + ifeq ($(PLATFORM),emscripten) + EMSCRIPTENOBJ += $(B)/$(CLIENTBIN)_opengl2.js \ + $(B)/$(CLIENTBIN)_opengl2.wasm \ + $(B)/$(CLIENTBIN)_opengl2.data + endif endif endif endif @@ -1870,10 +1922,15 @@ Q3OBJ = \ ifdef MINGW Q3OBJ += \ $(B)/client/con_passive.o +else +ifeq ($(PLATFORM),emscripten) + Q3OBJ += \ + $(B)/client/con_passive.o else Q3OBJ += \ $(B)/client/con_tty.o endif +endif Q3R2OBJ = \ $(B)/renderergl2/tr_animation.o \ @@ -3044,6 +3101,7 @@ clean2: @rm -f $(OBJ) @rm -f $(OBJ_D_FILES) @rm -f $(STRINGOBJ) + @rm -f $(EMSCRIPTENOBJ) @rm -f $(TARGETS) toolsclean: toolsclean-debug toolsclean-release diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 72dbfe1d..53a53264 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -290,6 +290,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif +//================================================================== EMSCRIPTEN === + +#ifdef __EMSCRIPTEN__ + +#define OS_STRING "emscripten" +#define ID_INLINE inline +#define PATH_SEP '/' + +#define ARCH_STRING "wasm32" + +#define Q3_LITTLE_ENDIAN + +#define DLL_EXT ".wasm" + +#endif + //================================================================== Q3VM === #ifdef Q3_VM diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index a3c5bb82..2678dc71 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -398,7 +398,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool int profileMask; int majorVersion; int minorVersion; - } contexts[3]; + } contexts[4]; int numContexts, type; const char *glstring; int perChannelColorBits; @@ -543,6 +543,14 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool ( r_preferOpenGLES->integer == -1 && profileMask == SDL_GL_CONTEXT_PROFILE_ES ) ); if ( preferOpenGLES ) { +#ifdef __EMSCRIPTEN__ + // WebGL 2.0 isn't fully backward compatible so you have to ask for it specifically + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_ES; + contexts[numContexts].majorVersion = 3; + contexts[numContexts].minorVersion = 0; + numContexts++; +#endif + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_ES; contexts[numContexts].majorVersion = 2; contexts[numContexts].minorVersion = 0; @@ -560,6 +568,13 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool numContexts++; if ( !preferOpenGLES ) { +#ifdef __EMSCRIPTEN__ + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_ES; + contexts[numContexts].majorVersion = 3; + contexts[numContexts].minorVersion = 0; + numContexts++; +#endif + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_ES; contexts[numContexts].majorVersion = 2; contexts[numContexts].minorVersion = 0; diff --git a/code/sys/sys_main.c b/code/sys/sys_main.c index 0113920b..d7341806 100644 --- a/code/sys/sys_main.c +++ b/code/sys/sys_main.c @@ -31,6 +31,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #ifndef DEDICATED #ifdef USE_LOCAL_HEADERS # include "SDL.h" @@ -863,10 +867,14 @@ int main( int argc, char **argv ) signal( SIGTERM, Sys_SigHandler ); signal( SIGINT, Sys_SigHandler ); +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop( Com_Frame, 0, 1 ); +#else while( 1 ) { Com_Frame( ); } +#endif return 0; }