mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-25 13:21:36 +00:00
Eukara wants native-code custom menus. He's weird.
Try to clean up the frametime global. fix some quirks with r_dynamic -1 Added scr_fov_mode cvar to control whether the fov is defined relative to horizontal, vertical, or guessed. fix a few fteqcc bugs tab completion for the gamedir command. fix the savegame_legacy command. it wasn't entirely compatible. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5254 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
6ee709e6d7
commit
5e937bcf48
40 changed files with 1157 additions and 279 deletions
|
@ -324,6 +324,7 @@ ADD_EXECUTABLE(fteqw WIN32
|
|||
engine/client/m_multi.c
|
||||
engine/client/m_options.c
|
||||
engine/client/m_script.c
|
||||
engine/client/m_native.c
|
||||
engine/client/m_single.c
|
||||
engine/client/menu.c
|
||||
engine/client/p_classic.c
|
||||
|
|
|
@ -599,6 +599,7 @@ CLIENT_OBJS = \
|
|||
m_options.o \
|
||||
m_single.o \
|
||||
m_script.o \
|
||||
m_native.o \
|
||||
m_mp3.o \
|
||||
roq_read.o \
|
||||
clq2_cin.o \
|
||||
|
|
157
engine/client/api_menu.h
Normal file
157
engine/client/api_menu.h
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2018
|
||||
* Marco Hladik All rights reserved.
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define NATIVEMENU_API_VERSION_MIN 0 //will be updated any time a symbol is renamed.
|
||||
#define NATIVEMENU_API_VERSION_MAX 0 //bumped for any change.
|
||||
#ifndef NATIVEMENU_API_VERSION //so you can hold back the reported version in order to work with older engines.
|
||||
#define NATIVEMENU_API_VERSION NATIVEMENU_API_VERSION_MAX //version reported to the other side.
|
||||
#endif
|
||||
|
||||
struct vfsfile_s;
|
||||
struct serverinfo_s;
|
||||
struct searchpathfuncs_s;
|
||||
enum slist_test_e;
|
||||
enum hostcachekey_e; //obtained via calls to gethostcacheindexforkey
|
||||
enum fs_relative;
|
||||
#ifndef __QUAKEDEF_H__
|
||||
#ifdef __cplusplus
|
||||
typedef enum {qfalse, qtrue} qboolean;//false and true are forcivly defined.
|
||||
#else
|
||||
typedef enum {false, true} qboolean;
|
||||
#endif
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
#ifdef _MSC_VER
|
||||
#define QDECL __cdecl
|
||||
#else
|
||||
#define QDECL
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint64_t qofs_t;
|
||||
#endif
|
||||
|
||||
struct menu_inputevent_args_s
|
||||
{
|
||||
enum {
|
||||
MIE_KEYDOWN = 0,
|
||||
MIE_KEYUP = 1,
|
||||
MIE_MOUSEDELTA = 2,
|
||||
MIE_MOUSEABS = 3,
|
||||
} eventtype;
|
||||
unsigned int devid;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int scancode;
|
||||
unsigned int charcode;
|
||||
} key;
|
||||
struct
|
||||
{
|
||||
float delta[2];
|
||||
float screen[2]; //virtual coords
|
||||
} mouse;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int api_version; //this may be higher than you expect.
|
||||
|
||||
int (*checkextension) (const char *ext);
|
||||
void (*error) (const char *err);
|
||||
void (*printf) (const char *text, ...);
|
||||
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.
|
||||
void (*cvar_set) (const char *name, const char *value);
|
||||
void (*registercvar) (const char *name, const char *defaultvalue, unsigned int flags, const char *description);
|
||||
|
||||
int (*isserver) (void);
|
||||
int (*getclientstate) (void);
|
||||
void (*localsound) (const char *sample, int channel, float volume);
|
||||
|
||||
// file input / search crap
|
||||
struct vfsfile_s *(*fopen) (const char *filename, char *modestring, enum fs_relative fsroot); //modestring should be one of rb,r+b,wb,w+b,ab,wbp. Mostly use a root of FS_GAMEONLY for writes, otherwise FS_GAME for reads.
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
// Menu specific stuff
|
||||
qboolean (*setkeydest) (qboolean focused); //returns whether it changed.
|
||||
int (*getkeydest) (void); //returns 0 if unfocused, -1 if active-but-unfocused, 1 if focused-and-active.
|
||||
int (*setmousetarget) (const char *cursorname, float hot_x, float hot_y, float scale); //forces absolute mouse coords whenever cursorname isn't NULL
|
||||
const char *(*keynumtostring) (int keynum, int modifier);
|
||||
int (*stringtokeynum) (const char *key, int *modifier);
|
||||
int (*findkeysforcommand) (int bindmap, const char *command, int *out_scancodes, int *out_modifiers, int keycount);
|
||||
|
||||
// Server browser stuff
|
||||
int (*gethostcachevalue) (int type);
|
||||
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 (*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);
|
||||
void (*refreshhostcache) (qboolean fullreset);
|
||||
enum hostcachekey_e (*gethostcacheindexforkey) (const char *key);
|
||||
} 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 (*Toggle) (int wantmode);
|
||||
int (*InputEvent) (struct menu_inputevent_args_s ev);
|
||||
void (*ConsoleCommand) (const char *cmd);
|
||||
} menu_export_t;
|
||||
|
||||
#ifndef NATIVEEXPORT
|
||||
#ifdef _WIN32
|
||||
#define NATIVEEXPORTPROTO QDECL
|
||||
#define NATIVEEXPORT __declspec(dllexport) NATIVEEXPORTPROTO
|
||||
#else
|
||||
#define NATIVEEXPORTPROTO
|
||||
#define NATIVEEXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
menu_export_t *NATIVEEXPORTPROTO GetMenuAPI (menu_import_t *import);
|
|
@ -4475,7 +4475,7 @@ Host_EndGame
|
|||
Call this to drop to a console without exiting the qwcl
|
||||
================
|
||||
*/
|
||||
NORETURN void VARGS Host_EndGame (char *message, ...)
|
||||
NORETURN void VARGS Host_EndGame (const char *message, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
@ -4510,7 +4510,7 @@ Host_Error
|
|||
This shuts down the client and exits qwcl
|
||||
================
|
||||
*/
|
||||
void VARGS Host_Error (char *error, ...)
|
||||
void VARGS Host_Error (const char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
@ -5581,6 +5581,7 @@ double Host_Frame (double time)
|
|||
#endif
|
||||
|
||||
cls.framecount++;
|
||||
cl.lasttime = cl.time;
|
||||
|
||||
RSpeedRemark();
|
||||
|
||||
|
@ -5799,9 +5800,7 @@ void CL_StartCinematicOrMenu(void)
|
|||
UI_Start();
|
||||
#endif
|
||||
|
||||
#ifdef MENU_DAT
|
||||
Cbuf_AddText("menu_restart\n", RESTRICT_LOCAL);
|
||||
#endif
|
||||
|
||||
Con_TPrintf ("^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081 %s %sInitialized ^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082\n", *fs_gamename.string?fs_gamename.string:"Nothing", com_installer?"Installer ":"");
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ enum mastertype_e
|
|||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
typedef enum hostcachekey_e
|
||||
{
|
||||
SLKEY_PING,
|
||||
SLKEY_MAP,
|
||||
|
@ -81,7 +81,7 @@ typedef enum
|
|||
SLKEY_CUSTOM = SLKEY_PLAYER0+MAX_CLIENTS
|
||||
} hostcachekey_t;
|
||||
|
||||
typedef enum
|
||||
typedef enum slist_test_e
|
||||
{
|
||||
SLIST_TEST_CONTAINS,
|
||||
SLIST_TEST_NOTCONTAIN,
|
||||
|
@ -226,11 +226,11 @@ void MasterInfo_Refresh(qboolean doreset);
|
|||
void Master_QueryServer(serverinfo_t *server);
|
||||
void MasterInfo_WriteServers(void);
|
||||
|
||||
int Master_KeyForName(const char *keyname);
|
||||
float Master_ReadKeyFloat(serverinfo_t *server, int keynum);
|
||||
char *Master_ReadKeyString(serverinfo_t *server, int keynum);
|
||||
hostcachekey_t Master_KeyForName(const char *keyname);
|
||||
float Master_ReadKeyFloat(serverinfo_t *server, hostcachekey_t keynum);
|
||||
char *Master_ReadKeyString(serverinfo_t *server, hostcachekey_t keynum);
|
||||
|
||||
void Master_SortServers(void);
|
||||
int Master_SortServers(void);
|
||||
void Master_SetSortField(hostcachekey_t field, qboolean descending);
|
||||
hostcachekey_t Master_GetSortField(void);
|
||||
qboolean Master_GetSortDescending(void);
|
||||
|
|
|
@ -955,6 +955,10 @@ void SCR_DrawCursor(void)
|
|||
cmod = kc_console;
|
||||
else if ((key_dest_mask & key_dest_absolutemouse & kdm_gmenu))
|
||||
cmod = kc_menu;
|
||||
#ifdef MENU_NATIVECODE
|
||||
else if ((key_dest_mask & key_dest_absolutemouse & kdm_nmenu))
|
||||
cmod = kc_nmenu;
|
||||
#endif
|
||||
else// if (key_dest_mask & key_dest_absolutemouse)
|
||||
cmod = prydoncursornum?kc_console:kc_game;
|
||||
|
||||
|
@ -1892,6 +1896,13 @@ void SCR_DrawLoading (qboolean opaque)
|
|||
return; //menuqc should have just drawn whatever overlays it wanted.
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (mn_entry && mn_entry->DrawLoading)
|
||||
{
|
||||
mn_entry->DrawLoading(vid.width, vid.height, host_frametime);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
//int mtype = M_GameType(); //unused variable
|
||||
y = vid.height/2;
|
||||
|
@ -3383,6 +3394,10 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
|
|||
|
||||
#ifdef MENU_DAT
|
||||
MP_Draw();
|
||||
#endif
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (mn_entry)
|
||||
mn_entry->Draw(vid.width, vid.height, host_frametime);
|
||||
#endif
|
||||
M_Draw (uimenu);
|
||||
|
||||
|
|
|
@ -808,6 +808,7 @@ typedef struct
|
|||
// the client simulates or interpolates movement to get these values
|
||||
double time; // this is the time value that the client
|
||||
// is rendering at. always <= realtime
|
||||
double lasttime; //cl.time from last frame.
|
||||
|
||||
float servertime; //current server time, bound between gametime and gametimemark
|
||||
float mtime; //server time as on the server when we last received a packet. not allowed to decrease.
|
||||
|
|
|
@ -704,24 +704,57 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
|
|||
{ //many mods assume only a single mouse device.
|
||||
//when we have multiple active abs devices, we need to avoid sending all of them, because that just confuses everyone. such mods will see only devices that are actually moving, so uni-cursor mods will see only the one that moved most recently.
|
||||
mouse->updated = false;
|
||||
#ifdef MENU_DAT
|
||||
if (!runningindepphys && MP_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
|
||||
if (!runningindepphys)
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
}
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (mn_entry)
|
||||
{
|
||||
struct menu_inputevent_args_s ev = {MIE_MOUSEABS, mouse->qdeviceid};
|
||||
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;
|
||||
if (mn_entry->InputEvent(ev))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (MP_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef CSQC_DAT
|
||||
if (!runningindepphys && CSQC_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
}
|
||||
if (!runningindepphys && CSQC_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (mn_entry && Key_Dest_Has(kdm_nmenu) && (mx || my))
|
||||
{
|
||||
struct menu_inputevent_args_s ev = {MIE_MOUSEABS, mouse->qdeviceid};
|
||||
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;
|
||||
if (mn_entry->InputEvent(ev))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (Key_Dest_Has(kdm_gmenu))
|
||||
if (mx || my)
|
||||
|
|
|
@ -2636,6 +2636,15 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
|
|||
#ifdef MENU_DAT
|
||||
if (Key_Dest_Has(kdm_gmenu) && !Key_Dest_Has(kdm_editor|kdm_console|kdm_cwindows))
|
||||
MP_Keyup (key, unicode, devid);
|
||||
#endif
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (mn_entry)
|
||||
{
|
||||
struct menu_inputevent_args_s ev = {MIE_KEYUP, devid};
|
||||
ev.key.scancode = key;
|
||||
ev.key.charcode = unicode;
|
||||
mn_entry->InputEvent(ev);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -2659,6 +2668,18 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
|
|||
#endif
|
||||
else if (Key_Dest_Has(kdm_emenu))
|
||||
M_Keydown (key, unicode);
|
||||
#ifdef MENU_NATIVECODE
|
||||
else if (Key_Dest_Has(kdm_nmenu))
|
||||
{
|
||||
if (mn_entry)
|
||||
{
|
||||
struct menu_inputevent_args_s ev = {MIE_KEYDOWN, devid};
|
||||
ev.key.scancode = key;
|
||||
ev.key.charcode = unicode;
|
||||
mn_entry->InputEvent(ev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
else if (Key_Dest_Has(kdm_gmenu))
|
||||
MP_Keydown (key, unicode, devid);
|
||||
|
@ -2709,6 +2730,15 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
|
|||
}
|
||||
if (Key_Dest_Has(kdm_emenu))
|
||||
M_Keyup (key, unicode);
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (Key_Dest_Has(kdm_nmenu) && mn_entry)
|
||||
{
|
||||
struct menu_inputevent_args_s ev = {MIE_KEYUP, devid};
|
||||
ev.key.scancode = key;
|
||||
ev.key.charcode = unicode;
|
||||
mn_entry->InputEvent(ev);
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (Key_Dest_Has(kdm_gmenu))
|
||||
MP_Keyup (key, unicode, devid);
|
||||
|
@ -2803,6 +2833,19 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
|
|||
return;
|
||||
}
|
||||
}
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (Key_Dest_Has(kdm_nmenu))
|
||||
{
|
||||
if (mn_entry)
|
||||
{
|
||||
struct menu_inputevent_args_s ev = {MIE_KEYDOWN, devid};
|
||||
ev.key.scancode = key;
|
||||
ev.key.charcode = unicode;
|
||||
if (mn_entry->InputEvent(ev))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (Key_Dest_Has(kdm_gmenu))
|
||||
{
|
||||
|
|
|
@ -250,16 +250,22 @@ typedef enum //highest has priority
|
|||
kdm_centerprint = 1u<<1, //enabled when there's a centerprint menu with clickable things.
|
||||
kdm_message = 1u<<2,
|
||||
kdm_gmenu = 1u<<3, //menu.dat
|
||||
kdm_emenu = 1u<<4, //engine's menus
|
||||
kdm_editor = 1u<<5,
|
||||
kdm_console = 1u<<6,
|
||||
kdm_cwindows = 1u<<7,
|
||||
#ifdef MENU_NATIVECODE
|
||||
kdm_nmenu = 1u<<4,
|
||||
#else
|
||||
kdm_nmenu = 0,
|
||||
#endif
|
||||
kdm_emenu = 1u<<5, //engine's menus
|
||||
kdm_editor = 1u<<6,
|
||||
kdm_console = 1u<<7,
|
||||
kdm_cwindows = 1u<<8,
|
||||
} keydestmask_t;
|
||||
|
||||
//unsigned int Key_Dest_Get(void); //returns highest priority destination
|
||||
#define Key_Dest_Add(kdm) (key_dest_mask |= (kdm))
|
||||
#define Key_Dest_Remove(kdm) (key_dest_mask &= ~(kdm))
|
||||
#define Key_Dest_Has(kdm) (key_dest_mask & (kdm))
|
||||
#define Key_Dest_Has_Higher(kdm) (key_dest_mask & (~0&~((kdm)|((kdm)-1)))) //must be a single bit
|
||||
#define Key_Dest_Toggle(kdm) do {if (key_dest_mask & kdm) Key_Dest_Remove(kdm); else Key_Dest_Add(kdm);}while(0)
|
||||
|
||||
extern unsigned int key_dest_absolutemouse; //if the active key dest bit is set, the mouse is absolute.
|
||||
|
@ -271,9 +277,12 @@ extern int key_lastpress;
|
|||
|
||||
enum
|
||||
{
|
||||
kc_game,
|
||||
kc_menu,
|
||||
kc_console,
|
||||
kc_game, //csprogs.dat
|
||||
kc_menu, //menu.dat
|
||||
#ifdef MENU_NATIVECODE
|
||||
kc_nmenu,
|
||||
#endif
|
||||
kc_console, //generic engine-defined cursor
|
||||
kc_max
|
||||
};
|
||||
extern struct key_cursor_s
|
||||
|
|
286
engine/client/m_native.c
Normal file
286
engine/client/m_native.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
#include "quakedef.h"
|
||||
#ifdef MENU_NATIVECODE
|
||||
static dllhandle_t *libmenu;
|
||||
menu_export_t *mn_entry;
|
||||
|
||||
extern unsigned int r2d_be_flags;
|
||||
#include "pr_common.h"
|
||||
#include "shader.h"
|
||||
#include "cl_master.h"
|
||||
|
||||
static int MN_checkextension(const char *extname)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < QSG_Extensions_count; i++)
|
||||
{
|
||||
if (!strcmp(QSG_Extensions[i].name, extname))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
Cvar_Get2(cvarname, defaulttext, flags, description, NULL);
|
||||
}
|
||||
static int MN_getserverstate(void)
|
||||
{
|
||||
if (!sv.active)
|
||||
return 0;
|
||||
if (svs.allocated_client_slots <= 1)
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
static int MN_getclientstate(void)
|
||||
{
|
||||
if (cls.state >= ca_active)
|
||||
return 2;
|
||||
if (cls.state != ca_disconnected)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static void MN_fclose(vfsfile_t *f)
|
||||
{
|
||||
VFS_CLOSE(f);
|
||||
}
|
||||
static void *MN_precache_pic(const char *picname)
|
||||
{
|
||||
return R2D_SafeCachePic(picname);
|
||||
}
|
||||
static int MN_drawgetimagesize(void *pic, int *w, int *h)
|
||||
{
|
||||
return R_GetShaderSizes(pic, w, h, true);
|
||||
}
|
||||
static void MN_drawquad(vec2_t position[4], vec2_t texcoords[4], void *pic, vec4_t rgba, unsigned int be_flags)
|
||||
{
|
||||
r2d_be_flags = be_flags;
|
||||
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)
|
||||
{
|
||||
float px, py, ix;
|
||||
unsigned int codeflags, codepoint;
|
||||
conchar_t buffer[2048], *str = buffer;
|
||||
COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false);
|
||||
|
||||
Font_BeginScaledString(font_default, 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);
|
||||
return ((px-ix)*(float)vid.width)/(float)vid.rotpixelwidth;
|
||||
}
|
||||
static float MN_stringwidth(const char *text, float height)
|
||||
{
|
||||
float px, py;
|
||||
conchar_t buffer[2048], *end;
|
||||
end = COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false);
|
||||
|
||||
Font_BeginScaledString(font_default, 0, 0, height, height, &px, &py);
|
||||
px = Font_LineScaleWidth(buffer, end);
|
||||
Font_EndString(font_default);
|
||||
return (px * (float)vid.width) / (float)vid.rotpixelwidth;
|
||||
}
|
||||
static void MN_drawsetcliparea(float x, float y, float width, float height)
|
||||
{
|
||||
srect_t srect;
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
srect.x = x / (float)vid.fbvwidth;
|
||||
srect.y = y / (float)vid.fbvheight;
|
||||
srect.width = width / (float)vid.fbvwidth;
|
||||
srect.height = height / (float)vid.fbvheight;
|
||||
srect.dmin = -99999;
|
||||
srect.dmax = 99999;
|
||||
srect.y = (1-srect.y) - srect.height;
|
||||
BE_Scissor(&srect);
|
||||
}
|
||||
static void MN_drawresetcliparea(void)
|
||||
{
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
BE_Scissor(NULL);
|
||||
}
|
||||
static qboolean MN_setkeydest(qboolean focused)
|
||||
{
|
||||
qboolean ret = Key_Dest_Has(kdm_nmenu);
|
||||
if (ret == focused)
|
||||
return false;
|
||||
if (focused)
|
||||
{
|
||||
if (key_dest_absolutemouse & kdm_nmenu)
|
||||
{ //we're activating the mouse cursor now... make sure the position is actually current.
|
||||
struct menu_inputevent_args_s ev = {MIE_MOUSEABS, -1};
|
||||
ev.mouse.screen[0] = mousecursor_x;
|
||||
ev.mouse.screen[1] = mousecursor_y;
|
||||
mn_entry->InputEvent(ev);
|
||||
}
|
||||
Key_Dest_Add(kdm_nmenu);
|
||||
}
|
||||
else
|
||||
Key_Dest_Remove(kdm_nmenu);
|
||||
return true;
|
||||
}
|
||||
static int MN_getkeydest(void)
|
||||
{
|
||||
if (Key_Dest_Has(kdm_nmenu))
|
||||
{
|
||||
if (Key_Dest_Has_Higher(kdm_nmenu))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int MN_setmousetarget(const char *cursorname, float hot_x, float hot_y, float scale)
|
||||
{
|
||||
if (cursorname)
|
||||
{
|
||||
struct key_cursor_s *m = &key_customcursor[kc_nmenu];
|
||||
if (scale <= 0)
|
||||
scale = 1;
|
||||
if (!strcmp(m->name, cursorname) || m->hotspot[0] != hot_x || m->hotspot[1] != hot_y || m->scale != scale)
|
||||
{
|
||||
Q_strncpyz(m->name, cursorname, sizeof(m->name));
|
||||
m->hotspot[0] = hot_x;
|
||||
m->hotspot[1] = hot_y;
|
||||
m->scale = scale;
|
||||
m->dirty = true;
|
||||
}
|
||||
key_dest_absolutemouse |= kdm_nmenu;
|
||||
}
|
||||
else
|
||||
key_dest_absolutemouse &= ~kdm_nmenu;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MN_Shutdown(void)
|
||||
{
|
||||
Key_Dest_Remove(kdm_nmenu);
|
||||
if (mn_entry)
|
||||
{
|
||||
mn_entry->Shutdown();
|
||||
mn_entry = NULL;
|
||||
}
|
||||
if (libmenu)
|
||||
{
|
||||
Sys_CloseLibrary(libmenu);
|
||||
libmenu = NULL;
|
||||
}
|
||||
}
|
||||
qboolean MN_Init(void)
|
||||
{
|
||||
menu_export_t *(QDECL *pGetMenuAPI) ( menu_import_t *import );
|
||||
static menu_import_t imports =
|
||||
{
|
||||
NATIVEMENU_API_VERSION_MAX,
|
||||
|
||||
MN_checkextension,
|
||||
Host_Error,
|
||||
Con_Printf,
|
||||
Con_DPrintf,
|
||||
MN_localcmd,
|
||||
Cvar_VariableValue,
|
||||
Cvar_VariableString,
|
||||
Cvar_SetNamed,
|
||||
MN_registercvar,
|
||||
|
||||
MN_getserverstate,
|
||||
MN_getclientstate,
|
||||
S_LocalSound2,
|
||||
|
||||
// file input / search crap
|
||||
FS_OpenVFS,
|
||||
MN_fclose,
|
||||
VFS_GETS,
|
||||
VFS_PRINTF,
|
||||
COM_EnumerateFiles,
|
||||
|
||||
// Drawing stuff
|
||||
MN_precache_pic,
|
||||
MN_drawgetimagesize,
|
||||
MN_drawquad,
|
||||
MN_drawstring,
|
||||
MN_stringwidth,
|
||||
MN_drawsetcliparea,
|
||||
MN_drawresetcliparea,
|
||||
|
||||
// Menu specific stuff
|
||||
MN_setkeydest,
|
||||
MN_getkeydest,
|
||||
MN_setmousetarget,
|
||||
Key_KeynumToString,
|
||||
Key_StringToKeynum,
|
||||
M_FindKeysForBind,
|
||||
|
||||
// Server browser stuff
|
||||
NULL,//MN_gethostcachevalue,
|
||||
Master_ReadKeyString,
|
||||
Master_ReadKeyFloat,
|
||||
|
||||
Master_ClearMasks,
|
||||
Master_SetMaskString,
|
||||
Master_SetMaskInteger,
|
||||
Master_SetSortField,
|
||||
Master_SortServers,
|
||||
Master_SortedServer,
|
||||
MasterInfo_Refresh,
|
||||
|
||||
Master_KeyForName,
|
||||
};
|
||||
dllfunction_t funcs[] =
|
||||
{
|
||||
{(void*)&pGetMenuAPI, "GetMenuAPI"},
|
||||
{NULL}
|
||||
};
|
||||
void *iterator = NULL;
|
||||
char syspath[MAX_OSPATH];
|
||||
char gamepath[MAX_QPATH];
|
||||
|
||||
while(COM_IteratePaths(&iterator, syspath, sizeof(syspath), gamepath, sizeof(gamepath)))
|
||||
{
|
||||
if (!com_nogamedirnativecode.ival)
|
||||
libmenu = Sys_LoadLibrary(va("%smenu_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, syspath), funcs);
|
||||
if (libmenu)
|
||||
break;
|
||||
|
||||
if (host_parms.binarydir && !strchr(gamepath, '/') && !strchr(gamepath, '\\'))
|
||||
libmenu = Sys_LoadLibrary(va("%smenu_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, host_parms.binarydir, gamepath), funcs);
|
||||
if (libmenu)
|
||||
break;
|
||||
|
||||
//some build systems don't really know the cpu type.
|
||||
if (host_parms.binarydir && !strchr(gamepath, '/') && !strchr(gamepath, '\\'))
|
||||
libmenu = Sys_LoadLibrary(va("%smenu_%s" ARCH_DL_POSTFIX, host_parms.binarydir, gamepath), funcs);
|
||||
if (libmenu)
|
||||
break;
|
||||
}
|
||||
|
||||
if (libmenu)
|
||||
{
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mn_entry = NULL;
|
||||
MN_Shutdown();
|
||||
Sys_CloseLibrary(libmenu);
|
||||
libmenu = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
|
@ -3638,8 +3638,12 @@ void M_Menu_ModelViewer_f(void)
|
|||
|
||||
typedef struct
|
||||
{
|
||||
ftemanifest_t **manifests;
|
||||
size_t nummanifests;
|
||||
struct
|
||||
{
|
||||
ftemanifest_t *manifest;
|
||||
char *gamedir;
|
||||
} *mod;
|
||||
size_t nummods;
|
||||
int y;
|
||||
} modmenu_t;
|
||||
|
||||
|
@ -3652,7 +3656,7 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct menu_s *m)
|
|||
|
||||
mods->y = y;
|
||||
|
||||
if (!mods->nummanifests)
|
||||
if (!mods->nummods)
|
||||
{
|
||||
Draw_FunString(x, y+0, "No games or mods known");
|
||||
#if defined(FTE_TARGET_WEB) || defined(NACL)
|
||||
|
@ -3665,12 +3669,22 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct menu_s *m)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; y+8 <= ym && i < mods->nummanifests; y+=8, i++)
|
||||
for (i = 0; y+8 <= ym && i < mods->nummods; y+=8, i++)
|
||||
{
|
||||
if (mousecursor_y >= y && mousecursor_y < y+8)
|
||||
Draw_AltFunString(x, y, mods->manifests[i]->formalname);
|
||||
if (mods->mod[i].manifest)
|
||||
{
|
||||
if (mousecursor_y >= y && mousecursor_y < y+8)
|
||||
Draw_AltFunString(x, y, mods->mod[i].manifest->formalname);
|
||||
else
|
||||
Draw_FunString(x, y, mods->mod[i].manifest->formalname);
|
||||
}
|
||||
else
|
||||
Draw_FunString(x, y, mods->manifests[i]->formalname);
|
||||
{
|
||||
if (mousecursor_y >= y && mousecursor_y < y+8)
|
||||
Draw_AltFunString(x, y, mods->mod[i].gamedir);
|
||||
else
|
||||
Draw_FunString(x, y, mods->mod[i].gamedir);
|
||||
}
|
||||
}
|
||||
}
|
||||
static qboolean Mods_Key(struct menucustom_s *c, struct menu_s *m, int key, unsigned int unicode)
|
||||
|
@ -3678,14 +3692,14 @@ static qboolean Mods_Key(struct menucustom_s *c, struct menu_s *m, int key, unsi
|
|||
modmenu_t *mods = c->dptr;
|
||||
int i;
|
||||
ftemanifest_t *man;
|
||||
if (key == K_MOUSE1)
|
||||
if (key == K_MOUSE1 || key == K_ENTER || key == K_GP_A)
|
||||
{
|
||||
qboolean wasgameless = !*FS_GetGamedir(false);
|
||||
i = (mousecursor_y - mods->y)/8;
|
||||
if (i < 0 || i > mods->nummanifests)
|
||||
if (i < 0 || i > mods->nummods)
|
||||
return false;
|
||||
man = mods->manifests[i];
|
||||
mods->manifests[i] = NULL; //make sure the manifest survives the menu being closed.
|
||||
man = mods->mod[i].manifest;
|
||||
mods->mod[i].manifest = NULL; //make sure the manifest survives the menu being closed.
|
||||
M_RemoveMenu(m);
|
||||
FS_ChangeGame(man, true, true);
|
||||
|
||||
|
@ -3711,22 +3725,60 @@ static void Mods_Remove (struct menu_s *m)
|
|||
modmenu_t *mods = m->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mods->nummanifests; i++)
|
||||
for (i = 0; i < mods->nummods; i++)
|
||||
{
|
||||
if (mods->manifests[i])
|
||||
FS_Manifest_Free(mods->manifests[i]);
|
||||
if (mods->mod[i].manifest)
|
||||
FS_Manifest_Free(mods->mod[i].manifest);
|
||||
Z_Free(mods->mod[i].gamedir);
|
||||
}
|
||||
Z_Free(mods->manifests);
|
||||
mods->manifests = NULL;
|
||||
Z_Free(mods->mod);
|
||||
mods->mod = NULL;
|
||||
}
|
||||
|
||||
static qboolean Mods_AddMod(void *usr, ftemanifest_t *man)
|
||||
static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man)
|
||||
{
|
||||
modmenu_t *mods = usr;
|
||||
int i = mods->nummanifests;
|
||||
mods->manifests = BZ_Realloc(mods->manifests, (i+1) * sizeof(*mods->manifests));
|
||||
mods->manifests[i] = man;
|
||||
mods->nummanifests = i+1;
|
||||
int i = mods->nummods;
|
||||
mods->mod = BZ_Realloc(mods->mod, (i+1) * sizeof(*mods->mod));
|
||||
mods->mod[i].manifest = man;
|
||||
mods->mod[i].gamedir = NULL;
|
||||
mods->nummods = i+1;
|
||||
return true;
|
||||
}
|
||||
static int QDECL Mods_AddGamedir(const char *fname, qofs_t fsize, time_t mtime, void *usr, searchpathfuncs_t *spath)
|
||||
{
|
||||
modmenu_t *mods = usr;
|
||||
size_t l = strlen(fname);
|
||||
int i, p;
|
||||
char gamedir[MAX_QPATH];
|
||||
if (l && fname[l-1] == '/' && l < countof(gamedir))
|
||||
{
|
||||
l--;
|
||||
memcpy(gamedir, fname, l);
|
||||
gamedir[l] = 0;
|
||||
for (i = 0; i < mods->nummods; i++)
|
||||
{
|
||||
//don't add dupes (can happen from gamedir+homedir)
|
||||
//if the gamedir was already included in one of the manifests, don't bother including it again.
|
||||
//this generally removes id1.
|
||||
if (mods->mod[i].manifest)
|
||||
{
|
||||
for (p = 0; p < countof(fs_manifest->gamepath); p++)
|
||||
if (mods->mod[i].manifest->gamepath[p].path)
|
||||
if (!Q_strcasecmp(mods->mod[i].manifest->gamepath[p].path, gamedir))
|
||||
return true;
|
||||
}
|
||||
else if (mods->mod[i].gamedir)
|
||||
{
|
||||
if (!Q_strcasecmp(mods->mod[i].gamedir, gamedir))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mods->mod = BZ_Realloc(mods->mod, (i+1) * sizeof(*mods->mod));
|
||||
mods->mod[i].manifest = NULL;
|
||||
mods->mod[i].gamedir = Z_StrDup(gamedir);
|
||||
mods->nummods = i+1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3737,9 +3789,16 @@ void M_Menu_Mods_f (void)
|
|||
modmenu_t mods;
|
||||
menucustom_t *c;
|
||||
menu_t *menu;
|
||||
extern qboolean com_homepathenabled;
|
||||
|
||||
memset(&mods, 0, sizeof(mods));
|
||||
FS_EnumerateKnownGames(Mods_AddMod, &mods);
|
||||
FS_EnumerateKnownGames(Mods_AddManifest, &mods);
|
||||
|
||||
if (com_homepathenabled)
|
||||
Sys_EnumerateFiles(com_homepath, "*", Mods_AddGamedir, &mods, NULL);
|
||||
Sys_EnumerateFiles(com_gamepath, "*", Mods_AddGamedir, &mods, NULL);
|
||||
|
||||
//FIXME: sort by mtime?
|
||||
|
||||
Key_Dest_Add(kdm_emenu);
|
||||
|
||||
|
|
|
@ -196,6 +196,74 @@ int M_FindKeysForCommand (int bindmap, int pnum, const char *command, int *keyli
|
|||
return M_FindKeysForBind(bindmap, va("%s%s", prefix, command), keylist, keymods, keycount);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
M_ToggleMenu_f
|
||||
================
|
||||
*/
|
||||
void M_ToggleMenu_f (void)
|
||||
{
|
||||
#ifndef NOBUILTINMENUS
|
||||
if (topmenu)
|
||||
{
|
||||
Key_Dest_Add(kdm_emenu);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CSQC_DAT
|
||||
if (CSQC_ConsoleCommand(-1, "togglemenu"))
|
||||
{
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (MP_Toggle(1))
|
||||
{
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (mn_entry)
|
||||
{
|
||||
mn_entry->Toggle(1);
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef VM_UI
|
||||
if (UI_OpenMenu())
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifndef NOBUILTINMENUS
|
||||
M_Menu_Main_f ();
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
M_Restart_f
|
||||
================
|
||||
*/
|
||||
void M_Init_Internal (void);
|
||||
void M_Restart_f(void)
|
||||
{
|
||||
M_Shutdown(false);
|
||||
|
||||
if (!strcmp(Cmd_Argv(1), "off"))
|
||||
{ //explicitly restart the engine's menu. not the menuqc crap
|
||||
//don't even start csqc menus.
|
||||
M_Init_Internal();
|
||||
}
|
||||
else
|
||||
M_Reinit();
|
||||
}
|
||||
|
||||
|
||||
#ifndef NOBUILTINMENUS
|
||||
|
||||
void M_Menu_Audio_f (void);
|
||||
|
@ -318,61 +386,6 @@ void M_CloseMenu_f (void)
|
|||
M_RemoveAllMenus(false);
|
||||
Key_Dest_Remove(kdm_emenu);
|
||||
}
|
||||
/*
|
||||
================
|
||||
M_ToggleMenu_f
|
||||
================
|
||||
*/
|
||||
void M_ToggleMenu_f (void)
|
||||
{
|
||||
if (topmenu)
|
||||
{
|
||||
Key_Dest_Add(kdm_emenu);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CSQC_DAT
|
||||
if (CSQC_ConsoleCommand(-1, "togglemenu"))
|
||||
{
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (MP_Toggle(1))
|
||||
{
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef VM_UI
|
||||
if (UI_OpenMenu())
|
||||
return;
|
||||
#endif
|
||||
|
||||
//it IS a toggle, so close the menu if its already active
|
||||
if (Key_Dest_Has(kdm_emenu))
|
||||
{
|
||||
Key_Dest_Remove(kdm_emenu);
|
||||
return;
|
||||
}
|
||||
if (Key_Dest_Has(kdm_console|kdm_cwindows))
|
||||
Key_Dest_Remove(kdm_console|kdm_cwindows);
|
||||
/*
|
||||
{
|
||||
if (cls.state != ca_active)
|
||||
{
|
||||
Key_Dest_Remove(kdm_console);
|
||||
M_Menu_Main_f();
|
||||
}
|
||||
else
|
||||
Con_ToggleConsole_Force ();
|
||||
}
|
||||
else*/
|
||||
{
|
||||
M_Menu_Main_f ();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/* KEYS MENU */
|
||||
|
@ -1316,6 +1329,9 @@ void M_DeInit_Internal (void)
|
|||
|
||||
void M_Shutdown(qboolean total)
|
||||
{
|
||||
#ifdef MENU_NATIVECODE
|
||||
MN_Shutdown();
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
MP_Shutdown();
|
||||
#endif
|
||||
|
@ -1325,6 +1341,9 @@ void M_Shutdown(qboolean total)
|
|||
|
||||
void M_Reinit(void)
|
||||
{
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (!MN_Init())
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (!MP_Init())
|
||||
#endif
|
||||
|
@ -1341,7 +1360,7 @@ void M_MenuPop_f(void);
|
|||
//menu.dat is loaded later... after the video and everything is up.
|
||||
void M_Init (void)
|
||||
{
|
||||
|
||||
Cmd_AddCommand("menu_restart", M_Restart_f);
|
||||
Cmd_AddCommand("togglemenu", M_ToggleMenu_f);
|
||||
Cmd_AddCommand("closemenu", M_CloseMenu_f);
|
||||
Cmd_AddCommand("fps_preset", FPS_Preset_f);
|
||||
|
@ -1380,12 +1399,18 @@ void M_Init_Internal (void){}
|
|||
void M_DeInit_Internal (void){}
|
||||
void M_Shutdown(qboolean total)
|
||||
{
|
||||
#ifdef MENU_NATIVECODE
|
||||
MN_Shutdown();
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
MP_Shutdown();
|
||||
#endif
|
||||
}
|
||||
void M_Reinit(void)
|
||||
{
|
||||
#ifdef MENU_NATIVECODE
|
||||
if (!MN_Init())
|
||||
#endif
|
||||
#ifdef MENU_DAT
|
||||
if (!MP_Init())
|
||||
#endif
|
||||
|
@ -1395,6 +1420,9 @@ void M_Reinit(void)
|
|||
}
|
||||
void M_Init (void)
|
||||
{
|
||||
Cmd_AddCommand("menu_restart", M_Restart_f);
|
||||
Cmd_AddCommand("togglemenu", M_ToggleMenu_f);
|
||||
|
||||
Media_Init();
|
||||
M_Reinit();
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ void M_Shutdown(qboolean total);
|
|||
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.
|
||||
void M_Menu_Installer (void); //given an embedded manifest, this displays an install menu for said game.
|
||||
mpic_t *M_CachePic (char *path);
|
||||
|
@ -454,7 +453,6 @@ void M_UnbindCommand (const char *command);
|
|||
//no builtin menu code.
|
||||
//stubs
|
||||
#define M_Menu_Prompt(cb,ctx,messages,optionyes,optionno,optioncancel) (cb)(ctx,-1)
|
||||
#define M_ToggleMenu_f() Cbuf_AddText("togglemenu\n",RESTRICT_LOCAL)
|
||||
//#define M_Shutdown(t) MP_Shutdown()
|
||||
|
||||
void M_Init (void);
|
||||
|
@ -466,6 +464,7 @@ void M_Draw (int uimenu);
|
|||
#endif
|
||||
int M_FindKeysForCommand (int bindmap, int pnum, const char *command, int *keylist, int *keymods, int keycount);
|
||||
int M_FindKeysForBind (int bindmap, const char *command, int *keylist, int *keymods, int keycount);
|
||||
void M_ToggleMenu_f (void);
|
||||
|
||||
#ifdef MENU_DAT
|
||||
void MP_CvarChanged(cvar_t *var);
|
||||
|
@ -484,6 +483,13 @@ int MP_BuiltinValid(const char *name, int num);
|
|||
qboolean MP_ConsoleCommand(const char *cmdtext);
|
||||
#endif
|
||||
|
||||
#ifdef MENU_NATIVECODE
|
||||
#include "../native/api_menu.h"
|
||||
extern menu_export_t *mn_entry;
|
||||
void MN_Shutdown(void);
|
||||
qboolean MN_Init(void);
|
||||
#endif
|
||||
|
||||
#define MGT_BAD ~0
|
||||
#define MGT_QUAKE1 0
|
||||
#define MGT_HEXEN2 1
|
||||
|
|
|
@ -1067,7 +1067,7 @@ void Master_ResortServer(serverinfo_t *server)
|
|||
}
|
||||
}
|
||||
|
||||
void Master_SortServers(void)
|
||||
int Master_SortServers(void)
|
||||
{
|
||||
serverinfo_t *server;
|
||||
|
||||
|
@ -1088,6 +1088,8 @@ void Master_SortServers(void)
|
|||
{
|
||||
Master_ResortServer(server);
|
||||
}
|
||||
|
||||
return numvisibleservers;
|
||||
}
|
||||
|
||||
serverinfo_t *Master_SortedServer(int idx)
|
||||
|
@ -1104,7 +1106,7 @@ int Master_NumSorted(void)
|
|||
}
|
||||
|
||||
|
||||
float Master_ReadKeyFloat(serverinfo_t *server, int keynum)
|
||||
float Master_ReadKeyFloat(serverinfo_t *server, hostcachekey_t keynum)
|
||||
{
|
||||
if (!server)
|
||||
return -1;
|
||||
|
@ -1164,7 +1166,7 @@ void Master_DecodeColour(vec3_t ret, int col)
|
|||
VectorSet(ret, ((col&0xff0000)>>16)/255.0, ((col&0x00ff00)>>8)/255.0, ((col&0x0000ff)>>0)/255.0);
|
||||
}
|
||||
|
||||
char *Master_ReadKeyString(serverinfo_t *server, int keynum)
|
||||
char *Master_ReadKeyString(serverinfo_t *server, hostcachekey_t keynum)
|
||||
{
|
||||
static char adr[MAX_ADR_SIZE];
|
||||
|
||||
|
@ -1237,7 +1239,7 @@ char *Master_ReadKeyString(serverinfo_t *server, int keynum)
|
|||
return "";
|
||||
}
|
||||
|
||||
int Master_KeyForName(const char *keyname)
|
||||
hostcachekey_t Master_KeyForName(const char *keyname)
|
||||
{
|
||||
int i;
|
||||
if (!strcmp(keyname, "map"))
|
||||
|
|
|
@ -7804,14 +7804,12 @@ qboolean CSQC_DrawView(void)
|
|||
|
||||
if (csqcg.frametime)
|
||||
{
|
||||
if (csqc_isdarkplaces)
|
||||
if (1)//csqc_isdarkplaces)
|
||||
{
|
||||
static double oldtime;
|
||||
if (cl.paused)
|
||||
*csqcg.frametime = 0; //apparently people can't cope with microstutter when they're using this as a test to see if the game is paused.
|
||||
else
|
||||
*csqcg.frametime = bound(0, cl.time - oldtime, 0.1);
|
||||
oldtime = cl.time;
|
||||
*csqcg.frametime = bound(0, cl.time - cl.lasttime, 0.1);
|
||||
}
|
||||
else
|
||||
*csqcg.frametime = host_frametime;
|
||||
|
|
|
@ -2700,19 +2700,6 @@ void MP_CoreDump_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
void MP_Reload_f(void)
|
||||
{
|
||||
M_Shutdown(false);
|
||||
|
||||
if (!strcmp(Cmd_Argv(1), "off"))
|
||||
{ //explicitly restart the engine's menu. not the menuqc crap
|
||||
//don't even start csqc menus.
|
||||
M_Init_Internal();
|
||||
}
|
||||
else
|
||||
M_Reinit();
|
||||
}
|
||||
|
||||
static void MP_Poke_f(void)
|
||||
{
|
||||
/*if (!SV_MayCheat())
|
||||
|
@ -2751,7 +2738,6 @@ void MP_Breakpoint_f(void)
|
|||
void MP_RegisterCvarsAndCmds(void)
|
||||
{
|
||||
Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f);
|
||||
Cmd_AddCommand("menu_restart", MP_Reload_f);
|
||||
Cmd_AddCommand("menu_cmd", MP_GameCommand_f);
|
||||
Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f);
|
||||
Cmd_AddCommand("loadfont", CL_LoadFont_f);
|
||||
|
|
|
@ -321,8 +321,8 @@ void Host_InitCommands (void);
|
|||
void Host_Init (quakeparms_t *parms);
|
||||
void Host_FinishInit(void);
|
||||
void Host_Shutdown(void);
|
||||
NORETURN void VARGS Host_Error (char *error, ...) LIKEPRINTF(1);
|
||||
NORETURN void VARGS Host_EndGame (char *message, ...) LIKEPRINTF(1);
|
||||
NORETURN void VARGS Host_Error (const char *error, ...) LIKEPRINTF(1);
|
||||
NORETURN void VARGS Host_EndGame (const char *message, ...) LIKEPRINTF(1);
|
||||
qboolean Host_SimulationTime(float time);
|
||||
double Host_Frame (double time);
|
||||
qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file);
|
||||
|
|
|
@ -1734,7 +1734,12 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte
|
|||
else
|
||||
{
|
||||
// set to full bright if no light data
|
||||
if (!surf->samples || !wmodel->lightdata)
|
||||
if (r_fullbright.ival)
|
||||
{
|
||||
for (i=0 ; i<size ; i++)
|
||||
blocklights[i] = 255*256;
|
||||
}
|
||||
else if (!wmodel->lightdata)
|
||||
{
|
||||
for (i=0 ; i<size*3 ; i++)
|
||||
{
|
||||
|
@ -1743,10 +1748,10 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte
|
|||
surf->cached_light[0] = d_lightstylevalue[0];
|
||||
surf->cached_colour[0] = cl_lightstyle[0].colourkey;
|
||||
}
|
||||
else if (r_fullbright.ival)
|
||||
else if (!surf->samples)
|
||||
{
|
||||
for (i=0 ; i<size ; i++)
|
||||
blocklights[i] = 255*256;
|
||||
blocklights[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2980,8 +2985,10 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent)
|
|||
struct webostate_s
|
||||
{
|
||||
char dbgid[12];
|
||||
struct webostate_s *next;
|
||||
model_t *wmodel;
|
||||
int cluster[2];
|
||||
qboolean generating;
|
||||
pvsbuffer_t pvs;
|
||||
vboarray_t ebo;
|
||||
void *ebomem;
|
||||
|
@ -2989,6 +2996,8 @@ struct webostate_s
|
|||
int numbatches;
|
||||
int lightstylevalues[MAX_LIGHTSTYLES]; //when using workers that only reprocessing lighting at 10fps, things get too ugly when things go out of sync
|
||||
|
||||
vec3_t lastpos;
|
||||
|
||||
batch_t *rbatches[SHADER_SORT_COUNT];
|
||||
|
||||
struct wesbatch_s
|
||||
|
@ -3002,7 +3011,7 @@ struct webostate_s
|
|||
vbo_t vbo;
|
||||
} batches[1];
|
||||
};
|
||||
static struct webostate_s *webostate;
|
||||
static struct webostate_s *webostates;
|
||||
static struct webostate_s *webogenerating;
|
||||
static int webogeneratingstate; //1 if generating, 0 if not, for waiting for sync.
|
||||
static void R_DestroyWorldEBO(struct webostate_s *es)
|
||||
|
@ -3028,8 +3037,9 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_)
|
|||
batch_t *b, *batch;
|
||||
mesh_t *m;
|
||||
int sortid;
|
||||
R_DestroyWorldEBO(webostate);
|
||||
webostate = ctx;
|
||||
struct webostate_s *webostate = ctx;
|
||||
webostate->next = webostates;
|
||||
webostates = webostate;
|
||||
webogenerating = NULL;
|
||||
webogeneratingstate = 0;
|
||||
mod = webostate->wmodel;
|
||||
|
@ -3097,7 +3107,9 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_)
|
|||
memset(m, 0, sizeof(*m));
|
||||
|
||||
if (b->shader->flags & SHADER_NEEDSARRAYS)
|
||||
{
|
||||
{ //this ebo cache stuff tracks only indexes, we don't know the actual surfs any more.
|
||||
//if NEEDSARRAYS is flagged then the cpu will need access to the mesh data - which it doesn't have.
|
||||
//while we could figure out this info, there would be a lot of vertexes that are not referenced, which would be horrendously slow.
|
||||
if (b->shader->flags & SHADER_SKY)
|
||||
continue;
|
||||
b->shader = R_RegisterShader_Vertex("unsupported");
|
||||
|
@ -3286,10 +3298,29 @@ void Surf_DrawWorld (void)
|
|||
#ifdef THREADEDWORLD
|
||||
if ((r_dynamic.ival < 0 || currentmodel->numbatches) && !r_refdef.recurse && currentmodel->type == mod_brush)
|
||||
{
|
||||
if (webostate && webostate->wmodel != currentmodel)
|
||||
struct webostate_s *webostate, *best = NULL, *generating = NULL;
|
||||
vec_t bestdist = FLT_MAX;
|
||||
for (webostate = webostates; webostate; webostate = webostate->next)
|
||||
{
|
||||
R_DestroyWorldEBO(webostate);
|
||||
webostate = NULL;
|
||||
if (webostate->wmodel != currentmodel)
|
||||
continue;
|
||||
if (webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2)
|
||||
{
|
||||
best = webostate;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3_t m;
|
||||
float d;
|
||||
VectorSubtract(webostate->lastpos, r_refdef.vieworg, m);
|
||||
d = DotProduct(m,m);
|
||||
if (bestdist > d)
|
||||
{
|
||||
bestdist = d;
|
||||
best = webostate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (qrenderer != QR_OPENGL && qrenderer != QR_VULKAN)
|
||||
|
@ -3304,7 +3335,7 @@ void Surf_DrawWorld (void)
|
|||
if (webostate->lightstylevalues[i] != d_lightstylevalue[i])
|
||||
break;
|
||||
}
|
||||
if (webostate && webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2 && i == MAX_LIGHTSTYLES)
|
||||
if (webostate && i == MAX_LIGHTSTYLES)
|
||||
{
|
||||
}
|
||||
else
|
||||
|
@ -3542,8 +3573,12 @@ void Surf_DeInit(void)
|
|||
#ifdef THREADEDWORLD
|
||||
while(webogenerating)
|
||||
COM_WorkerPartialSync(webogenerating, &webogeneratingstate, true);
|
||||
R_DestroyWorldEBO(webostate);
|
||||
webostate = NULL;
|
||||
while (webostates)
|
||||
{
|
||||
void *webostate = webostates;
|
||||
webostates = webostates->next;
|
||||
R_DestroyWorldEBO(webostate);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < numlightmaps; i++)
|
||||
|
@ -3578,13 +3613,19 @@ void Surf_Clear(model_t *mod)
|
|||
// return;/*they're on the hunk*/
|
||||
|
||||
#ifdef THREADEDWORLD
|
||||
struct webostate_s **link, *t;
|
||||
while(webogenerating)
|
||||
COM_WorkerPartialSync(webogenerating, &webogeneratingstate, true);
|
||||
|
||||
if (webostate && webostate->wmodel == mod)
|
||||
for (link = &webostates; (t=*link); )
|
||||
{
|
||||
R_DestroyWorldEBO(webostate);
|
||||
webostate = NULL;
|
||||
if (t->wmodel == mod)
|
||||
{
|
||||
*link = t->next;
|
||||
R_DestroyWorldEBO(t);
|
||||
}
|
||||
else
|
||||
link = &(*link)->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -4076,8 +4117,12 @@ void Surf_ClearLightmaps(void)
|
|||
#ifdef THREADEDWORLD
|
||||
while(webogenerating)
|
||||
COM_WorkerPartialSync(webogenerating, &webogeneratingstate, true);
|
||||
R_DestroyWorldEBO(webostate);
|
||||
webostate = NULL;
|
||||
while (webostates)
|
||||
{
|
||||
void *webostate = webostates;
|
||||
webostates = webostates->next;
|
||||
R_DestroyWorldEBO(webostate);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -4215,6 +4260,10 @@ TRACE(("dbg: Surf_NewMap: tp\n"));
|
|||
{
|
||||
vec3_t mins, maxs;
|
||||
//fixme: no rotation
|
||||
if (!cl_static_entities[i].ent.model && cl_static_entities[i].mdlidx > 0 && cl_static_entities[i].mdlidx < countof(cl.model_precache))
|
||||
cl_static_entities[i].ent.model = cl.model_precache[cl_static_entities[i].mdlidx];
|
||||
else if (!cl_static_entities[i].ent.model && cl_static_entities[i].mdlidx < 0 && (-cl_static_entities[i].mdlidx) < countof(cl.model_csqcprecache))
|
||||
cl_static_entities[i].ent.model = cl.model_csqcprecache[-cl_static_entities[i].mdlidx];
|
||||
if (cl_static_entities[i].ent.model)
|
||||
{
|
||||
//unfortunately, we need to know the actual size so that we can get this right. bum.
|
||||
|
|
|
@ -227,7 +227,7 @@ cvar_t scr_conalpha = CVARC ("scr_conalpha", "0.7",
|
|||
Cvar_Limiter_ZeroToOne_Callback);
|
||||
cvar_t scr_consize = CVAR ("scr_consize", "0.5");
|
||||
cvar_t scr_conspeed = CVAR ("scr_conspeed", "2000");
|
||||
// 10 - 170
|
||||
cvar_t scr_fov_mode = CVARFD ("scr_fov_mode", "0", CVAR_ARCHIVE, "Controls what the fov cvar actually controls:\n0: largest axis (ultra-wide monitors means less height will be visible).\n1: smallest axis (ultra-wide monitors will distort at the edges).\n2: horizontal axis.\n3: vertical axis.");
|
||||
cvar_t scr_fov = CVARFCD("fov", "90", CVAR_ARCHIVE, SCR_Fov_Callback,
|
||||
"field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108.");
|
||||
cvar_t scr_fov_viewmodel = CVARFD("r_viewmodel_fov", "", CVAR_ARCHIVE,
|
||||
|
@ -904,6 +904,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register(&scr_viewsize, SCREENOPTIONS);
|
||||
Cvar_Register(&scr_fov, SCREENOPTIONS);
|
||||
Cvar_Register(&scr_fov_viewmodel, SCREENOPTIONS);
|
||||
Cvar_Register(&scr_fov_mode, SCREENOPTIONS);
|
||||
|
||||
Cvar_Register (&scr_sshot_type, SCREENOPTIONS);
|
||||
Cvar_Register (&scr_sshot_compression, SCREENOPTIONS);
|
||||
|
|
|
@ -1166,15 +1166,67 @@ float CalcFov (float fov_x, float width, float height)
|
|||
|
||||
return a;
|
||||
}
|
||||
static void V_CalcAFov(float afov, float *x, float *y, float w, float h)
|
||||
{
|
||||
extern cvar_t scr_fov_mode;
|
||||
extern cvar_t r_stereo_separation;
|
||||
int mode = scr_fov_mode.ival;
|
||||
#ifdef FTE_TARGET_WEB
|
||||
if (r_refdef.stereomethod == STEREO_WEBVR)
|
||||
w *= 0.5;
|
||||
#endif
|
||||
if (r_refdef.stereomethod == STEREO_CROSSEYED && r_stereo_separation.value)
|
||||
w *= 0.5;
|
||||
|
||||
afov = bound(0.001, afov, 170);
|
||||
|
||||
restart:
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
case 0: //maj-
|
||||
if (h > w)
|
||||
{ //fov specified is interpreted as the horizontal fov at quake's original res: 640*432 (ie: with the sbar removed)...
|
||||
// afov = CalcFov(afov, 640, 432);
|
||||
mode = 3; //vertical
|
||||
}
|
||||
else
|
||||
mode = 2; //horizontal
|
||||
goto restart;
|
||||
case 1: //min+
|
||||
if (h < w)
|
||||
mode = 3; //vertical
|
||||
else
|
||||
mode = 2; //horizontal
|
||||
goto restart;
|
||||
case 2: //horizontal
|
||||
*x = afov;
|
||||
*y = CalcFov(afov, w, h);
|
||||
|
||||
if (*y > 170)
|
||||
{
|
||||
*y = 170;
|
||||
*x = CalcFov(170, h, w);
|
||||
}
|
||||
break;
|
||||
case 3: //vertical
|
||||
*y = afov;
|
||||
*x = CalcFov(afov, h, w);
|
||||
|
||||
if (*x > 170)
|
||||
{ //don't allow screwed fovs.
|
||||
*x = 170;
|
||||
*y = CalcFov(afov, w, h);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
void V_ApplyAFov(playerview_t *pv)
|
||||
{
|
||||
//explicit fov overrides aproximate fov.
|
||||
//aproximate fov is our regular fov value. explicit is settable by gamecode for weird aspect ratios
|
||||
if (!r_refdef.fov_x || !r_refdef.fov_y)
|
||||
{
|
||||
extern cvar_t r_stereo_separation;
|
||||
float ws;
|
||||
|
||||
float afov = r_refdef.afov;
|
||||
if (!afov) //make sure its sensible.
|
||||
{
|
||||
|
@ -1184,59 +1236,15 @@ void V_ApplyAFov(playerview_t *pv)
|
|||
afov *= pv->statsf[STAT_VIEWZOOM]/STAT_VIEWZOOM_SCALE;
|
||||
#endif
|
||||
}
|
||||
afov = bound(0.001, afov, 170);
|
||||
|
||||
ws = 1;
|
||||
#ifdef FTE_TARGET_WEB
|
||||
if (r_refdef.stereomethod == STEREO_WEBVR)
|
||||
ws = 0.5;
|
||||
#endif
|
||||
if (r_refdef.stereomethod == STEREO_CROSSEYED && r_stereo_separation.value)
|
||||
ws = 0.5;
|
||||
|
||||
//attempt to retain a classic fov
|
||||
if (ws*r_refdef.vrect.width < (r_refdef.vrect.height*640)/432)
|
||||
{
|
||||
r_refdef.fov_y = CalcFov(afov, (ws*r_refdef.vrect.width*r_refdef.pxrect.width)/vid.fbvwidth, (r_refdef.vrect.height*r_refdef.pxrect.height)/vid.fbvheight);
|
||||
r_refdef.fov_x = afov;//CalcFov(r_refdef.fov_y, 432, 640);
|
||||
}
|
||||
else
|
||||
{
|
||||
r_refdef.fov_y = CalcFov(afov, 640, 432);
|
||||
r_refdef.fov_x = CalcFov(r_refdef.fov_y, r_refdef.vrect.height, r_refdef.vrect.width*ws);
|
||||
}
|
||||
V_CalcAFov(afov, &r_refdef.fov_x, &r_refdef.fov_y, (r_refdef.vrect.width*r_refdef.pxrect.width)/vid.fbvwidth, (r_refdef.vrect.height*r_refdef.pxrect.height)/vid.fbvheight);
|
||||
}
|
||||
|
||||
if (!r_refdef.fovv_x || !r_refdef.fovv_y)
|
||||
{
|
||||
extern cvar_t r_stereo_separation;
|
||||
float ws;
|
||||
|
||||
float afov = scr_fov_viewmodel.value;
|
||||
if (afov)
|
||||
{
|
||||
afov = bound(0.001, afov, 170);
|
||||
|
||||
ws = 1;
|
||||
#ifdef FTE_TARGET_WEB
|
||||
if (r_refdef.stereomethod == STEREO_WEBVR)
|
||||
ws = 0.5;
|
||||
#endif
|
||||
if (r_refdef.stereomethod == STEREO_CROSSEYED && r_stereo_separation.value)
|
||||
ws = 0.5;
|
||||
|
||||
//attempt to retain a classic fov
|
||||
if (ws*r_refdef.vrect.width < (r_refdef.vrect.height*640)/432)
|
||||
{
|
||||
r_refdef.fovv_y = CalcFov(afov, (ws*r_refdef.vrect.width*r_refdef.pxrect.width)/vid.fbvwidth, (r_refdef.vrect.height*r_refdef.pxrect.height)/vid.fbvheight);
|
||||
r_refdef.fovv_x = afov;//CalcFov(r_refdef.fov_y, 432, 640);
|
||||
}
|
||||
else
|
||||
{
|
||||
r_refdef.fovv_y = CalcFov(afov, 640, 432);
|
||||
r_refdef.fovv_x = CalcFov(r_refdef.fovv_y, r_refdef.vrect.height, r_refdef.vrect.width*ws);
|
||||
}
|
||||
}
|
||||
V_CalcAFov(afov, &r_refdef.fovv_x, &r_refdef.fovv_y, (r_refdef.vrect.width*r_refdef.pxrect.width)/vid.fbvwidth, (r_refdef.vrect.height*r_refdef.pxrect.height)/vid.fbvheight);
|
||||
else
|
||||
{
|
||||
r_refdef.fovv_x = r_refdef.fov_x;
|
||||
|
|
|
@ -558,8 +558,8 @@ typedef struct vfsfile_s
|
|||
#define VFS_WRITE(vf,buffer,buflen) ((vf)->WriteBytes(vf,buffer,buflen))
|
||||
#define VFS_FLUSH(vf) do{if((vf)->Flush)(vf)->Flush(vf);}while(0)
|
||||
#define VFS_PUTS(vf,s) do{const char *t=s;(vf)->WriteBytes(vf,t,strlen(t));}while(0)
|
||||
char *VFS_GETS(vfsfile_t *vf, char *buffer, int buflen);
|
||||
void VARGS VFS_PRINTF(vfsfile_t *vf, char *fmt, ...) LIKEPRINTF(2);
|
||||
char *VFS_GETS(vfsfile_t *vf, char *buffer, size_t buflen);
|
||||
void VARGS VFS_PRINTF(vfsfile_t *vf, const char *fmt, ...) LIKEPRINTF(2);
|
||||
|
||||
enum fs_relative{
|
||||
FS_BINARYPATH, //for dlls and stuff
|
||||
|
|
|
@ -650,6 +650,15 @@ char *Cvar_VariableString (const char *var_name)
|
|||
return var->string;
|
||||
}
|
||||
|
||||
void Cvar_SetNamed (const char *var_name, const char *newvalue)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
var = Cvar_FindVar (var_name);
|
||||
if (!var)
|
||||
return;
|
||||
Cvar_Set(var, newvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
|
|
|
@ -202,6 +202,8 @@ float Cvar_VariableValue (const char *var_name);
|
|||
char *Cvar_VariableString (const char *var_name);
|
||||
// returns an empty string if not defined
|
||||
|
||||
void Cvar_SetNamed (const char *var_name, const char *newvalue);
|
||||
|
||||
char *Cvar_CompleteVariable (const char *partial);
|
||||
// attempts to match a partial variable name for command line completion
|
||||
// returns NULL if nothing fits
|
||||
|
|
|
@ -114,14 +114,14 @@ void FS_UnRegisterFileSystemModule(void *module)
|
|||
}
|
||||
}
|
||||
|
||||
char *VFS_GETS(vfsfile_t *vf, char *buffer, int buflen)
|
||||
char *VFS_GETS(vfsfile_t *vf, char *buffer, size_t buflen)
|
||||
{
|
||||
char in;
|
||||
char *out = buffer;
|
||||
int len;
|
||||
len = buflen-1;
|
||||
if (len == 0)
|
||||
size_t len;
|
||||
if (buflen <= 1)
|
||||
return NULL;
|
||||
len = buflen-1;
|
||||
while (len > 0)
|
||||
{
|
||||
if (VFS_READ(vf, &in, 1) != 1)
|
||||
|
@ -146,7 +146,7 @@ char *VFS_GETS(vfsfile_t *vf, char *buffer, int buflen)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
void VARGS VFS_PRINTF(vfsfile_t *vf, char *format, ...)
|
||||
void VARGS VFS_PRINTF(vfsfile_t *vf, const char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
@ -4462,8 +4462,8 @@ static int FS_IdentifyDefaultGameFromDir(const char *basedir)
|
|||
|
||||
//attempt to work out which game we're meant to be trying to run based upon a few things
|
||||
//1: fs_changegame console command override. fixme: needs to cope with manifests too.
|
||||
//2: -quake3 argument implies that the user wants to run quake3.
|
||||
//3: if we are ftequake3.exe then we always try to run quake3.
|
||||
//2: -quake3 (etc) argument implies that the user wants to run quake3.
|
||||
//3: otherwise if we are ftequake3.exe then we try to run quake3.
|
||||
//4: identify characteristic files within the working directory (like id1/pak0.pak implies we're running quake)
|
||||
//5: check where the exe actually is instead of simply where we're being run from.
|
||||
//6: try the homedir, just in case.
|
||||
|
|
|
@ -3932,12 +3932,32 @@ struct strbuf {
|
|||
char **strings;
|
||||
size_t used;
|
||||
size_t allocated;
|
||||
int flags;
|
||||
};
|
||||
|
||||
#define BUFFLAG_SAVED 1
|
||||
#define BUFSTRBASE 1
|
||||
struct strbuf *strbuflist;
|
||||
size_t strbufmax;
|
||||
|
||||
static void PR_buf_savegame(vfsfile_t *f, pubprogfuncs_t *prinst, qboolean binary)
|
||||
{
|
||||
size_t i, bufno;
|
||||
|
||||
for (bufno = 0; bufno < strbufmax; bufno++)
|
||||
{
|
||||
if (strbuflist[bufno].prinst == prinst && (strbuflist[bufno].flags & BUFFLAG_SAVED))
|
||||
{
|
||||
VFS_PRINTF (f, "buffer %i %i %i %i\n", bufno, 1, ev_string, strbuflist[bufno].used);
|
||||
VFS_PRINTF (f, "{\n");
|
||||
for (i = 0; i < strbuflist[bufno].used; i++)
|
||||
if (strbuflist[bufno].strings[i])
|
||||
VFS_PRINTF (f, "%i %s\n", i, strbuflist[bufno].strings[i]);
|
||||
VFS_PRINTF (f, "}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PF_buf_shutdown(pubprogfuncs_t *prinst)
|
||||
{
|
||||
size_t i, bufno;
|
||||
|
@ -3972,7 +3992,8 @@ void QCBUILTIN PF_buf_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
size_t i;
|
||||
|
||||
const char *type = ((prinst->callargc>0)?PR_GetStringOfs(prinst, OFS_PARM0):"string");
|
||||
// unsigned int flags = ((prinst->callargc>1)?G_FLOAT(OFS_PARM1):1);
|
||||
unsigned int flags = ((prinst->callargc>1)?G_FLOAT(OFS_PARM1):BUFFLAG_SAVED);
|
||||
flags &= BUFFLAG_SAVED;
|
||||
|
||||
if (!Q_strcasecmp(type, "string"))
|
||||
;
|
||||
|
@ -4001,6 +4022,7 @@ void QCBUILTIN PF_buf_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
strbuflist[i].used = 0;
|
||||
strbuflist[i].allocated = 0;
|
||||
strbuflist[i].strings = NULL;
|
||||
strbuflist[i].flags = flags;
|
||||
G_FLOAT(OFS_RETURN) = i+BUFSTRBASE;
|
||||
}
|
||||
// #441 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
|
||||
|
@ -6239,6 +6261,10 @@ void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored)
|
|||
#endif
|
||||
tokenize_flush();
|
||||
}
|
||||
void PR_Common_SaveGame(vfsfile_t *f, pubprogfuncs_t *prinst, qboolean binary)
|
||||
{
|
||||
PR_buf_savegame(f, prinst, binary);
|
||||
}
|
||||
|
||||
|
||||
#define DEF_SAVEGLOBAL (1u<<15)
|
||||
|
|
|
@ -499,6 +499,7 @@ void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
|
||||
int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason, pbool fatal);
|
||||
void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored);
|
||||
void PR_Common_SaveGame(vfsfile_t *f, pubprogfuncs_t *prinst, qboolean binary);
|
||||
|
||||
//FIXME
|
||||
pbool PR_RunWarning (pubprogfuncs_t *ppf, char *error, ...);
|
||||
|
|
|
@ -5425,6 +5425,8 @@ done:;
|
|||
for (i = 0; i < s->numpasses; i++)
|
||||
{
|
||||
pass = &s->passes[i];
|
||||
if (pass->prog)
|
||||
continue;
|
||||
if (pass->numtcmods || (s->passes[i].tcgen != TC_GEN_BASE && s->passes[i].tcgen != TC_GEN_LIGHTMAP) || !(s->passes[i].flags & SHADER_PASS_NOCOLORARRAY))
|
||||
{
|
||||
s->flags |= SHADER_NEEDSARRAYS;
|
||||
|
|
|
@ -60,9 +60,13 @@ none of these issues will be fixed by a compositing window manager, because ther
|
|||
|
||||
#ifdef VKQUAKE
|
||||
#include "vk/vkrenderer.h"
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
static qboolean XVK_SetupSurface_XLib(void);
|
||||
#endif
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
static qboolean XVK_SetupSurface_XCB(void);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef GLQUAKE
|
||||
#include <GL/glx.h>
|
||||
#ifdef USE_EGL
|
||||
|
|
|
@ -1477,7 +1477,7 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t
|
|||
ddef32_t *def32;
|
||||
ddef16_t *def16;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
// unsigned int j;
|
||||
const char *name;
|
||||
int type;
|
||||
int curprogs = prinst.pr_typecurrent;
|
||||
|
@ -1538,13 +1538,13 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t
|
|||
|
||||
v = (int *)¤t_progstate->globals[def16->ofs];
|
||||
|
||||
// make sure the value is not null, where there's no point in saving
|
||||
/* // make sure the value is not null, where there's no point in saving
|
||||
for (j=0 ; j<type_size[type] ; j++)
|
||||
if (v[j])
|
||||
break;
|
||||
if (j == type_size[type])
|
||||
continue;
|
||||
|
||||
*/
|
||||
add16:
|
||||
AddS("\""); AddS(name); AddS("\" \""); AddS(PR_UglyValueString(&progfuncs->funcs, def16->type&~DEF_SAVEGLOBAL, (eval_t *)v)); AddS("\"\n");
|
||||
}
|
||||
|
@ -1594,12 +1594,12 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t
|
|||
|
||||
v = (int *)¤t_progstate->globals[def32->ofs];
|
||||
|
||||
// make sure the value is not null, where there's no point in saving
|
||||
/* // make sure the value is not null, where there's no point in saving
|
||||
for (j=0 ; j<type_size[type] ; j++)
|
||||
if (v[j])
|
||||
break;
|
||||
if (j == type_size[type])
|
||||
continue;
|
||||
continue;*/
|
||||
add32:
|
||||
AddS("\""); AddS(name); AddS("\" \""); AddS(PR_UglyValueString(&progfuncs->funcs, def32->type&~DEF_SAVEGLOBAL, (eval_t *)v)); AddS("\"\n");
|
||||
}
|
||||
|
@ -1748,6 +1748,9 @@ char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_
|
|||
//there are two ways of saving everything.
|
||||
//0 is to save just the entities.
|
||||
//1 is to save the entites, and all the progs info so that all the variables are saved off, and it can be reloaded to exactly how it was (provided no files or data has been changed outside, like the progs.dat for example)
|
||||
//2 is for vanilla-compatible saved games
|
||||
//3 is a (human-readable) coredump
|
||||
//4 is binary saved games.
|
||||
char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, size_t *bufofs, size_t bufmax, int alldata)
|
||||
{
|
||||
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
|
||||
|
@ -1764,8 +1767,12 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, size_t *bufofs, size_t b
|
|||
}
|
||||
*bufofs = 0;
|
||||
|
||||
if (alldata == 2)
|
||||
{ //special Q1 savegame compatability mode.
|
||||
switch(alldata)
|
||||
{
|
||||
default:
|
||||
return NULL;
|
||||
case 2:
|
||||
//special Q1 savegame compatability mode.
|
||||
//engine will need to store references to progs type and will need to preload the progs and inti the ents itself before loading.
|
||||
|
||||
//Make sure there is only 1 progs loaded.
|
||||
|
@ -1785,9 +1792,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, size_t *bufofs, size_t b
|
|||
|
||||
oldprogs = prinst.pr_typecurrent;
|
||||
PR_SwitchProgs(progfuncs, 0);
|
||||
|
||||
ED_WriteGlobals(progfuncs, buf, bufofs, bufmax);
|
||||
|
||||
PR_SwitchProgs(progfuncs, oldprogs);
|
||||
|
||||
AddS ("}\n");
|
||||
|
@ -1807,10 +1812,11 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, size_t *bufofs, size_t b
|
|||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (alldata)
|
||||
{
|
||||
case 0: //Writes entities only
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
AddS("general {\n");
|
||||
AddS(qcva("\"maxprogs\" \"%i\"\n", prinst.maxprogs));
|
||||
// AddS(qcva("\"maxentities\" \"%i\"\n", maxedicts));
|
||||
|
@ -1856,6 +1862,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, size_t *bufofs, size_t b
|
|||
}
|
||||
PR_SwitchProgs(progfuncs, oldprogs);
|
||||
}
|
||||
|
||||
for (a = 0; a < sv_num_edicts; a++)
|
||||
{
|
||||
edictrun_t *ed = (edictrun_t *)EDICT_NUM(progfuncs, a);
|
||||
|
|
|
@ -838,7 +838,7 @@ long ParseNum (char *str)
|
|||
|
||||
#define MAXQCCFILES 3
|
||||
struct {
|
||||
char name[64];
|
||||
char *name;
|
||||
FILE *stdio;
|
||||
char *buff;
|
||||
int buffsize;
|
||||
|
@ -848,16 +848,11 @@ struct {
|
|||
int SafeOpenWrite (char *filename, int maxsize)
|
||||
{
|
||||
int i;
|
||||
if (strlen(filename) >= sizeof(qccfile[0].name))
|
||||
{
|
||||
QCC_Error(ERR_TOOMANYOPENFILES, "Filename %s too long", filename);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < MAXQCCFILES; i++)
|
||||
{
|
||||
if (!qccfile[i].stdio && !qccfile[i].buff)
|
||||
{
|
||||
strcpy(qccfile[i].name, filename);
|
||||
qccfile[i].name = strdup(filename);
|
||||
qccfile[i].buffsize = maxsize;
|
||||
qccfile[i].maxofs = 0;
|
||||
qccfile[i].ofs = 0;
|
||||
|
@ -926,6 +921,8 @@ pbool SafeClose(int hand)
|
|||
ret = externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
|
||||
free(qccfile[hand].buff);
|
||||
}
|
||||
free(qccfile[hand].name);
|
||||
qccfile[hand].name = NULL;
|
||||
qccfile[hand].buff = NULL;
|
||||
qccfile[hand].stdio = NULL;
|
||||
return ret;
|
||||
|
|
|
@ -6935,6 +6935,41 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs)
|
|||
return lhs;
|
||||
}
|
||||
|
||||
//this is more complex than it needs to be, in order to ensure that anon unions/structs can be handled.
|
||||
struct QCC_typeparam_s *QCC_PR_FindStructMember(QCC_type_t *t, const char *membername, unsigned int *out_ofs)
|
||||
{
|
||||
unsigned int nofs;
|
||||
int i;
|
||||
struct QCC_typeparam_s *r = NULL, *n;
|
||||
for (i = 0; i < t->num_parms; i++)
|
||||
{
|
||||
if ((!t->params[i].paramname || !*t->params[i].paramname) && (t->params[i].type->type == ev_struct || t->params[i].type->type == ev_union))
|
||||
{ //anonymous structs/unions can nest
|
||||
n = QCC_PR_FindStructMember(t->params[i].type, membername, &nofs);
|
||||
if (n)
|
||||
{
|
||||
if (r)
|
||||
break;
|
||||
r = n;
|
||||
*out_ofs = t->params[i].ofs + nofs;
|
||||
}
|
||||
}
|
||||
else if (flag_caseinsensitive?!stricmp (t->params[i].paramname, membername):!STRCMP(t->params[i].paramname, membername))
|
||||
{
|
||||
if (r)
|
||||
break;
|
||||
r = t->params+i;
|
||||
*out_ofs = r->ofs;
|
||||
}
|
||||
}
|
||||
if (i < t->num_parms)
|
||||
{
|
||||
QCC_PR_ParseError(0, "multiple members found matching %s.%s", t->name, membername);
|
||||
return NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*checks for:
|
||||
<d>[X]
|
||||
<d>[X].foo
|
||||
|
@ -7177,8 +7212,9 @@ vectorarrayindex:
|
|||
else if (((t->type == ev_pointer && !arraysize) || (t->type == ev_field && (t->aux_type->type == ev_struct || t->aux_type->type == ev_union)) || t->type == ev_struct || t->type == ev_union) && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
|
||||
{
|
||||
char *tname;
|
||||
unsigned int i;
|
||||
unsigned int ofs;
|
||||
pbool fld = t->type == ev_field;
|
||||
struct QCC_typeparam_s *p;
|
||||
if (!idx.cast && t->type == ev_pointer && !arraysize)
|
||||
{
|
||||
t = t->aux_type;
|
||||
|
@ -7200,18 +7236,14 @@ vectorarrayindex:
|
|||
else
|
||||
QCC_PR_ParseError(0, "indirection in something that is not a struct or union", tname);
|
||||
|
||||
for (i = 0; i < t->num_parms; i++)
|
||||
{
|
||||
if (QCC_PR_CheckName(t->params[i].paramname))
|
||||
break;
|
||||
}
|
||||
if (i == t->num_parms)
|
||||
p = QCC_PR_FindStructMember(t, QCC_PR_ParseName(), &ofs);
|
||||
if (!p)
|
||||
QCC_PR_ParseError(0, "%s is not a member of %s", pr_token, tname);
|
||||
if (!t->params[i].ofs && idx.cast)
|
||||
if (!ofs && idx.cast)
|
||||
;
|
||||
else if (QCC_OPCodeValid(&pr_opcodes[OP_ADD_I]))
|
||||
{
|
||||
tmp = QCC_MakeIntConst(t->params[i].ofs);
|
||||
tmp = QCC_MakeIntConst(ofs);
|
||||
if (idx.cast)
|
||||
idx = QCC_PR_Statement(&pr_opcodes[OP_ADD_I], QCC_SupplyConversion(idx, ev_integer, true), QCC_SupplyConversion(tmp, ev_integer, true), NULL);
|
||||
else
|
||||
|
@ -7219,14 +7251,14 @@ vectorarrayindex:
|
|||
}
|
||||
else
|
||||
{
|
||||
tmp = QCC_MakeFloatConst(t->params[i].ofs);
|
||||
tmp = QCC_MakeFloatConst(ofs);
|
||||
if (idx.cast)
|
||||
idx = QCC_PR_Statement(&pr_opcodes[OP_ADD_F], QCC_SupplyConversion(idx, ev_float, true), QCC_SupplyConversion(tmp, ev_float, true), NULL);
|
||||
else
|
||||
idx = tmp;
|
||||
}
|
||||
arraysize = t->params[i].arraysize;
|
||||
t = t->params[i].type;
|
||||
arraysize = p->arraysize;
|
||||
t = p->type;
|
||||
|
||||
if (fld)
|
||||
t = QCC_PR_FieldType(t);
|
||||
|
|
|
@ -3657,7 +3657,10 @@ void QCC_PR_Lex (void)
|
|||
|
||||
QCC_PR_LexWhitespace (false);
|
||||
|
||||
pr_token_line_last = pr_token_line;
|
||||
if (currentchunk)
|
||||
pr_token_line_last = currentchunk->currentlinenumber-1 + pr_token_line;
|
||||
else
|
||||
pr_token_line_last = pr_token_line;
|
||||
pr_token_line = pr_source_line;
|
||||
|
||||
if (!pr_file_p)
|
||||
|
|
|
@ -2727,6 +2727,8 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message,
|
|||
{
|
||||
CHARRANGE chrg;
|
||||
|
||||
if (!editor->modified)
|
||||
editor->oldline=~0;
|
||||
editor->modified = true;
|
||||
if (EditorModified(editor))
|
||||
if (MessageBox(NULL, "warning: file was modified externally. reload?", "Modified!", MB_YESNO) == IDYES)
|
||||
|
@ -2835,9 +2837,11 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message,
|
|||
Scin_HandleCharAdded(editor, not, pos);
|
||||
break;
|
||||
case SCN_SAVEPOINTREACHED:
|
||||
editor->oldline=~0;
|
||||
editor->modified = false;
|
||||
break;
|
||||
case SCN_SAVEPOINTLEFT:
|
||||
editor->oldline=~0;
|
||||
editor->modified = true;
|
||||
|
||||
if (EditorModified(editor))
|
||||
|
@ -3338,6 +3342,7 @@ int EditorSave(editor_t *edit)
|
|||
edit->filemodifiedtime = sbuf.st_mtime;
|
||||
|
||||
//remove the * in a silly way.
|
||||
edit->oldline=~0;
|
||||
UpdateEditorTitle(edit);
|
||||
|
||||
return true;
|
||||
|
@ -5833,8 +5838,23 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
|
|||
int i;
|
||||
RECT rect;
|
||||
PAINTSTRUCT ps;
|
||||
editor_t *editor;
|
||||
switch (message)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
//if any child editors are still open, send close requests to them first.
|
||||
//this allows them to display prompts, instead of silently losing changes.
|
||||
for (editor = editors; editor;)
|
||||
{
|
||||
editor_t *n = editor->next;
|
||||
if (editor->window)
|
||||
SendMessage(editor->window, WM_CLOSE, 0, 0);
|
||||
editor = n;
|
||||
}
|
||||
//okay, they're all dead. we can kill ourselves now.
|
||||
if (!editors)
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
case WM_CREATE:
|
||||
{
|
||||
CLIENTCREATESTRUCT ccs;
|
||||
|
|
|
@ -397,6 +397,7 @@ struct {
|
|||
} targets[] = {
|
||||
{QCF_STANDARD, "standard"},
|
||||
{QCF_STANDARD, "q1"},
|
||||
{QCF_STANDARD, "id"},
|
||||
{QCF_STANDARD, "quakec"},
|
||||
{QCF_HEXEN2, "hexen2"},
|
||||
{QCF_HEXEN2, "h2"},
|
||||
|
@ -4141,6 +4142,8 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
|
|||
{
|
||||
flag_acc = true;
|
||||
}
|
||||
else if (!strcmp(myargv[i]+5, "frikqcc"))
|
||||
keyword_state = true;
|
||||
else if (!strcmp(myargv[i]+5, "fteqcc"))
|
||||
; //as above, its the default.
|
||||
else if (!strcmp(myargv[i]+5, "id"))
|
||||
|
|
|
@ -12733,7 +12733,7 @@ void PR_DumpPlatform_f(void)
|
|||
"accessor infostring : string\n{\n"
|
||||
"\tget string[string] = infoget;\n"
|
||||
#ifdef QCGC
|
||||
"\tinline set* string[string fld] = {(*this) = infoadd(*this, fld, value);};\n"
|
||||
"\tinline seti& string[string fld] = {this = infoadd(this, fld, value);};\n"
|
||||
#endif
|
||||
"};\n");
|
||||
VFS_PRINTF(f,
|
||||
|
|
|
@ -9,6 +9,9 @@ extern cvar_t coop;
|
|||
extern cvar_t teamplay;
|
||||
extern cvar_t pr_enable_profiling;
|
||||
|
||||
cvar_t sv_savefmt = CVARFD("sv_savefmt", "1", CVAR_SAVE, "Specifies the format used for the saved game.\n0=legacy.\n1=fte\n2=binary");
|
||||
cvar_t sv_autosave = CVARFD("sv_autosave", "5", CVAR_SAVE, "Interval for autosaves, in minutes. Set to 0 to disable autosave.");
|
||||
|
||||
void SV_Savegame_f (void);
|
||||
|
||||
//Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
|
||||
|
@ -73,6 +76,7 @@ void SV_SavegameComment (char *text, size_t textsize)
|
|||
text[textsize-1] = '\0';
|
||||
}
|
||||
|
||||
#ifndef QUAKETC
|
||||
//expects the version to have already been parsed
|
||||
void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
||||
{
|
||||
|
@ -282,7 +286,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
// the rest of the file is sent directly to the progs engine.
|
||||
|
||||
if (version == 5 || version == 6)
|
||||
Q_InitProgs(); //reinitialize progs entirly.
|
||||
;//Q_InitProgs(); //reinitialize progs entirly.
|
||||
else
|
||||
{
|
||||
Q_SetProgsParms(false);
|
||||
|
@ -360,7 +364,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
}
|
||||
}
|
||||
|
||||
void SV_LegacySavegame_f (void)
|
||||
static void SV_LegacySavegame (const char *savename)
|
||||
{
|
||||
size_t len;
|
||||
char *s = NULL;
|
||||
|
@ -375,18 +379,6 @@ void SV_LegacySavegame_f (void)
|
|||
int i;
|
||||
char comment[SAVEGAME_COMMENT_LENGTH+1];
|
||||
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
Con_TPrintf ("save <savename> : save a game\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strstr(Cmd_Argv(1), ".."))
|
||||
{
|
||||
Con_TPrintf ("Relative pathnames are not allowed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sv.state != ss_active)
|
||||
{
|
||||
Con_TPrintf("Can't apply: Server isn't running or is still loading\n");
|
||||
|
@ -401,12 +393,12 @@ void SV_LegacySavegame_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
sprintf (name, "%s", Cmd_Argv(1));
|
||||
sprintf (name, "%s", savename);
|
||||
COM_RequireExtension (name, ".sav", sizeof(name));
|
||||
if (!FS_NativePath(name, FS_GAMEONLY, native, sizeof(native)))
|
||||
return;
|
||||
Con_TPrintf (U8("Saving game to %s...\n"), native);
|
||||
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);
|
||||
|
@ -486,13 +478,16 @@ void SV_LegacySavegame_f (void)
|
|||
svprogfuncs->parms->memfree(s);
|
||||
|
||||
VFS_CLOSE(f);
|
||||
}
|
||||
|
||||
FS_FlushFSHashWritten(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define CACHEGAME_VERSION_OLD 513
|
||||
#define CACHEGAME_VERSION_VERBOSE 514
|
||||
#define CACHEGAME_VERSION_BINARY 515
|
||||
|
||||
|
||||
|
||||
|
@ -1065,7 +1060,7 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
}
|
||||
}
|
||||
|
||||
if (version == CACHEGAME_VERSION_VERBOSE)
|
||||
if (version >= CACHEGAME_VERSION_VERBOSE)
|
||||
{
|
||||
char buf[8192];
|
||||
char *mode = "?";
|
||||
|
@ -1102,6 +1097,8 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
|
||||
VFS_PRINTF (f, "vwep %i %s\n", i, COM_QuotedString(sv.strings.vw_model_precache[i], buf, sizeof(buf), false));
|
||||
|
||||
PR_Common_SaveGame(f, svprogfuncs, version >= CACHEGAME_VERSION_BINARY);
|
||||
|
||||
//FIXME: string buffers
|
||||
//FIXME: hash tables
|
||||
//FIXME: skeletal objects?
|
||||
|
@ -1109,9 +1106,10 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
//FIXME: midi track
|
||||
//FIXME: custom temp-ents?
|
||||
//FIXME: pending uri_gets? (if only just to report fails)
|
||||
//FIXME: routing calls?
|
||||
//FIXME: sql queries?
|
||||
//FIXME: frik files?
|
||||
//FIXME: threads?
|
||||
//FIXME: qc threads?
|
||||
|
||||
VFS_PRINTF (f, "entities\n");
|
||||
}
|
||||
|
@ -1150,10 +1148,18 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
VFS_PRINTF (f,"\n");
|
||||
}
|
||||
|
||||
s = PR_SaveEnts(svprogfuncs, NULL, &len, 0, 1);
|
||||
VFS_PUTS(f, s);
|
||||
VFS_PUTS(f, "\n");
|
||||
svprogfuncs->parms->memfree(s);
|
||||
if (version >= CACHEGAME_VERSION_BINARY)
|
||||
{
|
||||
VFS_PUTS(f, va("%i\n", svprogfuncs->stringtablesize));
|
||||
VFS_WRITE(f, svprogfuncs->stringtable, svprogfuncs->stringtablesize);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = PR_SaveEnts(svprogfuncs, NULL, &len, 0, 1);
|
||||
VFS_PUTS(f, s);
|
||||
VFS_PUTS(f, "\n");
|
||||
svprogfuncs->parms->memfree(s);
|
||||
}
|
||||
|
||||
VFS_CLOSE (f);
|
||||
|
||||
|
@ -1167,11 +1173,12 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
}
|
||||
}
|
||||
|
||||
FS_FlushFSHashFull();
|
||||
FS_FlushFSHashWritten(name);
|
||||
}
|
||||
|
||||
#define FTESAVEGAME_VERSION 25000
|
||||
|
||||
//mapchange is true for Q2's map-change autosaves.
|
||||
void SV_Savegame (const char *savename, qboolean mapchange)
|
||||
{
|
||||
extern cvar_t nomonsters;
|
||||
|
@ -1199,6 +1206,14 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
char str[MAX_LOCALINFO_STRING+1];
|
||||
char *savefilename;
|
||||
|
||||
#ifndef QUAKETC
|
||||
if (!sv_savefmt.ival && !mapchange)
|
||||
{
|
||||
SV_LegacySavegame(savename);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!sv.state || sv.state == ss_clustermode)
|
||||
{
|
||||
Con_Printf("Server is not active - unable to save\n");
|
||||
|
@ -1240,7 +1255,7 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
|
||||
savefilename = va("saves/%s/info.fsv", savename);
|
||||
FS_CreatePath(savefilename, FS_GAMEONLY);
|
||||
f = FS_OpenVFS(savefilename, "wb", FS_GAMEONLY);
|
||||
f = FS_OpenVFS(savefilename, "wbp", FS_GAMEONLY);
|
||||
if (!f)
|
||||
{
|
||||
Con_Printf("Couldn't open file saves/%s/info.fsv\n", savename);
|
||||
|
@ -1417,6 +1432,7 @@ static int QDECL CompleteSaveList (const char *name, qofs_t flags, time_t mtime,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
#ifndef QUAKETC
|
||||
static int QDECL CompleteSaveListLegacy (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
|
||||
{
|
||||
struct xcommandargcompletioncb_s *ctx = parm;
|
||||
|
@ -1425,24 +1441,39 @@ static int QDECL CompleteSaveListLegacy (const char *name, qofs_t flags, time_t
|
|||
ctx->cb(stripped, NULL, NULL, ctx);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
|
||||
{
|
||||
if (argn == 1)
|
||||
{
|
||||
COM_EnumerateFiles(va("saves/%s*/info.fsv", partial), CompleteSaveList, ctx);
|
||||
#ifndef QUAKETC
|
||||
COM_EnumerateFiles(va("%s*.sav", partial), CompleteSaveListLegacy, ctx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void SV_Savegame_f (void)
|
||||
{
|
||||
if (Cmd_Argc() <= 2)
|
||||
SV_Savegame(Cmd_Argv(1), false);
|
||||
{
|
||||
const char *savename = Cmd_Argv(1);
|
||||
if (strstr(savename, ".."))
|
||||
{
|
||||
Con_TPrintf ("Relative pathnames are not allowed\n");
|
||||
return;
|
||||
}
|
||||
#ifndef QUAKETC
|
||||
if (!Q_strcasecmp(Cmd_Argv(0), "savegame_legacy"))
|
||||
SV_LegacySavegame(savename);
|
||||
else
|
||||
#endif
|
||||
SV_Savegame(savename, false);
|
||||
}
|
||||
else
|
||||
Con_Printf("%s: invalid number of arguments\n", Cmd_Argv(0));
|
||||
}
|
||||
|
||||
cvar_t sv_autosave = CVARFD("sv_autosave", "5", CVAR_SAVE, "Interval for autosaves, in minutes. Set to 0 to disable autosave.");
|
||||
void SV_AutoSave(void)
|
||||
{
|
||||
#ifndef NOBUILTINMENUS
|
||||
|
@ -1512,21 +1543,44 @@ void SV_Loadgame_f (void)
|
|||
gametype_e gametype;
|
||||
|
||||
int len;
|
||||
struct
|
||||
{
|
||||
char *pattern;
|
||||
flocation_t loc;
|
||||
} savefiles[] =
|
||||
{
|
||||
{"saves/%s/info.fsv"},
|
||||
#ifndef QUAKETC
|
||||
{"%s.sav"},
|
||||
#endif
|
||||
};
|
||||
int bd,best;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
if (!Renderer_Started() && !isDedicated)
|
||||
{
|
||||
Cbuf_AddText(va("wait;%s %s\n", Cmd_Argv(0), Cmd_Args()), Cmd_ExecLevel);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Q_strncpyz(savename, Cmd_Argv(1), sizeof(savename));
|
||||
|
||||
if (!*savename || strstr(savename, ".."))
|
||||
strcpy(savename, "quick");
|
||||
|
||||
Q_snprintfz (filename, sizeof(filename), "saves/%s/info.fsv", savename);
|
||||
f = FS_OpenVFS (filename, "rb", FS_GAME);
|
||||
if (!f)
|
||||
for (len = 0, bd=0x7fffffff,best=0; len < countof(savefiles); len++)
|
||||
{
|
||||
f = FS_OpenVFS (va("%s.sav", savename), "rb", FS_GAME);
|
||||
if (f)
|
||||
Q_snprintfz (filename, sizeof(filename), "%s.sav", savename);
|
||||
int d = FS_FLocateFile(va(savefiles[len].pattern, savename), FSLF_DONTREFERENCE|FSLF_DEEPONFAILURE, &savefiles[len].loc);
|
||||
if (bd > d)
|
||||
{
|
||||
bd = d;
|
||||
best = len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Q_snprintfz (filename, sizeof(filename), savefiles[best].pattern, savename);
|
||||
f = FS_OpenReadLocation(&savefiles[best].loc);
|
||||
if (!f)
|
||||
{
|
||||
Con_TPrintf ("ERROR: couldn't open %s.\n", filename);
|
||||
|
@ -1541,7 +1595,12 @@ void SV_Loadgame_f (void)
|
|||
version = atoi(str);
|
||||
if (version < FTESAVEGAME_VERSION || version >= FTESAVEGAME_VERSION+GT_MAX)
|
||||
{
|
||||
#ifdef QUAKETC
|
||||
VFS_CLOSE (f);
|
||||
Con_TPrintf ("Unable to load savegame of version %i\n", version);
|
||||
#else
|
||||
SV_Loadgame_Legacy(filename, f, version);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1581,6 +1581,7 @@ void SV_Loadgame_f (void);
|
|||
void SV_AutoSave(void);
|
||||
void SV_FlushLevelCache(void);
|
||||
extern cvar_t sv_autosave;
|
||||
extern cvar_t sv_savefmt;
|
||||
|
||||
|
||||
int SV_RateForClient(client_t *cl);
|
||||
|
|
|
@ -2542,6 +2542,33 @@ static void SV_Gamedir (void)
|
|||
Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING);
|
||||
}
|
||||
|
||||
static int QDECL CompleteGamedirPath (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
|
||||
{
|
||||
struct xcommandargcompletioncb_s *ctx = parm;
|
||||
char dirname[MAX_QPATH];
|
||||
if (*name)
|
||||
{
|
||||
size_t l = strlen(name)-1;
|
||||
if (l < countof(dirname) && name[l] == '/')
|
||||
{ //directories are marked with an explicit trailing slash. because we're weird.
|
||||
memcpy(dirname, name, l);
|
||||
dirname[l] = 0;
|
||||
ctx->cb(dirname, NULL, NULL, ctx);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void SV_Gamedir_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
|
||||
{
|
||||
extern qboolean com_homepathenabled;
|
||||
if (argn == 1)
|
||||
{
|
||||
if (com_homepathenabled)
|
||||
Sys_EnumerateFiles(com_homepath, va("%s*", partial), CompleteGamedirPath, ctx, NULL);
|
||||
Sys_EnumerateFiles(com_gamepath, va("%s*", partial), CompleteGamedirPath, ctx, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_Gamedir_f
|
||||
|
@ -3045,8 +3072,8 @@ void SV_InitOperatorCommands (void)
|
|||
Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
|
||||
|
||||
Cmd_AddCommand ("localinfo", SV_Localinfo_f);
|
||||
Cmd_AddCommandD ("gamedir", SV_Gamedir_f, "Change the current gamedir.");
|
||||
Cmd_AddCommand ("sv_gamedir", SV_Gamedir);
|
||||
Cmd_AddCommandAD ("gamedir", SV_Gamedir_f, SV_Gamedir_c, "Change the current gamedir.");
|
||||
Cmd_AddCommandAD ("sv_gamedir", SV_Gamedir, SV_Gamedir_c, "Change the gamedir reported to clients, without changing any actual paths on the server.");
|
||||
Cmd_AddCommand ("sv_settimer", SV_SetTimer_f);
|
||||
Cmd_AddCommand ("stuffcmd", SV_StuffToClient_f);
|
||||
|
||||
|
|
|
@ -5213,7 +5213,10 @@ void SV_InitLocal (void)
|
|||
Cvar_Register(&sv_autosave, cvargroup_servercontrol);
|
||||
#endif
|
||||
#endif
|
||||
Cmd_AddCommandAD ("savegame_legacy", SV_LegacySavegame_f, SV_Savegame_c, "Saves the game in a format compatible with vanilla Quake. Anything not supported by that format will be lost.");
|
||||
Cvar_Register(&sv_savefmt, cvargroup_servercontrol);
|
||||
#ifndef QUAKETC
|
||||
Cmd_AddCommandAD ("savegame_legacy", SV_Savegame_f, SV_Savegame_c, "Saves the game in a format compatible with vanilla Quake. Anything not supported by that format will be lost.");
|
||||
#endif
|
||||
Cmd_AddCommandAD ("savegame", SV_Savegame_f, SV_Savegame_c, "Saves the game to the named location.");
|
||||
Cmd_AddCommandAD ("loadgame", SV_Loadgame_f, SV_Savegame_c, "Loads an existing saved game.");
|
||||
Cmd_AddCommandAD ("save", SV_Savegame_f, SV_Savegame_c, "Saves the game to the named location.");
|
||||
|
|
Loading…
Reference in a new issue