Too many changes, sorry.

Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide 💩 etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-11-20 03:09:50 +00:00
parent 3e376f4cb2
commit 811bce25f1
112 changed files with 4275 additions and 1538 deletions

View File

@ -25,7 +25,20 @@ EXECUTE_PROCESS(COMMAND
)
IF (NOT "${FTE_REVISON}" STREQUAL "")
SET(FTE_REVISON SVNREVISION=${FTE_REVISON})
MESSAGE(STATUS "FTE SVN Revision ${FTE_REVISON}")
IF(FTE_REVISON MATCHES "M")
MESSAGE(STATUS "--- PRIVATE CHANGES DETECTED ---")
SET(FTE_REVISON SVNREVISION=${FTE_REVISON})
ELSE()
MESSAGE(STATUS "No local changes")
EXECUTE_PROCESS(COMMAND
svn info --show-item last-changed-date --no-newline
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE FTE_DATE
)
SET(FTE_REVISON SVNREVISION="${FTE_REVISON}" SVNDATE="${FTE_DATE}")
ENDIF()
ENDIF()
#plugins need visibility hidden in order to avoid conflicts with function names that match the engine.
@ -981,7 +994,7 @@ ADD_LIBRARY(irc MODULE
plugins/plugin.c
plugins/irc/ircclient.c
)
SET_TARGET_PROPERTIES(irc PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}")
SET_TARGET_PROPERTIES(irc PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_REVISON};${FTE_LIB_DEFINES}")
SET_TARGET_PROPERTIES(irc PROPERTIES PREFIX "fteplug_")
SET_TARGET_PROPERTIES(irc PROPERTIES LINK_FLAGS "-Wl,--no-undefined")
TARGET_LINK_LIBRARIES(irc m)
@ -1073,3 +1086,38 @@ INSTALL(TARGETS ${INSTALLTARGS}
RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}${FTE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
)
ADD_CUSTOM_TARGET(menusys ALL
VERBATIM
COMMAND fteqcc -srcfile "${CMAKE_CURRENT_SOURCE_DIR}/quakec/menusys/menu.src" -o "${CMAKE_CURRENT_BINARY_DIR}/menu.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" "${CMAKE_CURRENT_BINARY_DIR}/menu.lno"
SOURCES
quakec/menusys/menu.src
quakec/menusys/menusys/mitems.qc
quakec/menusys/menusys/mitems_common.qc
quakec/menusys/menusys/mitem_desktop.qc
quakec/menusys/menusys/mitem_exmenu.qc
quakec/menusys/menusys/mitem_edittext.qc
quakec/menusys/menusys/mitem_tabs.qc
quakec/menusys/menusys/mitem_colours.qc
quakec/menusys/menusys/mitem_checkbox.qc
quakec/menusys/menusys/mitem_slider.qc
quakec/menusys/menusys/mitem_combo.qc
quakec/menusys/menusys/mitem_bind.qc
quakec/menusys/menusys/mitem_spinnymodel.qc
quakec/menusys/menu/loadsave.qc
quakec/menusys/menu/newgame.qc
quakec/menusys/menu/options_basic.qc
quakec/menusys/menu/options_effects.qc
quakec/menusys/menu/options_keys.qc
quakec/menusys/menu/options.qc
quakec/menusys/menu/presets.qc
quakec/menusys/menu/servers.qc
quakec/menusys/menu/main.qc
quakec/menusys/menu/options_audio.qc
quakec/menusys/menu/options_configs.qc
quakec/menusys/menu/options_hud.qc
quakec/menusys/menu/options_particles.qc
quakec/menusys/menu/options_video.qc
quakec/menusys/menu/quit.qc
)

View File

@ -19,9 +19,18 @@ else
endif
ifeq ($(SVNREVISION),)
SVNREVISION:=-DSVNREVISION=$(shell test -d $(BASE_DIR)/../.svn && svnversion $(BASE_DIR) || echo -)
SVN_VERSION:=$(shell test -d $(BASE_DIR)/../.svn && svnversion $(BASE_DIR))
SVN_DATE:=$(shell test -d $(BASE_DIR)/../.svn && cd $(BASE_DIR) && svn info --show-item last-changed-date --no-newline)
SVNREVISION=
ifneq (,$(SVN_VERSION))
SVNREVISION+=-DSVNREVISION=$(SVN_VERSION)
endif
MAKE:=$(MAKE) SVNREVISION=$(SVNREVISION)
ifneq (M,$(findstring M,$(SVN_VERSION)))
SVNREVISION+=-DSVNDATE=$(SVN_DATE)
endif
endif
MAKE:=$(MAKE) --no-print-directory SVNREVISION="$(SVNREVISION)"
#WHOAMI:=$(shell whoami)

View File

@ -126,7 +126,7 @@ void CDAudio_Play(int track)
playing = true;
if (!bgmvolume.value)
if (!bgmvolume.value || !mastervolume.value)
CDAudio_Pause ();
}

View File

@ -46,6 +46,7 @@ extern cvar_t r_torch;
extern cvar_t r_shadows;
extern cvar_t r_showbboxes;
extern cvar_t gl_simpleitems;
float r_blobshadows;
extern cvar_t cl_gibfilter, cl_deadbodyfilter;
extern int cl_playerindex;
@ -3087,7 +3088,7 @@ void CLQ1_AddShadow(entity_t *ent)
scenetris_t *t;
cl_adddecal_ctx_t ctx;
if (!r_shadows.value || !ent->model || (ent->model->type != mod_alias && ent->model->type != mod_halflife))
if (!r_blobshadows || !ent->model || (ent->model->type != mod_alias && ent->model->type != mod_halflife))
return;
s = R_RegisterShader("shadowshader", SUF_NONE,
@ -3148,7 +3149,7 @@ void CLQ1_AddShadow(entity_t *ent)
}
ctx.t = t;
Vector4Set(ctx.rgbavalue, 0, 0, 0, r_shadows.value);
Vector4Set(ctx.rgbavalue, 0, 0, 0, r_blobshadows);
Mod_ClipDecal(cl.worldmodel, shadoworg, ctx.axis[0], ctx.axis[1], ctx.axis[2], radius, 0,0, CL_AddDecal_Callback, &ctx);
if (!t->numidx)
cl_numstris--;
@ -4151,8 +4152,33 @@ void CL_LinkPacketEntities (void)
else
{
/*bsp model size*/
VectorAdd(model->mins, ent->origin, absmin);
VectorAdd(model->maxs, ent->origin, absmax);
if (model->type == mod_brush && (state->angles[0]||state->angles[1]||state->angles[2]))
{
int i;
float v;
float max;
//q2 method, works best with origin brushes.
max = 0;
for (i=0 ; i<3 ; i++)
{
v =fabs( model->mins[i]);
if (v > max)
max = v;
v =fabs( model->maxs[i]);
if (v > max)
max = v;
}
for (i=0 ; i<3 ; i++)
{
absmin[i] = ent->origin[i] - max;
absmax[i] = ent->origin[i] + max;
}
}
else
{
VectorAdd(model->mins, ent->origin, absmin);
VectorAdd(model->maxs, ent->origin, absmax);
}
cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &ent->pvscache, absmin, absmax);
}

View File

@ -41,7 +41,7 @@ cvar_t cl_netfps = CVAR("cl_netfps", "150");
cvar_t cl_sparemsec = CVARC("cl_sparemsec", "10", CL_SpareMsec_Callback);
cvar_t cl_queueimpulses = CVAR("cl_queueimpulses", "0");
cvar_t cl_smartjump = CVAR("cl_smartjump", "1");
static cvar_t cl_iDrive = CVARFD("cl_iDrive", "1", CVAR_SEMICHEAT, "Effectively releases movement keys when the opposing key is pressed. This avoids dead-time when both keys are pressed. This can be emulated with various scripts, but that's messy.");
cvar_t cl_iDrive = CVARFD("cl_iDrive", "1", CVAR_SEMICHEAT, "Effectively releases movement keys when the opposing key is pressed. This avoids dead-time when both keys are pressed. This can be emulated with various scripts, but that's messy.");
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;

View File

@ -364,6 +364,9 @@ void CL_UpdateWindowTitle(void)
}
}
#ifdef __linux__
#include <malloc.h>
#endif
void CL_MakeActive(char *gamename)
{
extern int fs_finds;
@ -409,6 +412,10 @@ void CL_MakeActive(char *gamename)
TP_ExecTrigger("f_spawndemo", true);
else
TP_ExecTrigger("f_spawn", false);
#ifdef __linux__
malloc_trim(0);
#endif
}
/*
==================
@ -1802,6 +1809,7 @@ void CL_ClearState (qboolean gamestart)
CL_ResetFog(FOGTYPE_WATER);
CL_ResetFog(FOGTYPE_SKYROOM);
cl.gamespeed = 1;
cl.protocol_qw = PROTOCOL_VERSION_QW; //until we get an svc_serverdata
cl.allocated_client_slots = QWMAX_CLIENTS;
#ifndef CLIENTONLY
@ -4896,10 +4904,10 @@ void CL_Init (void)
Cmd_AddCommand ("kill", NULL);
Cmd_AddCommand ("pause", NULL);
Cmd_AddCommand ("say", CL_Say_f);
Cmd_AddCommand ("me", CL_SayMe_f);
Cmd_AddCommand ("sayone", CL_Say_f);
Cmd_AddCommand ("say_team", CL_SayTeam_f);
Cmd_AddCommandAD ("say", CL_Say_f, Key_EmojiCompletion_c, NULL);
Cmd_AddCommandAD ("me", CL_SayMe_f, Key_EmojiCompletion_c, NULL);
Cmd_AddCommandAD ("sayone", CL_Say_f, Key_EmojiCompletion_c, NULL);
Cmd_AddCommandAD ("say_team", CL_SayTeam_f, Key_EmojiCompletion_c, NULL);
#ifdef CLIENTONLY
Cmd_AddCommand ("serverinfo", NULL);
#else
@ -5892,9 +5900,9 @@ double Host_Frame (double time)
cl.gametimemark += time;
//if we're at a menu/console/thing
idle = !Key_Dest_Has_Higher(kdm_menu);
idle = ((cls.state == ca_disconnected) || cl.paused) && idle; //idle if we're disconnected/paused and not at a menu
idle |= !vid.activeapp; //always idle when tabbed out
// idle = !Key_Dest_Has_Higher(kdm_menu);
// idle = ((cls.state == ca_disconnected) || cl.paused) && idle; //idle if we're disconnected/paused and not at a menu
idle = !vid.activeapp; //always idle when tabbed out
//read packets early and always, so we don't have stuff waiting for reception quite so often.
//should smooth out a few things, and increase download speeds.
@ -6453,8 +6461,6 @@ void CL_ExecInitialConfigs(char *resetcommand)
Cbuf_AddText ("exec q3config.cfg\n", RESTRICT_LOCAL);
else //if (cfg <= def && cfg!=0x7fffffff)
Cbuf_AddText ("exec config.cfg\n", RESTRICT_LOCAL);
// else
// Cbuf_AddText ("exec fte.cfg\n", RESTRICT_LOCAL);
if (def!=FDEPTH_MISSING)
Cbuf_AddText ("exec autoexec.cfg\n", RESTRICT_LOCAL);
}
@ -6521,7 +6527,7 @@ void Host_FinishLoading(void)
SV_ArgumentOverrides();
#endif
Con_Printf ("\n%s\n", version_string());
Con_Printf ("\nEngine: %s\n", version_string());
Con_DPrintf("This program is free software; you can redistribute it and/or "
"modify it under the terms of the GNU General Public License "

View File

@ -3979,7 +3979,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
case 1:
cl.sendprespawn = true;
SCR_SetLoadingFile("loading data");
CL_RequestNextDownload();
CL_RequestNextDownload(); //this sucks, but sometimes mods send csqc-specific messages to us before things are properly inited. if we start doing stuff now then we can minimize the chances of dodgy mods screwing with us. FIXME: warn about receiving csqc messages before begin.
break;
case 2:

View File

@ -152,6 +152,20 @@ static void Plug_FreePlugImages(plugin_t *plug)
}
}
//called before shaders get flushed, to avoid issues later.
void Plug_FreeAllImages(void)
{
size_t i;
for (i = 0; i < pluginimagearraylen; i++)
{
if (pluginimagearray[i].pic)
{
R_UnloadShader(pluginimagearray[i].pic);
pluginimagearray[i].pic = NULL;
}
}
}
static qhandle_t Plug_Draw_LoadImage(const char *name, int type, const char *script)
{
int i;

View File

@ -1188,6 +1188,7 @@ void CL_PredictMovePNum (int seat)
}
if (i == pe->num_entities && pv->nolocalplayer)
{
return; //no player, nothing makes sense any more.
from.state = &nullstate;
nopred = true;
}

View File

@ -243,7 +243,7 @@ cvar_t scr_loadingrefresh = CVARD("scr_loadingrefresh", "0", "Force redrawing of
cvar_t scr_showloading = CVAR("scr_showloading", "1");
//things to configure the legacy loading screen
cvar_t scr_loadingscreen_picture = CVAR("scr_loadingscreen_picture", "gfx/loading");
cvar_t scr_loadingscreen_aspect = CVARD("scr_loadingscreen_aspect", "0", "Controls the aspect of levelshot images.\n0: Use source image's aspect.\n1: Force 4:3 aspect (ignore image's aspect), for best q3 compat.\n2: Ignore aspect considerations and just smear it over the entire screen.");
cvar_t scr_loadingscreen_aspect = CVARD("scr_loadingscreen_aspect", "0", "Controls the aspect of levelshot images.\n0: Use source image's aspect.\n1: Force 4:3 aspect (ignore image's aspect), for best q3 compat.\n2: Ignore aspect considerations and just smear it over the entire screen.\n-1: Disable levelshot use.");
cvar_t scr_loadingscreen_scale = CVAR("scr_loadingscreen_scale", "1");
cvar_t scr_loadingscreen_scale_limit = CVAR("scr_loadingscreen_scale_limit", "2");
@ -2001,7 +2001,7 @@ void SCR_DrawLoading (qboolean opaque)
int qdepth = COM_FDepthFile(qname, true);
int h2depth = COM_FDepthFile("gfx/menu/loading.lmp", true);
if (!(qdepth < h2depth || h2depth > FDEPTH_MISSING))
if (qdepth < h2depth && h2depth != FDEPTH_MISSING)
{ //hexen2 files.
//hexen2 has some fancy sliders built into its graphics in specific places. so this is messy.
pic = R2D_SafeCachePic ("gfx/menu/loading.lmp");
@ -2225,7 +2225,7 @@ void SCR_ImageName (const char *mapname)
strcpy(levelshotname, "levelshots/");
COM_FileBase(mapname, levelshotname + strlen(levelshotname), sizeof(levelshotname)-strlen(levelshotname));
if (qrenderer)
if (qrenderer && scr_loadingscreen_aspect.ival >= 0)
{
R_LoadHiResTexture(levelshotname, NULL, IF_NOWORKER|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP);
@ -2468,7 +2468,7 @@ static void SCR_ScreenShot_f (void)
Con_Printf (CON_ERROR "Couldn't get colour buffer for screenshot\n");
}
void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt, qboolean no2d)
void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt, qboolean no2d, qboolean hdr)
{
int width, height;
void *buf;
@ -2489,7 +2489,7 @@ void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum upload
{
r_refdef.warndraw = true;
Q_strncpyz(r_refdef.rt_destcolour[0].texname, "megascreeny", sizeof(r_refdef.rt_destcolour[0].texname));
/*vid.framebuffer =*/R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, fbwidth, fbheight, 1, RT_IMAGEFLAGS);
/*vid.framebuffer =*/R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, fbwidth, fbheight, (hdr&&sh_config.texfmt[PTI_RGBA16F])?PTI_RGBA16F:PTI_RGBA8, RT_IMAGEFLAGS);
BE_RenderToTextureUpdate2d(true);
}
else
@ -2639,7 +2639,7 @@ static void SCR_ScreenShot_Mega_f(void)
r_refdef.stereomethod = STEREO_LEFTONLY;
}
buffers[buf] = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride[buf], &fmt[buf], false);
buffers[buf] = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride[buf], &fmt[buf], false, false);
width[buf] = fbwidth;
height[buf] = fbheight;
@ -2754,7 +2754,7 @@ static void SCR_ScreenShot_VR_f(void)
r_refdef.eyeoffset[0] = sin(ang) * r_stereo_separation.value * 0.5;
r_refdef.eyeoffset[1] = cos(ang) * r_stereo_separation.value * 0.5;
r_refdef.eyeoffset[2] = 0;
buf = SCR_ScreenShot_Capture(width, height, &stride, &fmt, true);
buf = SCR_ScreenShot_Capture(width, height, &stride, &fmt, true, false);
switch(fmt)
{
case TF_BGRA32:
@ -2788,7 +2788,7 @@ static void SCR_ScreenShot_VR_f(void)
r_refdef.eyeoffset[0] *= -1;
r_refdef.eyeoffset[1] *= -1;
r_refdef.eyeoffset[2] = 0;
buf = SCR_ScreenShot_Capture(width, height, &stride, &fmt, true);
buf = SCR_ScreenShot_Capture(width, height, &stride, &fmt, true, false);
switch(fmt)
{
case TF_BGRA32:
@ -2901,7 +2901,7 @@ void SCR_ScreenShot_Cubemap_f(void)
mips.type = PTI_CUBE;
mips.encoding = 0;
mips.extrafree = NULL;
mips.mipcount = 6;
mips.mipcount = 1;
bb=0;
for (i = 0; i < 6; i++)
@ -2909,7 +2909,7 @@ void SCR_ScreenShot_Cubemap_f(void)
VectorCopy(sides[i].angle, cl.playerview->simangles);
VectorCopy(cl.playerview->simangles, cl.playerview->viewangles);
facedata = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true);
facedata = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true, true);
if (!facedata)
break;
if (!i)
@ -2941,6 +2941,10 @@ void SCR_ScreenShot_Cubemap_f(void)
}
if (i == 6)
{
qboolean pixelformats[PTI_MAX] = {0};
pixelformats[PTI_E5BGR9] = true;
Image_ChangeFormat(&mips, pixelformats, mips.encoding, fname);
Q_snprintfz(filename, sizeof(filename), "textures/%s", fname);
COM_DefaultExtension (filename, ext, sizeof(filename));
#ifdef IMAGEFMT_KTX
@ -2975,9 +2979,8 @@ void SCR_ScreenShot_Cubemap_f(void)
else
Con_Printf ("%s: Unknown format %s\n", Cmd_Argv(0), filename);
}
while (i-- > 0)
if (mips.mip[i].needfree)
BZ_Free(mips.mip[i].data);
if (mips.mip[0].needfree)
BZ_Free(mips.mip[0].data);
}
else
{
@ -2986,7 +2989,7 @@ void SCR_ScreenShot_Cubemap_f(void)
VectorCopy(sides[i].angle, cl.playerview->simangles);
VectorCopy(cl.playerview->simangles, cl.playerview->viewangles);
buffer = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true);
buffer = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true, false);
if (buffer)
{
Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh);

View File

@ -1146,7 +1146,7 @@ void CL_ParseTEnt (void)
if (type < countof(te_names))
Con_Printf(" te_%s\n", te_names[type]);
else
Con_Printf(" te_%i\n", type);
Con_Printf(" te_unknown_%i\n", type);
}
switch (type)

View File

@ -309,7 +309,7 @@ typedef struct
#define LFLAG_ORTHO (1<<11) //sun-style -light
#define LFLAG_INTERNAL (LFLAG_LIGHTMAP|LFLAG_FLASHBLEND) //these are internal to FTE, and never written to disk (ie: .rtlights files shouldn't contain these)
#define LFLAG_DYNAMIC (LFLAG_LIGHTMAP | LFLAG_FLASHBLEND | LFLAG_NORMALMODE | LFLAG_REALTIMEMODE)
#define LFLAG_DYNAMIC (LFLAG_LIGHTMAP | LFLAG_FLASHBLEND | LFLAG_NORMALMODE)
typedef struct dlight_s
{
@ -1619,7 +1619,7 @@ void Validation_FlushFileList(void);
void Validation_CheckIfResponse(char *text);
void Validation_DelatchRulesets(void);
void InitValidation(void);
void Validation_IncludeFile(char *filename, char *file, int filelen);
void Validation_FileLoaded(const char *filename, const qbyte *filedata, size_t filesize);
void Validation_Auto_Response(int playernum, char *s);
extern qboolean f_modified_particles;

View File

@ -580,8 +580,13 @@ void Con_History_Load(void)
}
void Con_History_Save(void)
{
vfsfile_t *file = FS_OpenVFS("conhistory.txt", "wb", FS_ROOT);
vfsfile_t *file;
int line;
if (!FS_GameIsInitialised())
return;
file = FS_OpenVFS("conhistory.txt", "wb", FS_ROOT);
if (file)
{
line = edit_line - CON_EDIT_LINES_MASK;
@ -2958,7 +2963,7 @@ void Con_DrawConsole (int lines, qboolean noback)
shader = R2D_SafeCachePic("tiprawimg");
shader->defaulttextures->base = Image_TextureIsValid(strtoull(key, NULL, 0));
}
if (shader && shader->defaulttextures->base)
if (shader && shader->defaulttextures->base && shader->defaulttextures->base->status == TEX_LOADED && ((shader->defaulttextures->base->flags&IF_TEXTYPEMASK) == (PTI_2D<<IF_TEXTYPESHIFT)))
{
shader->width = shader->defaulttextures->base->width;
shader->height = shader->defaulttextures->base->height;
@ -2973,6 +2978,8 @@ void Con_DrawConsole (int lines, qboolean noback)
shader->height = 240;
}
}
else
shader = NULL;
key = Info_ValueForKey(info, "modelviewer");
if (*key)
{

View File

@ -3678,8 +3678,8 @@ static void *ReadPSDFile(qbyte *buf, size_t len, const char *fname, int *outwidt
struct xcf_s
{
const qbyte *filestart;
size_t filesize;
size_t offset;
qofs_t filesize;
qofs_t offset;
unsigned int version;
qbyte compression;
@ -3692,7 +3692,7 @@ struct xcf_s
size_t *layeroffsets;
qbyte *flat;
};
static unsigned int XCF_ReadData(struct xcf_s *f, qbyte *out, size_t len)
static size_t XCF_ReadData(struct xcf_s *f, qbyte *out, size_t len)
{
size_t avail;
if (f->offset >= f->filesize)
@ -3731,7 +3731,7 @@ static float XCF_ReadFloat(struct xcf_s *f)
u.u = (w[0]<<24)|(w[1]<<16)|(w[2]<<8)|(w[3]<<0);
return u.f;
}
static size_t XCF_ReadOffset(struct xcf_s *f)
static qofs_t XCF_ReadOffset(struct xcf_s *f)
{ //XCF is natively big-endian.
qbyte w[8];
size_t h, l;
@ -3740,7 +3740,7 @@ static size_t XCF_ReadOffset(struct xcf_s *f)
XCF_ReadData(f, w, sizeof(w));
h = (w[0]<<24)|(w[1]<<16)|(w[2]<<8)|(w[3]<<0);
l = (w[4]<<24)|(w[5]<<16)|(w[6]<<8)|(w[7]<<0);
return (h<<32)|l;
return qofs_Make(l, h);
}
return XCF_Read32(f);
}
@ -3878,7 +3878,7 @@ static struct xcf_heirachy_s XCF_ReadHeirachy(struct xcf_s *f)
{
struct xcf_heirachy_s ctx;
uint32_t x, y, lw, lh;
size_t ofs, tofs;
qofs_t ofs, tofs;
if (!f->offset)
{
memset(&ctx, 0, sizeof(ctx));
@ -4593,6 +4593,58 @@ static void Image_LoadTexture_Failed(void *ctx, void *data, size_t a, size_t b)
texid_t tex = ctx;
tex->status = TEX_FAILED;
}
static void Image_FixupImageSize(texid_t tex, unsigned int w, unsigned int h)
{
tex->width = w;
tex->height = h;
//ezhud breaks without this. I assume other things will too. this is why you shouldn't depend upon querying an image's size.
if (!strncmp(tex->ident, "gfx/", 4))
{
size_t lumpsize;
qbyte lumptype;
qpic_t *pic = W_GetLumpName(tex->ident+4, &lumpsize, &lumptype);
if (pic && lumptype == TYP_QPIC && lumpsize >= 8)
{
w = LittleLong(pic->width);
h = LittleLong(pic->height);
if (lumpsize == 8 + w*h)
{
tex->width = w;
tex->height = h;
}
}
else
{
vfsfile_t *f;
const char *ext = COM_GetFileExtension(tex->ident, NULL);
if (!strcmp(ext, ".lmp"))
f = FS_OpenVFS(tex->ident, "rb", FS_GAME);
else if (!*ext)
{
char nname[MAX_QPATH+4];
Q_snprintfz(nname, sizeof(nname), "%s.lmp", tex->ident);
f = FS_OpenVFS(nname, "rb", FS_GAME);
}
else
f = NULL;
if (f)
{
unsigned int wh[2];
size_t size = VFS_GETLEN(f);
VFS_READ(f, wh, 8);
VFS_CLOSE(f);
if (size == 8+wh[0]*wh[1])
{
tex->width = wh[0];
tex->height = wh[1];
}
}
}
}
//FIXME: check loaded wad files too.
}
static void Image_LoadTextureMips(void *ctx, void *data, size_t a, size_t b)
{
int i;
@ -4657,20 +4709,6 @@ static void Image_LoadTextureMips(void *ctx, void *data, size_t a, size_t b)
if (mips->extrafree)
BZ_Free(mips->extrafree);
BZ_Free(mips);
//ezhud breaks without this. I assume other things will too. this is why you shouldn't depend upon querying an image's size.
if (!strncmp(tex->ident, "gfx/", 4))
{
size_t lumpsize;
qbyte lumptype;
qpic_t *pic = W_GetLumpName(tex->ident+4, &lumpsize, &lumptype);
if (pic && lumptype == TYP_QPIC && lumpsize == 8 + pic->width*pic->height)
{
tex->width = pic->width;
tex->height = pic->height;
}
}
//FIXME: check loaded wad files too.
}
#endif
@ -6632,6 +6670,86 @@ qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_
return NULL;
}
static void Image_MipMap1X8 (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight)
{
int i, j;
qbyte *inrow;
int rowwidth = inwidth; //rowwidth is the byte width of the input
inrow = in;
//mips round down, except for when the input is 1. which bugs out.
if (inwidth <= 1 && inheight <= 1)
out[0] = in[0];
else if (inheight <= 1)
{
//single row, don't peek at the next
for (in = inrow, j=0 ; j<outwidth ; j++, out+=1, in+=2)
out[0] = (in[0] + in[1])>>1;
}
else if (inwidth <= 1)
{
//single colum, peek only at this pixel
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
for (in = inrow, j=0 ; j<outwidth ; j++, out+=1, in+=2)
out[0] = (in[0] + in[rowwidth+0])>>1;
}
else
{
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
for (in = inrow, j=0 ; j<outwidth ; j++, out+=1, in+=2)
out[0] = (in[0] + in[1] + in[rowwidth+0] + in[rowwidth+1])>>2;
}
}
static void Image_MipMap2X8 (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight)
{
int i, j;
qbyte *inrow;
int rowwidth = inwidth*2; //rowwidth is the byte width of the input
inrow = in;
//mips round down, except for when the input is 1. which bugs out.
if (inwidth <= 1 && inheight <= 1)
{
out[0] = in[0];
out[1] = in[1];
}
else if (inheight <= 1)
{
//single row, don't peek at the next
for (in = inrow, j=0 ; j<outwidth ; j++, out+=2, in+=4)
{
out[0] = (in[0] + in[2])>>1;
out[1] = (in[1] + in[3])>>1;
}
}
else if (inwidth <= 1)
{
//single colum, peek only at this pixel
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
{
for (in = inrow, j=0 ; j<outwidth ; j++, out+=2, in+=4)
{
out[0] = (in[0] + in[rowwidth+0])>>1;
out[1] = (in[1] + in[rowwidth+1])>>1;
}
}
}
else
{
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
{
for (in = inrow, j=0 ; j<outwidth ; j++, out+=2, in+=4)
{
out[0] = (in[0] + in[2] + in[rowwidth+0] + in[rowwidth+2])>>2;
out[1] = (in[1] + in[3] + in[rowwidth+1] + in[rowwidth+3])>>2;
}
}
}
}
static void Image_MipMap3X8 (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight)
{
int i, j;
@ -6990,38 +7108,6 @@ static void Image_MipMap4X32F (float *in, int inwidth, int inheight, float *out,
}
}
static void Image_MipMap1X8 (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight)
{
int i, j;
qbyte *inrow;
int rowwidth = inwidth; //rowwidth is the byte width of the input
inrow = in;
//mips round down, except for when the input is 1. which bugs out.
if (inwidth <= 1 && inheight <= 1)
out[0] = in[0];
else if (inheight <= 1)
{
//single row, don't peek at the next
for (in = inrow, j=0 ; j<outwidth ; j++, out+=1, in+=2)
out[0] = (in[0] + in[1])>>1;
}
else if (inwidth <= 1)
{
//single colum, peek only at this pixel
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
for (in = inrow, j=0 ; j<outwidth ; j++, out+=1, in+=2)
out[0] = (in[0] + in[rowwidth+0])>>1;
}
else
{
for (i=0 ; i<outheight ; i++, inrow+=rowwidth*2)
for (in = inrow, j=0 ; j<outwidth ; j++, out+=1, in+=2)
out[0] = (in[0] + in[1] + in[rowwidth+0] + in[rowwidth+1])>>2;
}
}
static qbyte Image_BlendPalette_2(qbyte a, qbyte b)
{
return a;
@ -7101,6 +7187,9 @@ void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int flags)
}
return;
case PTI_R8:
case PTI_R8_SNORM:
case PTI_L8:
case PTI_L8_SRGB:
for (mip = mips->mipcount; mip < 32; mip++)
{
mips->mip[mip].width = mips->mip[mip-1].width >> 1;
@ -7119,6 +7208,29 @@ void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int flags)
Image_MipMap1X8(mips->mip[mip-1].data, mips->mip[mip-1].width, mips->mip[mip-1].height, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height);
mips->mipcount = mip+1;
}
return;
case PTI_RG8:
case PTI_RG8_SNORM:
case PTI_L8A8:
case PTI_L8A8_SRGB:
for (mip = mips->mipcount; mip < 32; mip++)
{
mips->mip[mip].width = mips->mip[mip-1].width >> 1;
mips->mip[mip].height = mips->mip[mip-1].height >> 1;
mips->mip[mip].depth = 1;
if (mips->mip[mip].width < 1 && mips->mip[mip].height < 1)
break;
if (mips->mip[mip].width < 1)
mips->mip[mip].width = 1;
if (mips->mip[mip].height < 1)
mips->mip[mip].height = 1;
mips->mip[mip].datasize = mips->mip[mip].width * mips->mip[mip].height * 2;
mips->mip[mip].data = BZ_Malloc(mips->mip[mip].datasize);
mips->mip[mip].needfree = true;
Image_MipMap2X8(mips->mip[mip-1].data, mips->mip[mip-1].width, mips->mip[mip-1].height, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height);
mips->mipcount = mip+1;
}
return;
case PTI_RGBA32F:
for (mip = mips->mipcount; mip < 32; mip++)
@ -7195,7 +7307,7 @@ void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int flags)
mips->mip[mip].width = 1;
if (mips->mip[mip].height < 1)
mips->mip[mip].height = 1;
mips->mip[mip].datasize = mips->mip[mip].width * mips->mip[mip].height * sizeof(qbyte)*4;
mips->mip[mip].datasize = mips->mip[mip].width * mips->mip[mip].height * sizeof(qbyte)*3;
mips->mip[mip].data = BZ_Malloc(mips->mip[mip].datasize);
mips->mip[mip].needfree = true;
@ -7695,6 +7807,28 @@ static void Image_Tr_NoTransform(struct pendingtextureinfo *mips, int dummy)
{
}
//may operate in place
static void Image_Tr_RGBX8toPaletted(struct pendingtextureinfo *mips, int dummy)
{
unsigned int mip;
for (mip = 0; mip < mips->mipcount; mip++)
{
qbyte *in = mips->mip[mip].data;
qbyte *out = mips->mip[mip].data;
unsigned int p = mips->mip[mip].width*mips->mip[mip].height*mips->mip[mip].depth;
unsigned short tmp;
if (!mips->mip[mip].needfree && !mips->extrafree)
{
mips->mip[mip].needfree = true;
mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p);
}
mips->mip[mip].datasize = p*sizeof(*out);
for(; p-->0; in += 4)
*out++ = GetPaletteIndexNoFB(in[0], in[1], in[2]);
}
}
//may operate in place
static void Image_Tr_8888toLuminence(struct pendingtextureinfo *mips, int channels)
{ //channels==1?L8
@ -10775,49 +10909,15 @@ static struct
{PTI_RGBA32F, PTI_RGB32F, Image_Tr_DropBytes, (16<<16)|12, true},
{PTI_RG8, PTI_RGBX8, Image_Tr_RG8ToRGXX8},
{PTI_RGBX8, PTI_P8, Image_Tr_RGBX8toPaletted},
};
void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, uploadfmt_t origfmt, const char *imagename)
void Image_ChangeFormat(struct pendingtextureinfo *mips, qboolean *allowedformats, uploadfmt_t origfmt, const char *imagename)
{
int mip;
if (flags & IF_PALETTIZE)
{
Image_DecompressFormat(mips, NULL); //force-decompress it, so that we can palettise it.
if (mips->encoding == PTI_RGBX8 || mips->encoding == PTI_RGBA8)
{
mips->encoding = PTI_P8;
for (mip = 0; mip < mips->mipcount; mip++)
{
unsigned int i;
unsigned char *out;
unsigned char *in;
void *needfree = NULL;
in = mips->mip[mip].data;
if (!in)
continue;
if (mips->mip[mip].needfree)
out = in;
else
{
needfree = in;
out = BZ_Malloc(mips->mip[mip].width*mips->mip[mip].height*sizeof(*out));
mips->mip[mip].data = out;
}
mips->mip[mip].datasize = mips->mip[mip].width*mips->mip[mip].height;
mips->mip[mip].needfree = true;
for (i = 0; i < mips->mip[mip].width*mips->mip[mip].height; i++, in+=4)
out[i] = GetPaletteIndexNoFB(in[0], in[1], in[2]);
if (needfree)
BZ_Free(needfree);
}
}
}
if (!allowedformats)
allowedformats = sh_config.texfmt;
//if that format isn't supported/desired, try converting it.
if (sh_config.texfmt[mips->encoding])
if (allowedformats[mips->encoding])
{
if (mips->encoding >= PTI_ASTC_FIRST && mips->encoding <= PTI_ASTC_LAST)
return; //ignore texture_allow_block_padding for astc.
@ -10837,7 +10937,7 @@ void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, upl
//when the format can't be used, decompress it if its one of those awkward compressed formats.
Image_DecompressFormat(mips, imagename);
if (sh_config.texfmt[mips->encoding])
if (allowedformats[mips->encoding])
return; //okay, that got it.
@ -10849,7 +10949,7 @@ void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, upl
{
if (formattransforms[i].src == src)
{
if (sh_config.texfmt[formattransforms[i].dest])
if (allowedformats[formattransforms[i].dest])
{
if (formattransforms[i].onebitalpha && !onebitokay)
{
@ -10873,7 +10973,7 @@ void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, upl
for (j = 0; j < countof(formattransforms); j++)
{
if (formattransforms[j].src == formattransforms[i].dest)
if (sh_config.texfmt[formattransforms[j].dest])
if (allowedformats[formattransforms[j].dest])
{
first = i;
sec = j;
@ -10896,11 +10996,23 @@ void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, upl
mips->encoding = formattransforms[sec].dest;
}
if (sh_config.texfmt[mips->encoding])
if (allowedformats[mips->encoding])
return; //okay, that got it.
}
}
static void Image_ChangeFormatFlags(struct pendingtextureinfo *mips, unsigned int flags, uploadfmt_t origfmt, const char *imagename)
{
if (flags & IF_PALETTIZE)
{
qboolean p8only[PTI_MAX] = {0};
p8only[PTI_P8] = true;
Image_ChangeFormat(mips, p8only, origfmt, imagename);
}
else
Image_ChangeFormat(mips, sh_config.texfmt, origfmt, imagename);
}
//resamples and depalettes as required
//ALWAYS frees rawdata, even on failure (but never mips).
static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flags, void *rawdata, void *palettedata, int imgwidth, int imgheight, uploadfmt_t fmt, qboolean freedata)
@ -11315,7 +11427,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
rgbadata = BZ_Malloc(imgwidth * imgheight*4);
for (i = 0; i < imgwidth * imgheight; i++)
{
static const int ColorIndex[16] = {0, 31, 47, 63, 79, 95, 111, 127, 143, 159, 175, 191, 199, 207, 223, 231};
static const int ColorIndex[16] = {0x00, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf, 0xbf, 0xc7, 0xcf, 0xdf, 0xe7};
static const unsigned ColorPercent[16] = {25, 51, 76, 102, 114, 127, 140, 153, 165, 178, 191, 204, 216, 229, 237, 247};
qbyte p = ((qbyte*)rawdata)[i];
rgbadata[i] = d_8to24rgbtable[ColorIndex[p>>4]] & 0x00ffffff;
@ -11912,7 +12024,7 @@ struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname
memmove(mips->mip, mips->mip+i, sizeof(*mips->mip)*mips->mipcount);
}
Image_ChangeFormat(mips, flags, TF_INVALID, fname);
Image_ChangeFormatFlags(mips, flags, TF_INVALID, fname);
return mips;
}
@ -11953,7 +12065,7 @@ struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname
if (Image_GenMip0(mips, flags, rgbadata, NULL, imgwidth, imgheight, format, true))
{
Image_GenerateMips(mips, flags);
Image_ChangeFormat(mips, flags, format, fname);
Image_ChangeFormatFlags(mips, flags, format, fname);
BZ_Free(filedata);
return mips;
}
@ -12230,11 +12342,9 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd
return false;
}
Image_GenerateMips(mips, flags);
Image_ChangeFormat(mips, flags, fmt, tex->ident);
tex->width = imgwidth;
tex->height = imgheight;
Image_ChangeFormatFlags(mips, flags, fmt, tex->ident);
Image_FixupImageSize(tex, imgwidth, imgheight);
if (flags & IF_NOWORKER)
Image_LoadTextureMips(tex, mips, 0, 0);
else
@ -12252,8 +12362,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname,
BZ_Free(tex->fallbackdata);
tex->fallbackdata = NULL;
tex->width = mips->mip[0].width;
tex->height = mips->mip[0].height;
Image_FixupImageSize(tex, mips->mip[0].width, mips->mip[0].height);
if ((flags & IF_NOWORKER) || Sys_IsMainThread())
Image_LoadTextureMips(tex, mips, 0, 0);
else
@ -12606,9 +12715,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
if (mips)
{
tex->width = mips->mip[0].width;
tex->height = mips->mip[0].height;
Image_FixupImageSize(tex, mips->mip[0].width, mips->mip[0].height);
if (tex->flags & IF_NOWORKER)
Image_LoadTextureMips(tex, mips, 0, 0);
else
@ -12980,7 +13087,7 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in
if (!Image_GenMip0(&mips, flags, data, palette, width, height, fmt, false))
return;
Image_GenerateMips(&mips, flags);
Image_ChangeFormat(&mips, flags, fmt, tex->ident);
Image_ChangeFormatFlags(&mips, flags, fmt, tex->ident);
rf->IMG_LoadTextureMips(tex, &mips);
tex->format = fmt;
tex->width = width;
@ -13148,7 +13255,8 @@ void Image_List_f(void)
failed++;
continue;
}
Con_Printf("^[\\imgptr\\%#"PRIxSIZE"^]", (size_t)tex);
if (((tex->flags&IF_TEXTYPEMASK)>>IF_TEXTYPESHIFT) == PTI_2D)
Con_Printf("^[\\imgptr\\%#"PRIxSIZE"^]", (size_t)tex);
if (tex->subpath)
Con_Printf("^h(%s)^h", tex->subpath);
Con_DLPrintf(1, " %x", tex->flags);
@ -13160,10 +13268,10 @@ void Image_List_f(void)
while((bullshit=strchr(defuck, '\\')))
*bullshit = '/';
// if ((tex->flags&(IF_CLAMP|IF_PALETTIZE)) == 0)
if (((tex->flags&IF_TEXTYPEMASK)>>IF_TEXTYPESHIFT) == PTI_2D || tex->format == PTI_P8)
Con_Printf("^[%s\\tip\\%s/%s\\tipimgptr\\%#"PRIxSIZE"^]: ", tex->ident, defuck, fname, (size_t)tex);
// else
// Con_Printf("^[%s\\tip\\%s/%s^]: ", tex->ident, defuck, fname);
else
Con_Printf("^[%s\\tip\\%s/%s^]: ", tex->ident, defuck, fname);
}
else
{
@ -13324,6 +13432,7 @@ void Image_Shutdown(void)
image_t *tex;
int i = 0, j = 0;
Cmd_RemoveCommand("r_imagelist");
Cmd_RemoveCommand("r_imageformats");
while (imagelist)
{
tex = imagelist;

View File

@ -790,7 +790,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
if (m_accel.value)
{
if (m_accel_style.ival)
if (m_accel_style.ival && frametime)
{
float accelsens = sensitivity.value*in_sensitivityscale;
float mousespeed = (sqrt (mx * mx + my * my)) / (1000.0f * (float) frametime);

View File

@ -627,7 +627,12 @@ static void INS_DeactivateMouse (void)
ClipCursor (NULL);
ReleaseCapture ();
SetCursorPos(window_rect.left+mousecursor_x, window_rect.top+mousecursor_y);
if (!vid.forcecursor)
{
vid.forcecursor = true;
vid.forcecursorpos[0] = mousecursor_x;
vid.forcecursorpos[1] = mousecursor_y;
}
}
mouseactive = false;
@ -729,6 +734,14 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
INS_ActivateMouse();
else
INS_DeactivateMouse();
if (vid.forcecursor && !mouseactive)
{
vid.forcecursor = false;
if (activeapp)
SetCursorPos(window_rect.left+vid.forcecursorpos[0], window_rect.top+vid.forcecursorpos[1]);
}
}

View File

@ -49,7 +49,7 @@ int key_count; // incremented every key event
int key_bindmaps[2];
char *keybindings[K_MAX][KEY_MODIFIERSTATES];
qbyte bindcmdlevel[K_MAX][KEY_MODIFIERSTATES];
qbyte bindcmdlevel[K_MAX][KEY_MODIFIERSTATES]; //should be a struct, but not due to 7 bytes wasted per on 64bit machines
qboolean consolekeys[K_MAX]; // if true, can't be rebound while in console
int keyshift[K_MAX]; // key to map to if shift held down in console
int key_repeats[K_MAX]; // if > 1, it is autorepeating
@ -1273,74 +1273,166 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode)
#endif
}
const char *Key_Demoji(char *buffer, size_t buffersize, const char *in)
{
static const struct
{
const char *pattern;
const char *repl;
} emoji[] =
{
//https://www.webpagefx.com/tools/emoji-cheat-sheet/
// {":)", "\xE2\x98\xBA"},
static qbyte *emojidata = NULL;
static const qbyte *builtinemojidata =
// "\x02\x03" ":)" "\xE2\x98\xBA"
#ifdef QUAKEHUD
{":sg:", "\xEE\x84\x82"},
{":ssg:", "\xEE\x84\x83"},
{":ng:", "\xEE\x84\x84"},
{":sng:", "\xEE\x84\x85"},
{":gl:", "\xEE\x84\x86"},
{":rl:", "\xEE\x84\x87"},
{":lg:", "\xEE\x84\x88"},
"\x04\x03" ":sg:" "\xEE\x84\x82"
"\x05\x03" ":ssg:" "\xEE\x84\x83"
"\x04\x03" ":ng:" "\xEE\x84\x84"
"\x05\x03" ":sng:" "\xEE\x84\x85"
"\x04\x03" ":gl:" "\xEE\x84\x86"
"\x04\x03" ":rl:" "\xEE\x84\x87"
"\x04\x03" ":lg:" "\xEE\x84\x88"
{":sg2:", "\xEE\x84\x92"},
{":ssg2:", "\xEE\x84\x93"},
{":ng2:", "\xEE\x84\x94"},
{":sng2:", "\xEE\x84\x95"},
{":gl2:", "\xEE\x84\x96"},
{":rl2:", "\xEE\x84\x97"},
{":lg2:", "\xEE\x84\x98"},
"\x05\x03" ":sg2:" "\xEE\x84\x92"
"\x06\x03" ":ssg2:" "\xEE\x84\x93"
"\x05\x03" ":ng2:" "\xEE\x84\x94"
"\x06\x03" ":sng2:" "\xEE\x84\x95"
"\x05\x03" ":gl2:" "\xEE\x84\x96"
"\x05\x03" ":rl2:" "\xEE\x84\x97"
"\x05\x03" ":lg2:" "\xEE\x84\x98"
{":shells:", "\xEE\x84\xA0"},
{":nails:", "\xEE\x84\xA1"},
{":rocket:", "\xEE\x84\xA2"},
{":cells:", "\xEE\x84\xA3"},
{":ga:", "\xEE\x84\xA4"},
{":ya:", "\xEE\x84\xA5"},
{":ra:", "\xEE\x84\xA6"},
"\x08\x03" ":shells:" "\xEE\x84\xA0"
"\x07\x03" ":nails:" "\xEE\x84\xA1"
"\x08\x03" ":rocket:" "\xEE\x84\xA2"
"\x07\x03" ":cells:" "\xEE\x84\xA3"
"\x04\x03" ":ga:" "\xEE\x84\xA4"
"\x04\x03" ":ya:" "\xEE\x84\xA5"
"\x04\x03" ":ra:" "\xEE\x84\xA6"
{":key1:", "\xEE\x84\xB0"},
{":key2:", "\xEE\x84\xB1"},
{":ring:", "\xEE\x84\xB2"},
{":pent:", "\xEE\x84\xB3"},
{":suit:", "\xEE\x84\xB4"},
{":quad:", "\xEE\x84\xB5"},
{":sigil1:", "\xEE\x84\xB6"},
{":sigil2:", "\xEE\x84\xB7"},
{":sigil3:", "\xEE\x84\xB8"},
{":sigil4:", "\xEE\x84\xB9"},
"\x06\x03" ":key1:" "\xEE\x84\xB0"
"\x06\x03" ":key2:" "\xEE\x84\xB1"
"\x06\x03" ":ring:" "\xEE\x84\xB2"
"\x06\x03" ":pent:" "\xEE\x84\xB3"
"\x06\x03" ":suit:" "\xEE\x84\xB4"
"\x06\x03" ":quad:" "\xEE\x84\xB5"
"\x08\x03" ":sigil1:" "\xEE\x84\xB6"
"\x08\x03" ":sigil2:" "\xEE\x84\xB7"
"\x08\x03" ":sigil3:" "\xEE\x84\xB8"
"\x08\x03" ":sigil4:" "\xEE\x84\xB9"
{":face1:", "\xEE\x85\x80"},
{":face_p1:", "\xEE\x85\x81"},
{":face2:", "\xEE\x85\x82"},
{":face_p2:", "\xEE\x85\x83"},
{":face3:", "\xEE\x85\x84"},
{":face_p3:", "\xEE\x85\x85"},
{":face4:", "\xEE\x85\x86"},
{":face_p4:", "\xEE\x85\x87"},
{":face5:", "\xEE\x85\x88"},
{":face_p5:", "\xEE\x85\x89"},
{":face_invis:", "\xEE\x85\x8A"},
{":face_invul2:", "\xEE\x85\x8B"},
{":face_inv2:", "\xEE\x85\x8C"},
{":face_quad:", "\xEE\x85\x8D"},
"\x07\x03" ":face1:" "\xEE\x85\x80"
"\x09\x03" ":face_p1:" "\xEE\x85\x81"
"\x07\x03" ":face2:" "\xEE\x85\x82"
"\x09\x03" ":face_p2:" "\xEE\x85\x83"
"\x07\x03" ":face3:" "\xEE\x85\x84"
"\x09\x03" ":face_p3:" "\xEE\x85\x85"
"\x07\x03" ":face4:" "\xEE\x85\x86"
"\x09\x03" ":face_p4:" "\xEE\x85\x87"
"\x07\x03" ":face5:" "\xEE\x85\x88"
"\x09\x03" ":face_p5:" "\xEE\x85\x89"
"\x0c\x03" ":face_invis:" "\xEE\x85\x8A"
"\x0d\x03" ":face_invul2:" "\xEE\x85\x8B"
"\x0b\x03" ":face_inv2:" "\xEE\x85\x8C"
"\x0b\x03" ":face_quad:" "\xEE\x85\x8D"
#endif
};
"";
static void Key_LoadEmojiList(void)
{
qbyte line[1024];
char nam[64];
char rep[64];
vfsfile_t *f;
char *json = FS_MallocFile("emoji.json", FS_GAME, NULL); //https://unicodey.com/emoji-data/emoji.json
emojidata = Z_StrDup(builtinemojidata);
if (json)
{
char *unified;
for (unified = json; (unified = strstr(unified, ",\"unified\":\"")); )
{
int i = 0;
char *t;
char *sn;
unsigned int u;
unified += 12;
t = unified;
//do
//{
u = strtol(t, &t, 16);
i += utf8_encode(rep+i, u, countof(rep)-i);
//} while (i < countof(rep) && *t++ == '-');
if (*t!='\"')
continue;
rep[i] = 0;
sn = strstr(unified, "\"short_names\":[");
if (sn)
{
sn += 15;
while (sn && *sn == '\"')
{
sn = COM_ParseTokenOut(sn, NULL, nam+1, sizeof(nam)-1, NULL);
nam[0] = ':';
Q_strncatz(nam, ":", sizeof(nam));
line[0] = strlen(nam);
line[1] = strlen(rep);
strcpy(line+2, nam);
strcpy(line+2+line[0], rep);
Z_StrCat((char**)&emojidata, line);
}
}
}
FS_FreeFile(json);
}
f = FS_OpenVFS("emoji.lst", "rb", FS_GAME);
if (f)
{
qbyte line[1024];
char nam[64];
char rep[64];
while (VFS_GETS(f, line, sizeof(line)))
{
COM_ParseTokenOut(COM_ParseTokenOut(line, NULL, nam, sizeof(nam), NULL), NULL, rep, sizeof(rep), NULL);
if (!*nam || !*rep)
continue; //next line then, I guess.
line[0] = strlen(nam);
line[1] = strlen(rep);
strcpy(line+2, nam);
strcpy(line+2+line[0], rep);
Z_StrCat((char**)&emojidata, line);
}
VFS_CLOSE(f);
}
}
void Key_EmojiCompletion_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
{
char guess[256];
char repl[256];
size_t ofs, len;
if (!emojidata)
Key_LoadEmojiList();
len = strlen(partial);
for (ofs = 0; emojidata[ofs]; )
{
if (len <= emojidata[ofs+0])
if (!strncmp(partial, &emojidata[ofs+2], len))
{
memcpy(guess, &emojidata[ofs+2], emojidata[ofs+0]);
guess[emojidata[ofs+0]] = 0;
memcpy(repl, &emojidata[ofs+2]+emojidata[ofs+0], emojidata[ofs+1]);
repl[emojidata[ofs+1]] = 0;
ctx->cb(guess, NULL, NULL, ctx);
}
ofs += 2+emojidata[ofs+0]+emojidata[ofs+1];
}
}
const char *Key_Demoji(char *buffer, size_t buffersize, const char *in)
{
char *estart = strchr(in, ':');
size_t i;
size_t ofs;
char *out = buffer, *outend = buffer+buffersize-1;
if (!estart)
return in;
if (!emojidata)
Key_LoadEmojiList();
for(; estart; )
{
if (out + (estart-in) >= outend)
@ -1349,21 +1441,22 @@ const char *Key_Demoji(char *buffer, size_t buffersize, const char *in)
out += estart-in;
in = estart;
for (i = 0; i < countof(emoji); i++)
for (ofs = 0; emojidata[ofs]; )
{
if (!strncmp(in, emoji[i].pattern, strlen(emoji[i].pattern)))
if (!strncmp(in, &emojidata[ofs+2], emojidata[ofs+0]))
break; //its this one!
ofs += 2+emojidata[ofs+0]+emojidata[ofs+1];
}
if (i < countof(emoji))
if (emojidata[ofs])
{
if (out + strlen(emoji[i].repl) >= outend)
if (out + emojidata[ofs+1] >= outend)
{
in = ""; //no half-emoji
break;
}
in += strlen(emoji[i].pattern);
memcpy(out, emoji[i].repl, strlen(emoji[i].repl));
out += strlen(emoji[i].repl);
in += emojidata[ofs+0];
memcpy(out, &emojidata[ofs+2]+emojidata[ofs+0], emojidata[ofs+1]);
out += emojidata[ofs+1];
estart = strchr(in, ':');
}
else
@ -2194,6 +2287,7 @@ the K_* names are matched up.
*/
int Key_StringToKeynum (const char *str, int *modifier)
{
int k;
keyname_t *kn;
if (!strnicmp(str, "std_", 4) || !strnicmp(str, "std+", 4))
@ -2237,21 +2331,27 @@ int Key_StringToKeynum (const char *str, int *modifier)
#if 0//def _WIN32
return VkKeyScan(str[0]);
#else
return str[0];
k = str[0];
// return str[0];
#endif
}
if (!strncmp(str, "K_", 2))
str+=2;
for (kn=keynames ; kn->name ; kn++)
else
{
if (!Q_strcasecmp(str,kn->name))
return kn->keynum;
if (!strncmp(str, "K_", 2))
str+=2;
for (kn=keynames ; kn->name ; kn++)
{
if (!Q_strcasecmp(str,kn->name))
return kn->keynum;
}
k = atoi(str);
}
if (atoi(str)) //assume ascii code. (prepend with a 0 if needed)
if (k) //assume ascii code. (prepend with a 0 if needed)
{
return atoi(str);
if (k >= 'A' && k <= 'Z')
k += 'a'-'A';
return k;
}
return -1;
}
@ -2548,14 +2648,28 @@ void Key_Bind_f (void)
char *alias = Cmd_AliasExist(keybindings[b][modifier], RESTRICT_LOCAL);
char quotedbind[2048];
char quotedalias[2048];
char leveldesc[1024];
if (bindcmdlevel[b][modifier] != level)
{
if (Cmd_ExecLevel > RESTRICT_SERVER)
Q_snprintfz(leveldesc, sizeof(leveldesc), ", for seat %i", Cmd_ExecLevel - RESTRICT_SERVER-1);
else if (Cmd_ExecLevel == RESTRICT_SERVER)
Q_snprintfz(leveldesc, sizeof(leveldesc), ", bound by server");
else if (bindcmdlevel[b][modifier]>=RESTRICT_INSECURE)
Q_snprintfz(leveldesc, sizeof(leveldesc), ", bound by insecure source");
else
Q_snprintfz(leveldesc, sizeof(leveldesc), ", at level %i", bindcmdlevel[b][modifier]);
}
else
*leveldesc = 0;
COM_QuotedString(keybindings[b][modifier], quotedbind, sizeof(quotedbind), false);
if (alias)
{
COM_QuotedString(alias, quotedalias, sizeof(quotedalias), false);
Con_Printf ("^[\"%s\"\\type\\bind %s %s^] = ^[\"%s\"\\type\\alias %s %s^]\n", Cmd_Argv(1), Cmd_Argv(1), quotedbind, keybindings[b][modifier], keybindings[b][modifier], quotedalias);
Con_Printf ("^[\"%s\"\\type\\bind %s %s^] = ^[\"%s\"\\type\\alias %s %s^]%s\n", Cmd_Argv(1), Cmd_Argv(1), quotedbind, keybindings[b][modifier], keybindings[b][modifier], quotedalias, leveldesc);
}
else
Con_Printf ("^[\"%s\"\\type\\bind %s %s^] = \"%s\"\n", Cmd_Argv(1), keybindings[b][modifier], Cmd_Argv(1), keybindings[b][modifier] );
Con_Printf ("^[\"%s\"\\type\\bind %s %s^] = \"%s\"%s\n", Cmd_Argv(1), keybindings[b][modifier], Cmd_Argv(1), keybindings[b][modifier], leveldesc);
}
else
Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );

View File

@ -311,6 +311,7 @@ qboolean Key_GetConsoleSelectionBox(struct console_s *con, int *sx, int *sy, int
qboolean Key_MouseShouldBeFree(void);
const char *Key_Demoji(char *buffer, size_t buffersize, const char *in); //strips out :smile: stuff.
void Key_EmojiCompletion_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx);
#endif
#endif

View File

@ -13,32 +13,7 @@
#ifdef PACKAGEMANAGER
#include "fs.h"
//whole load of extra args for the downloads menu (for the downloads menu to handle engine updates).
#if defined(VKQUAKE) && !defined(SERVERONLY)
#define PHPVK "&vk=1"
#else
#define PHPVK
#endif
#if defined(GLQUAKE) && !defined(SERVERONLY)
#define PHPGL "&gl=1"
#else
#define PHPGL
#endif
#if defined(D3DQUAKE) && !defined(SERVERONLY)
#define PHPD3D "&d3d=1"
#else
#define PHPD3D
#endif
#ifdef MINIMAL
#define PHPMIN "&min=1"
#else
#define PHPMIN
#endif
#ifdef HAVE_LEGACY
#define PHPLEG "&leg=1&test=1"
#else
#define PHPLEG "&leg=0&test=1"
#endif
//some extra args for the downloads menu (for the downloads menu to handle engine updates).
#if defined(_DEBUG) || defined(DEBUG)
#define PHPDBG "&dbg=1"
#else
@ -48,11 +23,10 @@
#define SVNREVISION -
#endif
#define SVNREVISIONSTR STRINGIFY(SVNREVISION)
#define DOWNLOADABLESARGS "ver=" SVNREVISIONSTR PHPVK PHPGL PHPD3D PHPMIN PHPLEG PHPDBG "&arch="PLATFORM "_" ARCH_CPU_POSTFIX
#define DOWNLOADABLESARGS PHPDBG
extern cvar_t pm_autoupdate;
extern cvar_t pm_downloads_url;
#define INSTALLEDFILES "installed.lst" //the file that resides in the quakedir (saying what's installed).
@ -194,10 +168,9 @@ static char *manifestpackages; //metapackage named by the manicfest.
static char *declinedpackages; //metapackage named by the manicfest.
static int domanifestinstall; //SECURITY_MANIFEST_*
#ifdef PLUGINS
static qboolean pluginpromptshown; //so we only show prompts for new externally-installed plugins once, instead of every time the file is reloaded.
#endif
#ifdef WEBCLIENT
static int allowphonehome = -1; //if autoupdates are disabled, make sure we get (temporary) permission before phoning home for available updates. (-1=unknown, 0=no, 1=yes)
static qboolean doautoupdate; //updates will be marked (but not applied without the user's actions)
static qboolean pkg_updating; //when flagged, further changes are blocked until completion.
#else
@ -1221,6 +1194,20 @@ void PM_PluginDetected(void *ctx, int status)
#endif
#endif
#ifndef SERVERONLY
void PM_AutoUpdateQuery(void *ctx, int status)
{
if (status == -1)
return; //'Later'
if (status == 1)
Cvar_ForceSet(&pkg_autoupdate, "0"); //'Disable'
else
Cvar_ForceSet(&pkg_autoupdate, "1"); //'Enable'
PM_WriteInstalledPackages();
Menu_Download_Update();
}
#endif
static void PM_PreparePackageList(void)
{
//figure out what we've previously installed.
@ -1251,6 +1238,13 @@ static void PM_PreparePackageList(void)
}
}
#endif
if (!pluginpromptshown && pkg_autoupdate.ival < 0 && numdownloadablelists)
{
pluginpromptshown = true;
#ifndef SERVERONLY
Menu_Prompt(PM_AutoUpdateQuery, NULL, "Would you like to\nenable update checks?", "Enable", "Disable", "Later");
#endif
}
}
}
@ -1821,6 +1815,22 @@ static void PM_ListDownloaded(struct dl_download *dl)
}
}
#endif
#ifndef SERVERONLY
static void PM_UpdatePackageList(qboolean autoupdate, int retry);
static void PM_AllowPackageListQuery_Callback(void *ctx, int opt)
{
unsigned int i;
allowphonehome = (opt==0);
//something changed, let it download now.
for (i = 0; i < numdownloadablelists; i++)
{
if (downloadablelist[i].received == -2)
downloadablelist[i].received = 0;
}
PM_UpdatePackageList(false, 0);
}
#endif
//retry 1==
static void PM_UpdatePackageList(qboolean autoupdate, int retry)
{
@ -1841,15 +1851,32 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
#else
doautoupdate |= autoupdate;
#ifdef SERVERONLY
allowphonehome = true; //erk.
#else
if (pkg_autoupdate.ival >= 1)
allowphonehome = true;
else if (allowphonehome == -1)
{
Menu_Prompt(PM_AllowPackageListQuery_Callback, NULL, "Query updates list?\n", "Okay", NULL, "Nope");
return;
}
#endif
//kick off the initial tier of list-downloads.
for (i = 0; i < numdownloadablelists; i++)
{
if (downloadablelist[i].received)
if (downloadablelist[i].received && allowphonehome>=0)
continue;
autoupdate = false;
if (downloadablelist[i].curdl)
continue;
if (allowphonehome<=0)
{
downloadablelist[i].received = -2;
continue;
}
downloadablelist[i].curdl = HTTP_CL_Get(va("%s%s"DOWNLOADABLESARGS, downloadablelist[i].url, strchr(downloadablelist[i].url,'?')?"&":"?"), NULL, PM_ListDownloaded);
if (downloadablelist[i].curdl)
{
@ -1884,7 +1911,6 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize)
{
const unsigned char *gah;
@ -3579,7 +3605,7 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix)
if (!mo)
{
y += 8;
MC_AddBufferedText(m, 48, 320, y, path+prefixlen, false, true);
MC_AddBufferedText(m, 48, 320-16, y, path+prefixlen, false, true);
y += 8;
Q_strncatz(path, "/", sizeof(path));
y = MD_AddItemsToDownloadMenu(m, y, path);
@ -3690,20 +3716,20 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
info->populated = true;
MC_AddFrameStart(m, 48);
y = 48;
b = MC_AddCommand(m, 48, 170, y, "Apply", MD_ApplyDownloads);
b = MC_AddCommand(m, 48, 320-16, 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);
d = b = MC_AddCommand(m, 48, 320-16, y, "Back", MD_PopMenu);
b->rightalign = false;
y+=8;
#ifdef WEBCLIENT
b = MC_AddCommand(m, 48, 170, y, "Mark Updates", MD_MarkUpdatesButton);
b = MC_AddCommand(m, 48, 320-16, 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 = MC_AddCommand(m, 48, 320-16, y, "Revert Updates", MD_RevertUpdates);
b->rightalign = false;
b->common.tooltip = "Reset selection to only those packages that are currently installed.";
y+=8;
@ -3711,7 +3737,7 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
c = MC_AddCustom(m, 48, y, p, 0, NULL);
c->draw = MD_AutoUpdate_Draw;
c->key = MD_AutoUpdate_Key;
c->common.width = 320;
c->common.width = 320-48-16;
c->common.height = 8;
y += 8;
#endif
@ -3761,7 +3787,7 @@ void Menu_DownloadStuff_f (void)
//should only be called AFTER the filesystem etc is inited.
void Menu_Download_Update(void)
{
if (!pkg_autoupdate.ival)
if (pkg_autoupdate.ival <= 0)
return;
PM_UpdatePackageList(true, 2);

View File

@ -176,7 +176,7 @@ float media_fadeouttime;
sfx_t *Media_NextTrack(int musicchannelnum, float *starttime)
{
sfx_t *s = NULL;
if (bgmvolume.value <= 0)
if (bgmvolume.value <= 0 || mastervolume.value <= 0)
return NULL;
if (media_fadeout)
@ -2816,6 +2816,10 @@ void Media_SetState(cin_t *cin, cinstates_t newstate)
}
cinstates_t Media_GetState(cin_t *cin)
{
if (!cin)
cin = R_ShaderGetCinematic(videoshader);
if (!cin)
return CINSTATE_INVALID;
return cin->playstate;
}

View File

@ -75,32 +75,75 @@ enum
ASPECT2D_CUSTOM,
};
typedef struct {
unsigned int w, h;
} ftevidmode_t;
static ftevidmode_t *vidmodes;
static size_t nummodes;
void VidMode_Clear(void)
{
BZ_Free(vidmodes);
vidmodes = NULL;
nummodes = 0;
}
void VidMode_Add(int w, int h)
{
size_t m;
for (m = 0; m < nummodes; m++)
{
if (vidmodes[m].w == w && vidmodes[m].h == h)
return;
}
Z_ReallocElements((void**)&vidmodes, &nummodes, nummodes+1, sizeof(*vidmodes));
vidmodes[m].w = w;
vidmodes[m].h = h;
}
static int QDECL VidMode_Sort(const void *v1, const void *v2)
{
const ftevidmode_t *m1 = v1, *m2 = v2;
int n1 = m1->w, n2=m2->w; //sort by width
if (n1 == n2)
n1 = m1->h, n2=m2->h; //then by height
if (n1 == n2)
return 0; //then give up and consider equal... which shouldn't happen.
if (n1 > n2)
return 1;
return -1;
}
qboolean M_Vid_GetMode(qboolean forfullscreen, int num, int *w, int *h)
{
int i;
for (i = 0; i < 4; i++)
int a;
extern cvar_t vid_devicename;
if (!nummodes)
{
const char **v = resaspects[i];
while (*v && num)
VidMode_Clear();
if (rf->VID_EnumerateVideoModes)
rf->VID_EnumerateVideoModes("", vid_devicename.string, VidMode_Add);
if (!nummodes)
{
v++;
num--;
}
if (*v)
{
const char *c = *v;
const char *s = strchr(c, 'x');
if (s)
for (a = 0; a < countof(resaspects); a++)
{
*w = atoi(c);
*h = atoi(s + 1);
return true;
const char **v = resaspects[a];
for (; *v; v++)
{
const char *c = *v;
const char *s = strchr(c, 'x');
if (s)
VidMode_Add(atoi(c), atoi(s+1));
}
}
return false;
}
qsort(vidmodes, nummodes, sizeof(*vidmodes), VidMode_Sort);
}
return false;
if (num < 0 || num >= nummodes)
return false;
*w = vidmodes[num].w;
*h = vidmodes[num].h;
return true;
}
@ -2616,7 +2659,8 @@ void CheckCustomMode(struct emenu_s *menu)
info->res2dsize[sel]->common.ishidden = false;
}
int M_MatchModes(int width, int height, int *outres)
//return value is aspect group, *outres is the mode index inside that aspect.
static int M_MatchModes(int width, int height, int *outres)
{
int i;
int ratio = -1;
@ -3332,7 +3376,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
ent.framestate.g[FS_REG].frame[0] = mods->framegroup;
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;
ent.framestate.g[FS_REG].endbone = 0x7fffffff;
ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname));
ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum));
ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66;
ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33;

View File

@ -1105,11 +1105,12 @@ static char *quitMessage [] =
"Press N to stay proud\n"
"and successful!",
"If you press Y to\n"
//this is a vanilla message... but I'm having enough issues with false-positives in malware scanners right now that I really don't want to risk an already-suspicious actual hunam seeing stuff like this... :)
/* "If you press Y to\n"
"quit, I will summon\n"
"Satan all over your\n"
"hard drive!",
*/
"Um, Asmodeus dislikes\n"
"his children trying to\n"
"quit. Press Y to return\n"

View File

@ -497,6 +497,8 @@ void MP_RegisterCvarsAndCmds(void);
int MP_BuiltinValid(const char *name, int num);
qboolean MP_ConsoleCommand(const char *cmdtext);
int MP_GetServerCategory(int index);
#else
#define MP_UsingGamecodeLoadingScreen() false
#endif
#ifdef MENU_NATIVECODE
@ -535,6 +537,7 @@ void Plug_SBar(playerview_t *pv);
qboolean Plug_ServerMessage(char *buffer, int messagelevel);
void Plug_Tick(void);
qboolean Plugin_ExecuteString(void);
void Plug_FreeAllImages(void);
#ifdef ANDROID
#define PLUGINPREFIX "libplug_" //android is kinda annoying and only extracts specific files.

View File

@ -131,7 +131,7 @@ extern void (*VID_DeInit) (void);
extern char *(*VID_GetRGBInfo) (int *stride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); //if stride is negative, then the return value points to the last line intead of the first. this allows it to be freed normally.
extern void (*VID_SetWindowCaption) (const char *msg);
extern void *SCR_ScreenShot_Capture (int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt, qboolean no2d);
extern void *SCR_ScreenShot_Capture (int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt, qboolean no2d, qboolean hdr);
extern void SCR_Init (void);
extern void SCR_DeInit (void);
extern qboolean (*SCR_UpdateScreen) (void);
@ -479,6 +479,7 @@ typedef struct rendererinfo_s {
//FIXME: keep this...
int (*VID_GetPriority) (void); //so that eg x11 or wayland can be prioritised depending on environment settings. assumed to be 1.
void (*VID_EnumerateVideoModes) (const char *driver, const char *output, void (*cb) (int w, int h));
//FIXME: add getdestopres
//FIXME: add clipboard handling

View File

@ -505,6 +505,9 @@ void SV_Master_Heartbeat (void)
if (realtime-interval - svs.last_heartbeat < interval)
return; // not time to send yet
if ((sv.allocated_client_slots == 1) && !isDedicated)
return; //don't heartbeat in single-player, we don't even have a public socket open!
svs.last_heartbeat = realtime-interval;
svs.heartbeat_sequence++;

View File

@ -169,7 +169,7 @@ typedef struct skytriblock_s
//this is the required render state for each particle
//dynamic per-particle stuff isn't important. only static state.
typedef struct {
enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_CDECAL, PT_UDECAL, PT_INVISIBLE} type;
enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_VBEAM, PT_CDECAL, PT_UDECAL, PT_INVISIBLE} type;
blendmode_t blendmode;
shader_t *shader;
@ -948,6 +948,12 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
ptype->looks.shader = R_RegisterShader(va("beam%s", namepostfix), SUF_NONE, defaultshader);
TEXASSIGNF(tn.base, beamtexture);
}
else if (ptype->looks.type == PT_VBEAM)
{
/*untextured beams get a single continuous blob*/
ptype->looks.shader = R_RegisterShader(va("vbeam%s", namepostfix), SUF_NONE, defaultshader);
TEXASSIGNF(tn.base, beamtexture);
}
else if (ptype->looks.type == PT_SPARKFAN)
{
/*untextured beams get a single continuous blob*/
@ -1942,6 +1948,8 @@ parsefluid:
{
if (!strcmp(value, "beam"))
ptype->looks.type = PT_BEAM;
else if (!strcmp(value, "vbeam"))
ptype->looks.type = PT_BEAM;
else if (!strcmp(value, "spark") || !strcmp(value, "linespark"))
ptype->looks.type = PT_SPARK;
else if (!strcmp(value, "sparkfan") || !strcmp(value, "trianglefan"))
@ -2279,7 +2287,7 @@ parsefluid:
FinishParticleType(ptype);
if (ptype->looks.type == PT_BEAM && !setbeamlen)
if ((ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM) && !setbeamlen)
ptype->rotationstartmin = 1/128.0;
}
@ -2324,6 +2332,9 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
case PT_BEAM:
Q_strncatz(outstr, "type beam\n", outstrlen);
break;
case PT_VBEAM:
Q_strncatz(outstr, "type vbeam\n", outstrlen);
break;
case PT_CDECAL:
if (ptype->surfflagmatch || ptype->surfflagmask)
Q_strncatz(outstr, va("clippeddecal %#x %#x\n", ptype->surfflagmask, ptype->surfflagmatch), outstrlen);
@ -2792,7 +2803,7 @@ static void FinishParticleType(part_type_t *ptype)
ptype->looks.type = PT_SPARK;
if (ptype->looks.type == PT_SPARK && !r_part_sparks.ival)
ptype->looks.type = PT_INVISIBLE;
if (ptype->looks.type == PT_BEAM && r_part_beams.ival <= 0)
if ((ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM) && r_part_beams.ival <= 0)
ptype->looks.type = PT_INVISIBLE;
if (ptype->rampmode && !ptype->ramp)
@ -2836,6 +2847,19 @@ static void FinishEffectinfoParticleType(part_type_t *ptype, qboolean blooddecal
ptype->scaledelta *= 2*2*ptype->looks.stretch; //fixme: this feels wrong, the results look correct though. hrmph.
ptype->looks.stretch = 1;
}
else if (ptype->looks.type == PT_BEAM || ptype->looks.type == PT_VBEAM)
{ //ignore what the particle says and just spawn it from a to b. don't accept mid-segment randomness.
if (ptype->t1 == 0 && ptype->t2 == 1)
ptype->looks.type = PT_VBEAM;
else
ptype->looks.type = PT_BEAM;
ptype->count = 0;
ptype->countextra = 2;
ptype->countrand = 0;
ptype->countspacing = 10000;
ptype->scale *= 0.5;
}
if (blooddecalonimpact) //DP blood particles generate decals unconditionally (and prevent blood from bouncing)
ptype->clipbounce = -2;
if (ptype->looks.type == PT_TEXTUREDSPARK)
@ -2864,10 +2888,15 @@ static void P_ImportEffectInfo(char *config, char *line)
part_type_t *ptype = NULL;
int parenttype;
char arg[8][1024];
int args = 0;
int args;
qboolean blooddecalonimpact = false; //tracked separately because it needs to override another field
float teximages[256][4];
struct
{
float tc[4];
char imgname[128];
} teximages[256];
{
int i;
@ -2876,37 +2905,64 @@ static void P_ImportEffectInfo(char *config, char *line)
//default assumes 8*8 grid, but we allow more
for (i = 0; i < 256; i++)
{
teximages[i][0] = 1/8.0 * (i & 7);
teximages[i][1] = 1/8.0 * (1+(i & 7));
teximages[i][2] = 1/8.0 * (1+(i>>3));
teximages[i][3] = 1/8.0 * (i>>3);
teximages[i].tc[0] = 1/8.0 * (i & 7);
teximages[i].tc[1] = 1/8.0 * (1+(i & 7));
teximages[i].tc[2] = 1/8.0 * (1+(i>>3));
teximages[i].tc[3] = 1/8.0 * (i>>3);
strcpy(teximages[i].imgname, "particles/particlefont");
}
//and this one needs to be subject to a hack. ho hum.
teximages[60].tc[0] = 0;
teximages[60].tc[1] = 1;
teximages[60].tc[2] = 0;
teximages[60].tc[3] = 1;
strcpy(teximages[60].imgname, "particles/nexbeam");
file = FS_OpenVFS("particles/particlefont.txt", "rb", FS_GAME);
if (file)
{
while (VFS_GETS(file, linebuf, sizeof(linebuf)))
{
line = COM_StringParse(linebuf, arg[0], sizeof(arg[0]), false, false);
line = COM_StringParse(line, arg[1], sizeof(arg[1]), false, false);
line = COM_StringParse(line, arg[2], sizeof(arg[2]), false, false);
line = COM_StringParse(line, arg[3], sizeof(arg[3]), false, false);
line = COM_StringParse(line, arg[4], sizeof(arg[4]), false, false);
args = 0;
line = COM_StringParse(linebuf, arg[args], sizeof(arg[args]), false, false);
if (line)
{
i = atoi(arg[0]);
teximages[i][0] = atof(arg[1]);
teximages[i][1] = atof(arg[3]);
teximages[i][2] = atof(arg[4]);
teximages[i][3] = atof(arg[2]);
for (args++; args < countof(arg); args++)
{
line = COM_StringParse(line, arg[args], sizeof(arg[args]), false, false);
if (!line)
break;
}
}
i = atoi(arg[0]);
if (i >= countof(teximages))
Con_Printf("particles/particlefont.txt: index too high - %i>=%u\n", i, (unsigned)countof(teximages));
else if (args == 2)
{
teximages[i].tc[0] = 0;
teximages[i].tc[1] = 1;
teximages[i].tc[2] = 0;
teximages[i].tc[3] = 1;
Q_strncpyz(teximages[i].imgname, arg[1], sizeof(teximages[i].imgname));
}
else if (args >= 5 && args <= 6)
{
teximages[i].tc[0] = atof(arg[1]); //s1
teximages[i].tc[1] = atof(arg[3]); //s2
teximages[i].tc[2] = atof(arg[4]); //t1
teximages[i].tc[3] = atof(arg[2]); //t2
Q_strncpyz(teximages[i].imgname, (args>=6)?arg[5]:"particles/particlefont", sizeof(teximages[i].imgname));
}
else
Con_Printf("particles/particlefont.txt: unsupported argument count - %i\n", args);
}
VFS_CLOSE(file);
}
}
for (;;)
for (args = 0;;)
{
if (!*line)
break;
@ -2964,7 +3020,6 @@ static void P_ImportEffectInfo(char *config, char *line)
ptype->alpharand = 1;
ptype->alphachange = -1;
ptype->die = 9999;
strcpy(ptype->texname, "particles/particlefont");
ptype->rgb[0] = 1;
ptype->rgb[1] = 1;
ptype->rgb[2] = 1;
@ -2983,10 +3038,11 @@ static void P_ImportEffectInfo(char *config, char *line)
ptype->dl_time = 0;
i = 63; //default texture is 63.
ptype->s1 = teximages[i][0];
ptype->s2 = teximages[i][1];
ptype->t1 = teximages[i][2];
ptype->t2 = teximages[i][3];
Q_strncpyz(ptype->texname, teximages[i].imgname, sizeof(ptype->texname));
ptype->s1 = teximages[i].tc[0];
ptype->s2 = teximages[i].tc[1];
ptype->t1 = teximages[i].tc[2];
ptype->t2 = teximages[i].tc[3];
ptype->texsstride = 0;
ptype->randsmax = 1;
}
@ -3064,20 +3120,28 @@ static void P_ImportEffectInfo(char *config, char *line)
ptype->looks.premul = 2;
ptype->flurry = 32; //may not still be valid later, but at least it would be an obvious issue with the original.
}
else if (!strcmp(arg[1], "entityparticle"))
{
ptype->die = 0;
ptype->looks.type = PT_NORMAL;
ptype->looks.blendmode = BM_PREMUL;//BM_BLEND;
ptype->looks.premul = 1;
}
else
{
Con_Printf("effectinfo type %s not supported\n", arg[1]);
}
}
else if (!strcmp(arg[0], "tex") && args == 3)
{
{ //assume that all textures will be packed into the same texture and on the same line...
int mini = atoi(arg[1]);
int maxi = atoi(arg[2]);
ptype->s1 = teximages[mini][0];
ptype->s2 = teximages[mini][1];
ptype->t1 = teximages[mini][2];
ptype->t2 = teximages[mini][3];
ptype->texsstride = teximages[(mini+1)&(sizeof(teximages)/sizeof(teximages[0])-1)][0] - teximages[mini][0];
Q_strncpyz(ptype->texname, teximages[mini].imgname, sizeof(ptype->texname));
ptype->s1 = teximages[mini].tc[0];
ptype->s2 = teximages[mini].tc[1];
ptype->t1 = teximages[mini].tc[2];
ptype->t2 = teximages[mini].tc[3];
ptype->texsstride = teximages[(mini+1)&(sizeof(teximages)/sizeof(teximages[0])-1)].tc[0] - teximages[mini].tc[0];
ptype->randsmax = (maxi - mini);
if (ptype->randsmax < 1)
ptype->randsmax = 1;
@ -4137,7 +4201,7 @@ static void PScript_ApplyOrgVel(vec3_t oorg, vec3_t ovel, vec3_t eforg, vec3_t a
{
case SM_UNICIRCLE:
m = pmax;
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
m--;
if (m < 1)
@ -4769,7 +4833,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
{
case SM_UNICIRCLE:
m = pcount;
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
m--;
if (m < 1)
@ -4843,7 +4907,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
if (!free_particles)
break;
p = free_particles;
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
{
if (!free_beams)
break;
@ -5137,7 +5201,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
}
// update beam list
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
{
if (b)
{
@ -5672,7 +5736,7 @@ static void P_ParticleTrailSpawn (vec3_t startpos, vec3_t end, part_type_t *ptyp
}
p = free_particles;
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
{
if (!free_beams)
{
@ -5950,7 +6014,7 @@ static void P_ParticleTrailSpawn (vec3_t startpos, vec3_t end, part_type_t *ptyp
ts->state1.lastdist = len;
// update beamseg list
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
{
if (b)
{
@ -5986,7 +6050,7 @@ static void P_ParticleTrailSpawn (vec3_t startpos, vec3_t end, part_type_t *ptyp
}
}
}
else if (ptype->looks.type == PT_BEAM)
else if (ptype->looks.type == PT_BEAM||ptype->looks.type == PT_VBEAM)
{
if (b)
{
@ -6423,6 +6487,73 @@ static void GL_DrawTexturedSparkParticle(int count, particle_t **plist, plooks_t
}
}
static void GL_DrawParticleVBeam(int count, beamseg_t **blist, plooks_t *type)
{
beamseg_t *b;
vec3_t v;
vec3_t cr;
beamseg_t *c;
particle_t *p;
particle_t *q;
float ts;
while(count--)
{
b = *blist++;
if (pscriptmesh.numvertexes >= BUFFERVERTS-4)
{
pscriptmesh.numindexes = pscriptmesh.numvertexes/4*6;
BE_DrawMesh_Single(type->shader, &pscriptmesh, NULL, 0);
pscriptmesh.numvertexes = 0;
}
c = b->next;
q = c->p;
if (!q)
continue;
p = b->p;
// q->rgba[3] = 1;
// p->rgba[3] = 1;
VectorSubtract(r_refdef.vieworg, q->org, v);
VectorNormalize(v);
CrossProduct(c->dir, v, cr);
VectorNormalize(cr);
ts = c->texture_s*q->angle + particletime*q->rotationspeed;
Vector4Copy(q->rgba, pscriptcolours[pscriptmesh.numvertexes+0]);
Vector4Copy(q->rgba, pscriptcolours[pscriptmesh.numvertexes+1]);
Vector2Set(pscripttexcoords[pscriptmesh.numvertexes+0], p->s1, p->t1);
Vector2Set(pscripttexcoords[pscriptmesh.numvertexes+1], p->s2, p->t2);
VectorMA(q->org, -q->scale, cr, pscriptverts[pscriptmesh.numvertexes+0]);
VectorMA(q->org, q->scale, cr, pscriptverts[pscriptmesh.numvertexes+1]);
VectorSubtract(r_refdef.vieworg, p->org, v);
VectorNormalize(v);
CrossProduct(b->dir, v, cr); // replace with old p->dir?
VectorNormalize(cr);
ts = b->texture_s*p->angle + particletime*p->rotationspeed;
(void)ts;
Vector4Copy(p->rgba, pscriptcolours[pscriptmesh.numvertexes+2]);
Vector4Copy(p->rgba, pscriptcolours[pscriptmesh.numvertexes+3]);
Vector2Set(pscripttexcoords[pscriptmesh.numvertexes+2], p->s1, p->t1);
Vector2Set(pscripttexcoords[pscriptmesh.numvertexes+3], p->s2, p->t2);
VectorMA(p->org, p->scale, cr, pscriptverts[pscriptmesh.numvertexes+2]);
VectorMA(p->org, -p->scale, cr, pscriptverts[pscriptmesh.numvertexes+3]);
pscriptmesh.numvertexes += 4;
}
if (pscriptmesh.numvertexes)
{
pscriptmesh.numindexes = pscriptmesh.numvertexes/4*6;
BE_DrawMesh_Single(type->shader, &pscriptmesh, NULL, 0);
pscriptmesh.numvertexes = 0;
}
}
static void GL_DrawParticleBeam(int count, beamseg_t **blist, plooks_t *type)
{
beamseg_t *b;
@ -6982,6 +7113,9 @@ static void PScript_DrawParticleTypes (void)
case PT_BEAM:
bdraw = GL_DrawParticleBeam;
break;
case PT_VBEAM:
bdraw = GL_DrawParticleVBeam;
break;
case PT_CDECAL:
break;
case PT_UDECAL:

View File

@ -461,6 +461,19 @@ void QCBUILTIN PF_cl_setwindowcaption(pubprogfuncs_t *prinst, struct globalvars_
}
}
void QCBUILTIN PF_cl_setmousepos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *world = prinst->parms->user;
float *pos = G_VECTOR(OFS_PARM0);
if (key_dest_absolutemouse & world->keydestmask)
{
vid.forcecursor = true;
vid.forcecursorpos[0] = (pos[0] * vid.pixelwidth) / vid.width;
vid.forcecursorpos[1] = (pos[1] * vid.pixelheight) / vid.height;
}
}
//#343
void QCBUILTIN PF_cl_setcursormode (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -654,12 +667,17 @@ void QCBUILTIN PF_cs_media_getproperty (pubprogfuncs_t *prinst, struct globalvar
}
void QCBUILTIN PF_cs_media_getstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
cinstates_t ret = CINSTATE_INVALID;
cin_t *cin;
cin = R_ShaderFindCinematic(shader);
if (cin)
ret = Media_GetState(cin);
if (prinst->callargc>0)
{
const char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
cin_t *cin;
cin = R_ShaderFindCinematic(shader);
if (cin)
ret = Media_GetState(cin);
}
else
ret = Media_GetState(NULL);
G_FLOAT(OFS_RETURN) = ret;
}
@ -911,8 +929,8 @@ void QCBUILTIN PF_cl_SetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr
{
int bm[2] =
{
G_FLOAT(OFS_PARM0+0),
G_FLOAT(OFS_PARM0+1)
G_VECTOR(OFS_PARM0)[0],
G_VECTOR(OFS_PARM0)[1]
};
Key_SetBindMap(bm);
G_FLOAT(OFS_RETURN) = 1;

View File

@ -80,6 +80,7 @@ static char csqc_printbuffer[8192];
cvar_t pr_csqc_maxedicts = CVAR("pr_csqc_maxedicts", "65536"); //not tied to protocol nor server. can be set arbitrarily high, except for memory allocations.
cvar_t pr_csqc_memsize = CVAR("pr_csqc_memsize", "-1");
cvar_t cl_csqcdebug = CVAR("cl_csqcdebug", "0"); //prints entity numbers which arrive (so I can tell people not to apply it to players...)
static cvar_t cl_csqc_nodeprecate = CVARAD("cl_csqc_nodeprecate", "0", "dpcompat_nocsqcwarnings", "When set, disables deprecation warnings.");
cvar_t cl_nocsqc = CVAR("cl_nocsqc", "0");
cvar_t pr_csqc_coreonerror = CVAR("pr_csqc_coreonerror", "1");
#if defined(NOBUILTINMENUS) && !defined(MENU_DAT)
@ -87,6 +88,7 @@ cvar_t pr_csqc_formenus = CVARF("pr_csqc_formenus", "1", CVAR_NOSET);
#else
cvar_t pr_csqc_formenus = CVAR("pr_csqc_formenus", "0");
#endif
static cvar_t dpcompat_csqcinputeventtypes = CVARD("dpcompat_csqcinputeventtypes", "999999", "Specifies the first csqc input event that the mod does not recognise. This should never have been a thing, but some mods are simply too buggy.");
extern cvar_t dpcompat_stats;
// standard effect cvars/sounds
@ -743,13 +745,13 @@ static void QCBUILTIN PF_cvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (!strcmp(str, "vid_conwidth"))
{
if (!csqc_isdarkplaces) //don't warn when its unfixable...
csqc_deprecated("vid_conwidth cvar has aspect issues");
csqc_deprecated("vid_conwidth - use (vector)getviewprop(VF_SCREENVSIZE)");
G_FLOAT(OFS_RETURN) = vid.width;
}
else if (!strcmp(str, "vid_conheight"))
{
if (!csqc_isdarkplaces)
csqc_deprecated("vid_conheight cvar has aspect issues");
csqc_deprecated("vid_conheight - use (vector)getviewprop(VF_SCREENVSIZE)");
G_FLOAT(OFS_RETURN) = vid.height;
}
else
@ -799,7 +801,7 @@ static void QCBUILTIN PF_checkbuiltin (pubprogfuncs_t *prinst, struct globalvars
char *funcname = NULL;
int args;
int builtinno;
if (prinst->GetFunctionInfo(prinst, funcref, &args, &builtinno, funcname, sizeof(funcname)))
if (prinst->GetFunctionInfo(prinst, funcref, &args, NULL, &builtinno, funcname, sizeof(funcname)))
{ //qc defines the function at least. nothing weird there...
if (builtinno > 0 && builtinno < prinst->parms->numglobalbuiltins)
{
@ -954,7 +956,9 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *fte_restrict in, entity_t *ft
csqcedict_t *p = (csqcedict_t*)skel_gettaginfo_args(csqcprogs, out->axis, out->origin, in->xv->tag_entity, in->xv->tag_index);
if (p && (int)p->xv->renderflags & CSQCRF_VIEWMODEL)
out->flags |= RF_DEPTHHACK|RF_WEAPONMODEL;
out->pvscache = p->pvsinfo; //for the areas.
out->pvscache.num_leafs = -1; //make visible globally
out->pvscache.headnode = 0;
#endif
}
@ -1706,6 +1710,117 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
csqc_poly_startidx = cl_numstrisidx;
}
//input is a line of verts, output is a quad strip
void QCBUILTIN PF_R_PolygonEndRibbon(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i;
int nv;
int flags = csqc_poly_flags;
int first;
vec3_t tang;
vec3_t dir;
vec3_t eyedir;
float separation = G_FLOAT(OFS_PARM0);
float sseparation = G_FLOAT(OFS_PARM1+0);
float tseparation = G_FLOAT(OFS_PARM1+1);
if (!csqc_poly_shader)
return;
nv = cl_numstrisvert-csqc_poly_startvert;
if (nv < 2)
{
csqc_poly_startvert = cl_numstrisvert;
csqc_poly_startidx = cl_numstrisidx;
return; //sod off.
}
flags &= ~BEF_LINES;
if (flags != csqc_poly_flags || (cl_numstrisvert-csqc_poly_origvert) >= 32768)
{
int sv = cl_numstrisvert - nv;
cl_numstrisvert -= nv;
CSQC_PolyFlush();
csqc_poly_origvert = cl_numstrisvert;
csqc_poly_origidx = cl_numstrisidx;
R2D_Flush = CSQC_PolyFlush;
csqc_poly_flags = flags;
csqc_poly_startvert = cl_numstrisvert;
csqc_poly_startidx = cl_numstrisidx;
memcpy(cl_strisvertv+cl_numstrisvert, cl_strisvertv + sv, sizeof(*cl_strisvertv) * nv);
memcpy(cl_strisvertt+cl_numstrisvert, cl_strisvertt + sv, sizeof(*cl_strisvertt) * nv);
memcpy(cl_strisvertc+cl_numstrisvert, cl_strisvertc + sv, sizeof(*cl_strisvertc) * nv);
cl_numstrisvert += nv;
}
nv = cl_numstrisvert-csqc_poly_startvert;
//dupe the verts
if (cl_numstrisvert+nv < cl_maxstrisvert)
cl_stris_ExpandVerts(cl_numstrisvert+nv);
memcpy(&cl_strisvertv[cl_numstrisvert], &cl_strisvertv[csqc_poly_startvert], sizeof(*cl_strisvertv)*nv);
memcpy(&cl_strisvertt[cl_numstrisvert], &cl_strisvertt[csqc_poly_startvert], sizeof(*cl_strisvertt)*nv);
memcpy(&cl_strisvertc[cl_numstrisvert], &cl_strisvertc[csqc_poly_startvert], sizeof(*cl_strisvertc)*nv);
//apply separation
VectorSubtract(cl_strisvertv[csqc_poly_startvert+0+1], cl_strisvertv[csqc_poly_startvert+0], dir);
VectorSubtract(cl_strisvertv[csqc_poly_startvert+0], r_refdef.vieworg, eyedir);
VectorNormalize(dir); VectorNormalize(eyedir);
CrossProduct(dir, eyedir, tang);
VectorMA(cl_strisvertv[csqc_poly_startvert+0], separation, tang, cl_strisvertv[csqc_poly_startvert+0]);
VectorMA(cl_strisvertv[cl_numstrisvert+0], -separation, tang, cl_strisvertv[cl_numstrisvert+0]);
cl_strisvertt[csqc_poly_startvert+0][0] += sseparation; //and update the generated s coord.
cl_strisvertt[csqc_poly_startvert+0][1] += tseparation; //and update the generated t coord.
for (i = 1; i < nv-1; i++)
{ //direction comes from its two neighbours, rather than itself and one of those neighbours
VectorSubtract(cl_strisvertv[csqc_poly_startvert+i+1], cl_strisvertv[csqc_poly_startvert+i-1], dir);
VectorSubtract(cl_strisvertv[csqc_poly_startvert+i], r_refdef.vieworg, eyedir);
VectorNormalize(dir); VectorNormalize(eyedir);
CrossProduct(dir, eyedir, tang);
VectorMA(cl_strisvertv[csqc_poly_startvert+i], separation, tang, cl_strisvertv[csqc_poly_startvert+i]);
VectorMA(cl_strisvertv[cl_numstrisvert+i], -separation, tang, cl_strisvertv[cl_numstrisvert+i]);
cl_strisvertt[csqc_poly_startvert+i][0] += sseparation; //and update the generated s coord.
cl_strisvertt[csqc_poly_startvert+i][1] += tseparation; //and update the generated t coord.
}
//don't wrap over
VectorSubtract(cl_strisvertv[csqc_poly_startvert+i], cl_strisvertv[csqc_poly_startvert+i-1], dir);
VectorSubtract(cl_strisvertv[csqc_poly_startvert+i], r_refdef.vieworg, eyedir);
VectorNormalize(dir); VectorNormalize(eyedir);
CrossProduct(dir, eyedir, tang);
VectorMA(cl_strisvertv[csqc_poly_startvert+i], separation, tang, cl_strisvertv[csqc_poly_startvert+i]);
VectorMA(cl_strisvertv[cl_numstrisvert+i], -separation, tang, cl_strisvertv[cl_numstrisvert+i]);
cl_strisvertt[csqc_poly_startvert+i][0] += sseparation; //and update the generated s coord.
cl_strisvertt[csqc_poly_startvert+i][1] += tseparation; //and update the generated t coord.
//verts are all set up right
cl_numstrisvert += nv;
if (cl_numstrisidx+(nv-1)*6 > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+(nv-1)*6 + 64;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
first = csqc_poly_startvert - csqc_poly_origvert;
/*build a double-triangle strip out of our lined verts*/
for (i = 1; i < nv; i++)
{
cl_strisidx[cl_numstrisidx++] = first + i-1;
cl_strisidx[cl_numstrisidx++] = first + i;
cl_strisidx[cl_numstrisidx++] = first + i+nv;
cl_strisidx[cl_numstrisidx++] = first + i+nv;
cl_strisidx[cl_numstrisidx++] = first + i-1+nv;
cl_strisidx[cl_numstrisidx++] = first + i-1;
}
/*set up ready for the next poly*/
csqc_poly_startvert = cl_numstrisvert;
csqc_poly_startidx = cl_numstrisidx;
}
typedef struct
{
vec3_t xyz;
@ -1819,6 +1934,7 @@ void QCBUILTIN PF_R_AddTrisoup_Simple(pubprogfuncs_t *prinst, struct globalvars_
qboolean csqc_rebuildmatricies;
float csqc_proj_matrix[16];
float csqc_proj_matrix_inverse[16];
float csqc_proj_frustum[2];
void V_ApplyAFov(playerview_t *pv);
void buildmatricies(void)
{
@ -1829,15 +1945,26 @@ void buildmatricies(void)
V_ApplyAFov(csqc_playerview);
/*build view and projection matricies*/
Matrix4x4_CM_ModelViewMatrix(modelview, r_refdef.viewangles, r_refdef.vieworg);
if (r_refdef.useperspective)
Matrix4x4_CM_Projection2(proj, r_refdef.fov_x, r_refdef.fov_y, 4);
else
Matrix4x4_CM_Orthographic(proj, -r_refdef.fov_x/2, r_refdef.fov_x/2, -r_refdef.fov_y/2, r_refdef.fov_y/2, r_refdef.mindist, r_refdef.maxdist>=1?r_refdef.maxdist:9999);
if (csqc_isdarkplaces)
{
/*doesn't bother to use the projection matrix. it isn't much of a transform.*/
Matrix4x4_CM_ModelViewMatrix(csqc_proj_matrix, r_refdef.viewangles, r_refdef.vieworg);
/*build the vp matrix*/
Matrix4_Multiply(proj, modelview, csqc_proj_matrix);
csqc_proj_frustum[0] = tan(r_refdef.fov_x * M_PI / 360.0);
csqc_proj_frustum[1] = tan(r_refdef.fov_y * M_PI / 360.0);
}
else
{
/*build view and projection matricies*/
Matrix4x4_CM_ModelViewMatrix(modelview, r_refdef.viewangles, r_refdef.vieworg);
if (r_refdef.useperspective)
Matrix4x4_CM_Projection2(proj, r_refdef.fov_x, r_refdef.fov_y, 4);
else
Matrix4x4_CM_Orthographic(proj, -r_refdef.fov_x/2, r_refdef.fov_x/2, -r_refdef.fov_y/2, r_refdef.fov_y/2, r_refdef.mindist, r_refdef.maxdist>=1?r_refdef.maxdist:9999);
/*build the vp matrix*/
Matrix4_Multiply(proj, modelview, csqc_proj_matrix);
}
/*build the unproject matrix (inverted vp matrix)*/
Matrix4_Invert(csqc_proj_matrix, csqc_proj_matrix_inverse);
@ -1871,21 +1998,26 @@ static void QCBUILTIN PF_cs_project (pubprogfuncs_t *prinst, struct globalvars_s
tempv[1] /= tempv[3];
tempv[2] /= tempv[3];
out[0] = (1+tempv[0])/2;
out[1] = 1-(1+tempv[1])/2;
out[2] = tempv[2];
if (csqc_isdarkplaces)
{ /*sigh*/
out[0] = out[0]*vid.width + r_refdef.vrect.x;
out[1] = out[1]*vid.height + r_refdef.vrect.y;
tempv[0] = -tempv[0]/tempv[2]/csqc_proj_frustum[0];
tempv[1] = tempv[1]/tempv[2]/csqc_proj_frustum[1];
out[0] = (1+tempv[0])/2;
out[1] = (1+tempv[1])/2;
out[2] = -tempv[2];
out[0] = out[0]*vid.width;
out[1] = out[1]*vid.height;
}
else
{
out[0] = (1+tempv[0])/2;
out[1] = 1-(1+tempv[1])/2;
out[2] = tempv[2];
out[0] = out[0]*r_refdef.vrect.width + r_refdef.vrect.x;
out[1] = out[1]*r_refdef.vrect.height + r_refdef.vrect.y;
}
if (tempv[3] < 0)
out[2] *= -1;
}
@ -1904,23 +2036,28 @@ static void QCBUILTIN PF_cs_unproject (pubprogfuncs_t *prinst, struct globalvars
if (csqc_isdarkplaces)
{ /*sigh*/
tx = ((tx-r_refdef.vrect.x)/vid.width);
ty = ((ty-r_refdef.vrect.y)/vid.height);
tx = ((tx)/vid.width);
ty = ((ty)/vid.height);
//this is kinda screwy
v[2] = -in[2];
v[0] = -(tx*2-1)*v[2]*csqc_proj_frustum[0];
v[1] = (ty*2-1)*v[2]*csqc_proj_frustum[1];
}
else
{
tx = ((tx-r_refdef.vrect.x)/r_refdef.vrect.width);
ty = ((ty-r_refdef.vrect.y)/r_refdef.vrect.height);
}
ty = 1-ty;
v[0] = tx*2-1;
v[1] = ty*2-1;
v[2] = in[2]*2-1; //gl projection matrix scales -1 to 1 (unlike d3d, which is 0 to 1)
v[3] = 1;
ty = 1-ty;
v[0] = tx*2-1;
v[1] = ty*2-1;
v[2] = in[2]*2-1; //gl projection matrix scales -1 to 1 (unlike d3d, which is 0 to 1)
//don't use 1, because the far clip plane really is an infinite distance away. and that tends to result division by infinity.
if (v[2] >= 1)
v[2] = 0.999999;
//don't use 1, because the far clip plane really is an infinite distance away. and that tends to result division by infinity.
if (v[2] >= 1)
v[2] = 0.999999;
}
v[3] = 1;
Matrix4x4_CM_Transform4(csqc_proj_matrix_inverse, v, tempv);
@ -2214,6 +2351,13 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
case VF_SKYROOM_CAMERA:
r_refdef.skyroom_enabled = true;
VectorCopy(p, r_refdef.skyroom_pos);
if (prinst->callargc >= 4)
{
VectorCopy(G_VECTOR(OFS_PARM2), r_refdef.skyroom_spin);
r_refdef.skyroom_spin[3] = G_FLOAT(OFS_PARM3);
}
else
Vector4Set(r_refdef.skyroom_spin, 0, 0, 0, 0);
break;
case VF_ORIGIN:
@ -5400,7 +5544,7 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s
return;
}
if (!prinst->GetFunctionInfo(prinst, func, NULL, NULL, NULL, 0))
if (!prinst->GetFunctionInfo(prinst, func, NULL, NULL, NULL, NULL, 0))
{
Con_Printf("PF_DeltaListen: Bad function index\n");
return;
@ -6447,6 +6591,7 @@ static struct {
{"R_BeginPolygon", PF_R_PolygonBegin, 306}, // #306 void(string texturename) R_BeginPolygon (EXT_CSQC_???)
{"R_PolygonVertex", PF_R_PolygonVertex, 307}, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex (EXT_CSQC_???)
{"R_EndPolygon", PF_R_PolygonEnd, 308}, // #308 void() R_EndPolygon (EXT_CSQC_???)
{"R_EndPolygonRibbon", PF_R_PolygonEndRibbon, 0},
{"addtrisoup_simple", PF_R_AddTrisoup_Simple, 0},
{"getproperty", PF_R_GetViewFlag, 309}, // #309 vector/float(float property) getproperty (EXT_CSQC_1)
@ -6507,7 +6652,8 @@ static struct {
{"getkeybind", PF_cl_getkeybind, 342}, // #342 string(float keynum) getkeybind (EXT_CSQC)
{"setcursormode", PF_cl_setcursormode, 343}, // #343 This is originally a DP extension
{"getcursormode", PF_cl_getcursormode, 0}, // #343 This is originally a DP extension
{"getcursormode", PF_cl_getcursormode, 0}, //
{"setmousepos", PF_cl_setmousepos, 0}, //
{"getmousepos", PF_cl_getmousepos, 344}, // #344 This is a DP extension
{"getinputstate", PF_cs_getinputstate, 345}, // #345 float(float framenum) getinputstate (EXT_CSQC)
@ -7120,7 +7266,8 @@ void CSQC_Shutdown(void)
if (csqc_deprecated_warned>1)
{
Con_Printf("total %u csqc deprecation warnings suppressed\n", csqc_deprecated_warned-1);
if (!cl_csqc_nodeprecate.ival)
Con_Printf("total %u csqc deprecation warnings suppressed\n", csqc_deprecated_warned-1);
csqc_deprecated_warned = 0;
}
}
@ -7478,7 +7625,7 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
csqc_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc;
}
csqc_deprecated_warned = false;
csqc_deprecated_warned = !!cl_csqc_nodeprecate.ival;
memset(cl.model_csqcname, 0, sizeof(cl.model_csqcname));
memset(cl.model_csqcprecache, 0, sizeof(cl.model_csqcprecache));
@ -7981,6 +8128,8 @@ void CSQC_RegisterCvarsAndThings(void)
Cvar_Register(&cl_csqcdebug, CSQCPROGSGROUP);
Cvar_Register(&cl_nocsqc, CSQCPROGSGROUP);
Cvar_Register(&pr_csqc_coreonerror, CSQCPROGSGROUP);
Cvar_Register(&cl_csqc_nodeprecate, CSQCPROGSGROUP);
Cvar_Register(&dpcompat_csqcinputeventtypes, CSQCPROGSGROUP);
}
void CSQC_CvarChanged(cvar_t *var)
@ -8039,6 +8188,7 @@ qboolean CSQC_DrawView(void)
{
int ticlimit = 10;
float mintic = 0.01;
float maxtic = 0.1;
double clframetime = host_frametime;
RSpeedLocals();
@ -8065,6 +8215,8 @@ qboolean CSQC_DrawView(void)
}
else
{
if (csqc_world.rbe)
maxtic = mintic; //physics engines need a fixed tick rate.
while(1)
{
host_frametime = cl.servertime - csqc_world.physicstime;
@ -8075,8 +8227,8 @@ qboolean CSQC_DrawView(void)
csqc_world.physicstime = cl.servertime;
break;
}
if (host_frametime > mintic)
host_frametime = mintic;
if (host_frametime > maxtic)
host_frametime = maxtic;
#ifdef USERBE
if (csqc_world.rbe)
@ -8295,8 +8447,9 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid)
{
static qbyte csqckeysdown[K_MAX];
void *pr_globals;
int ie = down?CSIE_KEYDOWN:CSIE_KEYUP;
if (!csqcprogs || !csqcg.input_event)
if (!csqcprogs || !csqcg.input_event || ie >= dpcompat_csqcinputeventtypes.ival)
return false;
#ifdef TEXTEDITOR
if (editormodal)
@ -8304,7 +8457,7 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid)
#endif
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
G_FLOAT(OFS_PARM0) = down?CSIE_KEYDOWN:CSIE_KEYUP;
G_FLOAT(OFS_PARM0) = ie;
G_FLOAT(OFS_PARM1) = MP_TranslateFTEtoQCCodes(key);
G_FLOAT(OFS_PARM2) = unicode;
G_FLOAT(OFS_PARM3) = devid;
@ -8338,7 +8491,7 @@ qboolean CSQC_MousePosition(float xabs, float yabs, unsigned int devid)
{
void *pr_globals;
if (!csqcprogs || !csqcg.input_event)
if (!csqcprogs || !csqcg.input_event || CSIE_MOUSEABS >= dpcompat_csqcinputeventtypes.ival)
return false;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
@ -8355,7 +8508,7 @@ qboolean CSQC_MouseMove(float xdelta, float ydelta, unsigned int devid)
{
void *pr_globals;
if (!csqcprogs || !csqcg.input_event)
if (!csqcprogs || !csqcg.input_event || CSIE_MOUSEDELTA >= dpcompat_csqcinputeventtypes.ival)
return false;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
@ -8372,7 +8525,7 @@ qboolean CSQC_MouseMove(float xdelta, float ydelta, unsigned int devid)
qboolean CSQC_JoystickAxis(int axis, float value, unsigned int devid)
{
void *pr_globals;
if (!csqcprogs || !csqcg.input_event)
if (!csqcprogs || !csqcg.input_event || CSIE_JOYAXIS >= dpcompat_csqcinputeventtypes.ival)
return false;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
@ -8387,7 +8540,7 @@ qboolean CSQC_JoystickAxis(int axis, float value, unsigned int devid)
qboolean CSQC_Accelerometer(float x, float y, float z)
{
void *pr_globals;
if (!csqcprogs || !csqcg.input_event)
if (!csqcprogs || !csqcg.input_event || CSIE_ACCELEROMETER >= dpcompat_csqcinputeventtypes.ival)
return false;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
@ -8401,7 +8554,7 @@ qboolean CSQC_Accelerometer(float x, float y, float z)
qboolean CSQC_Gyroscope(float x, float y, float z)
{
void *pr_globals;
if (!csqcprogs || !csqcg.input_event)
if (!csqcprogs || !csqcg.input_event || CSIE_GYROSCOPE >= dpcompat_csqcinputeventtypes.ival)
return false;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);

View File

@ -110,6 +110,8 @@ struct {
unsigned int owner; //kdm_foo. whoever has an interest in this font. font is purged when this becomes 0.
char slotname[16];
char facename[MAX_OSPATH];
float scale; //poop
int outline; //argh
int sizes;
int size[FONT_SIZES];
struct font_s *font[FONT_SIZES];
@ -209,6 +211,8 @@ void PR_ReleaseFonts(unsigned int purgeowner)
fontslot[i].sizes = 0;
fontslot[i].slotname[0] = '\0';
fontslot[i].facename[0] = '\0';
fontslot[i].scale = 1;
fontslot[i].outline = 0;
}
}
void PR_ReloadFonts(qboolean reload)
@ -236,7 +240,7 @@ void PR_ReloadFonts(qboolean reload)
{ //otherwise load it.
for (j = 0; j < fontslot[i].sizes; j++)
{
fontslot[i].font[j] = Font_LoadFont(fontslot[i].facename, fontslot[i].size[j]);
fontslot[i].font[j] = Font_LoadFont(fontslot[i].facename, fontslot[i].size[j], fontslot[i].scale, fontslot[i].outline);
}
}
}
@ -248,6 +252,7 @@ void QCBUILTIN PF_CL_findfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
extern cvar_t r_font_postprocess_outline;
const char *slotname = PR_GetStringOfs(prinst, OFS_PARM0);
const char *facename = PR_GetStringOfs(prinst, OFS_PARM1);
const char *sizestr = PR_GetStringOfs(prinst, OFS_PARM2);
@ -272,7 +277,7 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return;
//if its changed, purge it.
if (stricmp(fontslot[slotnum].slotname, slotname) || stricmp(fontslot[slotnum].facename, facename))
if (stricmp(fontslot[slotnum].slotname, slotname) || stricmp(fontslot[slotnum].facename, facename) || !fontslot[slotnum].sizes)
{
Q_strncpyz(fontslot[slotnum].slotname, slotname, sizeof(fontslot[slotnum].slotname));
Q_strncpyz(fontslot[slotnum].facename, facename, sizeof(fontslot[slotnum].facename));
@ -282,14 +287,41 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
Font_Free(fontslot[slotnum].font[i]);
fontslot[slotnum].font[i] = NULL;
}
fontslot[slotnum].sizes = 0;
fontslot[slotnum].owner = 0;
fontslot[slotnum].scale = 1;
fontslot[slotnum].outline = r_font_postprocess_outline.ival;
}
fontslot[slotnum].owner |= world->keydestmask;
while(*sizestr)
{
sizestr = COM_Parse(sizestr);
if (!strncmp(com_token, "scale=", 6))
{
fontslot[slotnum].scale = atof(com_token+6);
continue;
}
if (!strncmp(com_token, "outline=", 8))
{
fontslot[slotnum].outline = atoi(com_token+8);
continue;
}
if (!strncmp(com_token, "blur=", 5))
{
//fontslot[slotnum].blur = atoi(com_token+5);
continue;
}
if (!strncmp(com_token, "voffset=", 8))
{
//com_token+8 unused.
continue;
}
sz = atoi(com_token);
if (!sz)
continue; //o.O
for (i = 0; i < fontslot[slotnum].sizes; i++)
{
if (fontslot[slotnum].size[i] == sz)
@ -300,33 +332,45 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (i >= FONT_SIZES)
break;
fontslot[slotnum].size[i] = sz;
if (qrenderer == QR_NONE)
fontslot[slotnum].font[i] = NULL;
else
fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i]);
fontslot[slotnum].font[i] = NULL;
fontslot[slotnum].sizes++;
}
}
if (qrenderer > QR_NONE)
{
for (i = 0; i < fontslot[slotnum].sizes; i++)
fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline);
}
G_FLOAT(OFS_RETURN) = slotnum;
}
#ifdef HAVE_LEGACY
void CL_LoadFont_f(void)
{
extern cvar_t r_font_postprocess_outline;
//console command for compat with dp/debug.
if (Cmd_Argc() == 1)
{
int i, j;
int th;
for (i = 0; i < FONT_SLOTS; i++)
{
if (fontslot[i].sizes)
{
Con_Printf("%s: %s (", fontslot[i].slotname, fontslot[i].facename);
Con_Printf("%s[%i]: %s (", fontslot[i].slotname, i, fontslot[i].facename);
for (j = 0; j < fontslot[i].sizes; j++)
{
if (j)
Con_Printf(", ");
Con_Printf("%i", fontslot[i].size[j]);
if (fontslot[i].font[j])
{
th = Font_GetTrueHeight(fontslot[i].font[j]);
if (th != Font_CharPHeight(fontslot[i].font[j]))
Con_Printf("[%g]", ((float)th*vid.height)/vid.pixelheight);
}
}
Con_Printf(")\n");
}
@ -339,7 +383,7 @@ void CL_LoadFont_f(void)
char *slotname = Cmd_Argv(1);
char *facename = Cmd_Argv(2);
int sizenum = 3;
extern cvar_t dpcompat_console, gl_font;
extern cvar_t dpcompat_console, gl_font, con_textfont;
//loadfont slot face size1 size2...
@ -378,6 +422,9 @@ void CL_LoadFont_f(void)
fontslot[slotnum].font[i] = NULL;
}
fontslot[slotnum].owner = 0;
fontslot[slotnum].scale = 1;
fontslot[slotnum].sizes = 0;
fontslot[slotnum].outline = r_font_postprocess_outline.ival; //locked in at definition, so different fonts can have different settings even with vid_reload going on.
}
if (!*facename)
return;
@ -389,11 +436,23 @@ void CL_LoadFont_f(void)
int sz;
if (!strcmp(a, "scale"))
{
fontslot[slotnum].scale = atof(Cmd_Argv(sizenum++));
continue;
}
if (!strcmp(a, "outline"))
{
fontslot[slotnum].outline = atoi(Cmd_Argv(sizenum++));
continue;
}
if (!strcmp(a, "blur"))
{
//fontslot[slotnum].blur = atoi(Cmd_Argv(sizenum++));
sizenum++;
continue;
}
if (!strcmp(a, "voffset"))
{
// fontslot[slotnum].voffset = atof(Cmd_Argv(sizenum++));
sizenum++;
continue;
}
@ -411,16 +470,21 @@ void CL_LoadFont_f(void)
if (i >= FONT_SIZES)
break;
fontslot[slotnum].size[i] = sz;
if (qrenderer == QR_NONE)
fontslot[slotnum].font[i] = NULL;
else
fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i]);
fontslot[slotnum].font[i] = NULL;
fontslot[slotnum].sizes++;
}
}
if (qrenderer > QR_NONE)
{
for (i = 0; i < fontslot[slotnum].sizes; i++)
fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline);
}
//FIXME: slotnum0==default is problematic.
if (dpcompat_console.ival && (slotnum == 1 || (slotnum == 0 && !*gl_font.string)))
if (dpcompat_console.ival && slotnum == 1)
Cvar_Set(&con_textfont, facename);
if (dpcompat_console.ival && slotnum == 0)
Cvar_Set(&gl_font, facename);
}
}
@ -1300,7 +1364,7 @@ static struct
{
func_t init;
func_t shutdown;
func_t draw;
func_t draw; qboolean fuckeddrawsizes;
func_t drawloading;
func_t keydown;
func_t keyup;
@ -1500,7 +1564,7 @@ static void QCBUILTIN PF_checkbuiltin (pubprogfuncs_t *prinst, struct globalvars
char *funcname = NULL;
int args;
int builtinno;
if (prinst->GetFunctionInfo(prinst, funcref, &args, &builtinno, funcname, sizeof(funcname)))
if (prinst->GetFunctionInfo(prinst, funcref, &args, NULL, &builtinno, funcname, sizeof(funcname)))
{ //qc defines the function at least. nothing weird there...
if (builtinno > 0 && builtinno < prinst->parms->numglobalbuiltins)
{
@ -2282,7 +2346,7 @@ static struct {
{"argescape", PF_argescape, 295},
//gap
{"clearscene", PF_m_clearscene, 300},
//no addentities
// {"addentities", PF_Fixme, 301},
{"addentity", PF_m_addentity, 302},//FIXME: needs setmodel, origin, angles, colormap(eep), frame etc, skin,
#ifdef CSQC_DAT
{"setproperty", PF_R_SetViewFlag, 303},//should be okay to share
@ -2310,15 +2374,28 @@ static struct {
{"getkeybind", PF_cl_getkeybind, 342},
{"setcursormode", PF_cl_setcursormode, 343},
{"getcursormode", PF_cl_getcursormode, 0},
//gap
{"setmousepos", PF_cl_setmousepos, 0},
// {NULL, PF_Fixme, 344},
// {NULL, PF_Fixme, 345},
// {NULL, PF_Fixme, 346},
// {NULL, PF_Fixme, 347},
// {NULL, PF_Fixme, 348},
{"isdemo", PF_isdemo, 349},
// {NULL, PF_Fixme, 350},
// {NULL, PF_Fixme, 351},
{"registercommand", PF_menu_registercommand, 352},
//gap
{"wasfreed", PF_WasFreed, 353},
// {NULL, PF_Fixme, 354},
#ifdef HAVE_MEDIA_DECODER
{"videoplaying", PF_cs_media_getstate, 355},
#endif
{"findfont", PF_CL_findfont, 356},
{"loadfont", PF_CL_loadfont, 357},
//gap
// {"dynamiclight_get", PF_R_DynamicLight_Get, 372},
// {"dynamiclight_set", PF_R_DynamicLight_Set, 373},
// {NULL, PF_Fixme, 374},
// {NULL, PF_Fixme, 375},
{"setcustomskin", PF_m_setcustomskin, 376},
//gap
{"memalloc", PF_memalloc, 384},
@ -2336,6 +2413,15 @@ static struct {
{"setwindowcaption", PF_cl_setwindowcaption, 0},
{"cvars_haveunsaved", PF_cvars_haveunsaved, 0},
//gap
// {"writebyte, PF_Fixme, 401},
// {"writechar, PF_Fixme, 402},
// {"writeshort, PF_Fixme, 403},
// {"writelong, PF_Fixme, 404},
// {"writeangle, PF_Fixme, 405},
// {"writecoord, PF_Fixme, 406},
// {"writestring, PF_Fixme, 407},
// {"writeentity, PF_Fixme, 408},
//gap
{"buf_create", PF_buf_create, 440},
{"buf_del", PF_buf_del, 441},
{"buf_getsize", PF_buf_getsize, 442},
@ -2346,7 +2432,7 @@ static struct {
{"bufstr_set", PF_bufstr_set, 447},
{"bufstr_add", PF_bufstr_add, 448},
{"bufstr_free", PF_bufstr_free, 449},
//450
// {NULL, PF_Fixme, 450},
{"iscachedpic", PF_CL_is_cached_pic, 451},
{"precache_pic", PF_CL_precache_pic, 452},
{"free_pic", PF_CL_free_pic, 453},
@ -2365,7 +2451,7 @@ static struct {
{"cin_getstate", PF_cs_media_getstate, 464},
{"cin_restart", PF_cs_media_restart, 465},
#endif
{"drawline", PF_drawline, 466},
{"drawline", PF_CL_drawline, 466},
{"drawstring", PF_CL_drawcolouredstring, 467},
{"stringwidth", PF_CL_stringwidth, 468},
{"drawsubpic", PF_CL_drawsubpic, 469},
@ -2388,10 +2474,10 @@ static struct {
{"strtolower", PF_strtolower, 480},
{"strtoupper", PF_strtoupper, 481},
{"cvar_defstring", PF_cvar_defstring, 482},
//483
// {NULL, PF_Fixme, 483},
{"strreplace", PF_strreplace, 484},
{"strireplace", PF_strireplace, 485},
//486
// {NULL, PF_Fixme, 486},
#ifdef HAVE_MEDIA_DECODER
{"gecko_create", PF_cs_media_create, 487},
{"gecko_destroy", PF_cs_media_destroy, 488},
@ -2400,7 +2486,7 @@ static struct {
{"gecko_mousemove", PF_cs_media_mousemove, 491},
{"gecko_resize", PF_cs_media_resize, 492},
{"gecko_get_texture_extent",PF_cs_media_get_texture_extent,493},
{"gecko_getproperty", PF_cs_media_getproperty},
{"gecko_getproperty", PF_cs_media_getproperty, 0},
#endif
{"crc16", PF_crc16, 494},
{"cvar_type", PF_cvar_type, 495},
@ -2411,6 +2497,8 @@ static struct {
{"entityfieldtype", PF_entityfieldtype, 498},
{"getentityfieldstring", PF_getentityfieldstring, 499},
{"putentityfieldstring", PF_putentityfieldstring, 500},
// {NULL, PF_Fixme, 501},
// {NULL, PF_Fixme, 502},
{"whichpack", PF_whichpack, 503},
//gap
{"uri_escape", PF_uri_escape, 510},
@ -2425,10 +2513,12 @@ static struct {
{"cvar_description", PF_cvar_description, 518},
//gap
{"log", PF_Logarithm, 532},
//gap
// {"getsoundtime", PF_Fixme, 533},
{"soundlength", PF_soundlength, 534},
{"buf_loadfile", PF_buf_loadfile, 535},
{"buf_writefile", PF_buf_writefile, 536},
// {"bufstr_find", PF_Fixme, 537},
// {"matchpattern", PF_Fixme, 538},
//gap
{"setkeydest", PF_cl_setkeydest, 601},
{"getkeydest", PF_cl_getkeydest, 602},
@ -2462,7 +2552,8 @@ static struct {
{"netaddress_resolve", PF_netaddress_resolve, 625},
{"getgamedirinfo", PF_cl_getgamedirinfo, 626},
{"sprintf", PF_sprintf, 627},
//gap
// {NULL, PF_Fixme, 628},
// {NULL, PF_Fixme, 629},
{"setkeybind", PF_cl_setkeybind, 630},
{"getbindmaps", PF_cl_GetBindMap, 631},
{"setbindmaps", PF_cl_SetBindMap, 632},
@ -2471,8 +2562,10 @@ static struct {
{"crypto_getencryptlevel", PF_crypto_getencryptlevel, 635},
{"crypto_getmykeyfp", PF_crypto_getmykeyfp, 636},
{"crypto_getmyidfp", PF_crypto_getmyidfp, 637},
// {NULL, PF_Fixme, 638},
{"digest_hex", PF_digest_hex, 639},
{"digest_ptr", PF_digest_ptr, 0},
// {NULL, PF_Fixme, 640},
{"crypto_getmyidstatus", PF_crypto_getmyidfp, 641},
@ -2665,6 +2758,8 @@ static qboolean MP_KeyEvent(menu_t *menu, qboolean isdown, unsigned int devid, i
}
static void MP_TryRelease(menu_t *m)
{
if (inmenuprogs)
return; //if the qc asked for it, the qc probably already knows about it. don't recurse.
MP_Toggle(0);
}
@ -2916,7 +3011,13 @@ qboolean MP_Init (void)
mpfuncs.init = PR_FindFunction(menu_world.progs, "m_init", PR_ANY);
mpfuncs.shutdown = PR_FindFunction(menu_world.progs, "m_shutdown", PR_ANY);
mpfuncs.draw = PR_FindFunction(menu_world.progs, "m_draw", PR_ANY);
{
int args = 0;
qbyte *argsizes = NULL;
mpfuncs.draw = PR_FindFunction(menu_world.progs, "m_draw", PR_ANY);
menu_world.progs->GetFunctionInfo(menu_world.progs, mpfuncs.draw, &args, &argsizes, NULL, NULL, 0);
mpfuncs.fuckeddrawsizes = (args == 2 && argsizes[0] == 1 && argsizes[1] == 1);
}
mpfuncs.drawloading = PR_FindFunction(menu_world.progs, "m_drawloading", PR_ANY);
mpfuncs.inputevent = PR_FindFunction(menu_world.progs, "Menu_InputEvent", PR_ANY);
mpfuncs.keydown = PR_FindFunction(menu_world.progs, "m_keydown", PR_ANY);
@ -3085,21 +3186,36 @@ void MP_Draw(void)
inmenuprogs++;
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
((float *)pr_globals)[OFS_PARM0+0] = vid.width;
((float *)pr_globals)[OFS_PARM0+1] = vid.height;
((float *)pr_globals)[OFS_PARM0+2] = 0;
((float *)pr_globals)[OFS_PARM1+0] = vid.height; //dp compat, ish
if (scr_drawloading||scr_disabled_for_loading)
{ //don't draw the menu if we're meant to be drawing a loading screen
//the menu should provide a special function if it wants to draw custom loading screens. this is for compat with old/dp/lazy/crappy menus.
if (mpfuncs.drawloading)
{
((float *)pr_globals)[OFS_PARM0+0] = vid.width;
((float *)pr_globals)[OFS_PARM0+1] = vid.height;
((float *)pr_globals)[OFS_PARM0+2] = 0;
((float *)pr_globals)[OFS_PARM1] = scr_disabled_for_loading;
PR_ExecuteProgram(menu_world.progs, mpfuncs.drawloading);
}
}
else if (mpfuncs.draw)
{
if (mpfuncs.fuckeddrawsizes)
{ //pass useless sizes in two args if its a dp menu
((float *)pr_globals)[OFS_PARM0] = vid.pixelwidth;
((float *)pr_globals)[OFS_PARM1] = vid.pixelheight;
}
else
{ //pass useful sizes in a 1-arg vector if its an fte menu.
((float *)pr_globals)[OFS_PARM0+0] = vid.width;
((float *)pr_globals)[OFS_PARM0+1] = vid.height;
((float *)pr_globals)[OFS_PARM0+2] = 0;
}
PR_ExecuteProgram(menu_world.progs, mpfuncs.draw);
}
inmenuprogs--;
}

View File

@ -56,6 +56,7 @@ struct
extern cvar_t scr_conalpha;
extern cvar_t gl_conback;
extern cvar_t gl_font, con_textfont;
extern cvar_t r_font_postprocess_outline;
extern cvar_t gl_screenangle;
extern cvar_t vid_conautoscale;
extern cvar_t vid_conheight;
@ -137,6 +138,7 @@ void R2D_Shutdown(void)
{
Cvar_Unhook(&con_textfont);
Cvar_Unhook(&gl_font);
Cvar_Unhook(&r_font_postprocess_outline);
Cvar_Unhook(&vid_conautoscale);
Cvar_Unhook(&gl_screenangle);
Cvar_Unhook(&vid_conheight);
@ -195,6 +197,10 @@ void R2D_Shutdown(void)
Z_Free(atlas.data);
memset(&atlas, 0, sizeof(atlas));
#ifdef PLUGINS
Plug_FreeAllImages();
#endif
}
/*
@ -396,6 +402,7 @@ void R2D_Init(void)
Cvar_Hook(&con_textfont, R2D_Font_Callback);
Cvar_Hook(&gl_font, R2D_Font_Callback);
Cvar_Hook(&r_font_postprocess_outline, R2D_Font_Callback);
Cvar_Hook(&vid_conautoscale, R2D_Conautoscale_Callback);
Cvar_Hook(&gl_screenangle, R2D_ScreenAngle_Callback);
Cvar_Hook(&vid_conheight, R2D_Conheight_Callback);
@ -1107,9 +1114,9 @@ void R2D_Font_Changed(void)
LOGFONTW lf = {0};
CHOOSEFONTW cf = {sizeof(cf)};
extern HWND mainwindow;
font_default = Font_LoadFont("", 8);
font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival);
if (tsize != 8)
font_console = Font_LoadFont("", tsize);
font_console = Font_LoadFont("", tsize, 1, r_font_postprocess_outline.ival);
if (!font_console)
font_console = font_default;
@ -1152,15 +1159,15 @@ void R2D_Font_Changed(void)
#endif
}
font_default = Font_LoadFont(gl_font.string, 8);
font_default = Font_LoadFont(gl_font.string, 8, 1, r_font_postprocess_outline.ival);
if (!font_default && *gl_font.string)
font_default = Font_LoadFont("", 8);
font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival);
if (tsize != 8 || strcmp(gl_font.string, con_font_name))
{
font_console = Font_LoadFont(con_font_name, tsize);
font_console = Font_LoadFont(con_font_name, tsize, 1, r_font_postprocess_outline.ival);
if (!font_console)
font_console = Font_LoadFont("", tsize);
font_console = Font_LoadFont("", tsize, 1, r_font_postprocess_outline.ival);
}
if (!font_console)
font_console = font_default;

View File

@ -3764,6 +3764,7 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea
if (deluxe && (count & 1))
{
deluxe = false;
// count+=1;
Con_Print("WARNING: Deluxemapping with odd number of lightmaps\n");
}
@ -4190,6 +4191,11 @@ void Surf_NewMap (void)
#endif
int i;
//evil haxx
r_dynamic.ival = r_dynamic.value;
if (r_dynamic.ival > 0 && cl.worldmodel->fromgame == fg_quake3) //quake3 has no lightmaps, disable r_dynamic
r_dynamic.ival = 0;
memset (&r_worldentity, 0, sizeof(r_worldentity));
AngleVectors(r_worldentity.angles, r_worldentity.axis[0], r_worldentity.axis[1], r_worldentity.axis[2]);
VectorInverse(r_worldentity.axis[1]);

View File

@ -292,6 +292,7 @@ typedef struct
float hdr_value;
vec3_t skyroom_pos; /*the camera position for sky rooms*/
vec4_t skyroom_spin; /*the camera spin for sky rooms*/
qboolean skyroom_enabled; /*whether a skyroom position is defined*/
int firstvisedict; /*so we can skip visedicts in skies*/
@ -476,7 +477,7 @@ const char *Image_FormatName(uploadfmt_t encoding);
qboolean Image_FormatHasAlpha(uploadfmt_t encoding);
image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags);
struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname, const char *fname, qbyte *filedata, int filesize);
void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int flags, uploadfmt_t origfmt, const char *imagename);
void Image_ChangeFormat(struct pendingtextureinfo *mips, qboolean *allowedformats, uploadfmt_t origfmt, const char *imagename);
void *Image_FlipImage(const void *inbuffer, void *outbuffer, int *inoutwidth, int *inoutheight, int pixelbytes, qboolean flipx, qboolean flipy, qboolean flipd);
#ifdef D3D8QUAKE
@ -650,6 +651,8 @@ extern cvar_t r_novis;
extern cvar_t r_netgraph;
extern cvar_t r_deluxemapping_cvar;
extern qboolean r_deluxemapping;
extern qboolean r_fakeshadows; //enables the use of ortho model-only shadows
extern float r_blobshadows;
extern cvar_t r_softwarebanding_cvar;
extern qboolean r_softwarebanding;
extern cvar_t r_lightprepass_cvar;

View File

@ -73,6 +73,24 @@ static void QDECL R_Lightmap_Format_Changed(struct cvar_s *var, char *oldvalue)
if (qrenderer)
Surf_BuildLightmaps();
}
static void QDECL R_HDR_FramebufferFormat_Changed(struct cvar_s *var, char *oldvalue)
{
int i;
char *e;
for (i = 0; i < PTI_MAX; i++)
{
if (!Q_strcasecmp(var->string, Image_FormatName(i)))
{
var->ival = -i;
return;
}
}
var->ival = strtol(var->string, &e, 0);
if (*e && e == var->string)
Con_Printf("%s set to unknown image format\n", var->name);
if (var->ival < 0)
var->ival = 0;
}
#ifdef FTE_TARGET_WEB //webgl sucks too much to get a stable framerate without vsync.
cvar_t vid_vsync = CVARAF ("vid_vsync", "1",
@ -99,7 +117,7 @@ cvar_t gl_part_flame = CVARFD ("gl_part_flame", "1", CVAR_ARCHIVE, "Enable
//opengl library, blank means try default.
static cvar_t gl_driver = CVARFD ("gl_driver", "", CVAR_ARCHIVE | CVAR_VIDEOLATCH, "Specifies the graphics driver name to load. This is typically a filename. Blank for default.");
static cvar_t vid_devicename = CVARFD ("vid_devicename", "", CVAR_ARCHIVE | CVAR_VIDEOLATCH, "Specifies which video device to try to use. If blank or invalid then one will be guessed.");
cvar_t vid_devicename = CVARFD ("vid_devicename", "", CVAR_ARCHIVE | CVAR_VIDEOLATCH, "Specifies which video device to try to use. If blank or invalid then one will be guessed.");
cvar_t gl_shadeq1_name = CVARD ("gl_shadeq1_name", "*", "Rename all surfaces from quake1 bsps using this pattern for the purposes of shader names.");
extern cvar_t r_vertexlight;
extern cvar_t r_forceprogramify;
@ -177,7 +195,7 @@ cvar_t r_lightstylesmooth_limit = CVAR ("r_lightstylesmooth_limit", "2");
cvar_t r_lightstylespeed = CVAR ("r_lightstylespeed", "10");
cvar_t r_lightstylescale = CVAR ("r_lightstylescale", "1");
cvar_t r_lightmap_scale = CVARFD ("r_shadow_realtime_nonworld_lightmaps", "1", 0, "Scaler for lightmaps used when not using realtime world lighting. Probably broken.");
cvar_t r_hdr_framebuffer = CVARFD("r_hdr_framebuffer", "0", CVAR_ARCHIVE, "If enabled, the map will be rendered into a high-precision image framebuffer. This avoids issues with shaders that contribute more than 1 in any single pass (like overbrights).");
cvar_t r_hdr_framebuffer = CVARFCD("r_hdr_framebuffer", "0", CVAR_ARCHIVE, R_HDR_FramebufferFormat_Changed, "If enabled, the map will be rendered into a high-precision image framebuffer. This avoids issues with shaders that contribute more than 1 in any single pass (like overbrights). Can also be set to the name of an image format, to force rendering to that format first - interesting formats are L8, RGB565, B10G11R11F, and others.");
cvar_t r_hdr_irisadaptation = CVARF ("r_hdr_irisadaptation", "0", CVAR_ARCHIVE);
cvar_t r_hdr_irisadaptation_multiplier = CVAR ("r_hdr_irisadaptation_multiplier", "2");
cvar_t r_hdr_irisadaptation_minvalue = CVAR ("r_hdr_irisadaptation_minvalue", "0.5");
@ -286,7 +304,7 @@ cvar_t vid_fullscreen = CVARF ("vid_fullscreen", "2",
CVAR_ARCHIVE|CVAR_VIDEOLATCH);
cvar_t vid_height = CVARFD ("vid_height", "0",
CVAR_ARCHIVE | CVAR_VIDEOLATCH, "The screen height to attempt to use, in physical pixels. 0 means use desktop resolution.");
cvar_t vid_multisample = CVARFD ("vid_multisample", "0",
cvar_t vid_multisample = CVARAFD ("vid_multisample", "0", "vid_samples",
CVAR_ARCHIVE, "The number of samples to use for Multisample AntiAliasing (aka: msaa). A value of 1 explicitly disables it.");
cvar_t vid_refreshrate = CVARF ("vid_displayfrequency", "0",
CVAR_ARCHIVE | CVAR_VIDEOLATCH);
@ -437,6 +455,11 @@ cvar_t gl_texturemode2d = CVARFCD("gl_texturemode2d", "GL_LINEAR",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, Image_TextureMode_Callback,
"Specifies how 2d images are sampled. format is a 3-tupple ");
cvar_t r_font_linear = CVARF("r_font_linear", "1", 0);
cvar_t r_font_postprocess_outline = CVARFD("r_font_postprocess_outline", "0", 0, "Controls the number of pixels of dark borders to use around fonts.");
#if defined(HAVE_LEGACY) && defined(AVAIL_FREETYPE)
cvar_t dpcompat_smallerfonts = CVARFD("dpcompat_smallerfonts", "0", 0, "Mimics DP's behaviour of using a smaller font size than was actually requested.");
#endif
cvar_t vid_triplebuffer = CVARAFD ("vid_triplebuffer", "1", "gl_triplebuffer", CVAR_ARCHIVE, "Specifies whether the hardware is forcing tripplebuffering on us, this is the number of extra page swaps required before old data has been completely overwritten.");
@ -446,7 +469,7 @@ cvar_t r_portalonly = CVARD ("r_portalonly", "0", "Don't draw things whic
cvar_t r_noaliasshadows = CVARF ("r_noaliasshadows", "0", CVAR_ARCHIVE);
cvar_t r_lodscale = CVARFD ("r_lodscale", "5", CVAR_ARCHIVE, "Scales the level-of-detail reduction on models (for those that have lod).");
cvar_t r_lodbias = CVARFD ("r_lodbias", "0", CVAR_ARCHIVE, "Biases the level-of-detail on models (for those that have lod).");
cvar_t r_shadows = CVARFD ("r_shadows", "0", CVAR_ARCHIVE, "Draw basic blob shadows underneath entities without using realtime lighting.");
cvar_t r_shadows = CVARFD ("r_shadows", "0", CVAR_ARCHIVE, "Draw basic blob shadows underneath entities without using realtime lighting.");
cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground.");
cvar_t r_showfields = CVARD("r_showfields", "0", "Debugging. Shows entity fields boxes (entity closest to crosshair). 1=ssqc, 2=csqc.");
cvar_t r_showshaders = CVARD("r_showshaders", "0", "Debugging. Shows the name of the (worldmodel) shader being pointed to.");
@ -985,6 +1008,10 @@ void Renderer_Init(void)
Cvar_Register (&gl_texturemode, GLRENDEREROPTIONS);
Cvar_Register (&gl_texturemode2d, GLRENDEREROPTIONS);
Cvar_Register (&r_font_linear, GLRENDEREROPTIONS);
Cvar_Register (&r_font_postprocess_outline, GLRENDEREROPTIONS);
#if defined(HAVE_LEGACY) && defined(AVAIL_FREETYPE)
Cvar_Register (&dpcompat_smallerfonts, GLRENDEREROPTIONS);
#endif
Cvar_Register (&gl_mipcap, GLRENDEREROPTIONS);
Cvar_Register (&gl_texture_lodbias, GLRENDEREROPTIONS);
Cvar_Register (&gl_texture_anisotropic_filtering, GLRENDEREROPTIONS);
@ -1391,7 +1418,7 @@ qboolean R_ApplyRenderer (rendererstate_t *newr)
time = Sys_DoubleTime();
#ifndef NOBUILTINMENUS
M_RemoveAllMenus(true);
// M_RemoveAllMenus(true);
#endif
Media_CaptureDemoEnd();
R_ShutdownRenderer(true);
@ -1493,11 +1520,15 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
memcpy(host_basepal, default_quakepal, 768);
}
}
Validation_FileLoaded("gfx/palette.lmp", host_basepal, 768);
{
qbyte *colormap = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp", NULL);
if (colormap)
size_t csize;
qbyte *colormap = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp", &csize);
if (colormap && csize == VID_GRADES*256+1)
{
Validation_FileLoaded("gfx/colormap.lmp", colormap, csize);
j = VID_GRADES-1;
data = colormap + j*256;
vid.fullbright = 0;
@ -1595,6 +1626,24 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
Cvar_ForceSetValue(&vid_dpi_x, vid.dpi_x);
Cvar_ForceSetValue(&vid_dpi_y, vid.dpi_y);
#if 0//def HAVE_LEGACY
{ //if dp's vid_pixelheight cvar exists then lets force it to what we know.
//that said, some dp mods just end up trying to use a fov of 0('auto') when this is 0, which fixes all our fov woes, so don't break that if its explictly 0 (a bit of a hack, but quite handy).
//setting this properly seems to fuck over xonotic.
cvar_t *pixelheight = Cvar_FindVar("vid_pixelheight");
if (pixelheight && (pixelheight->value || !*pixelheight->string))
{
if (vid.dpi_x && vid.dpi_y)
{
float ipd_x = 1/vid.dpi_x;
float ipd_y = 1/vid.dpi_y;
Cvar_ForceSetValue(pixelheight, ipd_y/ipd_x);
}
else
Cvar_ForceSetValue(pixelheight, 1);
}
}
#endif
TRACE(("dbg: R_ApplyRenderer: R_PreNewMap (how handy)\n"));
Surf_PreNewMap();
@ -2992,7 +3041,7 @@ void R_SetFrustum (float projmat[16], float viewmat[16])
//do far plane
//fog will logically not actually reach 0, though precision issues will force it. we cut off at an exponant of -500
if (r_refdef.globalfog.density && r_refdef.globalfog.alpha>=1 && r_fog_cullentities.ival)
if (r_refdef.globalfog.density && r_refdef.globalfog.alpha>=1 && r_fog_cullentities.ival && !r_refdef.globalfog.depthbias)
{
float culldist;
float fog;
@ -3028,7 +3077,7 @@ void R_SetFrustum (float projmat[16], float viewmat[16])
p->normal[1] *= -scale;
p->normal[2] *= -scale;
// p->dist *= scale;
p->dist = DotProduct(r_origin, p->normal)-culldist;
p->dist = DotProduct(r_refdef.vieworg, p->normal)-culldist;
p->type = PLANE_ANYZ;
p->signbits = SignbitsForPlane (p);

View File

@ -1246,7 +1246,7 @@ void Draw_TinyString (float x, float y, const qbyte *str)
if (!font_tiny)
{
font_tiny = Font_LoadFont("gfx/tinyfont", 8);
font_tiny = Font_LoadFont("gfx/tinyfont", 8, 1, 0);
if (!font_tiny)
return;
}

View File

@ -122,13 +122,14 @@ typedef enum uploadfmt
PTI_RGBA32F, //usually overkill
//packed/misaligned formats: these are specified in native endian order (high bits listed first because that's how things are represented in hex), so may need byte swapping...
PTI_A2BGR10, //mostly for rendertargets, might also be useful for overbight lightmaps.
PTI_E5BGR9, //mostly for fancy lightmaps
PTI_B10G11R11F, //unshared exponents
PTI_RGB565, //16bit alphaless format.
PTI_RGBA4444, //16bit format (gl)
PTI_ARGB4444, //16bit format (d3d)
PTI_RGBA5551, //16bit alpha format (gl).
PTI_ARGB1555, //16bit alpha format (d3d).
#define PTI_FIRSTCOMPRESSED PTI_E5BGR9
PTI_E5BGR9, //mostly for fancy lightmaps (technically compressed, with a block size of 1...)
//(desktop/tegra) compressed formats
PTI_BC1_RGB, /*4bpp*/
PTI_BC1_RGB_SRGB, /*4bpp*/
@ -271,7 +272,7 @@ void Font_Init(void);
void Font_Shutdown(void);
int Font_RegisterTrackerImage(const char *image); //returns a unicode char value that can be used to embed the char within a line of text.
qboolean Font_TrackerValid(unsigned int imid);
struct font_s *Font_LoadFont(const char *fontfilename, float height);
struct font_s *Font_LoadFont(const char *fontfilename, float height, float scale, int outline);
void Font_Free(struct font_s *f);
void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py);
void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/
@ -279,6 +280,7 @@ void Font_Transform(float vx, float vy, int *px, int *py);
int Font_CharHeight(void);
float Font_CharVHeight(struct font_s *font);
int Font_CharPHeight(struct font_s *font);
int Font_GetTrueHeight(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

@ -311,6 +311,7 @@ static void S_Info(void);
static void S_Shutdown_f(void);
*/
static cvar_t s_al_disable = CVARD("s_al_disable", "0", "When set, prevents initialisation of openal. Audio ouput can then fall back to platfrm-specific output which doesn't have any of the miscilaneous openal limitations or bugs.");
static cvar_t s_al_debug = CVARD("s_al_debug", "0", "Enables periodic checks for OpenAL errors.");
static cvar_t s_al_use_reverb = CVARD("s_al_use_reverb", "1", "Controls whether reverb effects will be used. Set to 0 to block them. Reverb requires gamecode to configure the reverb properties, other than underwater.");
//static cvar_t s_al_max_distance = CVARFC("s_al_max_distance", "1000",0,OnChangeALSettings);
@ -536,6 +537,7 @@ static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache
static void QDECL OpenAL_CvarInit(void)
{
Cvar_Register(&s_al_disable, SOUNDVARS);
Cvar_Register(&s_al_debug, SOUNDVARS);
Cvar_Register(&s_al_use_reverb, SOUNDVARS);
// Cvar_Register(&s_al_max_distance, SOUNDVARS);
@ -638,7 +640,7 @@ static ssamplepos_t OpenAL_GetChannelPos(soundcardinfo_t *sc, channel_t *chan)
}
//schanged says the sample has changed, otherwise its merely moved around a little, maybe changed in volume, but nothing that will restart it.
static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned int schanged)
static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdatereason_t schanged)
{
oalinfo_t *oali = sc->handle;
ALuint src;
@ -682,12 +684,12 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
}
}
oali->source[chnum] = src;
schanged = true; //should normally be true anyway, but hey
schanged |= CUR_EVERYTHING; //should normally be true anyway, but hey
}
PrintALError("pre start sound");
if (schanged==true && src)
if ((schanged&CUR_SOUNDCHANGE) && src)
palSourceStop(src);
//reclaim any queued buffers
@ -710,7 +712,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
palGetSourcei(src, AL_SOURCE_STATE, &buf);
if (buf != AL_PLAYING)
{
schanged = true;
schanged |= CUR_EVERYTHING;
if(sfx->loopstart != -1)
chan->pos = sfx->loopstart<<PITCHSHIFT;
else if (chan->flags & CF_FORCELOOP)
@ -741,6 +743,8 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
cvolume = chan->master_vol/255.0f;
if (!(chan->flags & CF_CL_ABSVOLUME))
cvolume *= volume.value*voicevolumemod;
else
cvolume *= mastervolume.value;
//openal doesn't support loopstart (entire sample loops or not at all), so if we're meant to skip the first half then we need to stream it.
stream = sfx->decoder.decodedata || sfx->loopstart > 0;
@ -823,7 +827,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
palGetSourcei(src, AL_SOURCE_STATE, &buf);
if (buf != AL_PLAYING)
schanged = true;
schanged = CUR_EVERYTHING;
}
else
{
@ -900,7 +904,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
if (schanged)
{
if (schanged == 2 && chan->pos)
if (schanged == CUR_UPDATE && chan->pos)
{ //complex update, but not restart. pos contains an offset, rather than an absolute time.
int cursample;
palGetSourcei(src, AL_SAMPLE_OFFSET, &cursample);
@ -995,7 +999,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
}
/*and start it up again*/
if (schanged != 2)
if (schanged != CUR_UPDATE)
palSourcePlay(src);
}
@ -1030,6 +1034,8 @@ static qboolean OpenAL_InitLibrary(void)
#endif
#ifdef OPENAL_STATIC
if (s_al_disable.ival)
return false;
return true;
#else
static dllfunction_t openalfuncs[] =
@ -1072,6 +1078,8 @@ static qboolean OpenAL_InitLibrary(void)
{NULL}
};
if (s_al_disable.ival)
return false;
if (COM_CheckParm("-noopenal"))
return false;

View File

@ -72,10 +72,11 @@ int desired_bits = 16;
int sound_started=0;
cvar_t mastervolume = CVARFD( "mastervolume", "1", CVAR_ARCHIVE, "Additional multiplier for all other sounds.");
cvar_t bgmvolume = CVARAFD( "musicvolume", "0.3", "bgmvolume", CVAR_ARCHIVE,
"Volume level for background music.");
cvar_t volume = CVARAFD( "volume", "0.7", /*q3*/"s_volume",CVAR_ARCHIVE,
"Main volume level for all engine sound.");
"Volume level for game sounds (does not affect music, voice, or cinematics).");
cvar_t nosound = CVARFD( "nosound", "0", CVAR_ARCHIVE,
"Disable all sound from the engine. Cannot be overriden by configs or anything if set via the -nosound commandline argument.");
@ -1174,6 +1175,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
voicevolumemod = s_voip.lastspoke_any > realtime?snd_voip_ducking.value:1;
voicevolumemod *= mastervolume.value;
if (!voipsendenable || (voipcodec != s_voip.enccodec && s_voip.cdriver))
{
@ -2287,6 +2289,7 @@ void S_Init (void)
Cmd_AddCommand("soundcontrol", S_Control_f);
Cvar_Register(&nosound, "Sound controls");
Cvar_Register(&mastervolume, "Sound controls");
Cvar_Register(&volume, "Sound controls");
Cvar_Register(&precache, "Sound controls");
Cvar_Register(&loadas8bit, "Sound controls");
@ -2651,7 +2654,7 @@ static void SND_AccumulateSpacialization(soundcardinfo_t *sc, channel_t *ch, vec
int seat;
if (ch->flags & CF_CL_ABSVOLUME)
volscale = 1;
volscale = mastervolume.value;
else
volscale = volume.value * voicevolumemod;
@ -2778,7 +2781,7 @@ static void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
//sounds with absvolume ignore all volume etc cvars+settings
if (ch->flags & CF_CL_ABSVOLUME)
volscale = 1;
volscale = mastervolume.value;
else
volscale = volume.value * voicevolumemod;
@ -2877,7 +2880,7 @@ static void S_UpdateSoundCard(soundcardinfo_t *sc, qboolean updateonly, channel_
int skip;
int absstartpos = updateonly?target_chan->pos:0;
extern cvar_t cl_demospeed;
int chanupdatetype = true;
chanupdatereason_t chanupdatetype = updateonly?CUR_UPDATE:CUR_EVERYTHING;
if (!sfx)
sfx = target_chan->sfx;
@ -2899,7 +2902,7 @@ static void S_UpdateSoundCard(soundcardinfo_t *sc, qboolean updateonly, channel_
// spatialize
if (target_chan->sfx != sfx)
chanupdatetype = true;
chanupdatetype |= CUR_SOUNDCHANGE;
memset (target_chan, 0, sizeof(*target_chan));
if (!origin)
{
@ -2943,12 +2946,6 @@ static void S_UpdateSoundCard(soundcardinfo_t *sc, qboolean updateonly, channel_
target_chan->sfx = sfx;
if (updateonly && sc->ChannelUpdate)
{
chanupdatetype = 2;
absstartpos = 0;
}
target_chan->rate = ((1<<PITCHSHIFT) * ratemul); //*sfx->rate/sc->sn.speed;
if (target_chan->rate < 1) /*make sure the rate won't crash us*/
target_chan->rate = 1;
@ -3209,7 +3206,7 @@ static void S_StopSoundCard(soundcardinfo_t *sc, int entnum, int entchannel)
{
sc->channel[i].sfx = NULL;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, &sc->channel[i], true);
sc->ChannelUpdate(sc, &sc->channel[i], CUR_EVERYTHING);
if (entchannel)
break;
}
@ -3255,7 +3252,7 @@ void S_StopAllSounds(qboolean clear)
}
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, &sc->channel[i], true);
sc->ChannelUpdate(sc, &sc->channel[i], CUR_EVERYTHING);
}
}
@ -3346,7 +3343,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
SND_Spatialize (scard, ss);
if (scard->ChannelUpdate)
scard->ChannelUpdate(scard, ss, true);
scard->ChannelUpdate(scard, ss, CUR_EVERYTHING);
}
S_UnlockMixer();
@ -3376,7 +3373,7 @@ void S_Music_Clear(sfx_t *onlyifsample)
sc->channel[i].sfx = NULL;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, &sc->channel[i], true);
sc->ChannelUpdate(sc, &sc->channel[i], CUR_EVERYTHING);
if (s && s->decoder.ended && !S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly.
s->decoder.ended(s);
@ -3437,7 +3434,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
for (i = MUSIC_FIRST; i < MUSIC_STOP; i++)
{
qboolean changed = false;
chanupdatereason_t changed = false;
chan = &sc->channel[i];
if (!chan->sfx)
{
@ -3448,7 +3445,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
chan->sfx = newmusic;
chan->rate = 1<<PITCHSHIFT;
chan->pos = (int)(time * sc->sn.speed) * chan->rate;
changed = true;
changed = CUR_EVERYTHING;
chan->master_vol = bound(0, 1, 255);
chan->vol[0] = chan->vol[1] = chan->vol[2] = chan->vol[3] = chan->vol[4] = chan->vol[5] = chan->master_vol;
@ -3474,7 +3471,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
chan->sfx = NULL;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, chan, true);
sc->ChannelUpdate(sc, chan, CUR_EVERYTHING);
if (s && s->decoder.ended && !S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly.
s->decoder.ended(s);
@ -3555,7 +3552,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
chan->vol[0] = chan->vol[1] = chan->vol[2] = chan->vol[3] = chan->vol[4] = chan->vol[5] = bound(0, chan->master_vol * (volume.value*voicevolumemod), 255);
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, chan, (oldvol == 0) ^ (sc->ambientlevels[i] == 0));
sc->ChannelUpdate(sc, chan, ((oldvol == 0) ^ (sc->ambientlevels[i] == 0))?CUR_EVERYTHING:CUR_SPACIALISEONLY);
}
#endif
}
@ -3701,7 +3698,7 @@ static void S_Q2_AddEntitySounds(soundcardinfo_t *sc)
SND_Spatialize(sc, c);
if (c->sfx)
sc->ChannelUpdate(sc, c, false);
sc->ChannelUpdate(sc, c, CUR_SPACIALISEONLY);
}
else
{ //merge with any other ents, if we can
@ -3725,7 +3722,7 @@ static void S_Q2_AddEntitySounds(soundcardinfo_t *sc)
{
c->sfx = sfx;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, c, true);
sc->ChannelUpdate(sc, c, CUR_EVERYTHING);
}
}
}
@ -3769,7 +3766,7 @@ static void S_UpdateCard(soundcardinfo_t *sc)
{
ch->sfx = NULL;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, ch, true);
sc->ChannelUpdate(sc, ch, CUR_EVERYTHING);
}
ch->vol[0] = ch->vol[1] = ch->vol[2] = ch->vol[3] = ch->vol[4] = ch->vol[5] = 0;
continue;
@ -3779,7 +3776,7 @@ static void S_UpdateCard(soundcardinfo_t *sc)
{
if (ch->flags & CF_FOLLOW)
SND_Spatialize(sc, ch); //update it a little
sc->ChannelUpdate(sc, ch, false);
sc->ChannelUpdate(sc, ch, CUR_SPACIALISEONLY);
continue;
}
@ -4341,7 +4338,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
si->channel[i].pos = 0;
si->channel[i].master_vol = 255 * volume;
if (si->ChannelUpdate)
si->ChannelUpdate(si, &si->channel[i], false);
si->ChannelUpdate(si, &si->channel[i], CUR_SPACIALISEONLY);
break;
}
if (i == si->total_chans) //this one wasn't playing.
@ -4360,7 +4357,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
SND_Spatialize(si, c);
if (si->ChannelUpdate)
si->ChannelUpdate(si, c, true);
si->ChannelUpdate(si, c, CUR_EVERYTHING);
}
}
}

View File

@ -943,6 +943,9 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t forcedecode, siz
}
}
}
if (data)
Validation_FileLoaded(name, data, filesize);
}
if (!data)

View File

@ -105,7 +105,7 @@ typedef struct
#define CF_FORCELOOP 2 // forces looping. set on static sounds.
#define CF_NOSPACIALISE 4 // these sounds are played at a fixed volume in both speakers, but still gets quieter with distance.
//#define CF_PAUSED 8 // rate = 0. or something.
#define CF_CL_ABSVOLUME 16 // ignores volume cvar. this is ignored if received from the server because there's no practical way for the server to respect the client's preferences.
#define CF_CL_ABSVOLUME 16 // ignores volume cvar (but not mastervolume). this is ignored if received from the server because there's no practical way for the server to respect the client's preferences.
//#define CF_SV_RESERVED CF_CL_ABSVOLUME
#define CF_NOREVERB 32 // disables reverb on this channel, if possible.
#define CF_FOLLOW 64 // follows the owning entity (stops moving if we lose track)
@ -298,7 +298,7 @@ extern cvar_t snd_nominaldistance;
extern cvar_t loadas8bit;
extern cvar_t bgmvolume;
extern cvar_t volume;
extern cvar_t volume, mastervolume;
extern cvar_t snd_capture;
extern float voicevolumemod;
@ -339,6 +339,14 @@ extern sounddriver pWAV_InitCard;
extern sounddriver pAHI_InitCard;
*/
typedef enum
{
CUR_SPACIALISEONLY = 0, //for ticking over, respacialising, etc
CUR_UPDATE = (1u<<1), //flags/rate/offset changed without changing the sound itself
CUR_SOUNDCHANGE = (1u<<2), //the audio file changed too. reset everything.
CUR_EVERYTHING = CUR_UPDATE|CUR_SOUNDCHANGE
} chanupdatereason_t;
struct soundcardinfo_s { //windows has one defined AFTER directsound
char name[256]; //a description of the card.
char guid[256]; //device name as detected (so input code can create sound devices without bugging out too much)
@ -376,7 +384,7 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
unsigned int (*GetDMAPos) (soundcardinfo_t *sc); //get the current point that the hardware is reading from (the return value should not wrap, at least not very often)
void (*SetEnvironmentReverb) (soundcardinfo_t *sc, size_t reverb); //if you have eax enabled, change the environment. fixme. generally this is a stub. optional.
void (*Restore) (soundcardinfo_t *sc); //called before lock/unlock/lock/unlock/submit. optional
void (*ChannelUpdate) (soundcardinfo_t *sc, channel_t *channel, unsigned int schanged); //properties of a sound effect changed. this is to notify hardware mixers. optional.
void (*ChannelUpdate) (soundcardinfo_t *sc, channel_t *channel, chanupdatereason_t schanged); //properties of a sound effect changed. this is to notify hardware mixers. optional.
void (*ListenerUpdate) (soundcardinfo_t *sc, int entnum, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity); //player moved or something. this is to notify hardware mixers. optional.
ssamplepos_t (*GetChannelPos) (soundcardinfo_t *sc, channel_t *channel); //queries a hardware mixer's channel position (essentially returns channel->pos, except more up to date)

View File

@ -842,8 +842,6 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
strftime (buffer, sizeof(buffer), "Time: %Y-%m-%d %H:%M:%S\n",timeinfo);
write(fd, buffer, strlen(buffer));
Q_snprintfz(buffer, sizeof(buffer), "Binary: "__DATE__" "__TIME__"\n");
write(fd, buffer, strlen(buffer));
Q_snprintfz(buffer, sizeof(buffer), "Ver: %i.%02i%s\n", FTE_VER_MAJOR, FTE_VER_MINOR,
#ifdef OFFICIAL_RELEASE
" (official)");
@ -851,13 +849,17 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
"");
#endif
write(fd, buffer, strlen(buffer));
#ifdef SVNREVISION
if (strcmp(STRINGIFY(SVNREVISION), "-"))
{
Q_snprintfz(buffer, sizeof(buffer), "Revision: %s\n", STRINGIFY(SVNREVISION));
write(fd, buffer, strlen(buffer));
}
#if defined(SVNREVISION) && defined(SVNDATE)
Q_snprintfz(buffer, sizeof(buffer), "Revision: %s, %s\n", STRINGIFY(SVNREVISION), STRINGIFY(SVNDATE));
#else
Q_snprintfz(buffer, sizeof(buffer),
#ifdef SVNREVISION
"Revision: "STRINGIFY(SVNREVISION)"\n"
#endif
"Binary: "__DATE__" "__TIME__"\n");
#endif
write(fd, buffer, strlen(buffer));
backtrace_symbols_fd(array + firstframe, size - firstframe, fd);
write(fd, "\n", 1);
@ -1088,11 +1090,20 @@ int main (int c, const char **v)
newtime = Sys_DoubleTime ();
time = newtime - oldtime;
sleeptime = Host_Frame(time);
oldtime = newtime;
if (isDedicated)
{
sleeptime = SV_Frame();
oldtime = newtime;
NET_Sleep(sleeptime, noconinput?false:true);
}
else
{
sleeptime = Host_Frame(time);
oldtime = newtime;
if (sleeptime)
Sys_Sleep(sleeptime);
if (sleeptime)
Sys_Sleep(sleeptime);
}
}
}

View File

@ -317,113 +317,209 @@ void Sys_Quit (void)
//SDL provides no file enumeration facilities.
#if defined(_WIN32)
#include <windows.h>
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath)
{
qboolean go;
HANDLE r;
WIN32_FIND_DATA fd;
char apath[MAX_OSPATH];
char apath2[MAX_OSPATH];
char file[MAX_OSPATH];
char *s;
int go;
if (!gpath)
return 0;
// strcpy(apath, match);
Q_snprintfz(apath, sizeof(apath), "%s/%s", gpath, match);
for (s = apath+strlen(apath)-1; s> apath; s--)
WIN32_FIND_DATAW fd;
int nest = neststart; //neststart refers to just after a /
qboolean wild = false;
while(match[nest] && match[nest] != '/')
{
if (*s == '/')
break;
if (match[nest] == '?' || match[nest] == '*')
wild = true;
nest++;
}
*s = '\0';
//this is what we ask windows for.
Q_snprintfz(file, sizeof(file), "%s/*.*", apath);
//we need to make apath contain the path in match but not gpath
Q_strncpyz(apath2, match, sizeof(apath));
match = s+1;
for (s = apath2+strlen(apath2)-1; s> apath2; s--)
if (match[nest] == '/')
{
if (*s == '/')
break;
}
*s = '\0';
if (s != apath2)
strcat(apath2, "/");
char submatch[MAX_OSPATH];
char tmproot[MAX_OSPATH];
if (!wild)
return Sys_EnumerateFiles2(match, matchstart, nest+1, func, parm, spath);
if (nest-neststart+1> MAX_OSPATH)
return 1;
memcpy(submatch, match+neststart, nest - neststart);
submatch[nest - neststart] = 0;
nest++;
if (neststart+4 > MAX_OSPATH)
return 1;
memcpy(tmproot, match, neststart);
strcpy(tmproot+neststart, "*.*");
r = FindFirstFile(file, &fd);
if (r==(HANDLE)-1)
return 1;
go = true;
do
{
if (*fd.cFileName == '.'); //don't ever find files with a name starting with '.'
else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory
{
if (wildcmp(match, fd.cFileName))
{
Q_snprintfz(file, sizeof(file), "%s%s/", apath2, fd.cFileName);
go = func(file, fd.nFileSizeLow, 0, parm, spath);
}
wchar_t wroot[MAX_OSPATH];
r = FindFirstFileExW(widen(wroot, sizeof(wroot), tmproot), FindExInfoStandard, &fd, FindExSearchNameMatch, NULL, 0);
}
else
strcpy(tmproot+neststart, "");
if (r==(HANDLE)-1)
return 1;
go = true;
do
{
if (wildcmp(match, fd.cFileName))
char utf8[MAX_OSPATH];
char file[MAX_OSPATH];
narrowen(utf8, sizeof(utf8), fd.cFileName);
if (*utf8 == '.'); //don't ever find files with a name starting with '.'
else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory
{
Q_snprintfz(file, sizeof(file), "%s%s", apath2, fd.cFileName);
go = func(file, fd.nFileSizeLow, 0, parm, spath);
if (wildcmp(submatch, utf8))
{
int newnest;
if (strlen(tmproot) + strlen(utf8) + strlen(match+nest) + 2 < MAX_OSPATH)
{
Q_snprintfz(file, sizeof(file), "%s%s/", tmproot, utf8);
newnest = strlen(file);
strcpy(file+newnest, match+nest);
go = Sys_EnumerateFiles2(file, matchstart, newnest, func, parm, spath);
}
}
}
}
} while(FindNextFileW(r, &fd) && go);
FindClose(r);
}
while(FindNextFile(r, &fd) && go);
FindClose(r);
else
{
const char *submatch = match + neststart;
char tmproot[MAX_OSPATH];
if (neststart+4 > MAX_OSPATH)
return 1;
memcpy(tmproot, match, neststart);
strcpy(tmproot+neststart, "*.*");
{
wchar_t wroot[MAX_OSPATH];
r = FindFirstFileExW(widen(wroot, sizeof(wroot), tmproot), FindExInfoStandard, &fd, FindExSearchNameMatch, NULL, 0);
}
strcpy(tmproot+neststart, "");
if (r==(HANDLE)-1)
return 1;
go = true;
do
{
char utf8[MAX_OSPATH];
char file[MAX_OSPATH];
narrowen(utf8, sizeof(utf8), fd.cFileName);
if (*utf8 == '.')
; //don't ever find files with a name starting with '.' (includes .. and . directories, and unix hidden files)
else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory
{
if (wildcmp(submatch, utf8))
{
if (strlen(tmproot+matchstart) + strlen(utf8) + 2 < MAX_OSPATH)
{
Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, utf8);
go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), 0, parm, spath);
}
}
}
else
{
if (wildcmp(submatch, utf8))
{
if (strlen(tmproot+matchstart) + strlen(utf8) + 1 < MAX_OSPATH)
{
Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, utf8);
go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), 0, parm, spath);
}
}
}
} while(FindNextFileW(r, &fd) && go);
FindClose(r);
}
return go;
}
int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath)
{
char fullmatch[MAX_OSPATH];
int start;
if (strlen(gpath) + strlen(match) + 2 > MAX_OSPATH)
return 1;
strcpy(fullmatch, gpath);
start = strlen(fullmatch);
if (start && fullmatch[start-1] != '/')
fullmatch[start++] = '/';
fullmatch[start] = 0;
strcat(fullmatch, match);
return Sys_EnumerateFiles2(fullmatch, start, start, func, parm, spath);
}
#elif defined(linux) || defined(__unix__) || defined(__MACH__)
#include <dirent.h>
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
#include <errno.h>
static int Sys_EnumerateFiles2 (const char *truepath, int apathofs, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
{
DIR *dir;
char apath[MAX_OSPATH];
char file[MAX_OSPATH];
char truepath[MAX_OSPATH];
char *s;
const char *s;
struct dirent *ent;
struct stat st;
const char *wild;
const char *apath = truepath+apathofs;
//printf("path = %s\n", gpath);
//printf("match = %s\n", match);
if (!gpath)
gpath = "";
*apath = '\0';
Q_strncpyz(apath, match, sizeof(apath));
for (s = apath+strlen(apath)-1; s >= apath; s--)
//if there's a * in a system path, then we need to scan its parent directory to figure out what the * expands to.
//we can just recurse quicklyish to try to handle it.
wild = strchr(apath, '*');
if (!wild)
wild = strchr(apath, '?');
if (wild)
{
if (*s == '/')
char subdir[MAX_OSPATH];
for (s = wild+1; *s && *s != '/'; s++)
;
while (wild > truepath)
{
s[1] = '\0';
match += s - apath+1;
break;
if (*(wild-1) == '/')
break;
wild--;
}
memcpy(file, truepath, wild-truepath);
file[wild-truepath] = 0;
dir = opendir(file);
memcpy(subdir, wild, s-wild);
subdir[s-wild] = 0;
if (dir)
{
do
{
ent = readdir(dir);
if (!ent)
break;
if (*ent->d_name != '.')
{
#ifdef _DIRENT_HAVE_D_TYPE
if (ent->d_type != DT_DIR && ent->d_type != DT_UNKNOWN)
continue;
#endif
if (wildcmp(subdir, ent->d_name))
{
memcpy(file, truepath, wild-truepath);
Q_snprintfz(file+(wild-truepath), sizeof(file)-(wild-truepath), "%s%s", ent->d_name, s);
if (!Sys_EnumerateFiles2(file, apathofs, match, func, parm, spath))
{
closedir(dir);
return false;
}
}
}
} while(1);
closedir(dir);
}
return true;
}
if (s < apath) //didn't find a '/'
*apath = '\0';
Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath);
//printf("truepath = %s\n", truepath);
//printf("gamepath = %s\n", gpath);
//printf("apppath = %s\n", apath);
//printf("match = %s\n", match);
dir = opendir(truepath);
if (!dir)
{
Con_DPrintf("Failed to open dir %s\n", truepath);
Con_DLPrintf((errno==ENOENT)?2:1, "Failed to open dir %s\n", truepath);
return true;
}
do
@ -443,6 +539,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
if (!func(file, st.st_size, st.st_mtime, parm, spath))
{
// Con_DPrintf("giving up on search after finding %s\n", file);
closedir(dir);
return false;
}
@ -453,9 +550,35 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
}
} while(1);
closedir(dir);
return true;
}
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
{
char apath[MAX_OSPATH];
char truepath[MAX_OSPATH];
char *s;
if (!gpath)
gpath = "";
*apath = '\0';
Q_strncpyz(apath, match, sizeof(apath));
for (s = apath+strlen(apath)-1; s >= apath; s--)
{
if (*s == '/')
{
s[1] = '\0';
match += s - apath+1;
break;
}
}
if (s < apath) //didn't find a '/'
*apath = '\0';
Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath);
return Sys_EnumerateFiles2(truepath, strlen(gpath)+1, match, func, parm, spath);
}
#else
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, void *), void *parm, void *spath)
{

View File

@ -950,13 +950,76 @@ console_t *Con_TextEditor(const char *fname, const char *line, pubprogfuncs_t *d
file = FS_OpenVFS(fname, "rb", FS_GAME);
if (file)
{
char buffer[65536];
while (VFS_GETS(file, buffer, sizeof(buffer)))
unsigned char buffer[65536];
#ifdef HAVE_LEGACY
if (!strcmp(".bin", COM_GetFileExtension(fname, NULL)) && VFS_GETLEN(file) == 80*25*2)
{
Con_PrintCon(con, buffer, PFS_FORCEUTF8|PFS_KEEPMARKUP|PFS_NONOTIFY);
Con_PrintCon(con, "\n", PFS_FORCEUTF8|PFS_KEEPMARKUP|PFS_NONOTIFY);
static unsigned short ibmtounicode[256] =
{
0x0000,0x263A,0x263B,0x2665,0x2666,0x2663,0x2660,0x2022,0x25D8,0x25CB,0x25D9,0x2642,0x2640,0x266A,0x266B,0x263C, //0x00(non-ascii, display-only)
0x25BA,0x25C4,0x2195,0x203C,0x00B6,0x00A7,0x25AC,0x21A8,0x2191,0x2193,0x2192,0x2190,0x221F,0x2194,0x25B2,0x25BC, //0x10(non-ascii, display-only)
0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, //0x20(ascii)
0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, //0x30(ascii)
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F, //0x40(ascii)
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, //0x50(ascii)
0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, //0x60(ascii)
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x2302, //0x70(mostly ascii, one display-only)
0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7,0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5, //0x80(non-ascii, printable)
0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9,0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192, //0x90(non-ascii, printable)
0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA,0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB, //0xa0(non-ascii, printable)
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510, //0xb0(box-drawing, printable)
0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F,0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567, //0xc0(box-drawing, printable)
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B,0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580, //0xd0(box-drawing, printable)
0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4,0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229, //0xe0(maths(greek), printable)
0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248,0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0, //0xf0(maths, printable)
};
int c, l, len;
unsigned int u, code, oldcode;
char line[7*80+2];
char tohex[] = "0123456789ABCDEF";
VFS_READ(file, buffer, 80*25*2);
VFS_CLOSE(file);
for (l = 0; l < 25*(80*2); l+=80*2)
{
for(c = 0, len = 0, oldcode = ~0; c < 80; c++)
{
u = buffer[l+c*2];
code = buffer[l+c*2+1];
if (oldcode != code)
{
oldcode = code;
line[len++] = '^';
line[len++] = '&';
line[len++] = tohex[(code&0xf)>>0];
line[len++] = tohex[(code&0x70)>>4];
}
u = ibmtounicode[u]; //convert from dos's IBM437 codepage to unicode.
if (u == 0 || u == '\t' || u == '\n' || u == '\r')
line[len++] = ' ';
else if (u == '^')
{
line[len++] = '^';
line[len++] = '^';
}
else
len += utf8_encode(&line[len], u, 3);
}
line[len++] = '\n';
line[len] = 0;
Con_PrintCon(con, line, PFS_FORCEUTF8|PFS_NONOTIFY);
}
}
else
#endif
{
while (VFS_GETS(file, buffer, sizeof(buffer)))
{
Con_PrintCon(con, buffer, PFS_FORCEUTF8|PFS_KEEPMARKUP|PFS_NONOTIFY);
Con_PrintCon(con, "\n", PFS_FORCEUTF8|PFS_KEEPMARKUP|PFS_NONOTIFY);
}
VFS_CLOSE(file);
}
VFS_CLOSE(file);
}
}
for (l = con->oldest; l; l = l->newer)

View File

@ -5,13 +5,6 @@
#include "winquake.h"
#endif
typedef struct f_modified_s {
char name[MAX_QPATH];
qboolean ismodified;
struct f_modified_s *next;
} f_modified_t;
static f_modified_t *f_modified_list;
qboolean care_f_modified;
qboolean f_modified_particles;
@ -22,17 +15,19 @@ static void QDECL rulesetcallback(cvar_t *var, char *oldval)
cvar_t allow_f_version = CVAR("allow_f_version", "1");
cvar_t allow_f_server = CVAR("allow_f_server", "1");
cvar_t allow_f_modified = CVAR("allow_f_modified", "1");
cvar_t allow_f_skins = CVAR("allow_f_skins", "1");
cvar_t allow_f_ruleset = CVAR("allow_f_ruleset", "1");
cvar_t allow_f_scripts = CVAR("allow_f_scripts", "1");
#ifdef HAVE_LEGACY
cvar_t allow_f_modified = CVAR("allow_f_modified", "1");
cvar_t allow_f_fakeshaft = CVAR("allow_f_fakeshaft", "1");
cvar_t auth_validateclients = CVAR("auth_validateclients", "1");
#endif
cvar_t allow_f_system = CVAR("allow_f_system", "0");
cvar_t allow_f_cmdline = CVAR("allow_f_cmdline", "0");
cvar_t auth_validateclients = CVAR("auth_validateclients", "1");
cvar_t ruleset = CVARCD("ruleset", "none", rulesetcallback, "Known rulesets are:\nnone: no explicit rules, all 'minor cheats' are allowed.\nstrict: equivelent to the smackdown ruleset. Note that this will block certain graphical enhancements too.");
#ifdef HAVE_LEGACY
#define SECURITY_INIT_BAD_CHECKSUM 1
#define SECURITY_INIT_BAD_VERSION 2
#define SECURITY_INIT_ERROR 3
@ -62,6 +57,7 @@ static Security_Shutdown_t Security_Shutdown;
#if 0//def _WIN32
static void *secmodule;
#endif
#endif
static void Validation_Version(void)
{
@ -92,6 +88,7 @@ static void Validation_Version(void)
if (!allow_f_version.ival)
return; //suppress it
#ifdef HAVE_LEGACY
if (Security_Generate_Crc)
{
signed_buffer_t *resp;
@ -103,6 +100,7 @@ static void Validation_Version(void)
Q_snprintfz(auth, sizeof(authbuf), " crc: %s", resp->buf);
}
else
#endif
auth = "";
if (*sr)
@ -112,6 +110,7 @@ static void Validation_Version(void)
}
void Validation_CheckIfResponse(char *text)
{
#ifdef HAVE_LEGACY
//client name, version type(os-renderer where it matters, os/renderer where renderer doesn't), 12 char hex crc
int f_query_client;
int i;
@ -193,21 +192,25 @@ void Validation_CheckIfResponse(char *text)
else// if (!resp)
Con_Printf(CON_ERROR "AUTHENTICATION FAILED.\n");
}
#endif
}
void InitValidation(void)
{
Cvar_Register(&allow_f_version, "Authentication");
Cvar_Register(&allow_f_server, "Authentication");
#ifdef HAVE_LEGACY
Cvar_Register(&allow_f_modified, "Authentication");
Cvar_Register(&allow_f_fakeshaft, "Authentication");
#endif
Cvar_Register(&allow_f_skins, "Authentication");
Cvar_Register(&allow_f_ruleset, "Authentication");
Cvar_Register(&allow_f_fakeshaft, "Authentication");
Cvar_Register(&allow_f_scripts, "Authentication");
Cvar_Register(&allow_f_system, "Authentication");
Cvar_Register(&allow_f_cmdline, "Authentication");
Cvar_Register(&ruleset, "Authentication");
#ifdef HAVE_LEGACY
#if 0//def _WIN32
secmodule = LoadLibrary("fteqw-security.dll");
if (secmodule)
@ -251,30 +254,279 @@ void InitValidation(void)
Security_IsModelModified = NULL;
Security_Supported_Binaries = NULL;
Security_Shutdown = NULL;
#endif
}
//////////////////////
//f_modified
void Validation_IncludeFile(char *filename, char *file, int filelen)
#ifdef HAVE_LEGACY
#define FMOD_DM 1
#define FMOD_TF 2
static const struct {
const char *name;
unsigned int flags;
unsigned int hashes;
const char *hash;
} modifiles[] =
/*Note: I don't know what that 'debug' package refers to, these are just the hashes from ezquake.*/
{
}
{"progs/armor.mdl", FMOD_DM | FMOD_TF, 4, "\xef\xb8\xd1\x18\x73\xd9\x43\xfe\x13\x43\x10\xbb\x90\x90\x6a\xef\x96\x86\x04\x2b" //quake
"\xfc\x4f\x26\x8d\x7c\x1e\xbb\xfa\xbc\x28\x11\xc8\x32\x3d\x63\x21\x4f\x59\x0b\xfa" //debug
"\x2a\xc5\x72\x77\x13\x7c\xe3\xde\x23\x85\xbc\xbb\xba\x25\x85\x34\x49\xd6\x1b\x6e" //ruohis
"\xb2\xe7\x47\x56\x46\x57\x46\x52\xfa\x20\x03\xc1\x0c\xc9\x92\x1e\x72\x7c\x57\x27"},//plaguespack
{"progs/backpack.mdl", FMOD_DM | FMOD_TF, 2, "\xeb\xda\xce\x80\x82\xd2\xf7\x18\xc2\xe7\x11\xa9\xaa\x09\xe6\xff\x05\x60\x0a\x05" //quake
"\x82\xf3\xc1\xe7\x2e\xc2\x3d\x0c\xc0\x04\x1a\xd3\x52\xed\x51\x72\x23\xf2\xba\x45"},//debug
{"progs/bolt2.mdl", FMOD_DM | FMOD_TF, 1, "\xde\xa8\xfb\x14\xe4\x7a\x23\x99\x43\x60\x80\xc8\x54\xa4\xee\xeb\xa9\x99\x4a\x02"},//quake
{"progs/end1.mdl", FMOD_DM | FMOD_TF, 2, "\x9f\xd1\xfe\xd1\x32\xc6\x67\x5d\xe6\xa0\x72\x1d\xd7\x39\xab\x14\xc4\x35\xf4\x4b" //quake
"\x22\x93\xff\x51\x3d\xb8\x31\x8b\xbf\xbe\x88\x89\xe7\xdc\x17\x09\x04\x8e\x57\xd9"},//ruohis
{"progs/end2.mdl", FMOD_DM | FMOD_TF, 3, "\x20\xe6\xee\x98\x79\xcd\x7a\x10\x0d\x62\x31\x83\x48\x18\x9a\x2a\x1a\x9e\xd2\x64" //quake
"\x10\xb9\xa1\xe3\x6a\xe3\xc4\x28\x21\x93\xf6\x1a\x99\xdf\x19\x9d\xcb\xbf\xce\x5b" //unknown
"\x4b\x1e\xa7\x2e\x22\xcf\xf6\x0e\xa5\x3b\xd5\x86\x3d\x43\x45\x11\x54\x20\x71\xe6"},//ruohis
{"progs/end3.mdl", FMOD_DM | FMOD_TF, 3, "\x6d\x33\x1e\x7f\xb0\x4b\x4f\xe0\x1a\x5a\xc2\x4a\xe7\xdd\xae\x2c\x19\x33\x97\x09" //quake
"\x10\xb9\xa1\xe3\x6a\xe3\xc4\x28\x21\x93\xf6\x1a\x99\xdf\x19\x9d\xcb\xbf\xce\x5b" //unknown
"\xa0\xed\xc3\x04\x34\x25\x4f\x2b\xca\xbb\x7a\x12\xcf\x97\x5c\x75\x97\x65\x5b\x13"},//ruohis
{"progs/end4.mdl", FMOD_DM | FMOD_TF, 3, "\xaa\x72\xb5\xa4\x8d\xc3\x00\xdd\xa2\x8d\x0f\x13\x55\x0e\x7f\x79\x76\x2b\xa5\xcc" //quake
"\x10\xb9\xa1\xe3\x6a\xe3\xc4\x28\x21\x93\xf6\x1a\x99\xdf\x19\x9d\xcb\xbf\xce\x5b" //unkown
"\xc1\x54\x5a\x4d\xba\xaa\xa8\x1f\x2b\x5b\x0a\x60\x3f\xff\x08\x75\xde\x03\xaf\xc7"},//ruohis
{"progs/eyes.mdl", FMOD_DM | FMOD_TF, 1, "\xa8\x25\x6f\x27\x82\xf7\xb8\xc6\x52\x5d\xf7\x3e\x3e\x16\x1d\x91\x57\xe5\x79\x5d"},//quake
{"progs/g_light.mdl", FMOD_DM | FMOD_TF, 4, "\x66\x93\x9b\xcb\x91\x4d\xd7\x1f\xf6\x82\x6a\x9a\x3e\x2e\x6b\x5d\xac\xf5\x58\xc4" //quake
"\x78\xb4\x78\x9d\x49\xc8\x44\xfb\x9d\x6d\x6b\xc5\x39\x78\x73\xab\x48\xd8\xcf\x1f" //debug
"\x92\xb8\x31\x62\x16\xd6\x39\x1f\x5d\x71\x42\x14\x26\x28\xfc\xfb\xd6\xd8\x66\xc8" //plague
"\xb8\x50\x2d\xfe\xb4\x6e\xd5\x6a\xeb\xfc\x79\xe5\x6d\x6f\xe4\x43\xda\x16\xf6\x82"},//ruohis
{"progs/g_nail.mdl", FMOD_DM | FMOD_TF, 5, "\x71\x9f\x20\x7b\x0f\xd0\x7c\xa7\x53\x49\xf2\x91\x4b\x26\x2f\x93\x40\x74\x0e\x35" //quake
"\x5d\x9f\x61\xc6\x85\x1a\x51\x55\x63\xcc\xe0\x6d\x1a\x17\x61\xef\x73\xb1\xb1\x36" //debug
"\xc6\x31\x2e\xcb\xab\x64\x10\x1f\x81\xe6\x0b\x5e\x42\x86\x65\x5e\xf4\x1e\x41\xd9" //plague
"\x7e\xa3\x7d\xbe\x2b\x27\x31\xb5\x9a\xe8\x7d\x0c\xbd\x87\xf3\x26\xee\x31\xdc\x20" //ruohis
"\x64\x19\xdd\x86\x85\x6f\xe6\xeb\x4c\x5b\x7e\xf2\xda\xae\x30\x32\x60\x38\xc1\x10"},//pdp
{"progs/g_nail2.mdl", FMOD_DM | FMOD_TF, 4, "\x99\x44\xcb\x97\x1a\xe1\xe3\x88\xca\x6e\xec\xec\x8f\x6c\x3f\x88\x0c\xcf\x7e\xac" //quake
"\x69\x83\xd5\x9c\x27\x85\x4c\xe5\xb4\x34\xa2\xce\x3e\xd9\x2b\x47\x55\x86\xfa\x7d" //debug
"\x01\xe4\x3f\x7d\x44\x43\x8a\x73\x39\x24\xb6\x4a\xeb\x13\x73\xba\x36\x85\x6f\x6a" //plague
"\xca\x15\xdf\x38\x50\x43\xdb\xe2\x41\x58\x06\x5c\x8c\x54\xec\x67\xb2\xf0\xb3\x3d"},//ruohis
{"progs/g_rock.mdl", FMOD_DM | FMOD_TF, 5, "\x83\xdd\x17\x90\x4c\x95\x0d\x15\x44\x45\x5f\x9b\x72\x3b\x84\x10\x8e\x06\x97\x46" //quake
"\x53\x92\x4e\x33\x52\xa2\xa5\xa5\x56\xa8\xb9\x68\x47\x66\x22\x5e\xc7\xee\xba\xe4" //debug
"\xb0\xc7\x1f\xe3\x18\x06\x20\x35\x3c\x97\xa6\x8b\x55\xc5\x96\x12\xde\x1b\x54\xb2" //plague
"\x9a\xe2\xe3\xd2\xcf\x2a\x3a\x1e\x53\x1d\xf2\xa2\xdd\x2a\x45\x60\xfa\x2a\x73\xd8" //ruohis
"\xfe\x90\xe9\x10\xd2\x1e\x40\x3b\xad\x71\x9d\x9a\x59\xf0\x85\x90\x8f\x08\x10\x77"},//pdp
{"progs/g_rock2.mdl", FMOD_DM | FMOD_TF, 5, "\x20\xec\x47\x5a\xdc\x1c\x21\xd0\x60\xaf\xb8\xd6\xab\x3e\x81\xaf\x5b\x0b\x33\xba" //quake
"\xf9\x10\x4e\xe2\x41\xbc\x53\x0f\x2b\xee\x43\x60\xec\x7e\x57\x3d\x4c\x12\x75\xbc" //debug
"\xe9\xb3\x4e\x67\x27\x59\x32\xde\x37\x43\xbd\xda\x5c\x75\x7a\xc9\xf9\xf1\xf4\x97" //plagur
"\x58\x0c\x35\x54\x88\xfd\x09\x6a\x80\x4b\x21\xae\xde\x71\x1d\xc7\xe6\x0f\x9d\x10" //ruohis
"\xd9\x80\x42\x3c\x56\x3a\xa4\xd8\xeb\x31\xf9\xef\xaf\x10\x63\xb7\xad\x39\x8c\xb2"},//pdp
{"progs/g_shot.mdl", FMOD_DM | FMOD_TF, 5, "\xe1\x35\xa7\x35\x90\x60\xee\xc1\xb5\x40\x89\x9f\x1c\xfd\xde\x6c\x67\x1d\xec\x7e" //quake
"\x28\xa8\xbb\x7b\x98\x8f\x43\x99\x47\x37\x5e\x97\x2b\x8a\xbc\x6c\xb7\x4d\xa6\xd3" //debug
"\x58\x63\x48\xd3\x37\x3d\x3a\x4a\xe4\x43\xfc\x0e\x89\x2f\xa4\x55\x19\x85\x07\xf8" //plague
"\xd8\xaf\x4c\xc7\x02\xf9\x3a\xbc\x88\xb5\x52\xbb\x30\xca\x6f\x6f\x54\xb5\x2a\x5b" //ruohis
"\x5f\x01\x9f\x3a\x9e\xa2\x17\xd8\xfa\x87\x7a\xdc\x28\x16\xe3\xc6\x19\x11\x99\xaa"},//pdp
{"progs/gib1.mdl", FMOD_DM | FMOD_TF, 3, "\xa4\x9e\xdc\x99\x4a\xf7\x9b\x6e\x1e\x0a\x71\x25\x7b\xc7\x1f\x70\x92\x70\x77\x09" //quake
"\xfd\x06\xee\x69\x83\x84\xac\x8b\x3e\xa4\xc5\xf9\x22\x37\x51\xd7\xff\xa4\xd5\x55" //debug
"\xf8\x57\xff\x05\x96\xa0\x73\x10\x55\xd0\xe5\xc7\x0b\x04\x6c\x9c\x8a\xeb\xd2\x96"},//ruohis
{"progs/gib2.mdl", FMOD_DM | FMOD_TF, 3, "\x9b\xe2\xc3\x5a\xd9\x58\x63\xd6\x7a\xd2\x44\x10\xad\x48\xda\xb3\xbb\x9f\x1e\x5f" //quake
"\xdf\xa1\x51\x32\x08\x82\xe6\x50\x97\xf7\xf0\xef\x71\x4e\x89\x89\xe3\x5b\x50\x65" //debug
"\x87\xd6\x23\xdf\x47\x90\xea\x51\x97\x34\xdb\xbf\xdb\x63\x7b\xed\xfb\x1b\x1a\x13"},//ruohis
{"progs/gib3.mdl", FMOD_DM | FMOD_TF, 3, "\x61\x8e\x55\xc6\x63\x4f\xea\x13\x45\xda\xc9\x20\x2e\x21\x40\x06\x50\xf3\x98\x7b" //quake
"\x46\x0b\x8f\x79\x50\x72\x5c\xe5\xf5\xf3\x2f\x88\x80\x5a\x49\x75\x99\xed\xa3\x19" //debug
"\x1e\xf0\x5d\xff\x2f\x95\x06\x76\x84\xc7\x36\xdd\x33\x2d\xd7\xa0\x33\xfa\x6a\x06"},//ruohis
{"progs/grenade.mdl", FMOD_DM | FMOD_TF, 4, "\xb8\xff\xdf\x60\x0c\x1f\x87\xfc\x25\xc3\xf3\xd9\xaf\xdc\xaa\x61\xbf\x7c\xc3\x0e" //quake
"\x12\xdb\xf5\xda\x02\xfc\xd4\x41\x5a\xd3\x4d\x76\x88\x08\x49\xa4\xea\x6c\xd2\xd5" //debug
"\x10\xb9\xa1\xe3\x6a\xe3\xc4\x28\x21\x93\xf6\x1a\x99\xdf\x19\x9d\xcb\xbf\xce\x5b" //plague
"\x1e\x57\xe5\xec\xe8\x61\x5d\xa3\x49\xdf\xb6\xe2\xd9\x72\x53\xf3\x10\x89\xc7\x7a"},//ruohis
{"progs/invisibl.mdl", FMOD_DM | FMOD_TF, 3, "\x89\xf3\xe2\x23\x7f\x65\x79\x84\x25\x0d\x7e\x43\xae\x0b\x10\xee\x75\xa7\xd6\xba" //quake
"\x60\xae\xac\xe5\xfd\xe8\x2f\x8b\x78\x8e\xef\xb8\xe4\x6a\x23\x8d\xe3\x0b\xdb\xc3" //debug
"\x7e\x7e\x50\xb7\x19\x70\xdc\x84\x39\x1c\x5f\x8f\x79\x29\xdf\xc0\xdd\x93\x6b\xe8"},//ruohis
{"progs/invulner.mdl", FMOD_DM | FMOD_TF, 3, "\x75\xe1\x7e\x98\x35\x4f\x0d\xfd\x1c\x64\xd2\x06\xc8\x0d\x5c\x72\x7a\x53\x1f\x87" //quake
"\x3e\x0a\xb0\x57\x6d\xfa\x9a\x00\xcb\xc8\xc2\xa4\xcc\xec\xb0\xa7\x49\x70\xe5\xa9" //debug
"\x18\xa1\xcc\xdd\x41\x3d\x14\x9e\x57\xdc\xa8\xa2\xb7\x4e\x74\x82\x1b\x30\xaf\x09"},//ruohis
{"progs/missile.mdl", FMOD_DM | FMOD_TF, 4, "\xe8\xee\xdf\x9a\xc1\x72\x58\x18\xf8\x36\xbb\xb3\xab\x29\x6e\x99\xa9\xb2\x6a\xd4" //quake
"\x78\xa0\xe7\x2a\xd4\x93\x93\xc3\x88\x67\x57\x73\xd2\x99\x26\x24\xfd\x0b\x19\x8f" //debug
"\xec\xb3\x47\xe0\xe2\xd2\x03\xad\x07\x62\x14\x2a\xdf\xf2\xe1\x99\x42\x9f\x22\xfb" //plague
"\xca\x4a\x84\x7e\xf9\x7e\xb0\xb1\xd8\x94\x89\x3d\x4e\xd1\xb4\xe6\x58\x98\xc4\x56"},//ruohis
{"progs/quaddama.mdl", FMOD_DM | FMOD_TF, 3, "\x63\xf6\x60\x27\x05\x84\xdc\x32\xdf\x63\x75\x05\xa7\xc3\x14\x96\x9b\x94\x25\x01" //quake
"\x56\xa1\x10\x90\xdb\xad\x63\x1b\xe3\xd9\x9b\xbc\x4e\x6e\x8d\xff\x60\x12\xcd\xce" //debug
"\x6c\xcf\x93\xdb\xb8\xa0\x06\x70\x56\x8c\xb2\x90\xa7\xfb\x7a\xf9\xcb\x99\x36\x42"},//ruohis
{"progs/s_spike.mdl", FMOD_DM | FMOD_TF, 4, "\xe5\xf8\x08\xf3\xe2\x42\xc2\xcd\x1f\xb0\x71\x4f\x0a\x88\xb9\xaf\x9f\x8e\x19\x52" //quake
"\xcc\xe4\x59\xb1\xf0\xcc\x5d\xbc\xab\x93\x6e\x65\x24\xdd\x72\x3e\xc6\x6f\x44\x10" //debug
"\x11\x1b\xc6\xe7\x30\x7f\x3a\x70\xda\xa5\x51\x00\xd1\x5b\x4a\xb8\xac\x45\x36\xe2" //plague
"\xc5\x84\xbf\x40\x9c\x5a\xb8\xca\x24\xaa\x8b\x49\xc6\xd9\x07\xbe\x56\x67\x66\x6b"},//ruohis
{"progs/spike.mdl", FMOD_DM | FMOD_TF, 4, "\xaf\xad\xd9\xeb\x28\x2f\x3b\xfb\x34\x2c\xcc\x67\x1a\xc2\x6e\x92\x33\xa2\xe1\x09" //quake
"\x44\xb9\x8b\xe7\xe4\x53\xa7\x92\x6b\x22\x5c\x43\x5e\xa6\x21\x40\x6b\x8c\x38\xef" //debug
"\x95\xcb\xf1\x28\x91\xed\xb8\xaf\xff\x00\x83\x6a\x3f\xc0\x29\xeb\xcb\xbb\xa2\x28" //plague
"\x80\x59\x22\xd8\xf7\xe9\x99\x02\x66\xfd\x32\x67\x64\x52\x55\x54\x03\xa4\xbd\x67"},//ruohis
{"progs/suit.mdl", FMOD_DM | FMOD_TF, 2, "\xdd\xb9\xdc\xb7\x3b\xa0\x8d\xed\x5e\xfc\x6e\x41\x5a\x8d\xe3\x8e\x25\xbf\x63\x40" //quake
"\xf3\xe4\x4d\xbf\xc1\x27\x09\xe6\x00\x4f\x82\xf4\x56\xef\xfe\x21\x97\xa8\x00\xac"},//ruohis
{"progs/player.mdl", FMOD_DM, 2, "\xb4\x0a\xca\x95\x2e\xe6\x1b\x02\xa5\xe9\x55\x66\x1c\xef\xa7\xd4\x2f\x58\x84\xb4" //quake
"\x59\x34\x22\xc0\x8d\x7d\xb9\x42\x72\xf4\x2f\xc5\x10\x07\xee\xf3\x32\x11\xe2\x41"},//capnbubs
{"progs/player.mdl", FMOD_TF, 1, "\x58\xb6\xca\x8f\xef\x97\x7a\x02\x3d\xee\x6e\xa9\x46\x4f\xe4\xc1\xc9\x33\xa5\x18"},//tf
{"progs/tf_flag.mdl", FMOD_TF, 1, "\xf0\x9d\x96\x6e\xef\x9e\x1b\xc9\x40\x1a\xcb\x84\x2e\x12\xee\xca\x28\x3d\x1d\x1b"},//tf
{"progs/turrbase.mdl", FMOD_TF, 1, "\xd5\x73\xda\x0c\xcb\x03\x27\x82\x6b\xbe\x6c\x9e\xf7\x95\xfb\x94\xed\x4b\xc0\xc7"},//tf
{"progs/turrgun.mdl", FMOD_TF, 1, "\x6f\x12\x4b\x31\xb5\x7c\x8d\x7d\xc8\x85\xf1\x8d\xf7\x62\x36\x1f\x7b\x95\x72\xa2"},//tf
{"progs/disp.mdl", FMOD_TF, 1, "\x4a\xfa\x96\x55\x57\x24\x4e\xd9\xdf\x84\x0f\x14\xa8\xdd\x59\x58\xfc\x52\x67\xe9"},//tf
{"progs/tf_stan.mdl", FMOD_TF, 1, "\x1b\x2a\x73\x1b\xc2\x69\x30\x76\x70\xe2\x79\xe7\xaa\x9d\x2b\x25\x2a\xdb\xf7\xdd"},//tf
{"progs/hgren2.mdl", FMOD_TF, 1, "\x5f\x71\xc3\x1d\x0f\x3c\xc5\x58\xfc\x04\x15\xdb\xdf\x4b\x35\xab\x97\xee\xac\x6a"},//tf
{"progs/grenade2.mdl", FMOD_TF, 1, "\xef\x6c\x11\x4b\x74\xf0\xc6\xeb\x73\xea\xcd\x2a\x16\x87\x6a\x87\x9d\x40\xe7\xe5"},//tf
{"progs/detpack.mdl", FMOD_TF, 1, "\xe1\xd4\x73\xaf\x38\xdc\x98\x0c\xc0\x83\x39\x6d\x33\x00\xa7\xd7\x5e\x67\x6a\x61"},//tf
{"progs/s_bubble.spr", FMOD_DM | FMOD_TF, 1, "\xf2\xfa\xbe\x3d\x54\x86\xb3\x73\x74\x07\x91\x70\xf3\x85\xe2\xdf\x0e\xd9\xb5\x4d"},//quake
{"progs/s_explod.spr", FMOD_DM | FMOD_TF, 1, "\x06\x7b\x5a\x29\x88\x1f\xdf\xac\x94\x08\xa2\x50\x5f\x90\x75\x5c\x0b\x5d\xd9\xb9"},//quake
{"maps/b_bh100.bsp", FMOD_DM | FMOD_TF, 4, "\x02\xe3\xe7\x65\x4d\x5b\xa8\x94\x74\xe6\x92\x80\xf0\xe5\x00\xf7\xcc\x7f\x66\xde" //quake
"\xb6\xd5\x7f\x52\x7f\x70\x90\xd4\x22\x96\xd6\xab\x69\x8a\xd1\xf3\xb9\x0e\xbc\xe9" //ruohis1
"\xc1\x35\x21\xb4\x9c\x42\x16\x68\x3e\xce\xe3\x21\xfc\xf8\xb9\xfa\xe1\x7a\x38\x09" //ruohis2
"\xff\x55\xb4\xc6\x45\xb8\x7c\xad\x29\x67\x35\xa7\xcf\x5f\x37\x35\x79\xb4\xad\x10"},//generations
{"sound/buttons/airbut1.wav", FMOD_DM | FMOD_TF, 2, "\x1e\x14\xd5\x47\xeb\xe8\x25\xc9\x3c\x58\xe5\x26\x21\xd0\xdf\xc8\xef\x92\x67\x22" //quake
"\xe0\xbc\xfb\xd5\x31\xe4\x83\x20\x4d\xc5\x11\xaa\x53\xe0\x9c\x08\x11\xce\x03\xdf"},//mindgrind
{"sound/items/armor1.wav", FMOD_DM | FMOD_TF, 2, "\xb0\x8d\x48\x44\x1d\x0a\x0b\xef\xb4\xa8\xcd\x3a\x67\xb4\x87\x3d\xcc\x4f\xdd\xe4" //quake
"\xed\xda\x47\x1b\x6a\xcd\x60\x5a\x99\x04\x94\x83\x1b\x65\xeb\x65\xcf\xf6\x41\x44"},//mindgrind
{"sound/items/damage.wav", FMOD_DM | FMOD_TF, 2, "\xac\x78\x77\x19\xc5\x52\xa2\x92\x56\x02\xc3\x90\x64\xf2\xa6\x7b\x4f\x65\xab\x56" //quake
"\xa3\x87\xa0\x3d\xc7\xd4\x99\x17\x31\xbf\xda\x8d\x6f\xde\xe2\x42\xec\xab\xfd\x5b"},//mindgrind
{"sound/items/damage2.wav", FMOD_DM | FMOD_TF, 2, "\x4d\x9b\x9a\x71\x18\xb2\x76\x1c\x9f\x97\xbf\xfc\xfa\xe6\xa5\x5e\x0e\xda\xaf\x68" //quake
"\x9c\x77\xeb\xd0\x3c\xd8\xf1\x0b\x7e\x1c\x0e\x12\x9b\x44\xfa\x50\x5b\x65\xd4\x2c"},//mindgrind
{"sound/items/damage3.wav", FMOD_DM | FMOD_TF, 2, "\x6c\xde\x07\xfa\x39\x6d\x30\x6e\xed\xf3\x18\x7d\x58\x25\x27\x90\x7a\x1e\xd0\x63" //quake
"\x71\x3b\x0c\x2e\xc9\xcf\x52\xdd\xe5\xe1\x5f\x8e\xd9\x8f\xc4\x0a\x70\xb9\xd8\xa2"},//mindgrind
{"sound/items/health1.wav", FMOD_DM | FMOD_TF, 1, "\xb2\x17\xdd\xeb\x80\x9b\x28\xa1\xf2\xe3\x10\x78\xbf\x01\x8d\xdb\x96\x5a\x49\x0b"},//quake
{"sound/items/inv1.wav", FMOD_DM | FMOD_TF, 2, "\xb8\x40\x12\xa0\x30\xd4\x88\xb5\xe0\x06\x24\xc6\xfd\x9d\xe5\x39\x98\x4b\x5a\xad" //quake
"\xba\x08\x77\x78\x51\x2c\xf5\x63\x32\x59\x83\x55\x86\x6d\xb4\x7d\xcc\x30\xc8\xcc"},//mindgrind
{"sound/items/inv2.wav", FMOD_DM | FMOD_TF, 2, "\x5d\x02\xb6\x9a\xa2\x24\x9d\x2d\x7c\xb1\x27\xc1\x8a\x90\x9e\x01\xd3\xf7\x21\xa5" //quake
"\x8c\xbc\xa3\xb2\x5f\x6b\xb5\x7e\x67\x4d\x5e\x67\x40\x40\x05\x24\x0b\xcd\x2e\x3b"},//mindgrind
{"sound/items/inv3.wav", FMOD_DM | FMOD_TF, 2, "\x77\x57\x78\xfb\x26\x28\x62\x9c\x5c\xd0\x21\x61\x61\x56\x2d\xf4\x29\x54\x4a\xa3" //quake
"\x33\x54\x94\xa1\x52\x2c\x3e\x7f\x8a\x52\x44\x91\xf0\x1c\x89\x02\x55\xb2\x5e\xd9"},//mindgrind
{"sound/items/itembk2.wav", FMOD_DM | FMOD_TF, 2, "\x9b\x51\x8c\x17\x27\x05\x03\x3b\xd2\xae\x9a\x75\xd7\xa7\xdc\xf7\x36\x1e\x1a\xf0" //quake
"\xad\x6d\xdd\x41\x4b\xc2\xa8\x45\x5e\xb7\x56\xef\x5a\x91\xb3\x5a\x0f\xa7\x01\x29"},//mindgrind
{"sound/player/land.wav", FMOD_DM | FMOD_TF, 1, "\x41\x5e\xbb\xb8\x8e\xad\x87\xf0\xd5\x3c\x32\x13\x52\x20\x2d\x2e\x38\x9e\x8e\x33"},//quake
{"sound/player/land2.wav", FMOD_DM | FMOD_TF, 1, "\x5c\xb5\x13\x6c\x89\x15\x6c\xc4\x42\xac\xab\xee\x4e\xd2\x7c\x08\x86\x23\x55\xd9"},//quake
{"sound/misc/outwater.wav", FMOD_DM | FMOD_TF, 2, "\x36\xfc\xb6\x9c\xba\xe9\x20\x9c\x18\x84\x5f\x59\x9f\x6d\xe7\x50\xfd\x3d\x50\xa7" //quake
"\x15\x85\xe9\x6b\x26\x01\xab\xfe\x11\xc8\xed\x80\x12\x70\xcf\xe7\x80\x49\xef\x1d"},//mindgrind
{"sound/weapons/pkup.wav", FMOD_DM | FMOD_TF, 2, "\x23\x35\xa4\x05\x60\xab\xbb\x09\xa0\x67\xce\x77\x3d\xe2\x2f\xb5\x01\x57\x71\xf2" //quake
"\xbc\x1f\x26\xda\x68\x7c\xf4\x12\x94\xe7\x91\x9e\x4d\x43\x0a\xce\x77\x5e\xe3\xc4"},//mindgrind
{"sound/player/plyrjmp8.wav", FMOD_DM | FMOD_TF, 2, "\x46\xe9\xe2\x75\xf2\x54\xad\xc9\x03\x7b\xd4\x6c\xd4\xc9\xf0\xee\xda\x86\x33\x5d" //quake
"\x63\x82\x9e\x5a\x6e\xf0\xb3\xb9\xe1\x7d\x04\x8a\xec\x8b\xc1\x72\x77\xf9\x7d\x54"},//mindgrind
{"sound/items/protect.wav", FMOD_DM | FMOD_TF, 2, "\x51\x13\xff\x38\xc7\x99\x67\x7d\x6d\x25\x77\x75\x92\x31\x23\xbf\xaa\x3b\x22\xb6" //quake
"\x3f\x33\x48\x59\x2a\x88\x8e\xa2\x64\x29\xb8\xb4\xc5\x79\x06\xe1\xb1\x8c\x1f\x19"},//mindgrind
{"sound/items/protect2.wav", FMOD_DM | FMOD_TF, 2, "\x59\xd1\x8d\x58\x2c\x9f\x48\xae\x8e\x11\xf7\x22\x4c\xeb\x7e\x48\x97\xc9\x54\x3c" //quake
"\xb0\x77\xe9\x29\xfe\x78\x93\x0d\x37\x90\x48\xb4\x62\x3d\xd8\x02\x8d\x71\x0b\xce"},//mindgrind
{"sound/items/protect3.wav", FMOD_DM | FMOD_TF, 2, "\x43\x11\x9a\x86\x04\xa4\xe6\xc9\x0e\xd9\xd5\xcb\x4c\x7e\xb5\xa1\x20\xdd\x77\xae" //quake
"\x4c\x31\x19\x76\x1c\x90\xb6\x07\xe2\x01\x06\x00\x7e\x36\x58\xc3\xb1\x90\x9f\x99"},//mindgrind
{"sound/items/r_item1.wav", FMOD_DM | FMOD_TF, 2, "\x41\x29\xe1\xdd\x04\xb8\xb3\xfb\xfa\xf5\x6c\x77\xea\xf8\x1d\xe8\x63\x9f\x42\xa1" //quake
"\xd4\x54\x57\x0f\x5f\x4c\xb8\xa8\x3a\x90\x01\x00\x9c\x28\xab\xd3\x48\xc8\x3b\xa9"},//mindgrind
{"sound/items/r_item2.wav", FMOD_DM | FMOD_TF, 4, "\x47\x40\xda\xd9\x1a\x19\x7b\x5a\x0d\x86\x2d\xc0\xde\x79\xf6\x18\x3a\xd9\x7b\xc4" //quake
"\xd2\x00\x2a\xf6\xca\xaa\xce\x5f\x92\x16\xf9\x25\xb7\x2c\x60\xf7\x25\xa5\x0d\x23" //us
"\x46\xe6\xa8\x83\x13\xc3\x4c\xbc\x6e\xa9\x7a\xa0\xda\xea\x81\x9d\x10\xbd\x19\xf6" //ru
"\x39\xde\xd0\xd2\x33\x8d\xb7\x2b\x81\x30\xef\x09\xcf\xba\x90\xbe\xce\xec\x71\xbf"},//mindgrind
{"sound/misc/water1.wav", FMOD_DM | FMOD_TF, 2, "\xc7\xdb\x25\x86\xe6\x0a\xf3\xba\x65\x39\xb5\xfd\xd6\xb9\x7e\x2d\x04\x93\xfd\xf9" //quake
"\x18\x03\x8a\x83\x3e\xe5\x05\x08\x65\x40\xbf\x6e\xa0\xb9\x5f\xaa\x07\xd8\xca\xe1"},//mindgrind
{"sound/misc/water2.wav", FMOD_DM | FMOD_TF, 2, "\xec\x75\xda\xcc\x80\xd7\x5c\xfb\x5b\x3b\xd7\xe2\xad\x60\x35\x9f\x85\x6b\x11\x4e" //quake
"\x17\x6b\x0a\xfb\x33\xbc\x5f\x06\xc5\x7c\xab\x5f\xaa\x01\x0c\x11\x2e\x61\x8b\x27"},//mindgrind
{"sound/misc/menu1.wav", FMOD_DM | FMOD_TF, 2, "\x17\xb8\x19\x2e\x5f\x1c\x0e\x0c\xf8\xec\xa0\xd7\x7e\xc2\x78\xb2\x3c\x92\xe1\xb0" //quake
"\x73\x63\x3f\xf5\x3c\x61\x35\xd6\xd4\x41\x67\x9f\x05\xc2\x5c\x9d\x25\xc4\x15\x96"},//sean
{"sound/misc/menu2.wav", FMOD_DM | FMOD_TF, 2, "\xb1\x9a\x71\xd6\x2b\x7e\x40\x0a\x3b\x05\x3a\xb0\xcb\xc2\x4b\x2a\xf3\x7f\xcd\x61" //quake
"\xeb\x31\x56\xca\x89\x71\x57\x7b\x4e\xb1\xfd\x58\x90\x51\x56\xc4\xc4\x36\xc9\x6f"},//sean
{"sound/misc/menu3.wav", FMOD_DM | FMOD_TF, 2, "\x9a\x0b\x12\xae\x2e\x7d\x21\x3a\x90\x09\x4f\xc3\xed\x32\x43\x2d\x76\x8f\xc1\x97" //quake
"\xfe\xa5\x0c\xe6\x49\xf9\x0c\x30\x09\x5c\x2f\xb7\x70\x1c\x6d\x2b\x1f\xff\x2f\xd9"},//sean
{"sound/misc/talk.wav", FMOD_DM | FMOD_TF, 2, "\x1c\x32\x15\x5b\x26\xd8\xf2\x1a\x9f\x8e\x22\xb0\x56\x6f\xc0\x49\x8b\x5e\x35\xa8" //quake
"\x66\x60\x59\xab\x9d\xd4\xe1\xc7\xab\x9a\xdf\x00\x07\xfc\x14\xbd\xee\xae\xb2\x4a"},//sean
{"sound/misc/basekey.wav", FMOD_DM | FMOD_TF, 2, "\xce\x34\x61\x92\xd3\x6d\x80\x22\x4a\x62\x52\x19\xe9\xf7\x43\x8f\x64\xfe\xfd\xa6" //quake
"\xd4\x71\x98\xc9\xef\x0f\x0e\xc6\xf9\x4b\xe6\x14\x34\x39\xf4\xba\x18\xdf\x76\x53"},//gpl
{"sound/doors/runeuse.wav", FMOD_DM | FMOD_TF, 2, "\x59\x6d\x1d\xf4\xe8\x93\x9b\xe9\x25\xfd\xed\x15\x9c\x49\x8a\x66\x72\x25\xc6\x1a" //quake
"\x00\xb9\x76\xc5\xb3\x88\x89\x8f\x72\x0d\xa1\x85\xec\x42\x31\x4f\xba\xe3\x91\xac"},//sean
{"gfx/colormap.lmp", FMOD_DM | FMOD_TF, 1, "\x95\x37\x3b\xa9\x97\x63\x01\x17\x38\x1d\x76\x0a\x7d\xe6\x66\x48\x75\x2a\x2a\x3c"},//quake
{"gfx/palette.lmp", FMOD_DM | FMOD_TF, 1, "\x42\xe2\xa2\xa6\xda\xf7\xd0\xba\x1f\x35\x63\xe2\xad\xf8\x51\x6d\x4a\x5d\xa4\x49"},//quake
};
static enum {
FMOD_UNCHECKED,
FMOD_MODIFIED,
FMOD_UNMODIFIED,
} modifiles_status[countof(modifiles)];
static qboolean modified_neednotify;
static double modified_timestamp; //so we don't spam reanouncements
static void Validation_FilesModified (void)
{
Con_Printf ("f_modified not implemented\n");
}
size_t i;
unsigned int flagmatch = cl.teamfortress?FMOD_TF:FMOD_DM;
char buf[512];
qboolean evilhaxxor = false;
modified_timestamp = 0;
modified_neednotify = true;
Q_strncpyz(buf, "modified:", sizeof(buf));
for (i = 0; i < countof(modifiles); i++)
{
if ((modifiles[i].flags & flagmatch) && modifiles_status[i] == FMOD_MODIFIED)
{
evilhaxxor = true;
if (strlen(buf)>240)
{
modified_neednotify = false;//just spam at this point
Q_strncatz(buf, " & more...", sizeof(buf));
break;
}
else
{
Q_strncatz(buf, " ", sizeof(buf));
Q_strncatz(buf, COM_SkipPath(modifiles[i].name), sizeof(buf));
}
}
}
if (!evilhaxxor)
Q_strncpyz(buf, "all models okay", sizeof(buf));
CL_SendClientCommand(true, "say %s", buf);
}
static qboolean Validation_IsModified(void)
{
unsigned int flagmatch = cl.teamfortress?FMOD_TF:FMOD_DM;
size_t i;
for (i = 0; i < countof(modifiles); i++)
{
if ((modifiles[i].flags & flagmatch) && modifiles_status[i] == FMOD_MODIFIED)
return true;
}
modified_timestamp = 0;
modified_neednotify = true;
return false;
}
void Validation_WarnModified(void *ctx, void *data, size_t a, size_t b)
{
if (modified_neednotify)
{
if (modified_timestamp && modified_timestamp > realtime)
return;
CL_SendClientCommand(true, "say warning: stuff changed! Previous f_modified response is no longer valid.");
modified_timestamp = realtime+3.0; //mute further anouncements for a while.
}
}
#endif
void Validation_FileLoaded(const char *filename, const qbyte *filedata, size_t filesize)
{ //usually called on worker threads
#ifdef HAVE_LEGACY
qbyte digest[20];
size_t i, j;
unsigned int status;
for (i = 0; i < countof(modifiles); i++)
{
if (!strcmp(filename, modifiles[i].name) && (modifiles[i].flags & (cl.teamfortress?FMOD_TF:FMOD_DM)))
{
SHA1(digest, sizeof(digest), filedata, filesize);
for (j = 0; j < modifiles[i].hashes; j++)
{
if (!memcmp(digest, modifiles[i].hash+j*20, 20))
break;
}
status = (j==modifiles[i].hashes)?FMOD_MODIFIED:FMOD_UNMODIFIED;
if (status == FMOD_MODIFIED && modifiles_status[i] == FMOD_UNMODIFIED)
COM_AddWork(WG_MAIN, Validation_WarnModified, NULL, NULL, 0, 0); //make sure its the main thread that does the anouncing.
modifiles_status[i] = status;
return;
}
}
#endif
}
void Validation_FlushFileList(void)
{
f_modified_t *fm;
while(f_modified_list)
{
fm = f_modified_list->next;
Z_Free(f_modified_list);
f_modified_list = fm;
}
#ifdef HAVE_LEGACY
//just wipe the lot, resetting it back to 'unchecked'
memset(modifiles_status, 0, sizeof(modifiles_status));
modified_neednotify = false;
modified_timestamp = 0;
#endif
}
/////////////////////////
@ -327,6 +579,7 @@ static void Validation_Scripts(void)
Cbuf_AddText("say scripts are capped\n", RESTRICT_LOCAL);
}
#ifdef HAVE_LEGACY
static void Validation_FakeShaft(void)
{
extern cvar_t cl_truelightning;
@ -339,6 +592,7 @@ static void Validation_FakeShaft(void)
else
Cbuf_AddText("say fakeshaft off\n", RESTRICT_LOCAL);
}
#endif
static void Validation_System(void)
{ //subset of ruleset
@ -513,11 +767,16 @@ static void Validation_OldRuleset(void)
static void Validation_AllChecks(void)
{
extern cvar_t cl_iDrive;
char servername[22];
char playername[16];
char *enginebuild = version_string();
char *rawenginebuild = version_string();
char enginebuild[64];
char localpnamelen = strlen(cl.players[cl.playerview[0].playernum].name);
char ruleset[1024];
char extras[2][8];
size_t i, j;
qboolean hadspace;
//figure out the padding for the player's name.
if (localpnamelen >= 15)
@ -529,15 +788,48 @@ static void Validation_AllChecks(void)
playername[15-localpnamelen] = 0;
}
for (i = 0, j = 0, hadspace=false; rawenginebuild[i]&& j+1<countof(enginebuild); i++)
{
if (rawenginebuild[i] == ' ')
{
if (!strncmp(rawenginebuild+i, " SVN ", 5))
{
i+=5-1;
continue;
}
if (hadspace && !(isdigit(rawenginebuild[i-1])&&isdigit(rawenginebuild[i+1])))
continue;
hadspace=true;
enginebuild[j++] = '_';
}
else
enginebuild[j++] = rawenginebuild[i];
}
enginebuild[j++] = 0;
//get the current server address
NET_AdrToString(servername, sizeof(servername), &cls.netchan.remote_address);
//get the ruleset names
if (!Validation_GetCurrentRulesetName(ruleset, sizeof(ruleset), true))
Q_strncpyz(ruleset, "no ruleset", sizeof(ruleset));
Q_strncpyz(ruleset, "default", sizeof(ruleset));
extras[0][0] = '-'; //extra restrictions.
extras[1][0] = '+'; //extra cheats.
extras[0][1] = extras[1][1] = 0;
#ifdef HAVE_LEGACY
Q_strncatz(extras[Validation_IsModified()], "m", sizeof(extras[0]));
#endif
Q_strncatz(extras[1/*!!allow_scripts.ival*/], "s", sizeof(extras[0])); //we can't track whether a +foo was from a bind or an alias invoked from a bind, so we have to list it under the +, for now.
Q_strncatz(extras[0/*!!enemyforceskins.ival*/], "f", sizeof(extras[0])); //we don't support per-player skin forcing, so this should always be under the -.
Q_strncatz(extras[!!cl_iDrive.ival], "i", sizeof(extras[0]));
if (!extras[0][1])
*extras[0] = 0;
if (!extras[1][1])
*extras[1] = 0;
//now send it
CL_SendClientCommand(true, "say \"%s%21s " "%16s %s\"", playername, servername, enginebuild, ruleset);
CL_SendClientCommand(true, "say \"%s%21s " "%16s %s%s%s\"", playername, servername, enginebuild, ruleset, extras[1], extras[0]);
}
@ -607,12 +899,14 @@ void Validation_Apply_Ruleset(void)
void Validation_Auto_Response(int playernum, char *s)
{
static float versionresponsetime;
#ifdef HAVE_LEGACY
static float modifiedresponsetime;
static float fakeshaftresponsetime;
#endif
static float skinsresponsetime;
static float serverresponsetime;
static float rulesetresponsetime;
static float systemresponsetime;
static float fakeshaftresponsetime;
static float cmdlineresponsetime;
static float scriptsresponsetime;
@ -647,6 +941,7 @@ void Validation_Auto_Response(int playernum, char *s)
Validation_CmdLine();
cmdlineresponsetime = Sys_DoubleTime() + 5;
}
#ifdef HAVE_LEGACY
else if (!strncmp(s, "fakeshaft", 9) && fakeshaftresponsetime < Sys_DoubleTime())
{
Validation_FakeShaft();
@ -657,6 +952,7 @@ void Validation_Auto_Response(int playernum, char *s)
Validation_FilesModified();
modifiedresponsetime = Sys_DoubleTime() + 5;
}
#endif
else if (!strncmp(s, "scripts", 7) && scriptsresponsetime < Sys_DoubleTime())
{
Validation_Scripts();

View File

@ -51,8 +51,8 @@ typedef struct {
int wait; //-1 = default, 0 = off, 1 = on, 2 = every other
int multisample; //for opengl antialiasing (which requires context stuff)
int triplebuffer;
char subrenderer[MAX_QPATH];
char devicename[MAX_QPATH];
char subrenderer[MAX_QPATH]; //external driver
char devicename[MAX_QPATH]; //device name (usually monitor)
struct rendererinfo_s *renderer;
} rendererstate_t;
#ifndef SERVERONLY
@ -113,6 +113,9 @@ typedef struct
size_t ime_caret;
float ime_position[2]; //where to display any ime popups (virtual coords)
qboolean ime_allow; //enable the ime (ie: at the console or messagemode)
qboolean forcecursor;
float forcecursorpos[2]; //in physical pixels
} viddef_t;
extern viddef_t vid; // global video state

View File

@ -103,8 +103,36 @@ cvar_t crosshaircorrect = CVARFD("crosshaircorrect", "0", CVAR_SEMICHEAT, "Move
cvar_t crosshairimage = CVARD("crosshairimage", "", "Enables the use of an external/custom crosshair image");
cvar_t crosshairalpha = CVAR("crosshairalpha", "1");
cvar_t v_skyroom_origin = CVARD("r_skyroom_origin", "", "Specifies the center position of the skyroom's view. Skyrooms are drawn instead of skyboxes (typically with their own skybox around them). Entities in skyrooms will be drawn only when r_ignoreentpvs is 0. Can also be set with the _skyroom worldspawn key. This is overriden by csqc's VF_SKYROOM_CAMERA.");
cvar_t v_skyroom_orientation = CVARD("r_skyroom_orientation", "", "Specifies the orientation and spin of the skyroom.");
static qboolean v_skyroom_set;
static vec4_t v_skyroom_origin;
static vec4_t v_skyroom_orientation;
static void QDECL V_Skyroom_Changed(struct cvar_s *var, char *oldvalue)
{
char tok[64];
char *line = var->string;
if (*line)
v_skyroom_set = true;
else
v_skyroom_set = false;
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_origin[0] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_origin[1] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_origin[2] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_origin[3] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_orientation[3] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_orientation[0] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_orientation[1] = atof(tok);
line = COM_ParseTokenOut(line, NULL, tok, sizeof(tok), NULL);
v_skyroom_orientation[2] = atof(tok);
}
cvar_t v_skyroom = CVARFCD("skyroom", "", CVAR_SEMICHEAT, V_Skyroom_Changed, "Specifies the center position of the skyroom's view. Skyrooms are drawn instead of skyboxes (typically with their own skybox around them). Entities in skyrooms will be drawn only when r_ignoreentpvs is 0. Can also be set with the _skyroom worldspawn key. This is overriden by csqc's VF_SKYROOM_CAMERA.");
static cvar_t gl_cshiftpercent = CVAR("gl_cshiftpercent", "100");
cvar_t gl_cshiftenabled = CVARFD("gl_polyblend", "1", CVAR_ARCHIVE, "Controls whether temporary whole-screen colour changes should be honoured or not. Change gl_cshiftpercent if you want to adjust the intensity.\nThis does not affect v_cshift commands sent from the server.");
@ -349,7 +377,7 @@ static cshift_t cshift_lava = { {255,80,0}, 150 };
//static cshift_t cshift_server = { {130,80,50}, 0 };
cvar_t v_gamma = CVARFCD("gamma", "1.0", CVAR_ARCHIVE|CVAR_RENDERERCALLBACK, V_Gamma_Callback, "Controls how bright the screen is. Setting this to anything but 1 without hardware gamma requires glsl support and can noticably harm your framerate.");
cvar_t v_gamma = CVARAFCD("gamma", "1.0", "v_gamma", CVAR_ARCHIVE|CVAR_RENDERERCALLBACK, V_Gamma_Callback, "Controls how bright the screen is. Setting this to anything but 1 without hardware gamma requires glsl support and can noticably harm your framerate.");
cvar_t v_gammainverted = CVARFCD("v_gammainverted", "0", CVAR_ARCHIVE, V_Gamma_Callback, "Boolean that controls whether the gamma should be inverted (like quake) or not.");
cvar_t v_contrast = CVARAFCD("contrast", "1.0", "v_contrast", CVAR_ARCHIVE, V_Gamma_Callback, "Scales colour values linearly to make your screen easier to see. Setting this to anything but 1 without hardware gamma will reduce your framerates a little.");
cvar_t v_contrastboost = CVARFCD("v_contrastboost", "1.0", CVAR_ARCHIVE, V_Gamma_Callback, "Amplifies contrast in dark areas");
@ -1619,12 +1647,12 @@ void V_CalcRefdef (playerview_t *pv)
VectorMA(r_refdef.vieworg, v_gunkick.value, pv->punchorigin, r_refdef.vieworg);
}
if (*v_skyroom_origin.string)
if (v_skyroom_set)
{
r_refdef.skyroom_enabled = true;
r_refdef.skyroom_pos[0] = v_skyroom_origin.vec4[0];
r_refdef.skyroom_pos[1] = v_skyroom_origin.vec4[1];
r_refdef.skyroom_pos[2] = v_skyroom_origin.vec4[2];
VectorMA(v_skyroom_origin, v_skyroom_origin[3], r_refdef.vieworg, r_refdef.skyroom_pos);
Vector4Copy(v_skyroom_orientation, r_refdef.skyroom_spin);
r_refdef.skyroom_spin[3] *= cl.time;
}
if (chase_active.ival && cls.allow_cheats) //cheat restriction might be lifted some time when any wallhacks are solved.
@ -2577,14 +2605,14 @@ void V_Init (void)
Cvar_Register (&cl_bobmodel_side, VIEWVARS);
Cvar_Register (&cl_bobmodel_up, VIEWVARS);
Cvar_Register (&cl_bobmodel_speed, VIEWVARS);
Cvar_Register (&v_viewmodel_quake, VIEWVARS);
Cvar_Register (&v_kicktime, VIEWVARS);
Cvar_Register (&v_kickroll, VIEWVARS);
Cvar_Register (&v_kickpitch, VIEWVARS);
Cvar_Register (&v_deathtilt, VIEWVARS);
Cvar_Register (&v_skyroom_origin, VIEWVARS);
Cvar_Register (&v_skyroom_orientation, VIEWVARS);
Cvar_Register (&v_skyroom, VIEWVARS);
Cvar_Register (&scr_autoid, VIEWVARS);
Cvar_Register (&scr_autoid_team, VIEWVARS);

View File

@ -895,8 +895,8 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
}
else if (!strcmp("skyroom", key)) // for Quake mappers that lack the proper tools
{
extern cvar_t v_skyroom_origin;
Cvar_LockFromServer(&v_skyroom_origin, token);
extern cvar_t v_skyroom;
Cvar_LockFromServer(&v_skyroom, token);
}
else if (!strcmp("skyname", key)) // for HalfLife maps
{

View File

@ -71,6 +71,8 @@ qboolean suppress;
static void QDECL TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue);
static void QDECL TP_TeamColor_CB (struct cvar_s *var, char *oldvalue);
static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
//cvar_t enemyforceskins = CVARD("enemyforceskins", "0", "0: Read the skin as-is.\n1: Use the player's name instead of their skin setting.\n2: Use their userid (probably too unreliable).3: Use a per-team player index.\n");
//cvar_t teamforceskins = CVARD("enemyforceskins", "0", "0: Read the skin as-is.\n1: Use the player's name instead of their skin setting.\n2: Use their userid (probably too unreliable).3: Use a per-team player index.\n");
#define TP_SKIN_CVARS \
TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \

View File

@ -177,7 +177,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define FULLENGINENAME "FTE Quake" //the posh name for the engine
#endif
#ifndef ENGINEWEBSITE
#define ENGINEWEBSITE "^8http://^4fte.triptohell.info" //url for program
#define ENGINEWEBSITE "^8http://^4fte^8.^4triptohell^8.^4info" //url for program
#endif
#if !defined(_WIN32) || defined(WINRT)

View File

@ -666,54 +666,57 @@ static void Cmd_Exec_f (void)
{
f = Cmd_Argv(1);
if (!*f)
f = "fte";
f = fs_manifest->mainconfig;
if (!*f)
f = "config";
snprintf(name, sizeof(name)-5, "configs/%s", f);
COM_DefaultExtension(name, ".cfg", sizeof(name));
}
else
{
Q_strncpyz(name, Cmd_Argv(1), sizeof(name));
#ifndef QUAKETC
//fte writes to a different config file from that specified by the quake.rc, to avoid conflicts.
//so make sure that fte's settings override those from whatever other engine that wrote the legacy config.cfg file.
if (!strcmp(name, "config.cfg") || !strcmp(name, "q3config.cfg"))
if (*fs_manifest->mainconfig && Q_strcasecmp("config.cfg", fs_manifest->mainconfig) && Q_strcasecmp("q3config.cfg", fs_manifest->mainconfig))
{
int cfgdepth = COM_FDepthFile(name, true);
int defdepth = COM_FDepthFile("default.cfg", true);
Cbuf_InsertText("exec fte.cfg", Cmd_ExecLevel, true);
if (defdepth < cfgdepth && cfgdepth != FDEPTH_MISSING)
//fte writes to a different config file from that specified by the quake.rc, to avoid conflicts.
//so make sure that fte's settings override those from whatever other engine that wrote the legacy config.cfg file.
if (!strcmp(name, "config.cfg") || !strcmp(name, "q3config.cfg"))
{
if (cl_warncmd.ival)
int cfgdepth = COM_FDepthFile(name, true);
int defdepth = COM_FDepthFile("default.cfg", true);
Cbuf_InsertText(va("exec %s", fs_manifest->mainconfig), Cmd_ExecLevel, true);
if (defdepth < cfgdepth && cfgdepth != FDEPTH_MISSING)
{
char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
if (cl_warncmd.ival)
{
char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
}
return;
}
}
else if (!strcmp(name, fs_manifest->mainconfig))
{
int cfgdepth = COM_FDepthFile(name, true);
int defdepth = COM_FDepthFile("default.cfg", true);
if (defdepth < cfgdepth && cfgdepth != FDEPTH_MISSING)
{
if (cl_warncmd.ival)
{
char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
}
return;
}
return;
}
}
else if (!strcmp(name, "fte.cfg"))
{
int cfgdepth = COM_FDepthFile(name, true);
int defdepth = COM_FDepthFile("default.cfg", true);
if (defdepth < cfgdepth && cfgdepth != FDEPTH_MISSING)
{
if (cl_warncmd.ival)
{
char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
}
return;
}
}
#endif
}
if (!strncmp(name, "../", 3) || !strncmp(name, "..\\", 3) || !strncmp(name, "./", 2) || !strncmp(name, ".\\", 2))
@ -760,7 +763,7 @@ static void Cmd_Exec_f (void)
s+=3;
}
if (!strcmp(name, "config.cfg") || !strcmp(name, "q3config.cfg") || !strcmp(name, "fte.cfg"))
if (!strcmp(name, "config.cfg") || !strcmp(name, "q3config.cfg") || !strcmp(name, fs_manifest->mainconfig))
{
//if the config is from id1 and the default.cfg was from some mod, make sure the default.cfg overrides the config.
//we won't just exec the default instead, because we can at least retain things which are not specified (ie: a few binds)
@ -1352,6 +1355,7 @@ void Alias_WipeStuffedAliases(void)
void Cvar_List_f (void);
void Cvar_Reset_f (void);
void Cvar_ResetAll_f(void);
void Cvar_LockDefaults_f(void);
void Cvar_PurgeDefaults_f(void);
@ -2694,7 +2698,7 @@ static void Cmd_ExecuteStringGlobalsAreEvil (const char *text, int level)
if (dpcompat_console.ival && !strncmp(text, "alias", 5) && (text[5] == ' ' || text[5] == '\t'))
; //certain commands don't get pre-expanded in dp. evil hack. quote them to pre-expand anyway. double evil.
else
text = Cmd_ExpandString(text, dest, sizeof(dest), &level, !Cmd_IsInsecure()?true:false, true);
text = Cmd_ExpandString(text, dest, sizeof(dest), &level, true/*!Cmd_IsInsecure()?true:false*/, true);
Cmd_TokenizeString (text, (level == RESTRICT_LOCAL&&!dpcompat_console.ival)?true:false, false);
// execute the command line
@ -3950,20 +3954,10 @@ static void Cmd_WriteConfig_f(void)
char sysname[MAX_OSPATH];
qboolean all = true;
if (Cmd_IsInsecure() && Cmd_Argc() > 1)
{
Con_Printf ("%s not allowed\n", Cmd_Argv(0));
return;
}
filename = Cmd_Argv(1);
if (!*filename)
{
#ifdef QUAKETC
snprintf(fname, sizeof(fname), "config.cfg");
#else
snprintf(fname, sizeof(fname), "fte.cfg");
#endif
Q_strncpyz(fname, fs_manifest->mainconfig, sizeof(fname));
#if defined(CL_MASTER) && defined(HAVE_CLIENT)
MasterInfo_WriteServers();
@ -3973,8 +3967,32 @@ static void Cmd_WriteConfig_f(void)
all = cfg_save_all.ival;
}
else if (!Q_strcasecmp(Cmd_Argv(0), "saveconfig"))
{
//dpcompat: this variation allows writing to any path. at least force the extension.
snprintf(fname, sizeof(fname), "%s", filename);
COM_RequireExtension(fname, ".cfg", sizeof(fname));
if (Cmd_IsInsecure() && strncmp(fname, "data/", 5))
{
Con_Printf ("%s %s: not allowed\n", Cmd_Argv(0), Cmd_Args());
return;
}
FS_NativePath(fname, FS_BASEGAMEONLY, sysname, sizeof(sysname));
FS_CreatePath(fname, FS_BASEGAMEONLY);
f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY);
all = cfg_save_all.ival;// || !*cfg_save_all.string;
}
else
{
if (Cmd_IsInsecure())
{
Con_Printf ("%s %s: not allowed\n", Cmd_Argv(0), Cmd_Args());
return;
}
if (strstr(filename, ".."))
{
Con_Printf (CON_ERROR "Couldn't write config %s\n",filename);
@ -4212,6 +4230,7 @@ void Cmd_Init (void)
// register our commands
//
Cmd_AddCommandAD ("cfg_save",Cmd_WriteConfig_f, Cmd_Exec_c, NULL);
Cmd_AddCommandAD ("saveconfig",Cmd_WriteConfig_f, Cmd_Exec_c, NULL); //for dpcompat
Cmd_AddCommandAD ("cfg_load",Cmd_Exec_f, Cmd_Exec_c, NULL);
Cmd_AddCommand ("cfg_reset",Cmd_Reset_f);
@ -4256,6 +4275,9 @@ void Cmd_Init (void)
Cmd_AddCommandD ("cvarwatch", Cvar_Watch_f, "Prints a notification when the named cvar is changed. Also displays the start/end of configs. Alternatively, use '-watch foo' on the commandline.");
Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f);
Cmd_AddCommandD ("cvar_purgedefaults", Cvar_PurgeDefaults_f, "Resets all cvar defaults to back to the engine's default. Does not change their active value.");
Cmd_AddCommandD ("cvar_resettodefaults_nosaveonly", Cvar_ResetAll_f, "Resets all unsaved cvars to the mod's default value.");
Cmd_AddCommandD ("cvar_resettodefaults_saveonly", Cvar_ResetAll_f, "Resets all saved cvars to the mod's default value (without changing unsaved cvars).");
Cmd_AddCommandD ("cvar_resettodefaults_all", Cvar_ResetAll_f, "Resets all cvars to the mod's default value.");
Cmd_AddCommandD ("apropos", Cmd_Apropos_f, "Lists all cvars or commands with the specified substring somewhere in their name or descrition.");
Cmd_AddCommandD ("find", Cmd_Apropos_f, "Lists all cvars or commands with the specified substring somewhere in their name or descrition.");

View File

@ -22,6 +22,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//===========================================================================
/*FIXME: rewrite this to use something like the following
typedef struct
{
qbyte level:8;
qbyte seat:4; //for splitscreen binds etc
qbyte pad:2;
qbyte insecure:1; //from gamecode, untrusted configs, stuffed binds, etc. flagged for many reasons.
qbyte cvarlatch:1; //latches cvars so the user cannot change them till next map. should be RESTRICT_LOCAL to avoid users cheating by restrict-to-block server commands.
} cmdpermissions_t;
typedef struct
{
cbuf_t *cbuf; //exec etc inserts into this
cmdpermissions_t p; //access rights
} cmdstate_t;
void Cbuf_AddText(const char *text, qboolean addnl, qboolean insert, const cmdstate_t *cstate); //null for local?
char *Cbuf_GetNext(cmdpermissions_t permissions, qboolean ignoresemicolon);
void Cbuf_Execute(cbuf_t *cbuf);
void Cmd_ExecuteString (const char *text, const cmdstate_t *cstate);
//rcon can use a private cbuf, allowing it to parse properly despite level changes
//cbuf must internally track cmdpermissions_t of different blocks. inserstions/additions may merge, others force \n termination (network can do its own buffering).
typedef void (*xcommand_t) (const cmdstate_t *cstate);
*/
/*
Any number of commands can be added in a frame, from several different sources.
@ -168,11 +193,11 @@ void Cmd_Args_Set(const char *newargs, size_t len);
#define RESTRICT_MAX RESTRICT_MAX_USER
#define RESTRICT_LOCAL RESTRICT_MAX
#define RESTRICT_INSECURE RESTRICT_MAX+1
#define RESTRICT_SERVER RESTRICT_MAX+2
#define RESTRICT_LOCAL RESTRICT_MAX //commands typed at the console
#define RESTRICT_INSECURE RESTRICT_MAX+1 //commands from csqc or untrusted sources (really should be a separate flag, requires cbuf rewrite)
#define RESTRICT_SERVER RESTRICT_MAX+2 //commands from ssqc (untrusted, but allowed to lock cvars)
#define RESTRICT_RCON rcon_level.ival
#define RESTRICT_PROGS RESTRICT_MAX-2
//#define RESTRICT_SSQC RESTRICT_MAX-2
#define Cmd_FromGamecode() (Cmd_ExecLevel>=RESTRICT_SERVER) //cheat provention. block cheats if its not fromgamecode
#define Cmd_IsInsecure() (Cmd_ExecLevel>=RESTRICT_INSECURE) //prevention from the server from breaking/crashing/wiping us. if this returns true, block file access etc.

View File

@ -34,6 +34,7 @@ cvar_t r_meshpitch = CVARCD ("r_meshpitch", "1", r_meshpitch_callback, "Sp
#else
cvar_t r_meshpitch = CVARCD ("r_meshpitch", "-1", r_meshpitch_callback, "Specifies the direction of the pitch angle on mesh models formats, Quake compatibility requires -1.");
#endif
cvar_t dpcompat_skinfiles = CVARD ("dpcompat_skinfiles", "0", "When set, uses a nodraw shader for any unmentioned surfaces.");
#ifdef HAVE_CLIENT
static void Mod_UpdateCRC(void *ctx, void *data, size_t a, size_t b)
@ -71,6 +72,7 @@ void Mod_DoCRC(model_t *mod, char *buffer, int buffersize)
mod->tainted = (crc != 6967);
}
}
Validation_FileLoaded(mod->publicname, buffer, buffersize);
#endif
}
@ -3170,7 +3172,7 @@ void Mod_LoadAliasShaders(model_t *mod)
{
if (!f->defaultshader)
{
if (ai->csurface.flags & 0x80) //nodraw
if ((ai->csurface.flags & 0x80) || dpcompat_skinfiles.ival) //nodraw
f->shader = R_RegisterShader(f->shadername, SUF_NONE, "{\nsurfaceparm nodraw\nsurfaceparm nodlight\nsurfaceparm nomarks\nsurfaceparm noshadows\n}\n");
else
f->shader = R_RegisterSkin(f->shadername, mod->name);
@ -7207,7 +7209,7 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
mesh = (dpmmesh_t*)((char*)buffer + header->ofs_meshs);
for (i = 0; i < header->num_meshs; i++, mesh++)
{
m = &root[i];
m = &root[i];
Mod_DefaultMesh(m, mesh->shadername, i);
if (i < header->num_meshs-1)
m->nextsurf = &root[i+1];
@ -9529,4 +9531,8 @@ void Alias_Register(void)
#ifdef MODELFMT_OBJ
Mod_RegisterModelFormatText(NULL, "Wavefront Object (obj)", ".obj", Mod_LoadObjModel);
#endif
#ifndef SERVERONLY
Cvar_Register(&dpcompat_skinfiles, NULL);
#endif
}

View File

@ -104,7 +104,7 @@ cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "A
cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.");
cvar_t sys_platform = CVAR("sys_platform", PLATFORM);
cvar_t pkg_downloads_url = CVARFD("pkg_downloads_url", NULL, CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "The URL of a package updates list."); //read from the default.fmf
cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only.
cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "-1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only.
#ifdef HAVE_LEGACY
cvar_t pm_noround = CVARD("pm_noround", "0", "Disables player prediction snapping, in a way that cannot be reliably predicted but may be needed to avoid map bugs.");
#endif
@ -4785,11 +4785,15 @@ static void COM_Version_f (void)
Con_Printf("^4"ENGINEWEBSITE"\n");
Con_Printf("%s\n", version_string());
#if defined(SVNREVISION) && defined(SVNDATE)
Con_Printf("SVN Revision: %s - %s\n",STRINGIFY(SVNREVISION), STRINGIFY(SVNDATE));
#else
Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__);
#ifdef SVNREVISION
if (strcmp(STRINGIFY(SVNREVISION), "-"))
Con_Printf("SVN Revision: %s\n",STRINGIFY(SVNREVISION));
#endif
#endif
#ifdef CONFIG_FILE_NAME
Con_Printf("Build config: %s\n\n", COM_SkipPath(STRINGIFY(CONFIG_FILE_NAME)));
#endif
@ -7503,12 +7507,14 @@ char *version_string(void)
{
#ifdef OFFICIAL_RELEASE
Q_snprintfz(s, sizeof(s), "%s v%i.%02i", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR);
#elif defined(SVNREVISION) && defined(SVNDATE)
Q_snprintfz(s, sizeof(s), "%s SVN %s", DISTRIBUTION, STRINGIFY(SVNREVISION)); //if both are defined then its a known unmodified svn revision.
#else
#if defined(SVNREVISION)
#if defined(SVNREVISION)
if (strcmp(STRINGIFY(SVNREVISION), "-"))
Q_snprintfz(s, sizeof(s), "%s SVN %s", DISTRIBUTION, STRINGIFY(SVNREVISION));
Q_snprintfz(s, sizeof(s), "%s SVN %s %s", DISTRIBUTION, STRINGIFY(SVNREVISION), __DATE__);
else
#endif
#endif
Q_snprintfz(s, sizeof(s), "%s build %s", DISTRIBUTION, __DATE__);
#endif
done = true;

View File

@ -418,7 +418,7 @@ char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, q
#endif
#define PFS_CENTERED 16 //flag used by console prints (text should remain centered)
#define PFS_NONOTIFY 32 //flag used by console prints (text won't be visible other than by looking at the console)
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize_bytes, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator
unsigned int utf8_decode(int *error, const void *in, char const**out);
unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen);
unsigned int iso88591_encode(char *out, unsigned int unicode, int maxlen, qboolean markup);
@ -497,7 +497,7 @@ typedef struct searchpath_s
{
searchpathfuncs_t *handle;
unsigned int flags;
unsigned int flags; //SPF_*
char logicalpath[MAX_OSPATH]; //printable hunam-readable location of the package. generally includes a system path, including nested packages.
char purepath[256]; //server tracks the path used to load them so it can tell the client
@ -668,7 +668,13 @@ typedef struct
} parsever;
int minver; //if the engine svn revision is lower than this, the manifest will not be used as an 'upgrade'.
int maxver; //if not 0, the manifest will not be used
qboolean disablehomedir;
enum
{
MANIFEST_HOMEDIRWHENREADONLY=0,
MANIFEST_NOHOMEDIR,
MANIFEST_FORCEHOMEDIR,
} homedirtype;
char *mainconfig; //eg "fte.cfg", reducing conflicts with other engines, but can be other values...
char *updateurl; //url to download an updated manifest file from.
char *updatefile; //this is the file that needs to be written to update the manifest.
char *installation; //optional hardcoded commercial name, used for scanning the registry to find existing installs.
@ -683,7 +689,17 @@ typedef struct
char *basedir; //this is where we expect to find the data.
struct
{
qboolean base;
enum
{
GAMEDIR_DEFAULTFLAGS=0, //forgotten on gamedir switches (and a higher priority)
GAMEDIR_BASEGAME=1u<<0, //not forgotten on gamedir switches (and a lower priority)
GAMEDIR_PRIVATE=1u<<1, //don't report as the gamedir on networks.
GAMEDIR_READONLY=1u<<2, //don't write here...
GAMEDIR_USEBASEDIR=1u<<3, //packages will be read from the basedir (and homedir), but not other files. path is an empty string.
GAMEDIR_STEAMGAME=1u<<4, //finds the game via steam. must also be private+readonly.
GAMEDIR_SPECIAL=GAMEDIR_USEBASEDIR|GAMEDIR_STEAMGAME, //if one of these flags, then the gamedir cannot be simply concatenated to the basedir/homedir.
} flags;
char *path;
} gamepath[8];
struct manpack_s
@ -709,6 +725,7 @@ void COM_InitFilesystem (void); //does not set up any gamedirs.
qboolean FS_DownloadingPackage(void);
void FS_CreateBasedir(const char *path);
qboolean FS_ChangeGame(ftemanifest_t *newgame, qboolean allowreloadconfigs, qboolean allowbasedirchange);
qboolean FS_GameIsInitialised(void);
void FS_Shutdown(void);
struct gamepacks
{

View File

@ -183,6 +183,7 @@ void Cvar_List_f (void)
char *var, *search, *gsearch;
int gnum, i, num = 0;
int listflags = 0, cvarflags = 0;
int total = 0;
char strtmp[512];
static char *cvarlist_help =
"cvarlist list all cvars matching given parameters\n"
@ -380,6 +381,7 @@ showhelp:
// print cvar name
Con_Printf("%s", cmd->name);
total++;
// print current value
if (listflags & CLF_VALUES)
@ -428,6 +430,9 @@ showhelp:
if (!(listflags & CLF_RAW) && gnum)
Con_Printf("\n");
}
if (search && !strcmp(search, "*"))
Con_Printf("%i cvars\n", total);
}
//default values are meant to be constants.
@ -487,6 +492,38 @@ void Cvar_PurgeDefaults_f(void)
}
}
void Cvar_ResetAll_f(void)
{
cvar_group_t *grp;
cvar_t *var;
unsigned int bitmask; //the bits to care about
unsigned int bitmaskvalue; //must match this value
char *cmd = Cmd_Argv(0);
if (!Q_strcasecmp(cmd, "cvar_resettodefaults_saveonly"))
bitmask = CVAR_NORESET|CVAR_NOSET|CVAR_SAVE, bitmaskvalue = CVAR_SAVE;
else if (!Q_strcasecmp(cmd, "cvar_resettodefaults_nosaveonly"))
bitmask = CVAR_NORESET|CVAR_NOSET|CVAR_SAVE, bitmaskvalue = 0;
else //others...
bitmask = CVAR_NORESET|CVAR_NOSET, bitmaskvalue = 0;
for (grp=cvar_groups ; grp ; grp=grp->next)
{
for (var=grp->cvars ; var ; var=var->next)
{
if (!var->enginevalue)
continue; //can't reset the cvar's default if its an engine cvar.
if ((var->flags & bitmask) != bitmaskvalue)
continue;
if (var->defaultstr != var->enginevalue)
{
Cvar_DefaultFree(var->defaultstr);
var->defaultstr = var->enginevalue;
}
}
}
}
#define CRF_ALTNAME 0x1
void Cvar_Reset_f (void)
{

View File

@ -123,7 +123,7 @@ typedef struct cvar_group_s
//freestyle
#define CVAR_POINTER (1<<5) // q2 style. May be converted to q1 if needed. These are often specified on the command line and then converted into q1 when registered properly.
#define CVAR_UNUSED (1<<6) //the default string was malloced/needs to be malloced, free on unregister
//#define CVAR_UNUSED (1<<6) //the default string was malloced/needs to be malloced, free on unregister
#define CVAR_NOTFROMSERVER (1<<7) //cvar cannot be set by gamecode. the console will ignore changes to cvars if set at from the server or any gamecode. This is to protect against security flaws - like qterm
#define CVAR_USERCREATED (1<<8) //write a 'set' or 'seta' in front of the var name.
#define CVAR_CHEAT (1<<9) //latch to the default, unless cheats are enabled.

View File

@ -34,10 +34,12 @@ cvar_t cfg_reload_on_gamedir = CVAR("cfg_reload_on_gamedir", "1");
cvar_t fs_game = CVARFCD("game", "", CVAR_NOSAVE|CVAR_NORESET, fs_game_callback, "Provided for Q2 compat.");
cvar_t fs_gamedir = CVARFD("fs_gamedir", "", CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2 compat.");
cvar_t fs_basedir = CVARFD("fs_basedir", "", CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2 compat.");
cvar_t dpcompat_ignoremodificationtimes = CVARAFD("fs_packageprioritisation", "1", "dpcompat_ignoremodificationtimes", CVAR_NOUNSAFEEXPAND|CVAR_NOSAVE, "Favours the package that is:\n0: Most recently modified\n1: Is alphabetically last (favour z over a, 9 over 0).");
int active_fs_cachetype;
static int fs_referencetype;
int fs_finds;
void COM_CheckRegistered (void);
static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir, char *fname);
static void QDECL fs_game_callback(cvar_t *var, char *oldvalue)
{
@ -264,13 +266,13 @@ static ftemanifest_t *FS_Manifest_Clone(ftemanifest_t *oldm)
newm->rtcbroker = Z_StrDup(oldm->rtcbroker);
if (oldm->basedir)
newm->basedir = Z_StrDup(oldm->basedir);
newm->disablehomedir = oldm->disablehomedir;
newm->homedirtype = oldm->homedirtype;
for (i = 0; i < sizeof(newm->gamepath) / sizeof(newm->gamepath[0]); i++)
{
if (oldm->gamepath[i].path)
newm->gamepath[i].path = Z_StrDup(oldm->gamepath[i].path);
newm->gamepath[i].base = oldm->gamepath[i].base;
newm->gamepath[i].flags = oldm->gamepath[i].flags;
}
for (i = 0; i < sizeof(newm->package) / sizeof(newm->package[0]); i++)
{
@ -319,10 +321,16 @@ static void FS_Manifest_Print(ftemanifest_t *man)
{
if (man->gamepath[i].path)
{
if (man->gamepath[i].base)
Con_Printf("basegame %s\n", COM_QuotedString(man->gamepath[i].path, buffer, sizeof(buffer), false));
size_t bufsize = strlen(man->gamepath[i].path) + 16;
char *str = Z_Malloc(bufsize);
if (man->gamepath[i].flags & GAMEDIR_PRIVATE)
Q_strncatz(str, "*", bufsize);
Q_strncatz(str, man->gamepath[i].path, bufsize);
if (man->gamepath[i].flags & GAMEDIR_BASEGAME)
Con_Printf("basegame %s\n", COM_QuotedString(str, buffer, sizeof(buffer), false));
else
Con_Printf("gamedir %s\n", COM_QuotedString(man->gamepath[i].path, buffer, sizeof(buffer), false));
Con_Printf("gamedir %s\n", COM_QuotedString(str, buffer, sizeof(buffer), false));
}
}
@ -355,7 +363,7 @@ static void FS_Manifest_PurgeGamedirs(ftemanifest_t *man)
int i;
for (i = 0; i < sizeof(man->gamepath) / sizeof(man->gamepath[0]); i++)
{
if (man->gamepath[i].path && !man->gamepath[i].base)
if (man->gamepath[i].path && !(man->gamepath[i].flags&GAMEDIR_BASEGAME))
{
Z_Free(man->gamepath[i].path);
man->gamepath[i].path = NULL;
@ -378,6 +386,12 @@ static ftemanifest_t *FS_Manifest_Create(const char *syspath)
if (syspath)
man->updatefile = Z_StrDup(syspath); //this should be a system path.
#ifdef QUAKETC
man->mainconfig = Z_StrDup("config.cfg");
#else
man->mainconfig = Z_StrDup("fte.cfg");
#endif
return man;
}
@ -494,6 +508,33 @@ mirror:
return false;
}
static qboolean FS_GamedirIsOkay(const char *path)
{
if (!*path || strchr(path, '\n') || strchr(path, '\r') || !strcmp(path, ".") || !strcmp(path, "..") || strchr(path, ':') || strchr(path, '/') || strchr(path, '\\') || strchr(path, '$'))
{
Con_Printf("Illegal path specified: %s\n", path);
return false;
}
//don't allow leading dots, hidden files are evil.
//don't allow complex paths. those are evil too.
if (!*path || *path == '.' || !strcmp(path, ".") || strstr(path, "..") || strstr(path, "/")
|| strstr(path, "\\") || strstr(path, ":") )
{
Con_Printf ("Gamedir should be a single filename, not \"%s\"\n", path);
return false;
}
//some gamedirs should never be used for actual games/mods. Reject them.
if (!Q_strncasecmp(path, "downloads", 9) || !Q_strncasecmp(path, "docs", 4) || !Q_strncasecmp(path, "help", 4))
{
Con_Printf ("Gamedir should not be \"%s\"\n", path);
return false;
}
return true;
}
//parse Cmd_Argv tokens into the manifest.
static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
{
@ -551,6 +592,11 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
Z_Free(man->protocolname);
man->protocolname = Z_StrDup(Cmd_Argv(1));
}
else if (!Q_strcasecmp(cmd, "mainconfig"))
{
Z_Free(man->mainconfig);
man->mainconfig = Z_StrDup(Cmd_Argv(1));
}
else if (!Q_strcasecmp(cmd, "defaultexec"))
{
Z_Free(man->defaultexec);
@ -574,35 +620,66 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
Z_Free(man->updateurl);
man->updateurl = Z_StrDup(Cmd_Argv(1));
}
else if (!Q_strcasecmp(cmd, "disablehomedir"))
else if (!Q_strcasecmp(cmd, "disablehomedir") || !Q_strcasecmp(cmd, "homedirmode"))
{
man->disablehomedir = !!atoi(Cmd_Argv(1));
char *arg = Cmd_Argv(1);
if (!Q_strcasecmp(arg, "auto"))
man->homedirtype = MANIFEST_HOMEDIRWHENREADONLY;
else if (!*arg || atoi(arg))
man->homedirtype = MANIFEST_NOHOMEDIR;
else if (!atoi(arg) || !Q_strcasecmp(arg, "force"))
man->homedirtype = MANIFEST_FORCEHOMEDIR;
else if (!Q_strcasecmp(arg, "never"))
man->homedirtype = MANIFEST_NOHOMEDIR;
}
else if (!Q_strcasecmp(cmd, "basegame") || !Q_strcasecmp(cmd, "gamedir"))
{
int i;
char *newdir = Cmd_Argv(1);
//reject various evil path arguments.
if (!*newdir || strchr(newdir, '\n') || strchr(newdir, '\r') || !strcmp(newdir, ".") || !strcmp(newdir, "..") || strchr(newdir, ':') || strchr(newdir, '/') || strchr(newdir, '\\') || strchr(newdir, '$'))
for (i = 0; i < sizeof(man->gamepath) / sizeof(man->gamepath[0]); i++)
{
Con_Printf("Illegal path specified: %s\n", newdir);
}
else
{
for (i = 0; i < sizeof(man->gamepath) / sizeof(man->gamepath[0]); i++)
if (!man->gamepath[i].path)
{
if (!man->gamepath[i].path)
{
man->gamepath[i].base = !Q_strcasecmp(cmd, "basegame");
man->gamepath[i].flags = GAMEDIR_DEFAULTFLAGS;
if (!Q_strcasecmp(cmd, "basegame"))
man->gamepath[i].flags |= GAMEDIR_BASEGAME;
if (*newdir == '*')
{ //*dir makes the dir 'private' and not networked.
newdir++;
man->gamepath[i].flags |= GAMEDIR_PRIVATE;
if (!*newdir)
{ //a single asterisk means load packages from the basedir (but not other files). This is for doom compat.
man->gamepath[i].flags |= GAMEDIR_USEBASEDIR;
man->gamepath[i].flags |= GAMEDIR_READONLY; //must also be readonly, just in case.
man->gamepath[i].path = Z_StrDup(newdir);
break;
}
}
if (!strncmp(newdir, "steam:", 6))
{ //"steam:Subdir/gamedir"
char *sl = strchr(newdir+6, '/');
if (!sl)
break; //malformed steam link
man->gamepath[i].flags |= GAMEDIR_STEAMGAME;
*sl = 0;
if (!FS_GamedirIsOkay(sl+1))
break;
*sl = '/';
man->gamepath[i].path = Z_StrDup(newdir);
break;
}
if (!FS_GamedirIsOkay(newdir))
break;
man->gamepath[i].path = Z_StrDup(newdir);
break;
}
if (i == sizeof(man->gamepath) / sizeof(man->gamepath[0]))
{
Con_Printf("Too many game paths specified in manifest\n");
}
}
if (i == sizeof(man->gamepath) / sizeof(man->gamepath[0]))
{
Con_Printf("Too many game paths specified in manifest\n");
}
}
//FIXME: these should generate package-manager entries.
@ -731,11 +808,17 @@ static void COM_PathLine(searchpath_t *s)
(s->flags & SPF_WRITABLE)?"^[(w)\\tip\\Writable\\desc\\We can probably write here^]":"",
(s->handle->GeneratePureCRC)?va("^[(h)\\tip\\Hash: %x^]", s->handle->GeneratePureCRC(s->handle, 0, 0)):"");
}
qboolean FS_GameIsInitialised(void)
{
if (!com_searchpaths && !com_purepaths)
return false;
return true;
}
static void COM_Path_f (void)
{
searchpath_t *s;
if (!com_searchpaths && !com_purepaths)
if (!FS_GameIsInitialised())
{
Con_Printf("File system not initialised\n");
Con_Printf("gamedirfile: \"%s\"\n", gamedirfile);
@ -1818,19 +1901,13 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out
case FS_BASEGAMEONLY: // fte/
last = NULL;
wasbase = true;
for (i = 0; i < countof(fs_manifest->gamepath); i++)
{
if (fs_manifest && fs_manifest->gamepath[i].base && fs_manifest->gamepath[i].path)
if (fs_manifest && (fs_manifest->gamepath[i].flags&GAMEDIR_BASEGAME) && fs_manifest->gamepath[i].path)
{
if (!strcmp(fs_manifest->gamepath[i].path, "*"))
if (fs_manifest->gamepath[i].flags & GAMEDIR_SPECIAL)
continue;
if (fs_manifest->gamepath[i].base && !wasbase)
continue;
wasbase = fs_manifest->gamepath[i].base;
last = fs_manifest->gamepath[i].path;
if (*last == '*')
last++;
}
}
if (!last)
@ -1847,11 +1924,12 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out
{
if (fs_manifest && fs_manifest->gamepath[i].path)
{
if (*fs_manifest->gamepath[i].path == '*')
qboolean isbase = fs_manifest->gamepath[i].flags&GAMEDIR_BASEGAME;
if (fs_manifest->gamepath[i].flags&(GAMEDIR_PRIVATE|GAMEDIR_SPECIAL))
continue;
if (fs_manifest->gamepath[i].base && !wasbase)
if (isbase && !wasbase)
continue;
wasbase = fs_manifest->gamepath[i].base;
wasbase = isbase;
last = fs_manifest->gamepath[i].path;
}
}
@ -1866,11 +1944,10 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out
last = NULL;
for (i = 0; i < countof(fs_manifest->gamepath); i++)
{
if (fs_manifest && fs_manifest->gamepath[i].base && fs_manifest->gamepath[i].path)
if (fs_manifest && (fs_manifest->gamepath[i].flags&GAMEDIR_BASEGAME) && fs_manifest->gamepath[i].path)
{
if (*fs_manifest->gamepath[i].path == '*')
if (fs_manifest->gamepath[i].flags&(GAMEDIR_PRIVATE|GAMEDIR_SPECIAL))
continue;
wasbase = fs_manifest->gamepath[i].base;
last = fs_manifest->gamepath[i].path;
}
}
@ -2536,7 +2613,7 @@ static int QDECL FS_SortWildDataFiles(const void *va, const void *vb)
const char *na=qsortsucks+a->nameofs, *nb=qsortsucks+b->nameofs;
//sort by modification time...
if (a->mtime != b->mtime && a->mtime && b->mtime)
if (a->mtime != b->mtime && a->mtime && b->mtime && !dpcompat_ignoremodificationtimes.ival)
return a->mtime > b->mtime;
//then fall back and sort by name
@ -3279,7 +3356,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
//#define RMQCFG "sv_bigcoords 1\n"
#ifdef HAVE_SSL
#define UPDATEURL(g) "https://updates.triptohell.info/downloadables.php?game=" #g
#define UPDATEURL(g) "/downloadables.php?game=" #g
#else
#define UPDATEURL(g) NULL
#endif
@ -3879,6 +3956,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
searchpath_t *next;
int i, j;
int orderkey;
unsigned int fl;
COM_AssertMainThread("FS_ReloadPackFilesFlags");
COM_WorkerFullSync();
@ -3915,23 +3993,9 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
for (i = 0; i < countof(fs_manifest->gamepath); i++)
{
char *dir = fs_manifest->gamepath[i].path;
if (dir && fs_manifest->gamepath[i].base)
if (dir && (fs_manifest->gamepath[i].flags&GAMEDIR_BASEGAME))
{
//don't allow leading dots, hidden files are evil.
//don't allow complex paths. those are evil too.
if (!*dir || *dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/")
|| strstr(dir, "\\") || strstr(dir, ":") )
{
Con_Printf ("Gamedir should be a single filename, not \"%s\"\n", dir);
continue;
}
//some gamedirs should never be used...
if (!Q_strncasecmp(dir, "downloads", 9) || !Q_strncasecmp(dir, "docs", 4) || !Q_strncasecmp(dir, "help", 4))
{
Con_Printf ("Gamedir should not be \"%s\"\n", dir);
continue;
}
//paths should be validated before here, when parsing the manifest.
#ifdef NQPROT
//vanilla NQ uses a slightly different protocol when started with -rogue or -hipnotic (and by extension -quoth).
@ -3940,9 +4004,14 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
standard_quake = false;
#endif
//paths equal to '*' actually result in loading packages without an actual gamedir. note that this does not imply that we can write anything.
if (!strcmp(dir, "*"))
{
fl = SPF_EXPLICIT;
if (!(fs_manifest->gamepath[i].flags&GAMEDIR_READONLY))
fl |= SPF_WRITABLE;
if (fs_manifest->gamepath[i].flags&GAMEDIR_PRIVATE)
fl |= SPF_PRIVATE;
if (fs_manifest->gamepath[i].flags&GAMEDIR_USEBASEDIR)
{ //for doom - loading packages without an actual gamedir. note that this does not imply that we can write anything.
searchpathfuncs_t *handle = VFSOS_OpenPath(NULL, NULL, com_gamepath, com_gamepath, "");
searchpath_t *search = (searchpath_t*)Z_Malloc (sizeof(searchpath_t));
search->flags = 0;
@ -3950,19 +4019,26 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
Q_strncpyz(search->purepath, "", sizeof(search->purepath));
Q_strncpyz(search->logicalpath, com_gamepath, sizeof(search->logicalpath));
FS_AddDataFiles(&oldpaths, search->purepath, search->logicalpath, search, SPF_EXPLICIT, reloadflags);
FS_AddDataFiles(&oldpaths, search->purepath, search->logicalpath, search, fl, reloadflags);
handle->ClosePath(handle);
Z_Free(search);
}
else if (*dir == '*')
else if (fs_manifest->gamepath[i].flags&GAMEDIR_STEAMGAME)
{
//paths with a leading * are private, and not announced to clients that ask what the current gamedir is.
FS_AddGameDirectory(&oldpaths, dir+1, reloadflags, SPF_EXPLICIT|SPF_PRIVATE|SPF_WRITABLE);
char steamdir[MAX_OSPATH];
char *sl;
dir += 6;
sl = strchr(dir, '/');
if (*sl)
{
if (Sys_SteamHasFile(steamdir, sizeof(steamdir), dir, ""))
FS_AddSingleGameDirectory(&oldpaths, /*pure*/dir, steamdir, reloadflags, SPF_COPYPROTECTED|(fl&~SPF_WRITABLE));
}
}
else
{
FS_AddGameDirectory(&oldpaths, dir, reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
FS_AddGameDirectory(&oldpaths, dir, reloadflags, fl);
}
}
}
@ -3976,7 +4052,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
for (i = 0; i < countof(fs_manifest->gamepath); i++)
{
char *dir = fs_manifest->gamepath[i].path;
if (dir && !fs_manifest->gamepath[i].base)
if (dir && !(fs_manifest->gamepath[i].flags&GAMEDIR_BASEGAME))
{
//don't allow leading dots, hidden files are evil.
//don't allow complex paths. those are evil too.
@ -3990,7 +4066,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
for (j = 0; j < countof(fs_manifest->gamepath); j++)
{
char *dir2 = fs_manifest->gamepath[j].path;
if (dir2 && fs_manifest->gamepath[j].base && !strcmp(dir, dir2))
if (dir2 && (fs_manifest->gamepath[i].flags&GAMEDIR_BASEGAME) && !strcmp(dir, dir2))
break;
}
if (j < countof(fs_manifest->gamepath))
@ -4521,25 +4597,27 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
#if defined(__linux__) || defined(__unix__) || defined(__apple__)
#include <sys/stat.h>
static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir, char *fname)
static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir, char *fname) //returns the base system path
{
/*
Find where Valve's Steam distribution platform is installed.
Then take a look at that location for the relevent installed app.
*/
//FIXME: we ought to parse steamapps/libraryfolders.vdf (json) and read the "1" etc for games installed on different drives. default drive only for now.
FILE *f;
char *ev = getenv("HOME");
if (ev && *ev)
char *userhome = getenv("HOME");
if (userhome && *userhome)
{
Q_snprintfz(basepath, basepathlen, "%s/.steam/steam/SteamApps/common/%s", ev, steamdir);
Q_snprintfz(basepath, basepathlen, "%s/.steam/steam/steamapps/common/%s", userhome, steamdir);
if ((f = fopen(va("%s/%s", basepath, fname), "rb")))
{
fclose(f);
return true;
}
Q_snprintfz(basepath, basepathlen, "%s/.local/share/Steam/SteamApps/common/%s", ev, steamdir);
//steam apparently used to be more standard, or something? FIXME: yet still not xdg? no idea.
Q_snprintfz(basepath, basepathlen, "%s/.local/share/Steam/SteamApps/common/%s", userhome, steamdir);
if ((f = fopen(va("%s/%s", basepath, fname), "rb")))
{
fclose(f);
@ -4548,6 +4626,11 @@ static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir
}
return false;
}
#else
static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir, char *fname) //returns the base system path
{
return false;
}
#endif
qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char *poshname, const char *savedname)
@ -5708,7 +5791,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{
#ifdef _WIN32
if (!fixedbasedir)
Sys_Error("No recognised game data found in working directory.\n");
Sys_Error("No recognised game data found in working directory:\n%s", com_gamepath);
#endif
man = FS_Manifest_Parse(NULL,
"FTEManifestVer 1\n"
@ -5763,7 +5846,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
//if there's no base dirs, edit the manifest to give it its default ones.
for (j = 0; j < sizeof(man->gamepath) / sizeof(man->gamepath[0]); j++)
{
if (man->gamepath[j].path && man->gamepath[j].base)
if (man->gamepath[j].path && (man->gamepath[j].flags&GAMEDIR_BASEGAME))
break;
}
if (j == sizeof(man->gamepath) / sizeof(man->gamepath[0]))
@ -5778,7 +5861,25 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
if (!man->downloadsurl && gamemode_info[i].downloadsurl)
{
Cmd_TokenizeString(va("downloadsurl \"%s\"", gamemode_info[i].downloadsurl), false, false);
#ifndef FTE_TARGET_WEB
if (*gamemode_info[i].downloadsurl == '/')
{
conchar_t musite[256], *e;
char site[256];
char *oldprefix = "http://fte.";
char *newprefix = "https://updates.";
e = COM_ParseFunString(CON_WHITEMASK, ENGINEWEBSITE, musite, sizeof(musite), false);
COM_DeFunString(musite, e, site, sizeof(site), true, true);
if (!strncmp(site, oldprefix, strlen(oldprefix)))
{
memmove(site+strlen(newprefix), site+strlen(oldprefix), strlen(site)-strlen(oldprefix));
memcpy(site, newprefix, strlen(newprefix));
}
Cmd_TokenizeString(va("downloadsurl \"%s%s\"", site, gamemode_info[i].downloadsurl), false, false);
}
else
#endif
Cmd_TokenizeString(va("downloadsurl \"%s\"", gamemode_info[i].downloadsurl), false, false);
FS_Manifest_ParseTokens(man);
}
if (!man->protocolname)
@ -5838,10 +5939,6 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{
qboolean oldhome = com_homepathenabled;
COM_InitHomedir(man);
com_homepathenabled = com_homepathusable;
if (man->disablehomedir && !COM_CheckParm("-usehome"))
com_homepathenabled = false;
if (com_homepathenabled != oldhome)
{
@ -6394,19 +6491,16 @@ void FS_ArbitraryFile_c(int argn, const char *partial, struct xcommandargcomplet
}
}
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX)
#elif !defined(NOSTDIO)
#include <sys/stat.h>
#endif
static void COM_InitHomedir(ftemanifest_t *man)
{
int i;
qboolean usehome;
//FIXME: this should come from the manifest, as fte_GAME or something
//FIXME: this should come from the manifest, as fte_GAME or something
#ifdef _WIN32
#define HOMESUBDIR FULLENGINENAME
//windows gets formal names...
#ifdef GAME_FULLNAME
#define HOMESUBDIR GAME_FULLNAME
#else
#define HOMESUBDIR FULLENGINENAME
#endif
#else
//unix gets short names...
#ifdef GAME_SHORTNAME
#define HOMESUBDIR GAME_SHORTNAME
#else
@ -6414,169 +6508,253 @@ static void COM_InitHomedir(ftemanifest_t *man)
#endif
#endif
usehome = false;
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX)
//so this is kinda screwy
//"CSIDL_LOCAL_APPDATA/FTE Quake" is what we switched to, but we only use it if the other home dirs don't exist
//"CSIDL_PERSONAL(My Documents)/My Games/FTE Quake" is what we used to use... but personal now somehow means upload-to-internet in a nicely insecure we-own-all-your-data kind of way...
//"%USERPROFILE%/My Documents/My Games/FTE Quake" is an attempt to fall back to the earlier lame path if everything else fails
//"%USERPROFILE%/Saved Games/FTE Quake" is what we probably should be using. I don't know who comes up with these random paths. We have updates+downloads+etc as well as just saves, so we prioritise localdata instead (stuff that you do NOT want microsoft to upload to the internet all the time).
#include <shlobj.h>
static qboolean FS_GetBestHomeDir(ftemanifest_t *manifest)
{ //win32 sucks.
qboolean usehome = false;
HRESULT (WINAPI *dSHGetFolderPathW) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, wchar_t *pszPath) = NULL;
HRESULT (WINAPI *dSHGetKnownFolderPath) (const GUID *const rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath) = NULL;
dllfunction_t funcs[] =
{
{(void**)&dSHGetFolderPathW, "SHGetFolderPathW"},
{NULL,NULL}
};
dllfunction_t funcsvista[] =
{
{(void**)&dSHGetKnownFolderPath, "SHGetKnownFolderPath"},
{NULL,NULL}
};
DWORD winver = (DWORD)LOBYTE(LOWORD(GetVersion()));
enum
{
WINHOME_LOCALDATA,
WINHOME_SAVEDGAMES,
WINHOME_DOCUMENTS,
WINHOME_COUNT
};
struct
{
char path[MAX_OSPATH];
} homedir[WINHOME_COUNT];
int i;
/*HMODULE shfolder =*/ Sys_LoadLibrary("shfolder.dll", funcs);
/*HMODULE shfolder =*/ Sys_LoadLibrary("shell32.dll", funcsvista);
if (dSHGetKnownFolderPath)
{
wchar_t *wide;
static const GUID qFOLDERID_SavedGames = {0x4c5c32ff, 0xbb9d, 0x43b0, {0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}};
#define qKF_FLAG_CREATE 0x00008000
if (SUCCEEDED(dSHGetKnownFolderPath(&qFOLDERID_SavedGames, qKF_FLAG_CREATE, NULL, &wide)))
{
narrowen(homedir[WINHOME_SAVEDGAMES].path, sizeof(homedir[WINHOME_SAVEDGAMES].path), wide);
CoTaskMemFree(wide);
}
}
if (dSHGetFolderPathW)
{
wchar_t wfolder[MAX_PATH];
if (dSHGetFolderPathW(NULL, 0x5/*CSIDL_PERSONAL*/, NULL, 0, wfolder) == S_OK)
{
narrowen(homedir[WINHOME_DOCUMENTS].path, sizeof(homedir[WINHOME_DOCUMENTS].path), wfolder);
Q_strncatz(homedir[WINHOME_DOCUMENTS].path, "/My Games", sizeof(homedir[WINHOME_DOCUMENTS].path));
}
//at some point, microsoft (in their infinitesimal wisdom) decided that 'CSIDL_PERSONAL' should mean 'CSIDL_GIVEITALLTOMICROSOFT'
//so use the old/CSIDL_NOTACTUALLYPERSONAL path by default for compat, but if there's nothing there then switch to CSIDL_LOCAL_APPDATA instead
if (dSHGetFolderPathW(NULL, 0x1c/*CSIDL_LOCAL_APPDATA*/, NULL, 0, wfolder) == S_OK)
{
narrowen(homedir[WINHOME_LOCALDATA].path, sizeof(homedir[WINHOME_LOCALDATA].path), wfolder);
}
}
if (!*homedir[WINHOME_DOCUMENTS].path)
{ //guess. sucks for non-english people.
char *ev = getenv("USERPROFILE");
if (ev)
Q_snprintfz(homedir[WINHOME_DOCUMENTS].path, sizeof(homedir[WINHOME_DOCUMENTS].path), "%s/My Documents/My Games/%s/", ev, HOMESUBDIR);
}
// if (shfolder)
// FreeLibrary(shfolder);
for(i = 0; i < countof(homedir); i++)
{
char formal[MAX_OSPATH];
char informal[MAX_OSPATH];
if (!*homedir[i].path)
continue; //erk, don't know, not valid/known on this system.
if (!manifest || !manifest->formalname || (/*legacy compat hack case*/ !strcmp(manifest->formalname, "Quake") && strstr(HOMESUBDIR, "Quake")))
{
Q_snprintfz(formal, sizeof(formal), "%s/%s/", homedir[i].path, HOMESUBDIR); //'FTE Quake' or something hardcoded.
*informal = 0;
}
else
{
if ( strchr(manifest->formalname, '(') || //ugly
strchr(manifest->formalname, '[') || //ugly
strchr(manifest->formalname, '.') || //ugly
strchr(manifest->formalname, '\"') || //ugly (and invalid)
strchr(manifest->formalname, '|') || //invalid
strchr(manifest->formalname, '<') || //invalid
strchr(manifest->formalname, '>') || //invalid
strchr(manifest->formalname, '\\') || //long paths
strchr(manifest->formalname, '/') || //long paths
strchr(manifest->formalname, ':') || //alternative data stream separator
strchr(manifest->formalname, '*') || //wildcard
strchr(manifest->formalname, '?')) //wildcard
*formal = 0; //don't use filenames with awkward chars...
else
Q_snprintfz(formal, sizeof(formal), "%s/%s/", homedir[i].path, manifest->formalname); //'Quake' / 'The Wastes' / etc
Q_snprintfz(informal, sizeof(informal), "%s/%s/", homedir[i].path, manifest->installation); //'quake' / 'wastes' / etc
}
if (*formal && GetFileAttributesU(formal)!=INVALID_FILE_ATTRIBUTES) //path exists, use it.
{
Q_strncpyz(com_homepath, formal, sizeof(com_homepath));
break;
}
else if (*informal && GetFileAttributesU(informal)!=INVALID_FILE_ATTRIBUTES) //path exists, use it.
{
Q_strncpyz(com_homepath, informal, sizeof(com_homepath));
break;
}
else if (!*com_homepath)
{
if (!*informal)
Q_strncpyz(com_homepath, formal, sizeof(com_homepath));
else
Q_strncpyz(com_homepath, informal, sizeof(com_homepath));
continue; //keep looking, we might still find one that actually exists.
}
}
#ifdef NPFTE
if (!*com_homepath)
Q_snprintfz(com_homepath, sizeof(com_homepath), "/%s/", HOMESUBDIR);
//as a browser plugin, always use their home directory
return true;
#else
/*would it not be better to just check to see if we have write permission to the basedir?*/
if (winver >= 0x6) // Windows Vista and above
usehome = true; // always use home directory by default, as Vista+ mimics this behavior anyway
else if (winver >= 0x5) // Windows 2000/XP/2003
usehome = true; //might as well follow this logic. We use .manifest stuff to avoid getting redirected to obscure locations, so access rights is all that is relevant, not whether we're an admin or not.
#endif
if (usehome && manifest)
{
DWORD homeattr = GetFileAttributesU(com_homepath);
DWORD baseattr = GetFileAttributesU(com_gamepath);
if (homeattr != INVALID_FILE_ATTRIBUTES && (homeattr & FILE_ATTRIBUTE_DIRECTORY))
return true; //okay something else already created it. continue using it.
if (baseattr != INVALID_FILE_ATTRIBUTES && (baseattr & FILE_ATTRIBUTE_DIRECTORY))
{ //windows has an _access function, but it doesn't actually bother to check if you're allowed to access it, so its utterly pointless.
//instead try to append nothing to some file that'll probably exist anyway.
//this MAY fail if another program has it open. windows sucks.
vfsfile_t *writetest = VFSOS_Open("conhistory.txt", "a");
if (!writetest)
return true; //basedir isn't writable, we'll need our home! use it by default.
VFS_CLOSE(writetest);
}
//else don't use it (unless -usehome, anyway)
}
return false;
}
#elif defined(NOSTDIO)
static qboolean FS_GetBestHomeDir(void)
{ //no studio? webgl port? no file system access = no homedirs!
return false;
}
#else
#include <sys/stat.h>
static qboolean FS_GetBestHomeDir(ftemanifest_t *man)
{
qboolean usehome = false;
//on unix, we use environment settings.
//if $HOME/.fte/ exists then we use that because of legacy reasons.
//but if it doesn't exist then we use $XDG_DATA_HOME/.fte instead
//we used to use $HOME/.#HOMESUBDIR/ but this is now only used if it actually exists AND the new path doesn't.
//new installs use $XDG_DATA_HOME/#HOMESUBDIR/ instead
char *ev = getenv("FTEHOME");
if (ev && *ev)
{
if (ev[strlen(ev)-1] == '/')
Q_strncpyz(com_homepath, ev, sizeof(com_homepath));
else
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/", ev);
usehome = true; // always use home on unix unless told not to
ev = NULL;
}
else
ev = getenv("HOME");
if (ev && *ev)
{
const char *xdghome;
char oldhome[MAX_OSPATH];
char newhome[MAX_OSPATH];
struct stat s;
char *installation = (man && man->installation && *man->installation)?man->installation:HOMESUBDIR;
usehome = (man && man->installation && *man->installation)?true:false; //use it if we're running a game, otherwise don't bother if we're still loading.
xdghome = getenv("XDG_DATA_HOME");
if (!xdghome || !*xdghome)
xdghome = va("%s/.local/share", ev);
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(newhome, sizeof(newhome), "%s%s/", xdghome, installation);
else
Q_snprintfz(newhome, sizeof(newhome), "%s/%s/", xdghome, installation);
if (ev[strlen(ev)-1] == '/')
Q_snprintfz(oldhome, sizeof(oldhome), "%s.%s/", ev, installation);
else
Q_snprintfz(oldhome, sizeof(oldhome), "%s/.%s/", ev, installation);
if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1)
Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath));
else
Q_strncpyz(com_homepath, newhome, sizeof(com_homepath));
}
if (usehome && man)
{
struct stat statbuf;
if (stat(com_homepath, &statbuf) >= 0 && (statbuf.st_mode & S_IFMT)==S_IFDIR)
return true; //okay something else already created it. continue using it.
if (access(com_gamepath, W_OK) < 0)
return true; //baesdir isn't writable, we'll need our home! use it by default.
//else don't use it (unless -usehome, anyway)
}
return false;
}
#endif
static void COM_InitHomedir(ftemanifest_t *man)
{
int i;
//assume the home directory is the working directory.
*com_homepath = '\0';
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX)
{ //win32 sucks.
HRESULT (WINAPI *dSHGetFolderPathW) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, wchar_t *pszPath) = NULL;
dllfunction_t funcs[] =
{
{(void**)&dSHGetFolderPathW, "SHGetFolderPathW"},
{NULL,NULL}
};
DWORD winver = (DWORD)LOBYTE(LOWORD(GetVersion()));
/*HMODULE shfolder =*/ Sys_LoadLibrary("shfolder.dll", funcs);
if (dSHGetFolderPathW)
{
wchar_t wfolder[MAX_PATH];
char folder[MAX_OSPATH];
if (dSHGetFolderPathW(NULL, 0x5/*CSIDL_PERSONAL*/, NULL, 0, wfolder) == S_OK)
{
narrowen(folder, sizeof(folder), wfolder);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, HOMESUBDIR);
}
//at some point, microsoft (in their infinitesimal wisdom) decided that 'CSIDL_PERSONAL' should mean 'CSIDL_GIVEITALLTOMICROSOFT'
//so use the old/CSIDL_NOTACTUALLYPERSONAL path by default for compat, but if there's nothing there then switch to CSIDL_LOCAL_APPDATA instead
if ((!*com_homepath||!GetFileAttributesU(com_homepath)) && dSHGetFolderPathW(NULL, 0x1c/*CSIDL_LOCAL_APPDATA*/, NULL, 0, wfolder) == S_OK)
{
narrowen(folder, sizeof(folder), wfolder);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/%s/", folder, HOMESUBDIR);
}
}
// if (shfolder)
// FreeLibrary(shfolder);
if (!*com_homepath)
{
char *ev = getenv("USERPROFILE");
if (ev)
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Documents/My Games/%s/", ev, HOMESUBDIR);
}
#ifdef NPFTE
if (!*com_homepath)
Q_snprintfz(com_homepath, sizeof(com_homepath), "/%s/", HOMESUBDIR);
//as a browser plugin, always use their home directory
usehome = true;
#else
/*would it not be better to just check to see if we have write permission to the basedir?*/
if (winver >= 0x6) // Windows Vista and above
usehome = true; // always use home directory by default, as Vista+ mimics this behavior anyway
else if (winver >= 0x5) // Windows 2000/XP/2003
{
HMODULE advapi32;
BOOL (WINAPI *dCheckTokenMembership) (HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember) = NULL;
dllfunction_t funcs[] =
{
{(void**)&dCheckTokenMembership, "CheckTokenMembership"},
{NULL,NULL}
};
advapi32 = Sys_LoadLibrary("advapi32.dll", funcs);
if (advapi32)
{
if (dCheckTokenMembership)
{
// on XP systems, only use a home directory by default if we're a limited user or if we're on a network
BOOL isadmin, isonnetwork;
SID_IDENTIFIER_AUTHORITY ntauth = {SECURITY_NT_AUTHORITY};
PSID adminSID, networkSID;
isadmin = AllocateAndInitializeSid(&ntauth,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&adminSID);
// just checking the network rid should be close enough to matching domain logins
isonnetwork = AllocateAndInitializeSid(&ntauth,
1,
SECURITY_NETWORK_RID,
0, 0, 0, 0, 0, 0, 0,
&networkSID);
if (isadmin && !dCheckTokenMembership(0, adminSID, &isadmin))
isadmin = 0;
if (isonnetwork && !dCheckTokenMembership(0, networkSID, &isonnetwork))
isonnetwork = 0;
usehome = isonnetwork || !isadmin;
FreeSid(networkSID);
FreeSid(adminSID);
}
Sys_CloseLibrary(advapi32);
}
}
#endif
}
#elif !defined(NOSTDIO)
{
//on unix, we use environment settings.
//if $HOME/.fte/ exists then we use that because of legacy reasons.
//but if it doesn't exist then we use $XDG_DATA_HOME/.fte instead
//we used to use $HOME/.#HOMESUBDIR/ but this is now only used if it actually exists AND the new path doesn't.
//new installs use $XDG_DATA_HOME/#HOMESUBDIR/ instead
char *ev = getenv("FTEHOME");
if (ev && *ev)
{
if (ev[strlen(ev)-1] == '/')
Q_strncpyz(com_homepath, ev, sizeof(com_homepath));
else
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/", ev);
usehome = true; // always use home on unix unless told not to
ev = NULL;
}
else
ev = getenv("HOME");
if (ev && *ev)
{
const char *xdghome;
char oldhome[MAX_OSPATH];
char newhome[MAX_OSPATH];
struct stat s;
xdghome = getenv("XDG_DATA_HOME");
if (!xdghome || !*xdghome)
xdghome = va("%s/.local/share", ev);
if (man && man->installation)
{
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s%s/", xdghome, *man->installation?man->installation:HOMESUBDIR);
else
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/%s/", xdghome, *man->installation?man->installation:HOMESUBDIR);
}
else
{
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(newhome, sizeof(newhome), "%s%s/", xdghome, HOMESUBDIR);
else
Q_snprintfz(newhome, sizeof(newhome), "%s/%s/", xdghome, HOMESUBDIR);
if (ev[strlen(ev)-1] == '/')
Q_snprintfz(oldhome, sizeof(oldhome), "%s.%s/", ev, HOMESUBDIR);
else
Q_snprintfz(oldhome, sizeof(oldhome), "%s/.%s/", ev, HOMESUBDIR);
if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1)
Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath));
else
Q_strncpyz(com_homepath, newhome, sizeof(com_homepath));
}
usehome = true; // always use home on unix unless told not to
}
}
#endif
com_homepathusable = usehome;
if (man && (strstr(man->installation, "..") || strchr(man->installation, '/') || strchr(man->installation, '\\')))
com_homepathusable = false; //don't even try to generate a relative homedir.
else
com_homepathusable = FS_GetBestHomeDir(man);
com_homepathenabled = false;
if (man && man->homedirtype == MANIFEST_NOHOMEDIR)
com_homepathusable = false;
else if (man && man->homedirtype == MANIFEST_FORCEHOMEDIR)
com_homepathusable = true;
i = COM_CheckParm("-homedir");
if (i && i+1<com_argc)
{ //explicitly override the homedir.
@ -6591,7 +6769,6 @@ static void COM_InitHomedir(ftemanifest_t *man)
com_homepathusable = false;
com_homepathenabled = com_homepathusable;
}
/*
@ -6616,6 +6793,7 @@ void COM_InitFilesystem (void)
Cmd_AddCommandAD("dir", COM_Dir_f, FS_ArbitraryFile_c, "Displays filesystem listings. Accepts wildcards."); //q3 like
Cmd_AddCommandD("path", COM_Path_f, "prints a list of current search paths.");
Cmd_AddCommandAD("flocate", COM_Locate_f, FS_ArbitraryFile_c, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found.
Cmd_AddCommandAD("which", COM_Locate_f, FS_ArbitraryFile_c, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found.
//
@ -6632,6 +6810,7 @@ void COM_InitFilesystem (void)
Cvar_Register(&cfg_reload_on_gamedir, "Filesystem");
Cvar_Register(&dpcompat_ignoremodificationtimes, "Filesystem");
Cvar_Register(&com_fs_cache, "Filesystem");
Cvar_Register(&fs_gamename, "Filesystem");
Cvar_Register(&pkg_downloads_url, "Filesystem");

View File

@ -5309,9 +5309,25 @@ static void CM_FinalizeBrush(q2cbrush_t *brush)
}
for (i = 0; i < brush->numsides; i++)
{
j = Fragment_ClipPlaneToBrush(verts, countof(verts), planes, sizeof(planes[0]), brush->numsides, planes[i]);
while (j-- > 0)
AddPointToBounds(verts[j], brush->absmins, brush->absmaxs);
//most brushes are axial, which can save some a little loadtime
if (planes[i][0] == 1)
brush->absmaxs[0] = planes[i][3];
else if (planes[i][1] == 1)
brush->absmaxs[1] = planes[i][3];
else if (planes[i][2] == 1)
brush->absmaxs[2] = planes[i][3];
else if (planes[i][0] == -1)
brush->absmins[0] = -planes[i][3];
else if (planes[i][1] == -1)
brush->absmins[1] = -planes[i][3];
else if (planes[i][2] == -1)
brush->absmins[2] = -planes[i][3];
else
{
j = Fragment_ClipPlaneToBrush(verts, countof(verts), planes, sizeof(planes[0]), brush->numsides, planes[i]);
while (j-- > 0)
AddPointToBounds(verts[j], brush->absmins, brush->absmaxs);
}
}
}

View File

@ -455,20 +455,6 @@ static qboolean QDECL SSL_CloseFile(vfsfile_t *vfs)
return true;
}
static const qbyte updates_triptohell_certdata[962] = "\x30\x82\x03\xbe\x30\x82\x02\xa6\xa0\x03\x02\x01\x02\x02\x09\x00\xf4\x4e\x13\x08\x32\x85\xb5\x19\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x74\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x4b\x31\x10\x30\x0e\x06\x03\x55\x04\x08\x0c\x07\x45\x6e\x67\x6c\x61\x6e\x64\x31\x0f\x30\x0d\x06\x03\x55\x04\x07\x0c\x06\x4c\x6f\x6e\x64\x6f\x6e\x31\x0e\x30\x0c\x06\x03\x55\x04\x0a\x0c\x05\x46\x54\x45\x51\x57\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x55\x70\x64\x61\x74\x65\x73\x31\x20\x30\x1e\x06\x03\x55\x04\x03\x0c\x17\x75\x70\x64\x61\x74\x65\x73\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x1e\x17\x0d\x31\x39\x30\x35\x33\x31\x31\x30\x30\x39\x31\x39\x5a\x17\x0d\x32\x39\x30\x35\x32\x38\x31\x30\x30\x39\x31\x39\x5a\x30\x74\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x4b\x31\x10\x30\x0e\x06\x03\x55\x04\x08\x0c\x07\x45\x6e\x67\x6c\x61\x6e\x64\x31\x0f\x30\x0d\x06\x03\x55\x04\x07\x0c\x06\x4c\x6f\x6e\x64\x6f\x6e\x31\x0e\x30\x0c\x06\x03\x55\x04\x0a\x0c\x05\x46\x54\x45\x51\x57\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x55\x70\x64\x61\x74\x65\x73\x31\x20\x30\x1e\x06\x03\x55\x04\x03\x0c\x17\x75\x70\x64\x61\x74\x65\x73\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xaa\xb5\x9c\xcc\xe8\xbd\xad\x1c\x7f\x6b\x1c\xc9\x04\xe6\x2c\x10\xac\x99\xeb\x67\x0b\x9c\x24\xb8\x90\x77\xde\xaa\x44\xa2\x15\x31\x61\x52\x4d\xeb\x8f\x56\xb8\xaf\xc1\x2f\x66\xdd\x55\x8d\xd6\xec\xc3\xa4\x93\x8c\x86\xeb\xaf\x89\x17\x19\x2e\x6c\xc2\xd4\xf9\x92\xac\x2e\x73\x99\x56\xf2\xc3\xc4\x14\x56\x4a\x0d\xbe\x51\xc9\x8f\x4e\x92\x20\x2b\xae\x05\x0c\x7e\x87\xa5\x02\xe1\xc0\x7d\x71\xa7\x38\x72\x47\x3f\x31\x07\x90\xb0\x6d\xcf\xae\xb6\xdb\xeb\x39\xaa\x5f\xb4\x6f\x0c\x63\x2a\x21\x65\x36\xaa\x6b\xac\x97\xb6\xbe\x20\xa4\x87\x36\xbf\x35\xc5\xa6\x31\xe4\x9d\x85\xf3\xae\x8f\x6b\xf8\x59\x75\x0f\xb5\x5d\x31\x40\x39\x2e\xea\x48\x65\xdf\x91\xe3\x06\xfb\xb2\xec\xdc\xd0\x90\x94\xd6\x68\x4d\x62\x25\x9a\x3d\xc3\x74\x17\x7d\x0e\xe2\x1e\x34\xbf\x02\x85\xc4\x40\x88\x91\xeb\xe0\xf5\x92\x56\x42\x4f\xa6\x4c\x17\x88\xb2\x89\xd2\xec\x60\x54\x97\x20\x0a\xca\xf0\xd1\x33\x3f\x5b\x66\xb7\x8a\x42\x72\x67\xc9\x47\x83\xb3\xd4\x1e\xa8\x44\xbf\x5a\x1a\x85\x79\xee\xf8\x80\xde\x19\x1d\xc5\xdd\x50\x42\x10\x17\xb7\xc3\xd4\xf1\xcb\x8a\xb8\x71\x55\x31\x02\x03\x01\x00\x01\xa3\x53\x30\x51\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x2c\x68\x81\x8f\x40\x8c\x40\x42\x9f\xbd\xc5\x0b\x36\xfb\xe2\x76\xeb\x8d\xb4\xf3\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x2c\x68\x81\x8f\x40\x8c\x40\x42\x9f\xbd\xc5\x0b\x36\xfb\xe2\x76\xeb\x8d\xb4\xf3\x30\x0f\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x0c\x01\x35\x32\xb8\xe7\x96\xba\x3e\x53\x8c\x78\x41\xab\x9b\x7f\xe2\x7a\x80\x5a\xc9\x88\x06\x29\x28\xf9\x50\x7f\xcc\xb6\xcc\x34\x03\x45\x32\x79\x63\xe7\xde\x9c\x46\x29\xf4\xaf\x32\x72\x26\x11\xa0\x7b\x52\x23\x0a\xd5\x51\x91\x79\xf2\x50\x61\x80\x72\x40\xe7\x85\xb0\x13\x1d\x98\xdb\x14\x23\x59\xa4\xbc\xe9\xe0\x1b\xc0\x38\x33\x96\xbc\xbb\x56\x47\xcc\xbd\xe8\x40\x49\xdf\xaa\x64\x7e\x29\xe5\x9d\x40\xa5\x1a\x5c\x45\x1f\x5a\x77\x59\xfe\x7a\xb8\xf8\x4d\xc4\x9b\x31\xe6\x08\xc4\x95\xfa\x91\x8f\x91\x9f\x3c\xc4\x82\xb9\xf1\x6d\xa8\xa6\xc4\x09\xb1\xe9\xa8\x60\x9b\xaa\x4c\x79\xf0\x99\xb8\xad\x63\xb1\xe4\xc0\xaf\xf0\xdf\xc9\x33\x53\x4d\x09\xe4\x3f\x8d\x9e\x38\xc6\x93\xff\xcc\x91\x46\x7e\x67\x28\x61\xaa\xc7\x0b\xe2\xd8\x8c\xe4\xec\x8d\x44\xe7\x6a\x14\x78\x91\x7d\xec\xc7\x07\xed\xc9\x58\xdb\x35\xd4\x70\x06\x06\x39\x8d\x4b\x80\x2c\xb6\xa8\x79\x5c\x94\x15\x6c\x34\x06\x5c\xd7\xc5\x42\xc0\x72\x01\x71\x07\xf5\x25\x6a\xd0\x24\x86\xcd\x1b\x21\x07\xae\x40\xf8\xc1\xe4\x23\x0d\xa0\xc0\x23\xf0\x07\xba\xdc\x34\x5d\x47\xcf\x4b\x7b\xd5\x5d";
//static const qbyte fte_triptohell_certdata[917] = "\x30\x82\x03\x91\x30\x82\x02\x79\xa0\x03\x02\x01\x02\x02\x09\x00\xb5\x71\x47\x8d\x5e\x66\xf1\xd9\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x5f\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x46\x54\x45\x31\x1c\x30\x1a\x06\x03\x55\x04\x03\x0c\x13\x66\x74\x65\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x35\x30\x30\x35\x38\x31\x34\x5a\x17\x0d\x31\x37\x30\x33\x30\x34\x30\x30\x35\x38\x31\x34\x5a\x30\x5f\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x46\x54\x45\x31\x1c\x30\x1a\x06\x03\x55\x04\x03\x0c\x13\x66\x74\x65\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xdd\xb8\x7c\x69\x3d\x63\x95\xe3\x88\x15\xfd\xad\x93\x5e\x6b\x97\xfb\x74\xba\x1f\x83\x33\xe5\x8a\x8d\x8f\xb0\xbf\xf9\xd3\xa1\x2c\x65\x53\xa7\xef\xd3\x0f\xdc\x03\x60\x0a\x40\xef\xa8\xef\x3f\xb3\xd9\x8d\x31\x39\x12\x8a\xd8\x0e\x24\x8f\xe5\x58\x26\x86\x4c\x76\x6c\x59\x9a\xab\xea\x1c\x3d\xfb\x62\x62\xad\xaf\xd6\x00\x33\x76\x2d\xbb\xeb\xe8\xec\xb4\x76\x4f\xb0\xbe\xcf\xf0\x46\x94\x40\x02\x99\xd4\xb2\x71\x71\xd6\xf5\x1f\xc3\x4f\x1e\x1e\xb4\x0d\x82\x49\xc4\xa2\xdc\xae\x6f\x4e\x3a\xf9\x0e\xdd\xf4\xd2\x53\xe3\xe7\x7d\x58\x79\xf4\xce\x1f\x6c\xac\x81\x8c\x8c\xe1\x03\x5b\x22\x56\x92\x19\x4f\x74\xc0\x36\x41\xac\x1b\xfa\x9e\xf7\x2a\x0f\xd6\x4b\xcc\x9a\xca\x67\x87\xb7\x95\xdf\xb7\xd4\x7d\x8c\xcc\xa9\x25\xde\xdd\x8c\x1b\xd7\x32\xf2\x84\x25\x46\x7b\x10\x55\xf9\x80\xfd\x5d\xad\xab\xf9\x4c\x1f\xc0\xa5\xd1\x3f\x01\x86\x4d\xfa\x57\xab\x7a\x6d\xec\xf1\xdb\xf4\xad\xf2\x33\xcd\xa0\xed\xfe\x1b\x27\x55\x56\xba\x8c\x47\x70\x16\xd5\x75\x17\x8e\x80\xaa\x49\x5e\x93\x83\x1d\x6f\x1f\x2c\xf7\xa7\x64\xe6\x2e\x88\x8e\xff\x70\x5a\x41\x52\xae\x93\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x4e\x76\x4a\xce\x7b\x45\x14\x39\xeb\x9c\x28\x56\xb5\x7b\x8a\x18\x6f\x22\x17\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x4e\x76\x4a\xce\x7b\x45\x14\x39\xeb\x9c\x28\x56\xb5\x7b\x8a\x18\x6f\x22\x17\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x48\x22\x65\xed\x2e\xc5\xed\xbb\xe9\x40\x6c\x80\xc4\x63\x19\xd1\x00\xb4\x30\x34\x17\x7c\x7c\xbd\x1b\xc5\xa9\x43\x0c\x92\x6e\xd6\x2d\x11\x6c\x0d\xa6\xda\x30\xe9\xf7\x46\x7b\x01\xe4\x53\x23\xae\x88\xd1\xf2\xed\xca\x84\x06\x19\x97\xb9\x06\xfb\xda\xec\x72\x2d\x15\x20\xd2\x8f\x66\xad\xb5\xdd\x4b\x4f\xdf\x7e\xaf\xa3\x6c\x7f\x53\x32\x8f\xe2\x19\x5c\x44\x98\x86\x31\xee\xb4\x03\xe7\x27\xa1\x83\xab\xc3\xce\xb4\x9a\x01\xbe\x8c\x64\x2e\x2b\xe3\x4e\x55\xdf\x95\xeb\x16\x87\xbd\xfa\x11\xa2\x3e\x38\x92\x97\x36\xe9\x65\x60\xf3\xac\x68\x44\xb3\x51\x54\x3a\x42\xa8\x98\x9b\xee\x1b\x9e\x79\x6a\xaf\xc0\xbe\x41\xc4\xb1\x96\x42\xd9\x94\xef\x49\x5b\xbe\x2d\x04\xb9\xfb\x92\xbb\xdc\x0e\x29\xfd\xee\xa9\x68\x09\xf9\x9f\x69\x8b\x3d\xe1\x4b\xee\x24\xf9\xfe\x02\x3a\x0a\xb8\xcd\x6c\x07\x43\xa9\x4a\xe7\x03\x34\x2e\x72\xa7\x81\xaa\x40\xa9\x98\x5d\x97\xee\x2a\x99\xc6\x8f\xe8\x6f\x98\xa2\x85\xc9\x0d\x04\x19\x43\x6a\xd3\xc7\x15\x4c\x4b\xbc\xa5\xb8\x9f\x38\xf3\x43\x83\x0c\xef\x97\x6e\xa6\x20\xde\xc5\xd3\x1e\x3e\x5d\xcd\x58\x3d\x5c\x55\x7a\x90\x94";
//static const qbyte triptohell_certdata[933] = "\x30\x82\x03\xa1\x30\x82\x02\x89\xa0\x03\x02\x01\x02\x02\x09\x00\xea\xb7\x13\xcf\x55\xe5\xe8\x8c\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x31\x18\x30\x16\x06\x03\x55\x04\x03\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x35\x30\x30\x35\x38\x33\x37\x5a\x17\x0d\x31\x37\x30\x33\x30\x34\x30\x30\x35\x38\x33\x37\x5a\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x31\x18\x30\x16\x06\x03\x55\x04\x03\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xd8\x77\x62\xf6\x74\xa7\x75\xde\xda\x09\xae\x9e\x76\x7a\xc6\x2a\xcf\x9a\xbe\xc6\xb9\x6d\xe2\xca\x0f\x2d\x95\xb8\x89\x93\xf7\x50\x64\x92\x7d\x95\x34\xe4\x6e\xef\x52\x56\xef\x13\x9a\x3a\xae\x84\x5b\x57\x82\x04\x86\x74\xbd\x4e\x38\x32\x56\x00\xd6\x34\x9c\x23\xd6\x81\x8e\x29\x77\x45\x61\x20\xdf\x28\xf8\xe5\x61\x83\xec\xe6\xa0\x1a\x75\xa8\x3b\x53\x6f\xc4\x09\x61\x66\x3a\xf0\x81\xbf\x2c\xf5\x8e\xf1\xe2\x35\xe4\x24\x7f\x16\xcc\xce\x60\xa2\x42\x6e\xc2\x3a\x29\x75\x6c\x79\xb0\x99\x9c\xe2\xfe\x27\x32\xb6\xf7\x0d\x71\xfd\x62\x9d\x54\x7c\x40\xb2\xf5\xa0\xa4\x25\x31\x8d\x65\xfd\x3f\x3b\x9b\x7e\x84\x74\x17\x3c\x1f\xec\x50\xcf\x75\xb8\x5c\xca\xfc\x0f\xe8\x47\xd8\x64\xec\x5f\x6c\x45\x9a\x55\x49\x97\x3f\xcb\x49\x34\x71\x0a\x12\x13\xbc\x3d\x53\x81\x17\x9a\x92\x44\x91\x07\xc2\xef\x6d\x64\x86\x5d\xfd\x67\xd5\x99\x38\x95\x46\x74\x6d\xb6\xbf\x29\xc9\x5b\xac\xb1\x46\xd6\x9e\x57\x5c\x7b\x24\x91\xf4\x7c\xe4\x01\x31\x8c\xec\x79\x94\xb7\x3f\xd2\x93\x6d\xe2\x69\xbe\x61\x44\x2e\x8f\x1a\xdc\xa8\x97\xf5\x81\x8e\x0c\xe1\x00\xf2\x71\x51\xf3\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x18\xb2\x6b\x63\xcc\x17\x54\xf6\xf0\xb6\x9e\x62\xa4\x35\xcf\x47\x74\x13\x29\xbf\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x18\xb2\x6b\x63\xcc\x17\x54\xf6\xf0\xb6\x9e\x62\xa4\x35\xcf\x47\x74\x13\x29\xbf\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x7f\x24\x18\x8a\x79\xee\xf9\xeb\xed\x29\x1e\x21\x15\x8a\x53\xc9\xb7\xec\x30\xc4\x85\x9f\x45\x85\x26\x36\xb7\x07\xf3\xf1\xff\x3b\x89\x05\x0a\xd4\x30\x68\x31\x68\x33\xdd\xf6\x58\xa3\x85\x9f\x49\x50\x76\x9a\xc5\x79\x13\xe1\x4d\x67\x0c\xf3\x92\xf0\x1d\x02\x1f\xc4\x5c\xd4\xa1\x0c\x57\xdf\x46\x84\x43\x9f\xb0\xe2\x91\x62\xa8\xe0\x86\x0d\x47\xe1\xd9\x60\x01\xc4\xe0\xda\x6f\x06\x0a\xad\x38\xf3\x66\x68\xc5\xe2\x66\x3e\x47\x83\x65\x64\xcd\xff\xf3\xbb\xa7\xfa\x23\xf1\x82\x5e\x06\x6a\x91\x37\x51\xcd\xb9\x95\x20\x89\xff\xa1\x54\xb2\x76\xcf\x8e\xe1\xcd\x13\x93\x13\xd1\xda\x0d\x0d\xbc\x0f\xd5\x11\x26\xd6\xaf\x60\x0f\x4d\x8a\x4f\x28\xee\x6c\xf1\x99\xdc\xed\x16\xdc\x87\x26\xfd\x23\x8a\xb8\xb0\x20\x0e\xe2\x32\xf5\x8e\xb0\x65\x98\x13\xb8\x4b\x39\x7c\x8c\x98\xa2\x29\x75\x48\x3a\x89\xf9\x61\x77\x6c\x2d\x84\x41\x40\x17\xa6\x50\xc5\x09\x63\x10\xe7\x09\xd4\x5c\xdd\x0e\x71\x16\xaf\xb1\x32\xe4\xc0\xe6\xea\xfd\x26\x55\x07\x40\x95\x84\x48\x62\x04\x10\x92\xb2\xd9\x27\xfb\x8a\xf3\x7c\xe6\xfe\xd4\xfc\xa6\x33\x79\x01\x5c\xc3\x1f\x80\xa8\xf3";
static struct
{
char *hostname;
unsigned int datasize;
const qbyte *data;
} knowncerts[] = {
// {"triptohell.info", sizeof(triptohell_certdata), triptohell_certdata},
// {"fte.triptohell.info", sizeof(fte_triptohell_certdata), fte_triptohell_certdata},
{"updates.triptohell.info", sizeof(updates_triptohell_certdata), updates_triptohell_certdata},
};
static qboolean SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file, int *errorcode)
{
#ifdef HAVE_CLIENT
@ -506,50 +492,58 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
qboolean preverified = false;
int errcode = GNUTLS_E_CERTIFICATE_ERROR;
size_t i;
for (i = 0; i < countof(knowncerts); i++)
size_t knownsize;
qbyte *knowndata = TLS_GetKnownCertificate(file->certname, &knownsize);
if (knowndata)
{
if (!strcmp(knowncerts[i].hostname, file->certname))
unsigned int certcount, j;
const gnutls_datum_t *const certlist = qgnutls_certificate_get_peers(session, &certcount);
if (!certlist || !certcount)
{
unsigned int certcount, j;
const gnutls_datum_t *const certlist = qgnutls_certificate_get_peers(session, &certcount);
if (certlist && certcount)
{
size_t offset = 0;
for (j = 0; j < certcount; offset += certlist[j++].size)
{
if (certlist[j].size+offset > knowncerts[i].datasize)
break; //overflow...
if (memcmp(certlist[j].data, knowncerts[i].data+offset, certlist[j].size))
break;
}
if (j && j == certcount && offset == knowncerts[i].datasize)
preverified = true;
else
{
#ifdef _DEBUG
for (j = 0, offset = 0; j < certcount; j++)
offset += certlist[j].size;
Con_Printf("%s cert %zu bytes (chain %u)\n", file->certname, offset, certcount);
Con_Printf("\"");
for (j = 0; j < certcount; j++)
{
unsigned char *data = certlist[j].data;
unsigned int datasize = certlist[j].size, k;
for (k = 0; k < datasize; k++)
Con_Printf("\\x%02x", data[k]);
}
Con_Printf("\"\n\n");
#endif
Con_Printf(CON_ERROR "%s: Reported certificate does not match known certificate. Possible MITM attack, alternatively just an outdated client.\n", file->certname);
return GNUTLS_E_CERTIFICATE_ERROR;
}
}
break;
BZ_Free(knowndata);
return GNUTLS_E_CERTIFICATE_ERROR;
}
else
{
size_t offset = 0;
for (j = 0; j < certcount; offset += certlist[j++].size)
{
if (certlist[j].size+offset > knownsize)
break; //overflow...
if (memcmp(certlist[j].data, knowndata+offset, certlist[j].size))
break;
}
if (j && j == certcount && offset == knownsize)
preverified = true;
else
{
#ifdef _DEBUG
for (j = 0, offset = 0; j < certcount; j++)
offset += certlist[j].size;
Con_Printf("%s cert %zu bytes (chain %u)\n", file->certname, offset, certcount);
Con_Printf("/*%s*/\"", file->certname);
for (j = 0; file->certname[j]; j++)
Con_Printf("\\x%02x", file->certname[j]^0xff);
Con_Printf("\\xff");
Con_Printf("\\x%02x\\x%02x", (unsigned)offset&0xff, ((unsigned)offset>>8)&0xff);
for (j = 0; j < certcount; j++)
{
unsigned char *data = certlist[j].data;
unsigned int datasize = certlist[j].size, k;
for (k = 0; k < datasize; k++)
Con_Printf("\\x%02x", data[k]^0xff);
}
Con_Printf("\",\n\n");
#endif
Con_Printf(CON_ERROR "%s: Reported certificate does not match known certificate. Possible MITM attack, alternatively just an outdated client.\n", file->certname);
BZ_Free(knowndata);
return GNUTLS_E_CERTIFICATE_ERROR;
}
}
BZ_Free(knowndata);
}
#ifdef GNUTLS_HAVE_VERIFY3

View File

@ -8,6 +8,7 @@ I've given up for now.
*/
#include "winquake.h"
#include "netinc.h"
#define SECURITY_WIN32
#include <security.h>
#include <sspi.h>
@ -384,32 +385,12 @@ static void SSPI_Encode(sslfile_t *f)
SSPI_TryFlushCryptOut(f);
}
//these are known sites that use self-signed certificates, or are special enough that we don't trust corporate networks to hack in their own certificate authority for a proxy/mitm
//old static const qbyte triptohell_certdata[933] = "\x30\x82\x03\xa1\x30\x82\x02\x89\xa0\x03\x02\x01\x02\x02\x09\x00\x8b\xd0\x05\x63\x62\xd1\x6a\xe3\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x44\x31\x0c\x30\x0a\x06\x03\x55\x04\x08\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x07\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0b\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x03\x0c\x03\x42\x61\x64\x31\x12\x30\x10\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16\x03\x42\x61\x64\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x34\x32\x32\x34\x32\x34\x37\x5a\x17\x0d\x32\x34\x31\x32\x32\x31\x32\x32\x34\x32\x34\x37\x5a\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x44\x31\x0c\x30\x0a\x06\x03\x55\x04\x08\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x07\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0b\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x03\x0c\x03\x42\x61\x64\x31\x12\x30\x10\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16\x03\x42\x61\x64\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xaf\x10\x33\xfa\x39\xf5\xae\x2c\x91\x0e\x20\xe6\x3c\x5c\x7c\x1e\xeb\x16\x50\x2f\x05\x30\xfe\x67\xee\xa9\x00\x54\xd9\x4a\x86\xe6\xba\x80\xfb\x1a\x80\x08\x7e\x7b\x13\xe5\x1a\x18\xc9\xd4\x70\xbd\x5d\xc4\x38\xef\x64\xf1\x90\x2c\x53\x49\x93\x24\x36\x3e\x11\x59\x69\xa6\xdf\x37\xb2\x54\x82\x28\x3e\xdd\x30\x75\xa0\x18\xd8\xe1\xf5\x52\x73\x12\x5b\x37\x68\x1c\x59\xbd\x8c\x73\x66\x47\xbc\xcb\x9c\xfe\x38\x92\x8f\x74\xe9\xd1\x2f\x96\xd2\x5d\x6d\x11\x59\xb2\xdc\xbd\x8c\x37\x5b\x22\x76\x98\xe7\xbe\x08\xef\x1e\x99\xc4\xa9\x77\x2c\x9c\x0e\x08\x3c\x8e\xab\x97\x0c\x6a\xd7\x03\xab\xfd\x4a\x1e\x95\xb2\xc2\x9c\x3a\x16\x65\xd7\xaf\x45\x5f\x6e\xe7\xce\x51\xba\xa0\x60\x43\x0e\x07\xc5\x0b\x0a\x82\x05\x26\xc4\x92\x0a\x27\x5b\xfc\x57\x6c\xdf\xe2\x54\x8a\xef\x38\xf1\xf8\xc4\xf8\x51\x16\x27\x1f\x78\x89\x7c\x5b\xd7\x53\xcd\x9b\x54\x2a\xe6\x71\xee\xe4\x56\x2e\xa4\x09\x1a\x61\xf7\x0f\x97\x22\x94\xd7\xef\x21\x6c\xe6\x81\xfb\x54\x5f\x09\x92\xac\xd2\x7c\xab\xd5\xa9\x81\xf4\xc9\xb7\xd6\xbf\x68\xf8\x4f\xdc\xf3\x60\xa3\x3b\x29\x92\x9e\xdd\xa2\xa3\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x19\xed\xd0\x7b\x16\xaf\xb5\x0c\x9a\xe8\xd3\x46\x2e\x3c\x64\x29\xb6\xc1\x73\x5a\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x19\xed\xd0\x7b\x16\xaf\xb5\x0c\x9a\xe8\xd3\x46\x2e\x3c\x64\x29\xb6\xc1\x73\x5a\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x62\xa7\x26\xeb\xd4\x03\x29\x9c\x09\x33\x69\x7a\x9c\x65\x68\xec\x4c\xb9\x06\xeb\x1e\x51\x6f\x78\x20\xdc\xf6\x44\x5e\x06\x6e\x53\x87\x73\xe6\x14\x15\xb9\x17\x74\x67\xe0\x4e\x48\x38\xbc\x1c\xbd\xd0\xad\xd6\xbd\x8c\xf0\x3a\xe0\x13\x73\x19\xad\x8b\x79\x68\x67\x65\x9b\x7a\x4c\x81\xfb\xd9\x92\x77\x89\xb5\xb0\x53\xb0\xa5\xf7\x2d\x8e\x29\x60\x31\xd1\x9b\x2f\x63\x8a\x5f\x64\xc1\x61\xd5\xb7\xdf\x70\x3b\x2b\xf6\x1a\x96\xb9\xa7\x08\xca\x87\xa6\x8c\x60\xca\x6e\xd7\xee\xba\xef\x89\x0b\x93\xd5\xfd\xfc\x14\xba\xef\x27\xba\x90\x11\x90\xf7\x25\x70\xe7\x4e\xf4\x9c\x13\x27\xc1\xa7\x8e\xd9\x66\x43\x72\x20\x5b\xe1\x5c\x73\x74\xf5\x33\xf2\xa5\xf6\xe1\xd5\xac\xf3\x67\x5c\xe7\xd4\x0a\x8d\x91\x73\x03\x3e\x9d\xbc\x96\xc3\x0c\xdb\xd5\x77\x6e\x76\x44\x69\xaf\x24\x0f\x4f\x8b\x47\x36\x8b\xc3\xd6\x36\xdd\x26\x5a\x9c\xdd\x9c\x43\xee\x29\x43\xdd\x75\x2f\x19\x52\xfc\x1d\x24\x9c\x13\x29\x99\xa0\x6d\x7a\x95\xcc\xa0\x58\x86\xd8\xc5\xb9\xa3\xc2\x3d\x64\x1d\x85\x8a\xca\x53\x55\x8e\x9a\x6d\xc9\x91\x73\xf4\xe1\xe1\xa4\x9b\x76\xfc\x7f\x63\xc2\xb9\x23";
static const qbyte updates_triptohell_certdata[962] = "\x30\x82\x03\xbe\x30\x82\x02\xa6\xa0\x03\x02\x01\x02\x02\x09\x00\xf4\x4e\x13\x08\x32\x85\xb5\x19\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x74\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x4b\x31\x10\x30\x0e\x06\x03\x55\x04\x08\x0c\x07\x45\x6e\x67\x6c\x61\x6e\x64\x31\x0f\x30\x0d\x06\x03\x55\x04\x07\x0c\x06\x4c\x6f\x6e\x64\x6f\x6e\x31\x0e\x30\x0c\x06\x03\x55\x04\x0a\x0c\x05\x46\x54\x45\x51\x57\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x55\x70\x64\x61\x74\x65\x73\x31\x20\x30\x1e\x06\x03\x55\x04\x03\x0c\x17\x75\x70\x64\x61\x74\x65\x73\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x1e\x17\x0d\x31\x39\x30\x35\x33\x31\x31\x30\x30\x39\x31\x39\x5a\x17\x0d\x32\x39\x30\x35\x32\x38\x31\x30\x30\x39\x31\x39\x5a\x30\x74\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x4b\x31\x10\x30\x0e\x06\x03\x55\x04\x08\x0c\x07\x45\x6e\x67\x6c\x61\x6e\x64\x31\x0f\x30\x0d\x06\x03\x55\x04\x07\x0c\x06\x4c\x6f\x6e\x64\x6f\x6e\x31\x0e\x30\x0c\x06\x03\x55\x04\x0a\x0c\x05\x46\x54\x45\x51\x57\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x55\x70\x64\x61\x74\x65\x73\x31\x20\x30\x1e\x06\x03\x55\x04\x03\x0c\x17\x75\x70\x64\x61\x74\x65\x73\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xaa\xb5\x9c\xcc\xe8\xbd\xad\x1c\x7f\x6b\x1c\xc9\x04\xe6\x2c\x10\xac\x99\xeb\x67\x0b\x9c\x24\xb8\x90\x77\xde\xaa\x44\xa2\x15\x31\x61\x52\x4d\xeb\x8f\x56\xb8\xaf\xc1\x2f\x66\xdd\x55\x8d\xd6\xec\xc3\xa4\x93\x8c\x86\xeb\xaf\x89\x17\x19\x2e\x6c\xc2\xd4\xf9\x92\xac\x2e\x73\x99\x56\xf2\xc3\xc4\x14\x56\x4a\x0d\xbe\x51\xc9\x8f\x4e\x92\x20\x2b\xae\x05\x0c\x7e\x87\xa5\x02\xe1\xc0\x7d\x71\xa7\x38\x72\x47\x3f\x31\x07\x90\xb0\x6d\xcf\xae\xb6\xdb\xeb\x39\xaa\x5f\xb4\x6f\x0c\x63\x2a\x21\x65\x36\xaa\x6b\xac\x97\xb6\xbe\x20\xa4\x87\x36\xbf\x35\xc5\xa6\x31\xe4\x9d\x85\xf3\xae\x8f\x6b\xf8\x59\x75\x0f\xb5\x5d\x31\x40\x39\x2e\xea\x48\x65\xdf\x91\xe3\x06\xfb\xb2\xec\xdc\xd0\x90\x94\xd6\x68\x4d\x62\x25\x9a\x3d\xc3\x74\x17\x7d\x0e\xe2\x1e\x34\xbf\x02\x85\xc4\x40\x88\x91\xeb\xe0\xf5\x92\x56\x42\x4f\xa6\x4c\x17\x88\xb2\x89\xd2\xec\x60\x54\x97\x20\x0a\xca\xf0\xd1\x33\x3f\x5b\x66\xb7\x8a\x42\x72\x67\xc9\x47\x83\xb3\xd4\x1e\xa8\x44\xbf\x5a\x1a\x85\x79\xee\xf8\x80\xde\x19\x1d\xc5\xdd\x50\x42\x10\x17\xb7\xc3\xd4\xf1\xcb\x8a\xb8\x71\x55\x31\x02\x03\x01\x00\x01\xa3\x53\x30\x51\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x2c\x68\x81\x8f\x40\x8c\x40\x42\x9f\xbd\xc5\x0b\x36\xfb\xe2\x76\xeb\x8d\xb4\xf3\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x2c\x68\x81\x8f\x40\x8c\x40\x42\x9f\xbd\xc5\x0b\x36\xfb\xe2\x76\xeb\x8d\xb4\xf3\x30\x0f\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x0c\x01\x35\x32\xb8\xe7\x96\xba\x3e\x53\x8c\x78\x41\xab\x9b\x7f\xe2\x7a\x80\x5a\xc9\x88\x06\x29\x28\xf9\x50\x7f\xcc\xb6\xcc\x34\x03\x45\x32\x79\x63\xe7\xde\x9c\x46\x29\xf4\xaf\x32\x72\x26\x11\xa0\x7b\x52\x23\x0a\xd5\x51\x91\x79\xf2\x50\x61\x80\x72\x40\xe7\x85\xb0\x13\x1d\x98\xdb\x14\x23\x59\xa4\xbc\xe9\xe0\x1b\xc0\x38\x33\x96\xbc\xbb\x56\x47\xcc\xbd\xe8\x40\x49\xdf\xaa\x64\x7e\x29\xe5\x9d\x40\xa5\x1a\x5c\x45\x1f\x5a\x77\x59\xfe\x7a\xb8\xf8\x4d\xc4\x9b\x31\xe6\x08\xc4\x95\xfa\x91\x8f\x91\x9f\x3c\xc4\x82\xb9\xf1\x6d\xa8\xa6\xc4\x09\xb1\xe9\xa8\x60\x9b\xaa\x4c\x79\xf0\x99\xb8\xad\x63\xb1\xe4\xc0\xaf\xf0\xdf\xc9\x33\x53\x4d\x09\xe4\x3f\x8d\x9e\x38\xc6\x93\xff\xcc\x91\x46\x7e\x67\x28\x61\xaa\xc7\x0b\xe2\xd8\x8c\xe4\xec\x8d\x44\xe7\x6a\x14\x78\x91\x7d\xec\xc7\x07\xed\xc9\x58\xdb\x35\xd4\x70\x06\x06\x39\x8d\x4b\x80\x2c\xb6\xa8\x79\x5c\x94\x15\x6c\x34\x06\x5c\xd7\xc5\x42\xc0\x72\x01\x71\x07\xf5\x25\x6a\xd0\x24\x86\xcd\x1b\x21\x07\xae\x40\xf8\xc1\xe4\x23\x0d\xa0\xc0\x23\xf0\x07\xba\xdc\x34\x5d\x47\xcf\x4b\x7b\xd5\x5d";
//static const qbyte fte_triptohell_certdata[917] = "\x30\x82\x03\x91\x30\x82\x02\x79\xa0\x03\x02\x01\x02\x02\x09\x00\xb5\x71\x47\x8d\x5e\x66\xf1\xd9\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x5f\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x46\x54\x45\x31\x1c\x30\x1a\x06\x03\x55\x04\x03\x0c\x13\x66\x74\x65\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x35\x30\x30\x35\x38\x31\x34\x5a\x17\x0d\x31\x37\x30\x33\x30\x34\x30\x30\x35\x38\x31\x34\x5a\x30\x5f\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x46\x54\x45\x31\x1c\x30\x1a\x06\x03\x55\x04\x03\x0c\x13\x66\x74\x65\x2e\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xdd\xb8\x7c\x69\x3d\x63\x95\xe3\x88\x15\xfd\xad\x93\x5e\x6b\x97\xfb\x74\xba\x1f\x83\x33\xe5\x8a\x8d\x8f\xb0\xbf\xf9\xd3\xa1\x2c\x65\x53\xa7\xef\xd3\x0f\xdc\x03\x60\x0a\x40\xef\xa8\xef\x3f\xb3\xd9\x8d\x31\x39\x12\x8a\xd8\x0e\x24\x8f\xe5\x58\x26\x86\x4c\x76\x6c\x59\x9a\xab\xea\x1c\x3d\xfb\x62\x62\xad\xaf\xd6\x00\x33\x76\x2d\xbb\xeb\xe8\xec\xb4\x76\x4f\xb0\xbe\xcf\xf0\x46\x94\x40\x02\x99\xd4\xb2\x71\x71\xd6\xf5\x1f\xc3\x4f\x1e\x1e\xb4\x0d\x82\x49\xc4\xa2\xdc\xae\x6f\x4e\x3a\xf9\x0e\xdd\xf4\xd2\x53\xe3\xe7\x7d\x58\x79\xf4\xce\x1f\x6c\xac\x81\x8c\x8c\xe1\x03\x5b\x22\x56\x92\x19\x4f\x74\xc0\x36\x41\xac\x1b\xfa\x9e\xf7\x2a\x0f\xd6\x4b\xcc\x9a\xca\x67\x87\xb7\x95\xdf\xb7\xd4\x7d\x8c\xcc\xa9\x25\xde\xdd\x8c\x1b\xd7\x32\xf2\x84\x25\x46\x7b\x10\x55\xf9\x80\xfd\x5d\xad\xab\xf9\x4c\x1f\xc0\xa5\xd1\x3f\x01\x86\x4d\xfa\x57\xab\x7a\x6d\xec\xf1\xdb\xf4\xad\xf2\x33\xcd\xa0\xed\xfe\x1b\x27\x55\x56\xba\x8c\x47\x70\x16\xd5\x75\x17\x8e\x80\xaa\x49\x5e\x93\x83\x1d\x6f\x1f\x2c\xf7\xa7\x64\xe6\x2e\x88\x8e\xff\x70\x5a\x41\x52\xae\x93\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x4e\x76\x4a\xce\x7b\x45\x14\x39\xeb\x9c\x28\x56\xb5\x7b\x8a\x18\x6f\x22\x17\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x4e\x76\x4a\xce\x7b\x45\x14\x39\xeb\x9c\x28\x56\xb5\x7b\x8a\x18\x6f\x22\x17\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x48\x22\x65\xed\x2e\xc5\xed\xbb\xe9\x40\x6c\x80\xc4\x63\x19\xd1\x00\xb4\x30\x34\x17\x7c\x7c\xbd\x1b\xc5\xa9\x43\x0c\x92\x6e\xd6\x2d\x11\x6c\x0d\xa6\xda\x30\xe9\xf7\x46\x7b\x01\xe4\x53\x23\xae\x88\xd1\xf2\xed\xca\x84\x06\x19\x97\xb9\x06\xfb\xda\xec\x72\x2d\x15\x20\xd2\x8f\x66\xad\xb5\xdd\x4b\x4f\xdf\x7e\xaf\xa3\x6c\x7f\x53\x32\x8f\xe2\x19\x5c\x44\x98\x86\x31\xee\xb4\x03\xe7\x27\xa1\x83\xab\xc3\xce\xb4\x9a\x01\xbe\x8c\x64\x2e\x2b\xe3\x4e\x55\xdf\x95\xeb\x16\x87\xbd\xfa\x11\xa2\x3e\x38\x92\x97\x36\xe9\x65\x60\xf3\xac\x68\x44\xb3\x51\x54\x3a\x42\xa8\x98\x9b\xee\x1b\x9e\x79\x6a\xaf\xc0\xbe\x41\xc4\xb1\x96\x42\xd9\x94\xef\x49\x5b\xbe\x2d\x04\xb9\xfb\x92\xbb\xdc\x0e\x29\xfd\xee\xa9\x68\x09\xf9\x9f\x69\x8b\x3d\xe1\x4b\xee\x24\xf9\xfe\x02\x3a\x0a\xb8\xcd\x6c\x07\x43\xa9\x4a\xe7\x03\x34\x2e\x72\xa7\x81\xaa\x40\xa9\x98\x5d\x97\xee\x2a\x99\xc6\x8f\xe8\x6f\x98\xa2\x85\xc9\x0d\x04\x19\x43\x6a\xd3\xc7\x15\x4c\x4b\xbc\xa5\xb8\x9f\x38\xf3\x43\x83\x0c\xef\x97\x6e\xa6\x20\xde\xc5\xd3\x1e\x3e\x5d\xcd\x58\x3d\x5c\x55\x7a\x90\x94";
//static const qbyte triptohell_certdata[933] = "\x30\x82\x03\xa1\x30\x82\x02\x89\xa0\x03\x02\x01\x02\x02\x09\x00\xea\xb7\x13\xcf\x55\xe5\xe8\x8c\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x31\x18\x30\x16\x06\x03\x55\x04\x03\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x35\x30\x30\x35\x38\x33\x37\x5a\x17\x0d\x31\x37\x30\x33\x30\x34\x30\x30\x35\x38\x33\x37\x5a\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x11\x30\x0f\x06\x03\x55\x04\x07\x0c\x08\x4e\x65\x77\x20\x59\x6f\x72\x6b\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x31\x18\x30\x16\x06\x03\x55\x04\x03\x0c\x0f\x74\x72\x69\x70\x74\x6f\x68\x65\x6c\x6c\x2e\x69\x6e\x66\x6f\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xd8\x77\x62\xf6\x74\xa7\x75\xde\xda\x09\xae\x9e\x76\x7a\xc6\x2a\xcf\x9a\xbe\xc6\xb9\x6d\xe2\xca\x0f\x2d\x95\xb8\x89\x93\xf7\x50\x64\x92\x7d\x95\x34\xe4\x6e\xef\x52\x56\xef\x13\x9a\x3a\xae\x84\x5b\x57\x82\x04\x86\x74\xbd\x4e\x38\x32\x56\x00\xd6\x34\x9c\x23\xd6\x81\x8e\x29\x77\x45\x61\x20\xdf\x28\xf8\xe5\x61\x83\xec\xe6\xa0\x1a\x75\xa8\x3b\x53\x6f\xc4\x09\x61\x66\x3a\xf0\x81\xbf\x2c\xf5\x8e\xf1\xe2\x35\xe4\x24\x7f\x16\xcc\xce\x60\xa2\x42\x6e\xc2\x3a\x29\x75\x6c\x79\xb0\x99\x9c\xe2\xfe\x27\x32\xb6\xf7\x0d\x71\xfd\x62\x9d\x54\x7c\x40\xb2\xf5\xa0\xa4\x25\x31\x8d\x65\xfd\x3f\x3b\x9b\x7e\x84\x74\x17\x3c\x1f\xec\x50\xcf\x75\xb8\x5c\xca\xfc\x0f\xe8\x47\xd8\x64\xec\x5f\x6c\x45\x9a\x55\x49\x97\x3f\xcb\x49\x34\x71\x0a\x12\x13\xbc\x3d\x53\x81\x17\x9a\x92\x44\x91\x07\xc2\xef\x6d\x64\x86\x5d\xfd\x67\xd5\x99\x38\x95\x46\x74\x6d\xb6\xbf\x29\xc9\x5b\xac\xb1\x46\xd6\x9e\x57\x5c\x7b\x24\x91\xf4\x7c\xe4\x01\x31\x8c\xec\x79\x94\xb7\x3f\xd2\x93\x6d\xe2\x69\xbe\x61\x44\x2e\x8f\x1a\xdc\xa8\x97\xf5\x81\x8e\x0c\xe1\x00\xf2\x71\x51\xf3\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x18\xb2\x6b\x63\xcc\x17\x54\xf6\xf0\xb6\x9e\x62\xa4\x35\xcf\x47\x74\x13\x29\xbf\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x18\xb2\x6b\x63\xcc\x17\x54\xf6\xf0\xb6\x9e\x62\xa4\x35\xcf\x47\x74\x13\x29\xbf\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x7f\x24\x18\x8a\x79\xee\xf9\xeb\xed\x29\x1e\x21\x15\x8a\x53\xc9\xb7\xec\x30\xc4\x85\x9f\x45\x85\x26\x36\xb7\x07\xf3\xf1\xff\x3b\x89\x05\x0a\xd4\x30\x68\x31\x68\x33\xdd\xf6\x58\xa3\x85\x9f\x49\x50\x76\x9a\xc5\x79\x13\xe1\x4d\x67\x0c\xf3\x92\xf0\x1d\x02\x1f\xc4\x5c\xd4\xa1\x0c\x57\xdf\x46\x84\x43\x9f\xb0\xe2\x91\x62\xa8\xe0\x86\x0d\x47\xe1\xd9\x60\x01\xc4\xe0\xda\x6f\x06\x0a\xad\x38\xf3\x66\x68\xc5\xe2\x66\x3e\x47\x83\x65\x64\xcd\xff\xf3\xbb\xa7\xfa\x23\xf1\x82\x5e\x06\x6a\x91\x37\x51\xcd\xb9\x95\x20\x89\xff\xa1\x54\xb2\x76\xcf\x8e\xe1\xcd\x13\x93\x13\xd1\xda\x0d\x0d\xbc\x0f\xd5\x11\x26\xd6\xaf\x60\x0f\x4d\x8a\x4f\x28\xee\x6c\xf1\x99\xdc\xed\x16\xdc\x87\x26\xfd\x23\x8a\xb8\xb0\x20\x0e\xe2\x32\xf5\x8e\xb0\x65\x98\x13\xb8\x4b\x39\x7c\x8c\x98\xa2\x29\x75\x48\x3a\x89\xf9\x61\x77\x6c\x2d\x84\x41\x40\x17\xa6\x50\xc5\x09\x63\x10\xe7\x09\xd4\x5c\xdd\x0e\x71\x16\xaf\xb1\x32\xe4\xc0\xe6\xea\xfd\x26\x55\x07\x40\x95\x84\x48\x62\x04\x10\x92\xb2\xd9\x27\xfb\x8a\xf3\x7c\xe6\xfe\xd4\xfc\xa6\x33\x79\x01\x5c\xc3\x1f\x80\xa8\xf3";
static struct
{
wchar_t *hostname;
unsigned int datasize;
const qbyte *data;
//FIXME: include expiry information
//FIXME: add alternative when one is about to expire
} knowncerts[] = {
// {L"triptohell.info", sizeof(triptohell_certdata), triptohell_certdata},
// {L"fte.triptohell.info", sizeof(fte_triptohell_certdata), fte_triptohell_certdata},
{L"updates.triptohell.info", sizeof(updates_triptohell_certdata), updates_triptohell_certdata},
{NULL}
};
char *narrowen(char *out, size_t outlen, wchar_t *wide);
static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data, size_t datasize, qboolean datagram)
{
int i;
#ifndef SERVERONLY
size_t knownsize;
void *knowncert;
char realdomain[256];
#endif
if (datagram)
{
if (status == CERT_E_UNTRUSTEDROOT || SUCCEEDED(status))
@ -423,48 +404,31 @@ static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data,
}
return status;
}
for (i = 0; knowncerts[i].hostname; i++)
narrowen(realdomain, sizeof(realdomain), domain);
knowncert = TLS_GetKnownCertificate(realdomain, &knownsize);
if (knowncert)
{
if (!wcscmp(domain, knowncerts[i].hostname))
{
#ifdef _DEBUG
if (!knowncerts[i].data)
{
int j;
Con_Printf("%ls cert %i bytes\n", domain, (int)datasize);
Con_Printf("\"");
for (j = 0; j < datasize; j++)
Con_Printf("\\x%02x", data[j]);
Con_Printf("\"\n");
Con_Printf("\n");
for (j = 0; j < datasize; j++)
Con_Printf("%c", data[j]);
continue;
}
#endif
if (knowncerts[i].datasize == datasize && !memcmp(data, knowncerts[i].data, datasize))
{ //what we know about matched
if (status == CERT_E_UNTRUSTEDROOT)
status = SEC_E_OK;
break;
}
else
{
if (status != CERT_E_EXPIRED)
Con_Printf("%ls has an unexpected certificate\n", domain);
if (status == SEC_E_OK) //we (think) we know better.
status = TRUST_E_FAIL;
}
if (knownsize == datasize && !memcmp(data, knowncert, datasize))
{ //what we know about matched
if (status == CERT_E_UNTRUSTEDROOT || status == CERT_E_EXPIRED)
status = SEC_E_OK;
}
else
{
if (status != CERT_E_EXPIRED)
Con_Printf("%ls has an unexpected certificate\n", domain);
if (status == SEC_E_OK) //we (think) we know better.
status = TRUST_E_FAIL;
}
BZ_Free(knowncert);
}
#ifndef SERVERONLY
//self-signed and expired certs are understandable in many situations.
//prompt and cache (although this connection attempt will fail).
if (status == CERT_E_UNTRUSTEDROOT || status == CERT_E_UNTRUSTEDTESTROOT || status == CERT_E_EXPIRED)
if (CertLog_ConnectOkay(narrowen(realdomain, sizeof(realdomain), domain), data, datasize))
if (CertLog_ConnectOkay(realdomain, data, datasize))
return SEC_E_OK;
#endif

View File

@ -1053,8 +1053,19 @@ size_t NET_StringToSockaddr2 (const char *s, int defaultport, netadrtype_t afhin
//its not meant to be used for browsers etc, and I cba to register dns stuff for it.
//besides, browsers/etc would just bitch about its cert, so w/e.
//redirect the dns to the base host without affecting http(s) hosts/certificates.
if (!strcmp(s, "updates.triptohell.info"))
s += 8;
if (!strncmp(s, "updates.", 8))
{
conchar_t musite[256], *e;
char site[256];
char *oldprefix = "http://fte.";
e = COM_ParseFunString(CON_WHITEMASK, ENGINEWEBSITE, musite, sizeof(musite), false);
COM_DeFunString(musite, e, site, sizeof(site), true, true);
if (!strncmp(site, oldprefix, strlen(oldprefix)))
{
if (!strcmp(s+8,site+strlen(oldprefix)))
s += 8;
}
}
#endif
memset (sadr, 0, sizeof(*sadr));
@ -2111,6 +2122,52 @@ qboolean NET_IsLoopBackAddress (netadr_t *adr)
#ifdef HAVE_SSL
void *TLS_GetKnownCertificate(const char *certname, size_t *size)
{
//Note: This is XORed because of shitty scanners flagging binaries through false positive, flagging the sites that they were downloaded from, flagging binaries that contain references to those sites, and flagging any site that contains binaries.
//the xor helps break that shitty recursive loop of mistrust from defects in other people's code.
//at least until there's a sandbox that checks the dns resolutions for our update requests anyway.
//I should probably just copy the downloadables file to sourceforge.
static struct
{
qbyte *data;
} knowncerts[] = {
{
/*updates.triptohell.info*/"\x8a\x8f\x9b\x9e\x8b\x9a\x8c\xd1\x8b\x8d\x96\x8f\x8b\x90\x97\x9a\x93\x93\xd1\x96\x91\x99\x90\xff\xc2\x03\xcf\x7d\xfc\x41\xcf\x7d\xfd\x59\x5f\xfc\xfd\xfe\xfd\xfd\xf6\xff\x0b\xb1\xec\xf7\xcd\x7a\x4a\xe6\xcf\xf2\xf9\xf6\xd5\x79\xb7\x79\x08\xf2\xfe\xfe\xf4\xfa\xff\xcf\x8b\xce\xf4\xcf\xf6\xf9\xfc\xaa\xfb\xf9\xec\xfd\xaa\xb4\xce\xef\xcf\xf1\xf9\xfc\xaa\xfb\xf7\xf3\xf8\xba\x91\x98\x93\x9e\x91\x9b\xce\xf0\xcf\xf2\xf9\xfc\xaa\xfb\xf8\xf3\xf9\xb3\x90\x91\x9b\x90\x91\xce\xf1\xcf\xf3\xf9\xfc\xaa\xfb\xf5\xf3\xfa\xb9\xab\xba\xae\xa8\xce\xef\xcf\xf1\xf9\xfc\xaa\xfb\xf4\xf3\xf8\xaa\x8f\x9b\x9e\x8b\x9a\x8c\xce\xdf\xcf\xe1\xf9\xfc\xaa\xfb\xfc\xf3\xe8\x8a\x8f\x9b\x9e\x8b\x9a\x8c\xd1\x8b\x8d\x96\x8f\x8b\x90\x97\x9a\x93\x93\xd1\x96\x91\x99\x90\xcf\xe1\xe8\xf2\xce\xc6\xcf\xca\xcc\xce\xce\xcf\xcf\xc6\xce\xc6\xa5\xe8\xf2\xcd\xc6\xcf\xca\xcd\xc7\xce\xcf\xcf\xc6\xce\xc6\xa5\xcf\x8b\xce\xf4\xcf\xf6\xf9\xfc\xaa\xfb\xf9\xec\xfd\xaa\xb4\xce\xef\xcf\xf1\xf9\xfc\xaa\xfb\xf7\xf3\xf8\xba\x91\x98\x93\x9e\x91\x9b\xce\xf0\xcf\xf2\xf9\xfc\xaa\xfb\xf8\xf3\xf9\xb3\x90\x91\x9b\x90\x91\xce\xf1\xcf\xf3\xf9\xfc\xaa\xfb\xf5\xf3\xfa\xb9\xab\xba\xae\xa8\xce\xef\xcf\xf1\xf9\xfc\xaa\xfb\xf4\xf3\xf8\xaa\x8f\x9b\x9e\x8b\x9a\x8c\xce\xdf\xcf\xe1\xf9\xfc\xaa\xfb\xfc\xf3\xe8\x8a\x8f\x9b\x9e\x8b\x9a\x8c\xd1\x8b\x8d\x96\x8f\x8b\x90\x97\x9a\x93\x93\xd1\x96\x91\x99\x90\xcf\x7d\xfe\xdd\xcf\xf2\xf9\xf6\xd5\x79\xb7\x79\x08\xf2\xfe\xfe\xfe\xfa\xff\xfc\x7d\xfe\xf0\xff\xcf\x7d\xfe\xf5\xfd\x7d\xfe\xfe\xff\x55\x4a\x63\x33\x17\x42\x52\xe3\x80\x94\xe3\x36\xfb\x19\xd3\xef\x53\x66\x14\x98\xf4\x63\xdb\x47\x6f\x88\x21\x55\xbb\x5d\xea\xce\x9e\xad\xb2\x14\x70\xa9\x47\x50\x3e\xd0\x99\x22\xaa\x72\x29\x13\x3c\x5b\x6c\x73\x79\x14\x50\x76\xe8\xe6\xd1\x93\x3d\x2b\x06\x6d\x53\xd1\x8c\x66\xa9\x0d\x3c\x3b\xeb\xa9\xb5\xf2\x41\xae\x36\x70\xb1\x6d\xdf\xd4\x51\xfa\xf3\x81\x78\x5a\xfd\x1e\x3f\x82\x8e\x58\xc7\x8d\xb8\xc0\xce\xf8\x6f\x4f\x92\x30\x51\x49\x24\x14\xc6\x55\xa0\x4b\x90\xf3\x9c\xd5\xde\x9a\xc9\x55\x94\x53\x68\x49\x41\xdf\x5b\x78\xc9\x40\xca\x3a\x59\xce\x1b\x62\x7a\x0c\x51\x70\x94\x07\xa6\x8a\xf0\x4a\xa2\xce\xbf\xc6\xd1\x15\xb7\x9a\x20\x6e\x1c\xf9\x04\x4d\x13\x23\x2f\x6f\x6b\x29\x97\xb2\x9d\xda\x65\xc2\x3c\x8b\xe8\x82\xf1\x1d\xe1\xcb\x40\xfd\x7a\x3b\xbf\x77\x6e\x14\x1f\x0a\x6d\xa9\xbd\xb0\x59\xb3\xe8\x77\x4d\x76\x2d\x13\x9f\xab\x68\xdf\xf5\x35\x0f\x2e\xcc\xc0\xa4\x99\x48\x75\xbd\x8d\x98\x36\xb8\x7c\x4c\x2b\xe1\x57\xbb\x40\xa5\xe5\x7a\x86\x11\x07\x7f\x21\xe6\xe2\x3a\x22\xaf\xbd\xef\xe8\x48\x3c\x2b\x0e\x34\x75\x47\x8e\xaa\xce\xfd\xfc\xfe\xff\xfe\x5c\xac\xcf\xae\xcf\xe2\xf9\xfc\xaa\xe2\xf1\xfb\xe9\xfb\xeb\xd3\x97\x7e\x70\xbf\x73\xbf\xbd\x60\x42\x3a\xf4\xc9\x04\x1d\x89\x14\x72\x4b\x0c\xcf\xe0\xf9\xfc\xaa\xe2\xdc\xfb\xe7\xcf\xe9\x7f\xeb\xd3\x97\x7e\x70\xbf\x73\xbf\xbd\x60\x42\x3a\xf4\xc9\x04\x1d\x89\x14\x72\x4b\x0c\xcf\xf0\xf9\xfc\xaa\xe2\xec\xfe\xfe\x00\xfb\xfa\xcf\xfc\xfe\xfe\x00\xcf\xf2\xf9\xf6\xd5\x79\xb7\x79\x08\xf2\xfe\xfe\xf4\xfa\xff\xfc\x7d\xfe\xfe\xff\xf3\xfe\xca\xcd\x47\x18\x69\x45\xc1\xac\x73\x87\xbe\x54\x64\x80\x1d\x85\x7f\xa5\x36\x77\xf9\xd6\xd7\x06\xaf\x80\x33\x49\x33\xcb\xfc\xba\xcd\x86\x9c\x18\x21\x63\xb9\xd6\x0b\x50\xcd\x8d\xd9\xee\x5f\x84\xad\xdc\xf5\x2a\xae\x6e\x86\x0d\xaf\x9e\x7f\x8d\xbf\x18\x7a\x4f\xec\xe2\x67\x24\xeb\xdc\xa6\x5b\x43\x16\x1f\xe4\x3f\xc7\xcc\x69\x43\x44\xa9\xb8\x33\x42\x17\xbf\xb6\x20\x55\x9b\x81\xd6\x1a\x62\xbf\x5a\xe5\xa3\xba\xe0\xa5\x88\xa6\x01\x85\x47\x07\xb2\x3b\x64\xce\x19\xf7\x3b\x6a\x05\x6e\x70\x6e\x60\xc3\x3b\x7d\x46\x0e\x92\x57\x59\x3b\xf6\x4e\x16\x57\x9f\x64\x55\xb3\x86\x0f\x66\x47\x52\x9c\x4e\x1b\x3f\x50\x0f\x20\x36\xcc\xac\xb2\xf6\x1b\xc0\x72\x61\xc7\x39\x6c\x00\x33\x6e\xb9\x81\x98\xd7\x9e\x55\x38\xf4\x1d\x27\x73\x1b\x13\x72\xbb\x18\x95\xeb\x87\x6e\x82\x13\x38\xf8\x12\x36\xa7\x24\xca\x2b\x8f\xf9\xf9\xc6\x72\xb4\x7f\xd3\x49\x57\x86\xa3\x6b\xea\x93\xcb\xf9\xa3\x28\x3a\xbd\x3f\x8d\xfe\x8e\xf8\x0a\xda\x95\x2f\xdb\x79\x32\xe4\xde\xf8\x51\xbf\x07\x3e\x1b\xdc\xf2\x5f\x3f\xdc\x0f\xf8\x45\x23\xcb\xa2\xb8\x30\xb4\x84\x2a\xa2",
},
};
qbyte *r, *t;
size_t i, j, sz;
for (i = 0; i < countof(knowncerts); i++)
{
t = knowncerts[i].data;
for (j = 0; ; j++)
{
if (certname[j] != (t[j]^0xff))
break;
if (!certname[j])
{
j++;
t+=j;
sz = t[0] | (t[1]<<8);
t += 2;
r = BZ_Malloc(sz);
*size = sz;
while(sz --> 0)
r[sz] = t[sz]^0xff;
return r;
}
}
}
*size = 0;
//return Z_StrDup(""); //to force failure... gnutls debug code will dump out a cert that can be inserted above.
return NULL;
}
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver)
{
vfsfile_t *f = NULL;
@ -4058,7 +4115,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
;
#endif
#ifdef HAVE_SERVER
else if (!strcmp(name, "index.html"))
/*else if (!strcmp(name, "index.html"))
{
resp = "HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html\r\n";
@ -4069,11 +4126,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
"<meta charset='utf-8'>"
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"
"<meta name=viewport content='width=device-width, initial-scale=1'>"
#ifdef _WIN32
"<link rel='icon' type='image/vnd.microsoft.icon' href='/favicon.ico' />"
#else
"<link rel='icon' type='image/vnd.microsoft.icon' href='"ENGINEWEBSITE"/favicon.ico' />"
#endif
"<title>%s - %s</title>"
"<style>"
"body { background-color:#000000; color:#808080; height:100%%;width:100%%;margin:0;padding:0;}"
@ -4088,7 +4141,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
"</body>"
"</html>"
,fs_manifest->formalname, hostname.string, ENGINEWEBSITE, fs_manifest->installation, (st->remoteaddr.prot==NP_TLS)?"wss://":"ws://", arg[WCATTR_HOST]);
}
}*/
/*else if (!strcmp(name, "default.fmf") && (st->dlfile = FS_OpenVFS("default.fmf", "rb", FS_ROOT)))
{
resp = "HTTP/1.1 200 Ok\r\n"
@ -4270,7 +4323,8 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
resp = "HTTP/1.1 404 File Not Found\r\n"
"Content-Type: text/html\r\n";
body = "This is a Quake WebSocket server, not an http server.<br/>\r\n"
"<a href='"ENGINEWEBSITE"'>"FULLENGINENAME"</a>";
//"<a href='"ENGINEWEBSITE"'>"FULLENGINENAME"</a>"
;
}
st->clienttype = TCPC_HTTPCLIENT;

View File

@ -382,6 +382,7 @@ void FTENET_CloseCollection(ftenet_connections_t *col);
qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot);
int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_generic_connection_s **con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses);
void *TLS_GetKnownCertificate(const char *certname, size_t *size);
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server);
int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize); //datasize should be preinitialised to the max length allowed. -1 for not implemented. 0 for peer problems. 1 for success
#ifdef HAVE_PACKET

View File

@ -20,6 +20,7 @@ static char *cvargroup_progs = "Progs variables";
cvar_t utf8_enable = CVARD("utf8_enable", "0", "When 1, changes the qc builtins to act upon codepoints instead of bytes. Do not use unless com_parseutf8 is also set.");
cvar_t sv_gameplayfix_nolinknonsolid = CVARD("sv_gameplayfix_nolinknonsolid", "1", "When 0, setorigin et al will not link the entity into the collision nodes (which is faster, especially if you have a lot of non-solid entities. When 1, allows entities to freely switch between .solid values (except for SOLID_BSP) without relinking. A lot of DP mods assume a value of 1 and will bug out otherwise, while 0 will restore a bugs present in various mods.");
cvar_t sv_gameplayfix_blowupfallenzombies = CVARD("sv_gameplayfix_blowupfallenzombies", "0", "Allow findradius to find non-solid entities. This may break certain mods. It is better for mods to use FL_FINDABLE_NONSOLID instead.");
cvar_t sv_gameplayfix_findradiusdistancetobox = CVARD("sv_gameplayfix_findradiusdistancetobox", "0", "When 1, findradius checks to the nearest part of the entity instead of only its origin, making it find slightly more entities.");
cvar_t sv_gameplayfix_droptofloorstartsolid = CVARD("sv_gameplayfix_droptofloorstartsolid", "0", "When droptofloor fails, this causes a second attemp, but with traceline instead.");
cvar_t dpcompat_findradiusarealinks = CVARD("dpcompat_findradiusarealinks", "0", "Use the world collision info to accelerate findradius instead of looping through every single entity. May actually be slower for large radiuses, or fail to find entities which have not been linked properly with setorigin.");
#ifdef HAVE_LEGACY
@ -76,6 +77,7 @@ void PF_Common_RegisterCvars(void)
Cvar_Register (&sv_gameplayfix_blowupfallenzombies, cvargroup_progs);
Cvar_Register (&sv_gameplayfix_findradiusdistancetobox, cvargroup_progs);
Cvar_Register (&sv_gameplayfix_nolinknonsolid, cvargroup_progs);
Cvar_Register (&sv_gameplayfix_droptofloorstartsolid, cvargroup_progs);
Cvar_Register (&dpcompat_findradiusarealinks, cvargroup_progs);
@ -1484,20 +1486,20 @@ void QCBUILTIN PF_cvar_type (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
int ret = 0;
cvar_t *v;
v = Cvar_FindVar(str); //this builtin MUST NOT create cvars implicitly, otherwise there would be no way to test if it exists.
if (v && !(v->flags & CVAR_NOUNSAFEEXPAND))
cvar_t *v = Cvar_FindVar(str); //this builtin MUST NOT create cvars implicitly, otherwise there would be no way to test if it exists.
if (v)
{
ret |= 1; // CVAR_EXISTS
if(v->flags & CVAR_ARCHIVE)
ret |= 2; // CVAR_TYPE_SAVED
if(v->flags & CVAR_NOTFROMSERVER)
if(v->flags & (CVAR_NOTFROMSERVER|CVAR_NOUNSAFEEXPAND))
ret |= 4; // CVAR_TYPE_PRIVATE
if(!(v->flags & CVAR_USERCREATED))
ret |= 8; // CVAR_TYPE_ENGINE
if (v->description)
ret |= 16; // CVAR_TYPE_HASDESCRIPTION
if (v->flags & CVAR_NOSET)
ret |= 32; // CVAR_TYPE_READONLY
}
G_FLOAT(OFS_RETURN) = ret;
}
@ -1550,6 +1552,7 @@ void QCBUILTIN PF_cvar_setf (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
void QCBUILTIN PF_registercvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *name, *value;
int flags = (prinst->callargc>2)?G_FLOAT(OFS_PARM2):0;
value = PR_GetStringOfs(prinst, OFS_PARM0);
if (Cvar_FindVar(value))
@ -1562,8 +1565,10 @@ void QCBUILTIN PF_registercvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_
else
value = "";
flags &= CVAR_ARCHIVE;
// archive?
if (Cvar_Get(name, value, CVAR_USERCREATED, "QC created vars"))
if (Cvar_Get(name, value, CVAR_USERCREATED|flags, "QC created vars"))
G_FLOAT(OFS_RETURN) = 1;
else
G_FLOAT(OFS_RETURN) = 0;
@ -2186,19 +2191,19 @@ void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
G_INT(OFS_RETURN) = 0; //EOF
if (fnum < 0 || fnum >= MAX_QC_FILES)
{
PR_BIError(prinst, "PF_fgets: File out of range\n");
PF_Warningf(prinst, "PF_fgets: File out of range (%g)\n", G_FLOAT(OFS_PARM0));
return; //out of range
}
if (!pf_fopen_files[fnum].prinst)
{
PR_BIError(prinst, "PF_fgets: File is not open\n");
PF_Warningf(prinst, "PF_fgets: File is not open\n");
return; //not open
}
if (pf_fopen_files[fnum].prinst != prinst)
{
PR_BIError(prinst, "PF_fgets: File is from wrong instance\n");
PF_Warningf(prinst, "PF_fgets: File is from wrong instance\n");
return; //this just isn't ours.
}
@ -2984,10 +2989,21 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
for (i=0 ; i<numents ; i++)
{
ent = nearent[i];
if (ent->v->solid == SOLID_NOT && (!((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.value)
if (ent->v->solid == SOLID_NOT && (!((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.ival)
continue;
for (j=0 ; j<3 ; j++)
eorg[j] = org[j] - (ent->v->origin[j] + (ent->v->mins[j] + ent->v->maxs[j])*0.5);
if (sv_gameplayfix_findradiusdistancetobox.ival)
{
for (j=0 ; j<3 ; j++)
{
eorg[j] = org[j] - ent->v->origin[j];
eorg[j] -= bound(ent->v->mins[j], org[j], ent->v->maxs[j]);
}
}
else
{
for (j=0 ; j<3 ; j++)
eorg[j] = org[j] - (ent->v->origin[j] + (ent->v->mins[j] + ent->v->maxs[j])*0.5);
}
if (DotProduct(eorg,eorg) > rad)
continue;
@ -3005,8 +3021,19 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
continue;
if (ent->v->solid == SOLID_NOT && (!((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.value)
continue;
for (j=0 ; j<3 ; j++)
eorg[j] = org[j] - (ent->v->origin[j] + (ent->v->mins[j] + ent->v->maxs[j])*0.5);
if (sv_gameplayfix_findradiusdistancetobox.ival)
{
for (j=0 ; j<3 ; j++)
{
eorg[j] = org[j] - ent->v->origin[j];
eorg[j] -= bound(ent->v->mins[j], org[j], ent->v->maxs[j]);
}
}
else
{
for (j=0 ; j<3 ; j++)
eorg[j] = org[j] - (ent->v->origin[j] + (ent->v->mins[j] + ent->v->maxs[j])*0.5);
}
if (DotProduct(eorg,eorg) > rad)
continue;
@ -4168,11 +4195,11 @@ void QCBUILTIN PF_buf_copy (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
strbuflist[bufto].strings[i] = strbuflist[buffrom].strings[i]?Z_StrDup(strbuflist[buffrom].strings[i]):NULL;
}
static int PF_buf_sort_sortprefixlen;
static int QDECL PF_buf_sort_ascending(const void *a, const void *b)
static int QDECL PF_buf_sort_ascending_prefix(const void *a, const void *b)
{
return strncmp(*(char**)a, *(char**)b, PF_buf_sort_sortprefixlen);
}
static int QDECL PF_buf_sort_descending(const void *b, const void *a)
static int QDECL PF_buf_sort_descending_prefix(const void *b, const void *a)
{
return strncmp(*(char**)a, *(char**)b, PF_buf_sort_sortprefixlen);
}
@ -4208,9 +4235,9 @@ void QCBUILTIN PF_buf_sort (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//no nulls now, sort it.
PF_buf_sort_sortprefixlen = sortprefixlen; //eww, a global. burn in hell.
if (backwards) //z first
qsort(strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_descending);
qsort(strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_descending_prefix);
else //a first
qsort(strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_ascending);
qsort(strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_ascending_prefix);
}
// #445 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_buf_implode (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4269,18 +4296,18 @@ void QCBUILTIN PF_bufstr_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if ((unsigned int)bufno >= strbufmax)
{
RETURN_CSTRING("");
G_INT(OFS_RETURN) = 0;
return;
}
if (strbuflist[bufno].prinst != prinst)
{
RETURN_CSTRING("");
G_INT(OFS_RETURN) = 0;
return;
}
if (index >= strbuflist[bufno].used)
{
RETURN_CSTRING("");
G_INT(OFS_RETURN) = 0;
return;
}
@ -4391,6 +4418,10 @@ void QCBUILTIN PF_bufstr_free (pubprogfuncs_t *prinst, struct globalvars_s *pr_
strbuflist[bufno].strings[index] = NULL;
}
static int QDECL PF_buf_sort_ascending(const void *a, const void *b)
{
return strcmp(*(char**)a, *(char**)b);
}
void QCBUILTIN PF_buf_cvarlist (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
size_t bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
@ -4400,6 +4431,9 @@ void QCBUILTIN PF_buf_cvarlist (pubprogfuncs_t *prinst, struct globalvars_s *pr
cvar_group_t *grp;
cvar_t *var;
extern cvar_group_t *cvar_groups;
int plen = strlen(pattern), alen = strlen(antipattern);
qboolean pwc = strchr(pattern, '*')||strchr(pattern, '?'),
awc = strchr(antipattern, '*')||strchr(antipattern, '?');
if (bufno >= strbufmax)
return;
@ -4410,19 +4444,22 @@ void QCBUILTIN PF_buf_cvarlist (pubprogfuncs_t *prinst, struct globalvars_s *pr
for (i = 0; i < strbuflist[bufno].used; i++)
Z_Free(strbuflist[bufno].strings[i]);
Z_Free(strbuflist[bufno].strings);
strbuflist[bufno].strings = NULL;
strbuflist[bufno].used = strbuflist[bufno].allocated = 0;
//ignore name2, no point listing it twice.
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
{
if (pattern && wildcmp(pattern, var->name))
if (plen && (pwc?wildcmp(pattern, var->name):strncmp(var->name, pattern, plen)))
continue;
if (antipattern && !wildcmp(antipattern, var->name))
if (alen && (awc?!wildcmp(antipattern, var->name):!strncmp(var->name, antipattern, alen)))
continue;
PF_bufstr_add_internal(bufno, var->name, true);
}
qsort(strbuflist[bufno].strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_ascending);
}
//directly reads a file into a stringbuffer
@ -4693,15 +4730,16 @@ static void PR_uri_get_callback2(int iarg, void *data)
G_FLOAT(OFS_PARM0) = id;
G_FLOAT(OFS_PARM1) = (replycode!=200)?replycode:0; //for compat with DP, we change any 200s to 0.
G_INT(OFS_PARM2) = 0;
G_INT(OFS_PARM3) = 0;
if (ctx->file)
{
len = VFS_GETLEN(ctx->file);
buffer = malloc(len+1);
buffer[len] = 0;
VFS_READ(ctx->file, buffer, len);
G_INT(OFS_PARM2) = PR_TempString(prinst, buffer);
free(buffer);
G_INT(OFS_PARM2) = prinst->AllocTempString(prinst, &buffer, len+1);
len = VFS_READ(ctx->file, buffer, len);
if (len < 0)
buffer[len] = 0;
G_INT(OFS_PARM3) = len;
}
PR_ExecuteProgram(prinst, func);
@ -4749,7 +4787,7 @@ void QCBUILTIN PF_uri_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
if (!pr_enable_uriget.ival)
{
Con_Printf("PF_uri_get(\"%s\",%g): %s disabled\n", url, id, pr_enable_uriget.name);
Con_Printf("%s: blocking \"%s\"\n", pr_enable_uriget.name, url);
G_FLOAT(OFS_RETURN) = 0;
return;
}

View File

@ -39,8 +39,6 @@ struct wedict_s
/*the above is shared with ssqc*/
};
#define PF_drawline PF_Fixme
#define G_PROG G_FLOAT
//the lh extension system asks for a name for the extension.
@ -444,6 +442,7 @@ void QCBUILTIN PF_cl_getkeybind (pubprogfuncs_t *prinst, struct globalvars_s *pr
void QCBUILTIN PF_cl_setkeybind (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_setmousetarget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_getmousetarget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_setmousepos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_setcursormode (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_getcursormode (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_setwindowcaption (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -737,6 +736,7 @@ typedef enum
VF_ENVMAP = 220, //cubemap image for reflectcube
VF_USERDATA = 221,
VF_SKYROOM_CAMERA = 222,
VF_PIXELPSCALE = 223, //[dpi_x, dpi_y, dpi_y/dpi_x]
} viewflags;
/*FIXME: this should be changed*/

View File

@ -62,7 +62,7 @@ void SHA1Transform(unsigned int state[5], const unsigned char buffer[64])
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static unsigned char workspace[64];
unsigned char workspace[64];
block = (CHAR64LONG16*)workspace;
memcpy(block, buffer, 64);
#else

View File

@ -228,14 +228,6 @@ struct world_s
areagridlink_t *gridareas; //[gridsize[0]*gridsize[1]]
areagridlink_t jumboarea; //node containing ents too large to fit.
areagridlink_t portallist;
#else
areanode_t portallist;
#endif
#if defined(Q2SERVER) || !defined(USEAREAGRID)
areanode_t *areanodes;
int areanodedepth;
int numareanodes;
#endif
double physicstime; // the last time global physics were run
@ -274,6 +266,15 @@ struct world_s
rigidbodyengine_t *rbe;
#endif
#if defined(Q2SERVER) || !defined(USEAREAGRID)
areanode_t *areanodes;
int areanodedepth;
int numareanodes;
#ifndef USEAREAGRID
areanode_t portallist;
#endif
#endif
#ifdef ENGINE_ROUTING
void *waypoints;
#endif

View File

@ -482,7 +482,11 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, struct programpermu_s *perm
consts++;
defines[consts].Name = "ENGINE_"DISTRIBUTION;
defines[consts].Definition = __DATE__;
#ifdef SVNREVISION
defines[consts].Definition = STRINGIFY(SVNREVISION);
#else
defines[consts].Definition = "0";
#endif
consts++;
tmp = Z_Malloc(64);

View File

@ -289,7 +289,11 @@ static qboolean D3D9Shader_CreateProgram (program_t *prog, struct programpermu_s
consts++;
defines[consts].Name = "ENGINE_"DISTRIBUTION;
defines[consts].Definition = __DATE__;
#ifdef SVNREVISION
defines[consts].Definition = STRINGIFY(SVNREVISION);
#else
defines[consts].Definition = "0";
#endif
consts++;
for (defbufe = defbuf; *precompilerconstants; precompilerconstants++)

View File

@ -298,6 +298,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
skin->mappings[skin->nummappings].shader = R_RegisterSkin(shadername, skin->skinname);
R_BuildDefaultTexnums(NULL, skin->mappings[skin->nummappings].shader, 0);
skin->mappings[skin->nummappings].texnums = *skin->mappings[skin->nummappings].shader->defaulttextures;
skin->mappings[skin->nummappings].needsfree = false;
skin->nummappings++;
}
}
@ -398,6 +399,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
skin->mappings[skin->nummappings].shader = R_RegisterCustom (shadername, 0, Shader_DefaultSkin, NULL);
R_BuildDefaultTexnums(NULL, skin->mappings[skin->nummappings].shader, 0);
skin->mappings[skin->nummappings].texnums = *skin->mappings[skin->nummappings].shader->defaulttextures;
skin->mappings[skin->nummappings].needsfree = false;
skin->nummappings++;
}
}

View File

@ -1,6 +1,11 @@
#include "quakedef.h"
//#define FORCESTATE
#ifdef _DEBUG
#define DRAWCALL(f) if (developer.ival==-1) Con_Printf(f " (shader %s, ent %i)\n", shaderstate.curshader->name, (shaderstate.curbatch && shaderstate.curbatch->ent)?shaderstate.curbatch->ent->keynum:0)
#else
#define DRAWCALL(f)
#endif
void DumpGLState(void);
@ -34,7 +39,7 @@ extern texid_t scenepp_postproc_cube;
extern texid_t r_whiteimage;
#ifdef GLQUAKE
static texid_t shadowmap[2];
static texid_t shadowmap[3];
static int shadow_fbo_id;
static int shadow_fbo_depth_num;
#endif
@ -49,6 +54,7 @@ static const char LIGHTPASS_SHADER[] = "\
\
{\n\
map $diffuse\n\
nodepth\n\
blendfunc add\n\
}\n\
{\n\
@ -947,6 +953,7 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
qglDrawRangeElements(GL_TRIANGLES, 0, numverts - 1, numindicies, GL_INDEX_TYPE, indicies);
}
RQuantAdd(RQUANT_DRAWS, 1);
DRAWCALL("GLBE_RenderShadowBuffer");
RQuantAdd(RQUANT_SHADOWINDICIES, numindicies);
shaderstate.dummyvbo.indicies.gl.vbo = 0;
shaderstate.sourcevbo = NULL;
@ -1075,15 +1082,20 @@ void GLBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float sha
}
int GLBE_BeginRenderBuffer_DepthOnly(texid_t depthtexture);
qboolean GLBE_BeginShadowMap(int id, int w, int h, int *restorefbo)
qboolean GLBE_BeginShadowMap(int id, int w, int h, uploadfmt_t encoding, int *restorefbo)
{
if (!gl_config.ext_framebuffer_objects)
return false;
if (!TEXVALID(shadowmap[id]))
if (!TEXVALID(shadowmap[id]) || shadowmap[id]->width != w || shadowmap[id]->height != h || shadowmap[id]->format != encoding)
{
uploadfmt_t encoding = PTI_DEPTH16;
texid_t tex = shadowmap[id] = Image_CreateTexture(va("***shadowmap2d%i***", id), NULL, 0);
texid_t tex;
if (shadowmap[id])
Image_DestroyTexture(shadowmap[id]);
tex = shadowmap[id] = Image_CreateTexture(va("***shadowmap2d%i***", id), NULL, 0);
tex->width = w;
tex->height = h;
tex->format = encoding;
qglGenTextures(1, &tex->num);
GL_MTBind(0, GL_TEXTURE_2D, tex);
#ifdef SHADOWDBG_COLOURNOTDEPTH
@ -1113,6 +1125,7 @@ qboolean GLBE_BeginShadowMap(int id, int w, int h, int *restorefbo)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
}
tex->status = TEX_LOADED;
}
shaderstate.curshadowmap = shadowmap[id];
@ -1517,7 +1530,7 @@ void GLBE_DestroyFBOs(void)
shadow_fbo_id = 0;
shadow_fbo_depth_num = 0;
}
for (i = 0; i < 2; i++)
for (i = 0; i < countof(shadowmap); i++)
{
if (shadowmap[i])
{
@ -2450,7 +2463,7 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
mid[1] = 0.25*(src[0][1] + src[1][1] + src[2][1] + src[3][1]);
mid[2] = 0.25*(src[0][2] + src[1][2] + src[2][2] + src[3][2]);
VectorSubtract(src[0], mid, d);
radius = VectorLength(d);
radius = VectorLength(d) * 0.707;
mid2[0] = 0.25*(st[0][0] + st[1][0] + st[2][0] + st[3][0]);
mid2[1] = 0.25*(st[0][1] + st[1][1] + st[2][1] + st[3][1]);
@ -3113,6 +3126,7 @@ static void BE_SubmitMeshChain(qboolean usetesselation)
mesh = shaderstate.meshes[0];
qglDrawRangeElements(batchtype, mesh->vbofirstvert, mesh->vbofirstvert+mesh->numvertexes - 1, mesh->numindexes, GL_INDEX_TYPE, (index_t*)shaderstate.sourcevbo->indicies.gl.addr + mesh->vbofirstelement);
RQuantAdd(RQUANT_DRAWS, 1);
DRAWCALL("BE_SubmitMeshChain 1");
RQuantAdd(RQUANT_PRIMITIVEINDICIES, mesh->numindexes);
return;
}
@ -3148,6 +3162,7 @@ static void BE_SubmitMeshChain(qboolean usetesselation)
}
qglDrawRangeElements(batchtype, startv, endv - 1, endi, GL_INDEX_TYPE, ilst);
RQuantAdd(RQUANT_DRAWS, 1);
DRAWCALL("BE_SubmitMeshChain N");
RQuantAdd(RQUANT_PRIMITIVEINDICIES, endi);
}
return;
@ -3186,6 +3201,7 @@ static void BE_SubmitMeshChain(qboolean usetesselation)
{
qglMultiDrawElements(batchtype, counts, GL_INDEX_TYPE, indicies, drawcount);
RQuantAdd(RQUANT_DRAWS, drawcount);
DRAWCALL("BE_SubmitMeshChain MultiDraw");
drawcount = 0;
}
counts[drawcount] = endi-starti;
@ -3195,6 +3211,7 @@ static void BE_SubmitMeshChain(qboolean usetesselation)
}
qglMultiDrawElements(batchtype, counts, GL_INDEX_TYPE, indicies, drawcount);
RQuantAdd(RQUANT_DRAWS, drawcount);
DRAWCALL("BE_SubmitMeshChain MultiDraw");
}
#if 0 //def FTE_TARGET_WEB
else if (shaderstate.meshcount > 1)
@ -3271,6 +3288,7 @@ static void BE_SubmitMeshChain(qboolean usetesselation)
}
qglDrawRangeElements(batchtype, startv, endv - 1, endi-starti, GL_INDEX_TYPE, (index_t*)shaderstate.sourcevbo->indicies.gl.addr + starti);
RQuantAdd(RQUANT_DRAWS, 1);
DRAWCALL("BE_SubmitMeshChain Fallback");
RQuantAdd(RQUANT_PRIMITIVEINDICIES, endi-starti);
}
/*
@ -6273,8 +6291,6 @@ void GLBE_DrawWorld (batch_t **worldbatches)
// else
// shaderstate.updatetime = cl.servertime;
GLBE_SelectEntity(&r_worldentity);
BE_UpdateLightmaps();
if (worldbatches)
{
@ -6320,11 +6336,16 @@ void GLBE_DrawWorld (batch_t **worldbatches)
#ifdef RTLIGHTS
if (r_lightprepass)
{
GLBE_SelectEntity(&r_worldentity);
GLBE_DrawLightPrePass();
}
else
#endif
{
if (r_fakeshadows)
Sh_GenerateFakeShadows();
GLBE_SelectEntity(&r_worldentity);
if (shaderstate.identitylighting == 0)
BE_SelectMode(BEM_DEPTHDARK);
else
@ -6401,6 +6422,7 @@ void GLBE_DrawWorld (batch_t **worldbatches)
}
else
{
GLBE_SelectEntity(&r_worldentity);
GLBE_SubmitMeshes(NULL, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
#ifdef GL_LINE //no gles

View File

@ -518,7 +518,8 @@ void GLDraw_Init (void)
if (scr_showloading.ival)
{
mpic_t *pic = R2D_SafeCachePic ("gfx/loading.lmp");
extern cvar_t scr_loadingscreen_picture;
mpic_t *pic = R2D_SafeCachePic (scr_loadingscreen_picture.string);
if (pic && R_GetShaderSizes(pic, NULL, NULL, true))
{ //if its too big for the screen, letterbox it.
qglClearColor(0, 0, 0, 1);

View File

@ -15,7 +15,7 @@
void Font_Init(void);
void Font_Shutdown(void);
struct font_s *Font_LoadFont(const char *fontfilename, float height);
struct font_s *Font_LoadFont(const char *fontfilename, float height, float scale, int outline);
void Font_Free(struct font_s *f);
void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py);
void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/
@ -43,6 +43,8 @@ extern unsigned int r2d_be_flags;
#ifdef AVAIL_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
struct fontface_s;
int Font_ChangeFTSize(struct fontface_s *qface, int pixelheight);
#ifndef FT_LOAD_COLOR
#define FT_LOAD_COLOR (1L<<20)
@ -257,8 +259,8 @@ typedef struct fontface_s
#ifdef AVAIL_FREETYPE
struct
{
int activeheight; //needs reconfiguring when different sizes are used
int actualsize; //sometimes that activeheight isn't usable. :(
int activeheight; //needs reconfiguring when different sizes are used (so the same face can be used at multiple different sizes
int actualsize; //sometimes that activeheight isn't usable and we need to manually rescale. :(
FT_Face face;
void *membuf;
} ft;
@ -300,7 +302,10 @@ typedef struct font_s
char name[MAX_OSPATH];
texid_t singletexture;
unsigned short charheight;
unsigned short charheight; //requested height (space between lines)
unsigned short truecharheight; //what you actually got, for compat with dp's lets-use-the-wrong-size-for-double-padding-between-lines thing.
float scale; //some sort of poop
short outline;
unsigned short faces;
fontface_t *face[MAX_FACES];
@ -353,7 +358,7 @@ static avec4_t font_foretint;
static struct font_s *curfont;
static float curfont_scale[2];
static qboolean curfont_scaled;
//static qboolean curfont_scaled;
extern cvar_t r_font_linear;
@ -625,13 +630,21 @@ static struct charcache_s *Font_CopyChar(font_t *f, unsigned int oldcharidx, uns
//loads a new image into a given character slot for the given font.
//note: make sure it doesn't already exist or things will get cyclic
//alphaonly says if its a greyscale image. false means rgba.
static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT_Pixel_Mode pixelmode, void *data, unsigned int bmw, unsigned int bmh, unsigned int pitch)
{
static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT_Pixel_Mode pixelmode, void *data, unsigned int bmw, unsigned int bmh, unsigned int pitch){
int x, y;
union byte_vec4_u *out;
struct charcache_s *c = Font_GetCharStore(f, charidx);
int pad = 0;
#define BORDERCOLOUR 0
#define MAXOUTLINE 4
int outline = min(f->outline, MAXOUTLINE);
if (!bmw || !bmh)
outline = 0;
pad+=outline;
if (fontplanes.texnum[0]->flags & IF_LINEAR)
pad += 1; //pad the image data to avoid sampling outside
@ -789,6 +802,49 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT
c->flags = CHARF_FORCEWHITE; //private glyph colours
}
if (outline)
{
int bytes = (pixelmode == FT_PIXEL_MODE_GRAY)?1:4;
qbyte *alpha = (char*)data + bytes-1 - pitch*bmh;
static int filter_outline;
static unsigned char filter_highest[MAXOUTLINE*2+1][MAXOUTLINE*2+1];
if (outline != filter_outline)
{
filter_outline = outline;
for (y = -outline; y <= outline; y++)
for (x = -outline; x <= outline; x++)
filter_highest[outline+y][outline+x] = bound(0, (outline + 1 - sqrt(x*x + y*y))*255+.5, 255);
}
//expand it to out full(ish) size
alpha -= pitch*outline + bytes*outline;
out = &fontplanes.plane[c->bmx+((int)c->bmy-outline)*PLANEHEIGHT];
for (y = -outline; y < (int)bmh+outline; y++, out += PLANEWIDTH)
for (x = -outline; x < (int)bmw+outline; x++)
{
int xn, x1 = max(outline-x, 0), x2 = min(2*outline, (int)bmw-1-x+outline);
int yn, y1 = max(outline-y, 0), y2 = min(2*outline, (int)bmh-1-y+outline);
int v, m = out[x].rgba[3]*255;
for (yn = y1; yn <= y2; yn++)
for (xn = x1; xn <= x2; xn++)
{
v = filter_highest[yn][xn] * alpha[(xn+x)*bytes+(yn+y)*pitch];
m = max(m, v);
}
//out[x].c = 0;
out[x].rgba[3] = m/255;
}
c->bmx -= outline;
c->bmy -= outline;
c->bmw += outline*2;
c->bmh += outline*2;
}
fontplanes.planechanged = true;
return c;
}
@ -1082,29 +1138,8 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
if (qface->ft.activeheight != f->charheight)
{
qface->ft.activeheight = f->charheight;
if (FT_HAS_FIXED_SIZES(face) && !FT_IS_SCALABLE(face))
{ //freetype doesn't like scaling these for us, so we have to pick a usable size ourselves.
FT_Int best = 0, s;
int bestheight = 0, h;
for (s = 0; s < qface->ft.face->num_fixed_sizes; s++)
{
h = qface->ft.face->available_sizes[s].height;
//always try to pick the smallest size that is also >= our target size
if ((h > bestheight && bestheight < f->charheight) || (h >= f->charheight && h < bestheight))
{
bestheight = h;
best = s;
}
}
qface->ft.actualsize = qface->ft.face->available_sizes[best].height;
pFT_Select_Size(face, best);
}
else
{
pFT_Set_Pixel_Sizes(face, 0, f->charheight);
qface->ft.actualsize = f->charheight;
}
if (!Font_ChangeFTSize(qface, f->charheight))
return NULL; //some sort of error.
}
if (charidx == 0xfffe || pFT_Get_Char_Index(face, charidx)) //ignore glyph 0 (undefined)
if (pFT_Load_Char(face, charidx, FT_LOAD_RENDER|FT_LOAD_COLOR) == 0)
@ -1157,7 +1192,10 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
{
c->advance = slot->advance.x >> 6;
c->left = slot->bitmap_left;
c->top = f->charheight*3/4 - slot->bitmap_top;
/*if(1)
c->top = f->truecharheight - slot->bitmap_top;
else*/
c->top = f->charheight*3/4 - slot->bitmap_top;
return c;
}
}
@ -1414,6 +1452,57 @@ qboolean Font_LoadHorizontalFont(struct font_s *f, int fheight, const char *font
}
#ifdef AVAIL_FREETYPE
extern cvar_t dpcompat_smallerfonts;
int Font_ChangeFTSize(fontface_t *qface, int pixelheight)
{
FT_Face face = qface->ft.face;
qface->ft.activeheight = pixelheight;
#ifdef HAVE_LEGACY
if (dpcompat_smallerfonts.ival)
{ //sizes specified include extra spacing in dp, giving extra padding somewhere.
int s = pixelheight;
for(s = pixelheight; s; s--)
{
if (0==pFT_Set_Pixel_Sizes(face, 0, s))
if (face->size->metrics.height>>6 <= pixelheight)
break;
}
if (!s)
{
qface->ft.activeheight = 0; //something invalid
qface->ft.actualsize = qface->ft.activeheight;
return 0;
}
qface->ft.actualsize = qface->ft.activeheight;
return s;
}
else
#endif
if (FT_HAS_FIXED_SIZES(face) && !FT_IS_SCALABLE(face))
{ //freetype doesn't like scaling these for us, so we have to pick a usable size ourselves.
FT_Int best = 0, s;
int bestheight = 0, h;
for (s = 0; s < qface->ft.face->num_fixed_sizes; s++)
{
h = qface->ft.face->available_sizes[s].height;
//always try to pick the smallest size that is also >= our target size
if ((h > bestheight && bestheight < pixelheight) || (h >= pixelheight && h < bestheight))
{
bestheight = h;
best = s;
}
}
qface->ft.actualsize = qface->ft.face->available_sizes[best].height;
pFT_Select_Size(face, best);
}
else
{
pFT_Set_Pixel_Sizes(face, 0, pixelheight);
qface->ft.actualsize = pixelheight;
}
return pixelheight;
}
qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfilename)
{
fontface_t *qface;
@ -1436,6 +1525,8 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfil
if (!strcmp(qface->name, fontfilename) && qface->ft.face)
{
qface->refs++;
if (!f->faces)
f->truecharheight = Font_ChangeFTSize(qface, f->charheight);
f->face[f->faces++] = qface;
return true;
}
@ -1487,7 +1578,7 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfil
}
error = FT_Err_Cannot_Open_Resource;
if (FS_FLocateFile(fontfilename, FSLF_IFFOUND, &loc) || FS_FLocateFile(va("%s.ttf", fontfilename), FSLF_IFFOUND, &loc))
if (FS_FLocateFile(fontfilename, FSLF_IFFOUND, &loc) || FS_FLocateFile(va("%s.ttf", fontfilename), FSLF_IFFOUND, &loc) || FS_FLocateFile(va("%s.otf", fontfilename), FSLF_IFFOUND, &loc))
{
if (*loc.rawname && !loc.offset)
{
@ -1555,31 +1646,30 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfil
#endif
if (!error)
{
if (FT_HAS_FIXED_SIZES(face) && !FT_IS_SCALABLE(face))
{
height = 0; //will need to rescale manually I guess
error = pFT_Select_Size(face, 0);
}
else
error = pFT_Set_Pixel_Sizes(face, 0, height);
if (!error)
{
/*success!*/
qface = Z_Malloc(sizeof(*qface));
int trueheight;
/*success!*/
qface = Z_Malloc(sizeof(*qface));
qface->ft.face = face;
qface->ft.activeheight = qface->ft.actualsize = 0;//height;
qface->ft.membuf = fbase;
qface->refs++;
Q_strncpyz(qface->name, fontfilename, sizeof(qface->name));
trueheight = Font_ChangeFTSize(qface, f->charheight);
if (trueheight)
{ //okay, we can use it, link it in.
qface->flink = &faces;
qface->fnext = *qface->flink;
*qface->flink = qface;
if (qface->fnext)
qface->fnext->flink = &qface->fnext;
qface->ft.face = face;
qface->ft.activeheight = qface->ft.actualsize = height;
qface->ft.membuf = fbase;
qface->refs++;
Q_strncpyz(qface->name, fontfilename, sizeof(qface->name));
if (!f->faces)
f->truecharheight = trueheight;
f->face[f->faces++] = qface;
return true;
}
Z_Free(qface);
}
if (error && error != FT_Err_Cannot_Open_Resource)
Con_Printf("Freetype error: %i\n", error);
@ -1864,7 +1954,7 @@ void Doom_ExpandPatch(doompatch_t *p, unsigned char *b, int stride)
//creates a new font object from the given file, with each text row with the given height.
//width is implicit and scales with height and choice of font.
struct font_s *Font_LoadFont(const char *fontfilename, float vheight)
struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scale, int outline)
{
struct font_s *f;
int i = 0;
@ -1887,7 +1977,10 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight)
*parms++ = 0;
f = Z_Malloc(sizeof(*f));
f->outline = outline;
f->scale = scale;
f->charheight = height;
f->truecharheight = height;
Q_strncpyz(f->name, fontfilename, sizeof(f->name));
switch(M_GameType())
@ -2105,7 +2198,7 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight)
}
else
{
f->alt = Font_LoadFont(aname, vheight);
f->alt = Font_LoadFont(aname, vheight, scale, outline);
if (f->alt)
{
VectorCopy(f->alt->tint, f->alttint);
@ -2360,7 +2453,7 @@ void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py)
curfont_scale[0] = curfont->charheight;
curfont_scale[1] = curfont->charheight;
curfont_scaled = false;
// curfont_scaled = false;
}
void Font_Transform(float vx, float vy, int *px, int *py)
{
@ -2384,13 +2477,15 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx,
*px = (int)*px;
*py = (int)*py;
if ((int)(szx * vid.rotpixelheight/vid.height) == curfont->charheight && (int)(szy * vid.rotpixelheight/vid.height) == curfont->charheight)
/* if ((int)(szx * vid.rotpixelheight/vid.height) == curfont->charheight && (int)(szy * vid.rotpixelheight/vid.height) == curfont->charheight)
curfont_scaled = false;
else
curfont_scaled = true;
*/
curfont_scale[0] = (szx * (float)vid.rotpixelheight) / (curfont->charheight * (float)vid.height);
curfont_scale[1] = (szy * (float)vid.rotpixelheight) / (curfont->charheight * (float)vid.height);
curfont_scale[0] *= curfont->scale;
curfont_scale[1] *= curfont->scale;
}
void Font_EndString(struct font_s *font)
@ -2410,6 +2505,10 @@ int Font_CharPHeight(struct font_s *font)
{
return font->charheight;
}
int Font_GetTrueHeight(struct font_s *font) //Char[P]Height lies for compat with DP.
{
return font->truecharheight;
}
float Font_CharVHeight(struct font_s *font)
{
return ((float)font->charheight * vid.height)/vid.rotpixelheight;

View File

@ -1186,6 +1186,7 @@ void Mod_UnRegisterAllModelFormats(void *module)
}
}
//main thread. :(
void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b)
{
qboolean previouslyfailed;

View File

@ -2048,14 +2048,16 @@ void GLR_RenderView (void)
fmt = PTI_RGBA8;
if (r_hdr_framebuffer.ival < 0)
{
{ //cvar change handler will set ival negative if it matches a known format name, doesn't mean its supported.
fmt = -r_hdr_framebuffer.ival;
if (!sh_config.texfmt[fmt])
if (fmt >= PTI_FIRSTCOMPRESSED || !sh_config.texfmt[fmt])
fmt = PTI_RGB565;
}
else if ((r_refdef.flags&RDF_SCENEGAMMA)||(vid.flags&(VID_SRGBAWARE|VID_FP16))||r_hdr_framebuffer.ival)
{ //gamma ramps really need higher colour precision, otherwise the entire thing looks terrible.
if (sh_config.texfmt[PTI_RGBA16F])
if (sh_config.texfmt[PTI_B10G11R11F])
fmt = PTI_B10G11R11F;
else if (sh_config.texfmt[PTI_RGBA16F])
fmt = PTI_RGBA16F;
else if (sh_config.texfmt[PTI_A2BGR10])
fmt = PTI_A2BGR10;

View File

@ -101,20 +101,26 @@ qboolean GLSCR_UpdateScreen (void)
if (scr_disabled_for_loading)
{
extern char levelshotname[];
extern float scr_disabled_time;
if (Sys_DoubleTime() - scr_disabled_time > 60 || !Key_Dest_Has(~kdm_game))
float now = Sys_DoubleTime();
if (now - scr_disabled_time > 60 || Key_Dest_Has(~kdm_game))
{
//FIXME: instead of reenabling the screen, we should just draw the relevent things skipping only the game.
//FIXME: instead of reenabling the screen, we should just draw the relevent things skipping only the game (except that this requires a copy of the game beneath or otherwise results in flickering).
scr_disabled_for_loading = false;
}
else if (!*levelshotname && !CSQC_UseGamecodeLoadingScreen() && !MP_UsingGamecodeLoadingScreen()
#ifdef MENU_NATIVECODE
&& !(mn_entry && mn_entry->DrawLoading)
#endif
)
return false; //don't refresh if we can't do so safely.
else
{
// scr_drawloading = true;
SCR_DrawLoading (true);
SCR_SetUpToDrawConsole();
if (Key_Dest_Has(kdm_console))
SCR_DrawConsole(false);
// scr_drawloading = false;
if (R2D_Flush)
R2D_Flush();
VID_SwapBuffers();
@ -187,7 +193,19 @@ qboolean GLSCR_UpdateScreen (void)
if (R2D_DrawLevelshot())
;
else if (scr_con_current != vid.height)
R2D_ConsoleBackground(0, vid.height, true);
{
#ifdef HAVE_LEGACY
extern cvar_t dpcompat_console;
if (dpcompat_console.ival)
{
R2D_ImageColours(0,0,0,1);
R2D_FillBlock(0, 0, vid.width, vid.height);
R2D_ImageColours(1,1,1,1);
}
else
#endif
R2D_ConsoleBackground(0, vid.height, true);
}
else
scr_con_forcedraw = true;
@ -239,12 +257,27 @@ char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum up
int i, c;
qbyte *ret;
extern qboolean r2d_canhwgamma;
qboolean hdr = false;
*bytestride = 0;
*truewidth = vid.fbpwidth;
*trueheight = vid.fbpheight;
/*if (1)
if (*r_refdef.rt_destcolour[0].texname)
{
unsigned int w,h;
texid_t tid = R2D_RT_GetTexture(r_refdef.rt_destcolour[0].texname, &w, &h);
if (tid)
hdr = (tid->format==PTI_RGBA16F)||(tid->format==PTI_RGBA32F)||(tid->format==PTI_B10G11R11F);
}
if (hdr)
{
*fmt = PTI_RGBA16F;
ret = BZ_Malloc((*truewidth)*(*trueheight)*8);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_HALF_FLOAT, ret);
*bytestride = *truewidth*-8;
}
/*else if (1)
{
float *p;
@ -261,8 +294,8 @@ char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum up
ret[i*3+2]=p[i]*p[i]*p[i]*255;
}
BZ_Free(p);
}
else*/ if (gl_config.gles || (*truewidth&3))
}*/
else if (gl_config.gles || (*truewidth&3))
{
qbyte *p;
@ -277,7 +310,7 @@ char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum up
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret);
*bytestride = *truewidth*-3;
*fmt = TF_RGB24;
*fmt = PTI_RGB8;
c = (*truewidth)*(*trueheight);
p = ret;
for (i = 1; i < c; i++)
@ -291,7 +324,7 @@ char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum up
#if 1//def _DEBUG
else if (!gl_config.gles && sh_config.texfmt[PTI_BGRA8])
{
*fmt = TF_BGRA32;
*fmt = PTI_BGRA8;
ret = BZ_Malloc((*truewidth)*(*trueheight)*4);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, ret);
*bytestride = *truewidth*-4;
@ -299,7 +332,7 @@ char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum up
#endif
else
{
*fmt = TF_RGB24;
*fmt = PTI_RGB8;
ret = BZ_Malloc((*truewidth)*(*trueheight)*3);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret);
*bytestride = *truewidth*-3;
@ -307,21 +340,23 @@ char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum up
if (gammaworks && r2d_canhwgamma)
{
if (*fmt == TF_BGRA32 || *fmt == TF_RGBA32)
if (*fmt == PTI_BGRA8 || *fmt == PTI_BGRX8 || *fmt == PTI_BGR8)
{
c = (*truewidth)*(*trueheight)*4;
for (i=0 ; i<c ; i+=4)
int pxsize = (*fmt == PTI_BGR8)?3:4;
c = (*truewidth)*(*trueheight)*pxsize;
for (i=0 ; i<c ; i+=pxsize)
{
extern qbyte gammatable[256];
ret[i+0] = gammatable[ret[i+0]];
ret[i+0] = gammatable[ret[i+2]];
ret[i+1] = gammatable[ret[i+1]];
ret[i+2] = gammatable[ret[i+2]];
ret[i+2] = gammatable[ret[i+0]];
}
}
else
else if (*fmt == PTI_RGBA8 || *fmt == PTI_RGBX8 || *fmt == PTI_RGB8)
{
c = (*truewidth)*(*trueheight)*3;
for (i=0 ; i<c ; i+=3)
int pxsize = (*fmt == PTI_RGB8)?3:4;
c = (*truewidth)*(*trueheight)*pxsize;
for (i=0 ; i<c ; i+=pxsize)
{
extern qbyte gammatable[256];
ret[i+0] = gammatable[ret[i+0]];

View File

@ -1097,6 +1097,8 @@ static void Shader_SurfaceParm (parsestate_t *ps, char **ptr)
shader->flags |= SHADER_HASPALETTED;
else if (!Q_stricmp(token, "hastop") || !Q_stricmp(token, "hasbottom") || !Q_stricmp(token, "hastopbottom"))
shader->flags |= SHADER_HASTOPBOTTOM;
else
Con_DLPrintf(2, "Shader %s, Unknown surface parm \"%s\"\n", ps->s->name, token); //note that there are game-specific names used to override mod surfaceflags+contents
}
static void Shader_Sort (parsestate_t *ps, char **ptr)
@ -1105,7 +1107,12 @@ static void Shader_Sort (parsestate_t *ps, char **ptr)
char *token;
token = Shader_ParseString ( ptr );
if ( !Q_stricmp( token, "portal" ) )
if (r_forceprogramify.ival >= 2)
{
Con_DPrintf("Shader %s, ignoring 'sort %s'\n", ps->s->name, token);
return; //dp ignores 'sort' entirely.
}
else if ( !Q_stricmp( token, "portal" ) )
shader->sort = SHADER_SORT_PORTAL;
else if( !Q_stricmp( token, "sky" ) )
shader->sort = SHADER_SORT_SKY;
@ -1289,6 +1296,8 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p)
Q_strlcatfz(defines, &offset, sizeof(defines), "#define MAX_GPU_BONES %i\n", sh_config.max_gpu_bones);
if (gl_specular.value)
Q_strlcatfz(defines, &offset, sizeof(defines), "#define SPECULAR\n#define SPECULAR_BASE_MUL %f\n#define SPECULAR_BASE_POW %f\n", 1.0*gl_specular.value, max(1,gl_specular_power.value));
if (r_fakeshadows)
Q_strlcatfz(defines, &offset, sizeof(defines), "#define FAKESHADOWS\n%s", gl_config.arb_shadow?"#define USE_ARB_SHADOW\n":"");
for (n = 0; n < countof(permutations); n++)
{
@ -1363,6 +1372,8 @@ qboolean Com_PermuOrFloatArgument(const char *shadername, char *arg, size_t argl
//load-time-only permutations...
if (arglen == 8 && !strncmp("SPECULAR", arg, arglen) && gl_specular.value)
return true;
if (arglen == 11 && !strncmp("FAKESHADOWS", arg, arglen) && r_fakeshadows)
return true;
if ((arglen==5||arglen==6) && !strncmp("DELUXE", arg, arglen) && r_deluxemapping && Shader_PermutationEnabled(PERMUTATION_BUMPMAP))
return true;
if (arglen == 13 && !strncmp("OFFSETMAPPING", arg, arglen) && r_glsl_offsetmapping.ival)
@ -2697,6 +2708,7 @@ static shaderkey_t shaderkeys[] =
{"reflect", Shader_DP_Reflect, "dp"},
{"refract", Shader_DP_Refract, "dp"},
{"offsetmapping", Shader_DP_OffsetMapping, "dp"},
{"shadow", NULL, "dp"},
{"noshadow", NULL, "dp"},
{"polygonoffset", NULL, "dp"},
{"glossintensitymod", Shader_DP_GlossScale, "dp"}, //scales r_shadow_glossintensity(=1), aka: gl_specular
@ -4249,6 +4261,20 @@ void Shader_Reset(shader_t *s)
Hash_Add(&shader_active_hash, s->name, s, &s->bucket);
}
static void Shader_Regenerate(parsestate_t *ps, const char *shortname)
{
Shader_Reset(ps->s);
if (!strcmp(shortname, "textures/common/clip") || !strcmp(shortname, "textures/common/nodraw") || !strcmp(shortname, "common/nodraw"))
Shader_DefaultScript(ps, shortname,
"{\n"
"surfaceparm nodraw\n"
"surfaceparm nodlight\n"
"}\n");
else
ps->s->generator(ps, shortname, ps->s->genargs);
}
void Shader_Shutdown (void)
{
int i;
@ -5098,27 +5124,35 @@ void Shader_Finish (parsestate_t *ps)
if (!s->numpasses && s->sort != SHADER_SORT_PORTAL && !(s->flags & (SHADER_NODRAW|SHADER_SKY)) && !s->fog_dist)
{
pass = &s->passes[s->numpasses++];
pass = &s->passes[0];
pass->tcgen = TC_GEN_BASE;
if (TEXVALID(s->defaulttextures->base))
pass->texgen = T_GEN_DIFFUSE;
if (r_forceprogramify.ival >= 2)
{
Con_DPrintf("Shader %s with no passes, forcing nodraw\n", s->name);
s->flags |= SHADER_NODRAW;
}
else
{
pass->texgen = T_GEN_SINGLEMAP;
TEXASSIGN(pass->anim_frames[0], R_LoadHiResTexture(s->name, NULL, IF_NOALPHA));
if (!TEXVALID(pass->anim_frames[0]))
pass = &s->passes[s->numpasses++];
pass = &s->passes[0];
pass->tcgen = TC_GEN_BASE;
if (TEXVALID(s->defaulttextures->base))
pass->texgen = T_GEN_DIFFUSE;
else
{
Con_Printf("Shader %s failed to load default texture\n", s->name);
pass->anim_frames[0] = missing_texture;
pass->texgen = T_GEN_SINGLEMAP;
TEXASSIGN(pass->anim_frames[0], R_LoadHiResTexture(s->name, NULL, IF_NOALPHA));
if (!TEXVALID(pass->anim_frames[0]))
{
Con_Printf("Shader %s failed to load default texture\n", s->name);
pass->anim_frames[0] = missing_texture;
}
Con_Printf("Shader %s with no passes and no surfaceparm nodraw, inserting pass\n", s->name);
}
Con_Printf("Shader %s with no passes and no surfaceparm nodraw, inserting pass\n", s->name);
pass->shaderbits |= SBITS_MISC_DEPTHWRITE;
pass->rgbgen = RGB_GEN_VERTEX_LIGHTING;
pass->alphagen = ALPHA_GEN_IDENTITY;
pass->numMergedPasses = 1;
Shader_SetBlendmode(pass, NULL);
}
pass->shaderbits |= SBITS_MISC_DEPTHWRITE;
pass->rgbgen = RGB_GEN_VERTEX_LIGHTING;
pass->alphagen = ALPHA_GEN_IDENTITY;
pass->numMergedPasses = 1;
Shader_SetBlendmode(pass, NULL);
}
if (!Q_stricmp (s->name, "flareShader"))
@ -5454,6 +5488,7 @@ done:;
"{\n"
"map $diffuse\n"
"blendfunc add\n"
"nodepth\n"
"}\n"
"}\n");
}
@ -5468,6 +5503,29 @@ done:;
if (s->passes[0].shaderbits & SBITS_ATEST_BITS) //mimic DP's limited alphafunc support
s->passes[0].shaderbits = (s->passes[0].shaderbits & ~SBITS_ATEST_BITS) | SBITS_ATEST_GE128;
s->passes[0].shaderbits &= ~SBITS_DEPTHFUNC_BITS; //DP ignores this too.
if (s->flags & SHADER_CULL_BACK) //DP has no back-face culling
s->flags = (s->flags&~SHADER_CULL_BACK)|SHADER_CULL_FRONT;
//disable rtlight stuff when blended.
if ((s->passes[0].shaderbits & SBITS_SRCBLEND_BITS)==SBITS_SRCBLEND_ONE && (s->passes[0].shaderbits & SBITS_DSTBLEND_BITS)==SBITS_DSTBLEND_ZERO)
; //replace
else if ((s->passes[0].shaderbits & SBITS_SRCBLEND_BITS)==SBITS_SRCBLEND_ONE && (s->passes[0].shaderbits & SBITS_DSTBLEND_BITS)==SBITS_DSTBLEND_ONE)
s->flags |= SHADER_NOSHADOWS; //add-ignore-alpha
else if ((s->passes[0].shaderbits & SBITS_SRCBLEND_BITS)==SBITS_SRCBLEND_SRC_ALPHA && (s->passes[0].shaderbits & SBITS_DSTBLEND_BITS)==SBITS_DSTBLEND_ONE)
s->flags |= SHADER_NOSHADOWS; //add-with-alpha
else if ((s->passes[0].shaderbits & SBITS_SRCBLEND_BITS)==SBITS_SRCBLEND_SRC_ALPHA && (s->passes[0].shaderbits & SBITS_DSTBLEND_BITS)==SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
s->flags |= SHADER_NOSHADOWS; //blended
else
s->flags |= SHADER_NOSHADOWS|SHADER_NODLIGHT; //erk...
if (s->passes[0].numtcmods>1)
{ //reverse the order of tcmods (dp uses a texture matrix which it concats in reverse order)
tcmod_t tmp[SHADER_MAX_TC_MODS];
int j;
memcpy(tmp, s->passes[0].tcmods, sizeof(*tmp)*s->passes[0].numtcmods);
for (j = 0; j < s->passes[0].numtcmods; j++)
s->passes[0].tcmods[j] = tmp[s->passes[0].numtcmods-1-j];
}
}
Shader_Programify(ps);
}
@ -7240,16 +7298,7 @@ static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader
if (s->generator)
{
Shader_Reset(s);
if (!strcmp(shortname, "textures/common/clip"))
Shader_DefaultScript(&ps, cleanname,
"{\n"
"surfaceparm nodraw\n"
"surfaceparm nodlight\n"
"}\n");
else
s->generator(&ps, cleanname, s->genargs);
Shader_Regenerate(&ps, shortname);
return s;
}
else
@ -7607,9 +7656,7 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize)
if (!parsename && s->generator)
{
oldsort = s->sort;
Shader_Reset(s);
s->generator(&ps, shortname, s->genargs);
Shader_Regenerate(&ps, shortname);
if (s->sort != oldsort)
resort = true;
@ -7825,10 +7872,7 @@ void Shader_DoReload(void)
if (s->generator)
{
oldsort = s->sort;
Shader_Reset(s);
s->generator(&ps, shortname, s->genargs);
Shader_Regenerate(&ps, shortname);
if (s->sort != oldsort)
resort = true;
}

View File

@ -65,9 +65,14 @@ cvar_t r_shadow_realtime_dlight_specular = CVAR ("r_shadow_realtime_dlight_specu
cvar_t r_shadow_playershadows = CVARD ("r_shadow_playershadows", "1", "Controls the presence of shadows on the local player.");
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.");
static cvar_t r_shadow_shadowmapping_depthbits = CVARD ("r_shadow_shadowmapping_depthbits", "16", "Shadowmap depth bits. 16, 24, or 32.");
cvar_t r_sun_dir = CVARD ("r_sun_dir", "0.2 0.5 0.8", "Specifies the direction that crepusular rays appear along");
cvar_t r_sun_colour = CVARFD ("r_sun_colour", "0 0 0", CVAR_ARCHIVE, "Specifies the colour of sunlight that appears in the form of crepuscular rays.");
static cvar_t r_shadows_fakedistance = CVARD("r_shadows_fakedistance", "1024", "The radius to use for fake shadows.");
static cvar_t r_shadows_throwdirection = CVARD("r_shadows_throwdirection", "0 0 -1", "The direction to throw the fake shadows in. Should ideally be opposite to r_sun_dir, but that just shows how fake these things actually are.");
static cvar_t r_shadows_focus = CVARD("r_shadows_focus", "0 0 0", "Offset for the center of the fake-shadows volume.");
static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour, qbyte *pvs);
static pvsbuffer_t lvisb, lvisb2;
@ -2235,7 +2240,7 @@ static void Sh_LightFrustumPlanes(dlight_t *l, vec3_t axis[3], vec4_t *planes, i
//culling for the face happens in the caller.
//these faces should thus match Sh_LightFrustumPlanes
static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, float proj[16], const qbyte *lightpvs)
static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, int txsize, float proj[16], const qbyte *lightpvs)
{
vec3_t t1,t2,t3;
texture_t *tex;
@ -2303,19 +2308,19 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm
if (lighttype & (LSHADER_SPOT|LSHADER_ORTHO))
{
r_refdef.pxrect.x = (SHADOWMAP_SIZE-smsize)/2;
r_refdef.pxrect.x = (txsize-smsize)/2;
r_refdef.pxrect.width = smsize;
r_refdef.pxrect.height = smsize;
r_refdef.pxrect.y = (SHADOWMAP_SIZE-smsize)/2;
r_refdef.pxrect.maxheight = SHADOWMAP_SIZE;
r_refdef.pxrect.y = (txsize-smsize)/2;
r_refdef.pxrect.maxheight = txsize;
}
else
{
r_refdef.pxrect.x = (face%3 * SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2;
r_refdef.pxrect.x = (face%3 * txsize) + (txsize-smsize)/2;
r_refdef.pxrect.width = smsize;
r_refdef.pxrect.height = smsize;
r_refdef.pxrect.y = (((face<3)*SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2);
r_refdef.pxrect.maxheight = SHADOWMAP_SIZE*2;
r_refdef.pxrect.y = (((face<3)*txsize) + (txsize-smsize)/2);
r_refdef.pxrect.maxheight = txsize*2;
}
R_SetFrustum(proj, r_refdef.m_view);
@ -2338,14 +2343,16 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm
if (lighttype & LSHADER_ORTHO)
qglEnable(GL_DEPTH_CLAMP_ARB);
GL_CullFace(SHADER_CULL_FRONT);
GLBE_RenderShadowBuffer(smesh->numverts, smesh->vebo[0], smesh->verts, smesh->numindicies, smesh->vebo[1], smesh->indicies);
if (smesh)
GLBE_RenderShadowBuffer(smesh->numverts, smesh->vebo[0], smesh->verts, smesh->numindicies, smesh->vebo[1], smesh->indicies);
break;
#endif
#ifdef VKQUAKE
case QR_VULKAN:
//FIXME: generate a single commandbuffer (requires full separation of viewprojection matrix)
VKBE_BeginShadowmapFace();
VKBE_RenderShadowBuffer(smesh->vkbuffer);
if (smesh)
VKBE_RenderShadowBuffer(smesh->vkbuffer);
break;
#endif
#ifdef D3D11QUAKE
@ -2353,11 +2360,13 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm
//opengl render targets are upside down - our code kinda assumes gl
r_refdef.pxrect.y = r_refdef.pxrect.maxheight -(r_refdef.pxrect.y+r_refdef.pxrect.height);
D3D11BE_BeginShadowmapFace();
D3D11BE_RenderShadowBuffer(smesh->numverts, smesh->d3d11_vbuffer, smesh->numindicies, smesh->d3d11_ibuffer);
if (smesh)
D3D11BE_RenderShadowBuffer(smesh->numverts, smesh->d3d11_vbuffer, smesh->numindicies, smesh->d3d11_ibuffer);
break;
#endif
default:
//FIXME: should be able to merge batches between textures+lightmaps.
if (smesh)
for (tno = 0; tno < smesh->numbatches; tno++)
{
if (!smesh->batches[tno].count)
@ -2426,29 +2435,50 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm
*/
}
qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvis, int smsize)
qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvis, int smsize, int txsize)
{
int restorefbo = 0;
int f,lf;
float oprojs[16], oprojv[16], oview[16];
pxrect_t oprect;
shadowmesh_t *smesh;
qboolean isspot = !!(lighttype & (LSHADER_SPOT|LSHADER_ORTHO));
int sidevisible;
int oldflip = r_refdef.flipcull;
int oldexternalview = r_refdef.externalview;
int twidth;
int theight;
int smapidx;
uploadfmt_t fmt;
if (isspot)
if (r_shadow_shadowmapping_depthbits.ival >= 32 && sh_config.texfmt[PTI_DEPTH32])
fmt = PTI_DEPTH32;
else if (r_shadow_shadowmapping_depthbits.ival >= 24 && sh_config.texfmt[PTI_DEPTH24])
fmt = PTI_DEPTH24;
else if (r_shadow_shadowmapping_depthbits.ival >= 24 && sh_config.texfmt[PTI_DEPTH24_8])
fmt = PTI_DEPTH24_8;
else
fmt = PTI_DEPTH16;
if (lighttype & (LSHADER_SPOT|LSHADER_ORTHO))
{ //spotlights only face forwards. which is side 4. which is annoying.
f = 4;
lf = f+1;
sidevisible = 1<<f;
twidth = theight = txsize;
if (lighttype & LSHADER_FAKESHADOWS)
smapidx = 2;
else
smapidx = 1;
}
else
{
f = 0;
lf = 6;
sidevisible = (1<<6)-1;
twidth = txsize*3;
theight = txsize*2;
smapidx = 0;
}
if (R_CullSphere(l->origin, 0))
{ //if the light's center isn't onscreen, cull individual faces
@ -2492,7 +2522,10 @@ qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvi
memcpy(oprojv, r_refdef.m_projection_view, sizeof(oprojv));
memcpy(oview, r_refdef.m_view, sizeof(oview));
oprect = r_refdef.pxrect;
smesh = SHM_BuildShadowMesh(l, lvis, (lighttype & LSHADER_ORTHO)?SMT_ORTHO:SMT_SHADOWMAP);
if (lighttype & LSHADER_FAKESHADOWS)
smesh = NULL;
else
smesh = SHM_BuildShadowMesh(l, lvis, (lighttype & LSHADER_ORTHO)?SMT_ORTHO:SMT_SHADOWMAP);
if (lighttype & LSHADER_SPOT)
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, l->fov, l->fov, l->nearclip?l->nearclip:r_shadow_shadowmapping_nearclip.value, l->radius, false);
@ -2517,20 +2550,20 @@ qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvi
return false;
#ifdef GLQUAKE
case QR_OPENGL:
if (!GLBE_BeginShadowMap(isspot, (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*3)), (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*2)), &restorefbo))
if (!GLBE_BeginShadowMap(smapidx, twidth, theight, fmt, &restorefbo))
return false;
break;
#endif
#ifdef D3D11QUAKE
case QR_DIRECT3D11:
if (!D3D11_BeginShadowMap(isspot, (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*3)), (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*2))))
if (!D3D11_BeginShadowMap(smapidx, twidth, theight))
return false;
break;
#endif
#ifdef VKQUAKE
case QR_VULKAN:
if (!VKBE_BeginShadowmap(isspot, (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*3)), (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*2))))
if (!VKBE_BeginShadowmap(smapidx, twidth, theight))
return false;
break;
#endif
@ -2544,7 +2577,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvi
if (sidevisible & (1u<<f))
{
RQuantAdd(RQUANT_SHADOWSIDES, 1);
Sh_GenShadowFace(l, axis, lighttype, smesh, f, smsize, r_refdef.m_projection_std, lvis);
Sh_GenShadowFace(l, axis, lighttype, smesh, f, smsize, txsize, r_refdef.m_projection_std, lvis);
}
}
@ -2672,11 +2705,113 @@ qboolean Sh_GenerateShadowMap(dlight_t *l, int lighttype)
}
//fixme: light rotation
if (!Sh_GenShadowMap(l, lighttype, l->axis, lvis, smsize))
if (!Sh_GenShadowMap(l, lighttype, l->axis, lvis, smsize, SHADOWMAP_SIZE))
return false; //didn't need to do anything
return true;
}
void Sh_OrthoAlignToFrustum(dlight_t *dl, int smsize)
{
vec3_t neworg;
double dot;
double scale;
int i;
//there's 1 sample every dl->radius/(smsize*2)
//fixme: fit to frustum
VectorMA(r_origin, dl->radius/3, vpn, neworg);
VectorMA(neworg, -r_shadows_focus.vec4[2], vpn, neworg);
VectorMA(neworg, -r_shadows_focus.vec4[0], vright, neworg);
VectorMA(neworg, -r_shadows_focus.vec4[1], vup, neworg);
scale = dl->radius/(smsize*2);
for (i = 0; i < 3; i++)
{
dot = DotProduct_Double(neworg, dl->axis[i]);
dot /= scale;
dot = round(dot)-dot;
dot *= scale;
VectorMA(neworg, dot, dl->axis[i], neworg); //realign it on this axis.
}
VectorCopy(neworg, dl->origin);
}
qboolean r_fakeshadows;
static dlight_t r_fakelight;
void Sh_GenerateFakeShadows(void) //generates shadowmaps and selects the dlight, but does not actually render any lighting. the lightmapped-wall etc glsl must filter by itself if it wants to accept shadows.
{
dlight_t *l = &r_fakelight;
vec3_t mins, maxs;
srect_t rect;
int smsize;
int texwidth, texheight;
if (*r_shadows_throwdirection.string)
VectorCopy(r_shadows_throwdirection.vec4, l->axis[0]);
else
VectorNegate(r_sun_dir.vec4, l->axis[0]);
VectorNormalize(l->axis[0]);
VectorVectors(l->axis[0], l->axis[1], l->axis[2]);
VectorNegate(l->axis[1], l->axis[1]);
smsize = SHADOWMAP_SIZE*4; //spot lights or ortho lights can just use the full thing.
Sh_OrthoAlignToFrustum(l, smsize);
l->rebuildcache = true;
l->radius = r_shadows_fakedistance.value;
l->flags = LFLAG_SHADOWMAP|LFLAG_ORTHO;
if (R_CullSphere(l->origin, l->radius))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_FRUSTUM, 1);
return; //this should be the more common case
}
mins[0] = l->origin[0] - l->radius;
mins[1] = l->origin[1] - l->radius;
mins[2] = l->origin[2] - l->radius;
maxs[0] = l->origin[0] + l->radius;
maxs[1] = l->origin[1] + l->radius;
maxs[2] = l->origin[2] + l->radius;
if (Sh_ScissorForBox(mins, maxs, &rect))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_SCISSOR, 1);
return;
}
texwidth = smsize;
texheight = smsize;
switch(qrenderer)
{
#ifdef GLQUAKE
case QR_OPENGL:
GLBE_SetupForShadowMap(l, texwidth, texheight, (smsize) / (float)texwidth);
break;
#endif
#ifdef D3D11QUAKE
case QR_DIRECT3D11:
D3D11BE_SetupForShadowMap(l, texwidth, texheight, (smsize) / (float)texwidth);
break;
#endif
#ifdef VKQUAKE
case QR_VULKAN:
VKBE_SetupForShadowMap(l, texwidth, texheight, (smsize) / (float)texwidth);
break;
#endif
default:
(void)texwidth;
(void)texheight;
break;
}
if (!BE_SelectDLight(l, vec3_origin, l->axis, LSHADER_SMAP|LSHADER_ORTHO))
return;
if (!Sh_GenShadowMap(l, LSHADER_SMAP|LSHADER_ORTHO|LSHADER_FAKESHADOWS, l->axis, NULL, smsize, texwidth))
return;
RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1);
}
static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qbyte *vvis)
{
vec3_t mins, maxs;
@ -2800,7 +2935,7 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb
if (!BE_SelectDLight(l, colour, axis, lighttype))
return;
if (!Sh_GenShadowMap(l, lighttype, axis, lvis, smsize))
if (!Sh_GenShadowMap(l, lighttype, axis, lvis, smsize, SHADOWMAP_SIZE))
return;
RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1);
@ -3618,7 +3753,8 @@ void Sh_PreGenerateLights(void)
}
}
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:LFLAG_NORMALMODE);
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:0)
| (r_shadow_realtime_dlight.value?LFLAG_NORMALMODE:0);
for (dl = cl_dlights+rtlights_first, i=rtlights_first; i<rtlights_max; i++, dl++)
{
@ -3675,6 +3811,7 @@ void Com_ParseVector(char *str, vec3_t out)
void Sh_CheckSettings(void)
{
extern cvar_t r_shadows;
qboolean canstencil = false, cansmap = false, canshadowless = false;
r_shadow_shadowmapping.ival = r_shadow_shadowmapping.value;
r_shadow_realtime_world.ival = r_shadow_realtime_world.value;
@ -3763,6 +3900,14 @@ void Sh_CheckSettings(void)
{
//both shadow methods available.
}
cansmap = cansmap && (r_shadows.ival==2);
if (r_fakeshadows != cansmap)
{
r_fakeshadows = cansmap;
Shader_NeedReload(false);
}
r_blobshadows = r_fakeshadows?0:r_shadows.value; //force it off the hacky way.
}
void Sh_CalcPointLight(vec3_t point, vec3_t light)
@ -3776,7 +3921,8 @@ void Sh_CalcPointLight(vec3_t point, vec3_t light)
unsigned int ignoreflags;
vec3_t norm, impact;
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:LFLAG_NORMALMODE);
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:0)
| (r_shadow_realtime_dlight.value?LFLAG_NORMALMODE:0);
VectorClear(light);
if (ignoreflags)
@ -3818,16 +3964,6 @@ void Sh_CalcPointLight(vec3_t point, vec3_t light)
}
}
void Sh_OrthoAlignToFrustum(dlight_t *dl)
{
vec3_t neworg;
//there's 1 sample every dl->radius/(SHADOWMAP_SIZE*2)
//fixme: fit to frustum
VectorMA(r_origin, dl->radius/3, vpn, neworg);
VectorCopy(neworg, dl->origin);
}
int drawdlightnum;
void Sh_DrawLights(qbyte *vis)
{
vec3_t rotated[3];
@ -3836,18 +3972,20 @@ void Sh_DrawLights(qbyte *vis)
dlight_t *dl;
int i;
unsigned int ignoreflags;
extern cvar_t r_shadows;
if (r_shadow_realtime_world.modified ||
r_shadow_realtime_world_shadows.modified ||
r_shadow_realtime_dlight.modified ||
r_shadow_realtime_dlight_shadows.modified ||
r_shadow_shadowmapping.modified)
r_shadow_shadowmapping.modified || r_shadows.modified)
{
r_shadow_realtime_world.modified =
r_shadow_realtime_world_shadows.modified =
r_shadow_realtime_dlight.modified =
r_shadow_realtime_dlight_shadows.modified =
r_shadow_shadowmapping.modified =
r_shadows.modified =
false;
Sh_CheckSettings();
//make sure the lighting is reloaded
@ -3862,7 +4000,8 @@ void Sh_DrawLights(qbyte *vis)
return;
}
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:LFLAG_NORMALMODE);
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:0)
| (r_shadow_realtime_dlight.value?LFLAG_NORMALMODE:0);
// if (r_refdef.recurse)
for (dl = cl_dlights+rtlights_first, i=rtlights_first; i<rtlights_max; i++, dl++)
@ -3958,14 +4097,13 @@ void Sh_DrawLights(qbyte *vis)
else
axis = dl->axis;
drawdlightnum++;
if (dl->flags & LFLAG_ORTHO)
{
vec3_t saveorg = {dl->origin[0], dl->origin[1], dl->origin[2]};
vec3_t saveaxis[3];
memcpy(saveaxis, dl->axis, sizeof(saveaxis));
memcpy(dl->axis, axis, sizeof(saveaxis));
Sh_OrthoAlignToFrustum(dl);
Sh_OrthoAlignToFrustum(dl, SHADOWMAP_SIZE);
dl->rebuildcache = true;
Sh_DrawShadowMapLight(dl, colour, axis, NULL);
VectorCopy(saveorg, dl->origin);
@ -4029,8 +4167,6 @@ void Sh_DrawLights(qbyte *vis)
// if (developer.value)
// Con_Printf("%i lights drawn, %i frustum culled, %i pvs culled, %i scissor culled\n", bench.numlights, bench.numfrustumculled, bench.numpvsculled, bench.numscissorculled);
// memset(&bench, 0, sizeof(bench));
drawdlightnum = -1;
}
#endif
@ -4071,5 +4207,9 @@ void Sh_RegisterCvars(void)
Cvar_Register (&r_shadow_shadowmapping_bias, REALTIMELIGHTING);
Cvar_Register (&r_sun_dir, REALTIMELIGHTING);
Cvar_Register (&r_sun_colour, REALTIMELIGHTING);
Cvar_Register (&r_shadows_fakedistance, REALTIMELIGHTING);
Cvar_Register (&r_shadows_throwdirection, REALTIMELIGHTING);
Cvar_Register (&r_shadows_focus, REALTIMELIGHTING);
Cvar_Register (&r_shadow_shadowmapping_depthbits, REALTIMELIGHTING);
#endif
}

View File

@ -1916,7 +1916,7 @@ static const char *glsl_hdrs[] =
,
"sys/pcf.h",
//!!cvardf r_glsl_pcf
"#ifndef PCF\n"
"#if !defined(PCF) && !defined(FAKESHADOWS)\n"
"#define ShadowmapFilter(smap,proj) 1.0\n" //s_shadowmap generally. returns a scaler to say how much light should be used for this pixel.
"#else\n"
"#ifndef r_glsl_pcf\n"
@ -1936,7 +1936,7 @@ static const char *glsl_hdrs[] =
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
"return ((cubeproj.yxz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
"#elif defined(ORTHO)\n"
"#elif defined(ORTHO) || defined(FAKESHADOWS)\n"
//the light's origin is in the center of the 'cube', projecting from one side to the other, so don't bias the z.
"return ((cubeproj.xyz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//"#elif defined(CUBESHADOW)\n"
@ -2010,14 +2010,13 @@ static const char *glsl_hdrs[] =
"float s = 0.0;\n"
"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n"
"s += dosamp(0.0, 0.0);\n"
"return s;\n"
"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"return s/5.0;\n"
"s/=5.0;\n"
"#else\n"
"s += dosamp(-1.0, -1.0);\n"
"s += dosamp(-1.0, 0.0);\n"
@ -2028,8 +2027,21 @@ static const char *glsl_hdrs[] =
"s += dosamp(1.0, -1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"s += dosamp(1.0, 1.0);\n"
"return s/9.0;\n"
"s/=9.0;\n"
"#endif\n"
"#if defined(FAKESHADOWS)||defined(ORTHO)\n" //no cascaded shadow maps, so just fade shadows to 1 near the various edges of the shadow maps
"float d = shadowcoord.z;\n"
"d = max(d, shadowcoord.x);\n"
"d = max(d, 1.0-shadowcoord.x);\n"
"d = max(d, shadowcoord.y);\n"
"d = max(d, 1.0-shadowcoord.y);\n"
"if (d > 0.7)\n"
"s = mix(s, 1.0, min(1.0,10.0*(d-0.7)));\n"
"#endif\n"
"#ifdef FAKESHADOWS\n"
"s = s*0.5+0.5;\n" //don't be completely black
"#endif\n"
"return s;\n"
"#endif\n"
#endif
"}\n"

View File

@ -204,6 +204,9 @@ static struct
qXErrorHandler (*pXSetErrorHandler)(XErrorHandler);
int (*pXGrabServer)(Display *display);
int (*pXUngrabServer)(Display *display);
#define XI_RESOURCENAME "FTEQW"
#define XI_RESOURCECLASS "FTEQW"
char *(*pXSetLocaleModifiers)(char *modifier_list);
@ -290,14 +293,18 @@ static qboolean x11_initlib(void)
{(void**)&x11.pXSetSelectionOwner, "XSetSelectionOwner"},
{(void**)&x11.pXSetWMNormalHints, "XSetWMNormalHints"},
{(void**)&x11.pXSetWMProtocols, "XSetWMProtocols"},
{(void**)&x11.pXStoreName, "XStoreName"},
{(void**)&x11.pXSync, "XSync"},
{(void**)&x11.pXStoreName, "XStoreName"},
{(void**)&x11.pXSync, "XSync"},
{(void**)&x11.pXUndefineCursor, "XUndefineCursor"},
{(void**)&x11.pXUngrabKeyboard, "XUngrabKeyboard"},
{(void**)&x11.pXUngrabPointer, "XUngrabPointer"},
{(void**)&x11.pXWarpPointer, "XWarpPointer"},
{(void**)&x11.pXMatchVisualInfo, "XMatchVisualInfo"},
{(void**)&x11.pXMatchVisualInfo, "XMatchVisualInfo"},
{(void**)&x11.pXGetVisualInfo, "XGetVisualInfo"},
{(void**)&x11.pXGrabServer, "XGrabServer"},
{(void**)&x11.pXUngrabServer, "XUngrabServer"},
{NULL, NULL}
};
@ -541,7 +548,7 @@ static void VMODE_SelectMode(int *width, int *height, float rate)
#endif
#ifdef USE_XRANDR
#if 0
#if 1
#include <X11/extensions/Xrandr.h>
#else
//stuff to avoid dependancies
@ -621,6 +628,22 @@ static void VMODE_SelectMode(int *width, int *height, float rate)
unsigned short *green;
unsigned short *blue;
} XRRCrtcGamma;
typedef struct _XRRPanning {
Time timestamp;
unsigned int left;
unsigned int top;
unsigned int width;
unsigned int height;
unsigned int track_left;
unsigned int track_top;
unsigned int track_width;
unsigned int track_height;
int border_left;
int border_top;
int border_right;
int border_bottom;
} XRRPanning;
#endif
static struct
{
@ -671,7 +694,7 @@ static struct
XRRCrtcGamma *origgamma;
// Status (*pGetScreenSizeRange) (Display *dpy, Window window, int *minwidth, int *minheight, int *maxwidth, int *maxheight);
// void (*pSetScreenSize) (Display *dpy, Window window, int width, int height, int mmwidth, int mmheight);
void (*pSetScreenSize) (Display *dpy, Window window, int width, int height, int mmwidth, int mmheight);
XRRScreenResources *(*pGetScreenResources) (Display *dpy, Window window);
void *(*pFreeScreenResources)(XRRScreenResources *);
XRROutputInfo *(*pGetOutputInfo) (Display *dpy, XRRScreenResources *resources, RROutput output);
@ -685,6 +708,16 @@ static struct
//v1.3 has non-0 primary monitors.
RROutput (*pGetOutputPrimary) (Display *dpy, Window window);
Status (*pSetPanning) (Display *dpy, XRRScreenResources *resources, RRCrtc crtc, XRRPanning *panning); //we need this just in case.
XRRPanning * (*pGetPanning) (Display *dpy, XRRScreenResources *resources, RRCrtc crtc);
void (*pFreePanning) (XRRPanning *panning);
int pan[4]; //for restoring panning. pan region the screen may move to
int pantrack[4]; //screen region where the mouse may be for the mouse to be tracked in
int panborder[4]; //border region of crtc for panning to take place in. typically >=0...
int nvidiabug; //nvidia completely ignores panning requests, which fucks over fullscreen gameplay. we have to work around it by shrinking the screen which doesn't work with multiple displays (and risks fucking over everything else)
int origscreenwidth, origscreenwidthmm;
int origscreenheight, origscreenheightmm;
} xrandr;
static qboolean XRandR_Init(void)
{
@ -741,6 +774,8 @@ static qboolean XRandR_Init(void)
xrandr.pFreeGamma = Sys_GetAddressForName(xrandr.lib, "XRRFreeGamma");
xrandr.pSetCrtcGamma = Sys_GetAddressForName(xrandr.lib, "XRRSetCrtcGamma");
xrandr.pSetScreenSize = Sys_GetAddressForName(xrandr.lib, "XRRSetScreenSize");
if ( xrandr.pGetScreenResources && xrandr.pFreeScreenResources && xrandr.pFreeOutputInfo
&& xrandr.pGetCrtcInfo && xrandr.pFreeCrtcInfo && xrandr.pSetCrtcConfig
&& xrandr.pGetCrtcGamma && xrandr.pFreeGamma && xrandr.pSetCrtcGamma
@ -748,7 +783,19 @@ static qboolean XRandR_Init(void)
xrandr.canmodechange12 = true;
}
if (xrandr.vmajor > 1 || (xrandr.vmajor == 1 && xrandr.vminor >= 3))
{
xrandr.pGetOutputPrimary = Sys_GetAddressForName(xrandr.lib, "XRRGetOutputPrimary");
xrandr.pSetPanning = Sys_GetAddressForName(xrandr.lib, "XRRSetPanning");
xrandr.pGetPanning = Sys_GetAddressForName(xrandr.lib, "XRRGetPanning");
xrandr.pFreePanning = Sys_GetAddressForName(xrandr.lib, "XRRFreePanning");
}
xrandr.nvidiabug = false; //hopeful...
{
int op, firstev, firsterr;
if (x11.pXQueryExtension(vid_dpy, "NV-CONTROL", &op, &firstev, &firsterr))
xrandr.nvidiabug = true; //our dreams are so cruely shattered.
}
//FIXME: query monitor sizes and calculate dpi for vid.dpy_[x|y]
return true;
@ -816,10 +863,41 @@ static void XRandR_RevertMode(void)
XRRCrtcInfo *c = xrandr.crtcinfo;
if (c)
{
x11.pXGrabServer(vid_dpy);
if (xrandr.nvidiabug == 1)
{
if (Success == xrandr.pSetCrtcConfig(vid_dpy, xrandr.res, xrandr.crtc, CurrentTime, c->x, c->y, None, c->rotation, NULL, 0))
xrandr.pSetScreenSize(vid_dpy, DefaultRootWindow(vid_dpy), xrandr.origscreenwidth, xrandr.origscreenheight, xrandr.origscreenwidthmm, xrandr.origscreenheightmm);
}
if (Success == xrandr.pSetCrtcConfig(vid_dpy, xrandr.res, xrandr.crtc, CurrentTime, c->x, c->y, c->mode, c->rotation, c->outputs, c->noutput))
{
if (xrandr.pSetPanning)
{ //and try to reset panning back to its original values.
XRRPanning panning;
panning.timestamp = c->timestamp;
panning.left = xrandr.pan[0];
panning.top = xrandr.pan[1];
panning.width = xrandr.pan[2];
panning.height = xrandr.pan[3];
panning.track_left = xrandr.pantrack[0];
panning.track_top = xrandr.pantrack[1];
panning.track_width = xrandr.pantrack[2];
panning.track_height = xrandr.pantrack[3];
panning.border_left = xrandr.panborder[0];
panning.border_top = xrandr.panborder[1];
panning.border_right = xrandr.panborder[2];
panning.border_bottom = xrandr.panborder[3];
if (Success != xrandr.pSetPanning(vid_dpy, xrandr.res, xrandr.crtc, &panning))
Con_Printf("Revert panning configuration failed\n");
else
Con_DPrintf("Panning configuration succeeded\n");
}
Con_DPrintf("Reverted mode\n");
}
else
Con_Printf("Couldn't revert XRandR mode!\n");
x11.pXUngrabServer(vid_dpy);
}
else
{
@ -829,8 +907,9 @@ static void XRandR_RevertMode(void)
fullscreenflags &= ~FULLSCREEN_XRANDRACTIVE;
}
}
static void XRandR_ApplyMode(void)
static qboolean XRandR_ApplyMode(void)
{
qboolean ret = false;
Time config_timestamp;
if (!(fullscreenflags & FULLSCREEN_XRANDRACTIVE))
{
@ -839,10 +918,54 @@ static void XRandR_ApplyMode(void)
{
if (xrandr.crtcmode)
{
x11.pXGrabServer(vid_dpy);
if (xrandr.nvidiabug == 1)
{
/* nvidia's drivers are a bit shite and behave differently from every other driver
unlike other drivers they force panning enabled (and refuse to disable it), which then bugs out in SDL and Wine too.
(specifically, the panning width+height values are recalculated (completely ignoring any passed args), but left+top are not, the tracking+border areas are preserved but affect nothing)
the workaround is to:
lock the server (so other programs don't bug out too much),
disable the screen (for the next step to work),
change the virtual size to one that won't cause a problem with panning,
re-enable the screen with the desired video mode,
and unlock the server again.
This will not help with multimonitor setups, xrandr video mode switches are disabled entirely there.
*/
int screen_width = c->x + xrandr.crtcmode->width;
int screen_height = c->y + xrandr.crtcmode->height;
if (Success == xrandr.pSetCrtcConfig(vid_dpy, xrandr.res, xrandr.crtc, CurrentTime, c->x, c->y, None, c->rotation, NULL, 0))
xrandr.pSetScreenSize(vid_dpy, DefaultRootWindow(vid_dpy), screen_width, screen_height, (screen_width*xrandr.origscreenwidthmm)/xrandr.origscreenwidth, (screen_height*xrandr.origscreenheightmm)/xrandr.origscreenheight);
}
if (Success == xrandr.pSetCrtcConfig(vid_dpy, xrandr.res, xrandr.crtc, CurrentTime, c->x, c->y, xrandr.crtcmode->id, c->rotation, c->outputs, c->noutput))
{
if (xrandr.pSetPanning)
{ //disable panning, in case panning was previously enabled via exterior means
XRRPanning panning;
panning.timestamp = c->timestamp;
panning.left = c->x;
panning.top = c->y;
panning.width = panning.height = 0; //disables panning - "but RRSetScreenSize will silently enable panning if the screen size is increased. This does not happen if set to 0."
//set the tracking area inside of the border area, to make doubly sure
panning.track_left = c->x + 1;
panning.track_top = c->y + 1;
panning.track_width = xrandr.crtcmode->width-2;
panning.track_height = xrandr.crtcmode->height-2;
panning.border_left = panning.border_top = panning.border_right = panning.border_bottom = -16384; //border area is the region of this screen in which panning might be triggered.
if (Success != xrandr.pSetPanning(vid_dpy, xrandr.res, xrandr.crtc, &panning))
Con_Printf("Panning configuration failed\n");
else
Con_DPrintf("Panning configuration succeeded\n");
}
Con_DPrintf("Applied mode\n");
ret = true;
}
else
Con_Printf("Couldn't apply mode\n");
x11.pXUngrabServer(vid_dpy);
}
}
else
@ -852,6 +975,7 @@ static void XRandR_ApplyMode(void)
}
fullscreenflags |= FULLSCREEN_XRANDRACTIVE;
}
return ret;
}
static void XRandR_Shutdown(void)
@ -974,17 +1098,58 @@ static void XRandR_SelectMode(const char *devicename, int *x, int *y, int *width
fullscreenflags |= FULLSCREEN_DESKTOP;
Con_Printf("XRRSetCrtcConfig not needed\n");
}
else if (xrandr.crtcmode && Success == xrandr.pSetCrtcConfig(vid_dpy, xrandr.res, xrandr.crtc, c->timestamp, c->x, c->y, xrandr.crtcmode->id, c->rotation, c->outputs, c->noutput))
{
*x = c->x;
*y = c->y;
*width = xrandr.crtcmode->width;
*height = xrandr.crtcmode->height;
fullscreenflags |= FULLSCREEN_XRANDR | FULLSCREEN_XRANDRACTIVE;
Con_Printf("XRRSetCrtcConfig succeeded\n");
}
else
else if (!xrandr.crtcmode)
Con_Printf("XRRSetCrtcConfig failed\n");
else
{
xrandr.origscreenwidth = DisplayWidth(vid_dpy, scrnum);
xrandr.origscreenheight = DisplayHeight(vid_dpy, scrnum);
xrandr.origscreenwidthmm = DisplayWidthMM(vid_dpy, scrnum);
xrandr.origscreenheightmm = DisplayHeightMM(vid_dpy, scrnum);
if (xrandr.pGetPanning)
{
XRRPanning *panning = xrandr.pGetPanning(vid_dpy, xrandr.res, xrandr.crtc);
if (panning)
{
xrandr.pan[0] = panning->left?panning->left:c->x; //apparently some drivers can be buggy and forget left+top when panning was previously disabled, snappnig them to the wrong place when re-enabled.
xrandr.pan[1] = panning->top?panning->top:c->y;
xrandr.pan[2] = panning->width;
xrandr.pan[3] = panning->height;
xrandr.pantrack[0] = panning->track_left;
xrandr.pantrack[1] = panning->track_top;
xrandr.pantrack[2] = panning->track_width;
xrandr.pantrack[3] = panning->track_height;
xrandr.panborder[0] = panning->border_left;
xrandr.panborder[1] = panning->border_top;
xrandr.panborder[2] = panning->border_right;
xrandr.panborder[3] = panning->border_bottom;
xrandr.pFreePanning(panning);
}
}
if (xrandr.nvidiabug && (c->x != 0 || c->y != 0 || c->noutput>1))
{
Con_Printf("Nvidia and multimonitor detected. XRandR cannot be used safely under in this situation.\n");
xrandr.crtcmode = NULL;
}
else
{
if (xrandr.nvidiabug)
Con_Printf(CON_ERROR "Attempting NVIDIA panning workaround. Try 'xrandr --output foo --auto' to fix if this goes south..\n");
fullscreenflags |= FULLSCREEN_XRANDR;
if (XRandR_ApplyMode())
{ //worked
*x = c->x;
*y = c->y;
*width = xrandr.crtcmode->width;
*height = xrandr.crtcmode->height;
}
else
fullscreenflags &= ~FULLSCREEN_XRANDR;
}
}
}
else if (xrandr.canmodechange11)
{
@ -2509,7 +2674,7 @@ static void install_grabs(void)
{
x11.pXWarpPointer(vid_dpy, None, vid_window,
0, 0, 0, 0,
vid.width / 2, vid.height / 2);
vid.pixelwidth / 2, vid.pixelheight / 2);
}
// x11.pXSync(vid_dpy, True);
@ -2530,6 +2695,21 @@ static void uninstall_grabs(void)
x11.pXUngrabPointer(vid_dpy, CurrentTime);
// x11.pXSync(vid_dpy, True);
if (!vid.forcecursor)
{
vid.forcecursor = true;
vid.forcecursorpos[0] = vid.pixelwidth/2;
vid.forcecursorpos[1] = vid.pixelheight/2;
}
}
if (vid.forcecursor)
{
vid.forcecursor = false;
x11.pXWarpPointer(vid_dpy, vid_window, vid_window,
0, 0, vid.pixelwidth, vid.pixelheight,
vid.forcecursorpos[0], vid.forcecursorpos[1]);
}
}
@ -3552,21 +3732,25 @@ static void X_StoreIcon(Window wnd)
Atom propname = x11.pXInternAtom(vid_dpy, "_NET_WM_ICON", false);
Atom proptype = x11.pXInternAtom(vid_dpy, "CARDINAL", false);
size_t filesize;
size_t filesize = 0;
qbyte *filedata = NULL;
#ifdef AVAIL_PNGLIB
#ifdef IMAGEFMT_PNG
if (!filedata)
filedata = FS_LoadMallocFile("icon.png", &filesize);
#endif
if (!filedata)
filedata = FS_LoadMallocFile("icon.tga", &filesize);
#ifdef AVAIL_JPEGLIB
#ifdef IMAGEFMT_JPG
if (!filedata)
filedata = FS_LoadMallocFile("icon.jpg", &filesize);
#endif
#ifdef IMAGEFMT_BMP
if (!filedata)
filedata = FS_LoadMallocFile("icon.ico", &filesize);
#endif
#ifdef HAVE_LEGACY
if (!filedata)
filedata = FS_LoadMallocFile("darkplaces-icon.tga", &filesize);
#endif
if (filedata)
{
@ -3886,6 +4070,10 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int
scrnum = DefaultScreen(vid_dpy);
vid_root = RootWindow(vid_dpy, scrnum);
#define MILLIMETRESPERINCH 25.4 //sigh, why did we go for dpi?
vid.dpi_x = DisplayWidth(vid_dpy, scrnum) * (MILLIMETRESPERINCH / DisplayWidthMM(vid_dpy, scrnum));
vid.dpi_y = DisplayHeight(vid_dpy, scrnum) * (MILLIMETRESPERINCH / DisplayHeightMM(vid_dpy, scrnum));
fullscreenflags = 0;
if (info->fullscreen == 2)

View File

@ -169,12 +169,147 @@ void GLVID_DestroyCursor (void *cursor)
{
SDL_FreeCursor(cursor);
}
static void GLVID_SetIcon (void)
{
SDL_Surface *iconsurf = NULL;
size_t filesize = 0;
qbyte *filedata = NULL;
qbyte *imagedata = NULL;
#ifdef IMAGEFMT_PNG
if (!filedata)
filedata = FS_LoadMallocFile("icon.png", &filesize);
#endif
if (!filedata)
filedata = FS_LoadMallocFile("icon.tga", &filesize);
#ifdef IMAGEFMT_JPG
if (!filedata)
filedata = FS_LoadMallocFile("icon.jpg", &filesize);
#endif
#ifdef IMAGEFMT_BMP
if (!filedata)
filedata = FS_LoadMallocFile("icon.ico", &filesize);
#endif
#ifdef HAVE_LEGACY
if (!filedata)
filedata = FS_LoadMallocFile("darkplaces-icon.tga", &filesize);
#endif
if (filedata)
{
int imagewidth, imageheight;
uploadfmt_t format = PTI_INVALID;
imagedata = ReadRawImageFile(filedata, filesize, &imagewidth, &imageheight, &format, true, "icon.*");
Z_Free(filedata);
if (imagedata)
{
/* hopefully SDL can resize as appropriate
qbyte *resized = Image_ResampleTexture(format, imagedata, imagewidth, imageheight, NULL, 64, 64);
if (resized)
{
Z_Free(imagedata);
imagedata = resized;
imagewidth = 64;
imageheight = 64;
}*/
switch(format)
{
case PTI_LLLA8: //fallthrough
case PTI_RGBA8: iconsurf = SDL_CreateRGBSurfaceFrom(imagedata, imagewidth, imageheight, 32, 4*imagewidth, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); break;
case PTI_LLLX8: //fallthrough
case PTI_RGBX8: iconsurf = SDL_CreateRGBSurfaceFrom(imagedata, imagewidth, imageheight, 32, 4*imagewidth, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000); break;
case PTI_BGRA8: iconsurf = SDL_CreateRGBSurfaceFrom(imagedata, imagewidth, imageheight, 32, 4*imagewidth, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); break;
case PTI_BGRX8: iconsurf = SDL_CreateRGBSurfaceFrom(imagedata, imagewidth, imageheight, 32, 4*imagewidth, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000); break;
case PTI_A2BGR10: iconsurf = SDL_CreateRGBSurfaceFrom(imagedata, imagewidth, imageheight, 32, 4*imagewidth, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000); break;
default: //others shouldn't happen.
break;
}
}
}
if (!iconsurf)
{
#include "fte_eukara64.h"
// #include "bymorphed.h"
iconsurf = SDL_CreateRGBSurfaceFrom((void*)icon.pixel_data, icon.width, icon.height, 32, 4*icon.width, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); //RGBA byte order on a little endian machine, at least...
}
SDL_SetWindowIcon(sdlwindow, iconsurf);
SDL_FreeSurface(iconsurf);
Z_Free(imagedata);
}
//converts an output device name/number to an index.
//So we can use eg VGA-0 on linux and get the proper device.
static int SDLVID_GetVideoDevice(const char *devicename)
{
char *end;
int display = strtol(devicename, &end, 0);
if (*end)
{ //okay, so its not purely a number. scan by name
display = SDL_GetNumVideoDisplays();
if (display)
{
while (display --> 0)
{
const char *dname = SDL_GetDisplayName(display);
if (dname && !Q_strcasecmp(dname, devicename))
break;
}
}
}
else
{
if (display < 0 || display >= SDL_GetNumVideoDisplays())
display = 0;
}
return display;
}
static qboolean SDLVID_GetVideoMode(rendererstate_t *info, int *display, SDL_DisplayMode *mode)
{
SDL_DisplayMode targ;
*display = SDLVID_GetVideoDevice(info->devicename);
if (info->fullscreen != 1)
return false;
targ.w = info->width;
targ.h = info->height;
if (info->bpp == 30)
targ.format = SDL_PIXELFORMAT_ARGB2101010;
else
targ.format = SDL_PIXELFORMAT_UNKNOWN;
targ.driverdata = NULL;
targ.refresh_rate = info->rate;
if (SDL_GetClosestDisplayMode(*display, &targ, mode))
{
info->width = targ.w;
info->height = targ.h;
return true; //yay
}
return false; //fail
}
static void SDLVID_EnumerateVideoModes (const char *driver, const char *output, void (*cb) (int w, int h))
{
SDL_DisplayMode modeinfo;
int modes, m;
int display = SDLVID_GetVideoDevice(output);
modes = SDL_GetNumDisplayModes(display);
for (m = 0; m < modes; m++)
{
if (0==SDL_GetDisplayMode(display, m, &modeinfo))
cb(modeinfo.w, modeinfo.h);
}
}
#endif
static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qrenderer_t qrenderer)
{
int flags = 0;
int display = -1;
SDL_DisplayMode modeinfo, *usemode;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
#if !defined(FTE_TARGET_WEB) && SDL_MAJOR_VERSION < 2
@ -267,22 +402,58 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr
break;
#endif
}
if (info->fullscreen)
flags |= SDL_WINDOW_FULLSCREEN;
else
flags |= SDL_WINDOW_RESIZABLE;
flags |= SDL_WINDOW_RESIZABLE;
flags |= SDL_WINDOW_INPUT_GRABBED;
flags |= SDL_WINDOW_SHOWN;
#if SDL_PATCHLEVEL >= 1
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
sdlwindow = SDL_CreateWindow(FULLENGINENAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, info->width, info->height, flags);
usemode = NULL;
if (SDLVID_GetVideoMode(info, &display, &modeinfo))
usemode = &modeinfo;
rf->VID_EnumerateVideoModes = SDLVID_EnumerateVideoModes;
sdlwindow = SDL_CreateWindow(FULLENGINENAME, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display), info->width, info->height, flags);
if (!sdlwindow)
{
Con_Printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
return false;
}
SDL_SetWindowMinimumSize(sdlwindow, 320, 200);
if (usemode)
{
SDL_SetWindowDisplayMode(sdlwindow, usemode);
SDL_SetWindowFullscreen(sdlwindow, SDL_WINDOW_FULLSCREEN);
}
else if (info->fullscreen)
SDL_SetWindowFullscreen(sdlwindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_ShowWindow(sdlwindow);
#ifdef __linux__
if (usemode)
{ //try to work around an nvidia bug.
//if the user pans then they might get stuck with x11 at the wrong resolution, so try to back out if it would fail.
int w, h;
SDL_GetWindowSize(sdlwindow, &w, &h);
Sys_SendKeyEvents();
SDL_GetWindowSize(sdlwindow, &vid.pixelwidth, &vid.pixelheight);
if (w != vid.pixelwidth || h != vid.pixelheight)
{
Con_Printf(CON_ERROR "Video mode change didn't stick (Nvidia bug?). Resorting to fullscreen-desktop mode.\n");
SDL_SetWindowFullscreen(sdlwindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_ShowWindow(sdlwindow);
}
}
#endif
#if SDL_PATCHLEVEL >= 4
SDL_GetDisplayDPI(display, NULL, &vid.dpi_x, &vid.dpi_y);
#endif
CL_UpdateWindowTitle();
GLVID_SetIcon();
switch(qrenderer)
{
@ -329,13 +500,6 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr
}
#endif
{
SDL_Surface *iconsurf;
#include "bymorphed.h"
iconsurf = SDL_CreateRGBSurfaceFrom((void*)icon.pixel_data, icon.width, icon.height, 32, 4*icon.height, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); //RGBA byte order on a little endian machine, at least...
SDL_SetWindowIcon(sdlwindow, iconsurf);
SDL_FreeSurface(iconsurf);
}
#else
SDL_GetGammaRamp(intitialgammaramps[0], intitialgammaramps[1], intitialgammaramps[2]);
if (info->fullscreen)
@ -415,6 +579,7 @@ void GLVID_DeInit (void)
#if SDL_MAJOR_VERSION >= 2
SDL_SetWindowGammaRamp(sdlwindow, NULL, NULL, NULL);
switch(qrenderer)
{
#ifdef OPENGL_SDL
@ -424,7 +589,6 @@ void GLVID_DeInit (void)
#endif
#ifdef VULKAN_SDL
case QR_VULKAN:
break;
#endif
default:

View File

@ -131,7 +131,6 @@ qboolean R_DrawSkyroom(shader_t *skyshader)
float vmat[16];
refdef_t oldrefdef;
// extern cvar_t r_ignoreentpvs; //legacy value is 1...
extern cvar_t v_skyroom_orientation;
if (r_viewcluster == -1)
return false; //don't draw the skyroom if the camera is outside.
@ -168,16 +167,16 @@ qboolean R_DrawSkyroom(shader_t *skyshader)
if (r_worldentity.model->funcs.PointContents(r_worldentity.model, NULL, r_refdef.skyroom_pos) & FTECONTENTS_SOLID)
Con_DPrintf("Skyroom position %.1f %.1f %.1f in solid\n", r_refdef.skyroom_pos[0], r_refdef.skyroom_pos[1], r_refdef.skyroom_pos[2]);
if (*v_skyroom_orientation.string)
if (r_refdef.skyroom_spin[3])
{
vec3_t axis[3];
float ang = v_skyroom_orientation.vec4[3] * cl.time;
if (!v_skyroom_orientation.vec4[0]&&!v_skyroom_orientation.vec4[1]&&!v_skyroom_orientation.vec4[2])
VectorSet(v_skyroom_orientation.vec4, 0,0,1);
VectorNormalize(v_skyroom_orientation.vec4);
RotatePointAroundVector(axis[0], v_skyroom_orientation.vec4, vpn, ang);
RotatePointAroundVector(axis[1], v_skyroom_orientation.vec4, vright, ang);
RotatePointAroundVector(axis[2], v_skyroom_orientation.vec4, vup, ang);
float ang = r_refdef.skyroom_spin[3];
if (!r_refdef.skyroom_spin[0]&&!r_refdef.skyroom_spin[1]&&!r_refdef.skyroom_spin[2])
VectorSet(r_refdef.skyroom_spin, 0,0,1);
VectorNormalize(r_refdef.skyroom_spin);
RotatePointAroundVector(axis[0], r_refdef.skyroom_spin, vpn, ang);
RotatePointAroundVector(axis[1], r_refdef.skyroom_spin, vright, ang);
RotatePointAroundVector(axis[2], r_refdef.skyroom_spin, vup, ang);
Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, axis[0], axis[1], axis[2], r_refdef.vieworg);
}
else

View File

@ -54,7 +54,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "fixedemu",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x14\x00\x00\x00\x40\x00\x00\x00"
"\x74\x10\x00\x00\xB4\x10\x00\x00\x00\x0F\x00\x00\x01\x00\x42\x31\x63\x6F\x6E\x73\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x00\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x5B\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x5B\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x0F\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00"
"\x43\x00\x00\x00\x4C\x00\x00\x00\x50\x00\x00\x00\x57\x00\x00\x00\x58\x00\x00\x00\x59\x00\x00\x00\x5A\x00\x00\x00\x03\x00\x03\x00"
@ -185,7 +185,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x3D\x00\x04\x00\x06\x00\x00\x00\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00"
"\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00"
"\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00"
"\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00"
"\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00"
"\x56\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64"
"\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x08\x00\x04\x00\x00\x00\x04\x00\x00\x00"
"\x6D\x61\x69\x6E\x00\x00\x00\x00\x11\x00\x00\x00\x15\x00\x00\x00\x46\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00"
@ -560,7 +560,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x66\x72\x00\x3F\x33\x33\x33\x3F\x4C\xCC\xCD\x3F\x33\x33\x33\x01\x11\x46\x33\x74\x69\x6E\x74\x5F\x72\x65\x66\x6C\x00\x3F\x33\x33"
"\x33\x3F\x4C\xCC\xCD\x3F\x33\x33\x33\x01\x14\x42\x31\x64\x65\x70\x74\x68\x00\x00\x00\x00\x00\x01\x15\x46\x31\x61\x6C\x70\x68\x61"
"\x00\x00\x00\x00\x00\x01\x16\x46\x33\x66\x6F\x67\x74\x69\x6E\x74\x00\x3E\x4C\xCC\xCD\x3E\x99\x99\x9A\x3E\x4C\xCC\xCD\x00\x00\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x79\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x79\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x11\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x2C\x00\x00\x00\x49\x00\x00\x00\x4B\x00\x00\x00"
"\x4E\x00\x00\x00\x51\x00\x00\x00\x52\x00\x00\x00\x54\x00\x00\x00\x5D\x00\x00\x00\x75\x00\x00\x00\x76\x00\x00\x00\x77\x00\x00\x00"
@ -741,7 +741,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x06\x00\x00\x00\x41\x00\x00\x00\x3D\x00\x00\x00\x40\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x43\x00\x00\x00\x41\x00\x00\x00"
"\x42\x00\x00\x00\x41\x00\x05\x00\x36\x00\x00\x00\x44\x00\x00\x00\x1D\x00\x00\x00\x3B\x00\x00\x00\x3E\x00\x03\x00\x44\x00\x00\x00"
"\x43\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x45\x00\x00\x00\x1D\x00\x00\x00\xFE\x00\x02\x00\x45\x00\x00\x00\x38\x00\x01\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x80\x01\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x80\x01\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x0B\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x37\x00\x00\x00\x68\x00\x00\x00\x75\x00\x00\x00"
"\x82\x00\x00\x00\xD1\x00\x00\x00\x77\x01\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -1136,7 +1136,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#ifdef VKQUAKE
{QR_VULKAN, -1, "bloom_blur",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\x90\x0E\x00\x00\xBC\x0E\x00\x00\x08\x0C\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x4C\x00\x00\x00\x00\x00\x00\x00"
"\x90\x0E\x00\x00\xBC\x0E\x00\x00\x08\x0C\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x4C\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3F\x00\x00\x00\x47\x00\x00\x00\x48\x00\x00\x00\x49\x00\x00\x00\x4A\x00\x00\x00"
@ -1253,7 +1253,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00"
"\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00"
"\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x37\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x37\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00"
"\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x09\x00\x00\x00\x12\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00"
"\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
@ -1381,7 +1381,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "bloom_filter",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x1F\x00\x00\x00\x4C\x00\x00\x00"
"\xB0\x0F\x00\x00\xFC\x0F\x00\x00\x3C\x0C\x00\x00\x01\x00\x66\x33\x72\x5F\x62\x6C\x6F\x6F\x6D\x5F\x66\x69\x6C\x74\x65\x72\x00\x3F"
"\x33\x33\x33\x3F\x33\x33\x33\x3F\x33\x33\x33\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x52\x00\x00\x00\x00\x00\x00\x00"
"\x33\x33\x33\x3F\x33\x33\x33\x3F\x33\x33\x33\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x52\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x22\x00\x00\x00\x3F\x00\x00\x00\x41\x00\x00\x00\x45\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00\x4F\x00\x00\x00\x50\x00\x00\x00"
@ -1507,7 +1507,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x37\x00\x00\x00\x33\x00\x00\x00\x36\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x39\x00\x00\x00\x37\x00\x00\x00\x38\x00\x00\x00"
"\x41\x00\x05\x00\x2C\x00\x00\x00\x3A\x00\x00\x00\x13\x00\x00\x00\x31\x00\x00\x00\x3E\x00\x03\x00\x3A\x00\x00\x00\x39\x00\x00\x00"
"\x3D\x00\x04\x00\x07\x00\x00\x00\x3B\x00\x00\x00\x13\x00\x00\x00\xFE\x00\x02\x00\x3B\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x2F\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x2F\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00"
"\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x10\x00\x00\x00\x18\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00"
"\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
@ -1644,7 +1644,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "bloom_final",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x27\x00\x00\x00\x54\x00\x00\x00"
"\x04\x0F\x00\x00\x58\x0F\x00\x00\x78\x0C\x00\x00\x01\x00\x66\x31\x72\x5F\x62\x6C\x6F\x6F\x6D\x00\x00\x00\x00\x00\x01\x01\x66\x31"
"\x72\x5F\x62\x6C\x6F\x6F\x6D\x5F\x72\x65\x74\x61\x69\x6E\x00\x3F\x80\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00"
"\x72\x5F\x62\x6C\x6F\x6F\x6D\x5F\x72\x65\x74\x61\x69\x6E\x00\x3F\x80\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00"
"\x4E\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64"
"\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00"
"\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3F\x00\x00\x00\x49\x00\x00\x00\x4A\x00\x00\x00"
@ -1765,7 +1765,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00"
"\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00"
"\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00"
"\x06\x00\x08\x00\x32\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C"
"\x07\x00\x08\x00\x32\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C"
"\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00\x04\x00\x00\x00"
"\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x09\x00\x00\x00\x12\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00"
"\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x05\x00\x05\x00"
@ -2094,7 +2094,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#ifdef VKQUAKE
{QR_VULKAN, -1, "depthonly",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\x34\x0E\x00\x00\x60\x0E\x00\x00\x44\x09\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x49\x00\x00\x00\x00\x00\x00\x00"
"\x34\x0E\x00\x00\x60\x0E\x00\x00\x44\x09\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x49\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0D\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x3A\x00\x00\x00\x42\x00\x00\x00\x44\x00\x00\x00\x45\x00\x00\x00\x46\x00\x00\x00\x47\x00\x00\x00\x48\x00\x00\x00"
@ -2208,7 +2208,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00"
"\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00"
"\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x16\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x16\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x06\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x15\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00"
"\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
@ -2368,7 +2368,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "default2d",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x0F\x00\x00\x00\x3C\x00\x00\x00"
"\x10\x0F\x00\x00\x4C\x0F\x00\x00\x7C\x0C\x00\x00\x01\x00\x42\x31\x50\x52\x45\x4D\x55\x4C\x00\x00\x00\x00\x00\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x4F\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x4F\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0F\x00"
"\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3E\x00\x00\x00"
"\x40\x00\x00\x00\x44\x00\x00\x00\x4B\x00\x00\x00\x4C\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -2488,7 +2488,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00"
"\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00"
"\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00"
"\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x37\x00\x00\x00\x00\x00\x00\x00"
"\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x37\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x08\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x0B\x00\x00\x00\x26\x00\x00\x00\x2C\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -2631,6 +2631,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"return t_t0.Sample(s_t0, inp.tc) * inp.vcol;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
@ -2669,7 +2670,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "defaultadditivesprite",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x20\x00\x00\x00\x2C\x00\x00\x00\x20\x00\x00\x00\x4C\x00\x00\x00"
"\x7C\x0F\x00\x00\xC8\x0F\x00\x00\x54\x12\x00\x00\x01\x00\x46\x31\x4D\x41\x53\x4B\x00\x00\x00\x00\x00\x01\x01\x62\x31\x72\x5F\x66"
"\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x51\x00\x00\x00\x00\x00\x00\x00"
"\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x51\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0F\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3E\x00\x00\x00\x40\x00\x00\x00\x44\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00"
@ -2793,7 +2794,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00"
"\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00"
"\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x7D\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x7D\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x09\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x27\x00\x00\x00"
"\x5F\x00\x00\x00\x6E\x00\x00\x00\x70\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -3358,7 +3359,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x74\x1A\x00\x00\x08\x1B\x00\x00\xA0\x32\x00\x00\x01\x00\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70"
"\x70\x69\x6E\x67\x00\x00\x00\x00\x00\x01\x01\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70\x70\x69\x6E"
"\x67\x5F\x73\x63\x61\x6C\x65\x00\x3D\x23\xD7\x0A\x01\x02\x66\x31\x67\x6C\x5F\x73\x70\x65\x63\x75\x6C\x61\x72\x00\x00\x00\x00\x00"
"\x01\x03\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00"
"\x01\x03\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00"
"\xC0\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64"
"\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x11\x00\x00\x00\x00\x00\x04\x00\x00\x00"
"\x6D\x61\x69\x6E\x00\x00\x00\x00\x28\x00\x00\x00\x44\x00\x00\x00\x46\x00\x00\x00\x48\x00\x00\x00\x60\x00\x00\x00\x78\x00\x00\x00"
@ -3570,7 +3571,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x4B\x00\x00\x00\x38\x00\x01\x00\x36\x00\x05\x00\x07\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x37\x00\x03\x00"
"\x0C\x00\x00\x00\x15\x00\x00\x00\xF8\x00\x02\x00\x17\x00\x00\x00\x3D\x00\x04\x00\x0B\x00\x00\x00\x4E\x00\x00\x00\x44\x00\x00\x00"
"\x3E\x00\x03\x00\x15\x00\x00\x00\x4E\x00\x00\x00\x39\x00\x04\x00\x07\x00\x00\x00\x4F\x00\x00\x00\x09\x00\x00\x00\xFE\x00\x02\x00"
"\x4F\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\xD6\x01\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x4F\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\xD6\x01\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0B\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x36\x00\x00\x00"
"\x07\x01\x00\x00\x09\x01\x00\x00\x80\x01\x00\x00\xB0\x01\x00\x00\xCB\x01\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00"
@ -4186,7 +4187,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "defaultsky",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x20\x00\x00\x00\x2C\x00\x00\x00\x13\x00\x00\x00\x40\x00\x00\x00"
"\xFC\x0E\x00\x00\x3C\x0F\x00\x00\x74\x16\x00\x00\x01\x00\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3D\x00\x00\x00"
"\x47\x00\x00\x00\x49\x00\x00\x00\x4A\x00\x00\x00\x4B\x00\x00\x00\x4C\x00\x00\x00\x4D\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -4306,7 +4307,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00"
"\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00"
"\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\xAD\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\xAD\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x08\x00"
"\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x27\x00\x00\x00\x5C\x00\x00\x00\x98\x00\x00\x00\x10\x00\x03\x00"
"\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E"
@ -4643,7 +4644,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "defaultskybox",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x2C\x00\x00\x00\x13\x00\x00\x00\x40\x00\x00\x00"
"\xB8\x0F\x00\x00\xF8\x0F\x00\x00\x70\x11\x00\x00\x01\x00\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x58\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x58\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x47\x00\x00\x00"
"\x51\x00\x00\x00\x53\x00\x00\x00\x54\x00\x00\x00\x55\x00\x00\x00\x56\x00\x00\x00\x57\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -4769,7 +4770,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00"
"\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00"
"\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00"
"\x06\x00\x08\x00\x72\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C"
"\x07\x00\x08\x00\x72\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C"
"\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x08\x00\x04\x00\x00\x00"
"\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x27\x00\x00\x00\x62\x00\x00\x00\x66\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00"
"\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
@ -5019,7 +5020,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#ifdef VKQUAKE
{QR_VULKAN, -1, "defaultfill",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\x80\x0E\x00\x00\xAC\x0E\x00\x00\xA0\x09\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x4B\x00\x00\x00\x00\x00\x00\x00"
"\x80\x0E\x00\x00\xAC\x0E\x00\x00\xA0\x09\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x4B\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3F\x00\x00\x00\x46\x00\x00\x00\x47\x00\x00\x00\x48\x00\x00\x00\x49\x00\x00\x00"
@ -5135,7 +5136,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00"
"\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00"
"\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00"
"\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x19\x00\x00\x00\x00\x00\x00\x00"
"\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x19\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x09\x00\x00\x00\x0B\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00"
@ -5245,6 +5246,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"return inp.vcol;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
@ -5288,7 +5290,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "defaultsprite",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x20\x00\x00\x00\x2C\x00\x00\x00\x20\x00\x00\x00\x4C\x00\x00\x00"
"\x7C\x0F\x00\x00\xC8\x0F\x00\x00\x30\x12\x00\x00\x01\x00\x46\x31\x4D\x41\x53\x4B\x00\x00\x00\x00\x00\x01\x01\x62\x31\x72\x5F\x66"
"\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x51\x00\x00\x00\x00\x00\x00\x00"
"\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x51\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0F\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3E\x00\x00\x00\x40\x00\x00\x00\x44\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00"
@ -5412,7 +5414,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00"
"\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00"
"\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x7B\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x7B\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x09\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x27\x00\x00\x00"
"\x5D\x00\x00\x00\x6C\x00\x00\x00\x6E\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -5618,7 +5620,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"!!permu BUMP\n"
"!!permu SPECULAR\n"
"!!permu REFLECTCUBEMASK\n"
"!!permu FAKESHADOWS\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvardf r_glsl_pcf\n"
"!!cvardf r_tessellation_level=5\n"
"!!samps diffuse\n"
"!!samps !EIGHTBIT =FULLBRIGHT fullbright\n"
@ -5631,6 +5635,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3\n"
"!!samps =DELUXE deluxmap\n"
"!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3\n"
"!!samps =FAKESHADOWS shadowmap\n"
"#if defined(ORM) || defined(SG)\n"
"#define PBR\n"
@ -5664,6 +5669,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"varying vec2 lm0;\n"
"#endif\n"
"#endif\n"
"#ifdef FAKESHADOWS \n"
"varying vec4 vtexprojcoord;\n"
"#endif\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
@ -5700,12 +5709,18 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"lm3 = v_lmcoord4;\n"
"#endif\n"
"#endif\n"
"gl_Position = ftetransform();\n"
"#ifdef TESS\n"
"vertex = v_position;\n"
"normal = v_normal;\n"
"#endif\n"
"#ifdef FAKESHADOWS \n"
"gl_Position = ftetransform();\n"
"vtexprojcoord = (l_cubematrix*vec4(v_position.xyz, 1.0));\n"
"#else\n"
"gl_Position = ftetransform();\n"
"#endif\n"
"}\n"
"#endif\n"
@ -5850,6 +5865,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#define s_colourmap s_t0\n"
"#include \"sys/pbr.h\"\n"
"#include \"sys/pcf.h\"\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
@ -5996,6 +6012,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
//entity modifiers
"col *= e_colourident;\n"
"#ifdef FAKESHADOWS\n"
/*filter the light by the shadowmap. logically a boolean, but we allow fractions for softer shadows*/
"col.rgb *= ShadowmapFilter(s_shadowmap, vtexprojcoord);\n"
//col.g = ShadowmapFilter(s_shadowmap, vtexprojcoord);
"#endif\n"
"#if defined(MASK)\n"
"#if defined(MASKLT)\n"
"if (col.a < MASK)\n"
@ -6022,7 +6044,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x67\x5F\x73\x63\x61\x6C\x65\x00\x3D\x23\xD7\x0A\x01\x02\x66\x31\x67\x6C\x5F\x73\x70\x65\x63\x75\x6C\x61\x72\x00\x3E\x99\x99\x9A"
"\x01\x03\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x01\x04\x42\x31\x76\x65\x72\x74\x65\x78\x6C\x69\x74"
"\x00\x00\x00\x00\x00\x01\x05\x46\x31\x6D\x61\x73\x6B\x00\x3F\x80\x00\x00\x01\x06\x42\x31\x6D\x61\x73\x6B\x6C\x74\x00\x00\x00\x00"
"\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x8E\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x8E\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00"
"\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x0F\x00\x12\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x4D\x00\x00\x00"
"\x4F\x00\x00\x00\x56\x00\x00\x00\x5B\x00\x00\x00\x64\x00\x00\x00\x6E\x00\x00\x00\x70\x00\x00\x00\x72\x00\x00\x00\x73\x00\x00\x00"
@ -6198,7 +6220,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x3D\x00\x04\x00\x06\x00\x00\x00\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00"
"\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00"
"\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00"
"\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00"
"\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00"
"\x05\x02\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64"
"\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0C\x00\x04\x00\x00\x00\x04\x00\x00\x00"
"\x6D\x61\x69\x6E\x00\x00\x00\x00\x36\x00\x00\x00\x03\x01\x00\x00\x0A\x01\x00\x00\x11\x01\x00\x00\x38\x01\x00\x00\x43\x01\x00\x00"
@ -6246,7 +6268,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x5F\x61\x72\x67\x5F\x76\x65\x72\x74\x65\x78\x6C\x69\x74\x00\x00\x05\x00\x05\x00\x37\x01\x00\x00\x6C\x69\x67\x68\x74\x6D\x61\x70"
"\x73\x00\x00\x00\x05\x00\x03\x00\x38\x01\x00\x00\x76\x63\x00\x00\x05\x00\x05\x00\x41\x01\x00\x00\x73\x5F\x6C\x69\x67\x68\x74\x6D"
"\x61\x70\x00\x00\x05\x00\x03\x00\x43\x01\x00\x00\x6C\x6D\x30\x00\x05\x00\x04\x00\x4C\x01\x00\x00\x64\x65\x6C\x75\x78\x00\x00\x00"
"\x05\x00\x05\x00\x4E\x01\x00\x00\x73\x5F\x64\x65\x6C\x75\x78\x6D\x61\x70\x00\x00\x05\x00\x04\x00\x65\x01\x00\x00\x73\x70\x65\x63"
"\x05\x00\x05\x00\x4E\x01\x00\x00\x73\x5F\x64\x65\x6C\x75\x78\x65\x6D\x61\x70\x00\x05\x00\x04\x00\x65\x01\x00\x00\x73\x70\x65\x63"
"\x73\x00\x00\x00\x05\x00\x05\x00\x66\x01\x00\x00\x73\x5F\x73\x70\x65\x63\x75\x6C\x61\x72\x00\x00\x05\x00\x04\x00\x6C\x01\x00\x00"
"\x68\x61\x6C\x66\x64\x69\x72\x00\x05\x00\x04\x00\x7D\x01\x00\x00\x73\x70\x65\x63\x00\x00\x00\x00\x05\x00\x03\x00\x95\x01\x00\x00"
"\x72\x74\x63\x00\x05\x00\x05\x00\x9F\x01\x00\x00\x69\x6E\x76\x73\x75\x72\x66\x61\x63\x65\x00\x00\x05\x00\x06\x00\xBC\x01\x00\x00"
@ -7050,7 +7072,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\xFF\x53\x50\x56\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x2C\x00\x00\x00\x36\x00\x00\x00\x64\x00\x00\x00"
"\x6C\x0F\x00\x00\xD0\x0F\x00\x00\x24\x17\x00\x00\x01\x00\x66\x31\x72\x5F\x77\x61\x74\x65\x72\x61\x6C\x70\x68\x61\x00\x00\x00\x00"
"\x00\x01\x01\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x01\x02\x46\x31\x61\x6C\x70\x68\x61\x00\x00\x00"
"\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x50\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x50\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00"
"\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00"
"\x3B\x00\x00\x00\x3F\x00\x00\x00\x4B\x00\x00\x00\x4C\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00\x4F\x00\x00\x00\x03\x00\x03\x00"
@ -7173,7 +7195,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x06\x00\x00\x00\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00"
"\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00"
"\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00"
"\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\xB5\x00\x00\x00"
"\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\xB5\x00\x00\x00"
"\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30"
"\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x08\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E"
"\x00\x00\x00\x00\x2C\x00\x00\x00\x75\x00\x00\x00\xA1\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00"
@ -7490,7 +7512,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#ifdef VKQUAKE
{QR_VULKAN, -1, "defaultgammacb",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\xDC\x0E\x00\x00\x08\x0F\x00\x00\xAC\x0B\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x4E\x00\x00\x00\x00\x00\x00\x00"
"\xDC\x0E\x00\x00\x08\x0F\x00\x00\xAC\x0B\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x4E\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0F\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3E\x00\x00\x00\x40\x00\x00\x00\x44\x00\x00\x00\x4A\x00\x00\x00\x4B\x00\x00\x00"
@ -7609,7 +7631,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00"
"\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00"
"\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x30\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x30\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x08\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x09\x00\x00\x00"
"\x11\x00\x00\x00\x15\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00"
@ -7746,7 +7768,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x5C\x13\x00\x00\xD4\x13\x00\x00\x00\x15\x00\x00\x01\x00\x66\x33\x72\x5F\x66\x6C\x6F\x6F\x72\x63\x6F\x6C\x6F\x72\x00\x3F\x00\x00"
"\x00\x3F\x00\x00\x00\x3F\x00\x00\x00\x01\x03\x66\x33\x72\x5F\x77\x61\x6C\x6C\x63\x6F\x6C\x6F\x72\x00\x3E\x80\x00\x00\x3E\x80\x00"
"\x00\x3F\x00\x00\x00\x01\x06\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00"
"\x06\x00\x08\x00\x75\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C"
"\x07\x00\x08\x00\x75\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C"
"\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0F\x00\x00\x00\x00\x00"
"\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x27\x00\x00\x00\x44\x00\x00\x00\x4D\x00\x00\x00\x62\x00\x00\x00\x64\x00\x00\x00"
"\x68\x00\x00\x00\x70\x00\x00\x00\x72\x00\x00\x00\x73\x00\x00\x00\x74\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00"
@ -7900,7 +7922,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x3D\x00\x04\x00\x06\x00\x00\x00\x3B\x00\x00\x00\x3A\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x3C\x00\x00\x00\x38\x00\x00\x00"
"\x3B\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x3E\x00\x00\x00\x3C\x00\x00\x00\x3D\x00\x00\x00\x41\x00\x05\x00\x31\x00\x00\x00"
"\x3F\x00\x00\x00\x18\x00\x00\x00\x36\x00\x00\x00\x3E\x00\x03\x00\x3F\x00\x00\x00\x3E\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00"
"\x40\x00\x00\x00\x18\x00\x00\x00\xFE\x00\x02\x00\x40\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00"
"\x40\x00\x00\x00\x18\x00\x00\x00\xFE\x00\x02\x00\x40\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00"
"\x90\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64"
"\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x09\x00\x04\x00\x00\x00\x04\x00\x00\x00"
"\x6D\x61\x69\x6E\x00\x00\x00\x00\x37\x00\x00\x00\x7E\x00\x00\x00\x7F\x00\x00\x00\x87\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00"
@ -8592,7 +8614,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "postproc_fisheye",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x0D\x00\x00\x00\x3C\x00\x00\x00"
"\xCC\x0E\x00\x00\x08\x0F\x00\x00\xD0\x0E\x00\x00\x01\x00\x66\x31\x66\x66\x6F\x76\x00\x00\x00\x00\x00\x00\x00\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00"
"\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3F\x00\x00\x00"
"\x48\x00\x00\x00\x49\x00\x00\x00\x4A\x00\x00\x00\x4B\x00\x00\x00\x4C\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00"
@ -8710,7 +8732,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00"
"\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00"
"\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x54\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x54\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x0B\x00\x00\x00"
"\x43\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00"
@ -8866,7 +8888,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "postproc_panorama",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x0D\x00\x00\x00\x3C\x00\x00\x00"
"\xCC\x0E\x00\x00\x08\x0F\x00\x00\x60\x0C\x00\x00\x01\x00\x66\x31\x66\x66\x6F\x76\x00\x00\x00\x00\x00\x00\x00\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00"
"\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x3F\x00\x00\x00"
"\x48\x00\x00\x00\x49\x00\x00\x00\x4A\x00\x00\x00\x4B\x00\x00\x00\x4C\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00"
@ -8984,7 +9006,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00"
"\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00"
"\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x36\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x36\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00"
"\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x0B\x00\x00\x00"
"\x25\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00"
@ -9179,7 +9201,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "postproc_stereographic",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x0D\x00\x00\x00\x3C\x00\x00\x00"
"\x20\x0F\x00\x00\x5C\x0F\x00\x00\xB0\x0E\x00\x00\x01\x00\x66\x31\x66\x66\x6F\x76\x00\x00\x00\x00\x00\x00\x00\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x51\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x51\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0E\x00"
"\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x44\x00\x00\x00"
"\x4C\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00\x4F\x00\x00\x00\x50\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00"
@ -9300,7 +9322,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00"
"\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00"
"\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x56\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x56\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00"
"\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x0B\x00\x00\x00\x44\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00"
"\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
@ -9588,7 +9610,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#ifdef VKQUAKE
{QR_VULKAN, -1, "fxaa",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\x74\x0F\x00\x00\xA0\x0F\x00\x00\x5C\x1D\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x54\x00\x00\x00\x00\x00\x00\x00"
"\x74\x0F\x00\x00\xA0\x0F\x00\x00\x5C\x1D\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x54\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0F\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x1C\x00\x00\x00\x39\x00\x00\x00\x3B\x00\x00\x00\x42\x00\x00\x00\x44\x00\x00\x00\x49\x00\x00\x00\x50\x00\x00\x00\x51\x00\x00\x00"
@ -9712,7 +9734,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00"
"\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00"
"\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\xFB\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\xFB\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x08\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x18\x00\x00\x00\x1C\x00\x00\x00\xE7\x00\x00\x00"
"\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00"
@ -9988,7 +10010,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_VULKAN, -1, "underwaterwarp",
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x14\x00\x00\x00\x40\x00\x00\x00"
"\x20\x11\x00\x00\x60\x11\x00\x00\xF4\x0D\x00\x00\x01\x00\x66\x31\x72\x5F\x77\x61\x74\x65\x72\x77\x61\x72\x70\x00\x00\x00\x00\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x68\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x68\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x10\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x3A\x00\x00\x00\x3F\x00\x00\x00"
"\x41\x00\x00\x00\x49\x00\x00\x00\x5C\x00\x00\x00\x63\x00\x00\x00\x64\x00\x00\x00\x65\x00\x00\x00\x66\x00\x00\x00\x67\x00\x00\x00"
@ -10125,7 +10147,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00"
"\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00"
"\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x42\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x42\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00"
"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x0F\x00\x09\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x13\x00\x00\x00\x1E\x00\x00\x00\x28\x00\x00\x00"
"\x30\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00"
@ -10278,7 +10300,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x36\x00\x00\x00\x64\x00\x00\x00"
"\x2C\x10\x00\x00\x90\x10\x00\x00\xE4\x0E\x00\x00\x01\x00\x69\x31\x72\x5F\x6D\x65\x6E\x75\x74\x69\x6E\x74\x5F\x69\x6E\x76\x65\x72"
"\x73\x65\x00\x00\x00\x00\x00\x01\x01\x66\x33\x72\x5F\x6D\x65\x6E\x75\x74\x69\x6E\x74\x00\x3F\x2E\x14\x7B\x3E\xCC\xCC\xCD\x3E\x05"
"\x1E\xB8\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x56\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00"
"\x1E\xB8\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x56\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00"
"\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x0F\x00\x0E\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x22\x00\x00\x00\x3F\x00\x00\x00"
"\x41\x00\x00\x00\x47\x00\x00\x00\x50\x00\x00\x00\x51\x00\x00\x00\x52\x00\x00\x00\x53\x00\x00\x00\x54\x00\x00\x00\x03\x00\x03\x00"
@ -10407,7 +10429,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x06\x00\x00\x00\x36\x00\x00\x00\x35\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x37\x00\x00\x00\x33\x00\x00\x00\x36\x00\x00\x00"
"\x88\x00\x05\x00\x06\x00\x00\x00\x39\x00\x00\x00\x37\x00\x00\x00\x38\x00\x00\x00\x41\x00\x05\x00\x2C\x00\x00\x00\x3A\x00\x00\x00"
"\x13\x00\x00\x00\x31\x00\x00\x00\x3E\x00\x03\x00\x3A\x00\x00\x00\x39\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x3B\x00\x00\x00"
"\x13\x00\x00\x00\xFE\x00\x02\x00\x3B\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x4C\x00\x00\x00"
"\x13\x00\x00\x00\xFE\x00\x02\x00\x3B\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\x4C\x00\x00\x00"
"\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30"
"\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x07\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E"
"\x00\x00\x00\x00\x17\x00\x00\x00\x3B\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"
@ -10575,6 +10597,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"return texcolor * inp.vcol;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
@ -11404,7 +11427,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70\x70\x69\x6E\x67\x5F\x73\x63\x61\x6C\x65\x00\x3D\x23\xD7\x0A"
"\x01\x03\x69\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x70\x63\x66\x00\x00\x00\x00\x05\x01\x04\x42\x31\x70\x63\x66\x00\x00\x00\x00\x00\x01"
"\x05\x42\x31\x73\x70\x6F\x74\x00\x00\x00\x00\x00\x01\x06\x42\x31\x63\x75\x62\x65\x00\x00\x00\x00\x00\x01\x07\x62\x31\x72\x5F\x66"
"\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\xD3\x00\x00\x00\x00\x00\x00\x00"
"\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x03\x02\x23\x07\x00\x00\x01\x00\x07\x00\x08\x00\xD3\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00"
"\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x12\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00"
"\x24\x00\x00\x00\x40\x00\x00\x00\x42\x00\x00\x00\x44\x00\x00\x00\x4C\x00\x00\x00\x5D\x00\x00\x00\x5F\x00\x00\x00\x79\x00\x00\x00"
@ -11634,7 +11657,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"\x10\x00\x00\x00\x43\x00\x00\x00\x3D\x00\x04\x00\x0B\x00\x00\x00\x45\x00\x00\x00\x44\x00\x00\x00\x3E\x00\x03\x00\x11\x00\x00\x00"
"\x45\x00\x00\x00\x3D\x00\x04\x00\x0B\x00\x00\x00\x46\x00\x00\x00\x24\x00\x00\x00\x3E\x00\x03\x00\x0E\x00\x00\x00\x46\x00\x00\x00"
"\x39\x00\x04\x00\x07\x00\x00\x00\x47\x00\x00\x00\x09\x00\x00\x00\xFE\x00\x02\x00\x47\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07"
"\x00\x00\x01\x00\x06\x00\x08\x00\x22\x03\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x00\x00\x01\x00\x07\x00\x08\x00\x22\x03\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00"
"\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x0C\x00"
"\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x37\x00\x00\x00\x69\x00\x00\x00\x18\x02\x00\x00\x1A\x02\x00\x00"
"\x63\x02\x00\x00\xBE\x02\x00\x00\x14\x03\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00"

View File

@ -570,11 +570,13 @@ enum
LSHADER_SPOT=1u<<2, //filter based upon a single spotlight shadowmap
#ifdef LFLAG_ORTHO
LSHADER_ORTHO=1u<<3, //uses a parallel projection(ortho) matrix, with the light source being an entire plane instead of a singular point. which is weird. read: infinitely far away sunlight
LSHADER_MODES=1u<<4
LSHADER_MODES=1u<<4,
#else
LSHADER_ORTHO=0, //so bitmasks return false
LSHADER_MODES=1u<<3
LSHADER_MODES=1u<<3,
#endif
LSHADER_FAKESHADOWS=1u<<10, //special 'light' type that isn't a light but still needs a shadowmap. ignores world+bsp shadows.
};
enum
{
@ -875,7 +877,7 @@ void GLBE_FBO_Pop(int oldfbo);
void GLBE_FBO_Destroy(fbostate_t *state);
int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, int colourbuffers, texid_t destdepth, int width, int height, int layer);
qboolean GLBE_BeginShadowMap(int id, int w, int h, int *restorefbo);
qboolean GLBE_BeginShadowMap(int id, int w, int h, uploadfmt_t encoding, int *restorefbo);
void GLBE_EndShadowMap(int restorefbo);
void GLBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale);
@ -1001,6 +1003,7 @@ void D3D11BE_BaseEntTextures(const qbyte *worldpvs, const int *worldareas);
void Sh_PreGenerateLights(void);
//Draws lights, called from the backend
void Sh_DrawLights(qbyte *vis);
void Sh_GenerateFakeShadows(void);
void Sh_CheckSettings(void);
void SH_FreeShadowMesh(struct shadowmesh_s *sm);
//frees all memory

View File

@ -521,7 +521,7 @@ static struct {
{112, "fgets", &type_string, {&type_float,&type_string}, "string(float fhandle)"},
{113, "fputs", NULL, {&type_float,&type_string}, "void(float fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)"},
{114, "strlen", &type_float, {&type_string}, "float(string s)"},
{115, "strcat", &type_string, {&type_string,&type_string}, "string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)"},
{115, "strcat", &type_string, {&type_string,&type_string,&type_string,&type_string,&type_string,&type_string,&type_string,&type_string},"string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)"},
{116, "substring", &type_string, {&type_string,&type_float,&type_float}, "string(string s, float start, float length)"},
{117, "stov", &type_vector, {&type_string}, "vector(string s)"},
{118, "strzone", &type_string, {&type_string}, "string(string s, ...)"},
@ -967,6 +967,33 @@ char *DecompileAgressiveType(dfunction_t *df, dstatement_t *last, gofs_t ofs)
return NULL; //got to start of function... shouldn't really happen.
}
static unsigned int DecompileBuiltin(dfunction_t *df)
{
unsigned int bi, i;
if (df->first_statement > 0)
return 0; //not a builtin.
bi = -df->first_statement;
//okay, so this is kinda screwy, different mods have different sets of builtins, and a load of fte's are #0 too
//so just try to match by name first... lots of scanning. :(
if (df->s_name>0)
{
char *biname = strings + df->s_name;
for (i = 0; i < (sizeof(builtins)/sizeof(builtins[0])); i++)
{
if (!builtins[i].name)
continue;
if (!strcmp(builtins[i].name, biname))
{ //okay, this one matched.
bi = i;
break;
}
}
}
if (bi >= (sizeof(builtins)/sizeof(builtins[0])))
return 0; //unknown.
return bi;
}
char *DecompileReturnType(dfunction_t *df)
{
dstatement_t *ds;
@ -978,9 +1005,10 @@ char *DecompileReturnType(dfunction_t *df)
if (df->first_statement <= 0)
{
if (df->first_statement > -(int)(sizeof(builtins)/sizeof(builtins[0])))
if (builtins[-df->first_statement].returns)
return type_names[(*builtins[-df->first_statement].returns)->type];
unsigned int bi = DecompileBuiltin(df);
if (bi)
if (builtins[bi].returns)
return type_names[(*builtins[bi].returns)->type];
return "void"; //no returns statements found
}
@ -1070,8 +1098,9 @@ void DecompileCalcProfiles(void)
if (df->first_statement <= 0)
{
if (-df->first_statement <= sizeof(builtins)/sizeof(builtins[0]) && builtins[-df->first_statement].text)
QC_snprintfz(fname, sizeof(fname), "%s %s", builtins[-df->first_statement].text, strings + functions[i].s_name);
unsigned int bi = DecompileBuiltin(df);
if (bi && builtins[bi].text)
QC_snprintfz(fname, sizeof(fname), "%s %s", builtins[bi].text, strings + functions[i].s_name);
else
{
QC_snprintfz(fname, sizeof(fname), "__variant(...) %s", strings + functions[i].s_name);
@ -1872,11 +1901,12 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent
int pn;
dfunction_t *cf;
QCC_ddef_t *def;
int bi = DecompileBuiltin(df);
fn = ((int*)pr_globals)[k->a];
cf = &functions[fn];
if (cf->first_statement<=0 && cf->first_statement > -(signed)(sizeof(builtins)/sizeof(builtins[0]))) //builtins don't have this info.
if (bi) //builtins don't have this info.
{
QCC_type_t **p = builtins[-cf->first_statement].params[(s->b-ofs_parms[0])/ofs_size];
QCC_type_t **p = builtins[bi].params[(s->b-ofs_parms[0])/ofs_size];
parmtype = p?*p:NULL;
}
else
@ -2407,7 +2437,8 @@ char *DecompileValueString(etype_t type, void *val)
if (*(float *)val > 999999 || *(float *)val < -999999) // ugh
QC_snprintfz(line, sizeof(line), "%.f", *(float *)val);
else if ((!(*(int*)val & 0x7f800000) || (*(int*)val & 0x7f800000)==0x7f800000) && (*(int*)val & 0x7fffffff))
QC_snprintfz(line, sizeof(line), "%%%i", *(int*)val);
//QC_snprintfz(line, sizeof(line), "%%%i", *(int*)val);
QC_snprintfz(line, sizeof(line), "/*%di*/%s", *(int*)val, DecompileString(*(int *)val));
else if ((*(float *)val < 0.001) && (*(float *)val > 0))
QC_snprintfz(line, sizeof(line), "%.6f", *(float *)val);
else

View File

@ -607,7 +607,7 @@ static struct entvars_s *PDECL PR_entvars (pubprogfuncs_t *ppf, struct edict_s *
return (struct entvars_s *)edvars(ed);
}
static pbool PDECL PR_GetFunctionInfo(pubprogfuncs_t *ppf, func_t func, int *args, int *builtinnum, char *funcname, size_t funcnamesize)
static pbool PDECL PR_GetFunctionInfo(pubprogfuncs_t *ppf, func_t func, int *args, qbyte **argsizes, int *builtinnum, char *funcname, size_t funcnamesize)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
@ -627,6 +627,8 @@ static pbool PDECL PR_GetFunctionInfo(pubprogfuncs_t *ppf, func_t func, int *arg
f = pr_progstate[pnum].functions + fnum;
if (args)
*args = f->numparms;
if (argsizes)
*argsizes = f->parm_size;
if (builtinnum)
*builtinnum = -f->first_statement;
if (funcname)

View File

@ -1609,7 +1609,7 @@ static int PR_NoDebugVM(progfuncs_t *fte_restrict progfuncs)
strcpy(stack, "This platform does not support QC debugging\nStack Trace:");
ofs = strlen(stack);
PR_SaveCallStack (progfuncs, stack, &ofs, sizeof(stack));
PR_RunError (&progfuncs->funcs, stack);
PR_RunError (&progfuncs->funcs, "%s", stack);
return -1;
}
#endif

View File

@ -181,7 +181,7 @@ struct pubprogfuncs_s
void (PDECL *AddSharedVar) (pubprogfuncs_t *progfuncs, int start, int size);
void (PDECL *AddSharedFieldVar) (pubprogfuncs_t *progfuncs, int num, char *relstringtable);
char *(PDECL *RemoveProgsString) (pubprogfuncs_t *progfuncs, string_t str);
pbool (PDECL *GetFunctionInfo) (pubprogfuncs_t *progfuncs, func_t func, int *argcount, int *builtinnum, char *funcname, size_t funcnamesize); //queries the interesting info from a function def
pbool (PDECL *GetFunctionInfo) (pubprogfuncs_t *progfuncs, func_t func, int *argcount, qbyte **argsizes, int *builtinnum, char *funcname, size_t funcnamesize); //queries the interesting info from a function def
void (PDECL *GenerateStatementString) (pubprogfuncs_t *progfuncs, int statementnum, char *out, int outlen); //disassembles a specific statement. for debugging reports.
fdef_t *(PDECL *FieldInfo) (pubprogfuncs_t *progfuncs, unsigned int *count);
char *(PDECL *UglyValueString) (pubprogfuncs_t *progfuncs, etype_t type, union eval_s *val);

View File

@ -47,6 +47,11 @@ extern progfuncs_t *qccprogfuncs;
#endif
#endif
#ifndef STRINGIFY
#define STRINGIFY2(s) #s
#define STRINGIFY(s) STRINGIFY2(s)
#endif
void *qccHunkAlloc(size_t mem);
void qccClearHunk(void);

View File

@ -15,6 +15,9 @@ int QCC_PR_CheckCompConst(void);
pbool QCC_Include(const char *filename);
void QCC_FreeDef(QCC_def_t *def);
extern pbool destfile_explicit;
extern char destfile[1024];
#define MAXINCLUDEDIRS 8
char qccincludedir[MAXINCLUDEDIRS][256]; //the -src path, for #includes
struct qccincludeonced_s
@ -934,16 +937,15 @@ static pbool QCC_PR_Precompiler(void)
}
else if (!strncmp(directive, "merge", 5))
{
extern char destfile[1024];
pr_file_p=directive+5;
while(qcc_iswhitesameline(*pr_file_p))
pr_file_p++;
QCC_PR_SimpleGetString();
externs->Printf("Merging to %s\n", pr_token);
externs->Printf("Merging from %s\n", pr_token);
QCC_ImportProgs(pr_token);
if (!*destfile)
if (!*destfile && !destfile_explicit)
{
QCC_Canonicalize(destfile, sizeof(destfile), pr_token, compilingfile);
externs->Printf("Outputfile: %s\n", destfile);
@ -1062,15 +1064,17 @@ static pbool QCC_PR_Precompiler(void)
}
else if (!strncmp(directive, "output", 6))
{
extern char destfile[1024];
pr_file_p=directive+6;
while(qcc_iswhitesameline(*pr_file_p))
pr_file_p++;
QCC_PR_SimpleGetString();
QCC_Canonicalize(destfile, sizeof(destfile), pr_token, compilingfile);
externs->Printf("Outputfile: %s\n", pr_token);
if (!destfile_explicit)
{
QCC_Canonicalize(destfile, sizeof(destfile), pr_token, compilingfile);
externs->Printf("Outputfile: %s\n", pr_token);
}
QCC_PR_SkipToEndOfLine(true);
}
@ -1357,12 +1361,12 @@ static pbool QCC_PR_Precompiler(void)
}
else if (!QC_strcasecmp(qcc_token, "PROGS_DAT"))
{ //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
extern char destfile[1024];
char olddest[1024];
Q_strlcpy(olddest, destfile, sizeof(olddest));
QCC_COM_Parse(msg);
QCC_Canonicalize(destfile, sizeof(destfile), qcc_token, compilingfile);
if (!destfile_explicit) //if output file is named on the commandline, don't change it mid-compile
QCC_Canonicalize(destfile, sizeof(destfile), qcc_token, compilingfile);
if (strcmp(destfile, olddest))
externs->Printf("Outputfile: %s\n", destfile);
@ -3253,13 +3257,19 @@ static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t
QC_snprintfz(retbuf, retbufsize, "%i", rand());
return retbuf;
}
#if defined(SVNREVISION) && defined(SVNDATE)
if (!strcmp(constname, "__QCCREV__"))
return STRINGIFY(SVNREVISION); //no M or anything, so you can compare revisions properly
#endif
if (!strcmp(constname, "__QCCVER__"))
{
#ifdef SVNVERSION
if (strcmp(SVNVERSION, "-"))
return "FTEQCC " STRINGIFY(SVNVERSION);
#if defined(SVNREVISION) && defined(SVNDATE)
return "\"FTEQCC " STRINGIFY(SVNREVISION) " "STRINGIFY(SVNDATE)"\"";
#elif defined(SVNREVISION)
return "\"FTEQCC " STRINGIFY(SVNREVISION) " "__DATE__"\"";
#else
return "\""__DATE__"\"";
#endif
return "\"FTEQCC "__DATE__","__TIME__"\"";
}
if (!strcmp(constname, "__FILE__"))
{

View File

@ -1748,12 +1748,13 @@ void GenericMenu(WPARAM wParam)
break;
case IDM_ABOUT:
#ifdef SVNVERSION
if (strcmp(SVNVERSION, "-"))
MessageBox(NULL, "FTE QuakeC Compiler "STRINGIFY(SVNVERSION)" ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
else
#if defined(SVNREVISION) && defined(SVNDATE)
MessageBox(NULL, "FTE QuakeC Compiler "STRINGIFY(SVNREVISION)" ("SVNDATE")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
#elif defined(SVNREVISION)
MessageBox(NULL, "FTE QuakeC Compiler "STRINGIFY(SVNREVISION)" ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
#else
MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
#endif
MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
break;
case IDM_CASCADE:

View File

@ -76,6 +76,7 @@ pbool compressoutput;
pbool newstylesource;
char destfile[1024]; //the file we're going to output to
pbool destfile_explicit; //destfile was override on the commandline, don't let qc change it.
QCC_eval_t *qcc_pr_globals;
unsigned int numpr_globals;
@ -423,11 +424,13 @@ struct {
static const char *QCC_VersionString(void)
{
#ifdef SVNVERSION
if (strcmp(SVNVERSION, "-"))
return "FTEQCC: " STRINGIFY(SVNVERSION) " (" __DATE__")";
#endif
#if defined(SVNREVISION) && defined(SVNDATE)
return "FTEQCC: " STRINGIFY(SVNREVISION) " (" STRINGIFY(SVNDATE) ")";
#elif defined(SVNREVISION)
return "FTEQCC: " STRINGIFY(SVNREVISION) " (" __DATE__")";
#else
return "FTEQCC: " __DATE__;
#endif
}
/*
@ -4008,10 +4011,12 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
{ //explicit output file
i++;
strcpy(destfile, myargv[i]);
destfile_explicit = true;
}
else if ( !strncmp(myargv[i], "-o", 2) )
{ //explicit output file
strcpy(destfile, myargv[i]+2);
destfile_explicit = true;
}
else if ( !strcmp(myargv[i], "-qc") )
QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Argument %s is experimental", myargv[i]); //compile without linking. output cannot be read by engines.
@ -4995,7 +5000,7 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string));
strcpy(sourcefileslist[numsourcefiles++], qccmprogsdat);
currentsourcefile = 0;
}
else if (currentsourcefile == numsourcefiles)
else if (currentsourcefile == numsourcefiles || (currentsourcefile && destfile_explicit))
{
//no more.
qcc_compileactive = false;

View File

@ -576,7 +576,7 @@ static int minortype;
#endif
static int protocollen;
static qbyte buffer[MAX_QWMSGLEN];
static qbyte buffer[MAX_OVERALLMSGLEN];
static int bufferlen;
static int nullterms;
@ -1026,7 +1026,10 @@ void NPP_NQCheckDest(int dest)
void NPP_AddData(const void *data, int len)
{
if (bufferlen+len > sizeof(buffer))
Sys_Error("Preparse buffer was filled\n");
{
bufferlen = 0;
SV_Error("Preparse buffer was filled\n");
}
memcpy(buffer+bufferlen, data, len);
bufferlen+=len;
}

View File

@ -1779,7 +1779,7 @@ static void PDECL PR_DoSpawnInitialEntity(pubprogfuncs_t *progfuncs, struct edic
if (developer.value)
{
int argcount;
progfuncs->GetFunctionInfo(progfuncs, f, &argcount, NULL, spawnfuncname, sizeof(spawnfuncname));
progfuncs->GetFunctionInfo(progfuncs, f, &argcount, NULL, NULL, spawnfuncname, sizeof(spawnfuncname));
if (argcount != 0)
Con_Printf("Spawn function %s defined with unsatisfied arguments\n", spawnfuncname);
}
@ -6980,7 +6980,7 @@ static void QCBUILTIN PF_checkbuiltin (pubprogfuncs_t *prinst, struct globalvars
char *funcname = NULL;
int args;
int builtinno;
if (prinst->GetFunctionInfo(prinst, funcref, &args, &builtinno, funcname, sizeof(funcname)))
if (prinst->GetFunctionInfo(prinst, funcref, &args, NULL, &builtinno, funcname, sizeof(funcname)))
{ //qc defines the function at least. nothing weird there...
if (builtinno > 0 && builtinno < prinst->parms->numglobalbuiltins)
{
@ -10321,12 +10321,12 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
#ifndef SERVERONLY
//begin menu-only 'standard'
{"checkextension", PF_Fixme, 0, 0, 0, 1, D("float(string ext)", "Checks if the named extension is supported by the running engine.")},
{"error", PF_Fixme, 0, 0, 0, 2, "void(string err,...)"},
{"objerror", PF_Fixme, 0, 0, 0, 3, "void(string err,...)"},
{"print", PF_Fixme, 0, 0, 0, 4, "void(string text,...)"},
{"error", PF_Fixme, 0, 0, 0, 2, D("void(string err,...)", "Fatal error that will trigger a crash-to-console that users will actually notice.")},
{"objerror", PF_Fixme, 0, 0, 0, 3, D("void(string err,...)", "For some reason this has been redefined as non-fatal, and as it won't force the user to look at the console it'll generally be ignored completely so really what's the point? Other than as a convoluted way to remove(self) that is.")},
{"print", PF_Fixme, 0, 0, 0, 4, D("void(string text,...)", "Hello, world. Shoves junk on the console. Hopefully people will bother to read it, maybe.")},
{"bprint", PF_Fixme, 0, 0, 0, 5, "void(string text,...)"},
{"msprint", PF_Fixme, 0, 0, 0, 6, "void(float clientnum, string text,...)"},
{"cprint", PF_Fixme, 0, 0, 0, 7, "void(string text,...)"},
{"cprint", PF_Fixme, 0, 0, 0, 7, D("void(string text,...)", "Tries to show the given message in the centre of the screen, assuming that its not obscured by menus. Oh hey look, you're calling it in menuqc!")},
{"normalize", PF_Fixme, 0, 0, 0, 8, "vector(vector)"},
{"vlen", PF_Fixme, 0, 0, 0, 9, "float(vector)"},
{"vectoyaw", PF_Fixme, 0, 0, 0, 10, "float(vector)"},
@ -10347,11 +10347,11 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"findfloat", PF_Fixme, 0, 0, 0, 25, "entity(entity start, .__variant field, __variant match)"},
{"findchain", PF_Fixme, 0, 0, 0, 26, "entity(.string field, string match)"},
{"findchainfloat", PF_Fixme, 0, 0, 0, 27, "entity(.__variant field, __variant match)"},
{"precache_file", PF_Fixme, 0, 0, 0, 28, "string(string file)"},
{"precache_file", PF_Fixme, 0, 0, 0, 28, D("string(string file)", "Attempts to download the named file from the current server, if it isn't found locally. Not very useful as menuqc is normally meant to work before joining servers too.")},
{"precache_sound", PF_Fixme, 0, 0, 0, 29, "string(string sample)"},
{"coredump", PF_Fixme, 0, 0, 0, 30, "void()"},
{"traceon", PF_Fixme, 0, 0, 0, 31, "void()"},
{"traceoff", PF_Fixme, 0, 0, 0, 32, "void()"},
{"coredump", PF_Fixme, 0, 0, 0, 30, D("void()", "Takes a dump, writing the qcvm's state to disk. There are normally easier ways to debug, but I suppose this one still beats print spam.")},
{"traceon", PF_Fixme, 0, 0, 0, 31, D("void()", "Enables single-stepping. Its generally easier to just set a breakpoint.")},
{"traceoff", PF_Fixme, 0, 0, 0, 32, D("void()", "Disables single-stepping. Which sucks if you started said singlestepping outside of qc.")},
{"eprint", PF_Fixme, 0, 0, 0, 33, "void(entity)"},
{"rint", PF_Fixme, 0, 0, 0, 34, "float(float)"},
{"floor", PF_Fixme, 0, 0, 0, 35, "float(float)"},
@ -10361,12 +10361,12 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"cos", PF_Fixme, 0, 0, 0, 39, "float(float)"},
{"sqrt", PF_Fixme, 0, 0, 0, 40, "float(float)"},
{"randomvector", PF_Fixme, 0, 0, 0, 41, "vector()"},
{"registercvar", PF_Fixme, 0, 0, 0, 42, "float(string name, string value, float flags)"},
{"registercvar", PF_Fixme, 0, 0, 0, 42, D("float(string name, string value, float flags)", "Creates the cvar if it didn't already exist. This presents issues for setting those cvars via startup configs of course, and autocvars are easier but I suppose they don't get any flags (which are ignored anyway, of course).")},
{"min", PF_Fixme, 0, 0, 0, 43, "float(float,...)"},
{"max", PF_Fixme, 0, 0, 0, 44, "float(float,...)"},
{"bound", PF_Fixme, 0, 0, 0, 45, "float(float min,float value,float max)"},
{"pow", PF_Fixme, 0, 0, 0, 46, "float(float,float)"},
{"copyentity", PF_Fixme, 0, 0, 0, 47, "void(entity src, entity dst)"},
{"copyentity", PF_Fixme, 0, 0, 0, 47, D("void(entity src, entity dst)", "Copies all entity fields from one entity into another (forgetting any that were previously set on the destination).")},
{"fopen", PF_Fixme, 0, 0, 0, 48, "filestream(string filename, float mode)"},
{"fclose", PF_Fixme, 0, 0, 0, 49, "void(filestream fhandle)"},
{"fgets", PF_Fixme, 0, 0, 0, 50, "string(filestream fhandle)"},
@ -10375,36 +10375,36 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"strcat", PF_Fixme, 0, 0, 0, 53, "string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string)"},
{"substring", PF_Fixme, 0, 0, 0, 54, "string(string s, float start, float length)"},
{"stov", PF_Fixme, 0, 0, 0, 55, "vector(string)"},
{"strzone", PF_Fixme, 0, 0, 0, 56, "string(string)"},
{"strunzone", PF_Fixme, 0, 0, 0, 57, "void(string)"},
{"tokenize", PF_Fixme, 0, 0, 0, 58, "float(string)"},
{"argv", PF_Fixme, 0, 0, 0, 59, "string(float)"},
{"isserver", PF_Fixme, 0, 0, 0, 60, "float()"},
{"clientcount", PF_Fixme, 0, 0, 0, 61, "float()"},
{"clientstate", PF_Fixme, 0, 0, 0, 62, "float()"},
{"clientcommand", PF_Fixme, 0, 0, 0, 63, "void(float client, string s)"},
{"changelevel", PF_Fixme, 0, 0, 0, 64, "void(string map)"},
{"localsound", PF_Fixme, 0, 0, 0, 65, "void(string sample, optional float channel, optional float volume)"},
{"getmousepos", PF_Fixme, 0, 0, 0, 66, "vector()"},
{"strzone", PF_Fixme, 0, 0, 0, 56, D("string(string)", "Exists in FTE for compat only, no different from strcat.")},
{"strunzone", PF_Fixme, 0, 0, 0, 57, D("void(string)", "Exists in FTE for compat only, does nothing.")},
{"tokenize", PF_Fixme, 0, 0, 0, 58, D("float(string)", "Splits up the given string into its different components (what constitutes a token separator is not well defined and has been hacked about with over the years so have fun with that), returning the number of tokens that were found. Call argv(0 through ret-1) to retrieve each individual token. Take care to not use this recursively.")},
{"argv", PF_Fixme, 0, 0, 0, 59, D("string(float)", "Returns one of the tokens found via tokenize (and equivelent builtins).")},
{"isserver", PF_Fixme, 0, 0, 0, 60, D("float()", "Returns true if the local engine is running a server, and thus cvars and localcmds are shared with said server.")},
{"clientcount", PF_Fixme, 0, 0, 0, 61, D("float()", "Returns the maximum number of players on the server. Useless if its a remote server, so its a kinda useless builtin really.")},
{"clientstate", PF_Fixme, 0, 0, 0, 62, D("float()", "Tells you whether the client is actually connected to anything. 0 for a dedicated server (but dedicated servers don't normally run menuqc anyway), 2 if connecting or connected to a server (but not necessarily spawned+active), 1 for sitting around idle without trying to connect to anything yet.")},
{"clientcommand", PF_Fixme, 0, 0, 0, 63, D("void(float client, string s)", "Fakes a 'cmd foo' message from the specified player to the local server, and also bypasses ssqc handling of it greatly limiting the use of this builtin."), true},
{"changelevel", PF_Fixme, 0, 0, 0, 64, D("void(string map)", "Not really any different from a localcmd, but with proper string escapes.")},
{"localsound", PF_Fixme, 0, 0, 0, 65, D("void(string sample, optional float channel, optional float volume)", "Plays a sound, locally. precaching is optional, but recommended.")},
{"getmousepos", PF_Fixme, 0, 0, 0, 66, D("vector()", "Obsolete. Return values depend upon the current cursor mode. Implement Menu_InputEvent instead, so you can handle deltas as-is or absolutes if that's all the OS can provide.")},
{"gettime", PF_Fixme, 0, 0, 0, 67, "float(optional float timetype)"},
{"loadfromdata", PF_Fixme, 0, 0, 0, 68, "void(string data)"},
{"loadfromfile", PF_Fixme, 0, 0, 0, 69, "void(string data)"},
{"loadfromdata", PF_Fixme, 0, 0, 0, 68, D("void(string s)", "Reads a set of entities from the given string. This string should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead.")},
{"loadfromfile", PF_Fixme, 0, 0, 0, 69, D("void(string s)", "Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead.")},
{"mod", PF_Fixme, 0, 0, 0, 70, "float(float val, float m)"},
{"cvar_string", PF_Fixme, 0, 0, 0, 71, "string(string name)"},
{"crash", PF_Fixme, 0, 0, 0, 72, "void()"},
{"stackdump", PF_Fixme, 0, 0, 0, 73, "void()"},
{"cvar_string", PF_Fixme, 0, 0, 0, 71, D("string(string name)", "Returns the value of a cvar, as a string.")},
{"crash", PF_Fixme, 0, 0, 0, 72, D("void()", "Demonstrates that no program is bug free.")},
{"stackdump", PF_Fixme, 0, 0, 0, 73, D("void()", "Prints out the QC's stack, for console-based error reports.")},
{"search_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, float caseinsensitive, float quiet)"},
{"search_end", PF_Fixme, 0, 0, 0, 75, "void(searchhandle handle)"},
{"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(searchhandle handle)"},
{"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(searchhandle handle, float num)"},
{"etof", PF_Fixme, 0, 0, 0, 79, "float(entity)"},
{"ftoe", PF_Fixme, 0, 0, 0, 80, "entity(float)"},
{"validstring", PF_Fixme, 0, 0, 0, 81, "float(string)"},
{"altstr_count", PF_Fixme, 0, 0, 0, 82, "float(string str)"},
{"altstr_prepare", PF_Fixme, 0, 0, 0, 83, "string(string str)"},
{"altstr_get", PF_Fixme, 0, 0, 0, 84, "string(string str, float num)"},
{"altstr_set", PF_Fixme, 0, 0, 0, 85, "string(string str, float num, string set) "},
{"altstr_ins", PF_Fixme, 0, 0, 0, 86, "string(string str, float num, string set)"},
{"validstring", PF_Fixme, 0, 0, 0, 81, D("float(string)", "Returns true if str isn't null. In case 'if [not](str)' was configured to test for empty instead of null.")},
{"altstr_count", PF_Fixme, 0, 0, 0, 82, D("float(string str)", "Reports how many single-quotes there were in the string, divided by 2.")},
{"altstr_prepare", PF_Fixme, 0, 0, 0, 83, D("string(string str)", "Adds markup to escape only single-quotes. Does not add any.")},
{"altstr_get", PF_Fixme, 0, 0, 0, 84, D("string(string str, float num)", "Gets the Nth single-quoted token in the input.")},
{"altstr_set", PF_Fixme, 0, 0, 0, 85, D("string(string str, float num, string setval)", "Changes the Nth single-quoted token. The setval argument must not contain any single-quotes (use altstr_prepare to ensure this).")},
{"altstr_ins", PF_Fixme, 0, 0, 0, 86, D("string(string str, float num, string set)", NULL), true},
{"findflags", PF_Fixme, 0, 0, 0, 87, "entity(entity start, .float field, float match)"},
{"findchainflags", PF_Fixme, 0, 0, 0, 88, "entity(.float field, float match)"},
{"mcvar_defstring", PF_Fixme, 0, 0, 0, 89, "string(string name)" STUB},
@ -10909,7 +10909,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//gonna expose these to ssqc as a debugging extension
{"R_BeginPolygon", PF_R_PolygonBegin,0,0, 0, 306, D("void(string texturename, optional float flags, optional float is2d)", "Specifies the shader to use for the following polygons, along with optional flags.\nIf is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects.")},// (EXT_CSQC_???)
{"R_PolygonVertex", PF_R_PolygonVertex,0,0, 0, 307, D("void(vector org, vector texcoords, vector rgb, float alpha)", "Specifies a polygon vertex with its various properties.")},// (EXT_CSQC_???)
{"R_EndPolygon", PF_R_PolygonEnd,0, 0, 0, 308, D("void()", "Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader.")},
{"R_EndPolygon", PF_R_PolygonEnd,0, 0, 0, 308, D("void()", "Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon again if you wish to draw another polygon with the same shader.")},
{"R_EndPolygonRibbon",PF_Fixme, 0, 0, 0, 0, D("void(float radius, vector texcoordbias)", "Ends the current primitive and duplicates each vertex sideways into a ribbon. The texcoordbias will be added to each duplicated vertex allowing for regular 2d textures. At least 2 verticies must have been specified. You do not need to call beginpolygon again if you wish to draw another polygon with the same shader.")},
{"getproperty", PF_Fixme, 0, 0, 0, 309, D("#define getviewprop getproperty\n__variant(float property)", "Retrieve a currently-set (typically view) property, allowing you to read the current viewport or other things. Due to cheat protection, certain values may be unretrievable.")},// (EXT_CSQC_1)
@ -10969,7 +10970,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"setcursormode", PF_Fixme, 0, 0, 0, 343, D("void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale)", "Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port.")},
{"getcursormode", PF_Fixme, 0, 0, 0, 0, D("float(float effective)", "Reports the cursor mode this module previously attempted to use. If 'effective' is true, reports the cursor mode currently active (if was overriden by a different module which has precidence, for instance, or if there is only a touchscreen and no mouse).")},
{"getmousepos", PF_Fixme, 0, 0, 0, 344, D("vector()", "Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods.")}, // #344 This is a DP extension
{"getmousepos", PF_Fixme, 0, 0, 0, 344, D("vector()", "Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent instead for such things in csqc mods.")}, // #344 This is a DP extension
{"setmousepos", PF_Fixme, 0, 0, 0, 0, D("void(vector newpos)", "Warps the mouse cursor to the given location. Should normally only be done following setcursormode(TRUE,...). The warp MAY be visible through *_InputEvent, but normally be seen as an IE_ABSMOUSE event anyway. Not all systems support cursor warping (or even cursors), so this is a hint only and you should not depend upon it.")},
{"getinputstate", PF_Fixme, 0, 0, 0, 345, D("float(float inputsequencenum)", "Looks up an input frame from the log, setting the input_* globals accordingly.\nThe sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe.\nThe sequence equal to clientcommandframe will change between input frames.")},// (EXT_CSQC)
{"setsensitivityscaler",PF_Fixme,0, 0, 0, 346, D("void(float sens)", "Temporarily scales the player's mouse sensitivity based upon something like zoom, avoiding potential cvar saving and thus corruption.")},// (EXT_CSQC)
@ -12036,7 +12038,7 @@ void PR_DumpPlatform_f(void)
#undef comfieldstring
#undef comfieldfunction
{"URI_Get_Callback", "void(float reqid, float responsecode, string resourcebody)", QW|NQ|CS|MENU, "Called as an eventual result of the uri_get builtin."},
{"URI_Get_Callback", "void(float reqid, float responsecode, string resourcebody, int resourcebytes)", QW|NQ|CS|MENU, "Called as an eventual result of the uri_get builtin."},
{"SpectatorConnect", "void()", QW|NQ, "Called when a spectator joins the game."},
{"SpectatorDisconnect", "void()", QW|NQ, "Called when a spectator disconnects from the game."},
{"SpectatorThink", "void()", QW|NQ, "Called each frame for each spectator."},
@ -12751,7 +12753,13 @@ void PR_DumpPlatform_f(void)
"-Faccessors - use accessors instead of basic types via defines\n"
"-O - write to a different qc file\n"
"*/\n"
, FULLENGINENAME, STRINGIFY(SVNREVISION), __DATE__, Cmd_Argv(0), Cmd_Args());
, FULLENGINENAME, STRINGIFY(SVNREVISION),
#ifdef SVNDATE
STRINGIFY(SVNDATE)
#else
__DATE__
#endif
, Cmd_Argv(0), Cmd_Args());
VFS_PRINTF(f, "#pragma noref 1\n");
VFS_PRINTF(f, "//#pragma flag enable logicops\n");

View File

@ -1553,7 +1553,7 @@ void SV_Savegame (const char *savename, qboolean mapchange)
int height = vid.pixelheight;
image_t *img;
uploadfmt_t format;
void *rgbbuffer = SCR_ScreenShot_Capture(width, height, &stride, &format, false);
void *rgbbuffer = SCR_ScreenShot_Capture(width, height, &stride, &format, false, false);
if (rgbbuffer)
{
// extern cvar_t scr_sshot_type;

View File

@ -1110,14 +1110,15 @@ char *SV_BannedReason (netadr_t *a);
void SV_EvaluatePenalties(client_t *cl);
void SV_AutoAddPenalty (client_t *cl, unsigned int banflag, int duration, char *reason);
//note: not all penalties are actually penalties, but they can still expire.
#define BAN_BAN (1u<<0) //user is banned from the server
#define BAN_PERMIT (1u<<1) //user can evade block bans or filterban
#define BAN_PERMIT (1u<<1) //+user can evade block bans or filterban
#define BAN_CUFF (1u<<2) //can't shoot/use impulses
#define BAN_MUTE (1u<<3) //can't use say/say_team
#define BAN_MUTE (1u<<3) //can't use say/say_team/voip
#define BAN_CRIPPLED (1u<<4) //can't move
#define BAN_DEAF (1u<<5) //can't see say/say_team
#define BAN_LAGGED (1u<<6) //given an extra 200ms
#define BAN_VIP (1u<<7) //mods might give the user special rights, via the *VIP infokey. the engine itself currently does not do anything but track it.
#define BAN_VIP (1u<<7) //+mods might give the user special rights, via the *VIP infokey. the engine itself currently does not do anything but track it.
#define BAN_BLIND (1u<<8) //player's pvs is wiped.
#define BAN_SPECONLY (1u<<9) //player is forced to spectate
#define BAN_STEALTH (1u<<10)//player is not told of their bans
@ -1129,7 +1130,8 @@ void SV_AutoAddPenalty (client_t *cl, unsigned int banflag, int duration, char *
#define BAN_USER6 (1u<<16)//mod-specified
#define BAN_USER7 (1u<<17)//mod-specified
#define BAN_USER8 (1u<<18)//mod-specified
#define BAN_MAPPER (1u<<19)//player is allowed to use the brush/entity editing clc.
#define BAN_MAPPER (1u<<19)//+player is allowed to use the brush/entity editing clc.
#define BAN_VMUTE (1u<<20)//can't use voip (but can still use other forms of chat)
#define BAN_NOLOCALHOST (BAN_BAN|BAN_PERMIT|BAN_SPECONLY) //any attempt to ban localhost is denied, but you can vip, lag, cripple, etc them.

View File

@ -52,6 +52,7 @@ static const struct banflags_s
{BAN_PERMIT, {"safe", "permit"}},
{BAN_CUFF, {"cuff"}},
{BAN_MUTE, {"mute"}},
{BAN_VMUTE, {"vmute"}},
{BAN_CRIPPLED, {"cripple"}},
{BAN_DEAF, {"deaf"}},
{BAN_LAGGED, {"lag", "lagged"}},
@ -876,6 +877,17 @@ void SV_Map_f (void)
host_client->prespawn_stage = PRESPAWN_INVALID;
host_client->prespawn_idx = 0;
}
#ifdef NQPROT
if (dpcompat_nopreparse.ival)
{ //wipe broadcasts here...
sv.reliable_datagram.cursize = 0;
sv.datagram.cursize = 0;
sv.nqreliable_datagram.cursize = 0;
sv.nqdatagram.cursize = 0;
}
#endif
SV_SendMessagesToAll ();
if (flushparms)

View File

@ -2553,6 +2553,7 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
name = Info_ValueForKey (info->userinfo, "name");
/*
if (sv.world.worldmodel && info->protocol == SCP_QUAKEWORLD &&!atoi(Info_ValueForKey (info->userinfo, "iknow")))
{
if (sv.world.worldmodel->fromgame == fg_halflife && !(newcl->fteprotocolextensions & PEXT_HLBSP))
@ -2581,6 +2582,7 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
}
#endif
}
*/
SV_FixupName(name, temp.namebuf, sizeof(temp.namebuf));
name = temp.namebuf;
@ -5109,7 +5111,7 @@ float SV_Frame (void)
// get packets
isidle = !SV_ReadPackets (&delay);
if (pr_imitatemvdsv.ival)
if (pr_imitatemvdsv.ival || dpcompat_nopreparse.ival)
{
Cbuf_Execute ();
if (sv.state < ss_active) //whoops...
@ -5196,7 +5198,7 @@ float SV_Frame (void)
}
// process console commands
if (!pr_imitatemvdsv.value)
if (!(pr_imitatemvdsv.value || dpcompat_nopreparse.ival))
Cbuf_Execute ();
}
@ -5714,7 +5716,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
}
}
if (!cl->drop && strncmp(val, cl->name, sizeof(cl->namebuf)-1) && cl->state > cs_zombie)
if (!cl->drop && strncmp(newname, cl->name, sizeof(cl->namebuf)-1) && cl->state > cs_zombie)
{
if (*cl->name && cl->state >= cs_spawned && !cl->spectator && verbose)
{
@ -5989,9 +5991,7 @@ void SV_Init (quakeparms_t *parms)
Sys_Quit();
#endif
Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__);
Con_Printf ("%s\n", version_string());
Con_Printf ("Exe: %s\n", version_string());
Con_TPrintf ("======== %s Initialized ========\n", *fs_gamename.string?fs_gamename.string:"Nothing");

View File

@ -711,10 +711,7 @@ void SV_Init (struct quakeparms_s *parms)
Cvar_ForceCallback(&sv_masterport);
Cvar_ForceCallback(&sv_masterport_tcp);
Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__);
Con_Printf ("%s\n", version_string());
Con_Printf ("Exe: %s\n", version_string());
Con_TPrintf ("======== %s Initialized ========\n", "FTEMaster");
}

View File

@ -2541,6 +2541,7 @@ void SV_UserCmdMVDList_f (void)
void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
{
//#define EMBEDGAME
mvddest_t *d;
dir_t *dir;
file_t *list;
@ -2557,6 +2558,7 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
".mydiv { width: 20%%; height: 100%%; padding: 0px; margin: 0px; border: 0px solclass #aaaaaa; float:left; }"
".game { width: 80%%; height: 100%%; padding: 0px; margin: 0px; border: 0px solclass #aaaaaa; float:left; }"
"</style>"
#ifdef EMBEDGAME
"<script>"
"function playdemo(demo)"
"{"
@ -2564,6 +2566,7 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
"thegame.postMessage({cmd:'playdemo',url:demo}, '*');"
"}"
"</script>"
#endif
"</head>"
"<body>"
"<div class='mydiv'>\n"
@ -2588,7 +2591,11 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
{
char datetime[64];
strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", localtime(&list->mtime));
#ifdef EMBEDGAME
VFS_PRINTF(pipe, "%d: <a href='/demos/%s'>%s</a> %uk <a href='javascript:void(0)' onclick='playdemo(\"%s\")'>play</a> %s<br/>\n", i, list->name, list->name, (unsigned int)(list->size/1024), list->name, datetime);
#else
VFS_PRINTF(pipe, "%d: <a href='/demos/%s'>%s</a> %uk %s<br/>\n", i, list->name, list->name, (unsigned int)(list->size/1024), datetime);
#endif
}
}
@ -2606,13 +2613,15 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
VFS_PRINTF(pipe,
"</div>"
#ifdef EMBEDGAME
"<div class='game'>"
"<iframe name='thegame'" //the name of the game is... thegame!
" src='"ENGINEWEBSITE"/quake' allowfullscreen=true"
" frameborder='0' scrolling='no' marginheight='0' marginwidth='0' width='100%%' height='100%%'"
" onerror=\"alert('Failed to load engine')\">"
"</iframe>"
"</iframe>"
"</div>"
#endif
"</body>\n"
"</html>\n");

View File

@ -464,7 +464,7 @@ static int WPhys_FlyMove (world_t *w, wedict_t *ent, const vec3_t gravitydir, fl
if (-DotProduct(gravitydir, trace.plane.normal) > 0.7)
{
blocked |= 1; // floor
if (((wedict_t *)trace.ent)->v->solid == SOLID_BSP)
if (((wedict_t *)trace.ent)->v->solid == SOLID_BSP || dpcompat_noretouchground.ival)
{
ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
ent->v->groundentity = EDICT_TO_PROG(w->progs, trace.ent);

View File

@ -699,8 +699,6 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
strftime (buffer, sizeof(buffer), "Time: %Y-%m-%d %H:%M:%S\n",timeinfo);
write(fd, buffer, strlen(buffer));
Q_snprintfz(buffer, sizeof(buffer), "Binary: "__DATE__" "__TIME__"\n");
write(fd, buffer, strlen(buffer));
Q_snprintfz(buffer, sizeof(buffer), "Ver: %i.%02i%s\n", FTE_VER_MAJOR, FTE_VER_MINOR,
#ifdef OFFICIAL_RELEASE
" (official)");
@ -708,13 +706,17 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
"");
#endif
write(fd, buffer, strlen(buffer));
#ifdef SVNREVISION
if (strcmp(STRINGIFY(SVNREVISION), "-"))
{
Q_snprintfz(buffer, sizeof(buffer), "Revision: %s\n", STRINGIFY(SVNREVISION));
write(fd, buffer, strlen(buffer));
}
#if defined(SVNREVISION) && defined(SVNDATE)
Q_snprintfz(buffer, sizeof(buffer), "Revision: %s\nBinary: %s\n", STRINGIFY(SVNREVISION), STRINGIFY(SVNDATE));
#else
Q_snprintfz(buffer, sizeof(buffer),
#ifdef SVNREVISION
"Revision: "STRINGIFY(SVNREVISION)"\n"
#endif
"Binary: "__DATE__" "__TIME__"\n");
#endif
write(fd, buffer, strlen(buffer));
backtrace_symbols_fd(array + firstframe, size - firstframe, fd);
write(fd, "\n", 1);

Some files were not shown because too many files have changed in this diff Show More