diff --git a/engine/Makefile b/engine/Makefile index e90643ee..bd7b4e50 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -754,6 +754,7 @@ ifeq ($(FTE_TARGET),nacl) BASELDFLAGS = -lm -lppapi_gles2 -lnosys -lppapi IMAGELDFLAGS = + GL_CFLAGS=$(GLCFLAGS) GL_CFLAGS+=$(SPEEXCFLAGS) GL_CFLAGS+=-I$(realpath $(NACL_SDK_ROOT)/include) BASELDFLAGS+=-L$(realpath $(NACL_SDK_ROOT)/lib/$(NACLLIBS)) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index efc840ae..4cf76b0a 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -3851,8 +3851,8 @@ void Host_RunFileNotify(struct dl_download *dl) #define HRF_ABORT (1<<3) #define HRF_OPENED (1<<4) -// (1<<5) -// (1<<6) +#define HRF_DOWNLOADED (1<<5) //file was actually downloaded, and not from the local system +#define HRF_WAITING (1<<6) //file looks important enough that we should wait for it to start to download or something to see what file type it is. // (1<<7) #define HRF_DEMO_MVD (1<<8) @@ -3894,6 +3894,12 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype) //at this point the file is still downloading, so don't copy it out just yet. hrf_t *f = dl->user_ctx; + if (f->flags & HRF_WAITING) + { + f->flags &= ~HRF_WAITING; + waitingformanifest--; + } + if (mimetype && !(f->flags & HRF_FILETYPES)) { if (!strcmp(mimetype, "application/x-qtv")) //what uses this? @@ -3988,6 +3994,14 @@ void Host_RunFilePrompted(void *ctx, int button) Host_DoRunFile(f); } +static qboolean isurl(char *url) +{ +#ifdef FTE_TARGET_WEB + return true; //assume EVERYTHING is a url, because the local filesystem is pointless. +#endif + return !strncmp(url, "http://", 7) || !strncmp(url, "https://", 8); +} + void Host_DoRunFile(hrf_t *f) { char qname[MAX_QPATH]; @@ -3995,6 +4009,12 @@ void Host_DoRunFile(hrf_t *f) char loadcommand[MAX_OSPATH]; qboolean isnew = false; qboolean haschanged = false; + + if (f->flags & HRF_WAITING) + { + f->flags &= ~HRF_WAITING; + waitingformanifest--; + } if (f->flags & HRF_ABORT) { @@ -4014,15 +4034,17 @@ void Host_DoRunFile(hrf_t *f) char *ext; #ifdef WEBCLIENT - if ((!strncmp(f->fname, "http://", 7) || !strncmp(f->fname, "https://", 8)) && !f->srcfile) + if (isurl(f->fname) && !f->srcfile) { if (!(f->flags & HRF_OPENED)) { struct dl_download *dl; - f->flags |= HRF_OPENED; + f->flags |= HRF_OPENED|HRF_DOWNLOADED|HRF_WAITING; dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded); dl->notifystarted = Host_BeginFileDownload; dl->user_ctx = f; + + waitingformanifest++; return; } } @@ -4105,10 +4127,20 @@ void Host_DoRunFile(hrf_t *f) else { man = FS_Manifest_Parse(NULL, fdata); - if (!man->updateurl) - man->updateurl = Z_StrDup(f->fname); - BZ_Free(fdata); - FS_ChangeGame(man, true); + if (man) + { + if (!man->updateurl) + man->updateurl = Z_StrDup(f->fname); +// if (f->flags & HRF_DOWNLOADED) + man->blockupdate = true; + BZ_Free(fdata); + FS_ChangeGame(man, true); + } + else + { + Con_Printf("Manifest file %s does not appear valid\n", f->fname); + BZ_Free(fdata); + } } f->flags |= HRF_ABORT; @@ -4132,7 +4164,7 @@ void Host_DoRunFile(hrf_t *f) if (!f->srcfile) { #ifdef WEBCLIENT - if (!strncmp(f->fname, "http://", 7)) + if (isurl(f->fname)) { struct dl_download *dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded); dl->notifystarted = Host_BeginFileDownload; @@ -4288,6 +4320,8 @@ Runs all active servers extern cvar_t cl_netfps; extern cvar_t cl_sparemsec; +qboolean startuppending; +void CL_StartCinematicOrMenu(void); int nopacketcount; void SNDDMA_SetUnderWater(qboolean underwater); double Host_Frame (double time) @@ -4336,6 +4370,8 @@ double Host_Frame (double time) Host_FinishLoading(); return 0; } + if (startuppending) + CL_StartCinematicOrMenu(); #ifdef PLUGINS Plug_Tick(); @@ -4629,9 +4665,19 @@ void CL_ReadCDKey(void) //============================================================================ - void CL_StartCinematicOrMenu(void) { + if (cls.download) + { + startuppending = true; + return; + } + if (startuppending) + { + startuppending = false; + Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly. + } + //start up the ui now we have a renderer #ifdef VM_UI UI_Start(); @@ -4685,9 +4731,11 @@ void CL_StartCinematicOrMenu(void) { if (qrenderer > QR_NONE && !m_state) { - if (cl_demoreel.ival) + if (!cls.state && !m_state && !*FS_GetGamedir(false)) + M_Menu_Mods_f(); + if (!cls.state && !m_state && cl_demoreel.ival) CL_NextDemo(); - if (!cls.state) + if (!cls.state && !m_state) M_ToggleMenu_f(); } //Con_ForceActiveNow(); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 7c93821b..c16521a7 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1458,7 +1458,7 @@ void CL_RequestNextDownload (void) current_loading_size = cl.contentstage; if (stage < 0) return; - SCR_SetLoadingFile("prespawn"); + SCR_SetLoadingFile("receiving game state"); cl.sendprespawn = false; #ifdef warningmsg #pragma warningmsg("timedemo timer should start here") diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 2685fabf..9ecc06a2 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -226,6 +226,7 @@ void SCR_ScreenShot_f (void); void SCR_RSShot_f (void); void SCR_CPrint_f(void); +cvar_t con_stayhidden = CVARFD("con_stayhidden", "0", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works"); cvar_t show_fps = SCVARF("show_fps", "0", CVAR_ARCHIVE); cvar_t show_fps_x = SCVAR("show_fps_x", "-1"); cvar_t show_fps_y = SCVAR("show_fps_y", "-1"); @@ -245,6 +246,7 @@ void CLSCR_Init(void) { Cmd_AddCommand("cprint", SCR_CPrint_f); + Cvar_Register(&con_stayhidden, cl_screengroup); Cvar_Register(&scr_loadingrefresh, cl_screengroup); Cvar_Register(&show_fps, cl_screengroup); Cvar_Register(&show_fps_x, cl_screengroup); @@ -1425,7 +1427,7 @@ void SCR_SetLoadingStage(int stage) SCR_SetLoadingFile("starting server..."); break; case LS_CLIENT: - SCR_SetLoadingFile("initial state"); + SCR_SetLoadingFile("receiving map info"); break; } loading_stage = stage; @@ -1706,7 +1708,7 @@ void SCR_SetUpToDrawConsole (void) //android has an onscreen imm that we don't want to obscure fullscreenpercent = scr_consize.value; #endif - if ((!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload)) + if (!con_stayhidden.ival && (!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload)) { //force console to fullscreen if we're loading stuff // Key_Dest_Add(kdm_console); @@ -1720,9 +1722,25 @@ void SCR_SetUpToDrawConsole (void) scr_con_current = scr_conlines = 0; else #endif + { if (cls.state < ca_demostart) - Key_Dest_Add(kdm_console); - if (Key_Dest_Has(kdm_console)) + { + if (con_stayhidden.ival) + { + extern qboolean startuppending; + if (SCR_GetLoadingStage() == LS_NONE) + { + if (CL_TryingToConnect()) //if we're trying to connect, make sure there's a loading/connecting screen showing instead of forcing the menu visible + SCR_SetLoadingStage(LS_CONNECTION); + else if (!m_state && !startuppending) //don't force anything until the startup stuff has been done + M_ToggleMenu_f(); + } + } + else + Key_Dest_Add(kdm_console); + } + } + if (!con_stayhidden.ival && Key_Dest_Has(kdm_console)) scr_con_current = scr_conlines = vid.height * fullscreenpercent; } else if (Key_Dest_Has(kdm_console) || scr_chatmode) diff --git a/engine/client/console.c b/engine/client/console.c index b31c5465..3be96d02 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -453,6 +453,7 @@ void Con_ToggleConsole_Force(void) } void Con_ToggleConsole_f (void) { + extern cvar_t con_stayhidden; #ifdef CSQC_DAT if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand("toggleconsole")) { @@ -461,6 +462,9 @@ void Con_ToggleConsole_f (void) } #endif + if (con_stayhidden.ival >= 2) + return; //its hiding! + Con_ToggleConsole_Force(); } diff --git a/engine/client/keys.c b/engine/client/keys.c index 18b3702c..84438fca 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -1968,7 +1968,8 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) if (key == K_ESCAPE) if (shift_down) { - if (down) + extern cvar_t con_stayhidden; + if (down && con_stayhidden.ival < 3) { if (!Key_Dest_Has(kdm_console)) //don't toggle it when the console is already down. this allows typing blind to not care if its already active. Con_ToggleConsole_Force(); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 3011a9b6..eaecd209 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -1912,15 +1912,21 @@ static qboolean MC_GuiKey(int key, menu_t *menu) qboolean MC_Main_Key (int key, menu_t *menu) //here purly to restart demos. { - if (key == K_ESCAPE) + if (key == K_ESCAPE || key == K_MOUSE2) { extern int m_save_demonum; - extern cvar_t cl_demoreel; + extern cvar_t cl_demoreel, con_stayhidden; + if (cls.demonum != -1 && !cls.demoplayback && cls.state == ca_disconnected && cl_demoreel.ival) + CL_NextDemo (); + + //don't spam menu open+close events if we're not going to be allowing the console to appear + if (con_stayhidden.ival && cls.state == ca_disconnected) + if (!CL_TryingToConnect()) + return true; + Key_Dest_Remove(kdm_menu); m_state = m_none; cls.demonum = m_save_demonum; - if (cls.demonum != -1 && !cls.demoplayback && cls.state == ca_disconnected && cl_demoreel.ival) - CL_NextDemo (); return true; } return false; @@ -2087,14 +2093,18 @@ void M_Menu_Main_f (void) MC_AddCenterPicture(mainm, 4, 24, "gfx/ttl_main.lmp"); mainm->selecteditem = (menuoption_t *) - MC_AddConsoleCommandQBigFont (mainm, 72, 32, "Single ", "menu_single\n"); - MC_AddConsoleCommandQBigFont (mainm, 72, 52, "Multiplayer", "menu_multi\n"); - MC_AddConsoleCommandQBigFont (mainm, 72, 72, "Options ", "menu_options\n"); + MC_AddConsoleCommandQBigFont (mainm, 72, 32, "Single ", "menu_single\n"); + MC_AddConsoleCommandQBigFont (mainm, 72, 52, "Multiplayer ", "menu_multi\n"); + MC_AddConsoleCommandQBigFont (mainm, 72, 72, "Options ", "menu_options\n"); if (m_helpismedia.value) - MC_AddConsoleCommandQBigFont(mainm, 72, 92, "Media ", "menu_media\n"); + MC_AddConsoleCommandQBigFont(mainm, 72, 92, "Media ", "menu_media\n"); else - MC_AddConsoleCommandQBigFont(mainm, 72, 92, "Help ", "help\n"); - MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Quit ", "menu_quit\n"); + MC_AddConsoleCommandQBigFont(mainm, 72, 92, "Help ", "help\n"); +#ifdef FTE_TARGET_WEB + MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Save Settings", "menu_quit\n"); +#else + MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Quit ", "menu_quit\n"); +#endif mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32); } @@ -2150,7 +2160,11 @@ void M_Menu_Main_f (void) b->common.width = p->width; b->common.height = 20; b=MC_AddConsoleCommand (mainm, 72, 312, 112, "", "menu_quit\n"); +#ifdef FTE_TARGET_WEB + b->common.tooltip = "Save settings to local storage."; +#else b->common.tooltip = "Exit to DOS."; +#endif b->common.width = p->width; b->common.height = 20; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index e84053e2..88b141c9 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1438,9 +1438,10 @@ void M_Menu_Singleplayer_Cheats_Quake (void) cursorpositionY = (y + 24); #ifndef CLIENTONLY - currentskill = skill.value; - if ( !currentskill ) + if ( !*skill.string ) currentskill = 4; // no skill selected + else + currentskill = skill.value; for (currentmap = sizeof(maplist_q1)/sizeof(maplist_q1[0]) - 1; currentmap > 0; currentmap--) if (!strcmp(host_mapname.string, maplist_q1[currentmap])) @@ -1551,10 +1552,10 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void) cursorpositionY = (y + 24); #ifndef CLIENTONLY - currentskill = skill.value; - - if ( !currentskill ) - currentskill = 4; // no skill selected + if ( !*skill.string ) + currentskill = 3; // no skill selected + else + currentskill = skill.value; for (currentmap = sizeof(maplist_q2)/sizeof(maplist_q2[0]) - 1; currentmap > 0; currentmap--) if (!strcmp(host_mapname.string, maplist_q2[currentmap])) @@ -1835,10 +1836,10 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void) cursorpositionY = (y + 24); #ifndef CLIENTONLY - currentskill = skill.value; - - if ( !currentskill ) + if ( !*skill.string ) currentskill = 4; // no skill selected + else + currentskill = skill.value; #endif if ( strcmp ( host_mapname.string, "" ) == 0) diff --git a/engine/client/menu.c b/engine/client/menu.c index 18b3309b..8661e9d1 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -573,7 +573,7 @@ void M_Menu_Help_f (void) { for (i = 0; i < sizeof(helpstyles)/sizeof(helpstyles[0]); i++) { - if (COM_FDepthFile(va(helpstyles[i].pattern, num_help_pages+helpstyles[i].base), true)) + if (COM_FCheckExists(va(helpstyles[i].pattern, num_help_pages+helpstyles[i].base))) break; } if (i == sizeof(helpstyles)/sizeof(helpstyles[0])) @@ -602,11 +602,13 @@ void M_Help_Key (int key) switch (key) { case K_ESCAPE: + case K_MOUSE2: M_Menu_Main_f (); break; case K_UPARROW: case K_RIGHTARROW: + case K_MOUSE1: S_LocalSound ("misc/menu2.wav"); if (++help_page >= num_help_pages) help_page = 0; @@ -893,7 +895,10 @@ qboolean MC_SaveQuit_Key (int key, menu_t *menu) { switch (key) { + case 'o': + case 'O': case K_ESCAPE: + case K_MOUSE2: M_RemoveMenu(menu); break; @@ -902,16 +907,20 @@ qboolean MC_SaveQuit_Key (int key, menu_t *menu) case 'n': case 'N': M_RemoveMenu(menu); +#ifndef FTE_TARGET_WEB CL_Disconnect (); Sys_Quit (); +#endif break; case 'Y': case 'y': M_RemoveMenu(menu); Cmd_ExecuteString("cfg_save", RESTRICT_LOCAL); +#ifndef FTE_TARGET_WEB CL_Disconnect (); Sys_Quit (); +#endif break; default: @@ -921,6 +930,7 @@ qboolean MC_SaveQuit_Key (int key, menu_t *menu) return true; } +//quit menu void M_Menu_Quit_f (void) { menu_t *quitmenu; @@ -946,17 +956,19 @@ void M_Menu_Quit_f (void) if (!strcmp(arg, "prompt")) mode = 1; else if (!strcmp(arg, "noprompt")) - mode = 1; - else mode = 0; + else + mode = 1; } } switch(mode) { case 0: +#ifndef FTE_TARGET_WEB CL_Disconnect (); Sys_Quit (); +#endif break; case 2: Key_Dest_Add(kdm_menu); @@ -971,9 +983,14 @@ void M_Menu_Quit_f (void) MC_AddWhiteText(quitmenu, 64, 0, 100, " save them now? ", false); quitmenu->selecteditem = (menuoption_t *) +#ifdef FTE_TARGET_WEB + MC_AddConsoleCommand (quitmenu, 64, 0, 116, "Yes", "cfg_save; menupop\n"); + MC_AddConsoleCommand (quitmenu, 224,0, 116, "Cancel", "menupop\n"); +#else MC_AddConsoleCommand (quitmenu, 64, 0, 116, "Yes", "menu_quit forcesave\n"); MC_AddConsoleCommand (quitmenu, 144,0, 116, "No", "menu_quit force\n"); MC_AddConsoleCommand (quitmenu, 224,0, 116, "Cancel", "menupop\n"); +#endif MC_AddBox (quitmenu, 56, 76, 25, 5); break; @@ -986,17 +1003,25 @@ void M_Menu_Quit_f (void) quitmenu->key = MC_Quit_Key; - i = rand()&7; +#ifdef FTE_TARGET_WEB +// MC_AddWhiteText(quitmenu, 64, 0, 84, " ", false); + MC_AddWhiteText(quitmenu, 64, 0, 92, " There is nothing to save ", false); +// MC_AddWhiteText(quitmenu, 64, 0, 100, " ", false); + + quitmenu->selecteditem = (menuoption_t *) + MC_AddConsoleCommand (quitmenu, 120, 0, 116, "Oh", "menupop\n"); +#else + i = rand()&7; MC_AddWhiteText(quitmenu, 64, 0, 84, quitMessage[i*4+0], false); MC_AddWhiteText(quitmenu, 64, 0, 92, quitMessage[i*4+1], false); MC_AddWhiteText(quitmenu, 64, 0, 100, quitMessage[i*4+2], false); MC_AddWhiteText(quitmenu, 64, 0, 108, quitMessage[i*4+3], false); quitmenu->selecteditem = (menuoption_t *) - MC_AddConsoleCommand (quitmenu, 120, 0, 116, "Yes", "menu_quit force\n"); - MC_AddConsoleCommand (quitmenu, 208, 0, 116, "No", "menupop\n"); - + MC_AddConsoleCommand (quitmenu, 100, 0, 116, "Quit", "menu_quit force\n"); + MC_AddConsoleCommand (quitmenu, 194, 0, 116, "Cancel", "menupop\n"); +#endif MC_AddBox (quitmenu, 56, 76, 24, 5); break; } diff --git a/engine/client/menu.h b/engine/client/menu.h index 26ac6013..6b503e9b 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -108,6 +108,7 @@ void M_Keydown (int key, int unicode); void M_Keyup (int key, int unicode); void M_Draw (int uimenu); void M_ToggleMenu_f (void); +void M_Menu_Mods_f (void); //used at startup if the current gamedirs look dodgy. mpic_t *M_CachePic (char *path); void M_DrawTextBox (int x, int y, int width, int lines); void M_Menu_Quit_f (void); diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 54a7c617..f99ab9da 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2319,14 +2319,6 @@ void MP_Keydown(int key, int unicode) return; } } - if (key == K_ESCAPE) - { - if (keydown[K_LSHIFT] || keydown[K_RSHIFT]) - { - Con_ToggleConsole_Force(); - return; - } - } menutime = Sys_DoubleTime(); if (menu_world.g.time) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 37fe3f64..98bebf1c 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -14,8 +14,6 @@ entity_t *currententity; //nnggh int r_framecount; struct texture_s *r_notexture_mip; -r_config_t r_config; - qboolean r_blockvidrestart; int r_regsequence; @@ -1036,8 +1034,6 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr) pmove.numphysent = 0; - memset(&r_config, 0, sizeof(r_config)); - if (qrenderer != QR_NONE) //graphics stuff only when not dedicated { qbyte *data; @@ -1169,17 +1165,16 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n")); TRACE(("dbg: R_ApplyRenderer: reloading server map\n")); sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_WARN); TRACE(("dbg: R_ApplyRenderer: loaded\n")); - if (sv.world.worldmodel->needload) - { - SV_Error("Bsp went missing on render restart\n"); - } + TRACE(("dbg: R_ApplyRenderer: doing that funky phs thang\n")); SV_CalcPHS (); TRACE(("dbg: R_ApplyRenderer: clearing world\n")); World_ClearWorld (&sv.world); - if (svs.gametype == GT_PROGS) + if (sv.world.worldmodel->needload) + SV_UnspawnServer(); + else if (svs.gametype == GT_PROGS) { for (i = 0; i < MAX_MODELS; i++) { diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 8130e4fb..5a3015e3 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -297,10 +297,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef Q3SERVER //trying to trim memory use #undef Q2BSPS //emscripten can't cope with bss, leading to increased download time. too lazy to fix. #undef Q3BSPS //emscripten can't cope with bss, leading to increased download time. too lazy to fix. - #undef PSET_SCRIPT //bss+size +// #undef PSET_SCRIPT //bss+size #define GLSLONLY //pointless having the junk + #define GLESONLY //should reduce the conditions a little #define R_MAX_RECURSE 2 //less bss - #undef RTLIGHTS +// #undef RTLIGHTS #endif #ifdef WINRT #undef TCPCONNECT //err... @@ -319,6 +320,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef VOICECHAT #endif #undef TEXTEDITOR + #define GLESONLY //should reduce the conditions a little #endif #if defined(NACL) #undef SUPPORT_ICE @@ -327,6 +329,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef WEBSERVER //no sockets support (certainly no servers) #undef TCPCONNECT #undef IRCCONNECT + #define GLSLONLY //pointless having the junk + #define GLESONLY //should reduce the conditions a little #endif #ifndef MULTITHREAD diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 12558c30..ab98597c 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2855,7 +2855,7 @@ void Cmd_WriteConfig_f(void) snprintf(fname, sizeof(fname), "fte.cfg"); FS_NativePath(fname, FS_GAMEONLY, sysname, sizeof(sysname)); FS_CreatePath(fname, FS_GAMEONLY); - f = FS_OpenVFS(fname, "wb", FS_GAMEONLY); + f = FS_OpenVFS(fname, "wbp", FS_GAMEONLY); } else { @@ -2869,7 +2869,7 @@ void Cmd_WriteConfig_f(void) FS_NativePath(fname, FS_BASEGAMEONLY, sysname, sizeof(sysname)); FS_CreatePath(fname, FS_BASEGAMEONLY); - f = FS_OpenVFS(fname, "wb", FS_BASEGAMEONLY); + f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY); } if (!f) { diff --git a/engine/common/fs.c b/engine/common/fs.c index 755e72c9..0529eb51 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -12,7 +12,7 @@ #include "winquake.h" #endif -void fs_game_callback(cvar_t *var, char *oldvalue); +static void fs_game_callback(cvar_t *var, char *oldvalue); hashtable_t filesystemhash; qboolean com_fschanged = true; qboolean fs_readonly; @@ -28,7 +28,7 @@ static int fs_referencetype; int fs_finds; void COM_CheckRegistered (void); -void fs_game_callback(cvar_t *var, char *oldvalue) +static void fs_game_callback(cvar_t *var, char *oldvalue) { static qboolean runaway = false; char buf[MAX_OSPATH]; @@ -1363,13 +1363,15 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r if (!filename) return NULL; - +#ifdef _DEBUG if (strcmp(mode, "rb")) if (strcmp(mode, "r+b")) if (strcmp(mode, "wb")) if (strcmp(mode, "w+b")) if (strcmp(mode, "ab")) - return NULL; //urm, unable to write/append + if (strcmp(mode, "wbp")) + return NULL; //urm, unable to write/append +#endif //if there can only be one file (eg: write access) find out where it is. switch (relativeto) @@ -1538,7 +1540,7 @@ qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relative s = FS_OpenVFS(source, "rb", relativesource); if (s) { - d = FS_OpenVFS(dest, "wb", relativedest); + d = FS_OpenVFS(dest, "wbp", relativedest); if (d) { result = true; @@ -2027,11 +2029,16 @@ void COM_FlushFSCache(void) } } - if (com_fs_cache.ival) +#ifdef FTE_TARGET_WEB + //web target doesn't support filesystem enumeration, so make sure the cache is kept invalid and disabled. + com_fschanged = true; +#else + if (com_fs_cache.ival && com_fschanged) { //rebuild it if needed FS_RebuildFSHash(); } +#endif } /*since should start as 0, otherwise this can be used to poll*/ @@ -2210,128 +2217,6 @@ void COM_Gamedir (const char *dir) Z_Free(dup); } FS_ChangeGame(man, cfg_reload_on_gamedir.ival); - -#if 0 - char thispath[64]; - searchpath_t *next; - qboolean isbase; - - //don't allow leading dots, hidden files are evil. - //don't allow complex paths. those are evil too. - if (!*dir || *dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") - || strstr(dir, "\\") || strstr(dir, ":") ) - { - Con_TPrintf (TL_GAMEDIRAINTPATH); - return; - } - - isbase = false; - for (next = com_searchpaths; next; next = next->next) - { - if (next == com_base_searchpaths) - isbase = true; - - if (next->funcs == &osfilefuncs) - { - FS_CleanDir(next->purepath, thispath, sizeof(thispath)); - if (!strcmp(dir, thispath)) - { - if (isbase && com_searchpaths == com_base_searchpaths) - { - Q_strncpyz (gamedirfile, dir, sizeof(gamedirfile)); - return; - } - if (!isbase) - return; - break; - } - } - } - - FS_ForceToPure(NULL, NULL, 0); - -#ifndef SERVERONLY -// Host_WriteConfiguration(); //before we change anything. -#endif - - Q_strncpyz (gamedirfile, dir, sizeof(gamedirfile)); - -#ifndef CLIENTONLY - sv.gamedirchanged = true; -#endif -#ifndef SERVERONLY - cl.gamedirchanged = true; -#endif - - FS_FlushFSHashReally(); - - // - // free up any current game dir info - // - while (com_searchpaths != com_base_searchpaths) - { - com_searchpaths->handle->ClosePath(com_searchpaths->handle); - next = com_searchpaths->next; - Z_Free (com_searchpaths); - com_searchpaths = next; - } - - com_fschanged = true; - - // - // flush all data, so it will be forced to reload - // - Cache_Flush (); - - if (strchr(dir, ';')) - { - //separate case because parsestringset splits by whitespace too - while ((dir = COM_ParseStringSet(dir))) - { - if (!strcmp(dir, ";")) - continue; - if (!*dir) - continue; - - FS_AddGameDirectory(dir, va("%s%s", com_gamepath, com_token), ~0, SPF_EXPLICIT); - if (com_homepathenabled) - FS_AddGameDirectory(dir, va("%s%s", com_homepath, com_token), ~0, SPF_EXPLICIT); - } - } - else - { - FS_AddGameDirectory(dir, va("%s%s", com_gamepath, dir), ~0, SPF_EXPLICIT); - if (com_homepathenabled) - FS_AddGameDirectory(dir, va("%s%s", com_homepath, dir), ~0, SPF_EXPLICIT); - } - - -#ifndef SERVERONLY - if (!isDedicated) - { -// if (qrenderer != QR_NONE) //only do this if we have already started the renderer -// Cbuf_InsertText("vid_restart\n", RESTRICT_LOCAL); - - - if (COM_FDepthFile("config.cfg", true) <= (com_homepathenabled?1:0)) - { - Cbuf_InsertText("cl_warncmd 0\n" - "exec config.cfg\n" - "exec fte.cfg\n" - "cl_warncmd 1\n", RESTRICT_LOCAL, false); - } - } - - Shader_Init(); //FIXME! - - COM_Effectinfo_Clear(); - - Validation_FlushFileList(); //prevent previous hacks from making a difference. - - //FIXME: load new palette, if different cause a vid_restart. - -#endif -#endif } #define QCFG "set allow_download_refpackages 0\n" @@ -3722,7 +3607,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs) "FTEMANIFEST 1\n" "game \"\"\n" "name \"" FULLENGINENAME "\"\n" - "defaultexec \\\"vid_fullscreen 0; gl_font cour;vid_width 640; vid_height 480; menu_mods\"\n" + "defaultexec \\\"vid_fullscreen 0; gl_font cour;vid_width 640; vid_height 480\"\n" ); } } diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index fd6a921e..d56fecf4 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -772,7 +772,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e tinheight = inheight; //don't make scaled width any larger than it needs to be - if (r_config.texture_non_power_of_two) + if (gl_config.texture_non_power_of_two) { scaled_width = tinwidth; scaled_height = tinheight; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index e452e8b7..a31e1b27 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -230,6 +230,7 @@ static void BE_PolyOffset(qboolean pushdepth) } } +#ifndef GLSLONLY void GL_TexEnv(GLenum mode) { #ifndef FORCESTATE @@ -302,6 +303,7 @@ static void BE_SetPassBlendMode(int tmu, int pbm) } } } +#endif /*OpenGL requires glDepthMask(GL_TRUE) or glClear(GL_DEPTH_BUFFER_BIT) will fail*/ void GL_ForceDepthWritable(void) @@ -927,7 +929,7 @@ static void RevertToKnownState(void) } GL_SelectTexture(0); - +#ifndef GLSLONLY if (!gl_config_nofixedfunc) { BE_SetPassBlendMode(0, PBM_REPLACE); @@ -935,6 +937,7 @@ static void RevertToKnownState(void) GL_DeSelectProgram(); } +#endif shaderstate.shaderbits &= ~(SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY|SBITS_MASK_BITS|SBITS_AFFINE); shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE; @@ -989,7 +992,6 @@ int GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, fl if (qglShadeModel) qglShadeModel(GL_FLAT); - BE_SetPassBlendMode(0, PBM_REPLACE); GL_ForceDepthWritable(); // qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -1007,7 +1009,7 @@ static void T_Gen_CurrentRender(int tmu) if (r_refdef.recurse) return; - if (r_config.texture_non_power_of_two) + if (gl_config.texture_non_power_of_two_limited) { vwidth = pwidth; vheight = pheight; @@ -3040,7 +3042,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, break; case SP_RENDERTEXTURESCALE: - if (r_config.texture_non_power_of_two) + if (gl_config.texture_non_power_of_two_limited) { param4[0] = 1; param4[1] = 1; @@ -3317,7 +3319,20 @@ void GLBE_SelectMode(backendmode_t mode) default: break; case BEM_DEPTHONLY: - GL_DeSelectProgram(); +#ifndef GLSLONLY + if (!gl_config_nofixedfunc) + { + BE_SetPassBlendMode(0, PBM_REPLACE); + GL_DeSelectProgram(); + } + else +#endif + if (!shaderstate.allblackshader) + { + const char *defs[] = {NULL}; + shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL); + shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader, "m_modelviewprojection"); + } /*BEM_DEPTHONLY does support mesh writing, but its not the only way its used... FIXME!*/ while(shaderstate.lastpasstmus>0) { @@ -3327,7 +3342,6 @@ void GLBE_SelectMode(backendmode_t mode) //we don't write or blend anything (maybe alpha test... but mneh) BE_SendPassBlendDepthMask(SBITS_MISC_DEPTHWRITE | SBITS_MASK_BITS); - BE_SetPassBlendMode(0, PBM_REPLACE); GL_CullFace(SHADER_CULL_FRONT); break; @@ -3348,6 +3362,7 @@ void GLBE_SelectMode(backendmode_t mode) { GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex); } +#ifndef GLSLONLY if (!gl_config_nofixedfunc) { GL_DeSelectProgram(); @@ -3355,6 +3370,7 @@ void GLBE_SelectMode(backendmode_t mode) //replace mode please BE_SetPassBlendMode(0, PBM_REPLACE); } +#endif //we don't write or blend anything (maybe alpha test... but mneh) BE_SendPassBlendDepthMask(SBITS_MISC_DEPTHCLOSERONLY | SBITS_MASK_BITS); @@ -3400,7 +3416,10 @@ void GLBE_SelectMode(backendmode_t mode) Vector4Set(shaderstate.pendingcolourflat, 1, 1, 1, 1); shaderstate.pendingcolourvbo = 0; shaderstate.pendingcolourpointer = NULL; - BE_SetPassBlendMode(0, PBM_MODULATE); +#ifndef GLSLONLY + if (!gl_config_nofixedfunc) + BE_SetPassBlendMode(0, PBM_MODULATE); +#endif BE_SendPassBlendDepthMask(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | SBITS_MISC_DEPTHEQUALONLY); break; } @@ -3451,10 +3470,12 @@ static qboolean GLBE_RegisterLightShader(int mode) { if (!shaderstate.inited_shader_light[mode]) { - char *name = va("rtlight%s%s%s", + char *name = va("rtlight%s%s%s%s", (mode & LSHADER_SMAP)?"#PCF":"", (mode & LSHADER_SPOT)?"#SPOT":"", - (mode & LSHADER_CUBE)?"#CUBE":""); + (mode & LSHADER_CUBE)?"#CUBE":"", + (gl_config.arb_shadow && (mode & (LSHADER_SMAP|LSHADER_SPOT|LSHADER_CUBE)))?"#USE_ARB_SHADOW":"" + ); shaderstate.inited_shader_light[mode] = true; shaderstate.shader_light[mode] = R_RegisterCustom(name, SUF_NONE, Shader_LightPass, NULL); @@ -3847,7 +3868,18 @@ static void DrawMeshes(void) case BEM_WIREFRAME: //FIXME: do this with a shader instead? its not urgent as we can draw the shader normally anyway, just faster. //FIXME: we need to use a shader for vertex blending. not really an issue with mdl, but more significant with iqms (base pose!). - GL_DeSelectProgram(); +#ifndef GLSLONLY + if (!gl_config_nofixedfunc) + { + BE_SetPassBlendMode(0, PBM_REPLACE); + GL_DeSelectProgram(); + } + else +#endif + { + break; + } + shaderstate.pendingcolourvbo = 0; shaderstate.pendingcolourpointer = NULL; Vector4Set(shaderstate.pendingcolourflat, 1, 1, 1, 1); @@ -3855,14 +3887,13 @@ static void DrawMeshes(void) { GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex); } - BE_SetPassBlendMode(0, PBM_REPLACE); BE_SendPassBlendDepthMask(shaderstate.curshader->passes[0].shaderbits | SBITS_MISC_NODEPTHTEST); BE_EnableShaderAttributes((1u<flags & SHADER_HASLIGHTMAP) && !TEXVALID(shaderstate.curtexnums->fullbright) && !gl_config_nofixedfunc) + if ((shaderstate.curshader->flags & SHADER_HASLIGHTMAP) && !TEXVALID(shaderstate.curtexnums->fullbright)) { if (gl_config.arb_shader_objects) { @@ -3875,7 +3906,7 @@ static void DrawMeshes(void) GL_SelectProgram(shaderstate.allblackshader); BE_SendPassBlendDepthMask(shaderstate.curshader->passes[0].shaderbits); - BE_EnableShaderAttributes(1u<colour is created if usedepth is set and it doesn't previously exist int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, int mrt, texid_t destdepth, int width, int height) { + GLenum allcolourattachments[] ={GL_COLOR_ATTACHMENT0_EXT,GL_COLOR_ATTACHMENT1_EXT,GL_COLOR_ATTACHMENT2_EXT,GL_COLOR_ATTACHMENT3_EXT, + GL_COLOR_ATTACHMENT4_EXT,GL_COLOR_ATTACHMENT5_EXT,GL_COLOR_ATTACHMENT6_EXT,GL_COLOR_ATTACHMENT7_EXT}; int i; int old; @@ -4635,12 +4671,10 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i { qglGenFramebuffersEXT(1, &state->fbo); old = GLBE_FBO_Push(state); - enables |= FBO_RESET; } else old = GLBE_FBO_Push(state); - if (state->rb_size[0] != width || state->rb_size[1] != height || (enables & FBO_RESET)) { if (state->rb_depth && !(enables & FBO_RB_DEPTH)) @@ -4657,19 +4691,25 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i state->rb_size[1] = height; enables |= FBO_RESET; - if (mrt) - { - qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - qglReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + { //be careful here, gles2 doesn't support glDrawBuffer. hopefully it'll make things up, but this is worrying. + if (qglDrawBuffers) + qglDrawBuffers(mrt, allcolourattachments); + else if (qglDrawBuffer) + qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + if (qglReadBuffer) + qglReadBuffer(GL_COLOR_ATTACHMENT0_EXT); } else { - qglDrawBuffer(GL_NONE); - qglReadBuffer(GL_NONE); + if (qglDrawBuffers) + qglDrawBuffers(0, NULL); + else if (qglDrawBuffer) + qglDrawBuffer(GL_NONE); + if (qglReadBuffer) + qglReadBuffer(GL_NONE); } } - if (enables & FBO_TEX_DEPTH) { qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, destdepth.num, 0); @@ -4681,9 +4721,8 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i { //create an unnamed depth buffer qglGenRenderbuffersEXT(1, &state->rb_depth); - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, state->rb_depth); - if (!gl_config.ext_packed_depth_stencil) - qglGenRenderbuffersEXT(1, &state->rb_stencil); +// if (!gl_config.ext_packed_depth_stencil) +// qglGenRenderbuffersEXT(1, &state->rb_stencil); enables |= FBO_RESET; //make sure it gets instanciated } @@ -4694,10 +4733,9 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, state->rb_size[0], state->rb_size[1]); else { - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, state->rb_size[0], state->rb_size[1]); - - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, state->rb_stencil); - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, state->rb_size[0], state->rb_size[1]); + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16_ARB, state->rb_size[0], state->rb_size[1]); +// qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, state->rb_stencil); +// qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, state->rb_size[0], state->rb_size[1]); } qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, state->rb_depth); if (gl_config.ext_packed_depth_stencil) @@ -4709,6 +4747,38 @@ int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, i for (i = 0; i < mrt; i++) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_TEXTURE_2D, destcol[i].num, 0); + + i = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (GL_FRAMEBUFFER_COMPLETE_EXT != i) + { + switch(i) + { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_INCOMPLETE_FORMATS\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + Con_Printf("glCheckFramebufferStatus reported GL_FRAMEBUFFER_UNSUPPORTED\n"); + break; + default: + Con_Printf("glCheckFramebufferStatus returned %#x\n", i); + break; + } + } return old; } /* diff --git a/engine/gl/gl_bloom.c b/engine/gl/gl_bloom.c index ed0e640c..51c0e699 100644 --- a/engine/gl/gl_bloom.c +++ b/engine/gl/gl_bloom.c @@ -114,7 +114,7 @@ static void R_SetupBloomTextures(int w, int h) if (!TEXVALID(pingtex[i][j])) { sprintf(name, "***bloom*%c*%i***", 'a'+i, j); - TEXASSIGN(pingtex[i][j], GL_AllocNewTexture(name, texwidth[j], texheight[j], IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR)); + TEXASSIGN(pingtex[i][j], GL_AllocNewTexture(name, texwidth[j], texheight[j], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR)); } GL_MTBind(0, GL_TEXTURE_2D, pingtex[i][j]); qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texwidth[j], texheight[j], 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); @@ -180,7 +180,7 @@ qboolean R_CanBloom(void) return false; if (!gl_config.arb_shader_objects) return false; - if (!r_config.texture_non_power_of_two) + if (!gl_config.texture_non_power_of_two_limited) return false; return true; diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index a42975c8..25d2ea76 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -1075,10 +1075,14 @@ static qboolean GL_UploadCompressed (qbyte *file, int *out_width, int *out_heigh void GL_RoundDimensions(int *scaled_width, int *scaled_height, unsigned int flags) { - if (r_config.texture_non_power_of_two) //NPOT is a simple extension that relaxes errors. + if (gl_config.texture_non_power_of_two) //NPOT is a simple extension that relaxes errors. { TRACE(("dbg: GL_RoundDimensions: GL_ARB_texture_non_power_of_two\n")); } + else if (gl_config.texture_non_power_of_two_limited && (flags&IF_NOMIPMAP) && (flags&IF_CLAMP)) + { + //clamped mipless textures will work as-is in gles2/webgl + } else { int width = *scaled_width; @@ -1089,6 +1093,7 @@ void GL_RoundDimensions(int *scaled_width, int *scaled_height, unsigned int flag ; /*round npot textures down if we're running on an embedded system*/ + /* if (gl_config.gles) { if (*scaled_width != width) @@ -1096,6 +1101,7 @@ void GL_RoundDimensions(int *scaled_width, int *scaled_height, unsigned int flag if (*scaled_height != height) *scaled_height >>= 1; } + */ } if (flags & IF_NOMIPMAP) @@ -1251,10 +1257,10 @@ static void GL_Upload32_Int (const char *name, unsigned *data, int width, int he { glcolormode = GL_RGBA; /*our input is RGBA or RGBX, with the internal format restriction, we must therefore always have an alpha value*/ - if (gl_config.webgl_ie) - { + if (1)//gl_config.webgl_ie) + { //fixme: I think my npot mips don't work properly. type = GL_UNSIGNED_BYTE; - glcolormode = GL_RGBA; //I hope its 1. note that samples matching colormode means we can't use packed formats, and I'm too lazy to strip it + glcolormode = GL_RGBA; //I hope alpha is 1. note that samples matching colormode means we can't use packed formats, and I'm too lazy to strip it } else if (flags & IF_NOALPHA) { diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index e5cee16b..0c1c96dd 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -544,7 +544,7 @@ void R_RenderScene (void) #ifdef GL_STEREO GLint glb; qglGetIntegerv(GL_STEREO, &glb); - if (!glb) + if (!glb || !qglDrawBuffer) #endif stereomode = 0; //we are not a stereo context, so no stereoscopic rendering (this encourages it to otherwise be left enabled, which means the user is more likely to spot that they asked it to give a slower context. } @@ -1283,7 +1283,7 @@ static void R_RenderMotionBlur(void) shader_t *shader; //figure out the size of our texture. - if (r_config.texture_non_power_of_two) + if (gl_config.texture_non_power_of_two_limited) { //we can use any size, supposedly vwidth = vid.pixelwidth; vheight = vid.pixelheight; @@ -1402,7 +1402,7 @@ qboolean R_RenderScene_Cubemap(void) // prect.y = (vrect.y * vid.pixelheight)/vid.height; // prect.height = (vrect.height * vid.pixelheight)/vid.height; - if (r_config.texture_non_power_of_two) + if (r_config.texture_non_power_of_two_limited) { if (prect.width < prect.height) cmapsize = prect.width; @@ -1596,7 +1596,7 @@ void GLR_RenderView (void) } //disable stuff if its simply not supported. - if (dofbo || !gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !r_config.texture_non_power_of_two) + if (dofbo || !gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !gl_config.texture_non_power_of_two_limited) r_refdef.flags &= ~(RDF_ALLPOSTPROC); //block all of this stuff diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 4aa9066e..f9946e86 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -314,20 +314,21 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) else { float lhs; - cv = Cvar_Get(token, "", 0, "Shader Conditions"); - if (cv) - { - cv->flags |= CVAR_SHADERSYSTEM; - lhs = cv->value; - } + if (*token >= '0' && *token <= '9') + lhs = strtod(token, NULL); else { - if (*token < '0' || *token > '9') + cv = Cvar_Get(token, "", 0, "Shader Conditions"); + if (cv) + { + cv->flags |= CVAR_SHADERSYSTEM; + lhs = cv->value; + } + else { Con_Printf("Shader_EvaluateCondition: '%s' is not a cvar\n", token); return conditiontrue; } - lhs = strtod(token, NULL); } if (*token) token = COM_ParseExt(ptr, false, false); @@ -356,7 +357,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) else { if (cv) - conditiontrue = conditiontrue == !!cv->value; + conditiontrue = conditiontrue == !!lhs; } } if (*token) diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index dbd9a159..94e30fba 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -52,23 +52,23 @@ cvar_t r_shadow_shadowmapping_nearclip = CVAR("r_shadow_shadowmapping_nearclip", cvar_t r_shadow_shadowmapping_bias = CVAR("r_shadow_shadowmapping_bias", "0.03"); cvar_t r_shadow_scissor = CVAR("r_shadow_scissor", "1"); -cvar_t r_shadow_realtime_world = SCVARF ("r_shadow_realtime_world", "0", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_world_shadows = SCVARF ("r_shadow_realtime_world_shadows", "1", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_world_lightmaps = SCVARF ("r_shadow_realtime_world_lightmaps", "0", 0); +cvar_t r_shadow_realtime_world = CVARF ("r_shadow_realtime_world", "0", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_world_shadows = CVARF ("r_shadow_realtime_world_shadows", "1", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_world_lightmaps = CVARF ("r_shadow_realtime_world_lightmaps", "0", 0); #ifdef FTE_TARGET_WEB -cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "0", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_dlight = CVARF ("r_shadow_realtime_dlight", "0", CVAR_ARCHIVE); #else -cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "1", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_dlight = CVARF ("r_shadow_realtime_dlight", "1", CVAR_ARCHIVE); #endif -cvar_t r_shadow_realtime_dlight_shadows = SCVARF ("r_shadow_realtime_dlight_shadows", "1", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_dlight_ambient = SCVAR ("r_shadow_realtime_dlight_ambient", "0"); -cvar_t r_shadow_realtime_dlight_diffuse = SCVAR ("r_shadow_realtime_dlight_diffuse", "1"); -cvar_t r_shadow_realtime_dlight_specular = SCVAR ("r_shadow_realtime_dlight_specular", "4"); //excessive, but noticable. its called stylized, okay? shiesh, some people -cvar_t r_editlights_import_radius = SCVAR ("r_editlights_import_radius", "1"); -cvar_t r_editlights_import_ambient = SCVAR ("r_editlights_import_ambient", "0"); -cvar_t r_editlights_import_diffuse = SCVAR ("r_editlights_import_diffuse", "1"); -cvar_t r_editlights_import_specular = SCVAR ("r_editlights_import_specular", "1"); //excessive, but noticable. its called stylized, okay? shiesh, some people -cvar_t r_shadow_shadowmapping = SCVARF ("r_shadow_shadowmapping", "1", 0); +cvar_t r_shadow_realtime_dlight_shadows = CVARF ("r_shadow_realtime_dlight_shadows", "1", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_dlight_ambient = CVAR ("r_shadow_realtime_dlight_ambient", "0"); +cvar_t r_shadow_realtime_dlight_diffuse = CVAR ("r_shadow_realtime_dlight_diffuse", "1"); +cvar_t r_shadow_realtime_dlight_specular = CVAR ("r_shadow_realtime_dlight_specular", "4"); //excessive, but noticable. its called stylized, okay? shiesh, some people +cvar_t r_editlights_import_radius = CVAR ("r_editlights_import_radius", "1"); +cvar_t r_editlights_import_ambient = CVAR ("r_editlights_import_ambient", "0"); +cvar_t r_editlights_import_diffuse = CVAR ("r_editlights_import_diffuse", "1"); +cvar_t r_editlights_import_specular = CVAR ("r_editlights_import_specular", "1"); //excessive, but noticable. its called stylized, okay? shiesh, some people +cvar_t r_shadow_shadowmapping = CVARD ("r_shadow_shadowmapping", "1", "Enables soft shadows"); cvar_t r_shadow_shadowmapping_precision = CVARD ("r_shadow_shadowmapping_precision", "1", "Scales the shadowmap detail level up or down."); extern cvar_t r_shadow_shadowmapping_nearclip; extern cvar_t r_shadow_shadowmapping_bias; @@ -88,7 +88,7 @@ void Sh_Reset(void) #ifdef GLQUAKE if (shadow_fbo_id) { - qglDeleteRenderbuffersEXT(1, &shadow_fbo_id); + qglDeleteFramebuffersEXT(1, &shadow_fbo_id); shadow_fbo_id = 0; shadow_fbo_depth_num = 0; } @@ -109,7 +109,7 @@ void Sh_Reset(void) } if (crepuscular_fbo_id) { - qglDeleteRenderbuffersEXT(1, &crepuscular_fbo_id); + qglDeleteFramebuffersEXT(1, &crepuscular_fbo_id); crepuscular_fbo_id = 0; } #endif @@ -772,6 +772,7 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node) SHM_RecursiveWorldNodeQ1_r (dl, node->children[!side]); } +#ifdef Q2BSPS static void SHM_RecursiveWorldNodeQ2_r (dlight_t *dl, mnode_t *node) { int c, side; @@ -966,7 +967,6 @@ static void SHM_RecursiveWorldNodeQ2_r (dlight_t *dl, mnode_t *node) SHM_RecursiveWorldNodeQ2_r (dl, node->children[!side]); } -#ifdef Q2BSPS static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis, unsigned char *vvis) { mnode_t *node; @@ -2025,8 +2025,10 @@ void GL_BeginRenderBuffer_DepthOnly(texid_t depthtexture) // qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2); // qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, drb); - qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - qglReadBuffer(GL_NONE); + if (qglDrawBuffer) + qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + if (qglReadBuffer) + qglReadBuffer(GL_NONE); } else qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id); @@ -2044,8 +2046,12 @@ void GL_BeginRenderBuffer_DepthOnly(texid_t depthtexture) { qglGenFramebuffersEXT(1, &shadow_fbo_id); qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id); - qglDrawBuffer(GL_NONE); - qglReadBuffer(GL_NONE); + if (qglDrawBuffers) + qglDrawBuffers(0, NULL); + else if (qglDrawBuffer) + qglDrawBuffer(GL_NONE); + if (qglReadBuffer) + qglReadBuffer(GL_NONE); } else qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id); @@ -2370,24 +2376,28 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize) #ifdef DBG_COLOURNOTDEPTH qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); #else - qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + if (gl_config.gles) + qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + else + qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); #endif } - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - #if 1//def DBG_COLOURNOTDEPTH + #if 0//def DBG_COLOURNOTDEPTH qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); #else qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #endif - //in case we're using shadow samplers - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); + if (gl_config.arb_shadow) + { + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); + } } /*set framebuffer*/ @@ -3230,6 +3240,7 @@ void Sh_PurgeShadowMeshes(void) } free(edge); edge = NULL; + maxedge = 0; } void Sh_PreGenerateLights(void) @@ -3309,8 +3320,14 @@ void Sh_CheckSettings(void) { #ifdef GLQUAKE case QR_OPENGL: - canshadowless = true; //falls back to crappy texture env - if (gl_config.arb_shader_objects && gl_config.ext_framebuffer_objects && gl_config.arb_shadow) + canshadowless = gl_config.arb_shader_objects || !gl_config_nofixedfunc; //falls back to crappy texture env + if (!gl_config.arb_shader_objects) + Con_Printf("No arb_shader_objects\n"); + if (!gl_config.ext_framebuffer_objects) + Con_Printf("No ext_framebuffer_objects\n"); + if (!gl_config.arb_depth_texture) + Con_Printf("No arb_depth_texture\n"); + if (gl_config.arb_shader_objects && gl_config.ext_framebuffer_objects && gl_config.arb_depth_texture)// && gl_config.arb_shadow) cansmap = true; if (gl_stencilbits) canstencil = true; @@ -3337,14 +3354,12 @@ void Sh_CheckSettings(void) break; #endif default: - r_shadow_realtime_world.ival = 0; - r_shadow_realtime_dlight.ival = 0; - return; + break; } if (!canstencil && !cansmap && !canshadowless) { - //no shadow methods available at all. + //can't even do lighting if (r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival) Con_Printf("Missing driver extensions: realtime lighting is not possible.\n"); r_shadow_realtime_world.ival = 0; diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index d9e5522a..e1ae6f19 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -181,8 +181,9 @@ void (APIENTRY *qglBindVertexArray)(GLuint vaoarray); const GLubyte * (APIENTRY * qglGetStringi) (GLenum name, GLuint index); void (APIENTRY * qglGetPointerv) (GLenum pname, GLvoid **parms); +void (APIENTRY *qglDrawBuffers)(GLsizei n, GLsizei *ids); //gl2 #ifndef GL_STATIC -void (APIENTRY *qglGenRenderbuffersEXT)(GLsizei n, GLuint* ids); +void (APIENTRY *qglGenRenderbuffersEXT)(GLsizei n, GLuint *ids); void (APIENTRY *qglBindRenderbufferEXT)(GLenum target, GLuint id); void (APIENTRY *qglRenderbufferStorageEXT)(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height); void (APIENTRY *qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint textureId); @@ -442,8 +443,20 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) s++; gl_minor_version = atoi(s); } - if (webgl) - gl_major_version+=1; + if (webgl) //webgl version 1 equates to gles 2. + { + if (gl_major_version < 1) + { //ie reports a bollocks version. don't try using fixed function stuff. + gl_major_version = 2; + gl_minor_version = 0; + } + else if (gl_major_version == 1) + gl_major_version += 1; + //webgl2 is not defined yet. either 2 will be gles3 or they'll skip it or something I don't know. + //so assume webgl2 is still equivelent to gles2, to avoid confusions. + } + //FIXME: verify gles3 works properly. + //yes, I know, this can't cope with minor versions of 10+... I don't care yet. gl_config.glversion += gl_major_version + (gl_minor_version/10.f); @@ -577,22 +590,6 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglGenProgramsARB = NULL; */ - r_config.texture_non_power_of_two = false; - gl_config.sgis_generate_mipmap = false; - - gl_config.tex_env_combine = false; - gl_config.env_add = false; - gl_config.nv_tex_env_combine4 = false; - - gl_config.arb_texture_env_combine = false; - gl_config.arb_texture_env_dot3 = false; - gl_config.arb_texture_cube_map = false; - - gl_config.arb_shader_objects = false; - gl_config.ext_framebuffer_objects = false; - - gl_config.ext_texture_filter_anisotropic = 0; - gl_config.ext_packed_depth_stencil = GL_CheckExtension("GL_EXT_packed_depth_stencil"); if (GL_CheckExtension("GL_EXT_texture_filter_anisotropic")) @@ -603,7 +600,10 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) } if (GL_CheckExtension("GL_ARB_texture_non_power_of_two") || GL_CheckExtension("GL_OES_texture_npot")) - r_config.texture_non_power_of_two = true; + gl_config.texture_non_power_of_two = true; + //gles2 has limited npot as standard, which is sufficient to make the hud not look like poo. lets use it. + if ((gl_config.gles && gl_config.glversion >= 2) || gl_config.texture_non_power_of_two) + gl_config.texture_non_power_of_two_limited = true; // if (GL_CheckExtension("GL_SGIS_generate_mipmap")) //a suprising number of implementations have this broken. // gl_config.sgis_generate_mipmap = true; @@ -950,11 +950,25 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglBindVertexArray = NULL; } + if (gl_config.gles) + { //gles has different TexImage2D arguments for specifying quality. + gl_config.arb_depth_texture = GL_CheckExtension("GL_OES_depth_texture"); //gles2 + gl_config.arb_depth_texture |= GL_CheckExtension("GL_CHROMIUM_depth_texture"); //nacl + gl_config.arb_depth_texture |= GL_CheckExtension("GL_WEBGL_depth_texture"); //webgl. duh. + } + else + { + gl_config.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture"); + } gl_config.arb_shadow = GL_CheckExtension("GL_ARB_shadow"); - gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2 + //gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2. nvidia fucks up. depend on brute-force. :s -#ifndef GL_STATIC - if (GL_CheckExtension("GL_ARB_framebuffer_object")) +#ifdef GL_STATIC + gl_config.ext_framebuffer_objects = true; //exists as core in gles2 +#else + if ((gl_config.gles && gl_config.glversion >= 2) || //exists as core in gles2 + (!gl_config.gles && gl_config.glversion >= 3) || //exists as core in gl3 + GL_CheckExtension("GL_ARB_framebuffer_object")) //exists as an extension in gl2 { gl_config.ext_framebuffer_objects = true; qglGenFramebuffersEXT = (void *)getglext("glGenFramebuffers"); @@ -2012,13 +2026,19 @@ void GL_Init(void *(*getglfunction) (char *name)) GL_CheckExtensions (getglfunction); + if ((gl_config.gles && gl_config.glversion >= 3) || (!gl_config.gles && gl_config.glversion >= 2)) + qglDrawBuffers = (void *)getglext("glDrawBuffers"); + else + qglDrawBuffers = NULL; + if (gl_config.gles && gl_config.glversion >= 2) { - /*no matricies in gles, so don't try!*/ + /*these functions do not exist in gles2, they only exist on some platforms because they were provided for gl1*/ qglLoadMatrixf = NULL; qglPolygonMode = NULL; qglShadeModel = NULL; qglDepthRange = NULL; + qglDrawBuffer = NULL; qglEnableClientState = GL_ClientStateStub; qglDisableClientState = GL_ClientStateStub; @@ -2031,6 +2051,7 @@ void GL_Init(void *(*getglfunction) (char *name)) qglPolygonMode = NULL; qglShadeModel = NULL; qglDepthRange = NULL; + qglDrawBuffer = NULL; qglEnableClientState = GL_ClientStateStub; qglDisableClientState = GL_ClientStateStub; @@ -2044,11 +2065,6 @@ void GL_Init(void *(*getglfunction) (char *name)) if (qglShadeModel) qglShadeModel (GL_FLAT); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - #ifdef DEBUG if (qglDebugMessageControlARB) qglDebugMessageControlARB(0, 0, 0, 0, NULL, true); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 099d19f8..d33eaacb 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -52,12 +52,6 @@ void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2); void ClearBounds (vec3_t mins, vec3_t maxs); -//optional features common to all renderers, so I don't have to check to see which one it is all the time. -typedef struct { - qboolean texture_non_power_of_two; -} r_config_t; -extern r_config_t r_config; - #ifdef GLQUAKE #if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/ #if 1 @@ -218,10 +212,14 @@ typedef struct { qboolean arb_texture_env_dot3; qboolean arb_texture_cube_map; + qboolean texture_non_power_of_two; //full npot support. + qboolean texture_non_power_of_two_limited; //mipless,clamped npot works, but generic npot doesn't. qboolean arb_texture_compression; + // qboolean arb_fragment_program; qboolean arb_shader_objects; qboolean arb_shadow; + qboolean arb_depth_texture; qboolean ext_framebuffer_objects; qboolean ext_stencil_wrap; qboolean ext_packed_depth_stencil; @@ -731,6 +729,7 @@ extern void *(APIENTRY *qglMapBufferARB)(GLenum target, GLenum access); extern GLboolean (APIENTRY *qglUnmapBufferARB)(GLenum target); #endif +extern void (APIENTRY *qglDrawBuffers)(GLsizei n, GLsizei *ids); //gl2 //non-gles2 gl functions extern void (APIENTRY *qglAccum) (GLenum op, GLfloat value); diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 114e40bc..01787833 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -13,8 +13,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //modifier: RIPPLEMAP (s_t3 contains a ripplemap //modifier: TINT (some colour value) -"uniform float cvar_r_glsl_turbscale;\n" - "#ifndef FRESNEL\n" "#define FRESNEL 5.0\n" "#endif\n" @@ -49,6 +47,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" +"uniform float cvar_r_glsl_turbscale;\n" "uniform sampler2D s_t0; //refract\n" "uniform sampler2D s_t1; //normalmap\n" "uniform sampler2D s_t2; //diffuse/reflection\n" @@ -176,7 +175,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //the bloom filter //filter out any texels which are not to bloom -"uniform vec3 cvar_r_bloom_filter;\n" "varying vec2 tc;\n" "#ifdef VERTEX_SHADER\n" @@ -188,6 +186,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" +"uniform vec3 cvar_r_bloom_filter;\n" "uniform sampler2D s_t0;\n" "void main ()\n" "{\n" @@ -199,7 +198,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "bloom_final", "!!cvarf r_bloom\n" -"uniform float cvar_r_bloom;\n" //add them together //optionally apply tonemapping @@ -218,6 +216,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform sampler2D s_t1;\n" "uniform sampler2D s_t2;\n" "uniform sampler2D s_t3;\n" +"uniform float cvar_r_bloom;\n" "void main ()\n" "{\n" "gl_FragColor = \n" @@ -1695,6 +1694,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!cvardf r_glsl_pcf\n" +"#ifndef USE_ARB_SHADOW\n" +//fall back on regular samplers if we must +"#define sampler2DShadow sampler2D\n" +"#endif\n" + //this is the main shader responsible for realtime dlights. //texture units: @@ -1706,7 +1710,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //CUBESHADOW "#ifndef r_glsl_pcf\n" -"#error r_glsl_pcf wasn't defined\n" +"#error r_glsl_pcf wasnt defined\n" "#endif\n" "#if r_glsl_pcf < 1\n" "#undef r_glsl_pcf\n" @@ -1728,12 +1732,15 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" "varying vec3 eyevector;\n" "#endif\n" - "#if defined(PCF) || defined(CUBE) || defined(SPOT)\n" "varying vec4 vtexprojcoord;\n" +"#endif\n" + + +"#ifdef VERTEX_SHADER\n" +"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n" "uniform mat4 l_cubematrix;\n" "#endif\n" -"#ifdef VERTEX_SHADER\n" "#include \"sys/skeletal.h\"\n" "uniform vec3 l_lightposition;\n" "attribute vec2 v_texcoord;\n" @@ -1872,7 +1879,13 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.\n" "#else\n" +"#ifdef USE_ARB_SHADOW\n" +//with arb_shadow, we can benefit from hardware acclerated pcf, for smoother shadows "#define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n" +"#else\n" +//this will probably be a bit blocky. +"#define dosamp(x,y) float(texture2D(s_t4, shadowcoord.xy + (vec2(x,y)*l_shadowmapscale.xy)).r >= shadowcoord.z)\n" +"#endif\n" "float s = 0.0;\n" "#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n" "s += dosamp(0.0, 0.0);\n" @@ -1973,6 +1986,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "gl_FragColor.rgb = fog3additive(diff*colorscale*l_lightcolour);\n" "}\n" "#endif\n" + }, #endif #ifdef D3D9QUAKE diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 22714c9d..30f1919d 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -638,11 +638,14 @@ typedef struct extern sh_config_t sh_config; #ifdef GLSLONLY -#define gl_config_nofixedfunc true -#define gl_config_gles true + #define gl_config_nofixedfunc true #else -#define gl_config_nofixedfunc gl_config.nofixedfunc -#define gl_config_gles gl_config.gles + #define gl_config_nofixedfunc gl_config.nofixedfunc +#endif +#ifdef GLESONLY + #define gl_config_gles true +#else + #define gl_config_gles gl_config.gles #endif #ifdef GLQUAKE diff --git a/engine/nacl/gl_vidppapi.c b/engine/nacl/gl_vidppapi.c index 440532f2..1225f341 100644 --- a/engine/nacl/gl_vidppapi.c +++ b/engine/nacl/gl_vidppapi.c @@ -265,7 +265,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); GL_EndRendering(); - GL_DoSwap(); + GLVID_SwapBuffers(); // vid.pixelwidth = info->width; // vid.pixelheight = info->height; @@ -280,7 +280,7 @@ void GLVID_Shutdown (void) glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); GL_EndRendering(); - GL_DoSwap(); + GLVID_SwapBuffers(); ppb_core->ReleaseResource(glcontext); // glTerminatePPAPI(); diff --git a/engine/nacl/sys_ppapi.c b/engine/nacl/sys_ppapi.c index 77f8c635..ea660fd7 100644 --- a/engine/nacl/sys_ppapi.c +++ b/engine/nacl/sys_ppapi.c @@ -319,7 +319,7 @@ void startquake(char *manif) args[parms.argc++] = manif; } - Sys_Printf("Starting up\n"); + Sys_Printf("Starting up (Built "__DATE__ ", " __TIME__")\n"); COM_InitArgv(parms.argc, parms.argv); TL_InitLanguages(); diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index dc6709bd..bacd2023 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -2295,7 +2295,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl } } else - Sys_Error("Command %s not recognised", qcc_token); + Sys_Error("Bad entity lump: '%s' not recognised (last ent was %i)", qcc_token, ed?ed->entnum:0); } if (resethunk) { diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 6a83a4e2..bbe0fdf2 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -891,7 +891,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) } #endif - f = FS_OpenVFS (name, "wb", FS_GAMEONLY); + f = FS_OpenVFS (name, "wbp", FS_GAMEONLY); if (!f) { Con_TPrintf ("ERROR: couldn't open %s.\n", name); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 8414fffb..201518a2 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1325,7 +1325,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us #ifdef VM_Q1 if (svs.gametype != GT_Q1QVM) //we cannot do this with qvm #endif - svprogfuncs->SetStringField(svprogfuncs, ent, &ent->v->model, sv.world.worldmodel->name, true); + svprogfuncs->SetStringField(svprogfuncs, ent, &ent->v->model, sv.strings.model_precache[1], true); ent->v->modelindex = 1; // world model ent->v->solid = SOLID_BSP; ent->v->movetype = MOVETYPE_PUSH; @@ -1400,6 +1400,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us // load and spawn all other entities SCR_SetLoadingFile("entities"); + if (!deathmatch.value && !*skill.string) //skill was left blank so it doesn't polute serverinfo on deathmatch servers. in single player, we ensure that it gets a proper value. + Cvar_Set(&skill, "1"); if (progstype == PROG_H2) { extern cvar_t coop; diff --git a/engine/shaders/glsl/altwater.glsl b/engine/shaders/glsl/altwater.glsl index ff13a331..c60a3a0e 100644 --- a/engine/shaders/glsl/altwater.glsl +++ b/engine/shaders/glsl/altwater.glsl @@ -6,8 +6,6 @@ //modifier: RIPPLEMAP (s_t3 contains a ripplemap //modifier: TINT (some colour value) -uniform float cvar_r_glsl_turbscale; - #ifndef FRESNEL #define FRESNEL 5.0 #endif @@ -42,6 +40,7 @@ void main (void) } #endif #ifdef FRAGMENT_SHADER +uniform float cvar_r_glsl_turbscale; uniform sampler2D s_t0; //refract uniform sampler2D s_t1; //normalmap uniform sampler2D s_t2; //diffuse/reflection diff --git a/engine/shaders/glsl/bloom_filter.glsl b/engine/shaders/glsl/bloom_filter.glsl index d2e36e94..531b4e9d 100644 --- a/engine/shaders/glsl/bloom_filter.glsl +++ b/engine/shaders/glsl/bloom_filter.glsl @@ -2,7 +2,6 @@ //the bloom filter //filter out any texels which are not to bloom -uniform vec3 cvar_r_bloom_filter; varying vec2 tc; #ifdef VERTEX_SHADER @@ -14,6 +13,7 @@ void main () } #endif #ifdef FRAGMENT_SHADER +uniform vec3 cvar_r_bloom_filter; uniform sampler2D s_t0; void main () { diff --git a/engine/shaders/glsl/bloom_final.glsl b/engine/shaders/glsl/bloom_final.glsl index c5c21d15..4ca9f716 100644 --- a/engine/shaders/glsl/bloom_final.glsl +++ b/engine/shaders/glsl/bloom_final.glsl @@ -1,5 +1,4 @@ !!cvarf r_bloom -uniform float cvar_r_bloom; //add them together //optionally apply tonemapping @@ -18,6 +17,7 @@ uniform sampler2D s_t0; uniform sampler2D s_t1; uniform sampler2D s_t2; uniform sampler2D s_t3; +uniform float cvar_r_bloom; void main () { gl_FragColor = diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index fa4a1155..688a3b73 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -7,6 +7,11 @@ !!cvardf r_glsl_pcf +#ifndef USE_ARB_SHADOW +//fall back on regular samplers if we must +#define sampler2DShadow sampler2D +#endif + //this is the main shader responsible for realtime dlights. //texture units: @@ -18,7 +23,7 @@ //CUBESHADOW #ifndef r_glsl_pcf -#error r_glsl_pcf wasn't defined +#error r_glsl_pcf wasnt defined #endif #if r_glsl_pcf < 1 #undef r_glsl_pcf @@ -40,12 +45,15 @@ varying vec3 lightvector; #if defined(SPECULAR) || defined(OFFSETMAPPING) varying vec3 eyevector; #endif - #if defined(PCF) || defined(CUBE) || defined(SPOT) varying vec4 vtexprojcoord; +#endif + + +#ifdef VERTEX_SHADER +#if defined(PCF) || defined(CUBE) || defined(SPOT) uniform mat4 l_cubematrix; #endif -#ifdef VERTEX_SHADER #include "sys/skeletal.h" uniform vec3 l_lightposition; attribute vec2 v_texcoord; @@ -184,7 +192,13 @@ float ShadowmapFilter(void) return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds. #else +#ifdef USE_ARB_SHADOW + //with arb_shadow, we can benefit from hardware acclerated pcf, for smoother shadows #define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r +#else + //this will probably be a bit blocky. + #define dosamp(x,y) float(texture2D(s_t4, shadowcoord.xy + (vec2(x,y)*l_shadowmapscale.xy)).r >= shadowcoord.z) +#endif float s = 0.0; #if r_glsl_pcf >= 1 && r_glsl_pcf < 5 s += dosamp(0.0, 0.0); @@ -285,3 +299,4 @@ void main () gl_FragColor.rgb = fog3additive(diff*colorscale*l_lightcolour); } #endif + diff --git a/engine/web/fs_web.c b/engine/web/fs_web.c index f256a1eb..267d5e0b 100644 --- a/engine/web/fs_web.c +++ b/engine/web/fs_web.c @@ -64,6 +64,15 @@ static qboolean QDECL VFSWEB_Close(vfsfile_t *file) Z_Free(file); return true; } +static qboolean QDECL VFSWEB_ClosePersist(vfsfile_t *file) +{ + vfswebfile_t *intfile = (vfswebfile_t*)file; +#ifdef _DEBUG + Con_DPrintf("Persisting file %s\n", file->dbgname); +#endif + emscriptenfte_buf_pushtolocalstore(intfile->handle); + return VFSWEB_Close(file); +} vfsfile_t *FSWEB_OpenTemp(void) { @@ -99,11 +108,13 @@ vfsfile_t *VFSWEB_Open(const char *osname, const char *mode, qboolean *needsflus vfswebfile_t *file; //qboolean read = !!strchr(mode, 'r'); qboolean write = !!strchr(mode, 'w'); + qboolean update = !!strchr(mode, '+'); qboolean append = !!strchr(mode, 'a'); + qboolean persist = !!strchr(mode, 'p'); if (needsflush) *needsflush = false; - f = emscriptenfte_buf_open(osname, write||append); + f = emscriptenfte_buf_open(osname, (write && !update)?2:(write||append)); if (f == -1) return NULL; @@ -122,7 +133,10 @@ vfsfile_t *VFSWEB_Open(const char *osname, const char *mode, qboolean *needsflus file->funcs.Seek = VFSWEB_Seek; file->funcs.Tell = VFSWEB_Tell; file->funcs.GetLen = VFSWEB_GetSize; - file->funcs.Close = VFSWEB_Close; + if (persist && (write || append)) + file->funcs.Close = VFSWEB_ClosePersist; + else + file->funcs.Close = VFSWEB_Close; file->funcs.Flush = VFSWEB_Flush; file->handle = f; @@ -233,7 +247,7 @@ static void QDECL FSWEB_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, ch result = VFS_READ(f, buffer, loc->len); // do soemthing with result if (result != loc->len) - Con_Printf("FSWEB_ReadFile() fread: Filename: %s, expected %i, result was %u \n",loc->rawname,loc->len,(unsigned int)result); + Con_Printf("FSWEB_ReadFile() fread: Filename: %s, expected %u, result was %u \n",loc->rawname,(unsigned int)loc->len,(unsigned int)result); VFS_CLOSE(f); } diff --git a/engine/web/ftejslib.h b/engine/web/ftejslib.h index 28bfe1b0..0c78285d 100644 --- a/engine/web/ftejslib.h +++ b/engine/web/ftejslib.h @@ -1,23 +1,25 @@ - +//emscripten's download mechanism lacks usable progress indicators. void emscriptenfte_async_wget_data2(const char *url, void *ctx, void (*onload)(void*ctx,void*buf,int sz), void (*onerror)(void*ctx,int code), void (*onprogress)(void*ctx,int prog,int total)); //filesystem buffers are implemented in javascript so that we are not bound by power-of-two heap limitations quite so much. //also, we can't use emscripten's stdio because it reserves 16m file handles or something. +//these buffers do not track file offsets nor file access permissions. int emscriptenfte_buf_create(void); -int emscriptenfte_buf_open(const char *name, int createifneeded); -int emscriptenfte_buf_rename(const char *oldname, const char *newname); -int emscriptenfte_buf_delete(const char *fname); -void emscriptenfte_buf_release(int handle); -unsigned int emscriptenfte_buf_getsize(int handle); -int emscriptenfte_buf_read(int handle, int offset, void *data, int len); -int emscriptenfte_buf_write(int handle, int offset, const void *data, int len); +int emscriptenfte_buf_open(const char *name, int createifneeded); //open +int emscriptenfte_buf_rename(const char *oldname, const char *newname); //rename files (if it was open, the handle now refers to the new file instead) +int emscriptenfte_buf_delete(const char *fname); //delete the named file. there may be problems if its currently open +void emscriptenfte_buf_release(int handle); //close +void emscriptenfte_buf_pushtolocalstore(int handle); //make a copy in the browser's local storage, if possible. +unsigned int emscriptenfte_buf_getsize(int handle); //get the size of the file buffer +int emscriptenfte_buf_read(int handle, int offset, void *data, int len);//read data +int emscriptenfte_buf_write(int handle, int offset, const void *data, int len);//write data. no access checks. -//websocket is implemented in javascript because there is no usable C api (emscripten's javascript implementation is shite). -int emscriptenfte_ws_connect(const char *url); -void emscriptenfte_ws_close(int sockid); -int emscriptenfte_ws_cansend(int sockid, int extra, int maxpending); -int emscriptenfte_ws_send(int sockid, const void *data, int len); -int emscriptenfte_ws_recv(int sockid, void *data, int len); +//websocket is implemented in javascript because there is no usable C api (emscripten's javascript implementation is shite and has fatal errors). +int emscriptenfte_ws_connect(const char *url); //open a websocket connect to a specific host +void emscriptenfte_ws_close(int sockid); //close it again +int emscriptenfte_ws_cansend(int sockid, int extra, int maxpending); //returns false if we're blocking for some reason. avoids overflowing. everything is otherwise reliable. +int emscriptenfte_ws_send(int sockid, const void *data, int len); //send data to the peer. queues data. never dropped. +int emscriptenfte_ws_recv(int sockid, void *data, int len); //receive data from the peer. //misc stuff for printf replacements void emscriptenfte_alert(const char *msg); @@ -33,6 +35,7 @@ int emscriptenfte_setupcanvas( void(*Resized)(int newwidth, int newheight), void(*Mouse)(int devid,int abs,float x,float y,float z,float size), void(*Button)(int devid, int down, int mbutton), - int(*Keyboard)(int devid, int down, int keycode, int unicode) + int(*Keyboard)(int devid, int down, int keycode, int unicode), + void(*Hash)(char *newhash) ); diff --git a/engine/web/ftejslib.js b/engine/web/ftejslib.js index e90b6c7b..7e48ec50 100644 --- a/engine/web/ftejslib.js +++ b/engine/web/ftejslib.js @@ -11,13 +11,14 @@ mergeInto(LibraryManager.library, $FTEC: { + linebuffer:'', w: -1, h: -1, donecb:0, evcb: { resize:0, mouse:0, - key:0, + key:0 }, handleevent : function(event) @@ -101,12 +102,13 @@ mergeInto(LibraryManager.library, } }, emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser'], - emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk) + emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk,evh) { FTEC.evcb.resize = evresz; FTEC.evcb.mouse = evm; FTEC.evcb.button = evb; FTEC.evcb.key = evk; + FTEC.evcb.hashchange = evh; if (!FTEC.donecb) { FTEC.donecb = 1; @@ -128,21 +130,36 @@ mergeInto(LibraryManager.library, var ctx = Browser.createContext(Module['canvas'], true, true); if (!ctx) return 0; - Browser.setCanvasSize(nw, nh, false); +// Browser.setCanvasSize(nw, nh, false); window.onresize = function() { //emscripten's browser library will revert sizes wrongly or something when we're fullscreen, so make sure that doesn't happen. - if (Browser.isFullScreen) - { - Browser.windowedWidth = window.innerWidth; - Browser.windowedHeight = window.innerHeight; - } - else +// if (Browser.isFullScreen) +// { +// Browser.windowedWidth = window.innerWidth; +// Browser.windowedHeight = window.innerHeight; +// } +// else Browser.setCanvasSize(window.innerWidth, window.innerHeight, false); + if (FTEC.evcb.resize != 0) + Runtime.dynCall('vii', FTEC.evcb.resize, [Module['canvas'].width, Module['canvas'].height]); }; window.onresize(); + if (FTEC.evcb.hashchange) + window.onhashchange = function() + { + if (FTEC.evcb.hashchange != 0) + { + var val = location.hash; + var ptr = _malloc(val.length); + writeStringToMemory(val, ptr); + Runtime.dynCall('vi', FTEC.evcb.hashchange, [ptr]); + _free(ptr); + } + }; + return 1; }, @@ -161,7 +178,15 @@ mergeInto(LibraryManager.library, //FIXME: split+merge by \n emscriptenfte_print : function(msg) { - console.log(Pointer_stringify(msg)); + FTEC.linebuffer += Pointer_stringify(msg); + for(;;) + { + nl = FTEC.linebuffer.indexOf("\n"); + if (nl == -1) + break; + console.log(FTEC.linebuffer.substring(0, nl)); + FTEC.linebuffer = FTEC.linebuffer.substring(nl+1); + } }, emscriptenfte_ticks_ms : function() { @@ -192,7 +217,7 @@ mergeInto(LibraryManager.library, b.h = _emscriptenfte_handle_alloc(b); return b.h; }, - //temp files + //filesystem emulation emscriptenfte_buf_open__deps : ['emscriptenfte_buf_create'], emscriptenfte_buf_open : function(name, createifneeded) { @@ -201,6 +226,25 @@ mergeInto(LibraryManager.library, var r = -1; if (f == null) { + if (window.localStorage && createifneeded != 2) + { + var str = window.localStorage.getItem(name); + if (str != null) + { + console.log('read file '+name+': ' + str); + + var len = str.length; + var buf = new Uint8Array(len); + for (var i = 0; i < len; i++) + buf[i] = str.charCodeAt(i); + + var b = {h:-1, r:2, l:len,m:len,d:buf, n:name}; + r = b.h = _emscriptenfte_handle_alloc(b); + FTEH.f[name] = b; + return b.h; + } + } + if (createifneeded) r = _emscriptenfte_buf_create(); if (r != -1) @@ -218,6 +262,8 @@ mergeInto(LibraryManager.library, f.r+=1; r = f.h; } + if (f != null && createifneeded == 2) + f.l = 0; //truncate it. return r; }, emscriptenfte_buf_rename : function(oldname, newname) @@ -248,6 +294,30 @@ console.log('deleted '+name); } return 0; }, + emscriptenfte_buf_pushtolocalstore : function(handle) + { + var b = FTEH.h[handle]; + if (b == null) + { + Module.printError('emscriptenfte_buf_pushtolocalstore with invalid handle'); + return; + } + if (b.n == null) + return; + var data = b.d; + var len = b.l; + if (window.localStorage) + { + var foo = ""; + //use a divide and conquer implementation instead for speed? + for (var i = 0; i < len; i++) + foo += String.fromCharCode(data[i]); + window.localStorage.setItem(b.n, foo); +console.log('saved '+b.n+' persistantly: '+foo); + } + else + console.log('local storage not supported'); + }, emscriptenfte_buf_release : function(handle) { var b = FTEH.h[handle]; diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index 1bd2851a..a1693901 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -35,7 +35,7 @@ static unsigned int domkeytoquake(unsigned int code) /* 0*/ 0,0,0,0,0,0,0,0, K_BACKSPACE,K_TAB,0,0,0,K_ENTER,0,0, /* 16*/ K_SHIFT,K_CTRL,K_ALT,K_PAUSE,K_CAPSLOCK,0,0,0,0,0,0,K_ESCAPE,0,0,0,0, /* 32*/ ' ',K_PGUP,K_PGDN,K_END,K_HOME,K_LEFTARROW,K_UPARROW,K_RIGHTARROW, K_DOWNARROW,0,0,0,K_PRINTSCREEN,K_INS,K_DEL,0, - /* 48*/ '0','1','2','3','4','5','6','7', '8','9',0,0,0,0,0,0, + /* 48*/ '0','1','2','3','4','5','6','7', '8','9',0,0,0,'=',0,0, /* 64*/ 0,'a','b','c','d','e','f','g', 'h','i','j','k','l','m','n','o', /* 80*/ 'p','q','r','s','t','u','v','w', 'x','y','z',K_LWIN,K_RWIN,K_APP,0,0, @@ -43,7 +43,7 @@ static unsigned int domkeytoquake(unsigned int code) /*112*/ K_F1,K_F2,K_F3,K_F4,K_F5,K_F6,K_F7,K_F8,K_F9,K_F10,K_F11,K_F12,0,0,0,0, /*128*/ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /*144*/ K_KP_NUMLOCK,K_SCRLCK,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - /*160*/ 0,0,0,'#',0,0,0,0, 0,0,0,0,0,0,0,0, + /*160*/ 0,0,0,'#',0,0,0,0, 0,0,0,0,0,'-',0,0, /*176*/ 0,0,0,0,0,0,0,0, 0,0,';','=',',','-','.','/', /*192*/ '`',0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /*208*/ 0,0,0,0,0,0,0,0, 0,0,0,'[','\\',']','\'','`', @@ -70,7 +70,7 @@ static unsigned int domkeytoshift(unsigned int code) /* 0*/ 0,0,0,0,0,0,0,0, K_BACKSPACE,K_TAB,0,0,0,K_ENTER,0,0, /* 16*/ K_SHIFT,K_CTRL,K_ALT,K_PAUSE,K_CAPSLOCK,0,0,0,0,0,0,K_ESCAPE,0,0,0,0, /* 32*/ ' ',K_PGUP,K_PGDN,K_END,K_HOME,K_LEFTARROW,K_UPARROW,K_RIGHTARROW, K_DOWNARROW,0,0,0,K_PRINTSCREEN,K_INS,K_DEL,0, - /* 48*/ ')','!','\"',0/*£*/,'$','%','^','&', '*','(',0,0,0,0,0,0, + /* 48*/ ')','!','\"',0/*£*/,'$','%','^','&', '*','(',0,0,0,'+',0,0, /* 64*/ 0,'A','B','C','D','E','F','G', 'H','I','J','K','L','M','N','O', /* 80*/ 'P','Q','R','S','T','U','V','W', 'X','Y','Z',K_LWIN,K_RWIN,K_APP,0,0, @@ -78,7 +78,7 @@ static unsigned int domkeytoshift(unsigned int code) /*112*/ K_F1,K_F2,K_F3,K_F4,K_F5,K_F6,K_F7,K_F8,K_F9,K_F10,K_F11,K_F12,0,0,0,0, /*128*/ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /*144*/ K_KP_NUMLOCK,K_SCRLCK,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - /*160*/ 0,0,0,'~',0,0,0,0, 0,0,0,0,0,0,0,0, + /*160*/ 0,0,0,'~',0,0,0,0, 0,0,0,0,0,'_',0,0, /*176*/ 0,0,0,0,0,0,0,0, 0,0,':','+','<','_','>','?', /*192*/ '`',0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /*208*/ 0,0,0,0,0,0,0,0, 0,0,0,'{','|','}','@','`', @@ -151,7 +151,11 @@ static void DOM_ButtonEvent(int devid, int down, int button) IN_KeyEvent(0, down, K_MOUSE1+button, 0); } } - +void DOM_HashChanged(char *loc) +{ + //try and open it. generally downloading it from the server. + Host_RunFile(loc+1, strlen(loc+1), NULL); +} qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) { int flags; @@ -164,7 +168,8 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) VID_Resized, IN_MouseMove, DOM_ButtonEvent, - DOM_KeyEvent + DOM_KeyEvent, + DOM_HashChanged )) { Con_Printf("Couldn't set up canvas\n"); @@ -177,6 +182,8 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) qglViewport (0, 0, vid.pixelwidth, vid.pixelheight); + VID_Resized(vid.pixelwidth, vid.pixelheight); + mouseactive = false; return true; @@ -186,7 +193,7 @@ void GLVID_DeInit (void) { ActiveApp = false; - emscriptenfte_setupcanvas(-1, -1, NULL, NULL, NULL, NULL); + emscriptenfte_setupcanvas(-1, -1, NULL, NULL, NULL, NULL, NULL); } diff --git a/engine/web/prejs.js b/engine/web/prejs.js index 0da480b9..ed8eb1ce 100644 --- a/engine/web/prejs.js +++ b/engine/web/prejs.js @@ -1,20 +1,18 @@ Module['preRun'] = function() { - //FS.createPath('/', 'id1', true, true); - //FS.createPath('/', 'qw', true, true); - //FS.createPath('/', 'fte', true, true); - - //FS.createPath('/', 'tmp', true, true); - - //FS.createPreloadedFile('/id1/', 'pak0.pak', '/pak0.pak', true, false); - //FS.createPreloadedFile('/id1/', 'pak1.pak', '/pak1.pak', true, false); - //FS.createPreloadedFile('/id1/', 'pak2.pak', '/pak2.pak', true, false); - //FS.createPreloadedFile('/id1/', 'pak3.pak', '/pak3.pak', true, false); }; -Module['arguments'] = ['-nohome', '-manifest', document.location + '.fmf']; -// use query string in URL as command line -if (!document.referrer) { - qstring = decodeURIComponent(window.location.search.substring(1)).split(" "); - Module['arguments'] = Module['arguments'].concat(qstring); -} +{ + Module['arguments'] = ['-nohome']; + + var man = window.location.protocol+'//'+window.location.host+window.location.pathname + '.fmf'; + if (window.location.hash != "") + man = window.location.hash.substring(1); + + Module['arguments'] = Module['arguments'].concat(['-manifest', man]); + // use query string in URL as command line + if (!document.referrer) { + qstring = decodeURIComponent(window.location.search.substring(1)).split(" "); + Module['arguments'] = Module['arguments'].concat(qstring); + } +} \ No newline at end of file