From a343d8d843cdd25d52c3440fc8c29ebfb16e20c3 Mon Sep 17 00:00:00 2001 From: Spoike Date: Wed, 31 Jul 2013 00:20:16 +0000 Subject: [PATCH] Reduce webgl dependancies (no more q2/q3/plugins which wouldn't work anyway). Use websockets via our own javascript thunk to avoid issues/weirdness with emscripten's bsdsockets emulation. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4444 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 7 +-- engine/client/cl_main.c | 4 ++ engine/client/m_mp3.c | 22 ++------ engine/client/view.c | 10 +++- engine/common/bothdefs.h | 47 ++++++++++++----- engine/common/common.c | 18 +++++++ engine/common/net.h | 2 +- engine/common/net_wins.c | 108 +++++++++++++++++++++++++++++++++++---- engine/common/netinc.h | 11 ++-- engine/web/ftejslib.js | 76 +++++++++++++++++++++++++++ 10 files changed, 252 insertions(+), 53 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index 7ef551355..4a739d166 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1119,13 +1119,14 @@ endif ifeq ($(FTE_TARGET),web) WEB_PREJS ?= --pre-js web/prejs.js - WEB_MEMORY?=402653184 + WEB_MEMORY?=402653184 #384mb + ASMJS_MEMORY?=536870912 #512mb (required for asm.js) RELEASE_CFLAGS=-DOMIT_QCC -DGL_STATIC -DFTE_TARGET_WEB DEBUG_CFLAGS=-g --jcache -DOMIT_QCC -DGL_STATIC -DFTE_TARGET_WEB - RELEASE_LDFLAGS=-O1 $(WEB_PREJS) -s TOTAL_MEMORY=$(WEB_MEMORY) --js-library web/ftejslib.js --shell-file web/fteshell.html + RELEASE_LDFLAGS=-s ASM_JS=1 -O2 $(WEB_PREJS) -s TOTAL_MEMORY=$(ASMJS_MEMORY) --js-library web/ftejslib.js --shell-file web/fteshell.html +# RELEASE_LDFLAGS=-O1 $(WEB_PREJS) -s TOTAL_MEMORY=$(WEB_MEMORY) --js-library web/ftejslib.js --shell-file web/fteshell.html DEBUG_LDLAGS=-O0 $(WEB_PREJS) -s TOTAL_MEMORY=$(WEB_MEMORY) --js-library web/ftejslib.js CC=emcc - #-s ASM_JS=1 #BASELDFLAGS= #mostly we inherit the sdl defaults. because we can, however emscripten does not support sdl cd code. diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index e3218eee8..ba1d99bc1 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -4578,7 +4578,9 @@ void Host_Shutdown(void) } host_initialized = false; +#ifdef PLUGINS Plug_Shutdown(false); +#endif //disconnect server/client/etc CL_Disconnect_f(); @@ -4617,7 +4619,9 @@ void Host_Shutdown(void) FS_Shutdown(); +#ifdef PLUGINS Plug_Shutdown(true); +#endif Con_Shutdown(); Memory_DeInit(); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 756a9ac8e..badd68d22 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -1313,12 +1313,6 @@ cin_t *Media_WinAvi_TryLoad(char *name) } return NULL; } - -#else -cin_t *Media_WinAvi_TryLoad(char *name) -{ - return NULL; -} #endif //AVI Support (windows) @@ -2106,11 +2100,6 @@ cin_t *Media_Gecko_TryLoad(char *name) } return NULL; } -#else -cin_t *Media_Gecko_TryLoad(char *name) -{ - return NULL; -} #endif //Gecko Support @@ -2784,10 +2773,8 @@ static media_encoder_funcs_t capture_avi = }; #endif - static media_encoder_funcs_t *pluginencodersfunc[8]; static struct plugin_s *pluginencodersplugin[8]; - qboolean Media_RegisterEncoder(struct plugin_s *plug, media_encoder_funcs_t *funcs) { int i; @@ -2806,7 +2793,7 @@ void Media_StopRecordFilm_f(void); /*funcs==null closes ALL decoders from this plugin*/ qboolean Media_UnregisterEncoder(struct plugin_s *plug, media_encoder_funcs_t *funcs) { - qboolean success = true; + qboolean success = false; int i; for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++) @@ -2815,9 +2802,9 @@ qboolean Media_UnregisterEncoder(struct plugin_s *plug, media_encoder_funcs_t *f { if (currentcapture_funcs == funcs) Media_StopRecordFilm_f(); - - plugindecodersfunc[i] = NULL; - plugindecodersplugin[i] = NULL; + success = true; + pluginencodersfunc[i] = NULL; + pluginencodersplugin[i] = NULL; if (funcs) return success; } @@ -3131,7 +3118,6 @@ void Media_RecordFilm_f (void) } } } - if (capturesound.ival) { sndkhz = snd_speed?snd_speed:48000; diff --git a/engine/client/view.c b/engine/client/view.c index 5f430820a..38a2ab2e8 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1656,7 +1656,15 @@ void V_RenderView (void) SCR_VRectForPlayer(&r_refdef.grect, viewnum); V_RenderPlayerViews(r_refdef.playerview); - Plug_SBar(r_refdef.playerview); +#ifdef PLUGINS + Plug_SBar (r_refdef.playerview); +#else + if (Sbar_ShouldDraw()) + { + Sbar_Draw (r_refdef.playerview); + Sbar_DrawScoreboard (); + } +#endif SCR_TileClear (); } r_refdef.playerview = NULL; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index f63bbfa6a..5d89f9398 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -271,22 +271,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #ifdef FTE_TARGET_WEB -#undef VOICECHAT -#endif + //try to trim the fat + #undef VOICECHAT //too lazy to compile speex + #undef HLCLIENT //dlls... + #undef HLSERVER //dlls... + #undef CL_MASTER //bah. use the site to specify the servers. + #undef SV_MASTER //yeah, because that makes sense in a browser + #undef RAGDOLL //no ode + #undef TCPCONNECT //err... + #undef IRCCONNECT //not happening + #undef RUNTIMELIGHTING //too slow + #undef PLUGINS //pointless + #undef SUPPORT_ICE //utterly pointless + #undef VM_Q1 //no dlls + #undef MAP_PROC //meh + #undef HALFLIFEMODELS //blurgh + #undef WEBSERVER //hah, yeah, right + #undef SUPPORT_ICE //kinda requires udp, but whatever + //extra features stripped to try to reduce memory footprints + #undef Q2CLIENT + #undef Q2SERVER //requires a dll anyway. + #undef Q3CLIENT + #undef Q3SERVER //trying to trim memory use +#endif #ifdef ANDROID -#undef RTLIGHTS -#ifndef SPEEX_STATIC -#undef VOICECHAT + #undef RTLIGHTS + #ifndef SPEEX_STATIC + #undef VOICECHAT + #endif + #undef TEXTEDITOR #endif -#undef TEXTEDITOR -#endif -#ifdef NACL -#undef CL_MASTER //no sockets support -#undef SV_MASTER //noone uses this anyway -#undef WEBSERVER //no sockets support (certainly no servers) -#undef TCPCONNECT -#undef IRCCONNECT +#if defined(NACL) + #undef CL_MASTER //no sockets support + #undef SV_MASTER //noone uses this anyway + #undef WEBSERVER //no sockets support (certainly no servers) + #undef TCPCONNECT + #undef IRCCONNECT #endif #ifndef MULTITHREAD diff --git a/engine/common/common.c b/engine/common/common.c index 2047fccdc..5bd8d1b4b 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2332,6 +2332,24 @@ unsigned int unicode_charofsfrombyteofs(char *str, unsigned int byteofs) return chars; } +#ifdef FTE_TARGET_WEB +//targets that don't support towupper/towlower... +#define towupper Q_towupper +#define towlower Q_towlower +int towupper(int c) +{ + if (c < 128) + return toupper(c); + return c; +} +int towlower(int c) +{ + if (c < 128) + return tolower(c); + return c; +} +#endif + size_t unicode_strtoupper(char *in, char *out, size_t outsize) { //warning: towupper is locale-specific (eg: turkish has both I and dotted-I and thus i should transform to dotted-I rather than to I). diff --git a/engine/common/net.h b/engine/common/net.h index 817b0975f..f8b6d3bf1 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PORT_ANY -1 -#ifdef NACL +#if defined(NACL) || defined(FTE_TARGET_WEB) #define HAVE_WEBSOCKCL #endif diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 48b024a1d..9a688b27d 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -98,7 +98,11 @@ typedef struct ftenet_generic_connection_s { netadrtype_t addrtype[FTENET_ADDRTYPES]; qboolean islisten; +#ifdef HAVE_PACKET SOCKET thesocket; +#else + int thesocket; +#endif } ftenet_generic_connection_t; @@ -4061,7 +4065,92 @@ struct ftenet_generic_connection_s *FTENET_IRCConnect_EstablishConnection(qboole #endif -#ifdef HAVE_WEBSOCKCL +#ifdef FTE_TARGET_WEB +int emscriptenfte_ws_connect(char *url); +int emscriptenfte_ws_close(int sock); +int emscriptenfte_ws_cansend(int sock, int extra, int maxpending); +int emscriptenfte_ws_send(int sock, void *data, int len); +int emscriptenfte_ws_recv(int sock, void *data, int len); + +typedef struct +{ + ftenet_generic_connection_t generic; + int sock; + netadr_t remoteadr; + qboolean failed; +} ftenet_websocket_connection_t; + +static void FTENET_WebSocket_Close(ftenet_generic_connection_t *gcon) +{ + ftenet_websocket_connection_t *wsc = (void*)gcon; + emscriptenfte_ws_close(wsc->sock); +} +static qboolean FTENET_WebSocket_GetPacket(ftenet_generic_connection_t *gcon) +{ + ftenet_websocket_connection_t *wsc = (void*)gcon; + net_message.cursize = emscriptenfte_ws_recv(wsc->sock, net_message_buffer, sizeof(net_message_buffer)); + if (net_message.cursize > 0) + { + net_from = wsc->remoteadr; + return true; + } + net_message.cursize = 0;//just incase + return false; +} +static qboolean FTENET_WebSocket_SendPacket(ftenet_generic_connection_t *gcon, int length, void *data, netadr_t *to) +{ + ftenet_websocket_connection_t *wsc = (void*)gcon; + if (NET_CompareAdr(to, &wsc->remoteadr)) + { + emscriptenfte_ws_send(wsc->sock, data, length); + return true; + } + return false; +} + + +static ftenet_generic_connection_t *FTENET_WebSocket_EstablishConnection(qboolean isserver, const char *address) +{ + ftenet_websocket_connection_t *newcon; + + netadr_t adr; + int newsocket; + + if (isserver) + { + return NULL; + } + if (!NET_StringToAdr(address, 80, &adr)) + return NULL; //couldn't resolve the name + newsocket = emscriptenfte_ws_connect(address); + if (newsocket < 0) + return NULL; + newcon = Z_Malloc(sizeof(*newcon)); + if (newcon) + { + Q_strncpyz(newcon->generic.name, "WebSocket", sizeof(newcon->generic.name)); + newcon->generic.GetPacket = FTENET_WebSocket_GetPacket; + newcon->generic.SendPacket = FTENET_WebSocket_SendPacket; + newcon->generic.Close = FTENET_WebSocket_Close; + + newcon->generic.islisten = isserver; + newcon->generic.addrtype[0] = NA_WEBSOCKET; + newcon->generic.addrtype[1] = NA_INVALID; + + newcon->generic.thesocket = INVALID_SOCKET; + newcon->sock = newsocket; + + newcon->remoteadr = adr; + + return &newcon->generic; + } + return NULL; +} + +#endif + + +#ifdef NACL #include #include #include @@ -4080,8 +4169,8 @@ typedef struct PP_Resource sock; netadr_t remoteadr; - qboolean havepacket; struct PP_Var incomingpacket; + qboolean havepacket; qboolean failed; } ftenet_websocket_connection_t; @@ -4130,7 +4219,7 @@ static void websocketclosed(void *user_data, int32_t result) // Z_Free(wsc); } -static void FTENET_WebSocket_Close(ftenet_generic_connection_t *gcon) +static void FTENET_NaClWebSocket_Close(ftenet_generic_connection_t *gcon) { int res; /*meant to free the memory too, in this case we get the callback to do it*/ @@ -4140,7 +4229,7 @@ static void FTENET_WebSocket_Close(ftenet_generic_connection_t *gcon) ppb_websocket_interface->Close(wsc->sock, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), ccb); } -static qboolean FTENET_WebSocket_GetPacket(ftenet_generic_connection_t *gcon) +static qboolean FTENET_NaClWebSocket_GetPacket(ftenet_generic_connection_t *gcon) { ftenet_websocket_connection_t *wsc = (void*)gcon; int res; @@ -4198,7 +4287,7 @@ static qboolean FTENET_WebSocket_GetPacket(ftenet_generic_connection_t *gcon) } return false; } -static qboolean FTENET_WebSocket_SendPacket(ftenet_generic_connection_t *gcon, int length, void *data, netadr_t *to) +static qboolean FTENET_NaClWebSocket_SendPacket(ftenet_generic_connection_t *gcon, int length, void *data, netadr_t *to) { ftenet_websocket_connection_t *wsc = (void*)gcon; int res; @@ -4257,9 +4346,9 @@ static ftenet_generic_connection_t *FTENET_WebSocket_EstablishConnection(qboolea ppb_websocket_interface->Connect(newsocket, str, NULL, 0, ccb); ppb_var_interface->Release(str); Q_strncpyz(newcon->generic.name, "WebSocket", sizeof(newcon->generic.name)); - newcon->generic.GetPacket = FTENET_WebSocket_GetPacket; - newcon->generic.SendPacket = FTENET_WebSocket_SendPacket; - newcon->generic.Close = FTENET_WebSocket_Close; + newcon->generic.GetPacket = FTENET_NaClWebSocket_GetPacket; + newcon->generic.SendPacket = FTENET_NaClWebSocket_SendPacket; + newcon->generic.Close = FTENET_NaClWebSocket_Close; newcon->generic.islisten = isserver; newcon->generic.addrtype[0] = NA_WEBSOCKET; @@ -4884,7 +4973,6 @@ typedef struct unsigned short attrtype; unsigned short attrlen; } stunattr_t; -#define SUPPORT_ICE #ifdef SUPPORT_ICE /* Interactive Connectivity Establishment (rfc 5245) @@ -6129,8 +6217,10 @@ qboolean NET_WasSpecialPacket(netsrc_t netsrc) #endif } +#ifdef SUPPORT_ICE if (NET_WasStun(netsrc)) return true; +#endif #ifdef HAVE_NATPMP if (NET_Was_NATPMP(collection)) return true; diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 4619572a9..f91df94b1 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -1,16 +1,11 @@ -#ifndef NACL +#if !defined(NACL) && !defined(FTE_TARGET_WEB) #define HAVE_IPV4 //says we can send and receive AF_INET ipv4 udp packets. #define HAVE_TCP //says we can use tcp too (either ipv4 or ipv6) #define HAVE_PACKET //if we have the socket api at all... #endif -#ifdef FTE_TARGET_WEB -#undef HAVE_PACKET //no udp packet interface. -#undef HAVE_TCP //we should probably use websockets instead. -#endif - -#ifdef NACL +#if defined(NACL) || defined(FTE_TARGET_WEB) struct sockaddr { @@ -252,4 +247,4 @@ typedef struct void (QDECL *ICE_CloseModule)(void *module); //closes all unclosed connections, with warning. } icefuncs_t; extern icefuncs_t iceapi; -#endif \ No newline at end of file +#endif diff --git a/engine/web/ftejslib.js b/engine/web/ftejslib.js index 97e2c3491..9559d6a71 100644 --- a/engine/web/ftejslib.js +++ b/engine/web/ftejslib.js @@ -1,6 +1,82 @@ mergeInto(LibraryManager.library, { + $FTESockets__deps: [], + $FTESockets: { + socks: [] + }, + emscriptenfte_ws_connect__deps: ['$FTESockets'], + emscriptenfte_ws_connect : function(url) + { + var _url = Pointer_stringify(url); + var s = {ws:null, inq:[], err:0}; + for (var i = 0; ; i+=1) + { + if (!FTESockets.socks[i]) + { + s.ws = new WebSocket(_url, 'binary'); + if (!s.ws) + return -1; + FTESockets.socks[i] = s; + s.ws.onerror = function(event) {s.err = 1;}; + s.ws.onclose = function(event) {s.err = 1;}; + // s.ws.onopen = function(event) {}; + s.ws.onmessage = function(event) + { + assert(typeof event.data !== 'string' && event.data.byteLength); + s.inq.push(new Uint8Array(event.data)); + }; + return i; + } + } + return -1; + }, + emscriptenfte_ws_close : function(sockid) + { + var s = FTESockets.socks[sockid]; + if (!s) + return -1; + s.ws.close(); + s.ws = null; //make sure to avoid circular references + FTESockets.socks[sockid] = null; //socked is no longer accessible. + return 0; + }, + //separate call allows for more sane flood control when fragmentation is involved. + emscriptenfte_ws_cansend : function(sockid, extra, maxpending) + { + var s = FTESockets.socks[sockid]; + if (!s) + return 1; //go on punk, make my day. + return ((s.ws.bufferedAmount+extra) < maxpending); + }, + emscriptenfte_ws_send : function(sockid, data, len) + { + var s = FTESockets.socks[sockid]; + if (!s) + return -1; + s.s.send(HEAPU8.subarray(data, data+len).buffer); + return len; + }, + emscriptenfte_ws_recv : function(sockid, data, len) + { + var s = FTESockets.socks[sockid]; + if (!s) + return -1; + var inp = s.inq.shift(); + if (inp) + { + if (inp.length > len) + inp.length = len; + HEAPU8.set(inp, data); + return inp.length; + } + if (s.err) + return 0; + return -1; + }, + + + emscriptenfte_async_wget_data2 : function(url, ctx, onload, onerror, onprogress) { var _url = Pointer_stringify(url);