From ac471dd03e3af8cf98466ccadbb41e7b2476ddb7 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 2 Jun 2018 08:55:57 +0000 Subject: [PATCH] update native-menu things. attempt to deal with misaligned bsp models. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5258 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/api_menu.h | 92 ++++++++++---- engine/client/cl_main.c | 2 + engine/client/cl_parse.c | 2 +- engine/client/cl_plugin.inc | 3 + engine/client/cl_screen.c | 4 +- engine/client/client.h | 1 + engine/client/console.c | 4 +- engine/client/image.c | 26 +++- engine/client/in_generic.c | 9 +- engine/client/in_win.c | 1 + engine/client/keys.c | 2 +- engine/client/keys.h | 5 +- engine/client/m_download.c | 2 +- engine/client/m_items.c | 4 +- engine/client/m_mp3.c | 55 ++++++--- engine/client/m_native.c | 240 +++++++++++++++++++++++++++++------- engine/client/m_options.c | 46 +++++-- engine/client/menu.h | 2 +- engine/client/merged.h | 2 +- engine/client/net_master.c | 3 - engine/client/pr_menu.c | 6 +- engine/client/r_2d.c | 27 ++-- engine/client/r_surf.c | 1 + engine/client/render.h | 3 +- engine/client/renderer.c | 5 + engine/client/sbar.c | 2 +- engine/client/screen.h | 2 +- engine/client/snd_dma.c | 5 +- engine/common/cmd.c | 36 +++--- engine/common/com_mesh.c | 7 +- engine/common/com_mesh.h | 8 ++ engine/common/common.h | 4 +- engine/common/fs.c | 6 +- engine/common/net_wins.c | 4 +- engine/gl/gl_draw.c | 4 - engine/gl/gl_font.c | 24 ++-- engine/gl/gl_model.c | 138 +++++++++++++-------- engine/gl/gl_rmain.c | 2 +- engine/http/iwebiface.c | 2 +- engine/server/sv_init.c | 2 + engine/server/sv_user.c | 13 +- plugins/qi/qi.c | 2 +- 42 files changed, 581 insertions(+), 227 deletions(-) diff --git a/engine/client/api_menu.h b/engine/client/api_menu.h index 46b0c2b20..a26b07333 100644 --- a/engine/client/api_menu.h +++ b/engine/client/api_menu.h @@ -25,9 +25,13 @@ struct vfsfile_s; struct serverinfo_s; struct searchpathfuncs_s; +struct model_s; +struct font_s; +struct shader_s; enum slist_test_e; enum hostcachekey_e; //obtained via calls to gethostcacheindexforkey enum fs_relative; +enum com_tokentype_e; #ifndef __QUAKEDEF_H__ #ifdef __cplusplus typedef enum {qfalse, qtrue} qboolean;//false and true are forcivly defined. @@ -72,8 +76,39 @@ struct menu_inputevent_args_s }; }; +typedef enum +{ + MI_INIT, //initial startup + MI_RENDERER, //renderer restarted, any models/shaders/textures handles are no longer valid + MI_RESOLUTION, //video mode changed (scale or physical size) but without any gpu resources getting destroyed. you'll want to reload fonts. +} mintreason_t; + +typedef struct +{ + struct model_s *model; + int frame[2]; + float frametime[2]; + float frameweight[2]; + vec4_t matrix[3]; //axis/angles+origin +} menuentity_t; +typedef struct +{ + //these are in virtual coords, thus they need to be floats so that they can be rounded to ints more cleanly... yeah, scaling sucks. + vec2_t pos; + vec2_t size; + + float time; //affects shader effects + vec_t fov[2]; + vec4_t viewmatrix[3]; + + struct model_s *worldmodel; + int numentities; + menuentity_t *entlist; +} menuscene_t; + typedef struct { int api_version; //this may be higher than you expect. + const char *engine_version; int (*checkextension) (const char *ext); void (*error) (const char *err); @@ -81,9 +116,13 @@ typedef struct { void (*dprintf) (const char *text, ...); void (*localcmd) (const char *cmd); float (*cvar_float) (const char *name); - const char *(*cvar_string) (const char *name); //return value lasts until cvar_set is called, etc, so don't cache. + const char *(*cvar_string) (const char *name, qboolean effective); //NULL if it doesn't exist. return value lasts until cvar_set is called, etc, so don't cache. effective=true reports its active value, not the value that the user wanted. + const char *(*cvar_default) (const char *name); void (*cvar_set) (const char *name, const char *value); void (*registercvar) (const char *name, const char *defaultvalue, unsigned int flags, const char *description); + void (*registercommand) (const char *name, const char *description); + + char *(*parsetoken) (const char *data, char *out, int outlen, enum com_tokentype_e *toktype); int (*isserver) (void); int (*getclientstate) (void); @@ -94,21 +133,24 @@ typedef struct { void (*fclose) (struct vfsfile_s *fhandle); char *(*fgets) (struct vfsfile_s *fhandle, char *out, size_t outsize); //returns output buffer, or NULL void (*fprintf) (struct vfsfile_s *fhandle, const char *s, ...); - void (*EnumerateFiles) (const char *match, int (QDECL *callback)(const char *fname, qofs_t fsize, time_t mtime, void *ctx, struct searchpathfuncs_s *package), void *ctx); + void (*enumeratefiles) (const char *match, int (QDECL *callback)(const char *fname, qofs_t fsize, time_t mtime, void *ctx, struct searchpathfuncs_s *package), void *ctx); // Drawing stuff -// int (*iscachedpic) (const char *name); - void *(*precache_pic) (const char *name); - int (*drawgetimagesize) (void *pic, int *x, int *y); - void (*drawquad) (vec2_t position[4], vec2_t texcoords[4], void *pic, vec4_t rgba, unsigned int be_flags); -// void (*drawsubpic) (vec2_t pos, vec2_t sz, const char *pic, vec2_t srcpos, vec2_t srcsz, vec4_t rgba, unsigned int be_flags); -// void (*drawfill) (vec2_t position, vec2_t size, vec4_t rgba, unsigned int be_flags); -// float (*drawcharacter) (vec2_t position, int character, vec2_t scale, vec4_t rgba, unsigned int be_flags); -// float (*drawrawstring) (vec3_t position, char *text, vec3_t scale, vec4_t rgba, unsigned int be_flags); - float (*drawstring) (vec2_t position, const char *text, float height, vec4_t rgba, unsigned int be_flags); - float (*stringwidth) (const char *text, float height); void (*drawsetcliparea) (float x, float y, float width, float height); void (*drawresetcliparea) (void); + struct shader_s *(*cachepic)(const char *name); + qboolean (*drawgetimagesize)(struct shader_s *pic, int *x, int *y); + void (*drawquad) (const vec2_t position[4], const vec2_t texcoords[4], struct shader_s *pic, const vec4_t rgba, unsigned int be_flags); + + float (*drawstring) (vec2_t position, const char *text, struct font_s *font, float height, const vec4_t rgba, unsigned int be_flags); + float (*stringwidth) (const char *text, struct font_s *font, float height); + struct font_s *(*loadfont) (const char *facename, float intendedheight); //with ttf fonts, you'll probably want one for each size. + void (*destroyfont) (struct font_s *font); + + // 3D scene stuff + struct model_s *(*cachemodel)(const char *name); + void (*getmodelsize) (struct model_s *model, vec3_t out_mins, vec3_t out_maxs); + void (*renderscene) (menuscene_t *scene); // Menu specific stuff qboolean (*setkeydest) (qboolean focused); //returns whether it changed. @@ -119,39 +161,39 @@ typedef struct { int (*findkeysforcommand) (int bindmap, const char *command, int *out_scancodes, int *out_modifiers, int keycount); // Server browser stuff - int (*gethostcachevalue) (int type); + enum hostcachekey_e (*gethostcacheindexforkey) (const char *key); + struct serverinfo_s *(*getsortedhost) (int idx); char *(*gethostcachestring) (struct serverinfo_s *host, enum hostcachekey_e fld); float (*gethostcachenumber) (struct serverinfo_s *host, enum hostcachekey_e fld); void (*resethostcachemasks) (void); - void (*sethostcachemaskstring) (qboolean or, enum hostcachekey_e fld, char *str, enum slist_test_e op); + void (*sethostcachemaskstring) (qboolean or, enum hostcachekey_e fld, const char *str, enum slist_test_e op); void (*sethostcachemasknumber) (qboolean or, enum hostcachekey_e fld, int num, enum slist_test_e op); void (*sethostcachesort) (enum hostcachekey_e fld, qboolean descending); - void (*resorthostcache) (void); - struct serverinfo_s *(*getsortedhost) (int idx); + int (*resorthostcache) (void); void (*refreshhostcache) (qboolean fullreset); - enum hostcachekey_e (*gethostcacheindexforkey) (const char *key); + qboolean (*sendhostcachequeries) (void); //returns true while there are still waiting for servers. should be called each frame while you still care about the servers. } menu_import_t; typedef struct { int api_version; - void (*Init) (void); - void (*Shutdown) (void); - void (*Draw) (int width, int height, float frametime); - void (*DrawLoading) (int width, int height, float frametime); + void (*Init) (mintreason_t reason, float vwidth, float vheight, int pwidth, int pheight); + void (*Shutdown) (mintreason_t reason); + void (*Draw) (double frametime); + void (*DrawLoading) (double frametime); void (*Toggle) (int wantmode); int (*InputEvent) (struct menu_inputevent_args_s ev); - void (*ConsoleCommand) (const char *cmd); + qboolean(*ConsoleCommand) (const char *cmdline, int argc, char const*const*argv); } menu_export_t; #ifndef NATIVEEXPORT #ifdef _WIN32 - #define NATIVEEXPORTPROTO QDECL - #define NATIVEEXPORT __declspec(dllexport) NATIVEEXPORTPROTO + #define NATIVEEXPORTPROTO __declspec(dllexport) + #define NATIVEEXPORT NATIVEEXPORTPROTO #else #define NATIVEEXPORTPROTO #define NATIVEEXPORT __attribute__((visibility("default"))) #endif #endif -menu_export_t *NATIVEEXPORTPROTO GetMenuAPI (menu_import_t *import); +NATIVEEXPORTPROTO menu_export_t *QDECL GetMenuAPI (menu_import_t *import); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index caae67940..de8bddf18 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -4716,6 +4716,8 @@ unsigned int Host_GuessFileType(const char *mimetype, const char *filename) {HRF_MODEL, "psk"}, {HRF_MODEL, "zym"}, {HRF_MODEL, "dpm"}, + {HRF_MODEL, "gltf"}, + {HRF_MODEL, "glb"}, //sprites {HRF_MODEL, "spr"}, {HRF_MODEL, "spr2"}, diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 8f151e1d3..60c5785fc 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1461,7 +1461,7 @@ static int CL_LoadSounds(int stage, qboolean dontactuallyload) void Sound_CheckDownload(const char *s) { -#ifndef QUAKETC +#if !defined(QUAKETC) && defined(AVAIL_OGGVORBIS) char mangled[512]; #endif if (*s == '*') //q2 sexed sound diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 7ed2bd207..5fd0211fe 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -1251,6 +1251,9 @@ qintptr_t VARGS Plug_Mod_GetPluginModelFuncs(void *offset, quintptr_t mask, cons #else NULL, #endif + NULL, + Image_GetTexture, + FS_OpenVFS }; if (VM_LONG(arg[0]) >= sizeof(funcs)) return (qintptr_t)&funcs; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index fe2b1c322..479e7d17f 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1899,7 +1899,7 @@ void SCR_DrawLoading (qboolean opaque) #ifdef MENU_NATIVECODE if (mn_entry && mn_entry->DrawLoading) { - mn_entry->DrawLoading(vid.width, vid.height, host_frametime); + mn_entry->DrawLoading(host_frametime); return; } #endif @@ -3397,7 +3397,7 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) #endif #ifdef MENU_NATIVECODE if (mn_entry) - mn_entry->Draw(vid.width, vid.height, host_frametime); + mn_entry->Draw(host_frametime); #endif M_Draw (uimenu); diff --git a/engine/client/client.h b/engine/client/client.h index 4d5b294a1..ad7053d5a 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1665,6 +1665,7 @@ const char *Media_Send_GetProperty(cin_t *cin, const char *key); #define Media_StopFilm(a) (void)true #endif +void Media_SaveTracks(vfsfile_t *outcfg); void Media_Init(void); qboolean Media_NamedTrack(const char *initialtrack, const char *looptrack); //new background music interface void Media_NumberedTrack(unsigned int initialtrack, unsigned int looptrack); //legacy cd interface for protocols that only support numbered tracks. diff --git a/engine/client/console.c b/engine/client/console.c index 80634199a..367bc4a34 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1323,7 +1323,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, i = 0; x = left; - if (con->commandcompletion && con_showcompletion.ival) + if (con->commandcompletion && con_showcompletion.ival && text[0] && !(text[0] == '/' && !text[1])) { if (cl_chatmode.ival && (text[0] == '/' || (cl_chatmode.ival == 2 && Cmd_IsCommand(text)))) { //color the first token yellow, it's a valid command @@ -1337,7 +1337,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, { int cmdstart; cmdstart = text[0] == '/'?1:0; - fname = Cmd_CompleteCommand(text+cmdstart, true, true, con_commandmatch, NULL); + fname = Cmd_CompleteCommand(text+cmdstart, true, true, max(1, con_commandmatch), NULL); if (fname && strlen(fname) < 256) //we can compleate it to: { for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>0; p++) diff --git a/engine/client/image.c b/engine/client/image.c index 91aefef92..93af48494 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -5355,6 +5355,8 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla #if 0//def DECOMPRESS_BPTC case PTI_BC6_RGBFU: case PTI_BC6_RGBFS: + rcoding = PTI_RGBA16F; + break; case PTI_BC7_RGBA: case PTI_BC7_RGBA_SRGB: rcoding = PTI_ZOMGWTF; @@ -5412,6 +5414,10 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla return; } + //Fixme: PTI_E5BGR9 -> PTI_RGBA32F + //Fixme: PTI_RGBA16F -> PTI_RGBA32F + //FIXME: PTI_RGBA32F -> PTI_RGBA8 + if ((mips->encoding == PTI_RGBX8 && sh_config.texfmt[PTI_BGRX8]) || (mips->encoding == PTI_BGRX8 && sh_config.texfmt[PTI_RGBX8]) || (mips->encoding == PTI_RGBA8 && sh_config.texfmt[PTI_BGRA8]) || @@ -6598,7 +6604,8 @@ static qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, c int firstex = (tex->flags & IF_EXACTEXTENSION)?tex_extensions_count-1:0; flocation_t loc; - + + if (strncmp(tex->ident, "http:", 5) && strncmp(tex->ident, "https:", 6)) for(altname = tex->ident;altname;altname = nextalt) { nextalt = strchr(altname, ':'); @@ -6978,7 +6985,14 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t if (tex->fallbackdata) { - if (Image_LoadRawTexture(tex, tex->flags, tex->fallbackdata, (char*)tex->fallbackdata+(tex->fallbackwidth*tex->fallbackheight), tex->fallbackwidth, tex->fallbackheight, tex->fallbackfmt)) + if (tex->fallbackfmt == TF_INVALID) + { + void *data = tex->fallbackdata; + tex->fallbackdata = NULL; + if (Image_LoadTextureFromMemory(tex, tex->flags, tex->ident, fname, data, tex->fallbackwidth)) + return; + } + else if (Image_LoadRawTexture(tex, tex->flags, tex->fallbackdata, (char*)tex->fallbackdata+(tex->fallbackwidth*tex->fallbackheight), tex->fallbackwidth, tex->fallbackheight, tex->fallbackfmt)) { tex->fallbackdata = NULL; return; @@ -7098,7 +7112,7 @@ static void Image_Downloaded(struct dl_download *dl) #endif //find a texture. will try to load it from disk, using the fallback if it would fail. -image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt) +image_t *QDECL Image_GetTexture(const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt) { image_t *tex; @@ -7135,6 +7149,10 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned int b = fallbackwidth*fallbackheight, pb = 0; switch(fallbackfmt) { + case TF_INVALID: + b = fallbackwidth; + pb = fallbackheight; + break; case TF_8PAL24: pb = 3*256; b *= 1; @@ -7414,7 +7432,7 @@ void Image_List_f(void) Q_strncpyz(defuck, loc.search->logicalpath, sizeof(defuck)); while((bullshit=strchr(defuck, '\\'))) *bullshit = '/'; - Con_Printf("^[%s\\desc\\%s/%s^]: ", tex->ident, defuck, fname); + Con_Printf("^[%s\\tip\\%s/%s^]: ", tex->ident, defuck, fname); } else Con_Printf("%s: ", tex->ident); diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index 41e4dc0df..734e80bc9 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -122,7 +122,7 @@ static cvar_t joy_exponent = CVARD("joyexponent", "3", "Scales joystick/controll static cvar_t joy_radialdeadzone = CVARD("joyradialdeadzone", "1", "Treat controller dead zones as a pair, rather than per-axis."); -#define EVENTQUEUELENGTH 512 +#define EVENTQUEUELENGTH 1024 struct eventlist_s { enum @@ -747,7 +747,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame ev.mouse.delta[0] = mx; ev.mouse.delta[1] = my; ev.mouse.screen[0] = (mouse->oldpos[0] * vid.width) / vid.pixelwidth; - ev.mouse.screen[1] = (mouse->oldpos[1] * vid.width) / vid.pixelwidth; + ev.mouse.screen[1] = (mouse->oldpos[1] * vid.height) / vid.pixelheight; if (mn_entry->InputEvent(ev)) { mx = 0; @@ -1048,7 +1048,10 @@ z is height... generally its used as a mousewheel instead, but there are some '3 */ void IN_MouseMove(unsigned int devid, int abs, float x, float y, float z, float size) { - struct eventlist_s *ev = in_newevent(); + struct eventlist_s *ev; + if (!abs && !x && !y && !z) + return; //ignore non-movements + ev = in_newevent(); if (!ev) return; ev->devid = devid; diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 74c60c39c..28172ff5f 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -554,6 +554,7 @@ static void INS_DeactivateMouse (void) ClipCursor (NULL); ReleaseCapture (); + SetCursorPos(window_rect.left+mousecursor_x, window_rect.top+mousecursor_y); } mouseactive = false; diff --git a/engine/client/keys.c b/engine/client/keys.c index 1f7f1a42a..599e8be5f 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -2838,7 +2838,7 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down { if (mn_entry) { - struct menu_inputevent_args_s ev = {MIE_KEYDOWN, devid}; + struct menu_inputevent_args_s ev = {down?MIE_KEYDOWN:MIE_KEYUP, devid}; ev.key.scancode = key; ev.key.charcode = unicode; if (mn_entry->InputEvent(ev)) diff --git a/engine/client/keys.h b/engine/client/keys.h index 2233d4ff7..50bf114ca 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -244,6 +244,7 @@ K_MAX #define K_ALT K_LALT #define K_WIN K_LWIN +#ifdef __QUAKEDEF_H__ typedef enum //highest has priority { kdm_game = 1u<<0, //should always be set @@ -251,7 +252,7 @@ typedef enum //highest has priority kdm_message = 1u<<2, kdm_gmenu = 1u<<3, //menu.dat #ifdef MENU_NATIVECODE - kdm_nmenu = 1u<<4, + kdm_nmenu = 1u<<4, //should probably reuse gmenu... #else kdm_nmenu = 0, #endif @@ -315,6 +316,6 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode); struct console_s; qboolean Key_GetConsoleSelectionBox(struct console_s *con, int *sx, int *sy, int *ex, int *ey); qboolean Key_MouseShouldBeFree(void); - +#endif #endif diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 9fc0b59d5..0f016a873 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -2700,7 +2700,7 @@ void PM_Command_f(void) Con_Printf("Applying package changes\n"); if (qrenderer != QR_NONE) PM_PromptApplyChanges(); - else + else if (Cmd_ExecLevel == RESTRICT_LOCAL) PM_ApplyChanges(); } else if (!strcmp(act, "changes")) diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 9ee102e90..30af90010 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -1945,6 +1945,8 @@ static int M_Main_AddExtraOptions(menu_t *mainm, int y) {MC_AddConsoleCommandQBigFont(mainm, 72, y, "IRC ", "irc\n"); y += 20;} if (Cmd_Exists("qi")) {MC_AddConsoleCommandQBigFont(mainm, 72, y, "Quake Injector", "qi\n"); y += 20;} +// else if (PM_CanInstall("qi")) +// {MC_AddConsoleCommandQBigFont(mainm, 72, y, "Quake Injector", "pkg reset; pkg add qi; pkg apply\n"); y += 20;} if (Cmd_Exists("menu_download")) {MC_AddConsoleCommandQBigFont(mainm, 72, y, "Updates ", "menu_download\n"); y += 20;} @@ -2141,7 +2143,7 @@ void M_Menu_Main_f (void) } else { - int width, y; + int width; Key_Dest_Add(kdm_emenu); mainm = M_CreateMenu(0); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index c21aa6284..a60f2d2a2 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -352,7 +352,7 @@ qboolean Media_NamedTrack(const char *track, const char *looptrack) { "", #if defined(AVAIL_OGGOPUS) || defined(FTE_TARGET_WEB) - ".opus", + ".opus", //opus might be the future, but ogg is the present #endif #if defined(AVAIL_OGGVORBIS) || defined(FTE_TARGET_WEB) ".ogg", @@ -364,8 +364,9 @@ qboolean Media_NamedTrack(const char *track, const char *looptrack) NULL }; char trackname[MAX_QPATH]; + char tryname[MAX_QPATH]; + int bestdepth = 0x7fffffff, d; int ie, ip; - qboolean found = false; char *trackend; if (!track || !*track) //ignore calls if the primary track is invalid. whatever is already playing will continue to play. @@ -394,11 +395,11 @@ qboolean Media_NamedTrack(const char *track, const char *looptrack) if (!tracknum) //might as well require exact file { Q_snprintfz(trackname, sizeof(trackname), "%s", track); - found = COM_FCheckExists(trackname); + d = COM_FCheckExists(trackname); } else #endif - for(ip = 0; path[ip] && !found; ip++) + for(ip = 0; path[ip]; ip++) { if (tracknum) { @@ -406,33 +407,49 @@ qboolean Media_NamedTrack(const char *track, const char *looptrack) { if (tracknum <= 999) { - for(ie = 0; ext[ie] && !found; ie++) + for(ie = 0; ext[ie]; ie++) { - Q_snprintfz(trackname, sizeof(trackname), "%strack%03u%s", path[ip], tracknum, ext[ie]); - found = COM_FCheckExists(trackname); + Q_snprintfz(tryname, sizeof(tryname), "%strack%03u%s", path[ip], tracknum, ext[ie]); + d = COM_FDepthFile(tryname, false); + if (d < bestdepth) + { + bestdepth = d; + Q_strncpy(trackname, tryname, sizeof(trackname)); + } } } if (tracknum <= 99) { - for(ie = 0; ext[ie] && !found; ie++) + for(ie = 0; ext[ie]; ie++) { - Q_snprintfz(trackname, sizeof(trackname), "%strack%02u%s", path[ip], tracknum, ext[ie]); - found = COM_FCheckExists(trackname); + Q_snprintfz(tryname, sizeof(tryname), "%strack%02u%s", path[ip], tracknum, ext[ie]); + d = COM_FDepthFile(tryname, false); + if (d < bestdepth) + { + bestdepth = d; + Q_strncpy(trackname, tryname, sizeof(trackname)); + } } } } } else { - for(ie = 0; ext[ie] && !found; ie++) + for(ie = 0; ext[ie]; ie++) { - Q_snprintfz(trackname, sizeof(trackname), "%s%s%s", path[ip], track, ext[ie]); - found = COM_FCheckExists(trackname); + Q_snprintfz(tryname, sizeof(tryname), "%s%s%s", path[ip], track, ext[ie]); + d = COM_FDepthFile(tryname, false); + if (d < bestdepth) + { + bestdepth = d; + Q_strncpy(trackname, tryname, sizeof(trackname)); + } } } } - if (found) + //okay, do that faketrack thing if we got one. + if (bestdepth < 0x7fffffff) { #ifdef HAVE_CDPLAYER cdplaytracknum = 0; @@ -444,11 +461,11 @@ qboolean Media_NamedTrack(const char *track, const char *looptrack) } #ifdef HAVE_CDPLAYER + //couldn't do a faketrack, resort to actual cd tracks, if we're allowed if (tracknum && cdenabled) { Q_strncpyz(media_loopingtrack, looptrack, sizeof(media_loopingtrack)); - //couldn't do a faketrack, resort to actual cd tracks, if we're allowed if (!CDAudio_Startup()) return false; if (cdnumtracks <= 0) @@ -526,6 +543,14 @@ void Media_SetPauseTrack(qboolean paused) } #ifdef HAVE_CDPLAYER +void Media_SaveTracks(vfsfile_t *outcfg) +{ + unsigned int n; + char buf[MAX_QPATH*4]; + for (n = 1; n < REMAPPED_TRACKS; n++) + if (*cdremap[n].fname) + Con_Printf("cd remap %u %s\n", n, COM_QuotedString(cdremap[n].fname, buf, sizeof(buf), false)); +} void CD_f (void) { char *command; diff --git a/engine/client/m_native.c b/engine/client/m_native.c index 8f4f5b3c9..1eb2c9a63 100644 --- a/engine/client/m_native.c +++ b/engine/client/m_native.c @@ -8,7 +8,7 @@ extern unsigned int r2d_be_flags; #include "shader.h" #include "cl_master.h" -static int MN_checkextension(const char *extname) +static int MN_CheckExtension(const char *extname) { unsigned int i; for (i = 0; i < QSG_Extensions_count; i++) @@ -18,15 +18,41 @@ static int MN_checkextension(const char *extname) } return false; } -static void MN_localcmd(const char *text) +static void MN_LocalCmd(const char *text) { Cbuf_AddText(text, RESTRICT_LOCAL); //menus are implicitly trusted. latching and other stuff would be a nightmare otherwise. } -static void MN_registercvar(const char *cvarname, const char *defaulttext, unsigned int flags, const char *description) +static const char *MN_Cvar_String(const char *cvarname, qboolean effective) +{ + cvar_t *cv = Cvar_FindVar(cvarname); + if (cv) + { //some cvars don't change instantly, giving them (temporary) effective values that are different from their intended values. + if (cv->latched_string && !effective) + return cv->latched_string; + return cv->string; + } + else + return NULL; +} +static const char *MN_Cvar_GetDefault(const char *cvarname) +{ + cvar_t *cv = Cvar_FindVar(cvarname); + if (cv) + return cv->defaultstr?cv->defaultstr:""; + else + return NULL; +} +static void MN_RegisterCvar(const char *cvarname, const char *defaulttext, unsigned int flags, const char *description) { Cvar_Get2(cvarname, defaulttext, flags, description, NULL); } -static int MN_getserverstate(void) +void Cmd_DeleteAlias(const char *name); +static void MN_RegisterCommand(const char *commandname, const char *description) +{ + Cmd_DeleteAlias(commandname); //menuqc has no real way to register commands, so it has a nasty habit of creating loads of weird awkward aliases. + Cmd_AddCommandD(commandname, NULL, description); +} +static int MN_GetServerState(void) { if (!sv.active) return 0; @@ -34,7 +60,7 @@ static int MN_getserverstate(void) return 1; return 2; } -static int MN_getclientstate(void) +static int MN_GetClientState(void) { if (cls.state >= ca_active) return 2; @@ -46,50 +72,60 @@ static void MN_fclose(vfsfile_t *f) { VFS_CLOSE(f); } -static void *MN_precache_pic(const char *picname) +static shader_t *MN_CachePic(const char *picname) { return R2D_SafeCachePic(picname); } -static int MN_drawgetimagesize(void *pic, int *w, int *h) +static qboolean MN_DrawGetImageSize(void *pic, int *w, int *h) { - return R_GetShaderSizes(pic, w, h, true); + return R_GetShaderSizes(pic, w, h, true)>0; } -static void MN_drawquad(vec2_t position[4], vec2_t texcoords[4], void *pic, vec4_t rgba, unsigned int be_flags) +static void MN_DrawQuad(const vec2_t position[4], const vec2_t texcoords[4], shader_t *pic, const vec4_t rgba, unsigned int be_flags) { + extern shader_t *shader_draw_fill, *shader_draw_fill_trans; r2d_be_flags = be_flags; + if (!pic) + pic = rgba[3]==1?shader_draw_fill:shader_draw_fill_trans; R2D_ImageColours(rgba[0], rgba[1], rgba[2], rgba[3]); R2D_Image2dQuad(position, texcoords, pic); r2d_be_flags = 0; } -static float MN_drawstring(vec2_t position, const char *text, float height, vec4_t rgba, unsigned int be_flags) +static float MN_DrawString(const vec2_t position, const char *text, struct font_s *font, float height, const vec4_t rgba, unsigned int be_flags) { float px, py, ix; unsigned int codeflags, codepoint; conchar_t buffer[2048], *str = buffer; + if (!font) + font = font_default; + COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false); - Font_BeginScaledString(font_default, position[0], position[1], height, height, &px, &py); + R2D_ImageColours(rgba[0], rgba[1], rgba[2], rgba[3]); + Font_BeginScaledString(font, position[0], position[1], height, height, &px, &py); ix=px; while(*str) { str = Font_Decode(str, &codeflags, &codepoint); px = Font_DrawScaleChar(px, py, codeflags, codepoint); } - Font_EndString(font_default); + Font_EndString(font); return ((px-ix)*(float)vid.width)/(float)vid.rotpixelwidth; } -static float MN_stringwidth(const char *text, float height) +static float MN_StringWidth(const char *text, struct font_s *font, float height) { float px, py; conchar_t buffer[2048], *end; + if (!font) + font = font_default; + end = COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false); - Font_BeginScaledString(font_default, 0, 0, height, height, &px, &py); + Font_BeginScaledString(font, 0, 0, height, height, &px, &py); px = Font_LineScaleWidth(buffer, end); - Font_EndString(font_default); + Font_EndString(font); return (px * (float)vid.width) / (float)vid.rotpixelwidth; } -static void MN_drawsetcliparea(float x, float y, float width, float height) +static void MN_DrawSetClipArea(float x, float y, float width, float height) { srect_t srect; if (R2D_Flush) @@ -104,13 +140,13 @@ static void MN_drawsetcliparea(float x, float y, float width, float height) srect.y = (1-srect.y) - srect.height; BE_Scissor(&srect); } -static void MN_drawresetcliparea(void) +static void MN_DrawResetClipArea(void) { if (R2D_Flush) R2D_Flush(); BE_Scissor(NULL); } -static qboolean MN_setkeydest(qboolean focused) +static qboolean MN_SetKeyDest(qboolean focused) { qboolean ret = Key_Dest_Has(kdm_nmenu); if (ret == focused) @@ -119,9 +155,10 @@ static qboolean MN_setkeydest(qboolean focused) { if (key_dest_absolutemouse & kdm_nmenu) { //we're activating the mouse cursor now... make sure the position is actually current. + //FIXME: we should probably get the input code to do this for us when switching cursor modes. struct menu_inputevent_args_s ev = {MIE_MOUSEABS, -1}; - ev.mouse.screen[0] = mousecursor_x; - ev.mouse.screen[1] = mousecursor_y; + ev.mouse.screen[0] = (mousecursor_x * vid.width) / vid.pixelwidth; + ev.mouse.screen[1] = (mousecursor_y * vid.height) / vid.pixelheight; mn_entry->InputEvent(ev); } Key_Dest_Add(kdm_nmenu); @@ -130,7 +167,7 @@ static qboolean MN_setkeydest(qboolean focused) Key_Dest_Remove(kdm_nmenu); return true; } -static int MN_getkeydest(void) +static int MN_GetKeyDest(void) { if (Key_Dest_Has(kdm_nmenu)) { @@ -140,7 +177,7 @@ static int MN_getkeydest(void) } return 0; } -static int MN_setmousetarget(const char *cursorname, float hot_x, float hot_y, float scale) +static int MN_SetMouseTarget(const char *cursorname, float hot_x, float hot_y, float scale) { if (cursorname) { @@ -162,12 +199,108 @@ static int MN_setmousetarget(const char *cursorname, float hot_x, float hot_y, f return true; } +static model_t *MN_CacheModel(const char *name) +{ + return Mod_ForName(name, MLV_SILENT); +} +static qboolean MN_GetModelSize(model_t *model, vec3_t out_mins, vec3_t out_maxs) +{ + if (model) + { + while(model->loadstate == MLS_LOADING) + COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING); + + VectorCopy(model->mins, out_mins); + VectorCopy(model->maxs, out_maxs); + return model->loadstate == MLS_LOADED; + } + VectorClear(out_mins); + VectorClear(out_maxs); + return false; +} +static void MN_RenderScene(menuscene_t *scene) +{ + int i; + entity_t ent; + menuentity_t *e; + if (R2D_Flush) + R2D_Flush(); + + CL_ClearEntityLists(); + memset(&ent, 0, sizeof(ent)); + for (i = 0; i < scene->numentities; i++) + { + e = &scene->entlist[i]; + ent.keynum = i; + ent.model = scene->entlist[i].model; + VectorCopy(e->matrix[0], ent.axis[0]); ent.origin[0] = e->matrix[0][3]; + VectorCopy(e->matrix[1], ent.axis[1]); ent.origin[1] = e->matrix[0][7]; + VectorCopy(e->matrix[2], ent.axis[2]); ent.origin[2] = e->matrix[0][11]; + + ent.scale = 1; + ent.framestate.g[FS_REG].frame[0] = e->frame[0]; + ent.framestate.g[FS_REG].frame[1] = e->frame[1]; + ent.framestate.g[FS_REG].lerpweight[1] = e->frameweight[0]; + ent.framestate.g[FS_REG].lerpweight[0] = e->frameweight[1]; + ent.framestate.g[FS_REG].frametime[0] = e->frametime[0]; + ent.framestate.g[FS_REG].frametime[1] = e->frametime[1]; + + ent.playerindex = -1; + ent.topcolour = TOP_DEFAULT; + ent.bottomcolour = BOTTOM_DEFAULT; + Vector4Set(ent.shaderRGBAf, 1, 1, 1, 1); + VectorSet(ent.glowmod, 1, 1, 1); +#ifdef HEXEN2 + ent.drawflags = SCALE_ORIGIN_ORIGIN; + ent.abslight = 0; +#endif + ent.skinnum = 0; + ent.fatness = 0; + ent.forcedshader = NULL; + ent.customskin = 0; + + V_AddAxisEntity(&ent); + } + + VectorCopy(scene->viewmatrix[0], r_refdef.viewaxis[0]); r_refdef.vieworg[0] = scene->viewmatrix[0][3]; + VectorCopy(scene->viewmatrix[1], r_refdef.viewaxis[1]); r_refdef.vieworg[1] = scene->viewmatrix[0][7]; + VectorCopy(scene->viewmatrix[2], r_refdef.viewaxis[2]); r_refdef.vieworg[2] = scene->viewmatrix[0][11]; + + r_refdef.viewangles[0] = -(atan2(r_refdef.viewaxis[0][2], sqrt(r_refdef.viewaxis[0][1]*r_refdef.viewaxis[0][1]+r_refdef.viewaxis[0][0]*r_refdef.viewaxis[0][0])) * 180 / M_PI); + r_refdef.viewangles[1] = (atan2(r_refdef.viewaxis[0][1], r_refdef.viewaxis[0][0]) * 180 / M_PI); + r_refdef.viewangles[2] = 0; + + r_refdef.flags = 0; + if (scene->worldmodel && scene->worldmodel == cl.worldmodel) + r_refdef.flags &= ~RDF_NOWORLDMODEL; + else + r_refdef.flags |= RDF_NOWORLDMODEL; + r_refdef.fovv_x = r_refdef.fov_x = scene->fov[0]; + r_refdef.fovv_y = r_refdef.fov_y = scene->fov[1]; + r_refdef.vrect.x = scene->pos[0]; + r_refdef.vrect.y = scene->pos[1]; + r_refdef.vrect.width = scene->size[0]; + r_refdef.vrect.height = scene->size[1]; + r_refdef.time = scene->time; + r_refdef.useperspective = true; + r_refdef.mindist = bound(0.1, gl_mindist.value, 4); + r_refdef.maxdist = gl_maxdist.value; + r_refdef.playerview = &cl.playerview[0]; + + memset(&r_refdef.globalfog, 0, sizeof(r_refdef.globalfog)); + r_refdef.areabitsknown = false; + + R_RenderView(); + r_refdef.playerview = NULL; + r_refdef.time = 0; +} + void MN_Shutdown(void) { Key_Dest_Remove(kdm_nmenu); if (mn_entry) { - mn_entry->Shutdown(); + mn_entry->Shutdown(MI_INIT); mn_entry = NULL; } if (libmenu) @@ -182,19 +315,24 @@ qboolean MN_Init(void) static menu_import_t imports = { NATIVEMENU_API_VERSION_MAX, + NULL, - MN_checkextension, + MN_CheckExtension, Host_Error, Con_Printf, Con_DPrintf, - MN_localcmd, + MN_LocalCmd, Cvar_VariableValue, - Cvar_VariableString, + MN_Cvar_String, + MN_Cvar_GetDefault, Cvar_SetNamed, - MN_registercvar, + MN_RegisterCvar, + MN_RegisterCommand, - MN_getserverstate, - MN_getclientstate, + COM_ParseType, + + MN_GetServerState, + MN_GetClientState, S_LocalSound2, // file input / search crap @@ -204,25 +342,37 @@ qboolean MN_Init(void) VFS_PRINTF, COM_EnumerateFiles, - // Drawing stuff - MN_precache_pic, - MN_drawgetimagesize, - MN_drawquad, - MN_drawstring, - MN_stringwidth, - MN_drawsetcliparea, - MN_drawresetcliparea, + // Drawing stuff + MN_DrawSetClipArea, + MN_DrawResetClipArea, + + //pics + MN_CachePic, + MN_DrawGetImageSize, + MN_DrawQuad, + + //strings + MN_DrawString, + MN_StringWidth, + Font_LoadFont, + Font_Free, + + //3d stuff + MN_CacheModel, + MN_GetModelSize, + MN_RenderScene, // Menu specific stuff - MN_setkeydest, - MN_getkeydest, - MN_setmousetarget, + MN_SetKeyDest, + MN_GetKeyDest, + MN_SetMouseTarget, Key_KeynumToString, Key_StringToKeynum, M_FindKeysForBind, // Server browser stuff - NULL,//MN_gethostcachevalue, + Master_KeyForName, + Master_SortedServer, Master_ReadKeyString, Master_ReadKeyFloat, @@ -231,10 +381,8 @@ qboolean MN_Init(void) Master_SetMaskInteger, Master_SetSortField, Master_SortServers, - Master_SortedServer, MasterInfo_Refresh, - - Master_KeyForName, + CL_QueryServers, }; dllfunction_t funcs[] = { @@ -266,12 +414,14 @@ qboolean MN_Init(void) if (libmenu) { + imports.engine_version = version_string(); + key_dest_absolutemouse |= kdm_nmenu; mn_entry = pGetMenuAPI (&imports); if (mn_entry && mn_entry->api_version >= NATIVEMENU_API_VERSION_MIN && mn_entry->api_version <= NATIVEMENU_API_VERSION_MAX) { - mn_entry->Init(); + mn_entry->Init(0, vid.width, vid.height, vid.pixelwidth, vid.pixelheight); return true; } else diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 3bd4c0e6e..444978874 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -3041,6 +3041,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ shader_t *shader; vec2_t fs = {8,8}; // float bones[12*MAX_BONES]; + vec3_t lightpos = {0, 1, 0}; modelview_t *mods = c->dptr; @@ -3077,6 +3078,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ ent.scale = 1; // ent.angles[1] = realtime*45;//mods->yaw; // ent.angles[0] = realtime*23.4;//mods->pitch; + + ent.angles[0]*=r_meshpitch.value; + AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]); + ent.angles[0]*=r_meshpitch.value; + VectorInverse(ent.axis[1]); + ent.model = Mod_ForName(mods->modelname, MLV_WARN); if (!ent.model) return; //panic! @@ -3104,15 +3111,35 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66; ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33; - ent.light_dir[0] = 0; ent.light_dir[1] = 1; ent.light_dir[2] = 0; + + V_ApplyRefdef(); +/* + { + trace_t tr; + vec3_t worldmouse; + vec3_t mouse = {mousecursor_x/vid.width, 1-mousecursor_y/vid.height, 0.5}; + float d; + Matrix4x4_CM_UnProject(mouse, worldmouse, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y); + + d = DotProduct(worldmouse, fwd); + VectorMA(worldmouse, -d, fwd, worldmouse); + + if (ent.model->funcs.NativeTrace && ent.model->funcs.NativeTrace(ent.model, 0, &ent.framestate, ent.axis, r_refdef.vieworg, worldmouse, vec3_origin, vec3_origin, false, ~0, &tr)) + ; + else + VectorCopy(worldmouse, tr.endpos); + + VectorCopy(tr.endpos, lightpos); + } +*/ + + VectorNormalize(lightpos); + ent.light_dir[0] = DotProduct(lightpos, ent.axis[0]); + ent.light_dir[1] = DotProduct(lightpos, ent.axis[1]); + ent.light_dir[2] = DotProduct(lightpos, ent.axis[2]); + ent.light_known = 2; - - ent.angles[0]*=r_meshpitch.value; - AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]); - ent.angles[0]*=r_meshpitch.value; - VectorInverse(ent.axis[1]); - if (ent.model->type == mod_dummy) { Draw_FunString(0, 0, va("model \"%s\" not loaded", ent.model->name)); @@ -3296,7 +3323,6 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ V_AddEntity(&ent); - V_ApplyRefdef(); R_RenderView(); y = 0; @@ -3477,8 +3503,8 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k if (key == 'w') { mods->dist *= 0.9; - if (mods->dist < 5) - mods->dist = 5; + if (mods->dist < 1) + mods->dist = 1; } else if (key == 's') mods->dist /= 0.9; diff --git a/engine/client/menu.h b/engine/client/menu.h index 6e6f11fb2..5b6b9e675 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -484,7 +484,7 @@ qboolean MP_ConsoleCommand(const char *cmdtext); #endif #ifdef MENU_NATIVECODE -#include "../native/api_menu.h" +#include "api_menu.h" extern menu_export_t *mn_entry; void MN_Shutdown(void); qboolean MN_Init(void); diff --git a/engine/client/merged.h b/engine/client/merged.h index afed70a2e..769e74198 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -104,7 +104,7 @@ void R2D_ConsoleBackground (int firstline, int lastline, qboolean forceopaque); void R2D_EditorBackground (void); void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, mpic_t *pic); -void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic); +void R2D_Image2dQuad(vec2_t const*points, vec2_t const*texcoords, mpic_t *pic); void R2D_ImageColours(float r, float g, float b, float a); void R2D_ImagePaletteColour(unsigned int i, float a); diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 1d78e4327..9239311c0 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -67,9 +67,6 @@ extern cvar_t sv_listen_qw; extern cvar_t sv_listen_nq; extern cvar_t sv_listen_dp; extern cvar_t sv_listen_q3; -#ifdef HAVE_DTLS -extern cvar_t sv_listen_dtls; -#endif typedef struct { enum masterprotocol_e protocol; diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 7b478288b..8a80da867 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -218,7 +218,7 @@ void PR_ReloadFonts(qboolean reload) { //otherwise load it. for (j = 0; j < fontslot[i].sizes; j++) { - fontslot[i].font[j] = Font_LoadFont(fontslot[i].size[j], fontslot[i].facename); + fontslot[i].font[j] = Font_LoadFont(fontslot[i].facename, fontslot[i].size[j]); } } } @@ -285,7 +285,7 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (qrenderer == QR_NONE) fontslot[slotnum].font[i] = NULL; else - fontslot[slotnum].font[i] = Font_LoadFont(fontslot[slotnum].size[i], facename); + fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i]); fontslot[slotnum].sizes++; } } @@ -395,7 +395,7 @@ void CL_LoadFont_f(void) if (qrenderer == QR_NONE) fontslot[slotnum].font[i] = NULL; else - fontslot[slotnum].font[i] = Font_LoadFont(fontslot[slotnum].size[i], facename); + fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i]); fontslot[slotnum].sizes++; } } diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index f26135753..262076c1a 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -662,7 +662,7 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, draw_mesh.numvertexes += 4; draw_mesh.numindexes += 6; } -void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic) +void R2D_Image2dQuad(vec2_t const*points, vec2_t const*texcoords, mpic_t *pic) { int i; if (!pic) @@ -1061,9 +1061,9 @@ void R2D_Font_Changed(void) LOGFONTW lf = {0}; CHOOSEFONTW cf = {sizeof(cf)}; extern HWND mainwindow; - font_default = Font_LoadFont(8, ""); + font_default = Font_LoadFont("", 8); if (tsize != 8) - font_console = Font_LoadFont(tsize, ""); + font_console = Font_LoadFont("", tsize); if (!font_console) font_console = font_default; @@ -1102,18 +1102,27 @@ void R2D_Font_Changed(void) } #endif - font_default = Font_LoadFont(8, gl_font.string); + font_default = Font_LoadFont(gl_font.string, 8); if (!font_default && *gl_font.string) - font_default = Font_LoadFont(8, ""); + font_default = Font_LoadFont("", 8); if (tsize != 8) { - font_console = Font_LoadFont(tsize, gl_font.string); + font_console = Font_LoadFont(gl_font.string, tsize); if (!font_console) - font_console = Font_LoadFont(tsize, ""); + font_console = Font_LoadFont("", tsize); } if (!font_console) font_console = font_default; + + //these are here instead of R2D_Console_Resize because this is guarenteed to happen in a sane place, while R2D_Console_Resize can happen during waits. +#ifdef MENU_NATIVECODE + if (mn_entry) + mn_entry->Init(MI_RESOLUTION, vid.width, vid.height, vid.rotpixelwidth, vid.rotpixelheight); +#endif +#ifdef PLUGINS + Plug_ResChanged(); +#endif } static void QDECL R2D_Font_Callback(struct cvar_s *var, char *oldvalue) @@ -1210,10 +1219,6 @@ void R2D_Console_Resize(void) vid.height = cheight; Cvar_ForceCallback(&gl_font); - -#ifdef PLUGINS - Plug_ResChanged(); -#endif } static void QDECL R2D_Conheight_Callback(struct cvar_s *var, char *oldvalue) diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index a5faa8dfd..8d608b0b2 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -507,6 +507,7 @@ static void Surf_AddDynamicLightsColours (msurface_t *surf) rad = cl_dlights[lnum].radius; VectorSubtract(cl_dlights[lnum].origin, currententity->origin, lightofs); + //FIXME: transform by forward/right/up dist = DotProduct (lightofs, surf->plane->normal) - surf->plane->dist; rad -= fabs(dist); minlight = cl_dlights[lnum].minlight; diff --git a/engine/client/render.h b/engine/client/render.h index c0997de20..ab3a85060 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -361,6 +361,7 @@ typedef struct { qboolean modified; qboolean external; qboolean hasdeluxe; + uploadfmt_t fmt; int width; int height; glRect_t rectchange; @@ -443,7 +444,7 @@ enum imageflags image_t *Image_FindTexture (const char *identifier, const char *subpath, unsigned int flags); image_t *Image_CreateTexture(const char *identifier, const char *subpath, unsigned int flags); -image_t *Image_GetTexture (const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt); +image_t *QDECL Image_GetTexture (const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt); qboolean Image_UnloadTexture(image_t *tex); //true if it did something. void Image_DestroyTexture (image_t *tex); qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, char *fname, qbyte *filedata, int filesize); //intended really for worker threads, but should be fine from the main thread too diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 45f32147b..7ce2ef72b 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1290,6 +1290,11 @@ void D3DSucks(void) void R_ShutdownRenderer(qboolean devicetoo) { +#ifdef MENU_NATIVECODE + if (mn_entry) + mn_entry->Shutdown(MI_RENDERER); +#endif + //make sure the worker isn't still loading stuff COM_WorkerFullSync(); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index ec3da18bb..8c62f25ca 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -1222,7 +1222,7 @@ void Draw_TinyString (float x, float y, const qbyte *str) if (!font_tiny) { - font_tiny = Font_LoadFont(8, "gfx/tinyfont"); + font_tiny = Font_LoadFont("gfx/tinyfont", 8); if (!font_tiny) return; } diff --git a/engine/client/screen.h b/engine/client/screen.h index f8c712535..5435d4430 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -245,7 +245,7 @@ void Font_Init(void); void Font_Shutdown(void); int Font_RegisterTrackerImage(const char *image); //returns a unicode char value that can be used to embed the char within a line of text. qboolean Font_TrackerValid(unsigned int imid); -struct font_s *Font_LoadFont(float height, const char *fontfilename); +struct font_s *Font_LoadFont(const char *fontfilename, float height); void Font_Free(struct font_s *f); void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py); void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/ diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 8cff26c24..e46c670ba 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -1922,10 +1922,7 @@ static void QDECL S_EnumeratedOutDevice(const char *driver, const char *deviceco char nbuf[1024]; char dbuf[1024]; - if (devicecode && ( strchr(devicecode, ' ') || - strchr(devicecode, '\"'))) - fullintname = va("\"%s:%s\"", driver, devicecode); //it'll all get escaped anyway. but yeah, needs to be a single token or our multi-device stuff won't work properly. yes, this is a bit of a hack. - else if (devicecode) + if (devicecode) fullintname = va("%s:%s", driver, devicecode); else fullintname = driver; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index ba2bd7ec5..e4fa29797 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1151,25 +1151,16 @@ static void Cmd_AliasEdit_f (void) } #endif -void Cmd_DeleteAlias(char *name) +void Cmd_DeleteAlias(const char *name) { - cmdalias_t *a, *b; - if (!strcmp(cmd_alias->name, name)) + cmdalias_t *a, **link; + for (link = &cmd_alias; (a = *link); link = &(*link)->next) { - a = cmd_alias; - cmd_alias = cmd_alias->next; - Z_Free(a->value); - Z_Free(a); - return; - } - for (a = cmd_alias ; a ; a=a->next) - { - if (!strcmp(a->next->name, name)) + if (!strcmp(a->name, name)) { - b = a->next; - a->next = b->next; - Z_Free(b->value); - Z_Free(b); + *link = a->next; + Z_Free(a->value); + Z_Free(a); return; } } @@ -2732,6 +2723,10 @@ void Cmd_ExecuteString (const char *text, int level) #if defined(MENU_DAT) && !defined(SERVERONLY) if (MP_ConsoleCommand(text)) return; //let the csqc handle it if it wants. +#endif +#if defined(MENU_NATIVECODE) + if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, cmd_argv)) + return; #endif Cmd_ForwardToServer (); } @@ -2894,6 +2889,10 @@ void Cmd_ExecuteString (const char *text, int level) if (MP_ConsoleCommand(text)) return; //let the csqc handle it if it wants. #endif +#if defined(MENU_NATIVECODE) + if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, cmd_argv)) + return; +#endif #ifdef PLUGINS if (Plugin_ExecuteString()) @@ -3975,6 +3974,11 @@ void Cmd_WriteConfig_f(void) Key_WriteBindings (f); if (cfg_save_buttons.ival) IN_WriteButtons(f, all); + + #ifdef HAVE_CDPLAYER +// if (cfg_save_cdtracks.ival) + Media_SaveTracks(f); + #endif if (cfg_save_infos.ival) CL_SaveInfo(f); #else diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 09f3ffcd1..f6130b995 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -2027,7 +2027,12 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader) continue; #else if (!mod->numanimations) - continue; + { + if (mod->ofs_skel_xyz) + posedata = mod->ofs_skel_xyz; + else + continue; + } else { galiaspose_t *pose; diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 7acb3bfc0..5951d80c5 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -158,6 +158,7 @@ typedef struct galiasinfo_s //#ifndef SERVERONLY vec2_t *ofs_st_array; + vec2_t *ofs_lmst_array; vec4_t *ofs_rgbaf; byte_vec4_t *ofs_rgbaub; //#endif @@ -227,9 +228,16 @@ typedef struct modplugfuncs_s struct terrainfuncs_s *(QDECL *GetTerrainFuncs)(void); void *reserved2; + image_t *(QDECL *GetTexture)(const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt); + vfsfile_t *(QDECL *OpenVFS)(const char *filename, const char *mode, enum fs_relative relativeto); void *unused3; void *unused4; void *unused5; + void *unused6; + void *unused7; + void *unused8; + void *unused9; + void *unused10; } modplugfuncs_t; #define MODPLUGFUNCS_VERSION 2 diff --git a/engine/common/common.h b/engine/common/common.h index 4081f664c..8590dae11 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -365,8 +365,6 @@ extern char com_token[65536]; typedef enum {TTP_UNKNOWN, TTP_STRING, TTP_LINEENDING, TTP_RAWTOKEN, TTP_EOF, TTP_PUNCTUATION} com_tokentype_t; extern com_tokentype_t com_tokentype; -extern qboolean com_eof; - //these cast away the const for the return value. //char *COM_Parse (const char *data); #define COM_Parse(d) COM_ParseOut(d,com_token, sizeof(com_token)) @@ -587,7 +585,7 @@ qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relative qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto); void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize); -vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto); +vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto); vfsfile_t *FS_OpenTemp(void); vfsfile_t *FS_OpenTCP(const char *name, int defaultport); diff --git a/engine/common/fs.c b/engine/common/fs.c index 5b960a88e..506cb80b9 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -795,7 +795,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void Q_snprintfz(link, sizeof(link), "\\tip\\Change Map\\map\\%s", name+5); colour = "^4"; //disconnects } - else if (!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "spr") || !Q_strcasecmp(link, "mdl") || !Q_strcasecmp(link, "md3") || !Q_strcasecmp(link, "iqm") || !Q_strcasecmp(link, "vvm") || !Q_strcasecmp(link, "psk") || !Q_strcasecmp(link, "dpm") || !Q_strcasecmp(link, "zym") || !Q_strcasecmp(link, "md5mesh") || !Q_strcasecmp(link, "md5anim")) + else if (!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "spr") || !Q_strcasecmp(link, "mdl") || !Q_strcasecmp(link, "md3") || !Q_strcasecmp(link, "iqm") || !Q_strcasecmp(link, "vvm") || !Q_strcasecmp(link, "psk") || !Q_strcasecmp(link, "dpm") || !Q_strcasecmp(link, "zym") || !Q_strcasecmp(link, "md5mesh") || !Q_strcasecmp(link, "md5anim") || !Q_strcasecmp(link, "gltf") || !Q_strcasecmp(link, "glb") || !Q_strcasecmp(link, "ase") || !Q_strcasecmp(link, "lwo")) Q_snprintfz(link, sizeof(link), "\\tip\\Open in Model Viewer\\modelviewer\\%s", name); else if (!Q_strcasecmp(link, "qc") || !Q_strcasecmp(link, "src") || !Q_strcasecmp(link, "qh") || !Q_strcasecmp(link, "h") || !Q_strcasecmp(link, "c") || !Q_strcasecmp(link, "cfg") || !Q_strcasecmp(link, "rc") @@ -804,7 +804,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void || !Q_strcasecmp(link, "glsl") || !Q_strcasecmp(link, "hlsl") || !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups")) Q_snprintfz(link, sizeof(link), "\\tip\\Open in Text Editor\\edit\\%s", name); - else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx") || !Q_strcasecmp(link, "bmp") || !Q_strcasecmp(link, "dds")) + else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx") || !Q_strcasecmp(link, "bmp") || !Q_strcasecmp(link, "dds") || !Q_strcasecmp(link, "ktx")) { //FIXME: image replacements are getting in the way here. Q_snprintfz(link, sizeof(link), "\\tiprawimg\\%s\\tip\\(note: image replacement rules are context-dependant, including base path, sub path, extension, or complete replacement via a shader)", name); @@ -1882,7 +1882,7 @@ a = append t = text mode (because windows sucks). binary is otherwise assumed. p = persist (ie: saved games and configs, but not downloads or large content) */ -vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto) +vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto) { char cleanname[MAX_QPATH]; char fullname[MAX_OSPATH]; diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index d95a57cd6..ba04af2c0 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -98,9 +98,9 @@ cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless."); cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command."); cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port."); -cvar_t net_enable_http = CVARD("net_enable_http", "1", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay."); +cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay."); cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients."); -cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "1", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections."); +cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections."); #endif #if defined(HAVE_DTLS) && !defined(CLIENTONLY) static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue) diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 193367932..1aed5b013 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -450,14 +450,10 @@ void GLDraw_Init (void) TRACE(("dbg: GLDraw_ReInit: PPL_LoadSpecularFragmentProgram\n")); GL_InitSceneProcessingShaders(); - -// Cmd_AddCommandD ("r_imagelist", GLDraw_ImageList_f, "Debug command. Reveals current list of loaded images."); } void GLDraw_DeInit (void) { - Cmd_RemoveCommand ("r_imagelist"); - R2D_Shutdown(); R_GAliasFlushSkinCache(true); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 8fd573307..f01ca011f 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -15,7 +15,7 @@ void Font_Init(void); void Font_Shutdown(void); -struct font_s *Font_LoadFont(float height, const char *fontfilename); +struct font_s *Font_LoadFont(const char *fontfilename, float height); void Font_Free(struct font_s *f); void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py); void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/ @@ -1769,7 +1769,7 @@ void Doom_ExpandPatch(doompatch_t *p, unsigned char *b, int stride) //creates a new font object from the given file, with each text row with the given height. //width is implicit and scales with height and choice of font. -struct font_s *Font_LoadFont(float vheight, const char *fontfilename) +struct font_s *Font_LoadFont(const char *fontfilename, float vheight) { struct font_s *f; int i = 0; @@ -1779,6 +1779,7 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) int height = ((vheight * vid.rotpixelheight)/vid.height) + 0.5; char facename[MAX_QPATH]; struct charcache_s *c; + float aspect = 1; enum { FMT_AUTO, //freetype, or quake @@ -1845,6 +1846,12 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) else if (*t == 'h') fmt = FMT_HORIZONTAL; } + if (!strncmp(parms, "aspect=", 7)) + { + char *t = parms+7; + aspect = strtod(t, &t); + parms = t; + } while(*parms && *parms != '&') parms++; @@ -2011,7 +2018,7 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) } else { - f->alt = Font_LoadFont(vheight, aname); + f->alt = Font_LoadFont(aname, vheight); if (f->alt) { VectorCopy(f->alt->tint, f->alttint); @@ -2158,7 +2165,7 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) else c = Font_GetCharStore(f, i); - c->advance = f->charheight; + c->advance = f->charheight * aspect; c->bmh = PLANEWIDTH/16; c->bmw = PLANEWIDTH/16; c->bmx = (i&15)*(PLANEWIDTH/16); @@ -2176,7 +2183,7 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) for (i = 0xe000; i <= 0xe0ff; i++) { c = Font_GetCharStore(f, i); - c->advance = f->charheight; + c->advance = f->charheight * aspect; c->bmh = PLANEWIDTH/16; c->bmw = PLANEWIDTH/16; c->bmx = ((i&15))*(PLANEWIDTH/16); @@ -2197,6 +2204,9 @@ void Font_Free(struct font_s *f) size_t i; struct charcache_s **link, *c, *valid; + if (!f) + return; + //kill the alt font first. if (f->alt) { @@ -2744,14 +2754,14 @@ int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint case DEFAULTPLANE: sx = ((px+c->left + dxbias)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top + dxbias)*(int)vid.height) / (float)vid.rotpixelheight; - sw = ((font->charheight)*vid.width) / (float)vid.rotpixelwidth; + sw = ((c->advance)*vid.width) / (float)vid.rotpixelwidth; sh = ((font->charheight)*vid.height) / (float)vid.rotpixelheight; v = Font_BeginChar(fontplanes.defaultfont); break; case BITMAPPLANE: sx = ((px+c->left + dxbias)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top + dxbias)*(int)vid.height) / (float)vid.rotpixelheight; - sw = ((font->charheight)*vid.width) / (float)vid.rotpixelwidth; + sw = ((c->advance)*vid.width) / (float)vid.rotpixelwidth; sh = ((font->charheight)*vid.height) / (float)vid.rotpixelheight; v = Font_BeginChar(font->singletexture); break; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 12408d29c..240f96f44 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1346,12 +1346,22 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b) magic = 0; else magic = LittleLong(*(unsigned *)buf); - for(i = 0; i < sizeof(modelloaders) / sizeof(modelloaders[0]); i++) + //look for known extensions first, to try to avoid issues with specific formats + for(i = 0; i < countof(modelloaders); i++) { - if (modelloaders[i].load && modelloaders[i].magic == magic && !modelloaders[i].ident) + if (modelloaders[i].load && modelloaders[i].ident && *modelloaders[i].ident == '.' && !Q_strcasecmp(modelloaders[i].ident+1, ext)) break; } - if (i < sizeof(modelloaders) / sizeof(modelloaders[0])) + //now look to see if we can find one with the right magic header + if (i == countof(modelloaders)) + { + for(i = 0; i < countof(modelloaders); i++) + { + if (modelloaders[i].load && modelloaders[i].magic == magic && !modelloaders[i].ident) + break; + } + } + if (i < countof(modelloaders)) { if (!modelloaders[i].load(mod, buf, filesize)) { @@ -5037,7 +5047,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi { struct vispatch_s vispatch; int i, j; - dheader_t *header; + dheader_t header; mmodel_t *bm; model_t *submod; unsigned int chksum; @@ -5048,11 +5058,22 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi qboolean hexen2map = false; qboolean isnotmap; qboolean using_rbe = true; + qboolean misaligned = false; COM_FileBase (mod->name, loadname, sizeof(loadname)); mod->type = mod_brush; - header = (dheader_t *)buffer; + if (fsize < sizeof(header)) + return false; + + mod_base = (qbyte *)buffer; + memcpy(&header, mod_base, sizeof(header)); + header.version = LittleLong(header.version); + for (i=0 ; iversion); - - if (i == BSPVERSION || i == BSPVERSIONPREREL) + switch(header.version) { + case BSPVERSION: + case BSPVERSIONPREREL: mod->fromgame = fg_quake; mod->engineflags |= MDLF_NEEDOVERBRIGHT; - } - else if (i == BSPVERSION_LONG1) - { + break; + case BSPVERSION_LONG1: longm = true; mod->fromgame = fg_quake; mod->engineflags |= MDLF_NEEDOVERBRIGHT; - } - else if (i == BSPVERSION_LONG2) - { + break; + case BSPVERSION_LONG2: longm = 2; mod->fromgame = fg_quake; mod->engineflags |= MDLF_NEEDOVERBRIGHT; - } - else if (i == BSPVERSIONHL) //halflife support + break; + case BSPVERSIONHL: //halflife support mod->fromgame = fg_halflife; - else - { + break; + default: Con_Printf (CON_ERROR "Mod_LoadBrushModel: %s has wrong version number (%i should be %i)\n", mod->name, i, BSPVERSION); return false; } @@ -5097,28 +5116,23 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi mod->lightmaps.width = 128;//LMBLOCK_WIDTH; mod->lightmaps.height = 128;//LMBLOCK_HEIGHT; -// swap all the lumps - mod_base = (qbyte *)header; - - for (i=0 ; ilumps, HEADER_LUMPS); - // checksum all of the map, except for entities mod->checksum = 0; mod->checksum2 = 0; for (i = 0; i < HEADER_LUMPS; i++) { - if ((unsigned)header->lumps[i].fileofs + (unsigned)header->lumps[i].filelen > fsize) + if ((header.lumps[i].fileofs & 3) && header.lumps[i].filelen) + misaligned = true; + + if ((unsigned)header.lumps[i].fileofs + (unsigned)header.lumps[i].filelen > fsize) { Con_Printf (CON_ERROR "Mod_LoadBrushModel: %s appears truncated\n", mod->name); return false; } if (i == LUMP_ENTITIES) continue; - chksum = Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + chksum = Com_BlockChecksum(mod_base + header.lumps[i].fileofs, header.lumps[i].filelen); mod->checksum ^= chksum; if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES) @@ -5126,13 +5140,39 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi mod->checksum2 ^= chksum; } - if (1)//mod_ebfs.value) + if (misaligned) + { //pre-phong versions of tyrutils wrote misaligned lumps. These crash on arm/etc. + char *tmp; + int ofs = 0; + Con_Printf(CON_WARNING"%s: Misaligned lumps detected\n", mod->name); + tmp = BZ_Malloc(fsize); + memcpy(tmp, mod_base, fsize); + for (i = 0; i < HEADER_LUMPS; i++) + { + if (ofs + header.lumps[i].filelen > fsize) + { //can happen if two lumps overlap... otherwise impossible. + Con_Printf(CON_ERROR"%s: Realignment failed\n", mod->name); + BZ_Free(tmp); + return false; + } + memcpy(mod_base + ofs, tmp+header.lumps[i].fileofs, header.lumps[i].filelen); + header.lumps[i].fileofs = ofs; + ofs += header.lumps[i].filelen; + } + BZ_Free(tmp); + } + else { - char *id; - id = (char *)(header + 1); - if (id[0]=='P' && id[1]=='A' && id[2]=='C' && id[3]=='K') - { //EBFS detected. - COM_LoadMapPackFile(mod->name, sizeof(dheader_t)); + Q1BSPX_Setup(mod, mod_base, fsize, header.lumps, HEADER_LUMPS); + + if (1)//mod_ebfs.value) + { + char *id; + id = (char *)mod_base + sizeof(dheader_t); + if (id[0]=='P' && id[1]=='A' && id[2]=='C' && id[3]=='K') + { //EBFS detected. + COM_LoadMapPackFile(mod->name, sizeof(dheader_t)); + } } } @@ -5140,56 +5180,56 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi crouchhullfile = NULL; - Mod_FindVisPatch(&vispatch, mod, header->lumps[LUMP_LEAFS].filelen); + Mod_FindVisPatch(&vispatch, mod, header.lumps[LUMP_LEAFS].filelen); // load into heap if (!isDedicated || using_rbe) { TRACE(("Loading verts\n")); - noerrors = noerrors && Mod_LoadVertexes (mod, mod_base, &header->lumps[LUMP_VERTEXES]); + noerrors = noerrors && Mod_LoadVertexes (mod, mod_base, &header.lumps[LUMP_VERTEXES]); TRACE(("Loading edges\n")); - noerrors = noerrors && Mod_LoadEdges (mod, mod_base, &header->lumps[LUMP_EDGES], longm); + noerrors = noerrors && Mod_LoadEdges (mod, mod_base, &header.lumps[LUMP_EDGES], longm); TRACE(("Loading Surfedges\n")); - noerrors = noerrors && Mod_LoadSurfedges (mod, mod_base, &header->lumps[LUMP_SURFEDGES]); + noerrors = noerrors && Mod_LoadSurfedges (mod, mod_base, &header.lumps[LUMP_SURFEDGES]); } if (!isDedicated) { TRACE(("Loading Textures\n")); - noerrors = noerrors && Mod_LoadTextures (mod, mod_base, &header->lumps[LUMP_TEXTURES]); + noerrors = noerrors && Mod_LoadTextures (mod, mod_base, &header.lumps[LUMP_TEXTURES]); } TRACE(("Loading Submodels\n")); - noerrors = noerrors && Mod_LoadSubmodels (mod, mod_base, &header->lumps[LUMP_MODELS], &hexen2map); + noerrors = noerrors && Mod_LoadSubmodels (mod, mod_base, &header.lumps[LUMP_MODELS], &hexen2map); if (noerrors) { TRACE(("Loading CH\n")); Mod_LoadCrouchHull(mod); } TRACE(("Loading Planes\n")); - noerrors = noerrors && Mod_LoadPlanes (mod, mod_base, &header->lumps[LUMP_PLANES]); + noerrors = noerrors && Mod_LoadPlanes (mod, mod_base, &header.lumps[LUMP_PLANES]); TRACE(("Loading Entities\n")); - Mod_LoadEntities (mod, mod_base, &header->lumps[LUMP_ENTITIES]); + Mod_LoadEntities (mod, mod_base, &header.lumps[LUMP_ENTITIES]); if (!isDedicated || using_rbe) { TRACE(("Loading Texinfo\n")); - noerrors = noerrors && Mod_LoadTexinfo (mod, mod_base, &header->lumps[LUMP_TEXINFO]); + noerrors = noerrors && Mod_LoadTexinfo (mod, mod_base, &header.lumps[LUMP_TEXINFO]); TRACE(("Loading Faces\n")); - noerrors = noerrors && Mod_LoadFaces (mod, mod_base, &header->lumps[LUMP_FACES], &header->lumps[LUMP_LIGHTING], longm); + noerrors = noerrors && Mod_LoadFaces (mod, mod_base, &header.lumps[LUMP_FACES], &header.lumps[LUMP_LIGHTING], longm); } if (!isDedicated) { TRACE(("Loading MarkSurfaces\n")); - noerrors = noerrors && Mod_LoadMarksurfaces (mod, mod_base, &header->lumps[LUMP_MARKSURFACES], longm); + noerrors = noerrors && Mod_LoadMarksurfaces (mod, mod_base, &header.lumps[LUMP_MARKSURFACES], longm); } if (noerrors) { TRACE(("Loading Vis\n")); - Mod_LoadVisibility (mod, mod_base, &header->lumps[LUMP_VISIBILITY], vispatch.visptr, vispatch.vislen); + Mod_LoadVisibility (mod, mod_base, &header.lumps[LUMP_VISIBILITY], vispatch.visptr, vispatch.vislen); } - noerrors = noerrors && Mod_LoadLeafs (mod, mod_base, &header->lumps[LUMP_LEAFS], longm, isnotmap, vispatch.leafptr, vispatch.leaflen); + noerrors = noerrors && Mod_LoadLeafs (mod, mod_base, &header.lumps[LUMP_LEAFS], longm, isnotmap, vispatch.leafptr, vispatch.leaflen); TRACE(("Loading Nodes\n")); - noerrors = noerrors && Mod_LoadNodes (mod, mod_base, &header->lumps[LUMP_NODES], longm); + noerrors = noerrors && Mod_LoadNodes (mod, mod_base, &header.lumps[LUMP_NODES], longm); TRACE(("Loading Clipnodes\n")); - noerrors = noerrors && Mod_LoadClipnodes (mod, mod_base, &header->lumps[LUMP_CLIPNODES], longm, hexen2map); + noerrors = noerrors && Mod_LoadClipnodes (mod, mod_base, &header.lumps[LUMP_CLIPNODES], longm, hexen2map); if (noerrors) { TRACE(("Loading hull 0\n")); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 646124b4e..4a67f4d37 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1935,7 +1935,7 @@ void GLR_RenderView (void) } if (dofbo) forcedfb = false; - else if (r_renderscale.value != 1) + else if (renderscale != 1) forcedfb = true; BE_Scissor(NULL); diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index 59a3657b4..67a584d65 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -68,7 +68,7 @@ vfsfile_t *IWebGenerateFile(const char *name, const char *content, int contentle return NULL; } vfsfile_t *VFSSTDIO_Open(const char *osname, const char *mode, qboolean *needsflush); -vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto) +vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto) { return VFSSTDIO_Open(filename, mode, NULL); } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index b8b2cb18c..b470f13f3 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -45,6 +45,7 @@ extern cvar_t sv_csqcdebug; extern cvar_t sv_csqc_progname; extern cvar_t sv_calcphs; extern cvar_t sv_playerslots, maxclients, maxspectators; +extern cvar_t sv_nqplayerphysics; //auto setting needs updating on map changes /* ================ @@ -1155,6 +1156,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, SV_UpdateMaxPlayers(0); } svs.gametype = newgametype; + Cvar_ForceCallback(&sv_nqplayerphysics); sv.models[1] = sv.world.worldmodel; #ifdef VM_Q1 diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index ceb09d770..795fb1562 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -34,6 +34,17 @@ edict_t *sv_player; usercmd_t cmd; +void QDECL SV_NQPhysicsUpdate(cvar_t *var, char *oldvalue) +{ + if (!strcmp(var->string, "auto")) + { //prediction requires nq physics, so use it by default in multiplayer. + if (progstype == PROG_QW || (!isDedicated && sv.allocated_client_slots > 1)) + var->ival = 1; + else + var->ival = 0; + } +} + extern cvar_t dpcompat_nopreparse; #ifdef SERVERONLY cvar_t cl_rollspeed = CVAR("cl_rollspeed", "200"); @@ -65,7 +76,7 @@ cvar_t cmd_allowaccess = CVAR("cmd_allowaccess", "0"); //set to 1 to allow cmd t cvar_t cmd_gamecodelevel = CVAR("cmd_gamecodelevel", STRINGIFY(RESTRICT_LOCAL)); //execution level which gamecode is told about (for unrecognised commands) cvar_t sv_pure = CVARFD("sv_pure", "", CVAR_SERVERINFO, "The most evil cvar in the world, many clients will ignore this.\n0=standard quake rules.\n1=clients should prefer files within packages present on the server.\n2=clients should use *only* files within packages present on the server.\nDue to quake 1.01/1.06 differences, a setting of 2 only works in total conversions."); -cvar_t sv_nqplayerphysics = CVARAD("sv_nqplayerphysics", "0", "sv_nomsec", "Disable player prediction and run NQ-style player physics instead. This can be used for compatibility with mods that expect exact behaviour."); +cvar_t sv_nqplayerphysics = CVARAFCD("sv_nqplayerphysics", "0", "sv_nomsec", 0, SV_NQPhysicsUpdate, "Disable player prediction and run NQ-style player physics instead. This can be used for compatibility with mods that expect exact behaviour."); cvar_t sv_edgefriction = CVARAF("sv_edgefriction", "2", "edgefriction", 0); diff --git a/plugins/qi/qi.c b/plugins/qi/qi.c index 59889f531..1f043a6bf 100644 --- a/plugins/qi/qi.c +++ b/plugins/qi/qi.c @@ -148,7 +148,7 @@ void QI_DeHTML(const char *in, char *out, size_t outsize) { //italics *out++ = '^'; outsize--; - *out++ = 'b'; + *out++ = close?'7':'3'; outsize--; } }