Flattened downloads menu.

Added scrollbars to various menus (when they're too tall for the virtual screen height).
Added warnings when qc draws to the screen outside of where it'll actually be displayed (freecs is guilty of this).
r_showshaders will now work in q2.
mod_texturelist will include a small preview, because I can.
plug_list command will now also display some plugins which are not currently loaded.
q1bsp now properly respects hitcontents (note that normally only hull 0 actually has contents other than solid+empty).
q1bsp now correctly reports content values in tracelines (this fixes freecs being unable to detect func_water).
Rewrote netgraph code. Now displays using polygons instead of textures for higher resolution graphs.
Fixed texture bug that appears with nouveau's core contexts (texture unit switches were not happening).
Added some better support for disabling vsync with nouveau, although its still broken fullscreen for some reason.
Changed fteqcc's warning for unrecognised CRCs. Should be more descriptive about the usual cause (but less technical and potentially technically wrong).



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5378 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-01-13 16:51:50 +00:00
parent b930659fe8
commit 2361c7d14f
52 changed files with 1532 additions and 626 deletions

View File

@ -129,11 +129,20 @@ IF(CMAKE_C_COMPILER_ID MATCHES "GNU")
#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wc++-compat") #lul
#TODO SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes") #for finding missing statics.
#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function") #
#might as well do this, public builds use the regular Makefile.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
ELSE()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
ENDIF()
ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEBUG")
ENDIF()
IF(${ANDROID})
# FIND_PACKAGE(Freetype REQUIRED)
@ -232,6 +241,7 @@ ELSEIF(${UNIX}) #linux(ish)
engine/client/snd_al.c
engine/client/snd_alsa.c
engine/client/snd_linux.c
engine/client/snd_pulse.c
engine/client/snd_sdl.c #we use SDL audio even without sys_sdl, because of pulseaudio fucking over alsa, alsa fucking over oss3, and oss4 not being used. Either way, openal should be the default anyway.
engine/client/cd_linux.c
@ -405,11 +415,92 @@ SET(FTE_COMMON_FILES
engine/common/translate.c
engine/common/zone.c
#important headers
engine/common/bothdefs.h
engine/common/config_fteqw.h
engine/common/config_minimal.h
engine/common/config_nocompat.h
engine/common/config_wastes.h
engine/common/config_freecs.h
#useless headers that I'll never search for
engine/client/api_menu.h
engine/client/cdaudio.h
engine/client/client.h
engine/client/cl_ignore.h
engine/client/cl_master.h
engine/client/clq3defs.h
engine/client/input.h
engine/client/keys.h
engine/client/menu.h
engine/client/merged.h
engine/client/modelgen.h
engine/client/quakedef.h
engine/client/render.h
engine/client/sbar.h
engine/client/screen.h
engine/client/sound.h
engine/client/spritegn.h
# engine/client/sys_plugfte.h
engine/client/vid.h
engine/client/view.h
engine/client/wad.h
# engine/client/winquake.h
engine/common/bothdefs.h
engine/common/bspfile.h
engine/common/cmd.h
engine/common/com_mesh.h
engine/common/common.h
engine/common/console.h
engine/common/crc.h
engine/common/cvar.h
engine/common/fs.h
engine/common/mathlib.h
engine/common/net.h
engine/common/netinc.h
engine/common/particles.h
engine/common/pmove.h
engine/common/pr_common.h
engine/common/protocol.h
engine/common/sys.h
engine/common/translate.h
engine/common/ui_public.h
engine/common/vm.h
engine/common/world.h
engine/common/zone.h
engine/gl/gl_draw.h
engine/gl/gl_model.h
engine/gl/glquake.h
engine/gl/glsupp.h
engine/gl/gl_terrain.h
engine/gl/gl_videgl.h
engine/gl/model_hl.h
engine/gl/shader.h
engine/http/iweb.h
engine/qclib/cmdlib.h
engine/qclib/execloop.h
engine/qclib/gui.h
engine/qclib/hash.h
engine/qclib/pr_comp.h
engine/qclib/progsint.h
engine/qclib/progslib.h
engine/qclib/progtype.h
engine/qclib/qcc.h
engine/qclib/qcd.h
engine/server/botlib.h
engine/server/progdefs.h
engine/server/progs.h
engine/server/q2game.h
engine/server/q3g_public.h
engine/server/server.h
#engine/server/svhl_gcapi.h
engine/server/sv_sql.h
#engine/sw/sw.h
#engine/sw/sw_spans.h
engine/vk/vkrenderer.h
engine/web/ftejslib.h
#sigh
engine/client/pr_skelobj.c
engine/client/m_download.c
@ -740,7 +831,7 @@ FIND_PATH(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
FIND_PATH(AVFORMAT_INCLUDE_DIR libavformat/avformat.h)
FIND_PATH(AVUTIL_INCLUDE_DIR libavutil/avutil.h)
FIND_PATH(AVSWSCALE_INCLUDE_DIR libswscale/swscale.h)
IF(AVFORMAT_INCLUDE_DIR)
IF((AVFORMAT_INCLUDE_DIR) AND (AVSWSCALE_INCLUDE_DIR))
FIND_LIBRARY(AVCODEC_LIBRARY avcodec)
FIND_LIBRARY(AVFORMAT_LIBRARY avformat)
FIND_LIBRARY(AVUTIL_LIBRARY avutil)

View File

@ -2242,7 +2242,12 @@ $(RELEASE_DIR)/iqm$(BITS): $(IQM_OBJECTS)
$(CC) -o $(RELEASE_DIR)/iqm$(BITS) $(IQM_OBJECTS) -lstdc++ -lm
iqm: $(RELEASE_DIR)/iqm$(BITS)
utils: httpserver iqm
MASTER_OBJECTS=server/sv_sys_unix.c common/sys_linux_threads.c common/net_ssl_gnutls.c server/sv_master.c common/net_wins.c common/cvar.c common/cmd.c common/sha1.c http/httpclient.c common/log.c common/fs.c common/fs_stdio.c common/common.c common/translate.c common/zone.c qclib/hash.c
$(RELEASE_DIR)/ftemaster$(BITS): $(MASTER_OBJECTS)
$(CC) -o $(RELEASE_DIR)/master$(BITS) $(MASTER_OBJECTS) -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl
master: $(RELEASE_DIR)/ftemaster$(BITS)
utils: httpserver iqm master
prefix ?= /usr/local
exec_prefix ?= $(prefix)

View File

@ -45,6 +45,7 @@ static cvar_t cl_iDrive = CVARFD("cl_iDrive", "1", CVAR_SEMICHEAT, "Effectively
cvar_t cl_run = CVARD("cl_run", "0", "Enables autorun, inverting the state of the +speed key.");
cvar_t cl_fastaccel = CVARD("cl_fastaccel", "1", "Begin moving at full speed instantly, instead of waiting a frame or so.");
extern cvar_t cl_rollspeed;
static cvar_t cl_sendchatstate = CVARD("cl_sendchatstate", "1", "Announce your chat state to the server in a privacy-violating kind of way. This allows other players to see your afk/at-console status.");
cvar_t cl_prydoncursor = CVAR("cl_prydoncursor", ""); //for dp protocol
cvar_t cl_instantrotate = CVARF("cl_instantrotate", "1", CVAR_SEMICHEAT);
@ -1811,10 +1812,17 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
if (!clientcount)
clientcount = 1;
chatstate = 0;
chatstate |= Key_Dest_Has(~kdm_game)?1:0;
chatstate |= vid.activeapp?0:2;
if (cl_sendchatstate.ival)
{
if (Key_Dest_Has(kdm_message|kdm_console|kdm_cwindows))
chatstate |= 1; //chatting
else if (Key_Dest_Has(~(kdm_game|kdm_centerprint)))
chatstate |= 2; //afk. ezquake sends chatting, but neither are really appropriate.
if (!vid.activeapp || vid.isminimized)
chatstate |= 2; //afk.
//FIXME: flag as afk if no new inputs for a while.
}
for (plnum = 0; plnum<clientcount; plnum++)
{
if (cl.playerview[plnum].chatstate != chatstate)
@ -2513,7 +2521,7 @@ void CL_InitInput (void)
#ifdef NQPROT
Cvar_Register (&cl_movement, inputnetworkcvargroup);
#endif
Cvar_Register (&cl_sendchatstate, inputnetworkcvargroup);
Cvar_Register (&cl_smartjump, inputnetworkcvargroup);
Cvar_Register (&cl_prydoncursor, inputnetworkcvargroup);

View File

@ -2499,7 +2499,7 @@ void CL_SetInfo_f (void)
CL_SetInfo(pnum, Cmd_Argv(1), Cmd_Argv(2));
}
#ifdef _DEBUG
#if 1//def _DEBUG
void CL_SetInfoBlob_f (void)
{
qofs_t fsize;
@ -4665,7 +4665,7 @@ void CL_Init (void)
Cmd_AddCommand ("user", CL_User_f);
Cmd_AddCommand ("users", CL_Users_f);
#ifdef _DEBUG
#if 1//def _DEBUG
Cmd_AddCommand ("setinfoblob", CL_SetInfoBlob_f);
#endif
Cmd_AddCommand ("setinfo", CL_SetInfo_f);
@ -5925,10 +5925,15 @@ double Host_Frame (double time)
VectorClear(cl.playerview[i].audio.velocity);
}
if (R2D_Flush)
{
R2D_Flush();
Con_Printf("R2D_Flush was set outside of SCR_UpdateScreen\n");
}
if (SCR_UpdateScreen && !vid.isminimized)
{
extern cvar_t r_stereo_method;
r_refdef.warndraw = false;
r_refdef.stereomethod = r_stereo_method.ival;
#ifdef FTE_TARGET_WEB
if (emscriptenfte_getvrframedata())
@ -5945,6 +5950,7 @@ double Host_Frame (double time)
Sys_Error("update didn't flush 2d cache\n");
RSpeedEnd(RSPEED_TOTALREFRESH);
}
r_refdef.warndraw = true;
}
else
fps_count++;

View File

@ -322,7 +322,7 @@ void CL_Parse_Disconnected(void)
//=============================================================================
int packet_latency[NET_TIMINGS];
float packet_latency[NET_TIMINGS];
int CL_CalcNet (float scale)
{

View File

@ -948,7 +948,7 @@ void SCR_DrawCursor(void)
return;
//choose the cursor based upon the module that has primary focus
if (key_dest_mask & key_dest_absolutemouse & (kdm_console|kdm_cwindows|kdm_editor))
if (key_dest_mask & key_dest_absolutemouse & (kdm_console|kdm_cwindows))
cmod = kc_console;
else if ((key_dest_mask & key_dest_absolutemouse & kdm_emenu))
cmod = kc_console;
@ -1644,8 +1644,10 @@ void SCR_StringXY(const char *str, float x, float y)
int px, py;
unsigned int codepoint;
int error;
//pick the largest of the two. this is to avoid awkwardness with fonts that lack a version <12 pixels high.
struct font_s *font = (Font_CharVHeight(font_console)>Font_CharVHeight(font_default))?font_console:font_default;
Font_BeginString(font_default, ((x<0)?vid.width:x), ((y<0)?vid.height - sb_lines:y), &px, &py);
Font_BeginString(font, ((x<0)?vid.width:x), ((y<0)?vid.height - sb_lines:y), &px, &py);
if (x < 0)
{
@ -1664,7 +1666,7 @@ void SCR_StringXY(const char *str, float x, float y)
codepoint = unicode_decode(&error, str, &str, true);
px = Font_DrawChar(px, py, CON_WHITEMASK, codepoint);
}
Font_EndString(font_default);
Font_EndString(font);
}
/*

View File

@ -282,9 +282,11 @@ sfx_t *cl_sfx_r_exp3;
cvar_t cl_expsprite = CVARFD("cl_expsprite", "1", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol).");
cvar_t r_explosionlight = CVARFC("r_explosionlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback);
cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT);
cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0");
cvar_t cl_legacystains = CVARD("cl_legacystains", "1", "WARNING: this cvar will default to 0 and later removed at some point"); //FIXME: do as the description says!
cvar_t cl_shaftlight = {"gl_shaftlight", "0.8"};
static cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0");
static cvar_t cl_legacystains = CVARD("cl_legacystains", "1", "WARNING: this cvar will default to 0 and later removed at some point"); //FIXME: do as the description says!
static cvar_t cl_shaftlight = CVAR("gl_shaftlight", "0.8");
static cvar_t cl_part_density_fade_start = CVARD("cl_part_density_fade_start", "1024", "Specifies the distance at which ssqc's pointparticles will start to get less dense.");
static cvar_t cl_part_density_fade = CVARD("cl_part_density_fade", "1024", "Specifies the distance over which ssqc pointparticles density fades from all to none. If this is set to 0 then particles will spawn at their normal density regardless of location on the map.");
typedef struct {
sfx_t **sfx;
@ -412,6 +414,9 @@ void CL_InitTEnts (void)
Cvar_Register (&r_explosionlight, "Temporary entity control");
Cvar_Register (&cl_legacystains, "Temporary entity control");
Cvar_Register (&cl_shaftlight, "Temporary entity control");
Cvar_Register (&cl_part_density_fade_start, "Temporary entity control");
Cvar_Register (&cl_part_density_fade, "Temporary entity control");
}
void CL_ShutdownTEnts (void)
@ -2264,7 +2269,8 @@ void CL_ParseTrailParticles(void)
void CL_ParsePointParticles(qboolean compact)
{
vec3_t org, dir;
unsigned int count, effectindex;
unsigned int effectindex;
float count;
effectindex = (unsigned short)MSG_ReadShort();
org[0] = MSG_ReadCoord();
@ -2285,6 +2291,21 @@ void CL_ParsePointParticles(qboolean compact)
effectindex = CL_TranslateParticleFromServer(effectindex);
if (cl.splitclients <= 1 && cl_part_density_fade.value > 0)
{
vec3_t move;
float dist;
VectorSubtract(org, cl.playerview[0].audio.origin, move);
dist = VectorLength(move);
if (dist > cl_part_density_fade_start.value)
{
dist -= cl_part_density_fade_start.value;
count = count - dist/cl_part_density_fade.value;
if (count < 0)
return;
}
}
if (P_RunParticleEffectType(org, dir, count, effectindex))
P_RunParticleEffect (org, dir, 15, 15);
}

View File

@ -1270,7 +1270,7 @@ void CL_ParseQTVFile(vfsfile_t *f, const char *fname, qtvfile_t *result);
//
#define NET_TIMINGS 256
#define NET_TIMINGSMASK 255
extern int packet_latency[NET_TIMINGS];
extern float packet_latency[NET_TIMINGS];
int CL_CalcNet (float scale);
void CL_CalcNet2 (float *pings, float *pings_min, float *pings_max, float *pingms_stddev, float *pingfr, int *pingfr_min, int *pingfr_max, float *dropped, float *choked, float *invalid);
void CL_ClearParseState(void);
@ -1621,6 +1621,8 @@ void Editor_Draw(void);
void Editor_Init(void);
struct pubprogfuncs_s;
void Editor_ProgsKilled(struct pubprogfuncs_s *dead);
#else
#define editormodal false
#endif
void SCR_StringToRGB (char *rgbstring, float *rgb, float rgbinputscale);

View File

@ -635,7 +635,7 @@ void Con_ToggleConsole_f (void)
}
#ifdef CSQC_DAT
if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand(-1, "toggleconsole"))
if (!editormodal && CSQC_ConsoleCommand(-1, "toggleconsole"))
{
Key_Dest_Remove(kdm_console);
return;
@ -2171,7 +2171,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
for (; l; l = l->older)
{
shader_t *pic = NULL;
int picw=0, pich=0;
float picw=0, pich=0;
s = (conchar_t*)(l+1);
if (lineagelimit)
@ -2202,23 +2202,59 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
imgname = Info_ValueForKey(linkinfo, "img");
if (*imgname)
{
pic = R_RegisterPic(imgname, NULL);
char *fl = Info_ValueForKey(linkinfo, "imgtype");
if (*fl)
pic = R_RegisterCustom(imgname, atoi(fl), NULL, NULL);
else
pic = R_RegisterPic(imgname, NULL);
if (pic)
{
imgname = Info_ValueForKey(linkinfo, "w");
imgname = Info_ValueForKey(linkinfo, "s");
if (*imgname)
picw = (atoi(imgname) * charh) / 8.0;
else if (pic->width)
picw = (pic->width * vid.pixelwidth) / vid.width;
{
if (pic->width <= 0 || pic->height <= 0)
picw = pich = 64;
else if (pic->width > pic->height)
{
picw = atof(imgname);
pich = picw * (float)pic->height/pic->width;
}
else
{
pich = atof(imgname);
picw = pich * (float)pic->width/pic->height;
}
}
else
picw = 64;
imgname = Info_ValueForKey(linkinfo, "h");
if (*imgname)
pich = (atoi(imgname) * charh) / 8.0;
else if (pic->height)
pich = (pic->height * vid.pixelheight) / vid.height;
else
pich = 64;
{
imgname = Info_ValueForKey(linkinfo, "w");
if (*imgname)
picw = atof(imgname);
else
picw = -1;
imgname = Info_ValueForKey(linkinfo, "h");
if (*imgname)
pich = atof(imgname);
else
pich = -1;
if (picw<0 && pich<0)
{
if (pic->width && pic->height)
{
pich = (pic->height * vid.pixelheight) / vid.height;
picw = (pic->width * vid.pixelwidth) / vid.width;
}
else
picw = pich = 64;
}
else if (picw<0)
picw = pich * (float)pic->width/pic->height;
else if (pich<0)
pich = picw * (float)pic->height/pic->width;
}
picw *= charh/8.0;
pich *= charh/8.0;
if (picw >= ex-sx)
{
@ -2799,9 +2835,16 @@ void Con_DrawConsole (int lines, qboolean noback)
if (!Plug_ConsoleLinkMouseOver(mousecursor_x, mousecursor_y, mouseover+2, info))
#endif
{
char *key = Info_ValueForKey(info, "tipimg");
char *key;
key = Info_ValueForKey(info, "tipimg");
if (*key)
shader = R2D_SafeCachePic(key);
{
char *fl = Info_ValueForKey(info, "tipimgtype");
if (*fl)
shader = R_RegisterCustom(key, atoi(fl), NULL, NULL);
else
shader = R2D_SafeCachePic(key);
}
else
{
key = Info_ValueForKey(info, "tiprawimg");

View File

@ -2597,7 +2597,7 @@ void Key_Init (void)
key_linepos = 0;
key_dest_mask = kdm_game;
key_dest_absolutemouse = kdm_centerprint | kdm_console | kdm_editor | kdm_cwindows | kdm_emenu;
key_dest_absolutemouse = kdm_centerprint | kdm_console | kdm_cwindows | kdm_emenu;
//
// init ascii characters in console mode
@ -2700,15 +2700,6 @@ qboolean Key_MouseShouldBeFree(void)
if (key_dest_absolutemouse & key_dest_mask)
return true;
if (Key_Dest_Has(kdm_editor))
return true;
// if (!vid.activeapp)
// return true;
if (Key_Dest_Has(kdm_emenu))
return true;
#ifdef VM_UI
if (UI_MenuState())
return false;
@ -2837,7 +2828,7 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
if (!down)
{
#ifdef MENU_DAT
if (Key_Dest_Has(kdm_gmenu) && !Key_Dest_Has(kdm_editor|kdm_console|kdm_cwindows))
if (Key_Dest_Has(kdm_gmenu) && !Key_Dest_Has(kdm_console|kdm_cwindows))
MP_Keyup (key, unicode, devid);
#endif
#ifdef MENU_NATIVECODE
@ -2865,10 +2856,6 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
if (!cls.state && !Key_Dest_Has(~kdm_game) && !Media_PlayingFullScreen())
M_ToggleMenu_f ();
}
#ifdef TEXTEDITOR
else if (Key_Dest_Has(kdm_editor))
Editor_Key (key, unicode);
#endif
else if (Key_Dest_Has(kdm_emenu))
M_Keydown (key, unicode);
#ifdef MENU_NATIVECODE
@ -3019,13 +3006,6 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
return;
}
#endif
#ifdef TEXTEDITOR
if (Key_Dest_Has(kdm_editor))
{
Editor_Key (key, unicode);
return;
}
#endif
#ifdef VM_UI
if (!Key_Dest_Has(~kdm_game) || !down)
{

View File

@ -257,9 +257,8 @@ typedef enum //highest has priority
kdm_nmenu = 0,
#endif
kdm_emenu = 1u<<5, //engine's menus
kdm_editor = 1u<<6,
kdm_console = 1u<<7,
kdm_cwindows = 1u<<8,
kdm_console = 1u<<6,
kdm_cwindows = 1u<<7,
} keydestmask_t;
//unsigned int Key_Dest_Get(void); //returns highest priority destination

View File

@ -630,6 +630,7 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
char mirror[countof(p->mirror)][MAX_OSPATH];
int nummirrors = 0;
int argc;
qboolean isauto;
if (!f)
return;
@ -729,6 +730,7 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
}
continue;
}
isauto = false;
if (version > 1)
{
char pathname[256];
@ -815,6 +817,8 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
flags &= ~DPF_ENABLED; //known about, (probably) cached, but not actually enabled.
else if (!strncmp(arg, "installed=", 6) && version>2)
flags |= parseflags & DPF_ENABLED;
else if (!strcmp(arg, "auto"))
isauto = true; //autoinstalled and NOT user-installed
else if (!strncmp(arg, "root=", 5) && (parseflags&DPF_ENABLED))
{
if (!Q_strcasecmp(arg+5, "bin"))
@ -974,7 +978,12 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
}
}
if (p->flags & DPF_ENABLED)
p->flags |= DPF_USERMARKED; //FIXME: we don't know if this was manual or auto
{
if (isauto)
p->flags |= DPF_AUTOMARKED; //FIXME: we don't know if this was manual or auto
else
p->flags |= DPF_USERMARKED; //FIXME: we don't know if this was manual or auto
}
PM_InsertPackage(p);
}
@ -1899,6 +1908,12 @@ static void PM_WriteInstalledPackages(void)
COM_QuotedConcat("test=1", buf, sizeof(buf));
}
if ((p->flags & DPF_AUTOMARKED) && !(p->flags & DPF_USERMARKED))
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat("auto", buf, sizeof(buf));
}
buf[sizeof(buf)-2] = 0; //just in case.
Q_strncatz(buf, "\n", sizeof(buf));
VFS_WRITE(f, buf, strlen(buf));
@ -2986,61 +3001,85 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
#ifdef WEBCLIENT
if (p->download)
Draw_FunString (x+4, y, va("%i", (int)p->download->qdownload.percent));
Draw_FunStringWidth (x, y, va("%i%%", (int)p->download->qdownload.percent), 48, 2, false);
else if (p->trymirrors)
Draw_FunString (x+4, y, "PND");
Draw_FunStringWidth (x, y, "PND", 48, 2, false);
else
#endif
{
if (!(p->flags & DPF_MARKED))
if (p->flags & DPF_USERMARKED)
{
if (!(p->flags & DPF_ENABLED))
{ //!DPF_MARKED|!DPF_ENABLED:
{ //DPF_MARKED|!DPF_ENABLED:
if (p->flags & DPF_PURGE)
Draw_FunString (x, y, "DEL"); //purge
else if (p->flags & DPF_HIDDEN)
Draw_FunString (x+4, y, "---");
else if (p->flags & DPF_CORRUPT)
Draw_FunString (x, y, "!!!");
Draw_FunStringWidth (x, y, "GET", 48, 2, false);
else if (p->flags & (DPF_PRESENT))
Draw_FunStringWidth (x, y, "USE", 48, 2, false);
else
{
Draw_FunString (x+4, y, "^Ue080^Ue082");
Draw_FunString (x+8, y, "^Ue081");
if (p->flags & DPF_PRESENT)
Draw_FunString (x+8, y, "-");
}
Draw_FunStringWidth (x, y, "GET", 48, 2, false);
}
else
{ //!DPF_MARKED|DPF_ENABLED:
if ((p->flags & DPF_PURGE) || PM_PurgeOnDisable(p))
Draw_FunString (x, y, "DEL");
{ //DPF_MARKED|DPF_ENABLED:
if (p->flags & DPF_PURGE)
Draw_FunStringWidth (x, y, "GET", 48, 2, false); //purge and reinstall.
else if (p->flags & DPF_CORRUPT)
Draw_FunStringWidth (x, y, "?""?""?", 48, 2, false);
else
Draw_FunString (x, y, "REM");
{
Draw_FunStringWidth (x, y, "^Ue080^Ue082", 48, 2, false);
Draw_FunStringWidth (x, y, "^Ue083", 48, 2, false);
}
}
}
else if (p->flags & DPF_MARKED)
{
if (!(p->flags & DPF_ENABLED))
{ //DPF_MARKED|!DPF_ENABLED:
if (p->flags & DPF_PURGE)
Draw_FunStringWidth (x, y, "^hGET", 48, 2, false);
else if (p->flags & (DPF_PRESENT))
Draw_FunStringWidth (x, y, "^hUSE", 48, 2, false);
else
Draw_FunStringWidth (x, y, "^hGET", 48, 2, false);
}
else
{ //DPF_MARKED|DPF_ENABLED:
if (p->flags & DPF_PURGE)
Draw_FunStringWidth (x, y, "^hGET", 48, 2, false); //purge and reinstall.
else if (p->flags & DPF_CORRUPT)
Draw_FunStringWidth (x, y, "?""?""?", 48, 2, false);
else
{
Draw_FunStringWidth (x, y, "^Ue080^Ue082", 48, 2, false);
Draw_FunStringWidth (x, y, "^Ue083", 48, 2, false);
}
}
}
else
{
if (!(p->flags & DPF_ENABLED))
{ //DPF_MARKED|!DPF_ENABLED:
{ //!DPF_MARKED|!DPF_ENABLED:
if (p->flags & DPF_PURGE)
Draw_FunString (x, y, "GET");
else if (p->flags & (DPF_PRESENT))
Draw_FunString (x, y, "USE");
else
Draw_FunString (x, y, "GET");
}
else
{ //DPF_MARKED|DPF_ENABLED:
if (p->flags & DPF_PURGE)
Draw_FunString (x, y, "GET"); //purge and reinstall.
Draw_FunStringWidth (x, y, "DEL", 48, 2, false); //purge
else if (p->flags & DPF_HIDDEN)
Draw_FunStringWidth (x, y, "---", 48, 2, false);
else if (p->flags & DPF_CORRUPT)
Draw_FunString (x, y, "?""?""?");
Draw_FunStringWidth (x, y, "!!!", 48, 2, false);
else
{
Draw_FunString (x+4, y, "^Ue080^Ue082");
Draw_FunString (x+8, y, "^Ue083");
Draw_FunStringWidth (x, y, "^Ue080^Ue082", 48, 2, false);
Draw_FunStringWidth (x, y, "^Ue081", 48, 2, false);
if (p->flags & DPF_PRESENT)
Draw_FunStringWidth (x, y, "-", 48, 2, false);
}
}
else
{ //!DPF_MARKED|DPF_ENABLED:
if ((p->flags & DPF_PURGE) || PM_PurgeOnDisable(p))
Draw_FunStringWidth (x, y, "DEL", 48, 2, false);
else
Draw_FunStringWidth (x, y, "REM", 48, 2, false);
}
}
}
@ -3053,9 +3092,9 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
// if (!(p->flags & (DPF_ENABLED|DPF_MARKED|DPF_PRESENT))
// continue;
if (&m->selecteditem->common == &c->common)
Draw_AltFunString (x+48, y, n);
else
// if (&m->selecteditem->common == &c->common)
// Draw_AltFunString (x+48, y, n);
// else
Draw_FunString(x+48, y, n);
}
}
@ -3106,8 +3145,10 @@ static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsig
PM_MarkPackage(p, DPF_USERMARKED);
//now: try to install
break;
case DPF_AUTOMARKED: //
p->flags |= DPF_USERMARKED;
break;
case DPF_USERMARKED:
case DPF_AUTOMARKED:
case DPF_MARKED:
p->flags |= DPF_PURGE;
//now: re-get despite already having it.
@ -3174,11 +3215,11 @@ static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct men
};
char *text;
int setting = bound(0, pm_autoupdate.ival, 2);
text = va("Auto Update: %s", settings[setting]);
if (&m->selecteditem->common == &c->common)
Draw_AltFunString (x+4, y, text);
else
Draw_FunString (x+4, y, text);
text = va("Auto Update: ^a%s", settings[setting]);
// if (&m->selecteditem->common == &c->common)
// Draw_AltFunString (x, y, text);
// else
Draw_FunString (x, y, text);
}
static qboolean MD_AutoUpdate_Key (struct menucustom_s *c, struct menu_s *m, int key, unsigned int unicode)
{
@ -3236,88 +3277,24 @@ static qboolean MD_RevertUpdates (union menuoption_s *mo,struct menu_s *m,int ke
return false;
}
static void MD_AddItemsToDownloadMenu(menu_t *m)
static int MD_AddItemsToDownloadMenu(menu_t *m, int y, const char *pathprefix)
{
char path[MAX_QPATH];
int y;
package_t *p;
menucustom_t *c;
char *slash;
menuoption_t *mo;
dlmenu_t *info = m->data;
int prefixlen;
p = availablepackages;
int prefixlen = strlen(pathprefix);
prefixlen = strlen(info->pathprefix);
y = 48;
MC_AddCommand(m, 0, 170, y, "Apply", MD_ApplyDownloads)->common.tooltip = "Enable/Disable/Download/Delete packages to match any changes made (you will be prompted with a list of the changes that will be made).";
y+=8;
MC_AddCommand(m, 0, 170, y, "Back", MD_PopMenu);
y+=8;
if (!prefixlen)
{
#ifdef WEBCLIENT
MC_AddCommand(m, 0, 170, y, "Mark Updates", MD_MarkUpdatesButton)->common.tooltip = "Select any updated versions of packages that are already installed.";
y+=8;
#endif
MC_AddCommand(m, 0, 170, y, "Revert Updates", MD_RevertUpdates)->common.tooltip = "Reset selection to only those packages that are currently installed.";
y+=8;
#ifdef WEBCLIENT
c = MC_AddCustom(m, 0, y, p, 0);
c->draw = MD_AutoUpdate_Draw;
c->key = MD_AutoUpdate_Key;
c->common.width = 320;
c->common.height = 8;
y += 8;
#endif
}
y+=4; //small gap
//add all packages in this dir
for (p = availablepackages; p; p = p->next)
{
if (strncmp(p->category, info->pathprefix, prefixlen))
if (strncmp(p->category, pathprefix, prefixlen))
continue;
if ((p->flags & DPF_HIDDEN) && (p->arch || !(p->flags & DPF_ENABLED)))
continue;
// if (p->flags & DPF_TESTING) //hide testing updates
// if (!(p->flags & (DPF_ENABLED|DPF_MARKED|DPF_PRESENT))
// continue;
slash = strchr(p->category+prefixlen, '/');
if (slash)
{
Q_strncpyz(path, p->category, MAX_QPATH);
slash = strchr(path+prefixlen, '/');
if (slash)
*slash = '\0';
for (mo = m->options; mo; mo = mo->common.next)
if (mo->common.type == mt_button)
if (!strcmp(mo->button.text+1, path + prefixlen))
break;
if (!mo)
{
package_t *s;
menubutton_t *b;
for (s = availablepackages; s; s = s->next)
{
if (!strncmp(s->category, info->pathprefix, slash-path) || s->category[slash-path] != '/')
continue;
if (!(s->flags & DPF_ENABLED) != !(s->flags & DPF_MARKED))
break;
}
b = MC_AddConsoleCommand(m, 6*8, 170, y, va("%s%s", s?"!":" ", path+prefixlen), va("menu_download \"%s/\"", path));
y += 8;
if (!m->selecteditem)
m->selecteditem = (menuoption_t*)b;
}
}
else
if (!slash)
{
c = MC_AddCustom(m, 0, y, p, downloadablessequence);
c->draw = MD_Draw;
@ -3331,16 +3308,59 @@ static void MD_AddItemsToDownloadMenu(menu_t *m)
m->selecteditem = (menuoption_t*)c;
}
}
//and then try to add any subdirs...
for (p = availablepackages; p; p = p->next)
{
if (strncmp(p->category, pathprefix, prefixlen))
continue;
if ((p->flags & DPF_HIDDEN) && (p->arch || !(p->flags & DPF_ENABLED)))
continue;
slash = strchr(p->category+prefixlen, '/');
if (slash)
{
Q_strncpyz(path, p->category, MAX_QPATH);
slash = strchr(path+prefixlen, '/');
if (slash)
*slash = '\0';
for (mo = m->options; mo; mo = mo->common.next)
if (mo->common.type == mt_text/*mt_button*/)
if (!strcmp(mo->button.text, path + prefixlen))
break;
if (!mo)
{
package_t *s;
for (s = availablepackages; s; s = s->next)
{
if (!strncmp(s->category, pathprefix, slash-path) || s->category[slash-path] != '/')
continue;
if (!(s->flags & DPF_ENABLED) != !(s->flags & DPF_MARKED))
break;
}
y += 8;
MC_AddBufferedText(m, 48, 320, y, path+prefixlen, false, true);
y += 8;
Q_strncatz(path, "/", sizeof(path));
y = MD_AddItemsToDownloadMenu(m, y, path);
}
}
}
return y;
}
#include "shader.h"
static void MD_Download_UpdateStatus(struct menu_s *m)
{
dlmenu_t *info = m->data;
int i;
int i, y;
package_t *p;
unsigned int totalpackages=0, selectedpackages=0, addpackages=0, rempackages=0, downloads=0;
menuoption_t *si;
menubutton_t *b, *d;
menucustom_t *c;
if (info->downloadablessequence != downloadablessequence || !info->populated)
{
@ -3427,7 +3447,39 @@ static void MD_Download_UpdateStatus(struct menu_s *m)
}
info->populated = true;
MD_AddItemsToDownloadMenu(m);
MC_AddFrameStart(m, 48);
y = 48;
b = MC_AddCommand(m, 48, 170, y, "Apply", MD_ApplyDownloads);
b->rightalign = false;
b->common.tooltip = "Enable/Disable/Download/Delete packages to match any changes made (you will be prompted with a list of the changes that will be made).";
y+=8;
d = b = MC_AddCommand(m, 48, 170, y, "Back", MD_PopMenu);
b->rightalign = false;
y+=8;
#ifdef WEBCLIENT
b = MC_AddCommand(m, 48, 170, y, "Mark Updates", MD_MarkUpdatesButton);
b->rightalign = false;
b->common.tooltip = "Select any updated versions of packages that are already installed.";
y+=8;
#endif
b = MC_AddCommand(m, 48, 170, y, "Revert Updates", MD_RevertUpdates);
b->rightalign = false;
b->common.tooltip = "Reset selection to only those packages that are currently installed.";
y+=8;
#ifdef WEBCLIENT
c = MC_AddCustom(m, 48, y, p, 0);
c->draw = MD_AutoUpdate_Draw;
c->key = MD_AutoUpdate_Key;
c->common.width = 320;
c->common.height = 8;
y += 8;
#endif
y+=4; //small gap
MD_AddItemsToDownloadMenu(m, y, info->pathprefix);
if (!m->selecteditem)
m->selecteditem = (menuoption_t*)d;
m->cursoritem = (menuoption_t*)MC_AddWhiteText(m, 40, 0, m->selecteditem->common.posy, NULL, false);
MC_AddFrameEnd(m, 48);
}
si = m->mouseitem;

View File

@ -306,7 +306,9 @@ static qboolean MI_Selectable(menuoption_t *op)
return true;
case mt_picture:
return false;
case mt_childwindow:
case mt_framestart:
return false;
case mt_frameend:
return true;
case mt_box:
return false;
@ -329,42 +331,67 @@ static qboolean MI_Selectable(menuoption_t *op)
static qboolean M_MouseMoved(menu_t *menu)
{
int ypos = menu->ypos, framescroll = 0;
menuoption_t *option;
// if (menu->prev && !menu->exclusive)
// if (M_MouseMoved(menu->prev))
// return true;
if (bindingactive)
return true;
for(option = menu->options; option; option = option->common.next)
{
if (mousemoved && !bindingactive && !option->common.ishidden)
if (option->common.ishidden)
continue;
if (mousecursor_x > menu->xpos+option->common.posx-option->common.extracollide && mousecursor_x < menu->xpos+option->common.posx+option->common.width)
{
if (mousecursor_x > menu->xpos+option->common.posx-option->common.extracollide && mousecursor_x < menu->xpos+option->common.posx+option->common.width)
if (mousecursor_y > ypos+option->common.posy && mousecursor_y < ypos+option->common.posy+option->common.height)
{
if (mousecursor_y > menu->ypos+option->common.posy && mousecursor_y < menu->ypos+option->common.posy+option->common.height)
if (MI_Selectable(option))
{
if (MI_Selectable(option))
if (menu->mouseitem != option)
{
if (menu->mouseitem != option)
/* if (!option->common.noselectionsound && vid.activeapp)
{
/* if (!option->common.noselectionsound && vid.activeapp)
{
#ifdef HEXEN2
if (M_GameType() == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
if (M_GameType() == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
#endif
S_LocalSound ("misc/menu1.wav");
}
*/
menu->mouseitem = option;
menu->tooltiptime = realtime + 1;
MenuTooltipChange(menu, menu->mouseitem->common.tooltip);
S_LocalSound ("misc/menu1.wav");
}
// if (menu->cursoritem)
// menu->cursoritem->common.posy = menu->selecteditem->common.posy;
*/
menu->mouseitem = option;
menu->tooltiptime = realtime + 1;
MenuTooltipChange(menu, menu->mouseitem->common.tooltip);
}
// if (menu->cursoritem)
// menu->cursoritem->common.posy = menu->selecteditem->common.posy;
}
}
}
switch(option->common.type)
{
case mt_framestart:
ypos += framescroll;
framescroll = 0;
break;
case mt_frameend:
{
menuoption_t *opt2;
int maxy = option->frame.common.posy;
for (opt2 = option->common.next; opt2; opt2 = opt2->common.next)
{
if (opt2->common.posy + opt2->common.height > maxy)
maxy = opt2->common.posy + opt2->common.height;
}
maxy -= vid.height-8;
framescroll += option->frame.frac * maxy;
ypos -= option->frame.frac * maxy;
}
break;
}
}
return true;
}
@ -382,11 +409,67 @@ static void M_CheckMouseMove(void)
M_MouseMoved(topmenu);
}
static float M_DrawScrollbar(int x, int y, int width, int height, float frac, qboolean mgrabbed)
{
float unused = 0;
mpic_t *pic;
int knob=y;
R2D_ImageColours(1,1,1,1);
pic = R2D_SafeCachePic("scrollbars/slidebg.tga");
if (pic && R_GetShaderSizes(pic, NULL, NULL, false)>0)
{
unused = 8*2+64; //top+bottom are 8 pixels, knob is 64
R2D_ScalePic(x + width - 8, y+8, 8, height-16, pic);
pic = R2D_SafeCachePic("scrollbars/arrow_up.tga");
R2D_ScalePic(x + width - 8, y, 8, 8, pic);
pic = R2D_SafeCachePic("scrollbars/arrow_down.tga");
R2D_ScalePic(x + width - 8, y + height - 8, 8, 8, pic);
knob += 8;
knob += frac * (float)(height-(unused));
pic = R2D_SafeCachePic("scrollbars/slider.tga");
R2D_ScalePic(x + width - 8, knob, 8, 64, pic);
}
else
{
unused = width; //top+bottom are invisible, knob is square
R2D_ImageColours(0.1, 0.1, 0.2, 1.0);
R2D_FillBlock(x, y, width, height);
knob += frac * (height-unused);
R2D_ImageColours(0.35, 0.35, 0.55, 1.0);
R2D_FillBlock(x, knob, width, width);
R2D_ImageColours(1,1,1,1);
}
if (mgrabbed)
{
float my;
my = mousecursor_y - y;
my -= unused/2;
my /= height-unused;
if (my > 1)
my = 1;
if (my < 0)
my = 0;
frac = my;
}
return frac;
}
static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu)
{
int i;
mpic_t *p;
int pw,ph;
int framescroll = 0;
if (option && option->common.type == mt_box && !option->common.ishidden)
{
@ -394,17 +477,18 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
option = option->common.next;
}
if (menu == topmenu && menu->mouseitem)
for (; option; option = option->common.next)
{
float alphamax = 0.5, alphamin = 0.2;
R2D_ImageColours(.5,.4,0,(sin(realtime*2)+1)*0.5*(alphamax-alphamin)+alphamin);
R2D_FillBlock(xpos+menu->mouseitem->common.posx, ypos+menu->mouseitem->common.posy, menu->mouseitem->common.width, menu->mouseitem->common.height);
R2D_ImageColours(1,1,1,1);
}
if (option->common.ishidden)
continue;
while (option)
{
if (!option->common.ishidden)
if (menu == topmenu && menu->mouseitem == option)
{
float alphamax = 0.5, alphamin = 0.2;
R2D_ImageColours(.5,.4,0,(sin(realtime*2)+1)*0.5*(alphamax-alphamin)+alphamin);
R2D_FillBlock(xpos+menu->mouseitem->common.posx, ypos+menu->mouseitem->common.posy, menu->mouseitem->common.width, menu->mouseitem->common.height);
R2D_ImageColours(1,1,1,1);
}
switch(option->common.type)
{
case mt_menucursor:
@ -457,14 +541,66 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
p = R2D_SafeCachePic(option->picture.picturename);
if (R_GetShaderSizes(p, &pw, &ph, false)>0)
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width?option->common.width:pw, option->common.height?option->common.height:ph, p);
{
float scale = (option->common.height?option->common.height:20.0)/ph;
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width?option->common.width:(pw*scale), ph*scale, p);
}
break;
case mt_picture:
p = R2D_SafeCachePic(option->picture.picturename);
if (R_GetShaderSizes(p, NULL, NULL, false)>0) R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy, option->common.width, option->common.height, p);
break;
case mt_childwindow:
MenuDrawItems(xpos+option->common.posx, ypos+option->common.posy, ((menu_t *)option->custom.dptr)->options, (menu_t *)option->custom.dptr);
case mt_framestart:
ypos += framescroll;
framescroll = 0;
if (R2D_Flush)
R2D_Flush();
BE_Scissor(NULL);
break;
case mt_frameend:
{
srect_t srect;
menuoption_t *opt2;
extern qboolean keydown[];
int maxy = option->frame.common.posy;
option->frame.common.width = 16;
option->frame.common.posx = vid.width - option->frame.common.width - xpos;
option->frame.common.height = vid.height-8-maxy - ypos;
for (opt2 = option->common.next; opt2; opt2 = opt2->common.next)
{
if (opt2->common.posy + opt2->common.height > maxy)
maxy = opt2->common.posy + opt2->common.height;
}
maxy -= vid.height-8;
if (maxy < 0)
{
option->frame.mousedown = false;
option->frame.frac = 0;
option->frame.common.width = 0;
option->frame.common.height = 0;
}
else
{
if (!keydown[K_MOUSE1])
option->frame.mousedown = false;
option->frame.frac = M_DrawScrollbar(xpos+option->frame.common.posx, ypos+option->common.posy, option->frame.common.width, option->frame.common.height, option->frame.frac, option->frame.mousedown);
if (R2D_Flush)
R2D_Flush();
srect.x = 0;
srect.y = (float)(ypos+option->common.posy) / vid.height;
srect.width = 1;
srect.height = 1 - srect.y;
srect.dmin = -99999;
srect.dmax = 99999;
srect.y = (1-srect.y) - srect.height;
BE_Scissor(&srect);
framescroll += option->frame.frac * maxy;
ypos -= option->frame.frac * maxy;
}
}
break;
case mt_box:
Draw_TextBox(xpos+option->common.posx, ypos+option->common.posy, option->box.width, option->box.height);
@ -627,7 +763,6 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
Sys_Error("Bad item type\n");
break;
}
option = option->common.next;
}
}
@ -773,7 +908,7 @@ menubind_t *MC_AddBind(menu_t *menu, int cx, int bx, int y, const char *caption,
return n;
}
menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, char *picname)
menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, int height, char *picname)
{
char selname[MAX_QPATH];
menupicture_t *n;
@ -793,6 +928,7 @@ menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, char *picname
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = height;
n->picturename = (char *)(n+1);
strcpy(n->picturename, picname);
@ -1066,6 +1202,34 @@ menucheck_t *MC_AddCheckBox(menu_t *menu, int tx, int cx, int y, const char *tex
menu->options = (menuoption_t *)n;
return n;
}
menuframe_t *MC_AddFrameStart(menu_t *menu, int y)
{
menuframe_t *n = Z_Malloc(sizeof(menuframe_t));
n->common.type = mt_framestart;
n->common.iszone = true;
n->common.posx = 0;
n->common.posy = y;
n->common.height = 0;
n->common.width = 0;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menuframe_t *MC_AddFrameEnd(menu_t *menu, int y)
{
menuframe_t *n = Z_Malloc(sizeof(menuframe_t));
n->common.type = mt_frameend;
n->common.iszone = true;
n->common.posx = 0;
n->common.posy = y;
n->common.height = 0;
n->common.width = 0;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int tx, int cx, int y, const char *text, qboolean (*func) (menucheck_t *option, menu_t *menu, chk_set_t set), int bits)
{
menucheck_t *n = Z_Malloc(sizeof(menucheck_t)+strlen(text)+1);
@ -2021,6 +2185,7 @@ void M_Menu_Main_f (void)
{
if (R_GetShaderSizes(R2D_SafeCachePic("pics/m_main_quit"), NULL, NULL, true) > 0)
{
int itemheight = 32;
Key_Dest_Add(kdm_emenu);
mainm = M_CreateMenu(0);
@ -2029,19 +2194,19 @@ void M_Menu_Main_f (void)
MC_AddPicture(mainm, 0, 4, 38, 166, "pics/m_main_plaque");
MC_AddPicture(mainm, 0, 173, 36, 42, "pics/m_main_logo");
#ifndef CLIENTONLY
MC_AddSelectablePicture(mainm, 68, 13, "pics/m_main_game");
MC_AddSelectablePicture(mainm, 68, 13, itemheight, "pics/m_main_game");
#endif
MC_AddSelectablePicture(mainm, 68, 53, "pics/m_main_multiplayer");
MC_AddSelectablePicture(mainm, 68, 93, "pics/m_main_options");
MC_AddSelectablePicture(mainm, 68, 133, "pics/m_main_video");
MC_AddSelectablePicture(mainm, 68, 173, "pics/m_main_quit");
MC_AddSelectablePicture(mainm, 68, 53, itemheight, "pics/m_main_multiplayer");
MC_AddSelectablePicture(mainm, 68, 93, itemheight, "pics/m_main_options");
MC_AddSelectablePicture(mainm, 68, 133, itemheight, "pics/m_main_video");
MC_AddSelectablePicture(mainm, 68, 173, itemheight, "pics/m_main_quit");
#ifndef CLIENTONLY
b = MC_AddConsoleCommand (mainm, 68, 320, 13, "", "menu_single\n");
b->common.tooltip = "Singleplayer.";
mainm->selecteditem = (menuoption_t *)b;
b->common.width = 12*20;
b->common.height = 32;
b->common.height = itemheight;
#endif
b = MC_AddConsoleCommand (mainm, 68, 320, 53, "", "menu_multi\n");
b->common.tooltip = "Multiplayer.";
@ -2049,19 +2214,19 @@ void M_Menu_Main_f (void)
mainm->selecteditem = (menuoption_t *)b;
#endif
b->common.width = 12*20;
b->common.height = 32;
b->common.height = itemheight;
b = MC_AddConsoleCommand (mainm, 68, 320, 93, "", "menu_options\n");
b->common.tooltip = "Options.";
b->common.width = 12*20;
b->common.height = 32;
b->common.height = itemheight;
b = MC_AddConsoleCommand (mainm, 68, 320, 133, "", "menu_video\n");
b->common.tooltip = "Video Options.";
b->common.width = 12*20;
b->common.height = 32;
b->common.height = itemheight;
b = MC_AddConsoleCommand (mainm, 68, 320, 173, "", "menu_quit\n");
b->common.tooltip = "Quit to DOS.";
b->common.width = 12*20;
b->common.height = 32;
b->common.height = itemheight;
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 42, mainm->selecteditem->common.posy);
}

View File

@ -439,38 +439,34 @@ void M_Menu_Setup_f (void)
#ifdef Q2CLIENT
if (M_GameType() == MGT_QUAKE2) //quake2 main menu.
{
if (R2D_SafeCachePic("pics/m_banner_player_setup"))
static const char *modeloptions[] =
{
static const char *modeloptions[] =
{
"male",
"female",
NULL
};
mpic_t *p;
menucustom_t *cu;
Key_Dest_Add(kdm_emenu);
"male",
"female",
NULL
};
mpic_t *p;
menucustom_t *cu;
Key_Dest_Add(kdm_emenu);
menu = M_CreateMenu(sizeof(setupmenu_t));
info = menu->data;
// menu->key = MC_Main_Key;
menu = M_CreateMenu(sizeof(setupmenu_t));
info = menu->data;
// menu->key = MC_Main_Key;
MC_AddPicture(menu, 0, 4, 38, 166, "pics/m_main_plaque");
p = R2D_SafeCachePic("pics/m_main_logo");
if (!p)
return;
MC_AddPicture(menu, 0, 173, 36, 42, "pics/m_main_logo");
MC_AddPicture(menu, 0, 4, 38, 166, "pics/m_main_plaque");
MC_AddPicture(menu, 0, 173, 36, 42, "pics/m_main_logo");
menu->selecteditem = (menuoption_t*)
(info->nameedit = MC_AddEdit(menu, 64, 160, 40, "Your name", name.string));
(info->modeledit = MC_AddCvarCombo(menu, 64, 160,72, "model", &skin, (const char **)modeloptions, (const char **)modeloptions));
info->modeledit->selectedoption = !strncmp(skin.string, "female", 6);
cu = MC_AddCustom(menu, 64, 88+16, NULL, 0);
cu->draw = MSetupQ2_TransDraw;
cu->key = MSetupQ2_ChangeSkin;
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_player_setup");
menu->cursoritem = (menuoption_t*)MC_AddCursorSmall(menu, &resel, 54, 32);
}
menu->selecteditem = (menuoption_t*)
(info->nameedit = MC_AddEdit(menu, 64, 160, 40, "Your name", name.string));
(info->modeledit = MC_AddCvarCombo(menu, 64, 160,72, "model", &skin, (const char **)modeloptions, (const char **)modeloptions));
info->modeledit->selectedoption = !strncmp(skin.string, "female", 6);
cu = MC_AddCustom(menu, 64, 88+16, NULL, 0);
cu->draw = MSetupQ2_TransDraw;
cu->key = MSetupQ2_ChangeSkin;
menu->cursoritem = (menuoption_t*)MC_AddCursorSmall(menu, &resel, 54, 32);
return;
}
#endif

View File

@ -123,7 +123,6 @@ menu_t *M_Options_Title(int *y, int infosize)
{
case MGT_QUAKE2: //q2...
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_options");
*y += 32;
break;
#ifdef HEXEN2
case MGT_HEXEN2://h2
@ -325,6 +324,9 @@ void M_Menu_Options_f (void)
};
menu_t *menu = M_Options_Title(&y, 0);
static menuresel_t resel;
int framey = y;
MC_AddFrameStart(menu, framey);
y = MC_AddBulk(menu, &resel, bulk, 16, 216, y);
#ifdef PLUGINS
@ -348,6 +350,7 @@ void M_Menu_Options_f (void)
MC_AddCvarCombo(menu, 16, 216, y, "Use Hud Plugin", &plug_sbar, hudplugopts, hudplugvalues); y += 8;
}
#endif
MC_AddFrameEnd(menu, framey);
}
#ifndef __CYGWIN__
@ -667,7 +670,9 @@ void M_Menu_Audio_f (void)
MB_END()
};
static menuresel_t resel;
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 216, y);
MC_AddFrameEnd(menu, y);
}
#else
@ -764,7 +769,9 @@ void M_Menu_Particles_f (void)
static menuresel_t resel;
menu = M_Options_Title(&y, 0);
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 200, y);
MC_AddFrameEnd(menu, y);
}
const char *presetname[] =
@ -1202,7 +1209,9 @@ void M_Menu_FPS_f (void)
MB_EDITCVAR("Skybox", "r_skybox"),
MB_END()
};
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 216, y);
MC_AddFrameEnd(menu, y);
}
}
@ -1263,7 +1272,9 @@ void M_Menu_Render_f (void)
MB_END()
};
menu = M_Options_Title(&y, 0);
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 216, y);
MC_AddFrameEnd(menu, y);
}
#ifdef GLQUAKE
@ -1359,7 +1370,9 @@ void M_Menu_Textures_f (void)
};
menu_t *menu = M_Options_Title(&y, 0);
static menuresel_t resel;
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 216, y);
MC_AddFrameEnd(menu, y);
}
#endif
@ -1656,7 +1669,9 @@ void M_Menu_Lighting_f (void)
MB_END()
};
static menuresel_t resel;
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 216, y);
MC_AddFrameEnd(menu, y);
}
}
@ -2881,7 +2896,30 @@ void M_Menu_Video_f (void)
int y;
int resmodechoice, res2dmodechoice;
int reschoices[ASPECT_RATIOS], res2dchoices[ASPECT_RATIOS];
menu_t *menu = M_Options_Title(&y, sizeof(videomenuinfo_t));
menu_t *menu;
//not calling M_Options_Title because of quake2's different banner.
y = 32;
Key_Dest_Add(kdm_emenu);
menu = M_CreateMenu(sizeof(videomenuinfo_t));
switch(M_GameType())
{
case MGT_QUAKE2: //q2...
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_video");
break;
#ifdef HEXEN2
case MGT_HEXEN2://h2
MC_AddPicture(menu, 16, 0, 35, 176, "gfx/menu/hplaque.lmp");
MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title3.lmp");
y += 32;
break;
#endif
default: //q1
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/p_option.lmp");
break;
}
info = (videomenuinfo_t*)menu->data;
snprintf(current3dres, sizeof(current3dres), "Current: %ix%i", vid.pixelwidth, vid.pixelheight);
@ -2963,7 +3001,9 @@ void M_Menu_Video_f (void)
MB_END()
};
MC_AddFrameStart(menu, y);
MC_AddBulk(menu, &resel, bulk, 16, 200, y);
MC_AddFrameEnd(menu, y);
}
/*

View File

@ -89,7 +89,6 @@ void M_MenuS_Clear_f (void)
void M_MenuS_Script_f (void) //create a menu.
{
extern menu_t *topmenu;
int items;
menu_t *oldmenu;
char *alias = Cmd_Argv(1);

View File

@ -241,7 +241,18 @@ void M_Menu_Save_f (void)
menu->remove = M_Menu_LoadSave_UnloadShaders;
menu->reset = M_Menu_LoadSave_UnloadShaders;
MC_AddCenterPicture (menu, 4, 24, "gfx/p_save.lmp");
switch(M_GameType())
{
#ifdef Q2CLIENT
case MGT_QUAKE2:
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_save_game.pcx");
break;
#endif
default:
MC_AddCenterPicture(menu, 4, 24, "gfx/p_save.lmp");
break;
}
menu->cursoritem = (menuoption_t *)MC_AddRedText(menu, 8, 0, 32, NULL, false);
M_ScanSaves ();
@ -271,8 +282,18 @@ void M_Menu_Load_f (void)
menu->data = menu+1;
menu->remove = M_Menu_LoadSave_UnloadShaders;
menu->reset = M_Menu_LoadSave_UnloadShaders;
MC_AddCenterPicture(menu, 4, 24, "gfx/p_load.lmp");
switch(M_GameType())
{
#ifdef Q2CLIENT
case MGT_QUAKE2:
MC_AddCenterPicture(menu, 4, 24, "pics/m_banner_load_game.pcx");
break;
#endif
default:
MC_AddCenterPicture(menu, 4, 24, "gfx/p_load.lmp");
break;
}
M_ScanSaves ();

View File

@ -530,7 +530,7 @@ void M_Menu_Keys_f (void)
{
#ifdef Q2CLIENT
case MGT_QUAKE2:
//fixme: no art?
MC_AddCenterPicture(menu, 0, 60, "pics/m_banner_customize.pcx");
y = 48;
bindnames = q2bindnames;
break;
@ -606,13 +606,14 @@ void M_Menu_Keys_f (void)
return;
}
MC_AddFrameStart(menu, 48+8);
while (bindnames->name)
{
MC_AddBind(menu, 16, 170, y, bindnames->name, bindnames->command, NULL);
y += 8;
bindnames++;
}
MC_AddFrameEnd(menu, 48+8);
}
void M_UnbindCommand (const char *command)
@ -1479,12 +1480,11 @@ void M_Draw (int uimenu)
#endif
#ifndef NOBUILTINMENUS
{extern menu_t *topmenu;
if (topmenu)
{
M_Complex_Draw ();
stillactive = true;
}}
}
#endif
if (!stillactive)
Key_Dest_Remove(kdm_emenu);
@ -1497,7 +1497,12 @@ void M_Keydown (int key, int unicode)
if (topmenu)
{
if (key == K_MOUSE1) //mouse clicks are deferred until the release event. this is for touch screens and aiming.
menu_mousedown = true;
{
if (topmenu->mouseitem->common.type == mt_frameend)
topmenu->mouseitem->frame.mousedown = true;
else
menu_mousedown = true;
}
else if (key == K_LSHIFT || key == K_RSHIFT || key == K_LALT || key == K_RALT || key == K_LCTRL || key == K_RCTRL)
; //modifiers are sent on up events instead.
else

View File

@ -120,7 +120,8 @@ struct menu_s;
typedef enum {
mt_childwindow,
mt_framestart,
mt_frameend,
mt_button,
mt_qbuttonbigfont,
mt_hexen2buttonbigfont,
@ -243,6 +244,13 @@ typedef struct {
char *command;
} menubind_t;
typedef struct {
menucommon_t common;
qboolean mousedown;
float frac;
union menuoption_s *suboptions;
} menuframe_t;
typedef union menuoption_s {
menucommon_t common;
menubutton_t button;
@ -255,6 +263,7 @@ typedef union menuoption_s {
menubox_t box;
menucheck_t check;
menubind_t bind;
menuframe_t frame;
} menuoption_t;
typedef struct menutooltip_s {
@ -308,7 +317,7 @@ menutext_t *MC_AddWhiteText(menu_t *menu, int lhs, int rhs, int y, const char *t
menubind_t *MC_AddBind(menu_t *menu, int cx, int bx, int y, const char *caption, char *command, char *tooltip);
menubox_t *MC_AddBox(menu_t *menu, int x, int y, int width, int height);
menupicture_t *MC_AddPicture(menu_t *menu, int x, int y, int width, int height, char *picname);
menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, char *picname);
menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, int height, char *picname);
menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, int height, char *picname);
menupicture_t *MC_AddCursor(menu_t *menu, menuresel_t *resel, int x, int y);
menuoption_t *MC_AddCursorSmall(menu_t *menu, menuresel_t *reselection, int x, int y);
@ -326,6 +335,8 @@ menucombo_t *MC_AddCvarCombo(menu_t *menu, int tx, int cx, int y, const char *ca
menuedit_t *MC_AddEdit(menu_t *menu, int cx, int ex, int y, char *text, char *def);
menuedit_t *MC_AddEditCvar(menu_t *menu, int cx, int ex, int y, char *text, char *name, qboolean slim);
menucustom_t *MC_AddCustom(menu_t *menu, int x, int y, void *dptr, int dint);
menuframe_t *MC_AddFrameStart(menu_t *menu, int y); //call before items are added
menuframe_t *MC_AddFrameEnd(menu_t *menu, int y); //and call AFTER that stuff with the same y.
typedef struct menubulk_s {
menutype_t type;

View File

@ -22,8 +22,16 @@ extern unsigned int r2d_be_flags;
#define DRAWFLAG_2D (1u<<2)
#define DRAWFLAG_TWOSIDED 0x400
#define DRAWFLAG_LINES 0x800
static unsigned int PF_SelectDPDrawFlag(int flag)
static unsigned int PF_SelectDPDrawFlag(pubprogfuncs_t *prinst, int flag)
{
if (r_refdef.warndraw)
{
if (!*r_refdef.rt_destcolour[0].texname)
{
r_refdef.warndraw = false; //don't spam too much
PR_RunWarning(prinst, "Detected attempt to draw to framebuffer where framebuffer is not valid\n");
}
}
csqc_dp_lastwas3d = false; //for compat with dp's stupid beginpolygon
//flags:
@ -47,7 +55,7 @@ void QCBUILTIN PF_CL_drawfill (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
float alpha = G_FLOAT(OFS_PARM3);
int flag = prinst->callargc >= 5?G_FLOAT(OFS_PARM4):0;
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_FillBlock(pos[0], pos[1], size[0], size[1]);
r2d_be_flags = 0;
@ -473,7 +481,7 @@ void QCBUILTIN PF_CL_drawcolouredstring (pubprogfuncs_t *prinst, struct globalva
COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false);
str = buffer;
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &px, &py);
ipx = px;
R2D_ImageColours(r, g, b, alpha);
@ -542,7 +550,7 @@ void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
else
G_FLOAT(OFS_RETURN) = 1;
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
if ((size[0] < 0) ^ (size[1] < 0))
R2D_Image(pos[0]+size[0], pos[1]+size[1], -size[0], -size[1], 1, 1, 0, 0, p);
@ -588,7 +596,7 @@ void QCBUILTIN PF_CL_drawrotpic (pubprogfuncs_t *prinst, struct globalvars_s *pr
Vector2Set(tcoords[2], 1, 1);
Vector2Set(tcoords[3], 0, 1);
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, NULL, p);
r2d_be_flags = 0;
@ -613,7 +621,7 @@ void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
p = R2D_SafePicFromWad(picname);
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
if ((size[0] < 0) ^ (size[1] < 0))
R2D_Image(pos[0]+size[0], pos[1]+size[1], -size[0], -size[1], srcPos[0]+srcSize[0], srcPos[1]+srcSize[1], srcPos[0], srcPos[1], p);
@ -660,7 +668,7 @@ void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s
Vector2Set(tcoords[2], srcPos[0]+srcSize[0] , srcPos[1]+srcSize[1] );
Vector2Set(tcoords[3], srcPos[0] , srcPos[1]+srcSize[1] );
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, NULL, p);
r2d_be_flags = 0;
@ -836,7 +844,7 @@ void QCBUILTIN PF_CL_drawcharacter (pubprogfuncs_t *prinst, struct globalvars_s
if (chara < 32 && chara != '\t')
chara |= 0xe000;
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
Font_DrawScaleChar(x, y, CON_WHITEMASK, chara);
@ -866,7 +874,7 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s
return;
}
r2d_be_flags = PF_SelectDPDrawFlag(flag);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
@ -914,7 +922,7 @@ void QCBUILTIN PF_CL_drawline (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
"}\n"
"}\n");
r2d_be_flags = PF_SelectDPDrawFlag(flags);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flags);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Line(point1[0], point1[1], point2[0], point2[1], shader_draw_line);
R2D_ImageColours(1,1,1,1);
@ -2579,8 +2587,8 @@ qboolean MP_Init (void)
menuprogparms.ReadFile = MP_PRReadFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
menuprogparms.FileSize = MP_PRFileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
menuprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
menuprogparms.Printf = (void *)Con_Printf;//Con_Printf;//void (*printf) (char *, ...);
menuprogparms.Printf = (void *)Con_DPrintf;//Con_DPrintf;//void (*dprintf) (char *, ...);
menuprogparms.Printf = PR_Printf;//Con_Printf;//void (*printf) (char *, ...);
menuprogparms.DPrintf = PR_DPrintf;//Con_DPrintf;//void (*dprintf) (char *, ...);
menuprogparms.Sys_Error = Sys_Error;
menuprogparms.Abort = Menu_Abort;
menuprogparms.CheckHeaderCrc = Menu_CheckHeaderCrc;
@ -2915,6 +2923,8 @@ qboolean MP_Keydown(int key, int unicode, unsigned int devid)
PR_ExecuteProgram(menu_world.progs, mpfuncs.keydown);
result = true; //doesn't have a return value, so if the menu is set up for key events, all events are considered eaten.
}
if (R2D_Flush)
R2D_Flush();
inmenuprogs--;
return result;
}
@ -2954,6 +2964,8 @@ void MP_Keyup(int key, int unicode, unsigned int devid)
G_FLOAT(OFS_PARM1) = unicode;
PR_ExecuteProgram(menu_world.progs, mpfuncs.keyup);
}
if (R2D_Flush)
R2D_Flush();
inmenuprogs--;
}
@ -2973,6 +2985,8 @@ qboolean MP_MousePosition(float xabs, float yabs, unsigned int devid)
G_FLOAT(OFS_PARM2) = (yabs * vid.height) / vid.pixelheight;
G_FLOAT(OFS_PARM3) = devid;
PR_ExecuteProgram (menu_world.progs, mpfuncs.inputevent);
if (R2D_Flush)
R2D_Flush();
inmenuprogs--;
return G_FLOAT(OFS_RETURN);
}
@ -2992,6 +3006,8 @@ qboolean MP_MouseMove(float xdelta, float ydelta, unsigned int devid)
G_FLOAT(OFS_PARM2) = (ydelta * vid.height) / vid.pixelheight;
G_FLOAT(OFS_PARM3) = devid;
PR_ExecuteProgram (menu_world.progs, mpfuncs.inputevent);
if (R2D_Flush)
R2D_Flush();
inmenuprogs--;
return G_FLOAT(OFS_RETURN);
}
@ -3010,6 +3026,8 @@ qboolean MP_JoystickAxis(int axis, float value, unsigned int devid)
G_FLOAT(OFS_PARM2) = value;
G_FLOAT(OFS_PARM3) = devid;
PR_ExecuteProgram (menu_world.progs, mpfuncs.inputevent);
if (R2D_Flush)
R2D_Flush();
inmenuprogs--;
return G_FLOAT(OFS_RETURN);
}
@ -3040,6 +3058,8 @@ qboolean MP_Toggle(int mode)
G_FLOAT(OFS_PARM0) = mode;
PR_ExecuteProgram(menu_world.progs, mpfuncs.toggle);
}
if (R2D_Flush)
R2D_Flush();
inmenuprogs--;
return true;

View File

@ -308,6 +308,8 @@ typedef struct
qbyte areabits[MAX_MAP_AREA_BYTES];
vec4_t userdata[16]; /*for custom glsl*/
qboolean warndraw; /*buggy gamecode likes drawing outside of te drawing logic*/
} refdef_t;
extern refdef_t r_refdef;
@ -517,6 +519,7 @@ typedef struct
unsigned short *extents;
unsigned char *styles;
unsigned char *shifts;
unsigned char defaultshift;
} lightmapoverrides_t;
typedef struct bspx_header_s bspx_header_t;
void Mod_LoadLighting (struct model_s *loadmodel, bspx_header_t *bspx, qbyte *mod_base, lump_t *l, qboolean interleaveddeluxe, lightmapoverrides_t *overrides);

View File

@ -186,7 +186,7 @@ cvar_t r_part_rain = CVARFD ("r_part_rain", "0",
"Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects.");
cvar_t r_skyboxname = CVARFC ("r_skybox", "",
CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM, R_SkyBox_Changed);
cvar_t r_softwarebanding_cvar = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM|CVAR_RENDERERLATCH, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well).");
cvar_t r_softwarebanding_cvar = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM|CVAR_RENDERERLATCH|CVAR_ARCHIVE, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well).");
qboolean r_softwarebanding;
cvar_t r_speeds = CVAR ("r_speeds", "0");
cvar_t r_stainfadeammount = CVAR ("r_stainfadeammount", "1");

View File

@ -176,17 +176,17 @@ static int Sbar_BottomColour(player_info_t *p)
#endif
//Draws a pre-marked-up string with no width limit. doesn't support new lines
void Draw_ExpandedString(float x, float y, conchar_t *str)
void Draw_ExpandedString(struct font_s *font, float x, float y, conchar_t *str)
{
int px, py;
unsigned int codeflags, codepoint;
Font_BeginString(font_default, x, y, &px, &py);
Font_BeginString(font, x, y, &px, &py);
while(*str)
{
str = Font_Decode(str, &codeflags, &codepoint);
px = Font_DrawChar(px, py, codeflags, codepoint);
}
Font_EndString(font_default);
Font_EndString(font);
}
//Draws a marked-up string using the regular char set with no width limit. doesn't support new lines
@ -195,7 +195,7 @@ void Draw_FunString(float x, float y, const void *str)
conchar_t buffer[2048];
COM_ParseFunString(CON_WHITEMASK, str, buffer, sizeof(buffer), false);
Draw_ExpandedString(x, y, buffer);
Draw_ExpandedString(font_default, x, y, buffer);
}
//Draws a marked up string using the alt char set (legacy mode would be |128)
void Draw_AltFunString(float x, float y, const void *str)
@ -203,7 +203,7 @@ void Draw_AltFunString(float x, float y, const void *str)
conchar_t buffer[2048];
COM_ParseFunString(CON_ALTMASK, str, buffer, sizeof(buffer), false);
Draw_ExpandedString(x, y, buffer);
Draw_ExpandedString(font_default, x, y, buffer);
}
//Draws a marked up string no wider than $width virtual pixels.
@ -285,7 +285,31 @@ static char *q2sb_nums[2][11] =
static mpic_t *Sbar_Q2CachePic(char *name)
{
return R2D_SafeCachePic(va("pics/%s.pcx", name));
mpic_t *pic = R2D_SafeCachePic(va("pics/%s.pcx", name));
#if defined(IMAGEFMT_PCX)
int xmin,ymin,swidth,sheight;
size_t length;
pcx_t *pcx = (pcx_t*)COM_LoadTempFile(va("pics/%s.pcx", name), 0, &length);
if (pcx && length >= sizeof(*pcx))
{
xmin = LittleShort(pcx->xmin);
ymin = LittleShort(pcx->ymin);
swidth = LittleShort(pcx->xmax)-xmin+1;
sheight = LittleShort(pcx->ymax)-ymin+1;
if (pcx->manufacturer == 0x0a
&& pcx->version == 5
&& pcx->encoding == 1
&& pcx->bits_per_pixel == 8
&& swidth <= 1024
&& sheight <= 1024)
{
pic->width = swidth;
pic->height = sheight;
}
}
#endif
return pic;
}
#define ICON_WIDTH 24
@ -1210,7 +1234,7 @@ void Sbar_DrawString (float x, float y, char *str)
void Sbar_DrawExpandedString (float x, float y, conchar_t *str)
{
Draw_ExpandedString (sbar_rect.x + x /*+ ((sbar_rect.width - 320)>>1) */, sbar_rect.y + y+ sbar_rect.height-SBAR_HEIGHT, str);
Draw_ExpandedString (font_default, sbar_rect.x + x /*+ ((sbar_rect.width - 320)>>1) */, sbar_rect.y + y+ sbar_rect.height-SBAR_HEIGHT, str);
}
void Draw_TinyString (float x, float y, const qbyte *str)

View File

@ -257,6 +257,7 @@ 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*/
void Font_Transform(float vx, float vy, int *px, int *py);
int Font_CharHeight(void);
float Font_CharVHeight(struct font_s *font);
float Font_CharScaleHeight(void);
int Font_CharWidth(unsigned int charflags, unsigned int codepoint);
float Font_CharScaleWidth(unsigned int charflags, unsigned int codepoint);

View File

@ -1750,6 +1750,7 @@ extern sounddriver_t DSOUND_Output;
sounddriver_t SDL_Output;
#ifdef __linux__
sounddriver_t ALSA_Output;
sounddriver_t Pulse_Output;
#endif
sounddriver_t OSS_Output;
#ifdef AVAIL_OPENAL
@ -1794,11 +1795,12 @@ static sounddriver_t *outputdrivers[] =
&WASAPI_Output, //this is last, so that we can default to exclusive. woot.
#endif
&SDL_Output, //prefered on linux
&SDL_Output, //prefered on linux. distros can ensure that its configured correctly.
#ifdef __linux__
&ALSA_Output, //pure shite
&Pulse_Output, //wasteful, and availability generally means Alsa is broken/defective.
&ALSA_Output, //pure shite, and availability generally means OSS is broken/defective.
#endif
&OSS_Output, //good, but not likely to work any more on linux (unlike every other unix system with a decent opengl driver)
&OSS_Output, //good for low latency audio, but not likely to work any more on linux (unlike every other unix system with a decent opengl driver)
#ifdef __DJGPP__
&SBLASTER_Output, //zomgwtfdos?
#endif

View File

@ -1701,7 +1701,7 @@ static qboolean SCR_VRectForPlayer(vrect_t *vrect, int pnum, unsigned maxseats)
return pnum < w*h;
}
void Draw_ExpandedString(float x, float y, conchar_t *str);
void Draw_ExpandedString(struct font_s *font, float x, float y, conchar_t *str);
static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
{
@ -1753,6 +1753,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
&tp_name_lg
};
#endif
struct font_s *font = font_default;
VectorCopy(org, tagcenter);
tagcenter[2] += 32;
@ -1805,7 +1806,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
{
y -= 8;
len = COM_ParseFunString(textflags, pname, buffer, sizeof(buffer), false) - buffer;
Draw_ExpandedString(x - len*4, y, buffer);
Draw_ExpandedString(font, x - len*4, y, buffer);
}
if (!haveinfo)
@ -1887,10 +1888,10 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
if (len && (buffer[0] & CON_CHARMASK) == '{' && (buffer[len-1] & CON_CHARMASK) == '}')
{ //these are often surrounded by {} to make them white in chat messages, and recoloured.
buffer[len-1] = 0;
Draw_ExpandedString(x + barwidth*0.5 + 4, y, buffer+1);
Draw_ExpandedString(font, x + barwidth*0.5 + 4, y, buffer+1);
}
else
Draw_ExpandedString(x + barwidth*0.5 + 4, y, buffer);
Draw_ExpandedString(font, x + barwidth*0.5 + 4, y, buffer);
}
}
#else
@ -1915,8 +1916,40 @@ void R_DrawNameTags(void)
if (r_projection.ival) //we don't actually know how to transform the points unless the projection is coded in advance. and it isn't.
return;
if (cls.protocol == CP_QUAKE2)
return; //FIXME: q2 has its own ent logic, which messes stuff up here.
#if defined(CSQC_DAT) || !defined(CLIENTONLY)
if (r_showshaders.ival && cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED)
{
trace_t trace;
char *str;
vec3_t targ;
vec2_t scale = {12,12};
msurface_t *surf;
VectorMA(r_refdef.vieworg, 8192, vpn, targ);
//FIXME: should probably do a general trace, to hit (networked) submodels too
cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace);
surf = Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos);
if (surf)
{
shader_t *shader = surf->texinfo->texture->shader;
char fname[MAX_QPATH];
char *body = shader?Shader_GetShaderBody(shader, fname, countof(fname)):NULL;
if (body)
{
// Q_snprintfz(fname, sizeof(fname), "<default shader>");
str = va("^2%s^7\n%s\n{%s\n", fname, surf->texinfo->texture->name, body);
Z_Free(body);
}
else
str = va("hit '%s'", surf->texinfo->texture->name);
}
else
str = "hit nothing";
R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_console, scale);
}
else
#endif
if (r_showfields.ival)
{
@ -1982,6 +2015,56 @@ void R_DrawNameTags(void)
}
}
}
#ifdef Q2SERVER //not enough fields for it to really be worth it.
if (w == &sv.world && svs.gametype == GT_QUAKE2 && ge)
{
struct q2edict_s *e;
int best = 0;
float bestscore = 0, score = 0;
for (i = 1; i < ge->num_edicts; i++)
{
e = &ge->edicts[i];
if (!e->inuse)
continue;
VectorInterpolate(e->mins, 0.5, e->maxs, org);
VectorAdd(org, e->s.origin, org);
VectorSubtract(org, r_refdef.vieworg, diff);
if (DotProduct(diff, diff) < 16*16)
continue; //ignore stuff too close(like the player themselves)
VectorNormalize(diff);
score = DotProduct(diff, vpn);// r_refdef.viewaxis[0]);
if (score > bestscore)
{
int hitent;
vec3_t imp;
if (CL_TraceLine(r_refdef.vieworg, org, imp, NULL, &hitent)>=1 || hitent == i)
{
best = i;
bestscore = score;
}
}
}
if (best)
{
e = &ge->edicts[best];
VectorInterpolate(e->mins, 0.5, e->maxs, org);
VectorAdd(org, e->s.origin, org);
if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y))
{
char *entstr = va("entity %i {\n\tmodelindex %i\n\torigin \"%f %f %f\"\n}\n", e->s.number, e->s.modelindex, e->s.origin[0], e->s.origin[1], e->s.origin[2]);
if (entstr)
{
vec2_t scale = {8,8};
int x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
int y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_console, scale);
}
}
}
}
else
#endif
if (w && w->progs)
{
int best = 0;
@ -2036,36 +2119,8 @@ void R_DrawNameTags(void)
}
}
#if defined(CSQC_DAT) || !defined(CLIENTONLY)
if (r_showshaders.ival && cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED)
{
trace_t trace;
char *str;
vec3_t targ;
vec2_t scale = {12,12};
msurface_t *surf;
VectorMA(r_refdef.vieworg, 8192, vpn, targ);
cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace);
surf = Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos);
if (surf)
{
shader_t *shader = surf->texinfo->texture->shader;
char fname[MAX_QPATH];
char *body = shader?Shader_GetShaderBody(shader, fname, countof(fname)):NULL;
if (body)
{
str = va("%s:\n%s\n{%s\n", fname, surf->texinfo->texture->name, body);
Z_Free(body);
}
else
str = va("hit '%s'", surf->texinfo->texture->name);
}
else
str = "hit nothing";
R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_console, scale);
}
#endif
if (cls.protocol == CP_QUAKE2)
return; //FIXME: q2 has its own ent logic, which messes stuff up here.
if (((!r_refdef.playerview->spectator && !cls.demoplayback) || !scr_autoid.ival) && (!cl.teamplay || !scr_autoid_team.ival))
return;

View File

@ -10,6 +10,8 @@
#endif
#endif
//#include <x86intrin.h>
//small helper to aid compiling.
#if defined(SKELETALMODELS) || defined(MD3MODELS)
#define SKELORTAGS

View File

@ -6466,12 +6466,16 @@ void FS_RegisterDefaultFileSystems(void)
FS_RegisterFileSystemType(NULL, "PAK", FSPAK_LoadArchive, true);
#endif
#endif
FS_RegisterFileSystemType(NULL, "pk3dir", VFSOS_OpenPath, true);
FS_RegisterFileSystemType(NULL, "pk3dir", VFSOS_OpenPath, true); //used for git repos or whatever, to make packaging easier
#ifdef PACKAGE_PK3
FS_RegisterFileSystemType(NULL, "pk3", FSZIP_LoadArchive, true);
FS_RegisterFileSystemType(NULL, "pk4", FSZIP_LoadArchive, true);
FS_RegisterFileSystemType(NULL, "apk", FSZIP_LoadArchive, false);
FS_RegisterFileSystemType(NULL, "zip", FSZIP_LoadArchive, false);
FS_RegisterFileSystemType(NULL, "pk3", FSZIP_LoadArchive, true); //quake3's extension for zips
FS_RegisterFileSystemType(NULL, "pk4", FSZIP_LoadArchive, true); //quake4's extension for zips...
#ifdef Q2CLIENT
FS_RegisterFileSystemType(NULL, "pkz", FSZIP_LoadArchive, true); //q2pro uses a different extension
FS_RegisterFileSystemType(NULL, "pkx", FSZIP_LoadArchive, true); //q2xp naturally uses a different extension too... you'll be glad to know that yq2 uses pk3 instead. yay consistency - every engine uses something different!
#endif
FS_RegisterFileSystemType(NULL, "apk", FSZIP_LoadArchive, false); //android package
FS_RegisterFileSystemType(NULL, "zip", FSZIP_LoadArchive, false); //regular zip file (don't automatically read from these, because it gets messy)
FS_RegisterFileSystemType(NULL, "exe", FSZIP_LoadArchive, false); //for self-extracting zips.
#endif
#ifdef PACKAGE_VPK

View File

@ -1538,7 +1538,7 @@ Mod_LoadFaces
=================
*/
#ifndef SERVERONLY
static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, qboolean lightofsisdouble)
static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, qboolean lightofsisdouble, lightmapoverrides_t *overrides)
{
dsface_t *in;
msurface_t *out;
@ -1549,13 +1549,18 @@ static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, qboo
unsigned short lmshift, lmscale;
char buf[64];
lmscale = atoi(Mod_ParseWorldspawnKey(mod, "lightmap_scale", buf, sizeof(buf)));
if (!lmscale)
lmshift = LMSHIFT_DEFAULT;
if (overrides->offsets)
lmshift = overrides->defaultshift;
else
{
for(lmshift = 0; lmscale > 1; lmshift++)
lmscale >>= 1;
lmscale = atoi(Mod_ParseWorldspawnKey(mod, "lightmap_scale", buf, sizeof(buf)));
if (!lmscale)
lmshift = LMSHIFT_DEFAULT;
else
{
for(lmshift = 0; lmscale > 1; lmshift++)
lmscale >>= 1;
}
}
in = (void *)(mod_base + l->fileofs);
@ -1602,14 +1607,25 @@ static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, qboo
}
#endif
out->lmshift = lmshift;
if (overrides->shifts)
out->lmshift = overrides->shifts[surfnum];
else
out->lmshift = lmshift;
CalcSurfaceExtents (mod, out);
if (overrides->extents)
{
out->extents[0] = overrides->extents[surfnum*2+0];
out->extents[1] = overrides->extents[surfnum*2+1];
}
// lighting info
for (i=0 ; i<MAXQ1LIGHTMAPS ; i++)
out->styles[i] = in->styles[i];
i = LittleLong(in->lightofs);
if (overrides->offsets)
i = overrides->offsets[surfnum];
else
i = LittleLong(in->lightofs);
if (i == -1)
out->samples = NULL;
else if (lightofsisdouble)
@ -1629,6 +1645,11 @@ static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, qboo
}
}
if (overrides->extents)
{
for (i=0 ; i<MAXQ1LIGHTMAPS ; i++)
out->styles[i] = overrides->extents[surfnum*4+i];
}
}
return true;
@ -4412,48 +4433,52 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
break;
#ifndef SERVERONLY
default:
// load into heap
noerrors = noerrors && Mod_LoadVertexes (mod, mod_base, &header.lumps[Q2LUMP_VERTEXES]);
if (header.version == BSPVERSION_Q2W)
/*noerrors = noerrors &&*/ Mod_LoadVertexNormals(mod, mod_base, &header.lumps[19]);
noerrors = noerrors && Mod_LoadEdges (mod, mod_base, &header.lumps[Q2LUMP_EDGES], false);
noerrors = noerrors && Mod_LoadSurfedges (mod, mod_base, &header.lumps[Q2LUMP_SURFEDGES]);
if (noerrors)
Mod_LoadLighting (mod, bspx, mod_base, &header.lumps[Q2LUMP_LIGHTING], header.version == BSPVERSION_Q2W, NULL);
noerrors = noerrors && CModQ2_LoadSurfaces (mod, mod_base, &header.lumps[Q2LUMP_TEXINFO]);
noerrors = noerrors && CModQ2_LoadPlanes (mod, mod_base, &header.lumps[Q2LUMP_PLANES]);
noerrors = noerrors && CModQ2_LoadTexInfo (mod, mod_base, &header.lumps[Q2LUMP_TEXINFO], loadname);
if (noerrors)
Mod_LoadEntities (mod, mod_base, &header.lumps[Q2LUMP_ENTITIES]);
noerrors = noerrors && CModQ2_LoadFaces (mod, mod_base, &header.lumps[Q2LUMP_FACES], header.version == BSPVERSION_Q2W);
noerrors = noerrors && Mod_LoadMarksurfaces (mod, mod_base, &header.lumps[Q2LUMP_LEAFFACES], false);
noerrors = noerrors && CModQ2_LoadVisibility (mod, mod_base, &header.lumps[Q2LUMP_VISIBILITY]);
noerrors = noerrors && CModQ2_LoadBrushSides (mod, mod_base, &header.lumps[Q2LUMP_BRUSHSIDES]);
noerrors = noerrors && CModQ2_LoadBrushes (mod, mod_base, &header.lumps[Q2LUMP_BRUSHES]);
noerrors = noerrors && CModQ2_LoadLeafBrushes (mod, mod_base, &header.lumps[Q2LUMP_LEAFBRUSHES]);
noerrors = noerrors && CModQ2_LoadLeafs (mod, mod_base, &header.lumps[Q2LUMP_LEAFS]);
noerrors = noerrors && CModQ2_LoadNodes (mod, mod_base, &header.lumps[Q2LUMP_NODES]);
noerrors = noerrors && CModQ2_LoadSubmodels (mod, mod_base, &header.lumps[Q2LUMP_MODELS]);
noerrors = noerrors && CModQ2_LoadAreas (mod, mod_base, &header.lumps[Q2LUMP_AREAS]);
noerrors = noerrors && CModQ2_LoadAreaPortals (mod, mod_base, &header.lumps[Q2LUMP_AREAPORTALS]);
if (!noerrors)
{
return NULL;
}
lightmapoverrides_t overrides = {0};
overrides.defaultshift = LMSHIFT_DEFAULT;
// load into heap
noerrors = noerrors && Mod_LoadVertexes (mod, mod_base, &header.lumps[Q2LUMP_VERTEXES]);
if (header.version == BSPVERSION_Q2W)
/*noerrors = noerrors &&*/ Mod_LoadVertexNormals(mod, mod_base, &header.lumps[19]);
noerrors = noerrors && Mod_LoadEdges (mod, mod_base, &header.lumps[Q2LUMP_EDGES], false);
noerrors = noerrors && Mod_LoadSurfedges (mod, mod_base, &header.lumps[Q2LUMP_SURFEDGES]);
if (noerrors)
Mod_LoadLighting (mod, bspx, mod_base, &header.lumps[Q2LUMP_LIGHTING], header.version == BSPVERSION_Q2W, &overrides);
noerrors = noerrors && CModQ2_LoadSurfaces (mod, mod_base, &header.lumps[Q2LUMP_TEXINFO]);
noerrors = noerrors && CModQ2_LoadPlanes (mod, mod_base, &header.lumps[Q2LUMP_PLANES]);
noerrors = noerrors && CModQ2_LoadTexInfo (mod, mod_base, &header.lumps[Q2LUMP_TEXINFO], loadname);
if (noerrors)
Mod_LoadEntities (mod, mod_base, &header.lumps[Q2LUMP_ENTITIES]);
noerrors = noerrors && CModQ2_LoadFaces (mod, mod_base, &header.lumps[Q2LUMP_FACES], header.version == BSPVERSION_Q2W, &overrides);
noerrors = noerrors && Mod_LoadMarksurfaces (mod, mod_base, &header.lumps[Q2LUMP_LEAFFACES], false);
noerrors = noerrors && CModQ2_LoadVisibility (mod, mod_base, &header.lumps[Q2LUMP_VISIBILITY]);
noerrors = noerrors && CModQ2_LoadBrushSides (mod, mod_base, &header.lumps[Q2LUMP_BRUSHSIDES]);
noerrors = noerrors && CModQ2_LoadBrushes (mod, mod_base, &header.lumps[Q2LUMP_BRUSHES]);
noerrors = noerrors && CModQ2_LoadLeafBrushes (mod, mod_base, &header.lumps[Q2LUMP_LEAFBRUSHES]);
noerrors = noerrors && CModQ2_LoadLeafs (mod, mod_base, &header.lumps[Q2LUMP_LEAFS]);
noerrors = noerrors && CModQ2_LoadNodes (mod, mod_base, &header.lumps[Q2LUMP_NODES]);
noerrors = noerrors && CModQ2_LoadSubmodels (mod, mod_base, &header.lumps[Q2LUMP_MODELS]);
noerrors = noerrors && CModQ2_LoadAreas (mod, mod_base, &header.lumps[Q2LUMP_AREAS]);
noerrors = noerrors && CModQ2_LoadAreaPortals (mod, mod_base, &header.lumps[Q2LUMP_AREAPORTALS]);
if (!noerrors)
{
return NULL;
}
#ifndef CLIENTONLY
mod->funcs.FatPVS = Q23BSP_FatPVS;
mod->funcs.EdictInFatPVS = Q23BSP_EdictInFatPVS;
mod->funcs.FindTouchedLeafs = Q23BSP_FindTouchedLeafs;
mod->funcs.FatPVS = Q23BSP_FatPVS;
mod->funcs.EdictInFatPVS = Q23BSP_EdictInFatPVS;
mod->funcs.FindTouchedLeafs = Q23BSP_FindTouchedLeafs;
#endif
mod->funcs.LightPointValues = GLQ2BSP_LightPointValues;
mod->funcs.StainNode = GLR_Q2BSP_StainNode;
mod->funcs.MarkLights = Q2BSP_MarkLights;
mod->funcs.ClusterPVS = CM_ClusterPVS;
mod->funcs.ClusterForPoint = CM_PointCluster;
mod->funcs.PointContents = Q2BSP_PointContents;
mod->funcs.NativeTrace = CM_NativeTrace;
mod->funcs.NativeContents = CM_NativeContents;
mod->funcs.LightPointValues = GLQ2BSP_LightPointValues;
mod->funcs.StainNode = GLR_Q2BSP_StainNode;
mod->funcs.MarkLights = Q2BSP_MarkLights;
mod->funcs.ClusterPVS = CM_ClusterPVS;
mod->funcs.ClusterForPoint = CM_PointCluster;
mod->funcs.PointContents = Q2BSP_PointContents;
mod->funcs.NativeTrace = CM_NativeTrace;
mod->funcs.NativeContents = CM_NativeContents;
}
break;
#endif
}

View File

@ -2154,13 +2154,81 @@ void Plug_CloseAll_f(void)
}
}
int QDECL Plug_List_Print(const char *fname, qofs_t fsize, time_t modtime, void *parm, searchpathfuncs_t *spath)
{
plugin_t *plug;
char plugname[MAX_QPATH];
//lots of awkward logic so we hide modules for other cpus.
size_t nl = strlen(fname);
size_t u;
const char *knownarch[] =
{
"x32", "x64", "amd64", "x86", //various x86 ABIs
"arm", "arm64", "armhf", //various arm ABIs
"ppc", "unk", //various misc ABIs
};
if (nl >= strlen(ARCH_DL_POSTFIX) && !Q_strcasecmp(fname+nl-strlen(ARCH_DL_POSTFIX), ARCH_DL_POSTFIX))
{
nl -= strlen(ARCH_DL_POSTFIX);
for (u = 0; u < countof(knownarch); u++)
{
size_t al = strlen(knownarch[u]);
if (!Q_strncasecmp(fname+nl-al, knownarch[u], al))
{
nl -= al;
break;
}
}
if (u == countof(knownarch) || !Q_strcasecmp(knownarch[u], ARCH_CPU_POSTFIX))
{
if (nl > sizeof(plugname)-1)
nl = sizeof(plugname)-1;
if (nl>0&&fname[nl] == '_')
nl--; //ignore the _ before the ABI name.
memcpy(plugname, fname, nl);
plugname[nl] = 0;
//don't bother printing it if its already loaded.
for (plug = plugs; plug; plug = plug->next)
{
const char *existing = VM_GetFilename(plug->vm);
if (!Q_strncasecmp(existing, parm, strlen(parm)) && !Q_strcasecmp(existing+strlen(parm), fname))
return true;
}
Con_Printf("^[%s%s\\type\\plug_load %s\\^]: not loaded\n", (const char*)parm, fname, plugname+((!Q_strncasecmp(plugname,"fteplug_", 8))?8:0));
}
}
return true;
}
void Plug_List_f(void)
{
char binarypath[MAX_OSPATH];
char rootpath[MAX_OSPATH];
unsigned int u;
char *mssuck;
plugin_t *plug;
for (plug = plugs; plug; plug = plug->next)
{
VM_PrintInfo(plug->vm);
}
if (FS_NativePath("", FS_BINARYPATH, binarypath, sizeof(binarypath)))
{
while ((mssuck=strchr(binarypath, '\\')))
*mssuck = '/';
Sys_EnumerateFiles(binarypath, "fteplug_*" ARCH_DL_POSTFIX, Plug_List_Print, binarypath, NULL);
}
if (FS_NativePath("", FS_ROOT, rootpath, sizeof(rootpath)))
{
while ((mssuck=strchr(rootpath, '\\')))
*mssuck = '/';
if (strcmp(binarypath, rootpath))
Sys_EnumerateFiles(rootpath, "fteplug_*" ARCH_DL_POSTFIX, Plug_List_Print, rootpath, NULL);
}
for (u = 0; staticplugins[u].name; u++)
Plug_List_Print(staticplugins[u].name, 0, 0, "", NULL);
}
void Plug_Shutdown(qboolean preliminary)

View File

@ -250,7 +250,7 @@ static qboolean PM_TransformedHullCheck (model_t *model, framestate_t *framestat
return false;
}
Q1BSP_RecursiveHullCheck (&box_hull, box_hull.firstclipnode, 0, 1, start_l, end_l, trace);
Q1BSP_RecursiveHullCheck (&box_hull, box_hull.firstclipnode, start_l, end_l, MASK_PLAYERSOLID, trace);
}
trace->endpos[0] += origin[0];

View File

@ -720,6 +720,27 @@ static int Q1_HullPointContents (hull_t *hull, int num, vec3_t p)
#define DIST_EPSILON (0.03125)
#if 1
static const q1toftecontents[] =
{
0,//EMPTY
FTECONTENTS_SOLID,//SOLID
FTECONTENTS_WATER,//WATER
FTECONTENTS_SLIME,//SLIME
FTECONTENTS_LAVA,//LAVA
FTECONTENTS_SKY,//SKY
FTECONTENTS_SOLID,//STRIPPED
FTECONTENTS_PLAYERCLIP,//CLIP
Q2CONTENTS_CURRENT_0,//FLOW_1
Q2CONTENTS_CURRENT_90,//FLOW_2
Q2CONTENTS_CURRENT_180,//FLOW_3
Q2CONTENTS_CURRENT_270,//FLOW_4
Q2CONTENTS_CURRENT_UP,//FLOW_5
Q2CONTENTS_CURRENT_DOWN,//FLOW_6
Q2CONTENTS_WINDOW,//TRANS
FTECONTENTS_LADDER,//LADDER
};
enum
{
rht_solid,
@ -728,6 +749,7 @@ enum
};
struct rhtctx_s
{
unsigned int checkcontents;
vec3_t start, end;
mclipnode_t *clipnodes;
mplane_t *planes;
@ -746,9 +768,11 @@ reenter:
if (num < 0)
{
unsigned int c = q1toftecontents[-1-num];
/*hit a leaf*/
if (num == Q1CONTENTS_SOLID)
if (c & ctx->checkcontents)
{
trace->contents = c;
if (trace->allsolid)
trace->startsolid = true;
return rht_solid;
@ -756,10 +780,10 @@ reenter:
else
{
trace->allsolid = false;
if (num == Q1CONTENTS_EMPTY)
trace->inopen = true;
else
if (c & FTECONTENTS_FLUID)
trace->inwater = true;
else
trace->inopen = true;
return rht_empty;
}
}
@ -813,9 +837,11 @@ reenter:
if (midf > p2f) midf = p2f;
VectorInterpolate(ctx->start, midf, ctx->end, mid);
//check the near side
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side], p1f, midf, p1, mid, trace);
if (rht != rht_empty && !trace->allsolid)
return rht;
//check the far side
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side^1], midf, p2f, mid, p2, trace);
if (rht != rht_solid)
return rht;
@ -847,24 +873,25 @@ reenter:
return rht_impact;
}
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, unsigned int hitcontents, trace_t *trace)
{
if (VectorEquals(p1, p2))
{
/*points cannot cross planes, so do it faster*/
switch(Q1_HullPointContents(hull, num, p1))
{
case Q1CONTENTS_SOLID:
int q1 = Q1_HullPointContents(hull, num, p1);
unsigned int c = q1toftecontents[-1-q1];
trace->contents = c;
if (c & hitcontents)
trace->startsolid = true;
break;
case Q1CONTENTS_EMPTY:
trace->allsolid = false;
trace->inopen = true;
break;
default:
else if (c & FTECONTENTS_FLUID)
{
trace->allsolid = false;
trace->inwater = true;
break;
}
else
{
trace->allsolid = false;
trace->inopen = true;
}
return true;
}
@ -875,7 +902,8 @@ qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f,
VectorCopy(p2, ctx.end);
ctx.clipnodes = hull->clipnodes;
ctx.planes = hull->planes;
return Q1BSP_RecursiveHullTrace(&ctx, num, p1f, p2f, p1, p2, trace) != rht_impact;
ctx.checkcontents = hitcontents;
return Q1BSP_RecursiveHullTrace(&ctx, num, 0, 1, p1, p2, trace) != rht_impact;
}
}
@ -1576,7 +1604,6 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, framestate_t *framestate,
traceinfo.solidcontents = hitcontentsmask;
Q1BSP_RecursiveBrushCheck(&traceinfo, model->rootnode, 0, 1, start, end);
memcpy(trace, &traceinfo.trace, sizeof(trace_t));
trace->contents = FTECONTENTS_SOLID;
if (trace->fraction < 1)
{
float d1 = DotProduct(start, trace->plane.normal) - trace->plane.dist;
@ -1614,8 +1641,7 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, framestate_t *framestate,
end_l[0] = DotProduct(tmp, axis[0]);
end_l[1] = DotProduct(tmp, axis[1]);
end_l[2] = DotProduct(tmp, axis[2]);
trace->contents = FTECONTENTS_SOLID;
Q1BSP_RecursiveHullCheck(hull, hull->firstclipnode, 0, 1, start_l, end_l, trace);
Q1BSP_RecursiveHullCheck(hull, hull->firstclipnode, start_l, end_l, hitcontentsmask, trace);
if (trace->fraction == 1)
{
@ -1639,7 +1665,7 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, framestate_t *framestate,
{
VectorSubtract(start, offset, start_l);
VectorSubtract(end, offset, end_l);
Q1BSP_RecursiveHullCheck(hull, hull->firstclipnode, 0, 1, start_l, end_l, trace);
Q1BSP_RecursiveHullCheck(hull, hull->firstclipnode, start_l, end_l, hitcontentsmask, trace);
if (trace->fraction == 1)
{
@ -1756,7 +1782,7 @@ static qbyte *Q1BSP_ClusterPVS (model_t *model, int cluster, pvsbuffer_t *buffer
static void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node, pvsbuffer_t *pvsbuffer)
{
mplane_t *plane;
float d;
float d;
while (1)
{

View File

@ -933,19 +933,19 @@ void VM_PrintInfo(vm_t *vm)
qvm_t *qvm;
// Con_Printf("%s (%p): ", vm->name, vm->hInst);
Con_Printf("%s: ", vm->filename);
Con_Printf("^2%s", vm->filename);
switch(vm->type)
{
case VM_NATIVE:
Con_Printf("native\n");
Con_Printf(": native\n");
break;
case VM_BUILTIN:
Con_Printf("built in\n");
Con_Printf(": built in\n");
break;
case VM_BYTECODE:
Con_Printf("interpreted\n");
Con_Printf(": interpreted\n");
if((qvm=vm->hInst))
{
Con_Printf(" code length: %d\n", qvm->len_cs);
@ -955,7 +955,7 @@ void VM_PrintInfo(vm_t *vm)
break;
default:
Con_Printf("unknown\n");
Con_Printf(": unknown\n");
break;
}
}

View File

@ -429,8 +429,6 @@ void GL_SelectTexture(int target)
shaderstate.currenttmu = target;
if (qglActiveTextureARB)
qglActiveTextureARB(target + mtexid0);
else if (qglSelectTextureSGIS)
qglSelectTextureSGIS(target + mtexid0);
}
void GL_SelectVBO(int vbo)
@ -3134,6 +3132,47 @@ static void BE_SubmitMeshChain(qboolean usetesselation)
}
return;
}
else if (qglMultiDrawElements)
{ //if we're drawing via a VBO then we don't really need DrawRangeElements any more.
//and avoiding so many calls into the driver also gives the driver a chance to optimise the draws instead of constantly checking if anything changed.
static GLsizei counts[1024];
static const GLvoid *indicies[countof(counts)];
GLsizei drawcount = 0;
GL_SelectEBO(shaderstate.sourcevbo->indicies.gl.vbo);
for (m = 0, mesh = shaderstate.meshes[0]; m < shaderstate.meshcount; )
{
startv = mesh->vbofirstvert;
starti = mesh->vbofirstelement;
endv = startv+mesh->numvertexes;
endi = starti+mesh->numindexes;
//find consecutive surfaces
for (++m; m < shaderstate.meshcount; m++)
{
mesh = shaderstate.meshes[m];
if (endi == mesh->vbofirstelement)
{
endv = mesh->vbofirstvert+mesh->numvertexes;
endi = mesh->vbofirstelement+mesh->numindexes;
}
else
{
break;
}
}
if (drawcount == countof(counts))
{
qglMultiDrawElements(batchtype, counts, GL_INDEX_TYPE, indicies, drawcount);
drawcount = 0;
}
counts[drawcount] = endi-starti;
indicies[drawcount] = (index_t*)shaderstate.sourcevbo->indicies.gl.addr + starti;
drawcount++;
}
qglMultiDrawElements(batchtype, counts, GL_INDEX_TYPE, indicies, drawcount);
}
else
{
GL_SelectEBO(shaderstate.sourcevbo->indicies.gl.vbo);

View File

@ -1206,6 +1206,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out, gw, gh, gw*4);
if (c)
{
c->flags = 0; //private glyph colours
c->advance = gw;
c->left = 0;
c->top = 0;
@ -2386,7 +2387,7 @@ void Font_EndString(struct font_s *font)
// Font_Flush();
// curfont = NULL;
R2D_Flush = Font_Flush;
R2D_Flush = font_foremesh.numindexes?Font_Flush:NULL;
}
//obtains the font's row height (each row of chars should be drawn using this increment)
@ -2394,6 +2395,10 @@ int Font_CharHeight(void)
{
return curfont->charheight;
}
float Font_CharVHeight(struct font_s *font)
{
return ((float)font->charheight * vid.height)/vid.rotpixelheight;
}
//obtains the font's row height (each row of chars should be drawn using this increment)
float Font_CharScaleHeight(void)

View File

@ -141,22 +141,38 @@ static void Mod_BatchList_f(void)
{
for (batch = mod->batches[i]; batch; batch = batch->next)
{
char editname[MAX_QPATH];
char *body = Shader_GetShaderBody(batch->texture->shader, editname, sizeof(editname));
if (!body)
body = "SHADER NOT KNOWN";
else
{
char *cr;
while ((cr = strchr(body, '\r')))
*cr = ' ';
}
Con_Printf(" ^[%s\\tipimg\\%s\\tipimgtype\\%i\\tip\\{%s^]", batch->texture->shader->name, batch->texture->shader->name, batch->texture->shader->usageflags, body);
#if MAXRLIGHTMAPS > 1
if (batch->lightmap[3] >= 0)
Con_Printf(" %s lm=(%i:%i %i:%i %i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->lightmap[2], batch->lmlightstyle[2], batch->lightmap[3], batch->lmlightstyle[3], batch->maxmeshes);
Con_Printf("^2 lm=(%i:%i %i:%i %i:%i %i:%i)", batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->lightmap[2], batch->lmlightstyle[2], batch->lightmap[3], batch->lmlightstyle[3]);
else if (batch->lightmap[2] >= 0)
Con_Printf(" %s lm=(%i:%i %i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->lightmap[2], batch->lmlightstyle[2], batch->maxmeshes);
Con_Printf("^2 lm=(%i:%i %i:%i %i:%i)", batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->lightmap[2], batch->lmlightstyle[2]);
else if (batch->lightmap[1] >= 0)
Con_Printf(" %s lm=(%i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->maxmeshes);
Con_Printf("^2 lm=(%i:%i %i:%i)", batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1]);
else
if (batch->lightmap[1] >= 0)
#else
if (batch->lmlightstyle[0] != 255)
#endif
Con_Printf(" %s lm=(%i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->maxmeshes);
Con_Printf("^2 lm=(%i:%i)", batch->lightmap[0], batch->lmlightstyle[0]);
else
Con_Printf(" %s lm=%i surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->maxmeshes);
Con_Printf("^2 lm=%i", batch->lightmap[0]);
count++;
if (batch->envmap)
Con_Printf("^3 envmap=%s", batch->envmap->ident);
Con_Printf(" surfs=%u\n", batch->maxmeshes);
}
}
Con_Printf("^h(%u batches, lm %i*%i, lux %s)\n", count, mod->lightmaps.width, mod->lightmaps.height, mod->lightmaps.deluxemapping?"true":"false");
@ -173,6 +189,7 @@ static void Mod_TextureList_f(void)
int count = 0;
char *body;
char editname[MAX_OSPATH];
int preview = (Cmd_Argc()==1)?8:atoi(Cmd_Argv(1));
for (m=0 , mod=mod_known ; m<mod_numknown ; m++, mod++)
{
if (shownmodelname)
@ -207,10 +224,17 @@ static void Mod_TextureList_f(void)
*cr = ' ';
}
if (preview)
{
if (*editname)
Con_Printf("^[\\edit\\%s\\img\\%s\\imgtype\\%i\\s\\%i\\tip\\{%s^]", editname, tx->name, tx->shader->usageflags, preview, body);
else
Con_Printf("^[\\img\\%s\\imgtype\\%i\\s\\%i\\tip\\{%s^]", tx->shader->name, tx->shader->usageflags, preview, body);
}
if (*editname)
Con_Printf(" ^[^7%s\\edit\\%s\\tipimg\\%s\\tip\\{%s^]\n", tx->name, editname, tx->name, body);
Con_Printf(" ^[%s\\edit\\%s\\tipimg\\%s\\tipimgtype\\%i\\tip\\{%s^]\n", tx->name, editname, tx->name, tx->shader->usageflags, body);
else
Con_Printf(" ^[^7%s\\tipimg\\%s\\tip\\{%s^]\n", tx->name, tx->name, body);
Con_Printf(" ^[%s\\tipimg\\%s\\tipimgtype\\%i\\tip\\{%s^]\n", tx->name, tx->shader->name, tx->shader->usageflags, body);
count++;
}
}
@ -1759,14 +1783,46 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
}
#ifndef SERVERONLY
#if 0//def Q2BSPS //Q2XP's alternative to lit files, for higher res lightmaps (that seem to have light coming from the wrong directions...)
if (loadmodel->fromgame == fg_quake2 && overrides && !interleaveddeluxe)
{
char litname[MAX_QPATH];
size_t litsize;
qbyte *xplm;
COM_StripExtension(loadmodel->name, litname, sizeof(litname));
Q_strncatz(litname, ".xplm", sizeof(litname));
xplm = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize);
if (litdata)
{
int scale;
size_t numsurfs = LittleLong(*(int *)&xplm[0]);
unsigned int *offsets = (unsigned int*)(xplm+4);
scale = xplm[(numsurfs+1)*4];
for (overrides->defaultshift=0; scale && !(scale&1); scale>>=1)
overrides->defaultshift++;
if (scale == 1)
{ //its a supported shift
litdata = xplm+(numsurfs+1)*4+1;
samples = (litsize-(numsurfs+1)*4+1)/3;
overrides->offsets = offsets;
}
}
}
#endif
if (!expdata && !litdata && r_loadlits.value)
{
char *litnames[] = {
"%s.lit2",
"%s.hdr",
"%s.lit",
"lits/%s.lit2",
"lits/%s.lit"
struct
{
char *pattern;
int type;
} litnames[] = {
{"%s.lit2",2},
{"%s.hdr",1},
{"%s.lit",0},
{"lits/%s.lit2",2},
{"lits/%s.lit",0},
};
char litbasep[MAX_QPATH];
char litbase[MAX_QPATH];
@ -1780,14 +1836,14 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
COM_StripExtension(loadmodel->name, litbasep, sizeof(litbasep));
COM_FileBase(loadmodel->name, litbase, sizeof(litbase));
for (i = 0; i < sizeof(litnames)/sizeof(litnames[0]); i++)
for (i = 0; i < countof(litnames); i++)
{
if (temp_lit2support.ival && !(i & 1))
if (!temp_lit2support.ival && litnames[i].type==2)
continue;
if (strchr(litnames[i], '/'))
Q_snprintfz(litname, sizeof(litname), litnames[i], litbase);
if (strchr(litnames[i].pattern, '/'))
Q_snprintfz(litname, sizeof(litname), litnames[i].pattern, litbase);
else
Q_snprintfz(litname, sizeof(litname), litnames[i], litbasep);
Q_snprintfz(litname, sizeof(litname), litnames[i].pattern, litbasep);
depth = COM_FDepthFile(litname, false);
if (depth < bestdepth)
{
@ -1797,10 +1853,10 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
}
if (best >= 0)
{
if (strchr(litnames[best], '/'))
Q_snprintfz(litname, sizeof(litname), litnames[best], litbase);
if (strchr(litnames[best].pattern, '/'))
Q_snprintfz(litname, sizeof(litname), litnames[best].pattern, litbase);
else
Q_snprintfz(litname, sizeof(litname), litnames[best], litbasep);
Q_snprintfz(litname, sizeof(litname), litnames[best].pattern, litbasep);
litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize);
}
else
@ -1828,7 +1884,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
litdata += 8; //header+version
}
else if (litver == 0x10001)
{
{ //hdr lighting, e5bgr9 format
if (l->filelen && samples*4 != (litsize-8))
Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname);
else
@ -2098,6 +2154,8 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
}
else
loadmodel->lightdata = expdata;
//FIXME: no desaturation/gamma logic.
return;
}
else if (litdata)

View File

@ -556,7 +556,7 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan
void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node);
void GLQ1BSP_LightPointValues(struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir);
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, struct trace_s *trace);
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, unsigned int hitcontents, struct trace_s *trace);
/*
==============================================================================

View File

@ -22,91 +22,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
#include "shader.h"
extern qbyte *draw_chars; // 8*8 graphic characters
static texid_t netgraphtexture; // netgraph texture
static shader_t *netgraphshader;
void Draw_ExpandedString(struct font_s *font, float x, float y, conchar_t *str);
static int timehistory[NET_TIMINGS];
static int findex;
#define NET_GRAPHHEIGHT 32
static qbyte ngraph_texels[NET_GRAPHHEIGHT][NET_TIMINGS];
static void R_LineGraph (int x, int h)
//#define GRAPHTEX
#ifdef GRAPHTEX
static texid_t netgraphtexture; // netgraph texture
static shader_t *netgraphshader;
static unsigned int ngraph_texels[NET_GRAPHHEIGHT][NET_TIMINGS];
#else
static struct
{
int i;
int s;
int color, color2 = 0xff;
unsigned int col;
float height;
} ngraph[NET_TIMINGS];
#endif
s = NET_GRAPHHEIGHT;
if (h == 10000 || h<0)
{
color = 0; // yellow
color2 = 1;
h=abs(h);
}
else if (h == 9999)
{
color = 2; // red
color2 = 3;
}
else if (h == 9998)
{
color = 4; // blue
color2 = 5;
}
else
{
color = 6; // white
color2 = 7;
}
if (h>s)
h = s;
for (i=0 ; i<h ; i++)
if (i & 1)
ngraph_texels[NET_GRAPHHEIGHT - i - 1][x] = (qbyte)color2;
else
ngraph_texels[NET_GRAPHHEIGHT - i - 1][x] = (qbyte)color;
for ( ; i<s ; i++)
ngraph_texels[NET_GRAPHHEIGHT - i - 1][x] = (qbyte)8;
}
/*
static void Draw_CharToNetGraph (int x, int y, int num)
{
int row, col;
qbyte *source;
int drawline;
int nx;
if (!draw_chars)
return;
row = num>>4;
col = num&15;
source = draw_chars + (row<<10) + (col<<3);
for (drawline = 8; drawline; drawline--, y++)
{
for (nx=0 ; nx<8 ; nx++)
if (source[nx] != 255)
ngraph_texels[y][nx+x] = 0x60 + source[nx];
source += 128;
}
}
*/
/*
==============
R_NetGraph
==============
*/
//instead of assuming the quake palette, we should use a predictable lookup table. it makes the docs much easier.
static unsigned ngraph_palette[] =
{
@ -120,14 +54,79 @@ static unsigned ngraph_palette[] =
0xffefefef, //white2
0x00000000 //invisible.
};
static void R_LineGraph (int x, float h)
{
int s;
unsigned color, color2;
s = NET_GRAPHHEIGHT;
if (h == 10000 || h<0)
{
color = 0xff00ffff; // yellow
color2 = 0xff00efef;
h=fabs(h);
}
else if (h == 9999)
{
color = 0xff0000ff; // red
color2 = 0xff0000ff;
}
else if (h == 9998)
{
color = 0xffff0000; // blue
color2 = 0xffef0000;
}
else
{
color = 0xffffffff; // white
color2 = 0xffefefef;
}
#ifdef GRAPHTEX
if (h>s)
h = s;
for (i=0 ; i<h ; i++)
if (i & 1)
ngraph_texels[NET_GRAPHHEIGHT - i - 1][x] = color2;
else
ngraph_texels[NET_GRAPHHEIGHT - i - 1][x] = color;
for ( ; i<s ; i++)
ngraph_texels[NET_GRAPHHEIGHT - i - 1][x] = 0x00000000;
#else
ngraph[x].col = color;
if (h > s)
ngraph[x].height = 1;
else
ngraph[x].height = h/(float)s;
#endif
}
/*
==============
R_NetGraph
==============
*/
void R_NetGraph (void)
{
int a, x, i, y;
int a, x, i;
float y;
int lost;
char st[80];
unsigned ngraph_pixels[NET_GRAPHHEIGHT][NET_TIMINGS];
float pi, po, bi, bo;
vec2_t p[4];
vec2_t tc[4];
vec4_t rgba[4];
extern shader_t *shader_draw_fill;
conchar_t line[2048];
float textheight, graphtop;
float pings, pings_min, pings_max, pingms_stddev, pingfr, dropped, choked, invalid;
int pingfr_min, pingfr_max;
x = 0;
if (r_netgraph.value < 0)
{
@ -142,7 +141,7 @@ void R_NetGraph (void)
}
else
{
int last = 10000;
float last = 10000;
lost = CL_CalcNet(r_netgraph.value);
for (a=0 ; a<NET_TIMINGS ; a++)
{
@ -155,38 +154,87 @@ void R_NetGraph (void)
}
}
// now load the netgraph texture into gl and draw it
for (y = 0; y < NET_GRAPHHEIGHT; y++)
for (x = 0; x < NET_TIMINGS; x++)
ngraph_pixels[y][x] = ngraph_palette[ngraph_texels[y][x]];
textheight = 4;
#ifdef HAVE_SERVER
if (sv.state && sv.allocated_client_slots != 1)
textheight+=2;
#endif
textheight = ceil(textheight*Font_CharVHeight(font_console)/8)*8; //might have a small gap underneath
x = ((vid.width - 320)>>1);
x = ((vid.width - 320)>>1); //eww
x=-x;
y = vid.height - sb_lines - 24 - NET_GRAPHHEIGHT - 2*8;
y = vid.height - sb_lines - textheight - NET_GRAPHHEIGHT - 2*8/*box borders*/;
M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8 + 3);
y += 8;
M_DrawTextBox (x, y, NET_TIMINGS/8, (NET_GRAPHHEIGHT + textheight)/8);
x = 8;
y += 8; //top border
graphtop = y+textheight;
sprintf(st, "%3i%% packet loss", lost);
Draw_FunString(8, y, st);
y += 8;
CL_CalcNet2(&pings, &pings_min, &pings_max, &pingms_stddev, &pingfr, &pingfr_min, &pingfr_max, &dropped, &choked, &invalid);
{
COM_ParseFunString(CON_WHITEMASK, va("%3.0f%% lost, %3.0f%% choked, %3.0f%% bad", dropped*100, choked*100, invalid*100), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
COM_ParseFunString(CON_WHITEMASK, va(" ping: %4.1fms %6.2f (%.1f-%.1f)\n", pings*1000, pingms_stddev, pings_min*1000, pings_max*1000), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
}
if (NET_GetRates(cls.sockets, &pi, &po, &bi, &bo))
{
Draw_FunString(8, y+0, va("in: %g %g\n", pi, bi)); //not relevent as a limit.
Draw_FunString(8, y+8, va("out: %g %g\n", po, bo)); //not relevent as a limit.
COM_ParseFunString(CON_WHITEMASK, va(" in: %.1f %.0fb\n", pi, bi), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
COM_ParseFunString(CON_WHITEMASK, va(" out: %.1f %.0fb\n", po, bo), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
}
y += 16;
#ifdef HAVE_SERVER
if (sv.state && sv.allocated_client_slots != 1 && NET_GetRates(svs.sockets, &pi, &po, &bi, &bo))
{
COM_ParseFunString(CON_WHITEMASK, va("sv in: %.1f %.0fb\n", pi, bi), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
COM_ParseFunString(CON_WHITEMASK, va("svout: %.1f %.0fb\n", po, bo), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
}
#endif
Image_Upload(netgraphtexture, TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
x=8;
y = graphtop; //rounding makes it ugly.
#ifdef GRAPHTEX
Image_Upload(netgraphtexture, TF_RGBA32, ngraph_texels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader);
#else
for (a=0 ; a<NET_TIMINGS ; a++)
{
Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]);
Vector2Copy(p[2], p[1]); Vector4Copy(rgba[2], rgba[1]);
Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT);
Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT);
Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (1-ngraph[a].height));
Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1);
Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0);
Vector4Copy(rgba[2+0], rgba[2+1]);
if (a)
R2D_Image2dQuad(p, tc, rgba, shader_draw_fill);
}
#endif
}
void R_FrameTimeGraph (int frametime)
{
int a, x, i, y;
unsigned ngraph_pixels[NET_GRAPHHEIGHT][NET_TIMINGS];
vec2_t p[4];
vec2_t tc[4];
vec4_t rgba[4];
extern shader_t *shader_draw_fill;
timehistory[findex++&NET_TIMINGSMASK] = frametime;
@ -197,28 +245,42 @@ void R_FrameTimeGraph (int frametime)
R_LineGraph (NET_TIMINGS-1-a, timehistory[i]);
}
// now load the netgraph texture into gl and draw it
for (y = 0; y < NET_GRAPHHEIGHT; y++)
for (x = 0; x < NET_TIMINGS; x++)
ngraph_pixels[y][x] = d_8to24rgbtable[ngraph_texels[y][x]];
x = ((vid.width - 320)>>1);
x=-x;
y = vid.height - sb_lines - 24 - NET_GRAPHHEIGHT - 1;
y = vid.height - sb_lines - 16 - NET_GRAPHHEIGHT;
M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8 + 1);
M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8);
x=8;
y += 8;
y += 8;
Image_Upload(netgraphtexture, TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
#ifdef GRAPHTEX
Image_Upload(netgraphtexture, TF_RGBA32, ngraph_texels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
x=8;
R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader);
#else
for (a=0 ; a<NET_TIMINGS ; a++)
{
Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]);
Vector2Copy(p[2], p[1]); Vector4Copy(rgba[2], rgba[1]);
Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT);
Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT);
Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (1-ngraph[a].height));
Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1);
Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0);
Vector4Copy(rgba[2+0], rgba[2+1]);
if (a)
R2D_Image2dQuad(p, tc, rgba, shader_draw_fill);
}
#endif
}
void R_NetgraphInit(void)
{
TEXASSIGN(netgraphtexture, Image_CreateTexture("***netgraph***", NULL, IF_UIPIC|IF_NOMIPMAP));
#ifdef GRAPHTEX
TEXASSIGN(netgraphtexture, Image_CreateTexture("***netgraph***", NULL, IF_UIPIC|IF_NOMIPMAP|IF_CLAMP));
netgraphshader = R_RegisterShader("netgraph", SUF_NONE,
"{\n"
"program default2d\n"
@ -229,4 +291,5 @@ void R_NetgraphInit(void)
"}\n"
);
netgraphshader->defaulttextures->base = netgraphtexture;
#endif
}

View File

@ -63,7 +63,7 @@ cvar_t r_shadow_realtime_dlight_ambient = CVAR ("r_shadow_realtime_dlight_ambie
cvar_t r_shadow_realtime_dlight_diffuse = CVAR ("r_shadow_realtime_dlight_diffuse", "1");
cvar_t r_shadow_realtime_dlight_specular = CVAR ("r_shadow_realtime_dlight_specular", "4"); //excessive, but noticable. its called stylized, okay? shiesh, some people
cvar_t r_shadow_playershadows = CVARD ("r_shadow_playershadows", "1", "Controls the presence of shadows on the local player.");
cvar_t r_shadow_shadowmapping = CVARD ("r_shadow_shadowmapping", "1", "Enables soft shadows instead of stencil shadows.");
cvar_t r_shadow_shadowmapping = CVARFD ("r_shadow_shadowmapping", "1", CVAR_ARCHIVE, "Enables soft shadows instead of stencil shadows.");
cvar_t r_shadow_shadowmapping_precision = CVARD ("r_shadow_shadowmapping_precision", "1", "Scales the shadowmap detail level up or down.");
extern cvar_t r_shadow_shadowmapping_nearclip;
extern cvar_t r_shadow_shadowmapping_bias;

View File

@ -1,3 +1,27 @@
/*
Lingering issues:
nvidia vsync:
with vsync enabled and framerates fluctuating across the 1000fps boundary, there is serious stuttering, like its re-showing the previous frame again.
this only happens with windows gl, and not vulkan/d3d so I'm assuming this is a driver bug with it mispredicting timings.
workaround: enable bloom or something else that's wasteful in terms of gpu time, to keep it under 1000fps.
nouveau vsync:
vsync seems forced when running fullscreen, but not when running windowed.
workaround: run windowed.
nouveau framerates:
nouveau doesn't seem to have any pstate control enabled.
workaround: sudo echo AUTO>/sys/kernel/debug/dri/0/pstate
(you could also use different ids for explicit pstates - eg to return to a low-power state)
(the engine cannot do this, as it requires root, nor does it know WHICH dri device to control)
(more recent gpus might not support this at all due to nvidia blocking them, but works for my 750ti)
(note that nouveau's presentation engine isn't that good, so don't expect 5000fps, but it should make rtlights usable)
core vs compatibility:
vid_gl_context_compatibility defaults to 1, because it still gives higher framerates (due to streaming vertex data from the cpu).
*/
#include "quakedef.h"
#ifdef GLQUAKE
#include "glquake.h"
@ -170,6 +194,7 @@ void (APIENTRY *qglGetTexLevelParameteriv) (GLenum target, GLint level, GLenum p
void (APIENTRY *qglGetTexEnviv) (GLenum target, GLenum pname, GLint *params);
void (APIENTRY *qglDrawRangeElements) (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
void (APIENTRY *qglMultiDrawElements) (GLenum mode, const GLsizei * count, GLenum type, const GLvoid * const * indices, GLsizei drawcount);
void (APIENTRY *qglArrayElement) (GLint i);
void (APIENTRY *qglVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
void (APIENTRY *qglNormalPointer) (GLenum type, GLsizei stride, const GLvoid *pointer);
@ -238,11 +263,8 @@ FTEPFNGLUNLOCKARRAYSEXTPROC qglUnlockArraysEXT;
qlpSelTexFUNC qglActiveTextureARB;
#endif
qlpSelTexFUNC qglClientActiveTextureARB;
qlpMTex3FUNC qglMultiTexCoord3fARB;
qlpMTex2FUNC qglMultiTexCoord2fARB;
//generic multitexture
lpMTexFUNC qglMTexCoord2fSGIS;
lpSelTexFUNC qglSelectTextureSGIS;
int mtexid0;
@ -627,9 +649,6 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
#ifndef qglActiveTextureARB
qglActiveTextureARB = NULL;
#endif
qglMultiTexCoord2fARB = NULL;
qglMultiTexCoord3fARB = NULL;
qglMTexCoord2fSGIS = NULL;
qglSelectTextureSGIS = NULL;
mtexid0 = 0;
@ -709,12 +728,12 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
// if (GL_CheckExtension("GL_SGIS_generate_mipmap")) //a suprising number of implementations have this broken.
// gl_config.sgis_generate_mipmap = true;
if (gl_config.gles)
if (gl_config.gles || gl_config_nofixedfunc)
{
#ifndef qglActiveTextureARB
qglActiveTextureARB = (void *) getglext("glActiveTexture");
#endif
qglClientActiveTextureARB = (void *) getglext("glClientActiveTexture");
qglClientActiveTextureARB = (void *) getglext("glClientActiveTexture"); //compat contexts only...
qglSelectTextureSGIS = qglActiveTextureARB;
mtexid0 = GL_TEXTURE0_ARB;
if (!gl_config.nofixedfunc)
@ -728,19 +747,16 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
qglActiveTextureARB = (void *) getglext("glActiveTextureARB");
#endif
qglClientActiveTextureARB = (void *) getglext("glClientActiveTextureARB");
qglMultiTexCoord2fARB = (void *) getglext("glMultiTexCoord2fARB");
qglMultiTexCoord3fARB = (void *) getglext("glMultiTexCoord3fARB");
qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_mtexarbable);
gl_mtexable = true;
qglMTexCoord2fSGIS = qglMultiTexCoord2fARB;
qglSelectTextureSGIS = qglActiveTextureARB;
mtexid0 = GL_TEXTURE0_ARB;
#ifndef qglActiveTextureARB
if (!qglActiveTextureARB || !qglClientActiveTextureARB || !qglMultiTexCoord2fARB)
if (!qglActiveTextureARB || !qglClientActiveTextureARB)
gl_mtexable = false;
else if (gl_mtexarbable == 1)
{
@ -751,8 +767,6 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
{
qglActiveTextureARB = NULL;
qglClientActiveTextureARB = NULL;
qglMultiTexCoord2fARB = NULL;
qglMTexCoord2fSGIS = NULL;
qglSelectTextureSGIS = NULL;
gl_mtexable=false;
gl_mtexarbable = false;
@ -1136,13 +1150,13 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
gl_config.arb_depth_texture |= GL_CheckExtension("GL_CHROMIUM_depth_texture"); //nacl
gl_config.arb_depth_texture |= GL_CheckExtension("GL_WEBGL_depth_texture"); //webgl. duh.
gl_config.arb_depth_texture |= GL_CheckExtension("GL_ANGLE_depth_texture"); //gah. should just use wildcards huh (no uploads)
gl_config.arb_shadow = gl_config.glversion>=3.0;//||GL_CheckExtension("GL_EXT_shadow_samplers");
}
else
{
gl_config.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture");
gl_config.arb_depth_texture = gl_config.glversion>=1.4 || GL_CheckExtension("GL_ARB_depth_texture");
gl_config.arb_shadow = gl_config.glversion>=1.4||GL_CheckExtension("GL_ARB_shadow");
}
gl_config.arb_shadow = GL_CheckExtension("GL_ARB_shadow");
gl_config.arb_shadow |= gl_config.glversion >= 3.0; //seems about right, for both gles and desktop...
//gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2. nvidia fucks up. depend on brute-force. :s
if (GL_CheckExtension("GL_ARB_seamless_cube_map"))
@ -2047,6 +2061,7 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
//150 [core|compatibility] == gl3.2
//300 ES == gles3
//310 ES == gles3.1
//320 ES == gles3.2
//330, 400, 410, 420, 430 [core|compatibility] == gl?.??
if (gl_config_gles)
@ -2056,6 +2071,13 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
else if (ver <= 330) //gles3 is rougly gl3.3 so 300es==330ish
ver = 300;
}
else
{
if (ver == 100)
ver = 110; //gles2 is roughly equivelent to gl2
else if (ver >= 300 && ver < 330)
ver = 330; //gles3 is roughly equivelent to gl3.3
}
if (gl_config_gles && ver != 100)
@ -2095,7 +2117,7 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
if (ver >= 130)
{
GLSlang_GenerateInternal(&glsl,
//gl3+ deprecated the some things. these are removed in forwards-compatible / core contexts.
//gl3+ deprecated some things. these are removed in forwards-compatible / core contexts.
//varying became either in or out, which is important if you have geometry shaders...
"#define varying in\n"
//now only the 'texture' function exists, with overloads for each sampler type.
@ -2137,6 +2159,8 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
#else
"#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#elif defined(GL_ES)\n"
"precision lowp sampler2DShadow;\n" //gah
"#endif\n"
#endif
"uniform sampler2DShadow s_shadowmap;\n",
@ -2948,11 +2972,6 @@ void GL_ForgetPointers(void)
#endif
qglClientActiveTextureARB = NULL;
qglSelectTextureSGIS = NULL;
qglMTexCoord2fSGIS = NULL;
qglMultiTexCoord2fARB = NULL;
qglMultiTexCoord3fARB = NULL;
qglMTexCoord2fSGIS = NULL;
qglSelectTextureSGIS = NULL;
mtexid0 = 0;
#ifndef GL_STATIC
@ -3204,6 +3223,8 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
if (qglDrawRangeElements == 0)
qglDrawRangeElements = GL_DrawRangeElementsEmul;
qglMultiDrawElements = (void *)getglext("glMultiDrawElements"); //since gl2
//fixme: definatly make non-core
qglPushAttrib = (void *)getglcore("glPushAttrib");
qglPopAttrib = (void *)getglcore("glPopAttrib");

View File

@ -1309,7 +1309,10 @@ static struct
const char * (*QueryExtensionsString)(Display * dpy, int screen);
void *(*GetProcAddress) (char *name);
void (*SwapInterval) (Display *dpy, GLXDrawable drawable, int interval);
void (*SwapIntervalSGI) (int interval); //FFS!
void (*SwapIntervalMESA) (unsigned int interval); //FFS!
void (*SwapIntervalEXT) (Display *dpy, GLXDrawable drawable, int interval);
qboolean swaptear;
GLXFBConfig *(*ChooseFBConfig)(Display *dpy, int screen, const int *attrib_list, int *nelements);
int (*GetFBConfigAttrib)(Display *dpy, GLXFBConfig config, int attribute, int * value);
@ -1675,6 +1678,29 @@ static void *GLX_GetSymbol(char *name)
return symb;
}
static qboolean GLX_CheckExtension(const char *ext)
{
const char *e = glx.glxextensions, *n;
size_t el = strlen(ext);
while(e && *e)
{
while (*e == ' ')
e++;
n = strchr(e, ' ');
if (!n)
n = n+strlen(e);
if (n-e == el && !strncmp(ext, e, el))
{
Con_DPrintf("GLX: Found %s\n", ext);
return true;
}
e = n;
}
Con_DPrintf("GLX: Missing %s\n", ext);
return false;
}
static qboolean GLX_InitLibrary(char *driver)
{
dllfunction_t funcs[] =
@ -1703,17 +1729,15 @@ static qboolean GLX_InitLibrary(char *driver)
if (!glx.gllibrary)
return false;
glx.QueryExtensionsString = GLX_GetSymbol("glXQueryExtensionsString");
glx.GetProcAddress = GLX_GetSymbol("glXGetProcAddress");
if (!glx.GetProcAddress)
glx.GetProcAddress = GLX_GetSymbol("glXGetProcAddressARB");
glx.QueryExtensionsString = GLX_GetSymbol("glXQueryExtensionsString");
glx.ChooseFBConfig = GLX_GetSymbol("glXChooseFBConfig");
glx.GetFBConfigAttrib = GLX_GetSymbol("glXGetFBConfigAttrib");
glx.GetVisualFromFBConfig = GLX_GetSymbol("glXGetVisualFromFBConfig");
glx.CreateContextAttribs = GLX_GetSymbol("glXCreateContextAttribsARB");
glx.SwapInterval = GLX_GetSymbol("glXSwapIntervalEXT");
return true;
}
@ -1724,29 +1748,6 @@ static qboolean GLX_InitLibrary(char *driver)
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
#endif
static qboolean GLX_CheckExtension(const char *ext)
{
const char *e = glx.glxextensions, *n;
size_t el = strlen(ext);
while(e && *e)
{
while (*e == ' ')
e++;
n = strchr(e, ' ');
if (!n)
n = n+strlen(e);
if (n-e == el && !strncmp(ext, e, el))
{
Con_DPrintf("GLX: Found %s\n", ext);
return true;
}
e = n;
}
Con_DPrintf("GLX: Missing %s\n", ext);
return false;
}
//Since GLX1.3 (equivelent to gl1.2)
static GLXFBConfig GLX_GetFBConfig(rendererstate_t *info)
{
@ -1757,9 +1758,6 @@ static GLXFBConfig GLX_GetFBConfig(rendererstate_t *info)
qboolean hassrgb, hasmultisample;//, hasfloats;
if (glx.QueryExtensionsString)
glx.glxextensions = glx.QueryExtensionsString(vid_dpy, scrnum);
if (!glx.ChooseFBConfig || !glx.GetVisualFromFBConfig)
{
Con_Printf("Missing function pointer\n");
@ -1832,7 +1830,7 @@ static GLXFBConfig GLX_GetFBConfig(rendererstate_t *info)
if (!info->multisample || !hasmultisample)
continue;
attrib[n++] = GLX_SAMPLE_BUFFERS_ARB; attrib[n++] = True;
attrib[n++] = GLX_SAMPLES_ARB, attrib[n++] = info->multisample;
attrib[n++] = GLX_SAMPLES_ARB; attrib[n++] = info->multisample;
}
//attrib[n++] = GLX_ACCUM_RED_SIZE; attrib[n++] = 0;
@ -3432,14 +3430,28 @@ void GLVID_SwapBuffers (void)
int n = vid_vsync.ival;
if (cls.timedemo && cls.demoplayback)
n = 0;
if (!glx.swaptear)
n = abs(n);
if (glx.swapint != n)
{
glx.swapint = n;
if (glx.SwapInterval)
if (glx.SwapIntervalEXT)
{
glx.SwapInterval(vid_dpy, vid_window, glx.swapint);
Con_Printf("Swap interval %i\n", glx.swapint);
glx.SwapIntervalEXT(vid_dpy, vid_window, glx.swapint);
Con_DPrintf("Swap interval changed to %i\n", glx.swapint);
}
else if (glx.SwapIntervalMESA && glx.swapint>=0)
{
glx.SwapIntervalMESA(glx.swapint);
Con_DPrintf("Swap interval changed to %i\n", glx.swapint);
}
else if (glx.SwapIntervalSGI && glx.swapint>0)
{
glx.SwapIntervalSGI(glx.swapint);
Con_DPrintf("Swap interval changed to %i\n", glx.swapint);
}
else
Con_Printf("Unable to change swap interval to %i\n", glx.swapint);
}
}
@ -3836,6 +3848,8 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int
break;
#endif
case PSL_GLX:
if (glx.QueryExtensionsString)
glx.glxextensions = glx.QueryExtensionsString(vid_dpy, scrnum);
fbconfig = GLX_GetFBConfig(info);
if (fbconfig)
visinfo = glx.GetVisualFromFBConfig(vid_dpy, fbconfig);
@ -3930,9 +3944,38 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int
if (visinfo != &vinfodef)
#endif
x11.pXFree(visinfo);
glx.SwapIntervalEXT = GLX_CheckExtension("GLX_EXT_swap_control")?GLX_GetSymbol("glXSwapIntervalEXT"):NULL;
glx.swaptear = glx.SwapIntervalEXT&&GLX_CheckExtension("GLX_EXT_swap_control_tear");
// if (glx.swaptear)
// glx.QueryDrawable(vid_dpy, vid_window, 0x20F3, &glx.swaptear);
if (!glx.SwapIntervalEXT)
glx.SwapIntervalMESA = GLX_CheckExtension("GLX_MESA_swap_control")?GLX_GetSymbol("glXSwapIntervalMESA"):NULL;
if (!glx.SwapIntervalEXT && !glx.SwapIntervalMESA)
glx.SwapIntervalSGI = GLX_CheckExtension("GLX_SGI_swap_control")?GLX_GetSymbol("glXSwapIntervalSGI"):NULL;
glx.swapint = vid_vsync.ival;
if (glx.SwapInterval)
glx.SwapInterval(vid_dpy, vid_window, glx.swapint);
if (!glx.swaptear)
glx.swapint = abs(glx.swapint);
if (*vid_vsync.string)
{
if (glx.SwapIntervalEXT /*&& (glx.swapint>=0 || swap_tear)*/)
{
glx.SwapIntervalEXT(vid_dpy, vid_window, glx.swapint);
Con_DPrintf("Swap interval %i\n", glx.swapint);
}
else if (glx.SwapIntervalMESA && glx.swapint>=0)
{
glx.SwapIntervalMESA(abs(glx.swapint));
Con_DPrintf("Swap interval %i\n", glx.swapint);
}
else if (glx.SwapIntervalSGI && glx.swapint>0)
{
glx.SwapIntervalSGI(glx.swapint);
Con_DPrintf("Swap interval %i\n", glx.swapint);
}
else
Con_Printf("Unable to explicitly %s vsync\n", glx.swapint?"configure":"disable");
}
break;
#ifdef USE_EGL
case PSL_EGL:

View File

@ -1039,9 +1039,7 @@ extern PFNGLGENPROGRAMSARBPROC qglGenProgramsARB;
extern FTEPFNGLLOCKARRAYSEXTPROC qglLockArraysEXT;
extern FTEPFNGLUNLOCKARRAYSEXTPROC qglUnlockArraysEXT;
typedef void (APIENTRY *lpMTexFUNC) (GLenum en, GLfloat f1, GLfloat f2);
typedef void (APIENTRY *lpSelTexFUNC) (GLenum en);
extern lpMTexFUNC qglMTexCoord2fSGIS;
extern lpSelTexFUNC qglSelectTextureSGIS;
//these functions are not available in gles2, for one reason or another
@ -1078,6 +1076,7 @@ extern FTEPFNGLACTIVESTENCILFACEEXTPROC qglActiveStencilFaceEXT;
extern void (APIENTRY *qglDepthBoundsEXT) (GLclampd zmin, GLclampd zmax);
extern void (APIENTRY *qglDrawRangeElements) (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
extern void (APIENTRY *qglMultiDrawElements) (GLenum mode, const GLsizei * count, GLenum type, const GLvoid * const * indices, GLsizei drawcount);
extern void (APIENTRY *qglEnableClientState) (GLenum array);
extern void (APIENTRY *qglVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

View File

@ -4,14 +4,14 @@
//contains the extra things that would otherwise be found in glext.h
typedef void (APIENTRY *qlpMTex2FUNC) (GLenum, GLfloat, GLfloat);
typedef void (APIENTRY *qlpMTex3FUNC) (GLenum, GLfloat, GLfloat, GLfloat);
//typedef void (APIENTRY *qlpMTex2FUNC) (GLenum, GLfloat, GLfloat);
//typedef void (APIENTRY *qlpMTex3FUNC) (GLenum, GLfloat, GLfloat, GLfloat);
typedef void (APIENTRY *qlpSelTexFUNC) (GLenum);
extern qlpSelTexFUNC qglActiveTextureARB;
extern qlpSelTexFUNC qglClientActiveTextureARB;
extern qlpMTex3FUNC qglMultiTexCoord3fARB;
extern qlpMTex2FUNC qglMultiTexCoord2fARB;
//extern qlpMTex3FUNC qglMultiTexCoord3fARB;
//extern qlpMTex2FUNC qglMultiTexCoord2fARB;
//This stuff is normally supplied in the <GL/glext.h> header file. I don't actually have one of them, so it's here instead.
#if 0 //change to 1 if you do actually have the file in question - and its up to date.

View File

@ -5193,7 +5193,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultwall",
"!!ver 100 150\n"
"!!ver 100 450\n"
"!!permu TESS\n"
"!!permu DELUXE\n"
"!!permu FULLBRIGHT\n"
@ -6591,6 +6591,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultwarp",
"!!ver 100 450\n"
"!!permu FOG\n"
"!!cvarf r_wateralpha\n"
"!!samps diffuse lightmap\n"
@ -9086,7 +9087,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;\n"
"if (r_glsl_ascii_mono != 0.0)\n"
"if (float(r_glsl_ascii_mono) != 0.0)\n"
"gray = gray = pow(gray, 0.7); //quake is just too dark otherwise.\n"
"else\n"
"gray = gray = pow(gray, 0.45); //col*char is FAR too dark otherwise, and much of the colour will come from the col term anyway.\n"
@ -9102,7 +9103,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"if (gray > 0.8) n = 11512810.0; // #\n"
"vec2 p = mod(uv/4.0, 2.0) - vec2(1.0);\n"
"if (r_glsl_ascii_mono != 0.0)\n"
"if (float(r_glsl_ascii_mono) != 0.0)\n"
"col = vec3(character(n, p));\n"
"else\n"
"col = col*character(n, p); //note that this is kinda cheating.\n"
@ -10620,7 +10621,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "rtlight",
"!!ver 100 150\n"
"!!ver 100 300\n"
"!!permu TESS\n"
"!!permu BUMP\n"
"!!permu FRAMEBLEND\n"

View File

@ -3592,7 +3592,7 @@ static unsigned short QCC_PR_WriteProgdefs (char *filename)
QCC_PR_Warning(WARN_SYSTEMCRC, NULL, 0, "please update your tenebrae system defs.\n");
break;
default:
QCC_PR_Warning(WARN_SYSTEMCRC, NULL, 0, "progs CRC not recognised from quake nor clones\n");
QCC_PR_Warning(WARN_SYSTEMCRC, NULL, 0, "system defs not recognised from quake nor clones\n");
break;
}

View File

@ -10920,7 +10920,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"runstandardplayerphysics",PF_runclientphys,0,0,0, 347, D("void(entity ent)", "Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement.")},
{"getplayerkeyvalue", PF_Fixme,0, 0, 0, 348, D("string(float playernum, string keyname)", "Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver.\nAlso includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness.")},// (EXT_CSQC)
{"getplayerkeyfloat", PF_Fixme,0, 0, 0, 0, D("float(float playernum, string keyname, optional float assumevalue)", "Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings.")},
{"getplayerkeyblob", PF_Fixme,0, 0, 0, 0, D("int(float playernum, string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"getplayerkeyblob", PF_Fixme,0, 0, 0, 0, D("int(float playernum, string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"getlocalinfo", PF_getlocalinfo,0, 0, 0, 0, D("int(string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"setlocalinfo", PF_setlocalinfo,0, 0, 0, 0, D("void(string keyname, optional void *outptr, int size)", "Changes the server's localinfo. This data will be available for the following map, and will *usually* reload with saved games.")},

View File

@ -142,7 +142,7 @@ pbool SV_ExtendedSaveData(pubprogfuncs_t *progfuncs, void *loadctx, const char *
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
sv.strings.sound_precache[idx] = PR_AddString(svprogfuncs, token, 0, false);
}
else if (!strcmp(token, "particle_precache"))
else if (!strcmp(token, "particle_precache") || !strcmp(token, "particle"))
{ //particle_precache N "MODELNAME"
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
idx = atoi(token);
@ -1674,6 +1674,9 @@ void SV_Savegame_f (void)
Con_TPrintf ("Relative pathnames are not allowed\n");
return;
}
//make sure the name is valid, eg if its omitted.
if (!*savename || strstr(savename, ".."))
savename = "quick";
#ifndef QUAKETC
if (!Q_strcasecmp(Cmd_Argv(0), "savegame_legacy"))
{

View File

@ -159,17 +159,17 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
axis = eaxis;
}
#ifndef CLIENTONLY
if (progstype != PROG_H2 || world != &sv.world)
#endif
eflags &= ~FLH2_NOZ|FLH2_HUNTFACE;
// try the move
// try the move
VectorCopy (ent->v->origin, oldorg);
VectorAdd (ent->v->origin, move, neworg);
// flying monsters don't step up
if ((eflags & (FL_SWIM | FL_FLY)) && !(eflags & (FLH2_NOZ|FLH2_HUNTFACE)))
if ((eflags & (FL_SWIM | FL_FLY))
#if defined(HEXEN2) && defined(HAVE_SERVER)
//hexen2 has some extra logic for FLH2_HUNTFACE, but its buggy and thus never used.
//it would be nice to redefine the NOZ flag to instead force noenemy here, but that's not hexen2-compatible and FLH2_NOZ is bound to conflict with some quake mod.
&& (world != &sv.world || progstype != PROG_H2 || !(eflags & (FLH2_NOZ|FLH2_HUNTFACE))))
#endif
{
// try one move with vertical motion, then one without
for (i=0 ; i<2 ; i++)
@ -182,8 +182,6 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
{
VectorSubtract(ent->v->origin, ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->origin, end);
dz = DotProduct(end, axis[2]);
if (eflags & FLH2_HUNTFACE) /*get the ent's origin_z to match its victims face*/
dz += ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->view_ofs[2];
if (dz > 40)
VectorMA(neworg, -8, axis[2], neworg);
if (dz < 30)
@ -193,7 +191,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
trace = World_Move (world, ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
if (set_move_trace)
set_move_trace(world->progs, &trace);
if (trace.fraction == 1)
{
if ( (eflags & FL_SWIM) && !(World_PointContents(world, trace.endpos) & FTECONTENTS_FLUID))
@ -204,11 +202,11 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
World_LinkEdict (world, ent, true);
return true;
}
if (noenemy || !enemy->entnum)
break;
}
return false;
}

View File

@ -867,7 +867,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
break;
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
{
{ //always in range if within 1024 units (consistent with quakeworld).
vec3_t delta;
VectorSubtract(origin, split->edict->v->origin, delta);
if (DotProduct(delta, delta) <= 1024*1024)
@ -2852,7 +2852,7 @@ static qboolean SV_SyncInfoBuf(client_t *client)
if (info == &svs.info)
pl = 255; //colourmaps being 1-based with these being 0-based means that only 0-254 are valid players, and 255 is unused, so lets use it for serverinfo blobs.
else
pl = (client_t*)info-svs.clients;
pl = (client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients;
ClientReliableWrite_Begin(client, svc_setinfo, 7+strlen(enckey)+1+strlen(encval)+1);
ClientReliableWrite_Byte(client, 255); //special meaning to say that this is a partial update

View File

@ -136,7 +136,7 @@ qboolean World_BoxTrace(struct model_s *model, int hulloverride, int frame, vec3
trace->allsolid = true;
VectorCopy (p2, trace->endpos);
return Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, p1, p2, trace);
return Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, p1, p2, against, trace);
}
qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
{
@ -1174,8 +1174,6 @@ wedict_t *World_TestEntityPosition (world_t *w, wedict_t *ent)
return NULL;
}
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace);
//wrapper function. Rotates the start and end positions around the angles if needed.
//qboolean TransformedHullCheck (hull_t *hull, vec3_t start, vec3_t end, trace_t *trace, vec3_t angles)
qboolean World_TransformedTrace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask)
@ -1223,9 +1221,10 @@ qboolean World_TransformedTrace (struct model_s *model, int hulloverride, frames
VectorSubtract (start, origin, start_l);
VectorSubtract (end, origin, end_l);
VectorCopy (end_l, trace->endpos);
result = Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, trace);
result = Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, start_l, end_l, MASK_PLAYERSOLID, trace);
VectorAdd (trace->endpos, origin, trace->endpos);
trace->contents = FTECONTENTS_BODY;
if (trace->contents)
trace->contents = FTECONTENTS_BODY;
}
else
result = false;

View File

@ -1,4 +1,4 @@
!!ver 100 150
!!ver 100 450
!!permu TESS
!!permu DELUXE
!!permu FULLBRIGHT

View File

@ -1,3 +1,4 @@
!!ver 100 450
!!permu FOG
!!cvarf r_wateralpha
!!samps diffuse lightmap