implemented pm_stepdown.

attempt to implement 'simple csqc' api.
handle qw+nq gunshot+blood+lightning differently - they do actually have different particle spawn patterns (qw is a single point, so spreads wider).
fix q3ui logo mesh thing. work around q3ui player meshes on d3d.
split video and renderer latching, so vid_reload delatches more stuff.
fix autosprite+autosprite2 in 6 different renderers...
added fog volumes to d3d9 renderer.
using matrix hacks instead of glDepthRange, this should give more consistent behaviour, especially now that we have r_viewmodel_fov.
small cleanup for gl shadowmaps to make the interface more consistent with other renderers.
added patchDef2 parsing to fte's .map loader, doesn't actually use it though.
some fixes for q3's shaders, including to try to get overbright working better.
updated customskin api to give more control.
first attempt at a packager system for fteqccgui. probably useless, but whatever.
menusys changes to try to support QSS's csqc.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5200 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-01-22 19:18:04 +00:00
parent 63acc99442
commit 9e8bb446f4
88 changed files with 5595 additions and 3104 deletions

View File

@ -1847,11 +1847,11 @@ _qcc-tmp: $(REQDIR)
qcc-rel:
@$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)"
qccgui-rel:
@$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
@$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
qcc-dbg:
@$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)"
qccgui-dbg:
@$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
@$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
#scintilla is messy as fuck when building statically. but at least we can strip out the lexers we don't use this way.
@ -1869,7 +1869,7 @@ scintilla$(BITS)_static:
@$(MAKE) reldir OUT_DIR=$(RELEASE_DIR)/$(QCC_DIR)scin
@$(MAKE) $(RELEASE_DIR)/scintilla$(BITS).a VPATH="$(SCINTILLA_DIRS)" CFLAGS="$(SCINTILLA_INC) -DDISABLE_D2D -DSTATIC_BUILD -DSCI_LEXER -std=c++11" OUT_DIR=$(RELEASE_DIR)/$(QCC_DIR)scin WCFLAGS="$(WCFLAGS) -Os" WARNINGFLAGS=
qccgui-scintilla: scintilla$(BITS)_static
@$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o decomp.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
@$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
ifdef windir
debugdir:

View File

@ -189,6 +189,7 @@ dlight_t *CL_AllocSlight(void)
dl = &cl_dlights[rtlights_max++];
CL_ClearDlight(dl, 0);
dl->flags = LFLAG_REALTIMEMODE;
dl->corona = 0;
return dl;
}

View File

@ -162,7 +162,7 @@ cvar_t cl_sendguid = CVARD("cl_sendguid", "", "Send a randomly generated 'glo
cvar_t cl_downloads = CVARFD("cl_downloads", "1", CVAR_NOTFROMSERVER, "Allows you to block all automatic downloads.");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer.");
cvar_t cl_download_mapsrc = CVARFD("cl_download_mapsrc", "", CVAR_ARCHIVE, "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\"");
cvar_t cl_download_mapsrc = CVARFD("cl_download_mapsrc", "", CVAR_ARCHIVE, "Specifies an http location prefix for map downloads. EG: \"http://example.com/path/quakemaps/\"");
cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)");
cvar_t requiredownloads = CVARFD("requiredownloads","1", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining.");
@ -2146,6 +2146,7 @@ void CL_CheckServerInfo(void)
cl.bunnyspeedcap = Q_atof(Info_ValueForKey(cl.serverinfo, "pm_bunnyspeedcap"));
movevars.slidefix = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_slidefix")) != 0);
movevars.airstep = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_airstep")) != 0);
movevars.stepdown = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_stepdown")) != 0);
movevars.walljump = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_walljump")));
movevars.ktjump = Q_atof(Info_ValueForKey(cl.serverinfo, "pm_ktjump"));
s = Info_ValueForKey(cl.serverinfo, "pm_stepheight");

View File

@ -1233,11 +1233,7 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
qboolean anycsqc;
char *endptr;
unsigned int chksum;
#ifdef _DEBUG
anycsqc = true;
#else
anycsqc = atoi(Info_ValueForKey(cl.serverinfo, "anycsqc"));
#endif
if (cls.demoplayback)
anycsqc = true;
s = Info_ValueForKey(cl.serverinfo, "*csprogs");
@ -3775,7 +3771,6 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
#ifdef PEXT_CSQC
CSQC_Shutdown();
CSQC_Init(cls.demoplayback, false, 0);
#endif
}
static void CLNQ_SendInitialUserInfo(void *ctx, const char *key, const char *value)

View File

@ -492,27 +492,61 @@ void CL_CalcCrouch (playerview_t *pv)
VectorCopy (pv->simorg, pv->oldorigin);
if (pv->onground && orgz - pv->oldz > 0)
if (pv->onground && orgz - pv->oldz)// > 0)
{
if (orgz - pv->oldz > movevars.stepheight+2)
{
// if on steep stairs, increase speed
if (pv->crouchspeed < 160)
{
pv->extracrouch = orgz - pv->oldz - host_frametime * 200 - 15;
pv->extracrouch = min(pv->extracrouch, 5);
}
pv->crouchspeed = 160;
}
pv->oldz += host_frametime * pv->crouchspeed;
if (pv->oldz > orgz)
pv->oldz = orgz;
{ //stepping down should be a little faster than stepping up.
//so steps will still feel a little juddery. my knees hate walking down steep hills, so I guess this is similar.
if (pv->crouchspeed > 0)
pv->crouchspeed = -pv->crouchspeed*2;
if (orgz - pv->oldz > 15 + pv->extracrouch)
pv->oldz = orgz - 15 - pv->extracrouch;
pv->extracrouch -= host_frametime * 200;
pv->extracrouch = max(pv->extracrouch, 0);
if (orgz - pv->oldz < -movevars.stepheight-2)
{
// if on steep stairs, increase speed
if (pv->crouchspeed > -160*2)
{
pv->extracrouch = orgz - pv->oldz + host_frametime * 400 + 15;
// pv->extracrouch = max(pv->extracrouch, -5);
}
pv->crouchspeed = -160*2;
}
pv->oldz += host_frametime * pv->crouchspeed;
if (pv->oldz < orgz)
pv->oldz = orgz;
if (pv->oldz > orgz + 15 - pv->extracrouch)
pv->oldz = orgz + 15 - pv->extracrouch;
pv->extracrouch += host_frametime * 400;
pv->extracrouch = min(pv->extracrouch, 0);
}
else
{
if (pv->crouchspeed < 0)
pv->crouchspeed = -pv->crouchspeed/2;
if (orgz - pv->oldz > movevars.stepheight+2)
{
// if on steep stairs, increase speed
if (pv->crouchspeed < 160)
{
pv->extracrouch = orgz - pv->oldz - host_frametime * 200 - 15;
pv->extracrouch = min(pv->extracrouch, 5);
}
pv->crouchspeed = 160;
}
pv->oldz += host_frametime * pv->crouchspeed;
if (pv->oldz > orgz)
pv->oldz = orgz;
// if (orgz - pv->oldz > 15 + pv->extracrouch)
if (pv->oldz < orgz - 15 - pv->extracrouch)
pv->oldz = orgz - 15 - pv->extracrouch;
pv->extracrouch -= host_frametime * 200;
pv->extracrouch = max(pv->extracrouch, 0);
}
pv->crouch = pv->oldz - orgz;
}
@ -520,12 +554,25 @@ void CL_CalcCrouch (playerview_t *pv)
{
// in air or moving down
pv->oldz = orgz;
pv->crouch += host_frametime * 150;
if (orgz - pv->oldz < 0)
pv->crouch -= orgz - pv->oldz; //if the view moved down, remove that amount from our crouching to avoid unneeded bobbing
if (pv->crouch > 0)
pv->crouch = 0;
pv->crouchspeed = 100;
{
//step-down
pv->crouch -= host_frametime * 150;
if (orgz - pv->oldz > 0)
pv->crouch += orgz - pv->oldz; //if the view moved down, remove that amount from our crouching to avoid unneeded bobbing
if (pv->crouch > 0)
pv->crouch = 0;
pv->crouchspeed = -100;
}
else
{ //step-up
pv->crouch += host_frametime * 150;
if (orgz - pv->oldz < 0)
pv->crouch -= orgz - pv->oldz; //if the view moved down, remove that amount from our crouching to avoid unneeded bobbing
if (pv->crouch > 0)
pv->crouch = 0;
pv->crouchspeed = 100;
}
pv->extracrouch = 0;
}
}

View File

@ -171,6 +171,7 @@ int
rtdp_nexuizplasma=P_INVALID,
rtdp_glowtrail=P_INVALID,
ptqw_gunshot=P_INVALID,
ptqw_blood=P_INVALID,
ptqw_lightningblood=P_INVALID,
@ -516,7 +517,8 @@ void CL_RegisterParticles(void)
rtdp_glowtrail = P_FindParticleType("TR_GLOWTRAIL");
/*internal to psystem*/ P_FindParticleType("SVC_PARTICLE");
ptqw_blood = P_FindParticleType("TE_BLOOD");
ptqw_gunshot = (pt_gunshot!=P_INVALID)?pt_gunshot:P_FindParticleType("TE_QWGUNSHOT"); /*shotgun*/
ptqw_blood = (ptdp_blood!=P_INVALID)?ptdp_blood:P_FindParticleType("TE_QWBLOOD");
ptqw_lightningblood = P_FindParticleType("TE_LIGHTNINGBLOOD");
#ifdef Q2CLIENT

View File

@ -414,7 +414,7 @@ void VQ3_AddEntity(const q3refEntity_t *q3)
ent.shaderRGBAf[2] = q3->shaderRGBA[2]/255.0f;
ent.shaderRGBAf[3] = q3->shaderRGBA[3]/255.0f;
/*don't set translucent, the shader is meant to already be correct*/
/*don't set force-translucent etc, the shader is meant to already be correct*/
// if (ent.shaderRGBAf[3] <= 0)
// return;
@ -581,6 +581,10 @@ void VQ3_RenderView(const q3refdef_t *ref)
{
int i;
extern cvar_t r_torch;
if (R2D_Flush)
R2D_Flush();
VectorCopy(ref->vieworg, r_refdef.vieworg);
r_refdef.viewangles[0] = -(atan2(ref->viewaxis[0][2], sqrt(ref->viewaxis[0][1]*ref->viewaxis[0][1]+ref->viewaxis[0][0]*ref->viewaxis[0][0])) * 180 / M_PI);
r_refdef.viewangles[1] = (atan2(ref->viewaxis[0][1], ref->viewaxis[0][0]) * 180 / M_PI);
@ -592,8 +596,8 @@ void VQ3_RenderView(const q3refdef_t *ref)
r_refdef.flags |= RDF_NOWORLDMODEL;
else
r_refdef.flags &= ~RDF_NOWORLDMODEL;
r_refdef.fov_x = ref->fov_x;
r_refdef.fov_y = ref->fov_y;
r_refdef.fovv_x = r_refdef.fov_x = ref->fov_x;
r_refdef.fovv_y = r_refdef.fov_y = ref->fov_y;
r_refdef.vrect.x = ref->x;
r_refdef.vrect.y = ref->y;
r_refdef.vrect.width = ref->width;
@ -604,6 +608,14 @@ void VQ3_RenderView(const q3refdef_t *ref)
r_refdef.maxdist = gl_maxdist.value;
r_refdef.playerview = &cl.playerview[0];
if (ref->y < 0)
{ //evil hack to work around player model ui bug.
//if the y coord is off screen, reduce the height to keep things centred, and reduce the fov to compensate.
r_refdef.vrect.height += ref->y*2;
r_refdef.fovv_y = r_refdef.fov_y = ref->fov_y * r_refdef.vrect.height / ref->height;
r_refdef.vrect.y = 0;
}
memset(&r_refdef.globalfog, 0, sizeof(r_refdef.globalfog));
if (r_torch.ival)
@ -1635,14 +1647,17 @@ void UI_Start (void)
void UI_Restart_f(void)
{
UI_Stop();
UI_Start();
if (uivm)
if (strcmp(Cmd_Argv(1), "off"))
{
if (cls.state)
VM_Call(uivm, UI_SET_ACTIVE_MENU, 2);
else
VM_Call(uivm, UI_SET_ACTIVE_MENU, 1);
UI_Start();
if (uivm)
{
if (cls.state)
VM_Call(uivm, UI_SET_ACTIVE_MENU, 2);
else
VM_Call(uivm, UI_SET_ACTIVE_MENU, 1);
}
}
}

View File

@ -297,8 +297,10 @@ typedef struct
#define LFLAG_NOSHADOWS (1<<8)
#define LFLAG_SHADOWMAP (1<<9)
#define LFLAG_CREPUSCULAR (1<<10)
#define LFLAG_CREPUSCULAR (1<<10) //weird type of sun light that gives god rays
//#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)
typedef struct dlight_s
@ -1389,6 +1391,8 @@ qboolean CSQC_ConsoleLink(char *text, char *info);
void CSQC_RegisterCvarsAndThings(void);
qboolean CSQC_SetupToRenderPortal(int entnum);
qboolean CSQC_DrawView(void);
qboolean CSQC_DrawHud(playerview_t *pv);
qboolean CSQC_DrawScores(playerview_t *pv);
qboolean CSQC_UseGamecodeLoadingScreen(void);
void CSQC_Shutdown(void);
qboolean CSQC_StuffCmd(int lplayernum, char *cmd, char *cmdend);

View File

@ -339,7 +339,7 @@ INS_ShowMouse
static void INS_ShowMouse (void)
{
if (!mouseshowtoggle)
{
{ //FIXME: we should be sending this via the window thread.
ShowCursor (TRUE);
mouseshowtoggle = 1;
}
@ -354,8 +354,12 @@ INS_HideMouse
static void INS_HideMouse (void)
{
if (mouseshowtoggle)
{
ShowCursor (FALSE);
{ //I'm told that nvidia's null-named 'Geforce Experience' (which is malware in my book) fucks with cursor visibility.
//So lets try to ensure that it gets hidden properly in case we've got race conditions and code getting injected into our process.
//in modern windows, this is per-thread, so blame code injection if this ever prints.
//FIXME: we should be sending this via the window thread.
while (ShowCursor (FALSE) >= 0)
Con_Printf(CON_WARNING "Force-hiding mouse cursor...\n");
mouseshowtoggle = 0;
}
}

View File

@ -1049,7 +1049,7 @@ menucheck_t *MC_AddCheckBox(menu_t *menu, int tx, int cx, int y, const char *tex
if (var)
if (!(var->flags & CVAR_ARCHIVE))
Con_Printf("Warning: %s is not set for archiving\n", var->name);
else if (var->flags & CVAR_RENDERERLATCH)
else if (var->flags & (CVAR_RENDERERLATCH|CVAR_VIDEOLATCH))
Con_Printf("Warning: %s requires a vid_restart\n", var->name);
#endif

View File

@ -62,6 +62,18 @@ static const char **resaspects[ASPECT_RATIOS] =
res16x10
};
#define ASPECT_LIST "4:3", "5:4", "16:9", "16:10",
enum
{
ASPECT3D_DESKTOP = ASPECT_RATIOS,
ASPECT3D_CUSTOM,
};
enum
{
ASPECT2D_AUTO = ASPECT_RATIOS,
ASPECT2D_HEIGHT,
ASPECT2D_SCALED,
ASPECT2D_CUSTOM,
};
qboolean M_Vid_GetMode(int num, int *w, int *h)
{
@ -982,6 +994,22 @@ void FPS_Preset_f (void)
return;
}
if (!stricmp("tenebrae", arg))
{ //for the luls. combine with the tenebrae mod for maximum effect.
Cbuf_InsertText(
"set r_shadow_realtime_world 1\n"
"set r_shadow_realtime_dlight 1\n"
"set r_shadow_bumpscale_basetexture 4\n"
"set r_shadow_shadowmapping 0\n"
"set gl_specular 1\n"
"set gl_specular_power 16\n"
"set gl_specular_fallback 1\n"
"set mod_litsprites_force 1\n"
"set r_nolerp 1\n" //well, that matches tenebrae. for the luls, right?
, RESTRICT_LOCAL, false);
return;
}
if (!stricmp("timedemo", arg))
{
//some extra things to pwn timedemos.
@ -2347,20 +2375,20 @@ void CheckCustomMode(struct menu_s *menu)
{
info->resmode->common.ishidden = false;
sel = info->resmode->selectedoption;
if (sel < ASPECT_RATIOS)
{
// unhide appropriate aspect ratio combo and restricted bpp/hz combos
info->bppfixed->common.ishidden = false;
info->hzfixed->common.ishidden = false;
info->ressize[sel]->common.ishidden = false;
}
else if (sel == (ASPECT_RATIOS + 1))
if (sel == ASPECT3D_CUSTOM)
{ // unhide custom entries for custom option
info->width->common.ishidden = false;
info->height->common.ishidden = false;
info->bpp->common.ishidden = false;
info->hz->common.ishidden = false;
}
else if (sel != ASPECT3D_DESKTOP)
{
// unhide appropriate aspect ratio combo and restricted bpp/hz combos
info->bppfixed->common.ishidden = false;
info->hzfixed->common.ishidden = false;
info->ressize[sel]->common.ishidden = false;
}
}
// hide all 2d display controls
info->width2d->common.ishidden = true;
@ -2369,15 +2397,17 @@ void CheckCustomMode(struct menu_s *menu)
for (i = 0; i < ASPECT_RATIOS; i++)
info->res2dsize[i]->common.ishidden = true;
sel = info->res2dmode->selectedoption;
if (sel < ASPECT_RATIOS) // unhide appropriate aspect ratio combo
info->res2dsize[sel]->common.ishidden = false;
else if (sel == (ASPECT_RATIOS + 1)) // unhide scale option
if (sel == ASPECT2D_SCALED) // unhide scale option
info->scale->common.ishidden = false;
else if (sel == (ASPECT_RATIOS + 2)) // unhide custom entries for custom option
else if (sel == ASPECT2D_HEIGHT) // unhide custom entries for height-only option
info->height2d->common.ishidden = false;
else if (sel == ASPECT2D_CUSTOM) // unhide custom entries for custom option
{
info->width2d->common.ishidden = false;
info->height2d->common.ishidden = false;
}
else if (sel != ASPECT2D_AUTO) // unhide appropriate aspect ratio combo
info->res2dsize[sel]->common.ishidden = false;
}
int M_MatchModes(int width, int height, int *outres)
@ -2438,10 +2468,10 @@ qboolean M_VideoApply (union menuoption_s *op, struct menu_s *menu, int key)
switch (info->resmode->selectedoption)
{
case ASPECT_RATIOS: // Desktop
case ASPECT3D_DESKTOP: // Desktop
dc = "1";
break;
case ASPECT_RATIOS + 1: // Custom
case ASPECT3D_CUSTOM: // Custom
wc = info->width->text;
hc = info->height->text;
bc = info->bpp->text;
@ -2485,10 +2515,14 @@ qboolean M_VideoApply (union menuoption_s *op, struct menu_s *menu, int key)
{
case ASPECT_RATIOS: // Default
break;
case ASPECT_RATIOS + 1: // Scale
case ASPECT2D_SCALED: // Scale
sc = info->scale->values[info->scale->selectedoption];
break;
case ASPECT_RATIOS + 2: // Custom
case ASPECT2D_HEIGHT:
wc = "0";
hc = info->height2d->text;
break;
case ASPECT2D_CUSTOM: // Custom
wc = info->width2d->text;
hc = info->height2d->text;
break;
@ -2660,6 +2694,7 @@ void M_Menu_Video_f (void)
static const char *res2dmodeopts[] = {
ASPECT_LIST
"Default",
"Square (by height)",
"Scale",
"Custom",
NULL
@ -2702,16 +2737,18 @@ void M_Menu_Video_f (void)
snprintf(current3dres, sizeof(current3dres), "Current: %ix%i", vid.pixelwidth, vid.pixelheight);
resmodechoice = M_MatchModes(vid.pixelwidth, vid.pixelheight, reschoices);
if (vid_desktopsettings.ival)
resmodechoice = ASPECT_RATIOS;
resmodechoice = ASPECT3D_DESKTOP;
else if (resmodechoice < 0)
resmodechoice = ASPECT_RATIOS + 1;
resmodechoice = ASPECT3D_CUSTOM;
res2dmodechoice = M_MatchModes(vid.pixelwidth, vid.pixelheight, res2dchoices);
if (vid_conautoscale.ival >= 1)
res2dmodechoice = ASPECT_RATIOS + 1;
if (vid_conautoscale.value > 0)
res2dmodechoice = ASPECT2D_SCALED;
else if (!vid_conwidth.ival && !vid_conheight.ival)
res2dmodechoice = ASPECT_RATIOS;
res2dmodechoice = ASPECT2D_AUTO;
else if (!vid_conwidth.ival)
res2dmodechoice = ASPECT2D_HEIGHT;
else if (res2dmodechoice < 0)
res2dmodechoice = ASPECT_RATIOS + 2;
res2dmodechoice = ASPECT2D_CUSTOM;
{
menubulk_t bulk[] =

View File

@ -59,6 +59,9 @@ typedef enum {
EXPLOSION2_POINT,
TELEPORTSPLASH_POINT,
MUZZLEFLASH_POINT,
QWGUNSHOT_POINT, //not actually the same as nq, to deal with higher counts better
QWSTDBLOOD_POINT, //same
QWLGBLOOD_POINT, //same
EFFECTTYPE_MAX
} effect_type_t;
@ -160,6 +163,13 @@ static int PClassic_FindParticleType(const char *name)
if (!stricmp("ef_brightfield", name))
return BRIGHTFIELD_POINT;
if (!stricmp("te_qwgunshot", name))
return QWGUNSHOT_POINT;
if (!stricmp("te_qwblood", name))
return QWSTDBLOOD_POINT;
if (!stricmp("te_lightningblood", name))
return QWLGBLOOD_POINT;
return P_INVALID;
}
@ -716,7 +726,7 @@ static void Classic_BlobExplosion (vec3_t org)
}
}
static void Classic_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
static void Classic_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count, qboolean qwstyle)
{
int i, j, scale;
cparticle_t *p;
@ -724,7 +734,10 @@ static void Classic_RunParticleEffect (vec3_t org, vec3_t dir, int color, int co
if (!dir)
dir = vec3_origin;
scale = (count > 130) ? 3 : (count > 20) ? 2 : 1;
if (qwstyle)
scale = (count > 130) ? 3 : (count > 20) ? 2 : 1; //QW
else
scale = 1; //NQ
count = ceil(count*r_part_density.value); //round-to-0 was resulting in blood being far too hard to see, especially when blood is often spawned with multiple points all rounded down
@ -739,7 +752,10 @@ static void Classic_RunParticleEffect (vec3_t org, vec3_t dir, int color, int co
p->die = cl.time + 0.1 * (rand() % 5);
p->rgb = d_8to24rgbtable[(color & ~7) + (rand() & 7)];
p->type = pt_grav;
if (qwstyle)
p->type = pt_grav; //QW
else
p->type = pt_slowgrav; //NQ
for (j = 0; j < 3; j++)
{
p->org[j] = org[j] + scale * ((rand() & 15) - 8);
@ -950,6 +966,15 @@ static int PClassic_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
#endif
}
break;
case QWGUNSHOT_POINT:
Classic_RunParticleEffect(org, dir, 0, count*20, true);
break;
case QWSTDBLOOD_POINT:
Classic_RunParticleEffect(org, dir, 73, count*20, true);
break;
case QWLGBLOOD_POINT:
Classic_RunParticleEffect(org, dir, 225, count*50, true);
break;
default:
return 1;
}
@ -977,6 +1002,7 @@ static float Classic_ParticleTrail (vec3_t start, vec3_t end, float leftover, ef
VectorScale(delta, 1 / len, dir); //unit vector in direction of trail
VectorMA(point, -leftover, dir, point);
Con_Printf("%g %g\n", len, leftover);
len += leftover;
rlen = len;
@ -1122,11 +1148,11 @@ static int PClassic_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dl
//svc_particle support: add X particles with the given colour, velocity, and aproximate origin.
static void PClassic_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
{
Classic_RunParticleEffect(org, dir, color, count);
Classic_RunParticleEffect(org, dir, color, count, false);
}
static void PClassic_RunParticleEffectPalette (const char *nameprefix, vec3_t org, vec3_t dir, int color, int count)
{
Classic_RunParticleEffect(org, dir, color, count);
Classic_RunParticleEffect(org, dir, color, count, false);
}
particleengine_t pe_classic =

View File

@ -25,13 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
EXT_CSQC is the 'root' extension
EXT_CSQC_1 are a collection of additional features to cover omissions in the original spec
note the CHEAT_PARANOID define disables certain EXT_CSQC_1 features,
in an attempt to prevent the player from finding out where he/she is, thus preventing aimbots.
This is specifically targetted towards deathmatch mods where each player is a single player.
In reality, this paranoia provides nothing which could not be done with a cheat proxy.
Seeing as the client ensures hashes match in the first place, this paranoia gives nothing in the long run.
Unfortunatly EXT_CSQC was designed around this paranoia.
simplecsqc lacks CSQC_UpdateView and has CSQC_DrawHud+CSQC_DrawScores instead.
if we're running arbitrary csqc, we block things that require too much game interaction...
*/
#ifdef CSQC_DAT
@ -39,8 +34,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "glquake.h" //evil to include this
#include "shader.h"
//#define CHEAT_PARANOID
#include "pr_common.h"
extern usercmd_t cl_pendingcmd[MAX_SPLITS];
@ -76,9 +69,10 @@ qboolean csqc_dp_lastwas3d; //to emulate DP correctly, we need to track whether
#else
static qboolean csqc_isdarkplaces;
#endif
static qboolean csqc_singlecheats; /*single player or cheats active, allowing custom addons*/
static qboolean csqc_mayread; //csqc is allowed to ReadByte();
static qboolean csqc_worldchanged; //make sure any caches are rebuilt properly before the next renderscene
static qboolean csqc_nogameaccess; /*the module is not trusted by the server, so isn't allowed to access origins+stuffcmds+etc*/
static qboolean csqc_singlecheats; /*single player or cheats active, allowing custom addons*/
static qboolean csqc_mayread; /*csqc is allowed to ReadByte();*/
static qboolean csqc_worldchanged; /*make sure any caches are rebuilt properly before the next renderscene*/
static char csqc_printbuffer[8192];
@ -126,6 +120,8 @@ extern sfx_t *cl_sfx_r_exp3;
globalfunction(shutdown_function, "CSQC_Shutdown"); \
globalfunction(f_updateview, "CSQC_UpdateView"); \
globalfunction(f_updateviewloading, "CSQC_UpdateViewLoading"); \
globalfunction(f_drawhud, "CSQC_DrawHud");/*simple csqc*/ \
globalfunction(f_drawscores, "CSQC_DrawScores");/*simple csqc*/ \
globalfunction(parse_stuffcmd, "CSQC_Parse_StuffCmd"); \
globalfunction(parse_centerprint, "CSQC_Parse_CenterPrint"); \
globalfunction(parse_print, "CSQC_Parse_Print"); \
@ -163,6 +159,9 @@ extern sfx_t *cl_sfx_r_exp3;
globalentity(self, "self"); /*entity Written before entering most qc functions*/ \
globalentity(other, "other"); /*entity Written before entering most qc functions*/ \
\
globalentity(deathmatch, "deathmatch"); /*for simplecsqc*/ \
globalentity(coop, "coop"); /*for simplecsqc*/ \
\
globalfloat(maxclients, "maxclients"); /*float max number of players allowed*/ \
globalfloat(numclientseats, "numclientseats"); /*float number of seats/splitscreen clients running on this client*/ \
\
@ -195,6 +194,7 @@ extern sfx_t *cl_sfx_r_exp3;
globalfloat(player_localentnum, "player_localentnum"); /*float the entity number the local player is looking out from*/ \
globalfloat(player_localnum, "player_localnum"); /*float the player number of the local player*/ \
globalfloat(intermission, "intermission"); /*float set when the client receives svc_intermission*/ \
globalfloat(intermission_time, "intermission_time"); /*float set when the client receives svc_intermission*/ \
globalvector(view_angles, "view_angles"); /*float set to the view angles at the start of each new frame (EXT_CSQC_1)*/ \
\
globalvector(pmove_org, "pmove_org"); /*deprecated. read/written by runplayerphysics*/ \
@ -278,6 +278,9 @@ static void CSQC_ChangeLocalPlayer(int seat)
if (csqcg.player_localnum)
*csqcg.player_localnum = csqc_playerview->playernum;
if (csqc_nogameaccess)
return; //don't give much info otherwise.
if (csqcg.view_angles)
{
csqcg.view_angles[0] = csqc_playerview->viewangles[0];
@ -344,6 +347,30 @@ static void CSQC_FindGlobals(qboolean nofuncs)
#define ensurevector(name) if (!csqcg.name) csqcg.name = junk._vector;
#define ensureentity(name) if (!csqcg.name) csqcg.name = &junk.edict;
if (csqc_nogameaccess)
{
csqcg.f_updateview = 0; //would fail
csqcg.f_updateviewloading = 0; //would fail
csqcg.parse_stuffcmd = 0; //could block cvar changes, thus allow cheats
csqcg.parse_setangles = 0; //too evil
csqcg.input_frame = 0; //no aimbot writing
csqcg.event_sound = csqcg.serversound = 0; //no sound snooping
csqcg.parse_tempentity = 0; //compat nightmare
csqcg.view_angles = NULL;
csqcg.physics_mode = NULL; //no thinks stuff
csqcg.pmove_org = NULL; //can't make aimbots if you don't know where you're aiming from.
csqcg.pmove_vel = NULL; //no dead reckoning please
csqcg.pmove_mins = csqcg.pmove_maxs = csqcg.pmove_jump_held = csqcg.pmove_waterjumptime = csqcg.pmove_onground = NULL; //I just want to kill theses
csqcg.input_angles = csqcg.input_movevalues = csqcg.input_buttons = csqcg.input_impulse = csqcg.input_lightlevel = csqcg.input_weapon = csqcg.input_servertime = NULL;
csqcg.input_clienttime = csqcg.input_cursor_screen = csqcg.input_cursor_start = csqcg.input_cursor_impact = csqcg.input_cursor_entitynumber = NULL;
}
else if (csqcg.f_updateview || csqcg.f_updateviewloading)
{ //full csqc AND simplecsqc's entry points at the same time are a bad idea that just result in confusion.
//full csqc mods should just disable engine hud drawing
csqcg.f_drawhud = 0;
csqcg.f_drawscores = 0;
}
#ifdef NOLEGACY
{
etype_t etype = ev_void;
@ -1243,6 +1270,11 @@ void QCBUILTIN PF_R_DynamicLight_Add(pubprogfuncs_t *prinst, struct globalvars_s
const char *cubemapname = (prinst->callargc > 4)?PR_GetStringOfs(prinst, OFS_PARM4):"";
int pflags = (prinst->callargc > 5)?G_FLOAT(OFS_PARM5):PFLAGS_CORONA;
#ifdef RTLIGHTS
// float *ambientdiffusespec = (prinst->callargc > 5)?{0,1,1}:G_VECTOR(OFS_PARM6);
// fov, orientation, corona, coronascale, etc. gah
#endif
wedict_t *self;
dlight_t *dl;
int dlkey;
@ -1854,6 +1886,9 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
switch(parametertype)
{
nogameaccess:
csqc_deprecated("PF_R_GetViewFlag: game access is blocked");
break;
case VF_ACTIVESEAT:
if (prinst == csqc_world.progs)
*r = csqc_playerseat;
@ -1876,44 +1911,50 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
break;
case VF_ORIGIN:
#ifdef CHEAT_PARANOID
VectorClear(r);
#else
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
VectorCopy(r_refdef.vieworg, r);
#endif
break;
case VF_ORIGIN_Z:
case VF_ORIGIN_X:
case VF_ORIGIN_Y:
#ifdef CHEAT_PARANOID
*r = 0;
#else
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
*r = r_refdef.vieworg[parametertype-VF_ORIGIN_X];
#endif
break;
case VF_ANGLES:
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
VectorCopy(r_refdef.viewangles, r);
break;
case VF_ANGLES_X:
case VF_ANGLES_Y:
case VF_ANGLES_Z:
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
*r = r_refdef.viewangles[parametertype-VF_ANGLES_X];
break;
case VF_CL_VIEWANGLES_V:
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
if (csqc_playerview)
VectorCopy(csqc_playerview->viewangles, r);
break;
case VF_CL_VIEWANGLES_X:
case VF_CL_VIEWANGLES_Y:
case VF_CL_VIEWANGLES_Z:
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
if (csqc_playerview)
*r = csqc_playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X];
break;
case VF_CARTESIAN_ANGLES:
if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess;
Con_Printf(CON_WARNING "WARNING: CARTESIAN ANGLES ARE NOT YET SUPPORTED!\n");
break;
@ -1924,12 +1965,12 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
case VF_SIZE_X:
*r = r_refdef.grect.width;
if (csqc_isdarkplaces)
if (csqc_isdarkplaces && prinst == csqc_world.progs)
*r *= (float)vid.pixelwidth / vid.width;
break;
case VF_SIZE_Y:
*r = r_refdef.grect.height;
if (csqc_isdarkplaces)
if (csqc_isdarkplaces && prinst == csqc_world.progs)
*r *= (float)vid.pixelheight / vid.height;
break;
case VF_SIZE:
@ -1937,7 +1978,7 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
r[1] = r_refdef.grect.height;
r[2] = 0;
if (csqc_isdarkplaces)
if (csqc_isdarkplaces && prinst == csqc_world.progs)
{
r[0] *= (float)vid.pixelwidth / vid.width;
r[1] *= (float)vid.pixelheight / vid.height;
@ -2820,7 +2861,7 @@ void QCBUILTIN PF_cs_setcustomskin (pubprogfuncs_t *prinst, struct globalvars_s
if (ent->skinobject > 0)
{
Mod_WipeSkin(ent->skinobject);
Mod_WipeSkin(ent->skinobject, false);
ent->skinobject = 0;
}
@ -2832,6 +2873,36 @@ void QCBUILTIN PF_cs_setcustomskin (pubprogfuncs_t *prinst, struct globalvars_s
ent->skinobject = -(int)Mod_RegisterSkinFile(fname);
}
}
void QCBUILTIN PF_cs_loadcustomskin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *fname = PR_GetStringOfs(prinst, OFS_PARM0);
const char *skindata = PF_VarString(prinst, 1, pr_globals);
if (*fname || *skindata)
{
if (*skindata)
G_FLOAT(OFS_RETURN) = Mod_ReadSkinFile(fname, skindata);
else
G_FLOAT(OFS_RETURN) = -(int)Mod_RegisterSkinFile(fname);
}
else
G_FLOAT(OFS_RETURN) = 0;
}
void QCBUILTIN PF_cs_releasecustomskin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int oldskin = G_FLOAT(OFS_PARM0);
if (oldskin > 0)
Mod_WipeSkin(oldskin, false);
}
void QCBUILTIN PF_cs_applycustomskin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
int newskin = G_FLOAT(OFS_PARM1);
int oldskin = ent->skinobject;
ent->skinobject = newskin;
if (oldskin > 0)
Mod_WipeSkin(oldskin, false);
}
static void QCBUILTIN PF_ReadByte(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -5085,6 +5156,12 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s
func_t func = G_INT(OFS_PARM1);
unsigned int flags = G_FLOAT(OFS_PARM2);
if (csqc_nogameaccess)
{
csqc_deprecated("PF_DeltaListen: game access is blocked");
return;
}
if (!prinst->GetFunctionInfo(prinst, func, NULL, NULL, NULL, 0))
{
Con_Printf("PF_DeltaListen: Bad function index\n");
@ -5131,6 +5208,14 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s *
lerpents_t *le;
entity_state_t *es;
if (csqc_nogameaccess)
{
G_FLOAT(OFS_RETURN+0) = 0;
G_FLOAT(OFS_RETURN+1) = 0;
G_FLOAT(OFS_RETURN+2) = 0;
return;
}
if (fldnum == GE_MAXENTS)
{
G_FLOAT(OFS_RETURN) = cl.maxlerpents;
@ -6214,6 +6299,9 @@ static struct {
{"particleeffectquery", PF_cs_particleeffectquery, 374},
{"adddecal", PF_R_AddDecal, 375},
{"setcustomskin", PF_cs_setcustomskin, 376},
{"loadcustomskin", PF_cs_loadcustomskin, 377},
{"applycustomskin", PF_cs_applycustomskin, 378},
{"releasecustomskin", PF_cs_releasecustomskin, 379},
{"memalloc", PF_memalloc, 384},
{"memfree", PF_memfree, 385},
@ -6285,6 +6373,7 @@ static struct {
{"clientcommand", PF_NoCSQC, 440}, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) (don't implement)
{"tokenize", PF_Tokenize, 441}, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
{"argv", PF_ArgV, 442}, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
{"argc", PF_ArgC, 0}, // #0 float() argc pointless, but whatever
{"setattachment", PF_setattachment, 443}, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
{"search_begin", PF_search_begin, 444}, // #444 float search_begin(string pattern, float caseinsensitive, float quiet) (DP_QC_FS_SEARCH)
@ -6615,7 +6704,7 @@ static pbool QDECL CSQC_EntFree (struct edict_s *e)
ent->xv->renderflags = 0;
if (ent->skinobject>0)
Mod_WipeSkin(ent->skinobject);
Mod_WipeSkin(ent->skinobject, false);
ent->skinobject = 0;
#ifdef USERBE
@ -6753,6 +6842,7 @@ void CSQC_Shutdown(void)
in_sensitivityscale = 1;
csqc_world.num_edicts = 0;
memset(&csqc_world, 0, sizeof(csqc_world));
memset(&csqcg, 0, sizeof(csqcg));
if (csqc_deprecated_warned>1)
{
@ -6762,12 +6852,9 @@ void CSQC_Shutdown(void)
}
//when the qclib needs a file, it calls out to this function.
qbyte *PDECL CSQC_PRLoadFile (const char *path, void *buffer, int bufsize, size_t *sz)
void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *sz)
{
qbyte *file;
size_t ssz;
if (!sz)
sz = &ssz;
qbyte *file = NULL;
if (!strcmp(path, "csprogs.dat"))
{
@ -6776,103 +6863,64 @@ qbyte *PDECL CSQC_PRLoadFile (const char *path, void *buffer, int bufsize, size_
if (csprogs_checksum)
{
file = COM_LoadStackFile(newname, buffer, bufsize, sz);
file = COM_LoadTempFile (newname, sz);
if (file)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, *sz) == csprogs_checksum)
return file;
}
else
{
if (LittleLong(Com_BlockChecksum(file, *sz)) == csprogs_checksum) //and the user wasn't trying to be cunning.
return file;
}
}
}
file = COM_LoadStackFile(path, buffer, bufsize, sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (csprogs_checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE)
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{
if (QCRC_Block(file, *sz) != csprogs_checksum)
return NULL;
file = NULL;
}
else
{
if (LittleLong(Com_BlockChecksum(file, *sz)) != csprogs_checksum)
return NULL; //not valid
if (LittleLong(Com_BlockChecksum(file, *sz)) != csprogs_checksum) //and the user wasn't trying to be cunning.
file = NULL;
}
#ifndef FTE_TARGET_WEB
//back it up
COM_WriteFile(newname, FS_GAMEONLY, file, *sz);
#endif
}
}
return file;
if (!file)
{
file = COM_LoadTempFile (path, sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (csprogs_checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{
if (QCRC_Block(file, *sz) != csprogs_checksum)
file = NULL;
}
else
{
if (LittleLong(Com_BlockChecksum(file, *sz)) != csprogs_checksum)
file = NULL; //not valid
}
#ifndef FTE_TARGET_WEB
if (file)
//back it up
COM_WriteFile(newname, FS_GAMEONLY, file, *sz);
#endif
}
}
}
}
else
file = COM_LoadTempFile (path, sz);
return COM_LoadStackFile(path, buffer, bufsize, sz);
if (file)
{
qbyte *buffer = buf_get(buf_ctx, *sz);
memcpy(buffer, file, *sz);
return buffer;
}
return NULL;
}
int QDECL CSQC_PRFileSize (const char *path)
{
qbyte *file;
size_t sz;
if (!strcmp(path, "csprogs.dat"))
{
char newname[MAX_QPATH];
snprintf(newname, MAX_QPATH, "csprogsvers/%x.dat", csprogs_checksum);
if (csprogs_checksum)
{
file = COM_LoadTempFile (newname, &sz);
if (file)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, sz) == csprogs_checksum)
return sz+1;
}
else
{
if (LittleLong(Com_BlockChecksum(file, sz)) == csprogs_checksum) //and the user wasn't trying to be cunning.
return sz+1;
}
}
}
file = COM_LoadTempFile(path, &sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (csprogs_checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE)
{
if (QCRC_Block(file, sz) != csprogs_checksum)
return -1; //not valid
}
else
{
if (LittleLong(Com_BlockChecksum(file, sz)) != csprogs_checksum)
return -1; //not valid
}
}
}
if (!file)
return -1;
return sz;
}
return COM_FileSize(path);
}
@ -7007,23 +7055,22 @@ void ASMCALL CSQC_ThinkTimeOp(pubprogfuncs_t *progs, edict_t *ed, float var)
pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
{
#ifndef csqc_isdarkplaces
if (!num)
{
if (crc == 22390)
csqc_isdarkplaces = false;
else
; //fte's full csqc stuff
else if (crc == 5927)
; //simple csqc. but only if
#ifndef csqc_isdarkplaces
else if (crc == 52195)
{
if (crc == 52195)
{
csqc_isdarkplaces = true;
Con_DPrintf(CON_WARNING "Running darkplaces csprogs.dat version\n");
}
else
Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n");
csqc_isdarkplaces = true;
Con_DPrintf(CON_WARNING "Running darkplaces csprogs.dat version\n");
}
}
#endif
else
Con_Printf(CON_WARNING "Running unknown csprogs.dat version\n");
}
return true;
}
@ -7071,6 +7118,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
movevars.ktjump = false;//pm_ktjump.value;
movevars.slidefix = true;//(pm_slidefix.value != 0);
movevars.airstep = true;//(pm_airstep.value != 0);
movevars.stepdown = true;
movevars.walljump = false;//(pm_walljump.value);
movevars.slidyslopes = false;//(pm_slidyslopes.value!=0);
movevars.watersinkspeed = 60;//*pm_watersinkspeed.string?pm_watersinkspeed.value:60;
@ -7091,7 +7139,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
memset(cl.model_csqcprecache, 0, sizeof(cl.model_csqcprecache));
csqcprogparms.progsversion = PROGSTRUCT_VERSION;
csqcprogparms.ReadFile = CSQC_PRLoadFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
csqcprogparms.ReadFile = CSQC_PRLoadFile;
csqcprogparms.FileSize = CSQC_PRFileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
csqcprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
csqcprogparms.Printf = PR_Printf;//Con_Printf;//void (*printf) (char *, ...);
@ -7160,12 +7208,17 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
csqc_isdarkplaces = false;
#endif
if (csdatenabled || csqc_singlecheats || anycsqc)
{
csqc_nogameaccess = false;
else
csqc_nogameaccess = true;
if (!csqc_nogameaccess)
{ //only load csprogs if its expected to be able to work without failing for game access reasons
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat");
if (csprogsnum == -1)
if (csprogsnum >= 0)
Con_DPrintf("Loaded csprogs.dat\n");
}
if (csqc_singlecheats || anycsqc)
{
csaddonnum = PR_LoadProgs(csqcprogs, "csaddon.dat");
@ -7177,12 +7230,27 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
else
Con_DPrintf("skipping csaddon.dat due to cheat restrictions\n");
if (csprogsnum < 0 && csaddonnum < 0) //simple csqc optionally uses the nq progs, but its explicitly limited
{
csqc_nogameaccess = true;
csprogsnum = PR_LoadProgs(csqcprogs, "progs.dat");
}
if (csprogsnum == -1 && csaddonnum == -1)
{
CSQC_Shutdown();
return false;
}
if (csqc_nogameaccess && !PR_FindFunction (csqcprogs, "CSQC_DrawHud", PR_ANY))
{ //simple csqc module is not csqc. abort now.
CSQC_Shutdown();
Con_DPrintf("Loaded progs.dat has no CSQC_DrawHud\n");
return false;
}
else if (csqc_nogameaccess)
Con_DPrintf("Loaded [csqc]progs.dat\n");
PR_ProgsAdded(csqcprogs, csprogsnum, "csprogs.dat");
PR_ProgsAdded(csqcprogs, csaddonnum, "csaddon.dat");
@ -7244,6 +7312,11 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
*str = PR_NewString(csqcprogs, s);
}
if (csqcg.deathmatch)
*csqcg.deathmatch = cl.deathmatch;
if (csqcg.coop)
*csqcg.coop = !cl.deathmatch && cl.allocated_client_slots > 1;
if (csqcg.init_function)
{
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
@ -7702,6 +7775,8 @@ qboolean CSQC_DrawView(void)
if (csqcg.intermission)
*csqcg.intermission = cl.intermissionmode;
if (csqcg.intermission_time)
*csqcg.intermission_time = cl.completed_time;
//work out which packet entities are solid
CL_SetSolidEntities ();
@ -7783,6 +7858,87 @@ qboolean CSQC_DrawView(void)
return true;
}
qboolean CSQC_DrawHud(playerview_t *pv)
{
if (csqcg.f_drawhud && (pv==cl.playerview/* || csqcg.numclientseats*/))
{
RSpeedMark();
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
//set csqc globals
CSQC_ChangeLocalPlayer(pv-cl.playerview);
if (csqcg.numclientseats)
*csqcg.numclientseats = cl.splitclients;
if (csqcg.simtime)
*csqcg.simtime = cl.time;
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
if (csqcg.cltime)
*csqcg.cltime = realtime;
G_FLOAT(OFS_PARM0+0) = r_refdef.grect.width;
G_FLOAT(OFS_PARM0+1) = r_refdef.grect.height;
G_FLOAT(OFS_PARM0+2) = 0;
G_FLOAT(OFS_PARM1) = (pv->sb_showscores?1:0) | (pv->sb_showteamscores?2:0);
// G_FLOAT(OFS_PARM2+0) = r_refdef.grect.x;
// G_FLOAT(OFS_PARM2+1) = r_refdef.grect.y;
// G_FLOAT(OFS_PARM2+2) = pv-cl.playerview;
PR_ExecuteProgram(csqcprogs, csqcg.f_drawhud);
if (*r_refdef.rt_destcolour[0].texname)
{
if (R2D_Flush)
R2D_Flush();
Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname));
BE_RenderToTextureUpdate2d(true);
}
RSpeedEnd(RSPEED_CSQCREDRAW);
return true;
}
return false;
}
qboolean CSQC_DrawScores(playerview_t *pv)
{
if (csqcg.f_drawscores && (pv==cl.playerview/* || csqcg.numclientseats*/))
{
RSpeedMark();
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
//set csqc globals (in case CSQC_DrawHud wasn't implemented)
CSQC_ChangeLocalPlayer(pv-cl.playerview);
if (csqcg.numclientseats)
*csqcg.numclientseats = cl.splitclients;
if (csqcg.simtime)
*csqcg.simtime = cl.time;
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
if (csqcg.cltime)
*csqcg.cltime = realtime;
G_FLOAT(OFS_PARM0+0) = r_refdef.grect.width;
G_FLOAT(OFS_PARM0+1) = r_refdef.grect.height;
G_FLOAT(OFS_PARM0+2) = 0;
G_FLOAT(OFS_PARM1) = (pv->sb_showscores?1:0) | (pv->sb_showteamscores?2:0);
// G_FLOAT(OFS_PARM2+0) = r_refdef.grect.x;
// G_FLOAT(OFS_PARM2+1) = r_refdef.grect.y;
// G_FLOAT(OFS_PARM2+2) = pv-cl.playerview;
PR_ExecuteProgram(csqcprogs, csqcg.f_drawscores);
if (*r_refdef.rt_destcolour[0].texname)
{
if (R2D_Flush)
R2D_Flush();
Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname));
BE_RenderToTextureUpdate2d(true);
}
RSpeedEnd(RSPEED_CSQCREDRAW);
return true;
}
return false;
}
qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid)
{
static qbyte csqckeysdown[K_MAX];

View File

@ -1817,7 +1817,7 @@ static void QCBUILTIN PF_m_setcustomskin(pubprogfuncs_t *prinst, struct globalva
if (val->_float > 0)
{
Mod_WipeSkin(val->_float);
Mod_WipeSkin(val->_float, false);
val->_float = 0;
}
@ -2485,7 +2485,27 @@ pbool PDECL Menu_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc)
return false;
}
static int QDECL MP_PRFileSize (const char *path)
static void *PDECL MP_PRReadFile (const char *path, qbyte *(PDECL *buf_get)(void *buf_ctx, size_t size), void *buf_ctx, size_t *size)
{
flocation_t loc;
if (FS_FLocateFile(path, FSLF_IFFOUND|FSLF_SECUREONLY, &loc))
{
qbyte *buffer = NULL;
vfsfile_t *file = FS_OpenReadLocation(&loc);
if (file)
{
*size = loc.len;
buffer = buf_get(buf_ctx, *size);
if (buffer)
VFS_READ(file, buffer, *size);
VFS_CLOSE(file);
}
return buffer;
}
else
return NULL;
}
static int PDECL MP_PRFileSize (const char *path)
{
flocation_t loc;
if (FS_FLocateFile(path, FSLF_IFFOUND|FSLF_SECUREONLY, &loc))
@ -2516,7 +2536,7 @@ qboolean MP_Init (void)
menuprogparms.progsversion = PROGSTRUCT_VERSION;
menuprogparms.ReadFile = COM_LoadStackFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
menuprogparms.ReadFile = MP_PRReadFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
menuprogparms.FileSize = MP_PRFileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
menuprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
menuprogparms.Printf = (void *)Con_Printf;//Con_Printf;//void (*printf) (char *, ...);
@ -2685,7 +2705,14 @@ void MP_CoreDump_f(void)
void MP_Reload_f(void)
{
M_Shutdown(false);
M_Reinit();
if (!strcmp(Cmd_Argv(1), "off"))
{ //explicitly restart the engine's menu. not the menuqc crap
//don't even start csqc menus.
M_Init_Internal();
}
else
M_Reinit();
}
static void MP_Poke_f(void)
@ -2795,6 +2822,7 @@ qboolean MP_Keydown(int key, int unicode, unsigned int devid)
if (setjmp(mp_abort))
return true;
#ifndef QUAKETC
if (key == 'c')
{
if (keydown[K_LCTRL] || keydown[K_RCTRL])
@ -2804,6 +2832,7 @@ qboolean MP_Keydown(int key, int unicode, unsigned int devid)
return true;
}
}
#endif
mpkeysdown[key>>3] |= (1<<(key&7));

View File

@ -3446,7 +3446,7 @@ void Surf_BuildModelLightmaps (model_t *m)
{
if (m->submodelof->loadstate != MLS_LOADED)
return;
newfirst = cl.model_precache[1]->lightmaps.first;
newfirst = m->submodelof->lightmaps.first;
}
else
{

View File

@ -162,6 +162,7 @@ typedef struct entity_s
#define Q1UNSPECIFIED 0x00ffffff //0xffRRGGBB or 0x0000000V are both valid values. so this is an otherwise-illegal value to say its not been set.
typedef struct
{
int refcount;
char skinname[MAX_QPATH];
int nummappings;
int maxmappings;
@ -487,7 +488,7 @@ extern texid_t ptritexture;
skinid_t Mod_RegisterSkinFile(const char *skinname);
skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext);
void Mod_WipeSkin(skinid_t id);
void Mod_WipeSkin(skinid_t id, qboolean force);
skinfile_t *Mod_LookupSkin(skinid_t id);
void Mod_Init (qboolean initial);

View File

@ -90,8 +90,8 @@ cvar_t gl_nocolors = CVARF ("gl_nocolors", "0", CVAR_ARCHIVE);
cvar_t gl_part_flame = CVARFD ("gl_part_flame", "1", CVAR_ARCHIVE, "Enable particle emitting from models. Mainly used for torch and flame effects.");
//opengl library, blank means try default.
static cvar_t gl_driver = CVARFD ("gl_driver", "", CVAR_ARCHIVE | CVAR_RENDERERLATCH, "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_RENDERERLATCH, "Specifies which video device to try to use. If blank or invalid then one will be guessed.");
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 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;
@ -178,7 +178,7 @@ cvar_t r_part_rain = CVARFD ("r_part_rain", "0",
"Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects.");
cvar_t r_skyboxname = CVARFC ("r_skybox", "",
CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM, R_SkyBox_Changed);
cvar_t r_softwarebanding_cvar = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well).");
cvar_t r_softwarebanding_cvar = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM|CVAR_RENDERERLATCH, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well).");
qboolean r_softwarebanding;
cvar_t r_speeds = CVAR ("r_speeds", "0");
cvar_t r_stainfadeammount = CVAR ("r_stainfadeammount", "1");
@ -248,38 +248,38 @@ cvar_t vid_conwidth = CVARF ("vid_conwidth", "0",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK);
//see R_RestartRenderer_f for the effective default 'if (newr.renderer == -1)'.
cvar_t vid_renderer = CVARFD ("vid_renderer", "",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Specifies which backend is used. Values that might work are: sv (dedicated server), headless (null renderer), vk (vulkan), gl (opengl), egl (opengl es), d3d9 (direct3d 9), d3d11 (direct3d 11, with default hardware rendering), d3d11 warp (direct3d 11, with software rendering).");
CVAR_ARCHIVE | CVAR_VIDEOLATCH, "Specifies which backend is used. Values that might work are: sv (dedicated server), headless (null renderer), vk (vulkan), gl (opengl), egl (opengl es), d3d9 (direct3d 9), d3d11 (direct3d 11, with default hardware rendering), d3d11 warp (direct3d 11, with software rendering).");
cvar_t vid_renderer_opts = CVARFD ("_vid_renderer_opts", "", CVAR_NOSET, "The possible video renderer apis, in \"value\" \"description\" pairs, for gamecode to read.");
cvar_t vid_bpp = CVARFD ("vid_bpp", "0",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The number of colour bits to request from the renedering context");
CVAR_ARCHIVE | CVAR_VIDEOLATCH, "The number of colour bits to request from the renedering context");
cvar_t vid_desktopsettings = CVARFD ("vid_desktopsettings", "0",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Ignore the values of vid_width and vid_height, and just use the same settings that are used for the desktop.");
CVAR_ARCHIVE | CVAR_VIDEOLATCH, "Ignore the values of vid_width and vid_height, and just use the same settings that are used for the desktop.");
#ifdef NACL
cvar_t vid_fullscreen = CVARF ("vid_fullscreen", "0",
CVAR_ARCHIVE);
#else
//these cvars will be given their names when they're registered, based upon whether -plugin was used. this means code can always use vid_fullscreen without caring, but gets saved properly.
cvar_t vid_fullscreen = CVARAFD (NULL, "1", "vid_fullscreen",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Whether to use fullscreen or not. A value of 2 specifies fullscreen windowed (aka borderless window) mode.");
CVAR_ARCHIVE | CVAR_VIDEOLATCH, "Whether to use fullscreen or not. A value of 2 specifies fullscreen windowed (aka borderless window) mode.");
cvar_t vid_fullscreen_alternative = CVARFD (NULL, "1",
CVAR_ARCHIVE, "Whether to use fullscreen or not. This cvar is saved to your config but not otherwise used in this operating mode.");
#endif
cvar_t vid_height = CVARFD ("vid_height", "0",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The screen height to attempt to use, in physical pixels. 0 means use desktop resolution.");
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_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_RENDERERLATCH);
CVAR_ARCHIVE | CVAR_VIDEOLATCH);
cvar_t vid_srgb = CVARFD ("vid_srgb", "0",
CVAR_ARCHIVE, "0: Off. Colour blending will be wrong.\n1: Only the framebuffer should use sRGB colourspace, textures and colours will be assumed to be linear. This has the effect of brightening the screen.\n2: Use sRGB extensions/support to ensure that the sh");
cvar_t vid_wndalpha = CVARD ("vid_wndalpha", "1", "When running windowed, specifies the window's transparency level.");
#if defined(_WIN32) && defined(MULTITHREAD)
cvar_t vid_winthread = CVARFD ("vid_winthread", "", CVAR_ARCHIVE|CVAR_RENDERERLATCH, "When enabled, window messages will be handled by a separate thread. This allows the game to continue rendering when Microsoft Windows blocks while resizing etc.");
cvar_t vid_winthread = CVARFD ("vid_winthread", "", CVAR_ARCHIVE|CVAR_VIDEOLATCH, "When enabled, window messages will be handled by a separate thread. This allows the game to continue rendering when Microsoft Windows blocks while resizing etc.");
#endif
//more readable defaults to match conwidth/conheight.
cvar_t vid_width = CVARFD ("vid_width", "0",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The screen width to attempt to use, in physical pixels. 0 means use desktop resolution.");
CVAR_ARCHIVE | CVAR_VIDEOLATCH, "The screen width to attempt to use, in physical pixels. 0 means use desktop resolution.");
cvar_t vid_dpi_x = CVARFD ("vid_dpi_x", "0", CVAR_NOSET, "For mods that need to determine the physical screen size (like with touchscreens). 0 means unknown");
cvar_t vid_dpi_y = CVARFD ("vid_dpi_y", "0", CVAR_NOSET, "For mods that need to determine the physical screen size (like with touchscreens). 0 means unknown");
@ -336,7 +336,7 @@ cvar_t r_tessellation_level = CVAR ("r_tessellation_level", "5");
cvar_t gl_blend2d = CVAR ("gl_blend2d", "1");
cvar_t gl_blendsprites = CVARD ("gl_blendsprites", "0", "Blend sprites instead of alpha testing them");
cvar_t r_deluxmapping_cvar = CVARAFD ("r_deluxemapping", "0", "r_glsl_deluxemapping",
CVAR_ARCHIVE, "Enables bumpmapping based upon precomputed light directions.\n0=off\n1=use if available\n2=auto-generate (if possible)");
CVAR_ARCHIVE|CVAR_RENDERERLATCH, "Enables bumpmapping based upon precomputed light directions.\n0=off\n1=use if available\n2=auto-generate (if possible)");
qboolean r_deluxmapping;
cvar_t r_shaderblobs = CVARD ("r_shaderblobs", "0", "If enabled, can massively accelerate vid restarts / loading (especially with the d3d renderer). Can cause issues when upgrading engine versions, so this is disabled by default.");
cvar_t gl_compress = CVARFD ("gl_compress", "0", CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed.");
@ -355,7 +355,7 @@ cvar_t gl_lerpimages = CVARFD ("gl_lerpimages", "1", CVAR_ARCHIVE, "Enable
//cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "",
// CVAR_ARCHIVE);
cvar_t gl_load24bit = CVARF ("gl_load24bit", "1",
CVAR_ARCHIVE);
CVAR_ARCHIVE|CVAR_RENDERERLATCH);
cvar_t r_clear = CVARAF("r_clear","0",
"gl_clear", 0);
@ -636,7 +636,7 @@ void R_ToggleFullscreen_f(void)
if (currentrendererstate.renderer->rtype == QR_HEADLESS || currentrendererstate.renderer->rtype == QR_NONE)
return;
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH);
newr = currentrendererstate;
if (newr.fullscreen)
@ -1011,7 +1011,7 @@ qboolean Renderer_Started(void)
void Renderer_Start(void)
{
r_blockvidrestart = false;
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH);
//renderer = none && currentrendererstate.bpp == -1 means we've never applied any mode at all
//if we currently have none, we do actually need to apply it still
@ -1608,6 +1608,7 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n"));
{
cl.worldmodel = NULL;
CG_Stop();
memset(cl.model_precache, 0, sizeof(cl.model_precache));
CG_Start();
if (cl.worldmodel)
Surf_NewMap();
@ -1726,6 +1727,8 @@ void R_ReloadRenderer_f (void)
float time = Sys_DoubleTime();
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
return; //don't bother reloading the renderer if its not actually rendering anything anyway.
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH);
R_ShutdownRenderer(false);
Con_DPrintf("teardown = %f\n", Sys_DoubleTime() - time);
//reloads textures without destroying video context.
@ -1975,7 +1978,7 @@ void R_RestartRenderer_f (void)
double time;
rendererstate_t newr;
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH);
if (!R_BuildRenderstate(&newr, vid_renderer.string))
{
Con_Printf("vid_renderer \"%s\" unsupported. Using default.\n", vid_renderer.string);
@ -2009,7 +2012,7 @@ void R_SetRenderer_f (void)
return;
}
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH);
if (!R_BuildRenderstate(&newr, param))
{
Con_Printf("setrenderer: parameter not supported (%s)\n", param);

View File

@ -721,7 +721,7 @@ void Sbar_ShowTeamScores (void)
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
;//return;
#endif
cl.playerview[seat].sb_showteamscores = true;
@ -768,7 +768,7 @@ void Sbar_ShowScores (void)
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
;//return;
#endif
cl.playerview[seat].sb_showscores = true;
@ -2224,6 +2224,9 @@ void Sbar_DrawScoreboard (playerview_t *pv)
if (Key_Dest_Has(~kdm_game))
return;
if (CSQC_DrawScores(pv))
return;
#ifndef CLIENTONLY
/*no scoreboard in single player (if you want bots, set deathmatch)*/
if (sv.state && sv.allocated_client_slots == 1)
@ -2773,6 +2776,9 @@ void Sbar_Draw (playerview_t *pv)
qboolean minidmoverlay;
extern cvar_t scr_centersbar;
if (CSQC_DrawHud(pv))
return;
headsup = !(cl_sbar.value || (scr_viewsize.value<100));
if ((sb_updates >= vid.numpages) && !headsup)
return;

View File

@ -161,7 +161,7 @@ cvar_t snd_voip_micamp = CVARAFD("cl_voip_micamp", "2", NULL, CVAR_ARCHIVE, "A
cvar_t snd_voip_codec = CVARAFD("cl_voip_codec", "", NULL, CVAR_ARCHIVE, "0: speex(@11khz). 1: raw. 2: opus. 3: speex(@8khz). 4: speex(@16). 5:speex(@32). 6: pcma. 7: pcmu.");
cvar_t snd_voip_noisefilter = CVARAFD("cl_voip_noisefilter", "1", NULL, CVAR_ARCHIVE, "Enable the use of the noise cancelation filter.");
cvar_t snd_voip_autogain = CVARAFD("cl_voip_autogain", "0", NULL, CVAR_ARCHIVE, "Attempts to normalize your voice levels to a standard level. Useful for lazy people, but interferes with voice activation levels.");
cvar_t snd_voip_opus_bitrate = CVARAFD("cl_voip_opus_bitrate", "3000", NULL, CVAR_ARCHIVE, "For codecs with non-specific bitrates, this specifies the target bitrate to use.");
cvar_t snd_voip_bitrate = CVARAFD("cl_voip_bitrate", "3000", NULL, CVAR_ARCHIVE, "For codecs with non-specific bitrates, this specifies the target bitrate to use.");
#endif
extern vfsfile_t *rawwritefile;
@ -1418,7 +1418,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
start = (short*)(s_voip.capturebuf + encpos);
frames = (s_voip.capturepos-encpos)/2;
nrate = snd_voip_opus_bitrate.value;
nrate = snd_voip_bitrate.value;
if (nrate != s_voip.curbitrate)
{
s_voip.curbitrate = nrate;
@ -1640,7 +1640,7 @@ void S_Voip_Init(void)
Cvar_Register(&snd_voip_codec, "Voice Chat");
Cvar_Register(&snd_voip_noisefilter, "Voice Chat");
Cvar_Register(&snd_voip_autogain, "Voice Chat");
Cvar_Register(&snd_voip_opus_bitrate, "Voice Chat");
Cvar_Register(&snd_voip_bitrate, "Voice Chat");
Cmd_AddCommand("+voip", S_Voip_Enable_f);
Cmd_AddCommand("-voip", S_Voip_Disable_f);
Cmd_AddCommand("voip", S_Voip_f);

View File

@ -2020,7 +2020,7 @@ void R_DrawNameTags(void)
vec2_t scale = {8,8};
x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, scale);
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_console, scale);
}
}
@ -2054,7 +2054,7 @@ void R_DrawNameTags(void)
}
else
str = "hit nothing";
R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_default, scale);
R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_console, scale);
}
#endif

View File

@ -303,6 +303,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef RTLIGHTS
#define RTLIGHTS //realtime lighting
#endif
//#define SHADOWDBG_COLOURNOTDEPTH //for debugging. renders shadowmaps to a colour buffer instead of a depth buffer. resulting in projected textures instead of actual shadows (the glsl only picks up the red component, but whatever)
// #define QWOVERQ3 //allows qw servers with q3 clients. requires specific cgame.

View File

@ -374,6 +374,7 @@ static void Alias_TransformVerticies_V(const float *bonepose, int vertcount, qby
}
matrix = mat;
}
//NOTE: else we assume that weights[0] is 1.
xyzout[0] = (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + matrix[ 3]);
xyzout[1] = (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + matrix[ 7]);
@ -2971,7 +2972,7 @@ void Mod_LoadAliasShaders(model_t *mod)
R_BuildDefaultTexnums(&f->texnums, f->shader);
}
}
Mod_WipeSkin(skinid);
Mod_WipeSkin(skinid, false);
}
}
#endif
@ -6965,6 +6966,40 @@ const void *IQM_FindExtension(const char *buffer, const char *extname, int index
return NULL;
}
static void Mod_CleanWeights(const char *modelname, size_t numverts, vec4_t *oweight, byte_vec4_t *oindex)
{ //some IQMs lack weight values, apparently.
int j, v;
qboolean problemfound = false;
for (v = 0; v < numverts; v++)
{
float t = oweight[v][0]+oweight[v][1]+oweight[v][2]+oweight[v][3];
if (!t)
{
problemfound = true;
Vector4Set(oweight[v], 1, 0, 0, 0);
}
else if (t < 0.99 || t > 1.01)
Vector4Scale(oweight[v], 1/t, oweight[v]);
//compact any omitted weights...
for(j = 3; j > 0; )
{
if (oweight[v][j] && !oweight[v][j-1])
{
problemfound = true;
oweight[v][j-1] = oweight[v][j];
oindex[v][j-1] = oindex[v][j];
oweight[v][j] = 0;
j++; //bubble back up
}
else
j--;
}
}
if (problemfound)
Con_Printf(CON_ERROR"%s has invalid vertex weights. Verticies will probably be attached to the wrong bones\n", modelname);
}
galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsize)
{
const struct iqmheader *h = (struct iqmheader *)buffer;
@ -7463,6 +7498,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsi
if (!IQM_ImportArray4B(buffer, &vbone, oindex, h->num_vertexes, h->num_joints))
Con_Printf(CON_WARNING "Invalid bone indexes detected inside %s\n", mod->name);
IQM_ImportArrayF(buffer, &vweight, (float*)oweight, 4, h->num_vertexes, defaultweight);
Mod_CleanWeights(mod->name, h->num_vertexes, oweight, oindex);
}
if (otcoords)

View File

@ -141,6 +141,8 @@ char *Cvar_FlagToName(int flag)
return "semicheat";
case CVAR_RENDERERLATCH:
return "renderlatch";
case CVAR_VIDEOLATCH:
return "videolatch";
case CVAR_SERVEROVERRIDE:
return "serverlatch";
case CVAR_RENDERERCALLBACK:
@ -725,8 +727,10 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
latch = "variable %s is latched and will be applied for the start of the next map\n";
// else if (var->flags & CVAR_LATCHFLUSH)
// latch = "variable %s is latched (type flush)\n";
else if (var->flags & CVAR_RENDERERLATCH && qrenderer != QR_NONE)
else if (var->flags & CVAR_VIDEOLATCH && qrenderer != QR_NONE)
latch = "variable %s will be changed after a vid_restart\n";
else if (var->flags & CVAR_RENDERERLATCH && qrenderer != QR_NONE)
latch = "variable %s will be changed after a vid_reload\n";
else if (var->flags & CVAR_RULESETLATCH)
latch = "variable %s is latched due to current ruleset\n";
#ifndef SERVERONLY
@ -739,7 +743,8 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
if (latch && !force)
{
if (cl_warncmd.value)
{
{ //FIXME: flag that there's a latched cvar instead of spamming prints.
//FIXME: apply pending rendererlatches vith a vid_reload when leaving the console/menu.
if (var->latched_string)
{ //already latched
if (strcmp(var->latched_string, value))
@ -1284,11 +1289,16 @@ qboolean Cvar_Command (int level)
Con_Printf ("\"%s\" is currently \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
Con_Printf ("Will be changed to \"%s\" on the next map\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
}
else if (v->flags & CVAR_RENDERERLATCH)
else if (v->flags & CVAR_VIDEOLATCH)
{
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
Con_Printf ("Will be changed to \"%s\" on vid_restart\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
}
else if (v->flags & CVAR_RENDERERLATCH)
{
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
Con_Printf ("Will be changed to \"%s\" on vid_reload\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
}
else
{
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));

View File

@ -128,7 +128,7 @@ typedef struct cvar_group_s
#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.
#define CVAR_SEMICHEAT (1<<10) //if strict ruleset, force to blank (aka 0).
#define CVAR_RENDERERLATCH (1<<11) //requires a vid_restart to reapply.
#define CVAR_RENDERERLATCH (1<<11) //requires a vid_reload to reapply.
#define CVAR_SERVEROVERRIDE (1<<12) //the server has overridden out local value - should probably be called SERVERLATCH
#define CVAR_RENDERERCALLBACK (1<<13) //force callback for cvars on renderer change
#define CVAR_NOUNSAFEEXPAND (1<<14) //cvar cannot be read by gamecode. do not expand cvar value when command is from gamecode.
@ -142,6 +142,7 @@ typedef struct cvar_group_s
#define CVAR_TEAMPLAYTAINT (1<<21) //current value contains the evaluation of a teamplay macro.
#define CVAR_WATCHED (1<<22) //report any attempts to change this cvar.
#define CVAR_VIDEOLATCH (1<<23)
#define CVAR_LASTFLAG CVAR_SHADERSYSTEM

View File

@ -5813,32 +5813,50 @@ void FS_ChangeGame_f(void)
//don't execute this if we're executing rcon commands, as this can change game directories.
if (cmd_blockwait)
return;
if (Cmd_IsInsecure())
return;
if (!*arg)
{
Con_Printf("Valid games are:\n");
for (i = 0; gamemode_info[i].argname; i++)
{
Con_Printf(" %s\n", gamemode_info[i].argname+1);
char nbase[MAX_OSPATH];
char *note = "not installed";
if (FS_DirHasGame(com_gamepath, i))
note = com_gamepath;
else if (Sys_FindGameData(gamemode_info[i].poshname, gamemode_info[i].argname+1, nbase, sizeof(nbase), false) && FS_FixPath(nbase, sizeof(nbase)) && FS_DirHasGame(nbase, i))
note = nbase;
Con_Printf(" %s (%s)\n", gamemode_info[i].argname+1, note);
}
//FIXME: scan for fmf files.
}
else
{
for (i = 0; gamemode_info[i].argname; i++)
{
if (!Q_strcasecmp(gamemode_info[i].argname+1, arg))
{
Con_Printf("Switching to %s\n", gamemode_info[i].argname+1);
PM_Shutdown();
FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, i), true, true);
return;
}
if (strrchr(arg, '/') && !strrchr(arg, '/')[1])
{
Q_strncpyz(com_gamepath, arg, sizeof(com_gamepath));
host_parms.basedir = com_gamepath;
FS_ChangeGame(FS_ReadDefaultManifest(NULL, 0, true), true, true);
}
else
{
for (i = 0; gamemode_info[i].argname; i++)
{
if (!Q_strcasecmp(gamemode_info[i].argname+1, arg))
{
Con_Printf("Switching to %s\n", gamemode_info[i].argname+1);
PM_Shutdown();
FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, i), true, true);
return;
}
}
#ifndef SERVERONLY
if (!Host_RunFile(arg, strlen(arg), NULL))
Con_Printf("Game unknown\n");
if (!Host_RunFile(arg, strlen(arg), NULL))
Con_Printf("Game unknown\n");
#endif
}
}
}
@ -6091,6 +6109,8 @@ void COM_InitFilesystem (void)
if (!*com_homepath)
com_homepathusable = false;
com_homepathenabled = com_homepathusable;
fs_readonly = COM_CheckParm("-readonly");
fs_thread_mutex = Sys_CreateMutex();

View File

@ -37,6 +37,7 @@
//#define Q3SURF_DUST 0x00040000
cvar_t q3bsp_surf_meshcollision_flag = CVARD("q3bsp_surf_meshcollision_flag", "0x80000000", "The surfaceparm flag(s) that enables q3bsp trisoup collision");
cvar_t q3bsp_surf_meshcollision_force = CVARD("q3bsp_surf_meshcollision_force", "0", "Force mesh-based collisions on all q3bsp trisoup surfaces.");
cvar_t q3bsp_mergeq3lightmaps = CVARD("q3bsp_mergedlightmaps", "16", "Specifies the maximum number of lightmaps that may be merged for performance reasons. Unfortunately this breaks tcgen on lightmap passes - if you care, set this to 1.");
#if Q3SURF_NODRAW != TI_NODRAW
#error "nodraw isn't constant"
@ -3511,7 +3512,7 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
maps /= 2;
{
int limit = min(sh_config.texture2d_maxsize / loadmodel->lightmaps.height, 16);//mod_mergeq3lightmaps.ival);
int limit = min(sh_config.texture2d_maxsize / loadmodel->lightmaps.height, q3bsp_mergeq3lightmaps.ival);
loadmodel->lightmaps.merge = 1;
while (loadmodel->lightmaps.merge*2 <= limit && loadmodel->lightmaps.merge < maps)
loadmodel->lightmaps.merge *= 2;
@ -3553,8 +3554,27 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
//and the submap
out += (m%loadmodel->lightmaps.merge)*mapsize;
#if 1
for(s = 0; s < mapsize; )
{
float i;
vec3_t l;
l[0] = *in++;
l[1] = *in++;
l[2] = *in++;
i = VectorNormalize(l);
i *= (1<<(2-gl_overbright.ival));
if (i > 255)
i = 255; //don't oversaturate (clamping results in discolouration, which looks weird)
VectorScale(l, i, l);
out[s++] = l[0];
out[s++] = l[1];
out[s++] = l[2];
}
#else
for(s = 0; s < mapsize; s++)
out[s] = lmgamma[*in++];
#endif
if (r_lightmap_saturation.value != 1.0f)
SaturateR8G8B8(out, mapsize, r_lightmap_saturation.value);
@ -6688,6 +6708,7 @@ void CM_Init(void) //register cvars.
Cvar_Register(&map_autoopenportals, MAPOPTIONS);
Cvar_Register(&q3bsp_surf_meshcollision_flag, MAPOPTIONS);
Cvar_Register(&q3bsp_surf_meshcollision_force, MAPOPTIONS);
Cvar_Register(&q3bsp_mergeq3lightmaps, MAPOPTIONS);
Cvar_Register(&r_subdivisions, MAPOPTIONS);
CM_InitBoxHull ();

View File

@ -567,7 +567,7 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
qgnutls_x509_crt_import(cert, certlist, GNUTLS_X509_FMT_DER);
if (qgnutls_x509_crt_check_hostname(cert, file->certname))
{
if (preverified && certstatus == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND))
if (preverified && (certstatus&~GNUTLS_CERT_EXPIRED) == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND))
return 0;
if (certstatus == 0)
return SSL_CheckUserTrust(session, file, 0);

View File

@ -375,7 +375,20 @@ int PM_StepSlideMove (qboolean in_air)
blocked = PM_SlideMove ();
if (!blocked)
{
if (!in_air && movevars.stepdown)
{ //if we were onground, try stepping down after the move to try to stay on said ground.
VectorMA (pmove.origin, movevars.stepheight, pmove.gravitydir, dest);
trace = PM_PlayerTracePortals (pmove.origin, dest, MASK_PLAYERSOLID, NULL);
if (trace.fraction != 1 && -DotProduct(pmove.gravitydir, trace.plane.normal) > MIN_STEP_NORMAL)
{
if (!trace.startsolid && !trace.allsolid)
VectorCopy (trace.endpos, pmove.origin);
}
}
return blocked; // moved the entire distance
}
if (in_air)
{

View File

@ -116,6 +116,7 @@ typedef struct {
int walljump;
qboolean slidefix;
qboolean airstep;
qboolean stepdown;
qboolean slidyslopes;
int stepheight;

View File

@ -6473,6 +6473,8 @@ lh_extension_t QSG_Extensions[] = {
//only in dp6 currently {"DP_ENT_GLOW"},
{"DP_ENT_VIEWMODEL"},
{"DP_GECKO_SUPPORT", 7, NULL, {"gecko_create", "gecko_destroy", "gecko_navigate", "gecko_keyevent", "gecko_mousemove", "gecko_resize", "gecko_get_texture_extent"}},
{"DP_GFX_FONTS", 2, NULL, {"findfont", "loadfont"}}, //note: font slot numbers/names are not special in fte.
// {"DP_GFX_FONTS_FREETYPE"}, //extra cvars are not supported.
// {"DP_GFX_QUAKE3MODELTAGS"},
{"DP_GFX_SKINFILES"},
{"DP_GFX_SKYBOX"}, //according to the spec. :)
@ -6505,7 +6507,6 @@ lh_extension_t QSG_Extensions[] = {
{"DP_QC_GETSURFACEPOINTATTRIBUTE", 1, NULL, {"getsurfacepointattribute"}},
{"DP_QC_MINMAXBOUND", 3, NULL, {"min", "max", "bound"}},
{"DP_QC_MULTIPLETEMPSTRINGS", 0, NULL, {NULL}, "Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine)."},
{"DP_SV_PRINT", 1, NULL, {"print"}, "Says that the print builtin can be used from nqssqc (as well as just csqc), bypassing the developer cvar issues."},
{"DP_QC_RANDOMVEC", 1, NULL, {"randomvec"}},
{"DP_QC_RENDER_SCENE", 0, NULL, {NULL}, "clearscene+addentity+setviewprop+renderscene+setmodel are available to menuqc. WARNING: DP advertises this extension without actually supporting it, FTE does actually support it."},
{"DP_QC_SINCOSSQRTPOW", 4, NULL, {"sin", "cos", "sqrt", "pow"}},
@ -6551,6 +6552,7 @@ lh_extension_t QSG_Extensions[] = {
// {"DP_SV_POINTPARTICLES", 3, NULL, {"particleeffectnum", "pointparticles", "trailparticles"}, "Specifies that pointparticles (and trailparticles) exists in ssqc as well as csqc (and that dp's trailparticles argument fuckup will normally work). ssqc values can be passed to csqc for use, the reverse is not true. Does NOT mean that DP's effectinfo.txt is supported, only that ssqc has functionality equivelent to csqc."},
{"DP_SV_POINTSOUND", 1, NULL, {"pointsound"}},
{"DP_SV_PRECACHEANYTIME", 0, NULL, {NULL}, "Specifies that the various precache builtins can be called at any time. WARNING: precaches are sent reliably while sound events, modelindexes, and particle events are not. This can mean sounds and particles might not work the first time around, or models may take a while to appear (after the reliables are received and the model is loaded from disk). Always attempt to precache a little in advance in order to reduce these issues (preferably at the start of the map...)"},
{"DP_SV_PRINT", 1, NULL, {"print"}, "Says that the print builtin can be used from nqssqc (as well as just csqc), bypassing the developer cvar issues."},
{"DP_SV_SETCOLOR"},
{"DP_SV_SPAWNFUNC_PREFIX"},
{"DP_SV_WRITEPICTURE", 1, NULL, {"WritePicture"}},
@ -6599,7 +6601,7 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_GFX_QUAKE3SHADERS", 0, NULL, {NULL}, "specifies that the engine has full support for vanilla quake3 shaders"},
{"FTE_GFX_REMAPSHADER", 0, NULL, {NULL}, "With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface."},
// {"FTE_GFX_IQM_HITMESH", 0, NULL, {NULL}, "Supports hitmesh iqm extensions. Also supports geomsets and embedded events."},
// {"FTE_GFX_MODELEVENTS", 1, NULL, {"processmodelevents", "getnextmodelevent", "getmodeleventidx"}, "Provides a query for per-animation events in model files, including from progs/foo.mdl.events files."},
{"FTE_GFX_MODELEVENTS", 1, NULL, {"processmodelevents", "getnextmodelevent", "getmodeleventidx"}, "Provides a query for per-animation events in model files, including from progs/foo.mdl.events files."},
{"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}, "Allows you to check if a client has too many reliable messages pending."},
{"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memfill8"}, "Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games."},
#ifdef HAVE_MEDIA_DECODER
@ -6635,6 +6637,7 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_QC_CHECKCOMMAND", 1, NULL, {"checkcommand"}, "Provides a way to test if a console command exists, and whether its a command/alias/cvar. Does not say anything about the expected meanings of any arguments or values."},
{"FTE_QC_CHECKPVS", 1, NULL, {"checkpvs"}},
{"FTE_QC_CROSSPRODUCT", 1, NULL, {"crossproduct"}},
{"FTE_QC_CUSTOMSKINS", 1, NULL, {"setcustomskin", "loadcustomskin", "applycustomskin", "releasecustomskin"}, "The engine supports the use of q3 skins, as well as the use of such skin 'files' to specify rich top+bottom colours, qw skins, geomsets, or texture composition even on non-players.."},
{"FTE_QC_FS_SEARCH_SIZEMTIME", 2, NULL, {"search_getfilesize", "search_getfilemtime"}},
{"FTE_QC_HARDWARECURSORS", 0, NULL, {NULL}, "setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed."},
{"FTE_QC_HASHTABLES", 6, NULL, {"hash_createtab", "hash_destroytab", "hash_add", "hash_get", "hash_delete", "hash_getkey"}, "Provides efficient string-based lookups."},
@ -6666,6 +6669,7 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_QUAKE3_SERVER", 0, NULL, {NULL}, "This engine is able to act as a quake3 server"},
#endif
{"FTE_SOLID_LADDER", NOBI "Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS"},
{"FTE_SPLITSCREEN", NOBI "Client supports splitscreen, controlled via cl_splitclients. Servers require allow_splitscreen 1 if splitscreen is to be used over the internet. Mods that use csqc will need to be aware for this to work properly. per-client networking may be problematic."},
#ifdef SQL
// serverside SQL functions for managing an SQL database connection

View File

@ -366,6 +366,18 @@ int VMQ3_Cvar_Register(q3vmcvar_t *v, char *name, char *defval, int flags)
c = Cvar_Get(name, defval, fteflags, "Q3VM cvars");
if (!c) //command name, etc
return 0;
if ((flags & CVAR_USERINFO) && !(c->flags & CVAR_USERINFO))
{
c->flags |= CVAR_USERINFO;
Info_SetValueForKey(cls.userinfo[0], c->name, c->string, sizeof(cls.userinfo[0]));
cls.resendinfo = true;
}
if ((flags & CVAR_SERVERINFO) && !(c->flags & CVAR_SERVERINFO))
{
c->flags |= CVAR_SERVERINFO;
Info_SetValueForKey (svs.info, c->name, c->string, MAX_SERVERINFO_STRING);
SV_SendServerInfoChange(c->name, c->string);
}
for (i = 0; i < MAX_VMQ3_CVARS; i++)
{
if (!q3cvlist[i])

View File

@ -1767,9 +1767,9 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (k = 0; k < 4; k++)
{
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
dst[k][0] = mid[0] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[8+1]);
}
}
break;
@ -1785,15 +1785,15 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
float len[3];
mat3_t m0, m1, m2, result;
float *quad[4];
vec3_t rot_centre, tv;
vec3_t rot_centre, tv, tv2;
quad[0] = (float *)(dst + mesh->indexes[k+0]);
quad[1] = (float *)(dst + mesh->indexes[k+1]);
quad[2] = (float *)(dst + mesh->indexes[k+2]);
quad[0] = (float *)(src + mesh->indexes[k+0]);
quad[1] = (float *)(src + mesh->indexes[k+1]);
quad[2] = (float *)(src + mesh->indexes[k+2]);
for (j = 2; j >= 0; j--)
{
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
quad[3] = (float *)(src + mesh->indexes[k+3+j]);
if (!VectorEquals (quad[3], quad[0]) &&
!VectorEquals (quad[3], quad[1]) &&
!VectorEquals (quad[3], quad[2]))
@ -1898,9 +1898,10 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (j = 0; j < 4; j++)
{
int v = ((vecV_t*)quad[j]-src);
VectorSubtract(quad[j], rot_centre, tv);
Matrix3_Multiply_Vec3((void *)result, tv, quad[j]);
VectorAdd(rot_centre, quad[j], quad[j]);
Matrix3_Multiply_Vec3((void *)result, tv, tv2);
VectorAdd(rot_centre, tv2, dst[v]);
}
}
break;
@ -2477,7 +2478,7 @@ qboolean D3D11BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsig
}
#ifdef RTLIGHTS
void D3D11BE_SetupForShadowMap(dlight_t *dl, qboolean isspot, int texwidth, int texheight, float shadowscale)
void D3D11BE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale)
{
#define SHADOWMAP_SIZE 512
extern cvar_t r_shadow_shadowmapping_nearclip, r_shadow_shadowmapping_bias;

View File

@ -1324,9 +1324,9 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (k = 0; k < 4; k++)
{
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
dst[k][0] = mid[0] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[8+1]);
}
}
break;
@ -1342,15 +1342,15 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
float len[3];
mat3_t m0, m1, m2, result;
float *quad[4];
vec3_t rot_centre, tv;
vec3_t rot_centre, tv, tv2;
quad[0] = (float *)(dst + mesh->indexes[k+0]);
quad[1] = (float *)(dst + mesh->indexes[k+1]);
quad[2] = (float *)(dst + mesh->indexes[k+2]);
quad[0] = (float *)(src + mesh->indexes[k+0]);
quad[1] = (float *)(src + mesh->indexes[k+1]);
quad[2] = (float *)(src + mesh->indexes[k+2]);
for (j = 2; j >= 0; j--)
{
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
quad[3] = (float *)(src + mesh->indexes[k+3+j]);
if (!VectorEquals (quad[3], quad[0]) &&
!VectorEquals (quad[3], quad[1]) &&
!VectorEquals (quad[3], quad[2]))
@ -1455,9 +1455,10 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (j = 0; j < 4; j++)
{
int v = ((vecV_t*)quad[j]-src);
VectorSubtract(quad[j], rot_centre, tv);
Matrix3_Multiply_Vec3((void *)result, tv, quad[j]);
VectorAdd(rot_centre, quad[j], quad[j]);
Matrix3_Multiply_Vec3((void *)result, tv, tv2);
VectorAdd(rot_centre, tv2, dst[v]);
}
}
break;

View File

@ -219,6 +219,11 @@ typedef struct
int mipfilter[3];
int picfilter[3];
D3DSAMPLERSTATETYPE anisfilter;
texid_t fogtexture;
float fogdensity;
float fogdepth;
float fogfar;
} d3dbackend_t;
typedef struct
@ -672,7 +677,7 @@ static const char LIGHTPASS_SHADER[] = "\
void D3D9BE_Init(void)
{
be_maxpasses = MAX_TMUS;
be_maxpasses = MAX_TC_TMUS;
memset(&shaderstate, 0, sizeof(shaderstate));
shaderstate.curvertdecl = -1;
shaderstate.curentity = &r_worldentity;
@ -1490,9 +1495,102 @@ static void GenerateTCMods3(const shaderpass_t *pass, float *dest)
}
}
static void tcgen_fog(float *st, unsigned int numverts, float *xyz, mfog_t *fog)
{
int i;
float z;
float eye, point;
vec4_t zmat;
vec4_t distmat;
//FIXME
float modelviewmatrix[16];
Matrix4_Multiply(r_refdef.m_view, shaderstate.m_model, modelviewmatrix);
//generate a simple matrix to calc only the projected z coord
zmat[0] = -modelviewmatrix[2];
zmat[1] = -modelviewmatrix[6];
zmat[2] = -modelviewmatrix[10];
zmat[3] = -modelviewmatrix[14];
VectorCopy(fog->visibleplane->normal, distmat);
distmat[3] = fog->visibleplane->dist;
Vector4Scale(zmat, shaderstate.fogfar, zmat);
if (fog && fog->visibleplane)
{
eye = (DotProduct(r_refdef.vieworg, distmat) - distmat[3]);
if (eye < 1)
eye = 1;
for (i = 0 ; i < numverts ; i++, xyz += sizeof(vecV_t)/sizeof(vec_t), st += 2 )
{
z = DotProduct(xyz, zmat) + zmat[3];
st[0] = z;
if (fog->visibleplane)
point = (DotProduct(xyz, distmat) - distmat[3]);
else
point = 1;
st[1] = point / (point - eye);
}
}
else
{
for (i = 0 ; i < numverts ; i++, xyz += sizeof(vecV_t)/sizeof(vec_t), st += 2 )
{
z = DotProduct(xyz, zmat) + zmat[3];
st[0] = z;
st[1] = 1.0;//31/32.0;
}
}
}
//end texture coords
/*******************************************************************************************************************/
static void GenerateFogTexture(texid_t *tex, float density, float zscale)
{
#define FOGS 256
#define FOGT 32
byte_vec4_t fogdata[FOGS*FOGT];
int s, t;
float f, z;
for(s = 0; s < FOGS; s++)
for(t = 0; t < FOGT; t++)
{
z = (float)s / (FOGS-1);
z *= zscale;
if (0)//q3
f = pow(z, 0.5);
else if (1)//GL_EXP
f = 1-exp(-density * z);
else //GL_EXP2
f = 1-exp(-(density*density) * z);
if (f < 0)
f = 0;
if (f > 1)
f = 1;
f *= (float)t / (FOGT-1);
fogdata[t*FOGS + s][0] = 255;
fogdata[t*FOGS + s][1] = 255;
fogdata[t*FOGS + s][2] = 255;
fogdata[t*FOGS + s][3] = 255*f;
}
if (!TEXVALID(*tex))
*tex = Image_CreateTexture("***fog***", NULL, IF_CLAMP|IF_NOMIPMAP);
Image_Upload(*tex, TF_RGBA32, fogdata, NULL, FOGS, FOGT, IF_CLAMP|IF_NOMIPMAP);
}
static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *dst, const mesh_t *mesh)
{
float *table;
@ -1588,9 +1686,9 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (k = 0; k < 4; k++)
{
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
dst[k][0] = mid[0] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[8+1]);
}
}
break;
@ -1606,15 +1704,15 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
float len[3];
mat3_t m0, m1, m2, result;
float *quad[4];
vec3_t rot_centre, tv;
vec3_t rot_centre, tv, tv2;
quad[0] = (float *)(dst + mesh->indexes[k+0]);
quad[1] = (float *)(dst + mesh->indexes[k+1]);
quad[2] = (float *)(dst + mesh->indexes[k+2]);
quad[0] = (float *)(src + mesh->indexes[k+0]);
quad[1] = (float *)(src + mesh->indexes[k+1]);
quad[2] = (float *)(src + mesh->indexes[k+2]);
for (j = 2; j >= 0; j--)
{
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
quad[3] = (float *)(src + mesh->indexes[k+3+j]);
if (!VectorEquals (quad[3], quad[0]) &&
!VectorEquals (quad[3], quad[1]) &&
!VectorEquals (quad[3], quad[2]))
@ -1712,9 +1810,10 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (j = 0; j < 4; j++)
{
int v = ((vecV_t*)quad[j]-src);
VectorSubtract(quad[j], rot_centre, tv);
Matrix3_Multiply_Vec3((void *)result, tv, quad[j]);
VectorAdd(rot_centre, quad[j], quad[j]);
Matrix3_Multiply_Vec3((void *)result, tv, tv2);
VectorAdd(rot_centre, tv2, dst[v]);
}
}
break;
@ -2340,7 +2439,7 @@ static void BE_DrawMeshChain_Internal(void)
//if anything is dynamic ALL must be dynamic
//might want to flag this for multi-mesh batches on pre-t&l cards too, so that there's no gaps.
if ((useshader->flags & SHADER_NEEDSARRAYS) && shaderstate.nummeshes > 0)
if ((useshader->flags & SHADER_NEEDSARRAYS || (shaderstate.curbatch && shaderstate.curbatch->fog)) && shaderstate.nummeshes > 0)
shaderstate.batchvbo = NULL;
if (shaderstate.batchvbo)
@ -2518,7 +2617,7 @@ static void BE_DrawMeshChain_Internal(void)
else
{
/*now go through and flush each pass*/
for (passno = 0, pass = useshader->passes; passno < shaderstate.curshader->numpasses; passno += pass->numMergedPasses)
for (passno = 0, pass = useshader->passes; passno < useshader->numpasses; passno += pass->numMergedPasses)
{
if (!BE_DrawMeshChain_SetupPass(pass+passno, vertcount))
continue;
@ -2531,6 +2630,59 @@ static void BE_DrawMeshChain_Internal(void)
// d3dcheck(IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, 0, 0, vertcount, idxfirst, idxcount/3));
}
}
if (shaderstate.curbatch && shaderstate.curbatch->fog && shaderstate.curbatch->fog->shader)
{
if (!TEXVALID(shaderstate.fogtexture) || shaderstate.fogdensity != shaderstate.curbatch->fog->shader->fog_dist || shaderstate.fogdepth != 2048)
{
shaderstate.fogdensity = shaderstate.curbatch->fog->shader->fog_dist;
shaderstate.fogdepth = 2048;
shaderstate.fogfar = 1.0f/shaderstate.fogdepth; /*scaler for z coords*/
GenerateFogTexture(&shaderstate.fogtexture, shaderstate.fogdensity, shaderstate.fogdepth);
}
while(shaderstate.lastpasscount>1)
{
passno = --shaderstate.lastpasscount;
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+passno, NULL, 0, 0));
BindTexture(passno, NULL);
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_COLOROP, D3DTOP_DISABLE));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAOP, D3DTOP_DISABLE));
}
shaderstate.lastpasscount = 1;
passno = 0;
BindTexture(passno, shaderstate.fogtexture);
BE_ApplyTMUState(passno, shaderstate.curtexflags[passno]);
Vector4Set((qbyte*)&shaderstate.passcolour, shaderstate.curbatch->fog->shader->fog_color[2], shaderstate.curbatch->fog->shader->fog_color[1], shaderstate.curbatch->fog->shader->fog_color[0], shaderstate.curbatch->fog->shader->fog_color[3]);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_CONSTANT, shaderstate.passcolour);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_COLORVERTEX, FALSE);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_COLORARG1, D3DTA_CONSTANT);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_COLORARG2, D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_COLOROP, D3DTOP_MODULATE);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAARG1, D3DTA_CONSTANT);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
BE_ApplyShaderBits(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (useshader->numpasses?SBITS_MISC_DEPTHEQUALONLY:0));
allocvertexbuffer(shaderstate.dynst_buff[passno], shaderstate.dynst_size, &shaderstate.dynst_offs[passno], &map, vertcount*sizeof(vec2_t));
for (mno = 0, vertcount = 0; mno < shaderstate.nummeshes; mno++)
{
m = shaderstate.meshlist[mno];
tcgen_fog((float*)map+vertcount*2, m->numvertexes, (float*)m->xyz_array, shaderstate.curbatch->fog);
vertcount += m->numvertexes;
}
IDirect3DVertexBuffer9_Unlock(shaderstate.dynst_buff[passno]);
IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+passno, shaderstate.dynst_buff[passno], shaderstate.dynst_offs[passno] - vertcount*sizeof(vec2_t), sizeof(vec2_t));
if (D3D_VDEC_ST0 != shaderstate.curvertdecl)
{
shaderstate.curvertdecl = D3D_VDEC_ST0;
d3dcheck(IDirect3DDevice9_SetVertexDeclaration(pD3DDev9, vertexdecls[shaderstate.curvertdecl]));
}
BE_SubmitMeshChain(vertbase, vertfirst, vertcount, idxfirst, idxcount);
}
break;
}
}
@ -3233,6 +3385,7 @@ void D3D9BE_DrawMesh_Single(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, uns
shaderstate.batchvbo = vbo;
shaderstate.curtime = realtime;
shaderstate.curshader = shader;
shaderstate.curbatch = NULL;
if (shader->numdefaulttextures)
shaderstate.curtexnums = shader->defaulttextures + ((int)(shader->defaulttextures_fps * shaderstate.curtime) % shader->numdefaulttextures);
else

View File

@ -70,7 +70,7 @@ void Mod_FlushSkin(skinid_t id)
return;
sk->qwskin = NULL;
}
void Mod_WipeSkin(skinid_t id)
void Mod_WipeSkin(skinid_t id, qboolean force)
{
//FIXME: skin objects should persist for a frame.
skinfile_t *sk;
@ -81,6 +81,8 @@ void Mod_WipeSkin(skinid_t id)
sk = registeredskins[id];
if (!sk)
return;
if (!force && --sk->refcount > 0)
return; //still in use.
for (i = 0; i < sk->nummappings; i++)
{
@ -100,7 +102,7 @@ static void Mod_WipeAllSkins(qboolean final)
if (final)
{
for (id = 0; id < numregisteredskins; )
Mod_WipeSkin(++id);
Mod_WipeSkin(++id, true);
Z_Free(registeredskins);
registeredskins = NULL;
numregisteredskins = 0;
@ -263,6 +265,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
}
skin = Z_Malloc(sizeof(*skin) - sizeof(skin->mappings) + sizeof(skin->mappings[0])*4);
skin->refcount++;
skin->maxmappings = 4;
Q_strncpyz(skin->skinname, skinname, sizeof(skin->skinname));
skin->q1lower = Q1UNSPECIFIED;
@ -418,7 +421,10 @@ skinid_t Mod_RegisterSkinFile(const char *skinname)
if (!registeredskins[id])
continue;
if (!strcmp(skinname, registeredskins[id]->skinname))
{
registeredskins[id]->refcount++;
return id+1;
}
}
f = FS_LoadMallocFile(skinname, NULL);
if (!f)

View File

@ -32,6 +32,12 @@ extern texid_t missing_texture_normal;
extern texid_t scenepp_postproc_cube;
extern texid_t r_whiteimage;
#ifdef GLQUAKE
static texid_t shadowmap[2];
static int shadow_fbo_id;
static int shadow_fbo_depth_num;
#endif
#ifndef GLSLONLY
static void GenerateTCMods(const shaderpass_t *pass, int passnum);
#endif
@ -1048,27 +1054,67 @@ void PPL_RevertToKnownState(void)
}
#ifdef RTLIGHTS
//called from gl_shadow
int GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale)
void GLBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale)
{
extern cvar_t r_shadow_shadowmapping_bias;
extern cvar_t r_shadow_shadowmapping_nearclip;
float n = r_shadow_shadowmapping_nearclip.value;
float f = shaderstate.lightradius;
float f = dl->radius;
float b = r_shadow_shadowmapping_bias.value;
//FIXME: this is used for rendering, not for shadow generation!
#define SHADOWMAP_SIZE 512
//projection frustum, slots 10+11. scaled by 0.5
//lightshadowmapproj is a projection matrix packed into a vec4, with various texture scaling stuff built in.
shaderstate.lightshadowmapproj[0] = shadowscale * (1.0-(1.0/texwidth)) * 0.5/3.0;
shaderstate.lightshadowmapproj[1] = shadowscale * (1.0-(1.0/texheight)) * 0.5/2.0;
shaderstate.lightshadowmapproj[2] = 0.5*(f+n)/(n-f);
shaderstate.lightshadowmapproj[3] = (f*n)/(n-f) - b*n*(1024/texheight);
shaderstate.lightshadowmapscale[0] = 1.0/(SHADOWMAP_SIZE*3);
shaderstate.lightshadowmapscale[1] = 1.0/(SHADOWMAP_SIZE*2);
shaderstate.lightshadowmapscale[0] = 1.0/texwidth;
shaderstate.lightshadowmapscale[1] = 1.0/texheight;
}
int GLBE_BeginRenderBuffer_DepthOnly(texid_t depthtexture);
qboolean GLBE_BeginShadowMap(int id, int w, int h, int *restorefbo)
{
if (!gl_config.ext_framebuffer_objects)
return false;
if (!TEXVALID(shadowmap[id]))
{
shadowmap[id] = Image_CreateTexture(va("***shadowmap2d%i***", id), NULL, 0);
qglGenTextures(1, &shadowmap[id]->num);
GL_MTBind(0, GL_TEXTURE_2D, shadowmap[id]);
#ifdef SHADOWDBG_COLOURNOTDEPTH
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
#else
if (gl_config.gles)
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
#endif
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#if 0//def SHADOWDBG_COLOURNOTDEPTH
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
#else
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
//in case we're using shadow samplers
if (gl_config.arb_shadow)
{
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
}
}
shaderstate.curshadowmap = shadowmap[id];
/*set framebuffer*/
*restorefbo = GLBE_BeginRenderBuffer_DepthOnly(shaderstate.curshadowmap);
shaderstate.depthrange = 0; //make sure the projection matrix is updated.
shaderstate.curshadowmap = shadowmaptex;
while(shaderstate.lastpasstmus>0)
{
GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex);
@ -1076,14 +1122,24 @@ int GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, fl
shaderstate.shaderbits &= ~SBITS_MISC_DEPTHWRITE;
// if (qglShadeModel)
// qglShadeModel(GL_FLAT);
GL_ForceDepthWritable();
// qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
BE_SelectMode(BEM_DEPTHONLY);
return shaderstate.fbo_current;
BE_Scissor(NULL);
qglViewport(0, 0, w, h);
GL_ForceDepthWritable();
qglClear (GL_DEPTH_BUFFER_BIT);
#ifdef SHADOWDBG_COLOURNOTDEPTH
qglColorMask(TRUE,TRUE,TRUE,TRUE);
qglClearColor(1,1,1,1);
qglClear (GL_COLOR_BUFFER_BIT);
#endif
return true;
}
void GLBE_EndShadowMap(int restorefbo)
{
GLBE_FBO_Pop(restorefbo);
shaderstate.depthrange = 0; //make sure the projection matrix is updated.
}
#endif
@ -1421,6 +1477,21 @@ void GLBE_DestroyFBOs(void)
shaderstate.temptexture = r_nulltex;
}
//shadowmapping stuff
if (shadow_fbo_id)
{
qglDeleteFramebuffersEXT(1, &shadow_fbo_id);
shadow_fbo_id = 0;
shadow_fbo_depth_num = 0;
}
for (i = 0; i < 2; i++)
{
if (shadowmap[i])
{
Image_DestroyTexture(shadowmap[i]);
shadowmap[i] = r_nulltex;
}
}
//nuke deferred rendering stuff
for (i = 0; i < countof(shaderstate.tex_gbuf); i++)
@ -1495,20 +1566,20 @@ void GLBE_Init(void)
#ifdef RTLIGHTS
Sh_CheckSettings();
if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival)
{
if (r_shadow_shadowmapping.ival)
{
GLBE_RegisterLightShader(LSHADER_SMAP);
GLBE_RegisterLightShader(LSHADER_SMAP|LSHADER_CUBE);
GLBE_RegisterLightShader(LSHADER_SMAP|LSHADER_SPOT);
}
else
{
GLBE_RegisterLightShader(LSHADER_STANDARD);
GLBE_RegisterLightShader(LSHADER_STANDARD|LSHADER_CUBE);
GLBE_RegisterLightShader(LSHADER_STANDARD|LSHADER_SPOT);
}
if ((r_shadow_realtime_dlight.ival && r_shadow_shadowmapping.ival) ||
(r_shadow_realtime_world.ival && r_shadow_shadowmapping.ival) )
{ //we expect some lights that will need shadowmapped shadows.
GLBE_RegisterLightShader(LSHADER_SMAP);
GLBE_RegisterLightShader(LSHADER_SMAP|LSHADER_CUBE);
GLBE_RegisterLightShader(LSHADER_SMAP|LSHADER_SPOT);
}
if ((r_shadow_realtime_dlight.ival && (!r_shadow_shadowmapping.ival || !r_shadow_realtime_dlight_shadows.ival)) ||
(r_shadow_realtime_world.ival && (!r_shadow_shadowmapping.ival || !r_shadow_realtime_world_shadows.ival )) )
{ //these are also used when there's no shadow.
//FIXME: should also happen if there's static world lights without shadows. Move elsewhere?
GLBE_RegisterLightShader(LSHADER_STANDARD);
GLBE_RegisterLightShader(LSHADER_STANDARD|LSHADER_CUBE);
GLBE_RegisterLightShader(LSHADER_STANDARD|LSHADER_SPOT);
}
#endif
@ -1677,9 +1748,9 @@ static float *tcgen3(const shaderpass_t *pass, int cnt, float *dst, const mesh_t
src = mesh->xyz_array;
for (i = 0; i < cnt; i++, dst += 3)
{
dst[0] = src[i][0] - r_refdef.vieworg[0];
dst[1] = r_refdef.vieworg[1] - src[i][1];
dst[2] = src[i][2] - r_refdef.vieworg[2];
dst[0] = src[i][0] - shaderstate.modelmatrix[3];
dst[1] = shaderstate.modelmatrix[7] - src[i][1];
dst[2] = src[i][2] - shaderstate.modelmatrix[11];
}
return dst-cnt*3;
@ -2138,6 +2209,84 @@ static void colourgen(const shaderpass_t *pass, int cnt, vec4_t *src, vec4_t *ds
}
#endif
static qboolean BE_GenTempMeshVBO(vbo_t **vbo, mesh_t *m);
static void DeformGen_Text(int stringid, int cnt, vecV_t *src, vecV_t *dst, const mesh_t *mesh)
{
#define maxlen 32
vecV_t *textverts = vertexarray;
static vec2_t texttc[maxlen*4];
extern index_t r_quad_indexes[];
static mesh_t textmesh, *meshptr = &textmesh;
int i;
vec3_t org;
vec3_t right;
vec3_t down;
float s, t, d;
char cvarname[64];
const char *text;
Q_snprintfz(cvarname, sizeof(cvarname), "r_shadertext_%i", stringid);
text = Cvar_Get(cvarname, "", 0, "Shader System")->string;
VectorCopy(mesh->snormals_array[0], right);
VectorNegate(mesh->tnormals_array[0], down);
CrossProduct(right, down, org);
if (DotProduct(mesh->normals_array[0], org) > 0)
VectorNegate(right, right);
VectorClear(org);
for (i = 0; i < cnt; i++)
VectorAdd(org, src[i], org);
VectorScale(org, 1.0/i, org);
for (i = 0, s = 0; i < 4; i++)
{
d = DotProduct(right, src[i]) - DotProduct(right, org);
if (s < d)
s = d;
}
i = strlen(text);
VectorScale(right, 2*s/i, right);
VectorScale(down, 2*s/i, down);
VectorMA(org, -i*0.5, right, org);
memset(&textmesh, 0, sizeof(textmesh));
textmesh.indexes = r_quad_indexes;
textmesh.xyz_array = textverts;
textmesh.st_array = texttc;
org[1] += 0;
for (i = 0; i < maxlen; )
{
qbyte c = *text++;
if (!c)
break;
if (c != ' ')
{
const float sz = 1 / 16.0f;
s = (c&15)*sz;
t = (c>>4)*sz;
VectorCopy(org, textverts[i*4+0]);
Vector2Set(texttc[i*4+0], s, t);
VectorAdd(textverts[i*4+0], right, textverts[i*4+1]);
Vector2Set(texttc[i*4+1], s+sz, t);
VectorAdd(textverts[i*4+1], down, textverts[i*4+2]);
Vector2Set(texttc[i*4+2], s+sz, t+sz);
VectorAdd(textverts[i*4+0], down, textverts[i*4+3]);
Vector2Set(texttc[i*4+3], s, t+sz);
i++;
}
VectorAdd(org, right, org);
}
textmesh.numindexes = i*6;
textmesh.numvertexes = i*4;
if (!BE_GenTempMeshVBO(&shaderstate.sourcevbo, &textmesh))
return;
shaderstate.meshcount = 1;
shaderstate.meshes = &meshptr;
#undef maxlen
}
static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *dst, const mesh_t *mesh)
{
float *table;
@ -2227,7 +2376,7 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
if (mesh->numindexes < 6)
break;
for (j = 0; j < cnt-3; j+=4, src+=4, dst+=4)
for (j = 0; j+3 < cnt; j+=4, src+=4, dst+=4)
{
vec3_t mid, d;
float radius;
@ -2239,9 +2388,9 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (k = 0; k < 4; k++)
{
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
dst[k][0] = mid[0] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[8+1]);
}
}
break;
@ -2257,15 +2406,15 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
float len[3];
mat3_t m0, m1, m2, result;
float *quad[4];
vec3_t rot_centre, tv;
vec3_t rot_centre, tv, tv2;
quad[0] = (float *)(dst + mesh->indexes[k+0]);
quad[1] = (float *)(dst + mesh->indexes[k+1]);
quad[2] = (float *)(dst + mesh->indexes[k+2]);
quad[0] = (float *)(src + mesh->indexes[k+0]);
quad[1] = (float *)(src + mesh->indexes[k+1]);
quad[2] = (float *)(src + mesh->indexes[k+2]);
for (j = 2; j >= 0; j--)
{
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
quad[3] = (float *)(src + mesh->indexes[k+3+j]);
if (!VectorEquals (quad[3], quad[0]) &&
!VectorEquals (quad[3], quad[1]) &&
!VectorEquals (quad[3], quad[2]))
@ -2370,15 +2519,20 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (j = 0; j < 4; j++)
{
int v = ((vecV_t*)quad[j]-src);
VectorSubtract(quad[j], rot_centre, tv);
Matrix3_Multiply_Vec3((const vec3_t*)result, tv, quad[j]);
VectorAdd(rot_centre, quad[j], quad[j]);
Matrix3_Multiply_Vec3((const vec3_t*)result, tv, tv2);
VectorAdd(rot_centre, tv2, dst[v]);
}
}
break;
// case DEFORMV_PROJECTION_SHADOW:
// break;
case DEFORMV_TEXT:
DeformGen_Text(deformv->args[0], cnt, src, dst, mesh);
break;
}
}
@ -2586,7 +2740,7 @@ static void GenerateColourMods(const shaderpass_t *pass)
if (r_nolightdir.ival || (!shaderstate.curentity->light_range[0] && !shaderstate.curentity->light_range[1] && !shaderstate.curentity->light_range[2]))
{
VectorCopy(shaderstate.curentity->light_avg, shaderstate.pendingcolourflat);
shaderstate.pendingcolourflat[3] = shaderstate.curentity->shaderRGBAf[3];
alphagen(pass, 1, meshlist->colors4f_array[0], &shaderstate.pendingcolourflat, meshlist);
shaderstate.colourarraytype = 0;
shaderstate.pendingcolourvbo = 0;
shaderstate.pendingcolourpointer = NULL;
@ -3299,7 +3453,14 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm,
#endif
{
vec4_t param4;
Vector4Set(param4, shaderstate.identitylighting, shaderstate.identitylighting, shaderstate.identitylighting, 1);
if (shaderstate.curbatch->flags & BEF_NODLIGHT)
{
Vector4Set(param4, 1, 1, 1, 1);
}
else
{
Vector4Set(param4, shaderstate.identitylighting, shaderstate.identitylighting, shaderstate.identitylighting, 1);
}
qglUniform4fvARB(ph, 1, (GLfloat*)param4);
}
break;
@ -3835,14 +3996,15 @@ void GLBE_SelectEntity(entity_t *ent)
}
shaderstate.depthrange = nd;
if (qglDepthRange)
qglDepthRange (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
else if (qglDepthRangef)
qglDepthRangef (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
// if (qglDepthRange)
// qglDepthRange (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
// else if (qglDepthRangef)
// qglDepthRangef (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
}
shaderstate.lastuniform = 0;
}
#if 1
static void BE_SelectFog(vec3_t colour, float alpha, float density)
{
@ -3865,11 +4027,12 @@ static qboolean GLBE_RegisterLightShader(int mode)
{
if (!shaderstate.inited_shader_light[mode])
{
char *name = va("rtlight%s%s%s%s",
char *name = va("rtlight%s%s%s%s%s",
(mode & LSHADER_SMAP)?"#PCF":"",
(mode & LSHADER_SPOT)?"#SPOT":"",
(mode & LSHADER_CUBE)?"#CUBE":"",
(gl_config.arb_shadow && (mode & (LSHADER_SMAP|LSHADER_SPOT|LSHADER_CUBE)))?"#USE_ARB_SHADOW":""
(mode & LSHADER_ORTHO)?"#ORTHO":"",
(gl_config.arb_shadow && (mode & (LSHADER_SMAP|LSHADER_SPOT|LSHADER_CUBE|LSHADER_ORTHO)))?"#USE_ARB_SHADOW":""
);
shaderstate.inited_shader_light[mode] = true;
@ -3907,7 +4070,7 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned
#ifdef RTLIGHTS
VectorCopy(dl->lightcolourscales, shaderstate.lightcolourscale);
shaderstate.lightcolourscale[2] *= gl_specular.value;
if (lmode & LSHADER_SPOT)
if (lmode & (LSHADER_SPOT|LSHADER_ORTHO))
shaderstate.lightcubemap = r_nulltex;
else
shaderstate.lightcubemap = dl->cubetexture;
@ -3918,7 +4081,18 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned
return false;
/*generate light projection information*/
if (shaderstate.lightmode & LSHADER_SPOT)
if (shaderstate.lightmode & LSHADER_ORTHO)
{
float xmin = -dl->radius;
float ymin = -dl->radius;
float znear = -dl->radius;
float xmax = dl->radius;
float ymax = dl->radius;
float zfar = dl->radius;
Matrix4x4_CM_Orthographic(shaderstate.lightprojmatrix, xmin, xmax, ymax, ymin, znear, zfar);
// Matrix4x4_CM_LightMatrixFromAxis(shaderstate.lightprojmatrix, axis[0], axis[1], axis[2], dl->origin);
}
else if (shaderstate.lightmode & LSHADER_SPOT)
{
float view[16];
float proj[16];
@ -4288,7 +4462,7 @@ static void DrawMeshes(void)
BE_RenderMeshProgram(shaderstate.wireframeshader, shaderstate.wireframeshader->passes, shaderstate.wireframeshader->prog);
}
#ifndef GLSLONLY
else if (gl_config_nofixedfunc)
else if (!gl_config_nofixedfunc)
{
BE_SetPassBlendMode(0, PBM_REPLACE);
GL_DeSelectProgram();
@ -4490,7 +4664,7 @@ static void DrawMeshes(void)
shaderstate.pendingcolourvbo = 0;
shaderstate.pendingcolourpointer = NULL;
BE_SetPassBlendMode(0, PBM_MODULATE);
BE_SendPassBlendDepthMask(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | SBITS_MISC_DEPTHEQUALONLY);
BE_SendPassBlendDepthMask(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (shaderstate.curshader->numpasses?SBITS_MISC_DEPTHEQUALONLY:0));
GenerateTCFog(0, shaderstate.curbatch->fog);
BE_EnableShaderAttributes((1u<<VATTR_LEG_VERTEX) | (1u<<VATTR_LEG_COLOUR) | (1u<<VATTR_LEG_TMU0), 0);
@ -5285,6 +5459,69 @@ void GLBE_FBO_Destroy(fbostate_t *state)
state->enables = 0;
}
#ifdef RTLIGHTS
#ifdef SHADOWDBG_COLOURNOTDEPTH
void GLBE_BeginRenderBuffer_DepthOnly(texid_t depthtexture)
{
if (gl_config.ext_framebuffer_objects)
{
if (!shadow_fbo_id)
{
int drb;
qglGenFramebuffersEXT(1, &shadow_fbo_id);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
//create an unnamed depth buffer
// qglGenRenderbuffersEXT(1, &drb);
// qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, drb);
// qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2);
// qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, drb);
if (qglDrawBuffer)
qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
if (qglReadBuffer)
qglReadBuffer(GL_NONE);
}
else
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
if (TEXVALID(depthtexture))
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, depthtexture->num, 0);
}
}
#else
int GLBE_BeginRenderBuffer_DepthOnly(texid_t depthtexture)
{
int old = shaderstate.fbo_current;
if (gl_config.ext_framebuffer_objects)
{
if (!shadow_fbo_id)
{
qglGenFramebuffersEXT(1, &shadow_fbo_id);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
if (qglDrawBuffers)
qglDrawBuffers(0, NULL);
else if (qglDrawBuffer)
qglDrawBuffer(GL_NONE);
if (qglReadBuffer)
qglReadBuffer(GL_NONE);
}
else
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
shaderstate.fbo_current = shadow_fbo_id;
if (shadow_fbo_depth_num != depthtexture->num)
{
shadow_fbo_depth_num = depthtexture->num;
if (TEXVALID(depthtexture))
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depthtexture->num, 0);
}
}
return old;
}
#endif
#endif
//state->colour is created if usedepth is set and it doesn't previously exist
int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, int mrt, texid_t destdepth, int width, int height, int layer)
{

View File

@ -7217,6 +7217,57 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
continue;
}
}
else if (inbrush && !strcmp(token, "patchDef2"))
{
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*validate {*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*parse texture name*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*validate (*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*xoffset = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*yoffset = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*rotation = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*xscale = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*yscale = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*validate )*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*validate (*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
while (!strcmp(token, "("))
{
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
while (!strcmp(token, "("))
{
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
//x = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
//y = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
//z = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
//s = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
//t = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*validate )*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
}
/*validate )*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
}
/*validate )*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*validate }*/
}
else if (inbrush)
{
//parse a plane
@ -7224,6 +7275,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
//hexen2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale utterlypointless
//Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//fte : ( px py pz pd ) texname [sx sy sz sd] [tx ty tz td] 0 1 1
//q3 : (( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) common/caulk common/caulk rotation sscale tscale detailcontents unused unused
brushtex_t *bt;
vec3_t d1,d2;
vec3_t points[3];
@ -7332,10 +7384,31 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
scale[1] = atof(token);
//hexen2 has some extra junk that is useless - some 'light' value, but its never used and should normally be -1.
//quake3 on the other hand has 3 different args. Contents Unused Unused. The contents conveys only CONTENTS_DETAIL. which is awkward as it varies by game.
while (*entities == ' ' || *entities == '\t')
entities++;
if (*entities == '-' || (*entities >= '0' && *entities <= '9'))
{
int ex1;
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
ex1 = atoi(token);
while (*entities == ' ' || *entities == '\t')
entities++;
if (*entities == '-' || (*entities >= '0' && *entities <= '9'))
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
while (*entities == ' ' || *entities == '\t')
entities++;
if (*entities == '-' || (*entities >= '0' && *entities <= '9'))
{
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
//if we got this far, then its q3 format.
//q3 is weird. the first extra arg is contents. but only the detail contents is used.
if (ex1 & Q3CONTENTS_DETAIL)
brushcontents |= Q3CONTENTS_DETAIL;
}
}
//okay, that's all the actual parsing, now try to make sense of this plane.
if (p == 4)

View File

@ -5306,7 +5306,7 @@ void Mod_LoadDoomSprite (model_t *mod)
"{\n" \
"map $diffuse\n" \
"if gl_blendsprites\n" \
"blendfunc GL_SRC_ALPHA GL_ONE\n" \
"blendfunc GL_ONE GL_ONE_MINUS_SRC_ALPHA\n" \
"else\n" \
"alphafunc ge128\n" \
"depthwrite\n" \
@ -5378,7 +5378,7 @@ void Mod_LoadSpriteFrameShader(model_t *spr, int frame, int subframe, mspritefra
"program defaultsprite\n"
"{\n"
"map $diffuse\n"
"blendfunc GL_SRC_ALPHA GL_ONE\n"
"blendfunc GL_ONE GL_ONE\n" //lit sprites are actually additive...
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
@ -5482,7 +5482,7 @@ static void * Mod_LoadSpriteFrame (model_t *mod, void *pin, void *pend, mspritef
}
Q_snprintfz(name, sizeof(name), "%s_%i.tga", mod->name, framenum);
pspriteframe->image = Image_GetTexture(name, "sprites", IF_NOMIPMAP|IF_NOGAMMA|IF_CLAMP, dataptr, palette, width, height, lowresfmt);
pspriteframe->image = Image_GetTexture(name, "sprites", IF_NOMIPMAP|IF_NOGAMMA|IF_CLAMP|IF_PREMULTIPLYALPHA, dataptr, palette, width, height, lowresfmt);
return (void *)((qbyte *)(pinframe+1) + size);
}

View File

@ -520,7 +520,7 @@ void R_RenderDlights (void)
}
qboolean Sh_GenerateShadowMap(dlight_t *l);
qboolean Sh_GenerateShadowMap(dlight_t *l, int lightflags);
qboolean Sh_CullLight(dlight_t *dl, qbyte *vvis);
void R_GenDlightMesh(struct batch_s *batch)
{
@ -554,7 +554,7 @@ void R_GenDlightMesh(struct batch_s *batch)
#ifdef RTLIGHTS
if (lightflags & LSHADER_SMAP)
{
if (!Sh_GenerateShadowMap(l))
if (!Sh_GenerateShadowMap(l, lightflags))
{
batch->meshes = 0;
return;
@ -1245,7 +1245,7 @@ void R_SaveRTLights_f(void)
light->style-1,
light->cubemapname, light->corona,
ang[0], ang[1], ang[2],
light->coronascale, light->lightcolourscales[0], light->lightcolourscales[1], light->lightcolourscales[2], light->flags&(LFLAG_NORMALMODE|LFLAG_REALTIMEMODE|LFLAG_CREPUSCULAR),
light->coronascale, light->lightcolourscales[0], light->lightcolourscales[1], light->lightcolourscales[2], light->flags&~(LFLAG_NOSHADOWS|LFLAG_INTERNAL),
light->rotation[0],light->rotation[1],light->rotation[2],light->fov
));
}

View File

@ -592,6 +592,13 @@ void R_SetupGL (float stereooffset, int i)
}
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_origin);
r_refdef.m_projection_view[2+4*0] *= 0.333;
r_refdef.m_projection_view[2+4*1] *= 0.333;
r_refdef.m_projection_view[2+4*2] *= 0.333;
r_refdef.m_projection_view[2+4*3] *= 0.333;
r_refdef.m_projection_view[14] -= 0.666;
//FIXME: bias, so that we use -1 to -.333 range instead of -.333 to 0.333
}
}
@ -1317,13 +1324,6 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
if (qglLoadMatrixf)
{
/*put GL back the way it was*/
qglMatrixMode(GL_PROJECTION);
qglLoadMatrixf(r_refdef.m_projection_std);
qglMatrixMode(GL_MODELVIEW);
}
GLBE_SelectEntity(&r_worldentity);
GL_CullFace(0);//make sure flipcull reversion takes effect

View File

@ -48,8 +48,9 @@ extern cvar_t r_fastturb, r_fastsky, r_skyboxname;
extern cvar_t r_drawflat;
extern cvar_t r_shaderblobs;
extern cvar_t r_tessellation;
extern cvar_t gl_compress;
//backend fills this in to say the max pass count
//backend fills this in to say the max fixed-function pass count (often 1, where its emulated by us, because we're too lazy).
int be_maxpasses;
@ -898,6 +899,11 @@ static void Shader_DeformVertexes ( shader_t *shader, shaderpass_t *pass, char *
}
else if ( !Q_stricmp (token, "projectionShadow") )
deformv->type = DEFORMV_PROJECTION_SHADOW;
else if ( !Q_strnicmp (token, "text", 4) )
{
deformv->type = DEFORMV_TEXT;
deformv->args[0] = atoi(token+4);
}
else
return;
@ -2535,14 +2541,17 @@ static void Shader_BEMode(shader_t *shader, shaderpass_t *pass, char **ptr)
//shorthand for rtlights
for (mode = 0; mode < LSHADER_MODES; mode++)
{
if ((mode & LSHADER_CUBE) && (mode & LSHADER_SPOT))
continue;
Q_snprintfz(subname, sizeof(subname), "%s%s%s%s%s", tokencopy,
if ((mode & LSHADER_CUBE) && (mode & (LSHADER_SPOT|LSHADER_ORTHO)))
continue; //cube projections don't make sense when the light isn't projecting a cube
if ((mode & LSHADER_ORTHO) && (mode & LSHADER_SPOT))
continue; //ortho+spot are mutually exclusive.
Q_snprintfz(subname, sizeof(subname), "%s%s%s%s%s%s", tokencopy,
(mode & LSHADER_SMAP)?"#PCF":"",
(mode & LSHADER_SPOT)?"#SPOT":"",
(mode & LSHADER_CUBE)?"#CUBE":"",
(mode & LSHADER_ORTHO)?"#ORTHO":"",
#ifdef GLQUAKE
(qrenderer == QR_OPENGL && gl_config.arb_shadow && (mode & (LSHADER_SMAP|LSHADER_SPOT)))?"#USE_ARB_SHADOW":""
(qrenderer == QR_OPENGL && gl_config.arb_shadow && (mode & LSHADER_SMAP))?"#USE_ARB_SHADOW":""
#else
""
#endif
@ -2621,6 +2630,21 @@ static shaderkey_t shaderkeys[] =
{"nooverlays", NULL, "doom3"},
{"nofragment", NULL, "doom3"},
/*RTCW vompat*/
{"nocompress", NULL, "rtcw"},
{"allowcompress", NULL, "rtcw"},
{"nofog", NULL, "rtcw"},
{"skyfogvars", NULL, "rtcw"},
{"sunshader", NULL, "rtcw"},
{"sun", NULL, "q3map2"}, //provides rgb and dir
{"sunExt", NULL, "q3map2"}, //treated as an alias
{"fogParms", NULL, "rtcw"}, //sets a cvar. *shudder*
{"fogvars", NULL, "rtcw"}, //sets a cvar. *shudder*
{"waterfogvars", NULL, "rtcw"}, //sets a cvar. *shudder*
{"light", NULL, "rtcw"}, //for q3map2, not us
{"lightgridmulamb", NULL, "rtcw"}, //urm
{"lightgridmuldir", NULL, "rtcw"}, //not really sure how this is useful to us
/*qfusion / warsow compat*/
// {"skyparms2", NULL, "qf"}, //skyparms without the underscore.
// {"skyparmssides", NULL, "qf"}, //skyparms with explicitly-named faces
@ -2981,6 +3005,37 @@ static void Shaderpass_VideoMap (shader_t *shader, shaderpass_t *pass, char **pt
#endif
}
static void Shaderpass_RTCW_Map_16bit (shader_t *shader, shaderpass_t *pass, char **ptr)
{
if (!gl_load24bit.ival) //urm, not sure if suitable choice of cvar
Shaderpass_Map(shader, pass, ptr);
}
static void Shaderpass_RTCW_Map_32bit (shader_t *shader, shaderpass_t *pass, char **ptr)
{
if (gl_load24bit.ival)
Shaderpass_Map(shader, pass, ptr);
}
static void Shaderpass_RTCW_Map_s3tc (shader_t *shader, shaderpass_t *pass, char **ptr)
{
if (sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival)
Shaderpass_Map(shader, pass, ptr);
}
static void Shaderpass_RTCW_Map_nos3tc (shader_t *shader, shaderpass_t *pass, char **ptr)
{
if (!(sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival))
Shaderpass_Map(shader, pass, ptr);
}
static void Shaderpass_RTCW_AnimMap_s3tc (shader_t *shader, shaderpass_t *pass, char **ptr)
{
if ((sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival))
Shaderpass_AnimMap(shader, pass, ptr);
}
static void Shaderpass_RTCW_AnimMap_nos3tc (shader_t *shader, shaderpass_t *pass, char **ptr)
{
if (!(sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival))
Shaderpass_AnimMap(shader, pass, ptr);
}
static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr, int qrtype)
{
/*accepts:
@ -3348,8 +3403,11 @@ static void Shaderpass_TcMod (shader_t *shader, shaderpass_t *pass, char **ptr)
tcmod->args[i] = Shader_ParseFloat (shader, ptr, 0);
tcmod->type = SHADER_TCMOD_PAGE;
}
// else if (!Q_stricmp (token, "entityTranslate")) //RTCW
// else if (!Q_stricmp (token, "swap")) //RTCW
else
{
Con_DPrintf("Unknown tcmod %s in %s\n", token, shader->name);
return;
}
@ -3441,6 +3499,8 @@ static void Shaderpass_TcGen ( shader_t *shader, shaderpass_t *pass, char **ptr
pass->tcgen = TC_GEN_LIGHTMAP;
} else if ( !Q_stricmp (token, "environment") ) {
pass->tcgen = TC_GEN_ENVIRONMENT;
} else if ( !Q_stricmp (token, "fireriseenv") ) { //from RTCW
pass->tcgen = TC_GEN_ENVIRONMENT; //FIXME: not supported
} else if ( !Q_stricmp (token, "vector") )
{
pass->tcgen = TC_GEN_VECTOR;
@ -3608,6 +3668,17 @@ static shaderkey_t shaderpasskeys[] =
{"alpha", Shaderpass_Alpha, "doom3"},
//RTCW
//fancy map lines use the map if that mode is active.
//FIXME: actually check these to ensure there's no issues with any shaders overriding the pass's previously specified map
// (hopefully no shaders would actually do that due to the engine loading both textures, which would be wasteful)
{"map16", Shaderpass_RTCW_Map_16bit, "rtcw"},
{"map32", Shaderpass_RTCW_Map_32bit, "rtcw"},
{"mapcomp", Shaderpass_RTCW_Map_s3tc, "rtcw"},
{"mapnocomp", Shaderpass_RTCW_Map_nos3tc, "rtcw"},
{"animcompmap", Shaderpass_RTCW_AnimMap_s3tc, "rtcw"},
{"animnocompmap",Shaderpass_RTCW_AnimMap_nos3tc,"rtcw"},
//qfusion/warsow compat
{"material", Shaderpass_QF_Material, "qf"},
{"animclampmap",Shaderpass_QF_AnimClampMap, "qf"},
@ -3980,8 +4051,9 @@ void Shader_Shutdown (void)
shader_reload_needed = false;
}
void Shader_SetBlendmode (shaderpass_t *pass)
void Shader_SetBlendmode (shaderpass_t *pass, shaderpass_t *lastpass)
{
qboolean lightmapoverbright;
if (pass->texgen == T_GEN_DELUXMAP)
{
pass->blendmode = PBM_DOTPRODUCT;
@ -3996,7 +4068,7 @@ void Shader_SetBlendmode (shaderpass_t *pass)
if (!(pass->shaderbits & SBITS_BLEND_BITS))
{
if (pass->texgen == T_GEN_LIGHTMAP)
if (pass->texgen == T_GEN_LIGHTMAP && lastpass)
pass->blendmode = PBM_OVERBRIGHT;
else if ((pass->rgbgen == RGB_GEN_IDENTITY) && (pass->alphagen == ALPHA_GEN_IDENTITY))
{
@ -4020,15 +4092,18 @@ void Shader_SetBlendmode (shaderpass_t *pass)
return;
}
lightmapoverbright = pass->texgen == T_GEN_LIGHTMAP || (lastpass && lastpass->texgen == T_GEN_LIGHTMAP && lastpass->blendmode != PBM_OVERBRIGHT);
if (((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_ZERO|SBITS_DSTBLEND_SRC_COLOR)) ||
((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_DST_COLOR|SBITS_DSTBLEND_ZERO)))
pass->blendmode = (pass->texgen == T_GEN_LIGHTMAP)?PBM_OVERBRIGHT:PBM_MODULATE;
((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_DST_COLOR|SBITS_DSTBLEND_ZERO)) ||
((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_DST_COLOR|SBITS_DSTBLEND_ONE_MINUS_DST_ALPHA)))
pass->blendmode = lightmapoverbright?PBM_OVERBRIGHT:PBM_MODULATE;
else if ((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ONE))
pass->blendmode = PBM_ADD;
else if ((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_SRC_ALPHA|SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA))
pass->blendmode = PBM_DECAL;
else
pass->blendmode = (pass->texgen == T_GEN_LIGHTMAP)?PBM_OVERBRIGHT:PBM_MODULATE;
pass->blendmode = lightmapoverbright?PBM_OVERBRIGHT:PBM_MODULATE;
}
void Shader_FixupProgPasses(shader_t *shader, shaderpass_t *pass)
@ -4486,10 +4561,12 @@ void Shader_SetPassFlush (shaderpass_t *pass, shaderpass_t *pass2)
{
pass->numMergedPasses++;
}
else if ((pass->blendmode == PBM_MODULATE || pass->blendmode == PBM_OVERBRIGHT) && pass2->blendmode == PBM_MODULATE)
else if ((pass->blendmode == PBM_MODULATE || pass->blendmode == PBM_OVERBRIGHT) && (pass2->blendmode == PBM_MODULATE || pass2->blendmode == PBM_OVERBRIGHT))
{
pass->numMergedPasses++;
}
else if (pass->blendmode == PBM_DECAL && pass2->blendmode == PBM_OVERBRIGHT)
pass->numMergedPasses++; //HACK: allow modulating overbright passes with decal passes. overbright passes need to blend with something for their lighting to be correct, so this is a tradeoff.
else
return;
}
@ -4751,7 +4828,7 @@ void Shader_Finish (shader_t *s)
pass->rgbgen = RGB_GEN_IDENTITY;
pass->alphagen = ALPHA_GEN_IDENTITY;
pass->numMergedPasses = 1;
Shader_SetBlendmode(pass);
Shader_SetBlendmode(pass, NULL);
}
if (!s->numpasses && s->sort != SHADER_SORT_PORTAL && !(s->flags & (SHADER_NODRAW|SHADER_SKY)) && !s->fog_dist)
@ -4776,7 +4853,7 @@ void Shader_Finish (shader_t *s)
pass->rgbgen = RGB_GEN_VERTEX_LIGHTING;
pass->alphagen = ALPHA_GEN_IDENTITY;
pass->numMergedPasses = 1;
Shader_SetBlendmode(pass);
Shader_SetBlendmode(pass, NULL);
}
if (!Q_stricmp (s->name, "flareShader"))
@ -4959,15 +5036,22 @@ done:;
// all passes have blendfuncs
if (i == s->numpasses)
{
int opaque;
int maskpass;
qboolean isopaque = false;
opaque = -1;
maskpass = -1;
pass = s->passes;
for (i = 0; i < s->numpasses; i++, pass++ )
{
if (pass->shaderbits & SBITS_ATEST_BITS)
{
opaque = i;
maskpass = i;
}
else if ((pass->shaderbits & SBITS_MASK_BITS) == 0)
{ //a few shaders use blendfunc one zero so that they're ignored when using r_vertexlight (while later alpha-masked surfs are not).
if (/*(pass->shaderbits & (SBITS_SRCBLEND_BITS|SBITS_DSTBLEND_BITS)) == 0 ||*/
(pass->shaderbits & (SBITS_SRCBLEND_BITS|SBITS_DSTBLEND_BITS)) == (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO))
isopaque = true;
}
if (pass->rgbgen == RGB_GEN_UNKNOWN)
@ -4980,7 +5064,7 @@ done:;
pass->rgbgen = RGB_GEN_IDENTITY;
}
Shader_SetBlendmode (pass);
Shader_SetBlendmode (pass, i?pass-1:NULL);
if (pass->blendmode == PBM_ADD)
s->defaulttextures->fullbright = pass->anim_frames[0];
@ -4988,8 +5072,15 @@ done:;
if (!(s->flags & SHADER_SKY ) && !s->sort)
{
if (opaque == -1)
s->sort = SHADER_SORT_BLEND;
if (isopaque)
s->sort = SHADER_SORT_OPAQUE;
else if (maskpass == -1)
{
if (s->numpasses && s->passes[0].blendmode == PBM_ADD)
s->sort = SHADER_SORT_ADDITIVE;
else
s->sort = SHADER_SORT_BLEND;
}
else
s->sort = SHADER_SORT_SEETHROUGH;
}
@ -5010,7 +5101,7 @@ done:;
sp->rgbgen = RGB_GEN_IDENTITY;
}
Shader_SetBlendmode (sp);
Shader_SetBlendmode (sp, j?sp-1:NULL);
}
if (!s->sort)
@ -5038,7 +5129,7 @@ done:;
break;
pass = s->passes + i;
for (j = i + pass->numMergedPasses; j < s->numpasses-i && j == i + pass->numMergedPasses && j < be_maxpasses; j++)
for (j = 1; j < s->numpasses-i && j == pass->numMergedPasses && j+1 < be_maxpasses; j++)
Shader_SetPassFlush (pass, pass + j);
i += pass->numMergedPasses;
@ -6273,7 +6364,7 @@ void Shader_DefaultBSPFlare(const char *shortname, shader_t *s, const void *args
pass->numtcmods = 0;
pass->tcgen = TC_GEN_BASE;
pass->numMergedPasses = 1;
Shader_SetBlendmode(pass);
Shader_SetBlendmode(pass, NULL);
if (!TEXVALID(pass->anim_frames[0]))
{

View File

@ -6,8 +6,6 @@ There is no screen-space culling of lit surfaces.
model meshes are interpolated multiple times per frame
*/
//#define DBG_COLOURNOTDEPTH
#if defined(RTLIGHTS) && !defined(SERVERONLY)
@ -48,11 +46,6 @@ static void SHM_Shutdown(void);
extern qboolean r_pushdepth;
#endif
#ifdef GLQUAKE
static texid_t shadowmap[2];
static int shadow_fbo_id;
static int shadow_fbo_depth_num;
#endif
texid_t crepuscular_texture_id;
fbostate_t crepuscular_fbo;
shader_t *crepuscular_shader;
@ -92,22 +85,6 @@ flushes textures so they can be regenerated at the real size
void Sh_Reset(void)
{
#ifdef GLQUAKE
if (shadow_fbo_id)
{
qglDeleteFramebuffersEXT(1, &shadow_fbo_id);
shadow_fbo_id = 0;
shadow_fbo_depth_num = 0;
}
if (shadowmap[0])
{
Image_DestroyTexture(shadowmap[0]);
shadowmap[0] = r_nulltex;
}
if (shadowmap[1])
{
Image_DestroyTexture(shadowmap[1]);
shadowmap[1] = r_nulltex;
}
if (crepuscular_texture_id)
{
Image_DestroyTexture(crepuscular_texture_id);
@ -2050,78 +2027,6 @@ static qboolean Sh_ScissorForBox(vec3_t mins, vec3_t maxs, vrect_t *r)
}
#endif
#ifdef GLQUAKE
#ifdef DBG_COLOURNOTDEPTH
void GL_BeginRenderBuffer_DepthOnly(texid_t depthtexture)
{
if (gl_config.ext_framebuffer_objects)
{
if (!shadow_fbo_id)
{
int drb;
qglGenFramebuffersEXT(1, &shadow_fbo_id);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
//create an unnamed depth buffer
// qglGenRenderbuffersEXT(1, &drb);
// qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, drb);
// qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2);
// qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, drb);
if (qglDrawBuffer)
qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
if (qglReadBuffer)
qglReadBuffer(GL_NONE);
}
else
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
if (TEXVALID(depthtexture))
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, depthtexture.num, 0);
}
}
#else
void GL_BeginRenderBuffer_DepthOnly(texid_t depthtexture)
{
if (gl_config.ext_framebuffer_objects)
{
if (!shadow_fbo_id)
{
qglGenFramebuffersEXT(1, &shadow_fbo_id);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
if (qglDrawBuffers)
qglDrawBuffers(0, NULL);
else if (qglDrawBuffer)
qglDrawBuffer(GL_NONE);
if (qglReadBuffer)
qglReadBuffer(GL_NONE);
}
else
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id);
if (shadow_fbo_depth_num != depthtexture->num)
{
shadow_fbo_depth_num = depthtexture->num;
if (TEXVALID(depthtexture))
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depthtexture->num, 0);
}
}
}
#endif
void GL_EndRenderBuffer_DepthOnly(int restorefbo, texid_t depthtexture, int texsize)
{
if (gl_config.ext_framebuffer_objects)
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, restorefbo);
}
else
{
GL_MTBind(0, GL_TEXTURE_2D, depthtexture);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
}
}
#endif
void D3D11BE_BeginShadowmapFace(void);
//determine the 5 bounding points of a shadowmap light projection side
@ -2156,7 +2061,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], shadowmesh_t *smesh, int face, int smsize, float proj[16])
static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, float proj[16])
{
vec3_t t1,t2,t3;
texture_t *tex;
@ -2222,7 +2127,7 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], shadowmesh_t *smesh, i
break;
}
if (l->fov)
if (lighttype & (LSHADER_SPOT|LSHADER_ORTHO))
{
r_refdef.pxrect.x = (SHADOWMAP_SIZE-smsize)/2;
r_refdef.pxrect.width = smsize;
@ -2241,15 +2146,13 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], shadowmesh_t *smesh, i
R_SetFrustum(proj, r_refdef.m_view);
#ifdef DBG_COLOURNOTDEPTH
#ifdef SHADOWDBG_COLOURNOTDEPTH
BE_SelectMode(BEM_STANDARD);
#else
BE_SelectMode(BEM_DEPTHONLY);
#endif
BE_SelectEntity(&r_worldentity);
switch(qrenderer)
{
#ifdef GLQUAKE
@ -2341,32 +2244,34 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], shadowmesh_t *smesh, i
*/
}
qboolean D3D11_BeginShadowMap(int id, int w, int h);
void D3D11_EndShadowMap(void);
void D3D11BE_SetupForShadowMap(dlight_t *dl, qboolean isspot, int texwidth, int texheight, float shadowscale);
qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvis, int smsize)
{
#ifdef GLQUAKE
int restorefbo = 0;
#endif
int f;
float oproj[16], oview[16];
int restorefbo;
int f,lf;
float oprojs[16], oprojv[16], oview[16];
pxrect_t oprect;
shadowmesh_t *smesh;
int isspot = (l->fov != 0);
qboolean isspot = !!(lighttype & (LSHADER_SPOT|LSHADER_ORTHO));
int sidevisible;
int oldflip = r_refdef.flipcull;
int oldexternalview = r_refdef.externalview;
if (!R_CullSphere(l->origin, 0))
sidevisible = l->fov?1:0x3f; //assume all are visible if the central point is onscreen
if (isspot)
{ //spotlights only face forwards. which is side 4. which is annoying.
f = 4;
lf = f+1;
sidevisible = 1<<f;
}
else
{
sidevisible = 0;
f = 0;
lf = 6;
sidevisible = (1<<6)-1;
}
if (R_CullSphere(l->origin, 0))
{ //if the light's center isn't onscreen, cull individual faces
//FIXME: if the fov is < 90, we need to clip by the near lightplane first
for (f = 0; f < (l->fov?1:6); f++)
for (; f < lf; f++)
{
vec4_t planes[5];
float dist;
@ -2392,8 +2297,8 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
if (dist <= 0)
break;
}
if (fp == r_refdef.frustum_numplanes)
sidevisible |= 1u<<f;
if (fp != r_refdef.frustum_numplanes)
sidevisible &= ~(1u<<f);
}
}
@ -2401,12 +2306,28 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
if (!sidevisible)
return false;
memcpy(oproj, r_refdef.m_projection_std, sizeof(oproj));
memcpy(oprojs, r_refdef.m_projection_std, sizeof(oprojs));
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, SMT_SHADOWMAP);
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, l->fov?l->fov:90, l->fov?l->fov:90, r_shadow_shadowmapping_nearclip.value, l->radius, false);
if (lighttype & LSHADER_SPOT)
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, l->fov, l->fov, r_shadow_shadowmapping_nearclip.value, l->radius, false);
else if (lighttype & LSHADER_ORTHO)
{
float xmin = -l->radius;
float ymin = -l->radius;
float znear = -l->radius;
float xmax = l->radius;
float ymax = l->radius;
float zfar = l->radius;
Matrix4x4_CM_Orthographic(r_refdef.m_projection_std, xmin, xmax, ymax, ymin, znear, zfar);
}
else
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, 90, 90, r_shadow_shadowmapping_nearclip.value, l->radius, false);
memcpy(r_refdef.m_projection_view, r_refdef.m_projection_std, sizeof(r_refdef.m_projection_view));
switch(qrenderer)
{
@ -2414,77 +2335,14 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
return false;
#ifdef GLQUAKE
case QR_OPENGL:
if (!TEXVALID(shadowmap[isspot]))
{
if (isspot)
{
shadowmap[isspot] = Image_CreateTexture("***shadowmap2dspot***", NULL, 0);
qglGenTextures(1, &shadowmap[isspot]->num);
GL_MTBind(0, GL_TEXTURE_2D, shadowmap[isspot]);
#ifdef DBG_COLOURNOTDEPTH
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SHADOWMAP_SIZE, SHADOWMAP_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
#else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, SHADOWMAP_SIZE, SHADOWMAP_SIZE, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
#endif
}
else
{
shadowmap[isspot] = Image_CreateTexture("***shadowmap2domni***", NULL, 0);
qglGenTextures(1, &shadowmap[isspot]->num);
GL_MTBind(0, GL_TEXTURE_2D, shadowmap[isspot]);
#ifdef DBG_COLOURNOTDEPTH
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
#else
if (gl_config.gles)
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
#endif
}
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#if 0//def DBG_COLOURNOTDEPTH
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
#else
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
//in case we're using shadow samplers
if (gl_config.arb_shadow)
{
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
}
}
/*set framebuffer*/
GL_BeginRenderBuffer_DepthOnly(shadowmap[isspot]);
restorefbo = GLBE_SetupForShadowMap(shadowmap[isspot], isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
BE_Scissor(NULL);
qglViewport(0, 0, smsize*3, smsize*2);
qglClear (GL_DEPTH_BUFFER_BIT);
#ifdef DBG_COLOURNOTDEPTH
qglClearColor(0,1,0,1);
qglClear (GL_COLOR_BUFFER_BIT);
#endif
if (!gl_config.nofixedfunc)
{
qglMatrixMode(GL_PROJECTION);
qglLoadMatrixf(r_refdef.m_projection_std);
qglMatrixMode(GL_MODELVIEW);
}
if (!GLBE_BeginShadowMap(isspot, (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*3)), (isspot?SHADOWMAP_SIZE:(SHADOWMAP_SIZE*2)), &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))))
return false;
// BE_Scissor(&rect);
break;
#endif
@ -2504,12 +2362,13 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
if (sidevisible & (1u<<f))
{
RQuantAdd(RQUANT_SHADOWSIDES, 1);
Sh_GenShadowFace(l, axis, smesh, f, smsize, r_refdef.m_projection_std);
Sh_GenShadowFace(l, axis, lighttype, smesh, f, smsize, r_refdef.m_projection_std);
}
}
memcpy(r_refdef.m_view, oview, sizeof(r_refdef.m_view));
memcpy(r_refdef.m_projection_std, oproj, sizeof(r_refdef.m_projection_std));
memcpy(r_refdef.m_projection_std, oprojs, sizeof(r_refdef.m_projection_std));
memcpy(r_refdef.m_projection_view, oprojv, sizeof(r_refdef.m_projection_view));
r_refdef.pxrect = oprect;
@ -2519,19 +2378,10 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
switch(qrenderer)
{
default:
break;
#ifdef GLQUAKE
case QR_OPENGL:
/*end framebuffer*/
GL_EndRenderBuffer_DepthOnly(restorefbo, shadowmap[isspot], smsize);
if (!gl_config.nofixedfunc)
{
qglMatrixMode(GL_PROJECTION);
qglLoadMatrixf(r_refdef.m_projection_std);
qglMatrixMode(GL_MODELVIEW);
qglLoadMatrixf(r_refdef.m_view);
}
GLBE_EndShadowMap(restorefbo);
GL_ViewportUpdate();
break;
#endif
@ -2546,18 +2396,20 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
VKBE_DoneShadows();
break;
#endif
default:
(void)restorefbo;
break;
}
return true;
}
qboolean Sh_GenerateShadowMap(dlight_t *l)
qboolean Sh_GenerateShadowMap(dlight_t *l, int lighttype)
{
qboolean isspot;
int smsize;
qbyte *vvis = r_refdef.scenevis;
qbyte *lvis;
int texwidth, texheight;
/* if (Sh_ScissorForBox(mins, maxs, &rect))
{
@ -2595,10 +2447,8 @@ qboolean Sh_GenerateShadowMap(dlight_t *l)
lvis = NULL;
isspot = l->fov != 0;
if (isspot)
smsize = SHADOWMAP_SIZE;
if (lighttype & (LSHADER_SPOT | LSHADER_ORTHO))
texwidth = texheight = smsize = SHADOWMAP_SIZE;
else
{
//Stolen from DP. Actually, LH pasted it to me in IRC.
@ -2612,19 +2462,35 @@ qboolean Sh_GenerateShadowMap(dlight_t *l)
distance = VectorLength(d);
lodlinear = (l->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / l->radius));
smsize = bound(16, lodlinear, SHADOWMAP_SIZE);
texwidth = smsize*3;
texheight = smsize*2;
}
switch(qrenderer)
{
#ifdef GLQUAKE
case QR_OPENGL:
GLBE_SetupForShadowMap(l, texwidth, texheight, (smsize-4) / (float)SHADOWMAP_SIZE);
break;
#endif
#ifdef D3D11QUAKE
if (qrenderer == QR_DIRECT3D11)
D3D11BE_SetupForShadowMap(l, isspot, isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
case QR_DIRECT3D11:
D3D11BE_SetupForShadowMap(l, texwidth, texheight, (smsize-4) / (float)SHADOWMAP_SIZE);
break;
#endif
#ifdef VKQUAKE
if (qrenderer == QR_VULKAN)
VKBE_SetupForShadowMap(l, isspot, isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
case QR_VULKAN:
VKBE_SetupForShadowMap(l, texwidth, texheight, (smsize-4) / (float)SHADOWMAP_SIZE);
break;
#endif
default:
(void)texwidth;
(void)texheight;
break;
}
//fixme: light rotation
if (!Sh_GenShadowMap(l, l->axis, lvis, smsize))
if (!Sh_GenShadowMap(l, lighttype, l->axis, lvis, smsize))
return false; //didn't need to do anything
return true;
}
@ -2635,7 +2501,17 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb
qbyte *lvis;
srect_t rect;
int smsize;
qboolean isspot;
int lighttype;
int texwidth, texheight;
if (l->fov != 0)
lighttype = LSHADER_SMAP|LSHADER_SPOT;
#ifdef LFLAG_ORTHO
else if (l->flags & LFLAG_ORTHO)
lighttype = LSHADER_SMAP|LSHADER_ORTHO;
#endif
else
lighttype = LSHADER_SMAP;
if (R_CullSphere(l->origin, l->radius))
{
@ -2688,10 +2564,18 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb
else
lvis = NULL;
isspot = l->fov != 0;
if (isspot)
smsize = SHADOWMAP_SIZE;
if (lighttype & LSHADER_SPOT)
{
smsize = SHADOWMAP_SIZE; //spot lights or ortho lights can just use the full thing.
texwidth = smsize;
texheight = smsize;
}
else if (lighttype & LSHADER_ORTHO)
{
smsize = SHADOWMAP_SIZE; //spot lights or ortho lights can just use the full thing.
texwidth = smsize;
texheight = smsize;
}
else
{
//Stolen from DP. Actually, LH pasted it to me in IRC.
@ -2705,20 +2589,36 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb
distance = VectorLength(d);
lodlinear = (l->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / l->radius));
smsize = bound(16, lodlinear, SHADOWMAP_SIZE);
texwidth = smsize*3;
texheight = smsize*2;
}
switch(qrenderer)
{
#ifdef GLQUAKE
case QR_OPENGL:
GLBE_SetupForShadowMap(l, texwidth, texheight, (smsize-4) / (float)SHADOWMAP_SIZE);
break;
#endif
#ifdef D3D11QUAKE
if (qrenderer == QR_DIRECT3D11)
D3D11BE_SetupForShadowMap(l, isspot, isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
case QR_DIRECT3D11:
D3D11BE_SetupForShadowMap(l, texwidth, texheight, (smsize-4) / (float)SHADOWMAP_SIZE);
break;
#endif
#ifdef VKQUAKE
if (qrenderer == QR_VULKAN)
VKBE_SetupForShadowMap(l, isspot, isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
case QR_VULKAN:
VKBE_SetupForShadowMap(l, texwidth, texheight, (smsize-4) / (float)SHADOWMAP_SIZE);
break;
#endif
default:
(void)texwidth;
(void)texheight;
break;
}
if (!BE_SelectDLight(l, colour, axis, isspot?LSHADER_SPOT:LSHADER_SMAP))
if (!BE_SelectDLight(l, colour, axis, lighttype))
return;
if (!Sh_GenShadowMap(l, axis, lvis, smsize))
if (!Sh_GenShadowMap(l, lighttype, axis, lvis, smsize))
return;
RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1);
@ -3594,6 +3494,7 @@ void Sh_CheckSettings(void)
case QR_VULKAN:
canshadowless = true;
cansmap = true;
canstencil = false;
break;
#endif
#ifdef GLQUAKE
@ -3601,14 +3502,14 @@ void Sh_CheckSettings(void)
canshadowless = gl_config.arb_shader_objects || !gl_config_nofixedfunc; //falls back to crappy texture env
if (gl_config.arb_shader_objects && gl_config.ext_framebuffer_objects && gl_config.arb_depth_texture)// && gl_config.arb_shadow)
cansmap = true;
else if (r_shadow_realtime_world_shadows.ival || r_shadow_realtime_dlight_shadows.ival)
else if ((r_shadow_realtime_world_shadows.ival || r_shadow_realtime_dlight_shadows.ival) && r_shadow_shadowmapping.ival)
{
if (!gl_config.arb_shader_objects)
Con_Printf("No arb_shader_objects\n");
if (!gl_config.ext_framebuffer_objects)
Con_Printf("No ext_framebuffer_objects\n");
if (!gl_config.arb_depth_texture)
Con_Printf("No arb_depth_texture\n");
Con_DPrintf("Shadowmapping unsupported: No arb_shader_objects\n");
else if (!gl_config.ext_framebuffer_objects)
Con_DPrintf("Shadowmapping unsupported: No ext_framebuffer_objects\n");
else if (!gl_config.arb_depth_texture)
Con_DPrintf("Shadowmapping unsupported: No arb_depth_texture\n");
}
if (gl_stencilbits)
canstencil = true;
@ -3642,7 +3543,7 @@ void Sh_CheckSettings(void)
{
//can't even do lighting
if (r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival)
Con_Printf("Missing driver extensions: realtime lighting is not possible.\n");
Con_Printf("Missing rendering features: realtime lighting is not possible.\n");
r_shadow_realtime_world.ival = 0;
r_shadow_realtime_dlight.ival = 0;
}
@ -3650,7 +3551,7 @@ void Sh_CheckSettings(void)
{
//no shadow methods available at all.
if ((r_shadow_realtime_world.ival&&r_shadow_realtime_world_shadows.ival)||(r_shadow_realtime_dlight.ival&&r_shadow_realtime_dlight_shadows.ival))
Con_Printf("Missing driver extensions: realtime shadows are not possible.\n");
Con_Printf("Missing rendering features: realtime shadows are not possible.\n");
r_shadow_realtime_world_shadows.ival = 0;
r_shadow_realtime_dlight_shadows.ival = 0;
}
@ -3660,7 +3561,7 @@ void Sh_CheckSettings(void)
if (!!r_shadow_shadowmapping.ival != cansmap)
{
if (r_shadow_shadowmapping.ival && ((r_shadow_realtime_world.ival&&r_shadow_realtime_world_shadows.ival)||(r_shadow_realtime_dlight.ival&&r_shadow_realtime_dlight_shadows.ival)))
Con_Printf("Missing driver extensions: forcing shadowmapping %s.\n", cansmap?"on":"off");
Con_Printf("Missing rendering features: forcing shadowmapping %s.\n", cansmap?"on":"off");
r_shadow_shadowmapping.ival = cansmap;
}
}

View File

@ -16,7 +16,7 @@ void (APIENTRY *qglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset
void (APIENTRY *qglCullFace) (GLenum mode);
void (APIENTRY *qglDepthFunc) (GLenum func);
void (APIENTRY *qglDepthMask) (GLboolean flag);
void (APIENTRY *qglDepthRangef) (GLclampf zNear, GLclampf zFar);
//void (APIENTRY *qglDepthRangef) (GLclampf zNear, GLclampf zFar);
void (APIENTRY *qglDisable) (GLenum cap);
void (APIENTRY *qglEnable) (GLenum cap);
void (APIENTRY *qglFinish) (void);
@ -122,7 +122,7 @@ void (APIENTRY *qglColor4f) (GLfloat red, GLfloat green, GLfloat blue, GLfloat a
void (APIENTRY *qglColor4fv) (const GLfloat *v);
//void (APIENTRY *qglColor4ub) (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
//void (APIENTRY *qglColor4ubv) (const GLubyte *v);
void (APIENTRY *qglDepthRange) (GLclampd zNear, GLclampd zFar);
//void (APIENTRY *qglDepthRange) (GLclampd zNear, GLclampd zFar);
void (APIENTRY *qglDrawBuffer) (GLenum mode);
void (APIENTRY *qglDrawPixels) (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
void (APIENTRY *qglEnd) (void);
@ -885,7 +885,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
#ifdef GL_STATIC
gl_config.arb_shader_objects = true;
#else
if (Cvar_Get("gl_blacklist_debug_glsl", "0", CVAR_RENDERERLATCH, "gl blacklists")->ival && !gl_config.nofixedfunc)
if (Cvar_Get("gl_blacklist_debug_glsl", "0", CVAR_VIDEOLATCH, "gl blacklists")->ival && !gl_config.nofixedfunc)
{
Con_Printf(CON_NOTICE "GLSL disabled\n");
gl_config.arb_shader_objects = false;
@ -925,7 +925,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
// glslang
//the gf2 to gf4 cards emulate vertex_shader and thus supports shader_objects.
//but our code kinda requires both for clean workings.
else if (strstr(gl_renderer, " Mesa ") && (gl_config.glversion < 3 || gl_config.gles) && Cvar_Get("gl_blacklist_mesa_glsl", "1", CVAR_RENDERERLATCH, "gl blacklists")->ival)
else if (strstr(gl_renderer, " Mesa ") && (gl_config.glversion < 3 || gl_config.gles) && Cvar_Get("gl_blacklist_mesa_glsl", "1", CVAR_VIDEOLATCH, "gl blacklists")->ival)
{
//(9:12:33 PM) bigfoot: Spike, can you please blacklist your menu shader on Mesa? My machine just hard locked up again because I forgot that pressing escape in FTE is verboten
//(11:51:42 PM) bigfoot: OpenGL vendor string: Tungsten Graphics, Inc
@ -1265,9 +1265,13 @@ static const char *glsl_hdrs[] =
"attribute vec4 v_colour4;"
#endif
"\n#endif\n"
#ifdef SHADOWDBG_COLOURNOTDEPTH
"#define sampler2DShadow sampler2D\n"
#else
"#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#endif\n"
#endif
"#ifndef SPECEXP\n"
"#define SPECEXP 1.0\n"
"#endif\n"
@ -1706,7 +1710,10 @@ static const char *glsl_hdrs[] =
"#ifdef SPOT\n"
//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.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"
"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"
//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, 0.0)) * vec3(0.5, 0.5, 1.0);\n"
//"#elif defined(CUBESHADOW)\n"
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r
@ -1751,7 +1758,10 @@ static const char *glsl_hdrs[] =
"float ShadowmapFilter(sampler2DShadow smap, vec4 cubeproj)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord(cubeproj);\n"
#ifdef SHADOWDBG_COLOURNOTDEPTH
//just r, unfortunately. oh well.
"return texture2D(smap, shadowcoord.xy + (vec2(0.0,0.0)*l_shadowmapscale.xy)).r;\n"
#else
"#if 0\n"//def GL_ARB_texture_gather
"vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(smap, ipart.xy, vec2(x,y)))\n"
@ -1796,6 +1806,7 @@ static const char *glsl_hdrs[] =
"return s/9.0;\n"
"#endif\n"
"#endif\n"
#endif
"}\n"
"#endif\n"
,
@ -2701,7 +2712,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
qglCullFace = (void *)getglcore("glCullFace");
qglDepthFunc = (void *)getglcore("glDepthFunc");
qglDepthMask = (void *)getglcore("glDepthMask");
qglDepthRangef = (void *)getglcore("glDepthRangef");
// qglDepthRangef = (void *)getglcore("glDepthRangef");
qglDisable = (void *)getglcore("glDisable");
qglEnable = (void *)getglcore("glEnable");
qglFinish = (void *)getglcore("glFinish");
@ -2743,7 +2754,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
qglColor4fv = GL_Color4fv_Emul; //can be missing in gles1
// qglColor4ub = (void *)getglcore("glColor4ub");
// qglColor4ubv = (void *)getglcore("glColor4ubv");
qglDepthRange = (void *)getglcore("glDepthRange");
// qglDepthRange = (void *)getglcore("glDepthRange");
qglDrawBuffer = (void *)getglcore("glDrawBuffer");
qglDrawPixels = (void *)getglcore("glDrawPixels");
qglEnd = (void *)getglcore("glEnd");
@ -2846,7 +2857,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
qglLoadMatrixf = NULL;
qglPolygonMode = NULL;
qglShadeModel = NULL;
qglDepthRange = NULL;
// qglDepthRange = NULL;
qglDrawBuffer = NULL;
qglEnableClientState = GL_ClientStateStub;
@ -2859,7 +2870,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
qglLoadMatrixf = NULL;
qglPolygonMode = NULL;
qglShadeModel = NULL;
qglDepthRange = NULL;
// qglDepthRange = NULL;
qglDrawBuffer = NULL;
qglEnableClientState = GL_ClientStateStub;

View File

@ -168,7 +168,7 @@ qboolean R_DrawSkyChain (batch_t *batch)
}
else if (skyshader->numpasses)
{ //if we have passes, then they're normally projected.
if (*r_fastsky.string && TEXVALID(batch->shader->defaulttextures->base) && TEXVALID(batch->shader->defaulttextures->fullbright))
if (*r_fastsky.string && skyshader->numpasses == 2 && TEXVALID(batch->shader->defaulttextures->base) && TEXVALID(batch->shader->defaulttextures->fullbright))
{ //we have a small perf trick to accelerate q1 skies, also helps avoids distortions, but doesn't work too well for any other type of sky.
R_CalcSkyChainBounds(batch);
GL_DrawSkyGrid(skyshader->defaulttextures);

View File

@ -100,7 +100,8 @@ typedef struct
DEFORMV_BULGE,
DEFORMV_AUTOSPRITE,
DEFORMV_AUTOSPRITE2,
DEFORMV_PROJECTION_SHADOW
DEFORMV_PROJECTION_SHADOW,
DEFORMV_TEXT
} type;
float args[4];
shaderfunc_t func;
@ -538,10 +539,16 @@ typedef struct {
enum
{
LSHADER_STANDARD=0u, //stencil or shadowless
LSHADER_CUBE=1u<<0, //has a cubemap
LSHADER_SMAP=1u<<1, //filter based upon 6 directions of a shadowmap
LSHADER_CUBE=1u<<0, //has a cubemap filter (FIXME: use custom 2d filter on spot lights)
LSHADER_SMAP=1u<<1, //filter based upon a shadowmap instead of stencil/unlit
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
#else
LSHADER_ORTHO=0, //so bitmasks return false
LSHADER_MODES=1u<<3
#endif
};
enum
{
@ -645,6 +652,16 @@ struct shader_s
} *clutter;
bucket_t bucket;
//arranged as a series of vec4s
/* struct
{
float offsetmappingscale; //default 1
float offsetmappingbias; //default 0
float specularexpscale; //default 1*gl_specular_power
float specularvalscale; //default 1*gl_specular
} fragpushdata;
*/
};
extern unsigned int r_numshaders;
@ -810,6 +827,12 @@ int GLBE_FBO_Push(fbostate_t *state);
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);
void GLBE_EndShadowMap(int restorefbo);
void GLBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale);
#endif
#ifdef D3D8QUAKE
void D3D8BE_Init(void);
@ -888,6 +911,10 @@ void D3D11BE_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *e
void D3D11BE_VBO_Destroy(vboarray_t *vearray, void *mem);
void D3D11BE_Scissor(srect_t *rect);
qboolean D3D11_BeginShadowMap(int id, int w, int h);
void D3D11_EndShadowMap(void);
void D3D11BE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale);
enum
{ //these are the buffer indexes
D3D11_BUFF_POS,
@ -912,8 +939,6 @@ void GLBE_PolyOffsetStencilShadow(qboolean foobar);
#else
void GLBE_PolyOffsetStencilShadow(void);
#endif
//sets up gl for depth-only FIXME
int GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale);
//Called from shadowmapping code into backend
void GLBE_BaseEntTextures(void);
void D3D9BE_BaseEntTextures(void);

View File

@ -2,7 +2,7 @@ COMMON_OBJS=comprout.o hash.o qcc_cmdlib.o qcd_main.o
QCC_OBJS=qccmain.o qcc_pr_comp.o qcc_pr_lex.o
VM_OBJS=pr_exec.o pr_edict.o pr_multi.o initlib.o qcdecomp.o
GTKGUI_OBJS=qcc_gtk.o qccguistuff.o
WIN32GUI_OBJS=qccgui.o qccguistuff.o
WIN32GUI_OBJS=qccgui.o qccguistuff.o packager.o
TUI_OBJS=qcctui.o
LIB_OBJS=
@ -75,6 +75,9 @@ qcd_main.o: qcd_main.c qcc.h
qccguistuff.o: qccguistuff.c qcc.h
$(DO_CC)
packager.o: qccguistuff.c qcc.h
$(DO_CC)
qcc_gtk.o: qcc_gtk.c qcc.h
$(DO_CC) `pkg-config --cflags gtk+-2.0`

View File

@ -5,11 +5,14 @@ void EditFile(const char *name, int line, pbool setcontrol);
void GUI_SetDefaultOpts(void);
int GUI_BuildParms(char *args, char **argv, pbool quick);
unsigned char *PDECL QCC_ReadFile (const char *fname, void *buffer, int len, size_t *sz);
//unsigned char *PDECL QCC_ReadFile (const char *fname, void *buffer, int len, size_t *sz);
int QCC_RawFileSize (const char *fname);
pbool QCC_WriteFile (const char *name, void *data, int len);
void GUI_DialogPrint(char *title, char *text);
void *GUIReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size);
int GUIFileSize(const char *fname);
void GUI_ParseCommandLine(char *args);
void GUI_SaveConfig(void);
void GUI_RevealOptions(void);

1387
engine/qclib/packager.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2499,6 +2499,10 @@ void PR_CleanUpStatements32(progfuncs_t *progfuncs, dstatement32_t *st, pbool he
}
char *decode(int complen, int len, int method, char *info, char *buffer);
unsigned char *PR_GetHeapBuffer (void *ctx, size_t bufsize)
{
return PRHunkAlloc(ctx, bufsize+1, "proginfo");
}
/*
===============
PR_LoadProgs
@ -2509,7 +2513,7 @@ int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_
unsigned int i, j, type;
// extensionbuiltin_t *eb;
// float fl;
int len;
// int len;
// int num;
// dfunction_t *f, *f2;
ddef16_t *d16;
@ -2528,6 +2532,7 @@ int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_
mfunction_t *fnc2;
dstatement16_t *st16;
size_t fsz;
int len;
int hmark=0xffffffff;
@ -2558,7 +2563,9 @@ int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_
// CRC_Init (&pr_crc);
retry:
if ((len=externs->FileSize(filename))<=0)
hmark = PRHunkMark(progfuncs);
pr_progs = externs->ReadFile(filename, PR_GetHeapBuffer, progfuncs, &fsz);
if (!pr_progs)
{
if (externs->autocompile == PR_COMPILENEXIST || externs->autocompile == PR_COMPILECHANGED) //compile if file is not found (if 2, we have already tried, so don't bother)
{
@ -2567,7 +2574,8 @@ retry:
printf("couldn't open progs %s. Attempting to compile.\n", filename);
CompileFile(progfuncs, filename);
}
if ((len=externs->FileSize(filename))<0)
pr_progs = externs->ReadFile(filename, PR_GetHeapBuffer, progfuncs, &fsz);
if (!pr_progs)
{
printf("Couldn't find or compile file %s\n", filename);
return false;
@ -2582,16 +2590,6 @@ retry:
}
}
hmark = PRHunkMark(progfuncs);
pr_progs = PRHunkAlloc(progfuncs, len+1, "proginfo");
if (!externs->ReadFile(filename, pr_progs, len+1, &fsz))
{
if (!complain)
return false;
printf("Failed to open %s", filename);
return false;
}
// for (i=0 ; i<len ; i++)
// CRC_ProcessByte (&pr_crc, ((byte *)pr_progs)[i]);
@ -2823,24 +2821,21 @@ retry:
strcpy(lnoname, filename);
StripExtension(lnoname);
strcat(lnoname, ".lno");
if ((len=externs->FileSize(lnoname))>0)
file = externs->ReadFile(lnoname, PR_GetHeapBuffer, progfuncs, &fsz);
if (file)
{
file = PRHunkAlloc(progfuncs, len+1, "line numbers");
if (externs->ReadFile(lnoname, file, len+1, &fsz))
if ( file[0] != lnotype
|| file[1] != version
|| file[2] != pr_progs->numglobaldefs
|| file[3] != pr_progs->numglobals
|| file[4] != pr_progs->numfielddefs
|| file[5] != pr_progs->numstatements
)
{
if ( file[0] != lnotype
|| file[1] != version
|| file[2] != pr_progs->numglobaldefs
|| file[3] != pr_progs->numglobals
|| file[4] != pr_progs->numfielddefs
|| file[5] != pr_progs->numstatements
)
{
PRHunkFree(progfuncs, ohm); //whoops: old progs or incompatible
}
else
pr_linenums = file + 6;
PRHunkFree(progfuncs, ohm); //whoops: old progs or incompatible
}
else
pr_linenums = file + 6;
}
}
@ -3171,7 +3166,7 @@ retry:
case OP_ADDRESS:
if (st[i+1].op == OP_STOREP_V && st[i+1].b == st[i].c)
{ //following stores a vector to this field.
if (st[i].b+2 < pr_progs->numglobals)
if (st[i].b+2u < pr_progs->numglobals)
{ //vectors are usually 3 fields. if they're not then we're screwed.
basictypetable[st[i].b+0] = ev_field;
basictypetable[st[i].b+1] = ev_field;
@ -3191,7 +3186,7 @@ retry:
basictypetable[st[i].b] = ev_field;
break;
case OP_LOAD_V:
if (st[i].b+2 < pr_progs->numglobals)
if (st[i].b+2u < pr_progs->numglobals)
{ //vectors are usually 3 fields. if they're not then we're screwed.
basictypetable[st[i].b+0] = ev_field;
basictypetable[st[i].b+1] = ev_field;

View File

@ -480,22 +480,10 @@ Returns the new program statement counter
int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsnum)
{
int i, j, c, o;
prstack_t *st;
pr_stack[pr_depth].s = pr_xstatement;
pr_stack[pr_depth].f = pr_xfunction;
pr_stack[pr_depth].progsnum = progsnum;
pr_stack[pr_depth].pushed = prinst.spushed;
pr_stack[pr_depth].stepping = progfuncs->funcs.debug_trace;
if (progfuncs->funcs.debug_trace == DEBUG_TRACE_OVER)
progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF;
if (prinst.profiling)
{
pr_stack[pr_depth].timestamp = Sys_GetClock();
}
pr_depth++;
if (pr_depth == MAX_STACK_DEPTH)
{
pr_depth--;
PR_StackTrace (&progfuncs->funcs, false);
printf ("stack overflow on call to %s (depth %i)\n", progfuncs->funcs.stringtable+f->s_name, pr_depth);
@ -505,6 +493,18 @@ int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsn
externs->Abort("Stack Overflow in %s\n", progfuncs->funcs.stringtable+f->s_name);
return pr_xstatement;
}
st = &pr_stack[pr_depth++];
st->s = pr_xstatement;
st->f = pr_xfunction;
st->progsnum = progsnum;
st->pushed = prinst.spushed;
st->stepping = progfuncs->funcs.debug_trace;
if (progfuncs->funcs.debug_trace == DEBUG_TRACE_OVER)
progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF;
if (prinst.profiling)
{
st->timestamp = Sys_GetClock();
}
prinst.localstack_used += prinst.spushed; //make sure the call doesn't hurt pushed pointers
@ -544,10 +544,14 @@ PR_LeaveFunction
int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs)
{
int i, c;
prstack_t *st;
if (pr_depth <= 0)
Sys_Error ("prog stack underflow");
// up stack
st = &pr_stack[--pr_depth];
// restore locals from the stack
c = pr_xfunction->locals;
prinst.localstack_used -= c;
@ -557,31 +561,28 @@ int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs)
for (i=0 ; i < c ; i++)
((int *)pr_globals)[pr_xfunction->parm_start + i] = prinst.localstack[prinst.localstack_used+i];
// up stack
pr_depth--;
PR_SwitchProgsParms(progfuncs, pr_stack[pr_depth].progsnum);
prinst.spushed = pr_stack[pr_depth].pushed;
PR_SwitchProgsParms(progfuncs, st->progsnum);
prinst.spushed = st->pushed;
if (!progfuncs->funcs.debug_trace)
progfuncs->funcs.debug_trace = pr_stack[pr_depth].stepping;
progfuncs->funcs.debug_trace = st->stepping;
if (prinst.profiling)
{
prclocks_t cycles;
cycles = Sys_GetClock() - pr_stack[pr_depth].timestamp;
cycles = Sys_GetClock() - st->timestamp;
if (cycles > prinst.profilingalert)
printf("QC call to %s took over a second\n", PR_StringToNative(&progfuncs->funcs,pr_xfunction->s_name));
pr_xfunction->profiletime += cycles;
pr_xfunction = pr_stack[pr_depth].f;
pr_xfunction = st->f;
if (pr_depth)
pr_xfunction->profilechildtime += cycles;
}
else
pr_xfunction = pr_stack[pr_depth].f;
pr_xfunction = st->f;
prinst.localstack_used -= prinst.spushed;
return pr_stack[pr_depth].s;
return st->s;
}
ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, char *name, eval_t **val)
@ -1307,7 +1308,7 @@ static const char *lastfile = 0;
lastfile = PR_StringToNative(&progfuncs->funcs, f->s_file);
faultline = lastline;
debugaction = externs->useeditor(&progfuncs->funcs, lastfile, ((lastline>0)?&lastline:NULL), &statement, fault, fatal);
debugaction = externs->useeditor(&progfuncs->funcs, lastfile, ((lastline!=-1)?&lastline:NULL), &statement, fault, fatal);
//if they changed the line to execute, we need to find a statement that is on that line
if (lastline && faultline != lastline)
@ -1797,7 +1798,7 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
}
//forget about any tracing if its active. control returning to the engine should not look like its calling some random function.
progfuncs->funcs.debug_trace = 0;
progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF;
// make a stack frame
prinst.exitdepth = pr_depth;

View File

@ -201,7 +201,7 @@ struct pubprogfuncs_s
typedef struct progexterns_s {
int progsversion; //PROGSTRUCT_VERSION
unsigned char *(PDECL *ReadFile) (const char *fname, void *buffer, int len, size_t *sz);
void *(PDECL *ReadFile) (const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size);
int (PDECL *FileSize) (const char *fname); //-1 if file does not exist
pbool (PDECL *WriteFile) (const char *name, void *data, int len);
int (VARGS *Printf) (const char *, ...) LIKEPRINTF(1);

View File

@ -738,6 +738,7 @@ enum {
WARN_UNEXPECTEDPUNCT,
WARN_UNINITIALIZED,
WARN_DENORMAL,
WARN_STRINGOFFSET, //works for static/memalloc strings, but fundamentally unsafe on tempstrings/etc, and varies between engine
WARN_OVERFLOW, //compile time overflow or inprecision.
WARN_ASSIGNMENTTOCONSTANT,
WARN_ASSIGNMENTTOCONSTANTFUNC,
@ -1105,6 +1106,11 @@ extern qcc_cachedsourcefile_t *qcc_sourcefile;
int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell, pbool legacyembed);
struct pkgctx_s;
struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message), void *userctx);
void Packager_Parse(struct pkgctx_s *ctx, char *scriptname);
void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname);
void Packager_Destroy(struct pkgctx_s *ctx);

View File

@ -826,8 +826,8 @@ long ParseNum (char *str)
#define MAXQCCFILES 3
struct {
char name[64];
FILE *stdio;
char *buff;
// int buffismalloc;
int buffsize;
int ofs;
int maxofs;
@ -842,20 +842,23 @@ int SafeOpenWrite (char *filename, int maxsize)
}
for (i = 0; i < MAXQCCFILES; i++)
{
if (!qccfile[i].buff)
if (!qccfile[i].stdio && !qccfile[i].buff)
{
strcpy(qccfile[i].name, filename);
qccfile[i].buffsize = maxsize;
qccfile[i].maxofs = 0;
qccfile[i].ofs = 0;
// if (maxsize > 8192)
// qccfile[i].buffismalloc = 1;
// else
// qccfile[i].buffismalloc = 0;
// if (qccfile[i].buffismalloc)
qccfile[i].stdio = NULL;
qccfile[i].buff = NULL;
if (maxsize < 0)
qccfile[i].stdio = fopen(filename, "wb");
else
qccfile[i].buff = malloc(qccfile[i].buffsize);
// else
// qccfile[i].buff = memalloc(qccfile[i].buffsize);
if (!qccfile[i].stdio && !qccfile[i].buff)
{
QCC_Error(ERR_TOOMANYOPENFILES, "Unable to open %s", filename);
return -1;
}
return i;
}
}
@ -865,28 +868,14 @@ int SafeOpenWrite (char *filename, int maxsize)
void ResizeBuf(int hand, int newsize)
{
// int wasmal = qccfile[hand].buffismalloc;
char *nb;
if (qccfile[hand].buffsize >= newsize)
return; //already big enough
// if (newsize > 8192)
// {
// qccfile[hand].buffismalloc = true;
nb = malloc(newsize);
// }
// else
// {
// qccfile[hand].buffismalloc = false;
// nb = memalloc(newsize);
// }
nb = malloc(newsize);
memcpy(nb, qccfile[hand].buff, qccfile[hand].maxofs);
// if (wasmal)
free(qccfile[hand].buff);
// else
// externs->memfree(qccfile[hand].buff);
free(qccfile[hand].buff);
qccfile[hand].buff = nb;
qccfile[hand].buffsize = newsize;
}
@ -917,12 +906,15 @@ pbool SafeClose(int hand)
{
progfuncs_t *progfuncs = qccprogfuncs;
pbool ret;
ret = externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
// if (qccfile[hand].buffismalloc)
if (qccfile[hand].stdio)
ret = 0==fclose(qccfile[hand].stdio);
else
{
ret = externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
free(qccfile[hand].buff);
// else
// externs->memfree(qccfile[hand].buff);
}
qccfile[hand].buff = NULL;
qccfile[hand].stdio = NULL;
return ret;
}
@ -1146,7 +1138,7 @@ unsigned short *QCC_makeutf16(char *mem, unsigned int len, int *outlen, pbool *e
//input is a raw file (will not be changed
//output is utf-8 data
char *QCC_SanitizeCharSet(char *mem, unsigned int *len, pbool *freeresult, int *origfmt)
char *QCC_SanitizeCharSet(char *mem, size_t *len, pbool *freeresult, int *origfmt)
{
if (freeresult)
*freeresult = true;
@ -1216,32 +1208,29 @@ char *QCC_SanitizeCharSet(char *mem, unsigned int *len, pbool *freeresult, int *
return mem;
}
static unsigned char *QCC_LoadFileHunk(void *ctx, size_t size)
{ //2 ensures we can always put a \n in there.
return (unsigned char*)qccHunkAlloc(sizeof(qcc_cachedsourcefile_t)+size+2) + sizeof(qcc_cachedsourcefile_t);
}
long QCC_LoadFile (char *filename, void **bufferptr)
{
qcc_cachedsourcefile_t *sfile;
progfuncs_t *progfuncs = qccprogfuncs;
char *mem;
int check;
int flen;
unsigned int len;
size_t len;
int line;
int orig;
pbool warned = false;
flen = externs->FileSize(filename);
if (flen < 0)
mem = externs->ReadFile(filename, QCC_LoadFileHunk, NULL, &len);
if (!mem)
{
QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename);
// if (!externs->Abort)
return -1;
// externs->Abort("failed to find file %s", filename);
return -1;
}
len = flen;
mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+2);
((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile;
qcc_sourcefile = (qcc_cachedsourcefile_t*)mem;
mem += sizeof(qcc_cachedsourcefile_t);
externs->ReadFile(filename, mem, len+2, NULL);
sfile = (qcc_cachedsourcefile_t*)(mem-sizeof(qcc_cachedsourcefile_t));
mem[len] = 0;
mem = QCC_SanitizeCharSet(mem, &len, NULL, &orig);
@ -1267,10 +1256,12 @@ long QCC_LoadFile (char *filename, void **bufferptr)
mem[len] = '\n';
mem[len+1] = '\0';
strcpy(qcc_sourcefile->filename, filename);
qcc_sourcefile->size = len;
qcc_sourcefile->file = mem;
qcc_sourcefile->type = FT_CODE;
strcpy(sfile->filename, filename);
sfile->size = len;
sfile->file = mem;
sfile->type = FT_CODE;
sfile->next = qcc_sourcefile;
qcc_sourcefile = sfile;
*bufferptr=mem;
@ -1278,6 +1269,7 @@ long QCC_LoadFile (char *filename, void **bufferptr)
}
void QCC_AddFile (char *filename)
{
qcc_cachedsourcefile_t *sfile;
progfuncs_t *progfuncs = qccprogfuncs;
char *mem;
int len;
@ -1286,26 +1278,33 @@ void QCC_AddFile (char *filename)
externs->Abort("failed to find file %s", filename);
mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+1);
((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile;
qcc_sourcefile = (qcc_cachedsourcefile_t*)mem;
qcc_sourcefile->size = len;
mem += sizeof(qcc_cachedsourcefile_t);
strcpy(qcc_sourcefile->filename, filename);
qcc_sourcefile->file = mem;
qcc_sourcefile->type = FT_DATA;
externs->ReadFile(filename, mem, len+1, NULL);
mem = externs->ReadFile(filename, QCC_LoadFileHunk, NULL, &len);
if (!mem)
externs->Abort("failed to find file %s", filename);
sfile = (qcc_cachedsourcefile_t*)(mem-sizeof(qcc_cachedsourcefile_t));
mem[len] = '\0';
sfile->size = len;
strcpy(sfile->filename, filename);
sfile->file = mem;
sfile->type = FT_DATA;
sfile->next = qcc_sourcefile;
qcc_sourcefile = sfile;
}
void *FS_ReadToMem(char *filename, void *mem, int *len)
static unsigned char *FS_ReadToMem_Alloc(void *ctx, size_t size)
{
unsigned char *mem;
progfuncs_t *progfuncs = qccprogfuncs;
mem = externs->memalloc(size+1);
mem[size] = 0;
return mem;
}
void *FS_ReadToMem(char *filename, size_t *len)
{
progfuncs_t *progfuncs = qccprogfuncs;
if (!mem)
{
*len = externs->FileSize(filename);
mem = externs->memalloc(*len);
}
return externs->ReadFile(filename, mem, *len, NULL);
return externs->ReadFile(filename, FS_ReadToMem_Alloc, NULL, len);
}
void FS_CloseFromMem(void *mem)

View File

@ -3086,7 +3086,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
else
{
if (!var_a.sym->constant)
QCC_PR_ParseWarning(0, "OP_ADD_SF: string+float may be unsafe");
QCC_PR_ParseWarning(WARN_STRINGOFFSET, "OP_ADD_SF: string+float may be unsafe");
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_a, var_b, NULL, 0);
}
@ -3136,7 +3136,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
case OP_ADD_SI:
case OP_ADD_IS:
QCC_PR_ParseWarning(0, "OP_ADD_SI: string+int may be unsafe");
QCC_PR_ParseWarning(WARN_STRINGOFFSET, "OP_ADD_SI: string+int may be unsafe");
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_a, var_b, NULL, 0);
var_c.cast = type_string;
return var_c;

View File

@ -203,7 +203,7 @@ pbool QCC_PR_UnInclude(void)
return true;
}
static void QCC_Canonicalize(char *fullname, size_t fullnamesize, char *newfile, char *base)
void QCC_Canonicalize(char *fullname, size_t fullnamesize, const char *newfile, const char *base)
{
int doubledots;
char *end = fullname;
@ -224,6 +224,7 @@ static void QCC_Canonicalize(char *fullname, size_t fullnamesize, char *newfile,
break;
}
//FIXME: length validation!
if (base)
strcpy(fullname, base);
else

View File

@ -23,6 +23,7 @@ void OptionsDialog(void);
static void GUI_CreateInstaller_Windows(void);
static void GUI_CreateInstaller_Android(void);
static void SetProgsSrcFileAndPath(char *filename);
static void CreateOutputWindow(pbool doannoates);
void AddSourceFile(const char *parentsrc, const char *filename);
#ifndef TVM_SETBKCOLOR
@ -449,59 +450,57 @@ void QCC_EnumerateFilesResult(const char *name, const void *compdata, size_t com
LoadFile
==============
*/
unsigned char *PDECL QCC_ReadFile (const char *fname, void *buffer, int len, size_t *sz)
void *QCC_ReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size)
//unsigned char *PDECL QCC_ReadFile (const char *fname, void *buffer, int len, size_t *sz)
{
long length;
size_t len;
FILE *f;
char *buffer;
vfile_t *v = QCC_FindVFile(fname);
if (v)
{
if (!buffer)
{
len = v->fsize;
len = v->fsize;
if (buf_get)
buffer = buf_get(buf_ctx, len+1);
else
buffer = malloc(len+1);
((char*)buffer)[len] = 0;
}
if (!buffer)
return NULL;
((char*)buffer)[len] = 0;
if (len > v->fsize)
len = v->fsize;
memcpy(buffer, v->fdata, len);
if (sz)
*sz = len;
if (out_size)
*out_size = len;
return buffer;
}
f = fopen(fname, "rb");
if (!f)
{
if (sz)
*sz = 0;
if (out_size)
*out_size = 0;
return NULL;
}
if (!buffer)
{
fseek(f, 0, SEEK_END);
len = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(len+1);
((char*)buffer)[len] = 0;
length = fread(buffer, 1, len, f);
if (length != len)
{
free(buffer);
buffer = NULL;
}
}
fseek(f, 0, SEEK_END);
len = ftell(f);
fseek(f, 0, SEEK_SET);
if (buf_get)
buffer = buf_get(buf_ctx, len+1);
else
buffer = malloc(len+1);
((char*)buffer)[len] = 0;
if (len != fread(buffer, 1, len, f))
{
length = fread(buffer, 1, len, f);
if (length != len)
buffer = NULL;
if (!buf_get)
free(buffer);
buffer = NULL;
}
fclose(f);
if (sz)
*sz = length;
if (out_size)
*out_size = len;
return buffer;
}
int PDECL QCC_RawFileSize (const char *fname)
@ -1606,6 +1605,7 @@ enum {
IDM_ENCODING_WINDOWS,
IDM_CREATEINSTALLER_WINDOWS,
IDM_CREATEINSTALLER_ANDROID,
IDM_CREATEINSTALLER_PACKAGES,
IDI_O_LEVEL0,
IDI_O_LEVEL1,
@ -1650,6 +1650,8 @@ void QueryOpenFile(void)
SetCurrentDirectory(oldpath);
}
static void Packager_MessageCallback(void *ctx, const char *fmt, ...);
//IDM_ stuff that needs no active window
void GenericMenu(WPARAM wParam)
{
@ -1696,6 +1698,19 @@ void GenericMenu(WPARAM wParam)
case IDM_CREATEINSTALLER_ANDROID:
GUI_CreateInstaller_Android();
break;
case IDM_CREATEINSTALLER_PACKAGES:
{
struct pkgctx_s *ctx;
CreateOutputWindow(false);
GUIprintf("");
ctx = Packager_Create(Packager_MessageCallback, NULL);
Packager_Parse(ctx, "packages.src");
Packager_WriteDataset(ctx, NULL);
Packager_Destroy(ctx);
}
break;
case IDM_ABOUT:
#ifdef SVNVERSION
@ -2443,8 +2458,7 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell)
//indentbuf may contain spaces or tabs. preferably tabs.
static void scin_get_line_indent(HWND editpane, int lineidx, char *indentbuf, size_t sizeofbuf)
{
int i;
size_t len;
size_t i, len;
while (lineidx --> 0)
{
len = SendMessage(editpane, SCI_LINELENGTH, lineidx, 0);
@ -2891,7 +2905,7 @@ static void EditorReload(editor_t *editor)
char *file;
unsigned int flen;
pbool dofree;
rawfile = QCC_ReadFile(editor->filename, NULL, 0, &flensz);
rawfile = QCC_ReadFile(editor->filename, NULL, NULL, &flensz);
flen = flensz;
file = QCC_SanitizeCharSet(rawfile, &flen, &dofree, &editor->savefmt);
@ -3332,26 +3346,42 @@ void EditorsRun(void)
{
}
unsigned char *GUIReadFile(const char *fname, void *buffer, int blen, size_t *sz)
static unsigned char *buf_get_malloc(void *ctx, size_t len)
{
return malloc(len);
}
void *GUIReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size)
{
editor_t *e;
size_t blen;
unsigned char *buffer;
if (!buf_get)
buf_get = buf_get_malloc;
for (e = editors; e; e = e->next)
{
if (e->window && !strcmp(e->filename, fname))
{
// int elen = GetWindowTextLengthW(e->editpane);
//our qcc itself is fine with utf-16, so long as it has a BOM.
if (e->scintilla)
{
{ //take the opportunity to grab a predefined preprocessor list for this file
char *deflist = QCC_PR_GetDefinesList();
SendMessage(e->editpane, SCI_SETKEYWORDS, 4, (LPARAM)deflist);
free(deflist);
blen = SendMessage(e->editpane, SCI_GETLENGTH, 0, 0);
buffer = buf_get(buf_ctx, blen);
blen = SendMessage(e->editpane, SCI_GETTEXT, blen, (LPARAM)buffer);
}
else if (e->savefmt == UTF_ANSI)
{
blen = GetWindowTextLengthA(e->editpane);
buffer = buf_get(buf_ctx, blen);
GetWindowTextA(e->editpane, buffer, blen);
}
else
{
blen = (GetWindowTextLengthW(e->editpane)+1)*2;
buffer = buf_get(buf_ctx, blen);
*(wchar_t*)buffer = 0xfeff;
GetWindowTextW(e->editpane, (wchar_t*)buffer+1, blen-sizeof(wchar_t));
}
@ -3375,11 +3405,12 @@ unsigned char *GUIReadFile(const char *fname, void *buffer, int blen, size_t *sz
}
}
*out_size = blen;
return buffer;
}
}
return QCC_ReadFile(fname, buffer, blen, NULL);
return QCC_ReadFile(fname, buf_get, buf_ctx, out_size);
}
int GUIFileSize(const char *fname)
@ -3391,13 +3422,7 @@ int GUIFileSize(const char *fname)
{
int len;
if (e->scintilla)
{ //take the opportunity to grab a predefined preprocessor list for this file
char *deflist = QCC_PR_GetDefinesList();
SendMessage(e->editpane, SCI_SETKEYWORDS, 4, (LPARAM)deflist);
free(deflist);
len = SendMessage(e->editpane, SCI_GETLENGTH, 0, 0);
}
else if (e->savefmt == UTF_ANSI)
len = GetWindowTextLengthA(e->editpane);
else
@ -5827,6 +5852,7 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
AppendMenu(m, MF_SEPARATOR, 0, NULL);
AppendMenu(m, 0, IDM_CREATEINSTALLER_WINDOWS, "Create Windows Installer");
AppendMenu(m, 0, IDM_CREATEINSTALLER_ANDROID, "Create Android Installer");
AppendMenu(m, 0, IDM_CREATEINSTALLER_PACKAGES, "Create Packages");
AppendMenu(m, MF_SEPARATOR, 0, NULL);
AppendMenu(m, 0, IDM_QUIT, "Exit");
AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Navigation");
@ -6727,7 +6753,7 @@ void RunCompiler(char *args, pbool quick)
}
void CreateOutputWindow(pbool doannoates)
static void CreateOutputWindow(pbool doannoates)
{
gui_doannotates = doannoates;
@ -6925,6 +6951,17 @@ void UpdateFileList(void)
}
}
static void Packager_MessageCallback(void *ctx, const char *fmt, ...)
{
va_list va;
char message[1024];
va_start (va, fmt);
vsnprintf (message, sizeof(message)-1, fmt, va);
va_end (va);
outlen = GUIEmitOutputText(outputbox, outlen, message, strlen(message), RGB(0, 0, 0));
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
pbool fl_acc;

View File

@ -19,27 +19,24 @@ char enginebinary[MAX_PATH];
char enginebasedir[MAX_PATH];
char enginecommandline[8192];
char *GUIReadFile(const char *fname, void *buffer, int blen, size_t *sz);
int GUIFileSize(const char *fname);
int qccpersisthunk = 1;
int Grep(char *filename, char *string)
{
int foundcount = 0;
char *last, *found, *linestart;
int line = 1;
int sz;
size_t sz;
char *raw, *buf;
pbool dofree;
int origfmt;
if (!filename)
return foundcount;
sz = GUIFileSize(filename);
if (sz <= 0)
raw = GUIReadFile(filename, NULL, NULL, &sz);
if (!raw)
return foundcount;
raw = malloc(sz+2);
raw[sz] = 0;
GUIReadFile(filename, raw, sz, NULL);
if (raw[sz] != 0)
return foundcount; //error....
buf = QCC_SanitizeCharSet(raw, &sz, &dofree, &origfmt);

View File

@ -40,7 +40,7 @@ extern int qccpersisthunk;
pbool QCC_PR_SimpleGetToken (void);
void QCC_PR_LexWhitespace (pbool inhibitpreprocessor);
void *FS_ReadToMem(char *fname, void *membuf, int *len);
void *FS_ReadToMem(char *fname, size_t *len);
void FS_CloseFromMem(void *mem);
unsigned int MAX_REGS;
@ -717,7 +717,6 @@ void QCC_PrintFiles (void)
}
}
int encode(int len, int method, char *in, int handle);
int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell, pbool legacyembed)
{
//helpers to deal with misaligned data. writes little-endian.
@ -1643,6 +1642,8 @@ pbool QCC_WriteData (int crc)
break;
default:
Sys_Error("structtype error");
funcdata = NULL;
funcdatasize = 0;
}
for (dupewarncount = 0, def = pr.def_head.next ; def ; def = def->next)
@ -2747,6 +2748,11 @@ static void QCC_MergeGlobalDefs16(ddef16_t *in, size_t num, void *values, size_t
QCC_FreeDef(root);
}
static unsigned char *QCC_LoadFileHunkAlloc(void *ctx, size_t size)
{
return (unsigned char*)qccHunkAlloc(size+1);
}
/*load a progs into the current compile state.*/
void QCC_ImportProgs(const char *filename)
{
@ -2770,21 +2776,17 @@ void QCC_ImportProgs(const char *filename)
if (numpr_globals != RESERVED_OFS) //not normally changed until after compiling
QCC_Error(ERR_BADEXTENSION, "#merge used too late. It must be used before any other definitions (regs).");
flen = externs->FileSize(filename);
if (flen < 0)
{
QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename);
return;
}
printf ("\nnote: The #merge feature is still experimental\n\n");
//FIXME: find overlapped locals. strip them. merge with new ones.
//FIXME: find temps. strip them. you get the idea.
//FIXME: find immediates. set up hash tables for them for reuse. HAH!
prog = qccHunkAlloc(flen);
externs->ReadFile(filename, prog, flen, NULL);
prog = externs->ReadFile(filename, QCC_LoadFileHunkAlloc, NULL, &flen);
if (!prog)
{
QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename);
return;
}
if (prog->version == 7 && prog->secondaryversion == PROG_SECONDARYVERSION16 && !prog->blockscompressed && !prog->numtypes)
;
@ -3693,7 +3695,7 @@ void QCC_PackFile (char *src, char *name)
QCC_Error (ERR_TOOMANYPAKFILES, "Too many files in pak file");
#if 1
f = FS_ReadToMem(src, NULL, &remaining);
f = FS_ReadToMem(src, &remaining);
if (!f)
{
printf ("%64s : %7s\n", name, "");
@ -4665,14 +4667,9 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine
strcpy(destfile, "");
compressoutput = 0;
p = externs->FileSize("qcc.cfg");
// if (p < 0)
// p = externs->FileSize("src/qcc.cfg");
if (p>0)
s = externs->ReadFile("qcc.cfg", QCC_LoadFileHunkAlloc, NULL, &p);
if (s)
{
s = qccHunkAlloc(p+1);
s = (char*)externs->ReadFile("qcc.cfg", s, p, NULL);
while(1)
{
s = QCC_COM_Parse(s);

View File

@ -2,8 +2,10 @@
#include "qcc.h"
#if !defined(NO_ZLIB) && !defined(FTE_TARGET_WEB) && !defined(NACL) && !defined(_XBOX)
#ifndef AVAIL_ZLIB
#define AVAIL_ZLIB
#endif
#endif
#ifdef AVAIL_ZLIB
#ifdef _WIN32

View File

@ -622,12 +622,41 @@ pbool PDECL PR_SSQC_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc
return false;
return true;
}
static void *PDECL SSQC_PRReadFile (const char *path, qbyte *(PDECL *buf_get)(void *buf_ctx, size_t size), void *buf_ctx, size_t *size)
{
flocation_t loc;
if (FS_FLocateFile(path, FSLF_IFFOUND, &loc))
{
qbyte *buffer = NULL;
vfsfile_t *file = FS_OpenReadLocation(&loc);
if (file)
{
*size = loc.len;
buffer = buf_get(buf_ctx, *size);
if (buffer)
VFS_READ(file, buffer, *size);
VFS_CLOSE(file);
}
return buffer;
}
else
return NULL;
}
static int PDECL SSQC_PRFileSize (const char *path)
{
flocation_t loc;
if (FS_FLocateFile(path, FSLF_IFFOUND, &loc))
return loc.len;
else
return -1;
}
void Q_SetProgsParms(qboolean forcompiler)
{
progstype = PROG_NONE;
svprogparms.progsversion = PROGSTRUCT_VERSION;
svprogparms.ReadFile = COM_LoadStackFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
svprogparms.FileSize = COM_FileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
svprogparms.ReadFile = SSQC_PRReadFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
svprogparms.FileSize = SSQC_PRFileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
svprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
svprogparms.Printf = PR_Printf;//Con_Printf;//void (*printf) (char *, ...);
svprogparms.DPrintf = PR_DPrintf;//Con_Printf;//void (*printf) (char *, ...);
@ -2297,14 +2326,16 @@ qboolean PR_ConsoleCmd(const char *command)
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
if (gfuncs.ConsoleCmd)
{
if (sv_redirected != RD_OBLIVION)
{
pr_global_struct->time = sv.world.physicstime;
int oself = pr_global_struct->self;
pr_global_struct->time = sv.world.physicstime;
if (sv_redirected == RD_CLIENT)
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, host_client->edict);
else
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts);
}
G_INT(OFS_PARM0) = PR_TempString(svprogfuncs, command);
PR_ExecuteProgram (svprogfuncs, gfuncs.ConsoleCmd);
pr_global_struct->self = oself;
return (int) G_FLOAT(OFS_RETURN);
}
}
@ -10505,12 +10536,16 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
// {"readsingleentitystate",PF_Fixme,0, 0, 0, 370},
{"deltalisten", PF_Fixme, 0, 0, 0, 371, D("float(string modelname, float(float isnew) updatecallback, float flags)", "Specifies a per-modelindex callback to listen for engine-networking entity updates. Such entities are automatically interpolated by the engine (unless flags specifies not to).\nThe various standard entity fields will be overwritten each frame before the updatecallback function is called.")},// (EXT_CSQC_1)
{"dynamiclight_spawnstatic",PF_Fixme,0, 0, 0, 0, D("float(vector org, float radius, vector rgb)", "Retrieves a property from the given dynamic/rt light. Return type depends upon the light field requested.")},
{"dynamiclight_get",PF_Fixme, 0, 0, 0, 372, D("__variant(float lno, float fld)", "Retrieves a property from the given dynamic/rt light. Return type depends upon the light field requested.")},
{"dynamiclight_set",PF_Fixme, 0, 0, 0, 373, D("void(float lno, float fld, __variant value)", "Changes a property on the given dynamic/rt light. Value type depends upon the light field to be changed.")},
{"particleeffectquery",PF_Fixme,0, 0, 0, 374, D("string(float efnum, float body)", "Retrieves either the name or the body of the effect with the given number. The effect body is regenerated from internal state, and can be changed before being reapplied via the localcmd builtin.")},
{"adddecal", PF_Fixme, 0, 0, 0, 375, D("void(string shadername, vector origin, vector up, vector side, vector rgb, float alpha)", "Adds a temporary clipped decal shader to the scene, centered at the given point with given orientation. Will be drawn by the next renderscene call, and freed by the next clearscene call.")},
{"setcustomskin", PF_Fixme, 0, 0, 0, 376, D("void(entity e, string skinfilename, optional string skindata)", "Sets an entity's skin overrides. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format:\nsurfacename,shadername - makes the named surface use the named shader\nreplace \"surfacename\" \"shadername\" - same.\nqwskin \"foo\" - use an unmodified quakeworld player skin (including crop+repalette rules)\nq1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red\nq1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue\ncompose \"surfacename\" \"shader\" \"imagename@x,y:w,h$s,t,s2,t2?r,g,b,a\" - compose a skin texture from multiple images.\n The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.\n Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader).")},
{"setcustomskin", PF_Fixme, 0, 0, 0, 376, D("void(entity e, string skinfilename, optional string skindata)", "Sets an entity's skin overrides to a new skin object. Releases the entities old skin (refcounted).")},
{"loadcustomskin", PF_Fixme, 0, 0, 0, 377, D("float(string skinfilename, optional string skindata)", "Creates a new skin object and returns it. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format:\nsurfacename,shadername - makes the named surface use the named shader\nreplace \"surfacename\" \"shadername\" - same.\nqwskin \"foo\" - use an unmodified quakeworld player skin (including crop+repalette rules)\nq1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red\nq1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue\ncompose \"surfacename\" \"shader\" \"imagename@x,y:w,h$s,t,s2,t2?r,g,b,a\" - compose a skin texture from multiple images.\n The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.\n Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). Must be matched with a releasecustomskin call later, and is pointless without applycustomskin.")},
{"applycustomskin", PF_Fixme, 0, 0, 0, 378, D("void(entity e, float skinobj)", "Updates the entity's custom skin (refcounted).")},
{"releasecustomskin",PF_Fixme, 0, 0, 0, 379, D("void(float skinobj)", "Lets the engine know that the skin will no longer be needed. Thanks to refcounting any ents with the skin already applied will retain their skin until later changed. It is valid to destroy a skin just after applying it to an ent in the same function that it was created in, as the skin will only be destroyed once its refcount rops to 0.")},
//END EXT_CSQC
{"memalloc", PF_memalloc, 0, 0, 0, 384, D("__variant*(int size)", "Allocate an arbitary block of memory")},
@ -12058,6 +12093,11 @@ void PR_DumpPlatform_f(void)
{"LFLAG_NOSHADOWS", "const float", CS, NULL, LFLAG_NOSHADOWS},
{"LFLAG_SHADOWMAP", "const float", CS, NULL, LFLAG_SHADOWMAP},
{"LFLAG_CREPUSCULAR", "const float", CS, NULL, LFLAG_CREPUSCULAR},
#ifdef LFLAG_ORTHO
{"LFLAG_ORTHOSUN", "const float", CS, NULL, LFLAG_ORTHO},
#else
{"LFLAG_ORTHOSUN", "const float", CS, NULL, 0},
#endif
#ifdef TERRAIN
{"TEREDIT_RELOAD", "const float", CS, NULL, ter_reload},

View File

@ -488,20 +488,31 @@ void SV_Map_f (void)
}
#endif
if (Cmd_Argc() != 2 && Cmd_Argc() != 3)
if (!Q_strcasecmp(Cmd_Argv(0), "map_restart"))
{
if (Cmd_IsInsecure())
return;
Con_TPrintf ("Available maps:\n", Cmd_Argv(0));
SV_MapList_f();
return;
float delay = atof(Cmd_Argv(1));
if (delay)
Con_DPrintf ("map_restart delay not implemented yet\n");
Q_strncpyz (level, ".", sizeof(level));
startspot = NULL;
//FIXME: if precaches+statics don't change, don't do the whole networking thing.
}
else
{
sv.mapchangelocked = false;
if (Cmd_Argc() != 2 && Cmd_Argc() != 3)
{
if (Cmd_IsInsecure())
return;
Con_TPrintf ("Available maps:\n", Cmd_Argv(0));
SV_MapList_f();
return;
}
Q_strncpyz (level, Cmd_Argv(1), sizeof(level));
startspot = ((Cmd_Argc() == 2)?NULL:Cmd_Argv(2));
Q_strncpyz (level, Cmd_Argv(1), sizeof(level));
startspot = ((Cmd_Argc() == 2)?NULL:Cmd_Argv(2));
}
q2savetos0 = !strcmp(Cmd_Argv(0), "gamemap") && !isDedicated; //q2
#ifdef Q3SERVER
@ -510,6 +521,8 @@ void SV_Map_f (void)
flushparms = !strcmp(Cmd_Argv(0), "map") || !strcmp(Cmd_Argv(0), "spmap");
newunit = flushparms || (!strcmp(Cmd_Argv(0), "changelevel") && !startspot);
sv.mapchangelocked = false;
if (strcmp(level, ".")) //restart current
{
snprintf (expanded, sizeof(expanded), "maps/%s.bsp", level); // this function and the if statement below, is a quake bugfix which stopped a map called "dm6++.bsp" from loading because of the + sign, quake2 map syntax interprets + character as "intro.cin+base1.bsp", to play a cinematic then load a map after
@ -3017,6 +3030,7 @@ void SV_InitOperatorCommands (void)
#endif
Cmd_AddCommandAD ("gamemap", SV_Map_f, SV_Map_c, NULL);
Cmd_AddCommandAD ("changelevel", SV_Map_f, SV_Map_c, NULL);
Cmd_AddCommandD ("map_restart", SV_Map_f, NULL); //from q3.
Cmd_AddCommand ("listmaps", SV_MapList_f);
Cmd_AddCommand ("maplist", SV_MapList_f);

View File

@ -894,6 +894,9 @@ int SV_CalcPing (client_t *cl, qboolean forcecalc)
int i;
int count;
if (cl->controller)
cl = cl->controller;
if (!cl->frameunion.frames)
return 0;
@ -5043,6 +5046,7 @@ void SV_InitLocal (void)
extern cvar_t pm_ktjump;
extern cvar_t pm_slidefix;
extern cvar_t pm_airstep;
extern cvar_t pm_stepdown;
extern cvar_t pm_walljump;
extern cvar_t pm_slidyslopes;
extern cvar_t pm_watersinkspeed;
@ -5102,6 +5106,7 @@ void SV_InitLocal (void)
Cvar_Register (&pm_slidefix, cvargroup_serverphysics);
Cvar_Register (&pm_slidyslopes, cvargroup_serverphysics);
Cvar_Register (&pm_airstep, cvargroup_serverphysics);
Cvar_Register (&pm_stepdown, cvargroup_serverphysics);
Cvar_Register (&pm_walljump, cvargroup_serverphysics);
Cvar_Register (&sv_compatiblehulls, cvargroup_serverphysics);

View File

@ -71,6 +71,7 @@ cvar_t pm_flyfriction = CVARFD("pm_flyfriction", "", CVAR_SERVERINFO, "Amount o
cvar_t pm_slidefix = CVARF("pm_slidefix", "", CVAR_SERVERINFO);
cvar_t pm_slidyslopes = CVARF("pm_slidyslopes", "", CVAR_SERVERINFO);
cvar_t pm_airstep = CVARF("pm_airstep", "", CVAR_SERVERINFO);
cvar_t pm_stepdown = CVARF("pm_stepdown", "", CVAR_SERVERINFO);
cvar_t pm_walljump = CVARF("pm_walljump", "", CVAR_SERVERINFO);
#define cvargroup_serverphysics "server physics variables"

View File

@ -97,6 +97,7 @@ extern cvar_t pm_ktjump;
extern cvar_t pm_slidefix;
extern cvar_t pm_slidyslopes;
extern cvar_t pm_airstep;
extern cvar_t pm_stepdown;
extern cvar_t pm_walljump;
extern cvar_t pm_watersinkspeed;
extern cvar_t pm_flyfriction;
@ -743,8 +744,14 @@ void SVNQ_New_f (void)
MSG_WriteByte (&host_client->netchan.message, svc_setview);
MSG_WriteEntity (&host_client->netchan.message, (host_client - svs.clients)+1);//NUM_FOR_EDICT(svprogfuncs, host_client->edict));
MSG_WriteByte (&host_client->netchan.message, svc_signonnum);
MSG_WriteByte (&host_client->netchan.message, 1);
if (!(host_client->fteprotocolextensions2 & PEXT2_PREDINFO))
{ //old clients can't cope with reliables until they finish loading the models specified above.
//we need to wait before sending any more
//updated clients can wait a bit, and use signonnum 1 to tell them when to start loading stuff.
MSG_WriteByte (&host_client->netchan.message, svc_signonnum);
MSG_WriteByte (&host_client->netchan.message, 1);
host_client->netchan.nqunreliableonly = 2;
}
// host_client->sendsignon = true;
// host_client->spawned = false; // need prespawn, spawn, etc
@ -754,8 +761,6 @@ void SVNQ_New_f (void)
else
host_client->prespawn_stage = PRESPAWN_SERVERINFO;
host_client->prespawn_idx = 0;
host_client->netchan.nqunreliableonly = 2;
}
#endif
@ -1008,6 +1013,30 @@ void SV_SendClientPrespawnInfo(client_t *client)
}
}
else if (client->prespawn_idx == 1)
{
FS_GetPackNames(buffer, sizeof(buffer), 2, true); /*retain extensions, or we'd have to assume pk3*/
ClientReliableWrite_Begin(client, svc_stufftext, 1+11+strlen(buffer)+1+1);
ClientReliableWrite_SZ(client, "//paknames ", 11);
ClientReliableWrite_SZ(client, buffer, strlen(buffer));
ClientReliableWrite_String(client, "\n");
}
else if (client->prespawn_idx == 2)
{
FS_GetPackHashes(buffer, sizeof(buffer), false);
ClientReliableWrite_Begin(client, svc_stufftext, 1+7+strlen(buffer)+1+1);
ClientReliableWrite_SZ(client, "//paks ", 7);
ClientReliableWrite_SZ(client, buffer, strlen(buffer));
ClientReliableWrite_String(client, "\n");
}
else if (client->prespawn_idx == 3)
{
if (ISNQCLIENT(client) && (client->fteprotocolextensions2 & PEXT2_PREDINFO))
{
ClientReliableWrite_Begin(client, svc_signonnum, 2);
ClientReliableWrite_Byte (client, 1);
}
}
else if (client->prespawn_idx == 4)
{
int track = 0;
@ -1024,23 +1053,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
if (!track && *sv.h2miditrack)
SV_StuffcmdToClient(client, va("music \"%s\"\n", sv.h2miditrack));
}
else if (client->prespawn_idx == 2)
{
FS_GetPackNames(buffer, sizeof(buffer), 2, true); /*retain extensions, or we'd have to assume pk3*/
ClientReliableWrite_Begin(client, svc_stufftext, 1+11+strlen(buffer)+1+1);
ClientReliableWrite_SZ(client, "//paknames ", 11);
ClientReliableWrite_SZ(client, buffer, strlen(buffer));
ClientReliableWrite_String(client, "\n");
}
else if (client->prespawn_idx == 3)
{
FS_GetPackHashes(buffer, sizeof(buffer), false);
ClientReliableWrite_Begin(client, svc_stufftext, 1+7+strlen(buffer)+1+1);
ClientReliableWrite_SZ(client, "//paks ", 7);
ClientReliableWrite_SZ(client, buffer, strlen(buffer));
ClientReliableWrite_String(client, "\n");
}
else if (client->prespawn_idx == 4)
else if (client->prespawn_idx == 5)
{
ClientReliableWrite_Begin(client, svc_setpause, 2);
ClientReliableWrite_Byte (client, sv.paused!=0);
@ -6864,6 +6877,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
movevars.ktjump = pm_ktjump.value;
movevars.slidefix = (pm_slidefix.value != 0);
movevars.airstep = (pm_airstep.value != 0);
movevars.stepdown = (pm_stepdown.value != 0);
movevars.walljump = (pm_walljump.value);
movevars.slidyslopes = (pm_slidyslopes.value!=0);
movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;
@ -7109,6 +7123,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
movevars.ktjump = pm_ktjump.value;
movevars.slidefix = (pm_slidefix.value != 0);
movevars.airstep = (pm_airstep.value != 0);
movevars.stepdown = (pm_stepdown.value != 0);
movevars.walljump = (pm_walljump.value);
movevars.slidyslopes = (pm_slidyslopes.value!=0);
movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;

View File

@ -3322,14 +3322,15 @@ void SVQ3_NewMapConnects(void)
if (svs.clients[i].state < cs_connected)
continue;
ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, false);
ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD);
if (ret)
{
SV_DropClient(&svs.clients[i]);
}
else
{
//FIXME: make sure bots get the right GAME_CLIENT_BEGIN
else if (svs.clients[i].protocol == SCP_BAD)
{ //spawn bots now.
svs.clients[i].state = cs_spawned;
SVQ3_ClientBegin(&svs.clients[i]);
}
}
}

View File

@ -1290,30 +1290,14 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
int forcedcontents;
switch((int)ent->v->skin)
{
case Q1CONTENTS_EMPTY:
forcedcontents = FTECONTENTS_EMPTY;
break;
case Q1CONTENTS_SOLID:
forcedcontents = FTECONTENTS_SOLID;
break;
case Q1CONTENTS_WATER:
forcedcontents = FTECONTENTS_WATER;
break;
case Q1CONTENTS_SLIME:
forcedcontents = FTECONTENTS_SLIME;
break;
case Q1CONTENTS_LAVA:
forcedcontents = FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SKY:
forcedcontents = FTECONTENTS_SKY;
break;
case Q1CONTENTS_LADDER:
forcedcontents = FTECONTENTS_LADDER;
break;
default:
forcedcontents = 0;
break;
case Q1CONTENTS_EMPTY: forcedcontents = FTECONTENTS_EMPTY; break;
case Q1CONTENTS_SOLID: forcedcontents = FTECONTENTS_SOLID; break;
case Q1CONTENTS_WATER: forcedcontents = FTECONTENTS_WATER; break;
case Q1CONTENTS_SLIME: forcedcontents = FTECONTENTS_SLIME; break;
case Q1CONTENTS_LAVA: forcedcontents = FTECONTENTS_LAVA; break;
case Q1CONTENTS_SKY: forcedcontents = FTECONTENTS_SKY; break;
case Q1CONTENTS_LADDER: forcedcontents = FTECONTENTS_LADDER;break;
default: forcedcontents = 0; break;
}
if (hitcontentsmask & forcedcontents)
{

View File

@ -222,7 +222,11 @@ void main()
void main ()
{
#ifdef ORTHO
float colorscale = 1.0;
#else
float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);
#endif
#ifdef PCF
/*filter the light by the shadowmap. logically a boolean, but we allow fractions for softer shadows*/
colorscale *= ShadowmapFilter(s_shadowmap, vtexprojcoord);

View File

@ -229,9 +229,9 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (k = 0; k < 4; k++)
{
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
dst[k][0] = mid[0] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[8+1]);
}
}
break;
@ -247,15 +247,15 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
float len[3];
mat3_t m0, m1, m2, result;
float *quad[4];
vec3_t rot_centre, tv;
vec3_t rot_centre, tv, tv2;
quad[0] = (float *)(dst + mesh->indexes[k+0]);
quad[1] = (float *)(dst + mesh->indexes[k+1]);
quad[2] = (float *)(dst + mesh->indexes[k+2]);
quad[0] = (float *)(src + mesh->indexes[k+0]);
quad[1] = (float *)(src + mesh->indexes[k+1]);
quad[2] = (float *)(src + mesh->indexes[k+2]);
for (j = 2; j >= 0; j--)
{
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
quad[3] = (float *)(src + mesh->indexes[k+3+j]);
if (!VectorEquals (quad[3], quad[0]) &&
!VectorEquals (quad[3], quad[1]) &&
!VectorEquals (quad[3], quad[2]))
@ -360,9 +360,10 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (j = 0; j < 4; j++)
{
int v = ((vecV_t*)quad[j]-src);
VectorSubtract(quad[j], rot_centre, tv);
Matrix3_Multiply_Vec3(result, tv, quad[j]);
VectorAdd(rot_centre, quad[j], quad[j]);
Matrix3_Multiply_Vec3(result, tv, tv2);
VectorAdd(rot_centre, tv2, dst[v]);
}
}
break;

View File

@ -2503,9 +2503,9 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (k = 0; k < 4; k++)
{
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
dst[k][0] = mid[0] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[0+1]);
dst[k][1] = mid[1] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[4+1]);
dst[k][2] = mid[2] + radius*((mesh->st_array[j+k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[j+k][1]-0.5)*r_refdef.m_view[8+1]);
}
}
break;
@ -2521,15 +2521,15 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
float len[3];
mat3_t m0, m1, m2, result;
float *quad[4];
vec3_t rot_centre, tv;
vec3_t rot_centre, tv, tv2;
quad[0] = (float *)(dst + mesh->indexes[k+0]);
quad[1] = (float *)(dst + mesh->indexes[k+1]);
quad[2] = (float *)(dst + mesh->indexes[k+2]);
quad[0] = (float *)(src + mesh->indexes[k+0]);
quad[1] = (float *)(src + mesh->indexes[k+1]);
quad[2] = (float *)(src + mesh->indexes[k+2]);
for (j = 2; j >= 0; j--)
{
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
quad[3] = (float *)(src + mesh->indexes[k+3+j]);
if (!VectorEquals (quad[3], quad[0]) &&
!VectorEquals (quad[3], quad[1]) &&
!VectorEquals (quad[3], quad[2]))
@ -2634,9 +2634,10 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
for (j = 0; j < 4; j++)
{
int v = ((vecV_t*)quad[j]-src);
VectorSubtract(quad[j], rot_centre, tv);
Matrix3_Multiply_Vec3((void *)result, tv, quad[j]);
VectorAdd(rot_centre, quad[j], quad[j]);
Matrix3_Multiply_Vec3((void *)result, tv, tv2);
VectorAdd(rot_centre, tv2, dst[v]);
}
}
break;
@ -4232,7 +4233,6 @@ void VKBE_SetupLightCBuffer(dlight_t *l, vec3_t colour)
static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
{
int i;
float ndr;
float modelmatrix[16];
float *m = modelmatrix;
float *proj;
@ -4473,7 +4473,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
cbe->w_fogdepthbias = r_refdef.globalfog.depthbias;
Vector2Set(cbe->pad7, 0, 0);
ndr = (e->flags & RF_DEPTHHACK)?0.333:1;
/*ndr = (e->flags & RF_DEPTHHACK)?0.333:1;
if (ndr != shaderstate.rc.depthrange)
{
VkViewport viewport;
@ -4486,7 +4486,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
viewport.minDepth = 0;
viewport.maxDepth = ndr;
vkCmdSetViewport(vk.rendertarg->cbuf, 0, 1, &viewport);
}
}*/
}
void VKBE_SubmitBatch(batch_t *batch)
@ -5015,7 +5015,7 @@ void VKBE_RT_Begin(struct vk_rendertarg *targ)
viewport.width = r_refdef.pxrect.width;
viewport.height = r_refdef.pxrect.height;
viewport.minDepth = 0;
viewport.maxDepth = shaderstate.rc.depthrange;
viewport.maxDepth = 1;
vkCmdSetViewport(vk.rendertarg->cbuf, 0, 1, &viewport);
wrekt.offset.x = viewport.x;
wrekt.offset.y = viewport.y;
@ -6125,7 +6125,7 @@ void VKBE_DoneShadows(void)
viewport.width = r_refdef.pxrect.width;
viewport.height = r_refdef.pxrect.height;
viewport.minDepth = 0;
viewport.maxDepth = shaderstate.rc.depthrange;
viewport.maxDepth = 1;
vkCmdSetViewport(vk.rendertarg->cbuf, 0, 1, &viewport);
}
@ -6133,7 +6133,7 @@ void VKBE_DoneShadows(void)
VKBE_SelectEntity(&r_worldentity);
}
void VKBE_SetupForShadowMap(dlight_t *dl, qboolean isspot, int texwidth, int texheight, float shadowscale)
void VKBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale)
{
#define SHADOWMAP_SIZE 512
extern cvar_t r_shadow_shadowmapping_nearclip, r_shadow_shadowmapping_bias;
@ -6182,7 +6182,17 @@ void VKBE_DrawWorld (batch_t **worldbatches)
shaderstate.curentity = NULL;
shaderstate.rc.depthrange = 0;
{
VkViewport viewport;
viewport.x = r_refdef.pxrect.x;
viewport.y = r_refdef.pxrect.y;
viewport.width = r_refdef.pxrect.width;
viewport.height = r_refdef.pxrect.height;
viewport.minDepth = 0;
viewport.maxDepth = 1;
vkCmdSetViewport(vk.rendertarg->cbuf, 0, 1, &viewport);
}
if (!r_refdef.recurse)
{

View File

@ -1559,6 +1559,10 @@ void VK_SetupViewPortProjection(qboolean flipy)
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false);
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false);
}
r_refdef.m_projection_view[2+4*0] *= 0.333;
r_refdef.m_projection_view[2+4*1] *= 0.333;
r_refdef.m_projection_view[2+4*2] *= 0.333;
r_refdef.m_projection_view[2+4*3] *= 0.333;
}
void VK_Set2D(void)
@ -3849,12 +3853,13 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
vkGetPhysicalDeviceFeatures(vk.gpu, &avail);
//try to enable whatever we can use, if we can.
features.robustBufferAccess = avail.robustBufferAccess;
features.textureCompressionBC = avail.textureCompressionBC;
features.textureCompressionETC2 = avail.textureCompressionETC2;
features.samplerAnisotropy = avail.samplerAnisotropy;
features.geometryShader = avail.geometryShader;
features.tessellationShader = avail.tessellationShader;
features.robustBufferAccess = avail.robustBufferAccess;
features.textureCompressionBC = avail.textureCompressionBC;
features.textureCompressionETC2 = avail.textureCompressionETC2;
features.textureCompressionASTC_LDR = avail.textureCompressionASTC_LDR;
features.samplerAnisotropy = avail.samplerAnisotropy;
features.geometryShader = avail.geometryShader;
features.tessellationShader = avail.tessellationShader;
//Add in the extensions we support
for (e = 0; e < countof(knowndevexts); e++)

View File

@ -427,7 +427,7 @@ struct vk_shadowbuffer;
struct vk_shadowbuffer *VKBE_GenerateShadowBuffer(vecV_t *verts, int numverts, index_t *indicies, int numindicies, qboolean istemp);
void VKBE_DestroyShadowBuffer(struct vk_shadowbuffer *buf);
void VKBE_RenderShadowBuffer(struct vk_shadowbuffer *buf);
void VKBE_SetupForShadowMap(dlight_t *dl, qboolean isspot, int texwidth, int texheight, float shadowscale);
void VKBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale);
qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height);
void VKBE_BeginShadowmapFace(void);
void VKBE_DoneShadows(void);

View File

@ -155,10 +155,10 @@ void Sys_Init(void)
{
extern cvar_t vid_width, vid_height, vid_fullscreen;
//vid_fullscreen takes effect only on mouse clicks, any suggestion to do a vid_restart is pointless.
vid_fullscreen.flags &= ~CVAR_RENDERERLATCH;
vid_fullscreen.flags &= ~CVAR_VIDEOLATCH;
//these are not really supported. so silence any spam that suggests we do something about something not even supported.
vid_width.flags &= ~CVAR_RENDERERLATCH;
vid_height.flags &= ~CVAR_RENDERERLATCH;
vid_width.flags &= ~CVAR_VIDEOLATCH;
vid_height.flags &= ~CVAR_VIDEOLATCH;
Cmd_AddCommand("sys_browserredirect", Sys_BrowserRedirect_f);
}

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@ static string(int fld, float foredit) readfield =
ret = strcat(ret, (fl & LFLAG_NOSHADOWS)?"c":"");
ret = strcat(ret, (fl & LFLAG_SHADOWMAP)?"s":"");
ret = strcat(ret, (fl & LFLAG_CREPUSCULAR)?"r":"");
ret = strcat(ret, (fl & LFLAG_ORTHO)?"o":"");
return ret;
case 6:
return ftos(dynamiclight_get(selectedlight, LFIELD_STYLE));
@ -141,6 +142,7 @@ static void(float fld, string newval) writefield =
if (strstrofs(newval, "c")>=0) fl |= LFLAG_NOSHADOWS;
if (strstrofs(newval, "s")>=0) fl |= LFLAG_SHADOWMAP;
if (strstrofs(newval, "r")>=0) fl |= LFLAG_CREPUSCULAR;
if (strstrofs(newval, "o")>=0) fl |= LFLAG_ORTHO;
dynamiclight_set(selectedlight, LFIELD_FLAGS, (float)fl);
return;
case 6:

View File

@ -55,7 +55,7 @@ static var float lasttool = ter_blank;
static int painttex;
static float mautorepeattime;
static entity tempent;
static var searchhandle texturesearch = -1;
static var searchhandle texturesearch = (searchhandle)-1;
static float texturesearchfirst;
static string texturesearchhighlighted;

View File

@ -47,12 +47,7 @@ float(float isnew) updateplayer =
var float autocvar_dp_workarounds_allow = TRUE;
var float autocvar_dp_workarounds_force = FALSE;
void(float reqid, float response, string body) URI_Get_Callback =
{
print(body);
};
.string ip;
.string netname;
void(float apilevel, string enginename, float engineversion) CSQC_Init =
{
dprint(sprintf("CSQC: Running on \"%s\" ver=%g, api=%g\n", enginename, engineversion, apilevel));
@ -69,30 +64,13 @@ void(float apilevel, string enginename, float engineversion) CSQC_Init =
#undef cmd
// Hud_Init(); //make sure the hud images are precached properly, so there's no stalls.
void() spam =
{
string post_data;
post_data = strcat("player_name=", self.netname, "&password_ip=", self.ip, "&minimum=0&version=fte");
uri_post("http://localhost/biggame.php", 0, "application/x-www-form-urlencoded", post_data);
self.nextthink = time + 1+random();
};
for (float i = 0; i < 32; i++)
{
entity foo = spawn();
foo.nextthink = time+1;
// foo.think = spam;
foo.netname = sprintf("test%g", i);
foo.ip = sprintf("127.0.0.%g", i+1);
}
};
float (float event, float parama, float paramb, float devid) CSQC_InputEvent =
{
if (!thedesktop)
return event!=IE_KEYUP;
if (items_keypress_(thedesktop, event, parama, paramb, devid))
if (items_keypress(thedesktop, event, parama, paramb, devid))
return TRUE;
return FALSE;

View File

@ -24,9 +24,9 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio =
pos += 8;
fr.add(menuitemcombo_spawn(_("Sound Device"), "s_device", '280 8', cvar_string("_s_device_opts")), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Master Volume"), "volume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Ambient Volume"),"s_ambientlevel", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Ambient Volume"),"ambient_level", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Self Volume"), "s_localvolume", '0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Music Volume"), "musicvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Channels"), "s_numspeakers", '1 6 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemcombo_spawn(_("Audio Quality"), "s_khz", '280 8', _(
"11025 \"11025hz (vanilla quake)\" "

View File

@ -1,7 +1,7 @@
.float skinobject;
class mitem_playerpreview : mitem_spinnymodel
{
#if defined(FTE_QC_CUSTOMSKINS)
virtual void(vector pos) item_draw =
{
//if you wanted to get more advanced, you could use q3 skins here.
@ -14,6 +14,7 @@ class mitem_playerpreview : mitem_spinnymodel
super::item_draw(pos);
};
#endif
};
static string() skinopts =
@ -34,6 +35,12 @@ static string() skinopts =
var float autocvar_m_pitch = 0.022;
class options_basic : mitem_exmenu
{
virtual float(string key) isvalid =
{
if (key == "m_pitchsign")
return TRUE;
return super::isvalid(key);
};
virtual string(string key) get =
{
if (key == "m_pitchsign")

View File

@ -33,9 +33,9 @@ nonstatic void(mitem_desktop desktop) M_Configs =
for (i = 0; i < c; i++)
{
string fname = search_getfilename(fs, i);
string iname = substring(fname, 13, -5);
string iname = strzone(substring(fname, 13, -5));
string dname = GetFirstLineComment(fname, iname);
iname = sprintf("exec \"%s\"", iname);
iname = sprintf("exec \"%s\"", fname);
if (dname && !fr.findchildcmd(iname))
fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=16], '100 16');
}

View File

@ -283,7 +283,7 @@ class mitem_servers : mitem
return TRUE;
};
};
class mitem_servers_players : mitem
{
mitem_servers listing;

View File

@ -13,6 +13,14 @@ class mitem_bind : mitem
item_scale = item_size[1];
item_flags |= IF_SELECTABLE;
item_text = strzone(item_text);
item_command = strzone(item_command);
};
virtual void() item_remove =
{
strunzone(item_text);
strunzone(item_command);
};
};
#define menuitembind_spawn(text,command,sz) \

View File

@ -21,6 +21,9 @@ class mitem_check : mitem
};
virtual void(vector pos) item_draw =
{
vector rgb = item_rgb;
if (!(item_flags & IF_SELECTABLE))
rgb *= 0.2;
local float truth = stof(get(item_command));
super::item_draw(pos);
@ -28,15 +31,15 @@ class mitem_check : mitem
if (dp_workarounds)
{ //lame, but whatever
ui.drawstring(pos, chr2str(0xe080, 0xe082), '1 1 0' * this.item_scale, this.item_rgb, this.item_alpha, 0);
ui.drawstring(pos, chr2str(0xe080, 0xe082), '1 1 0' * this.item_scale, rgb, this.item_alpha, 0);
if (truth)
ui.drawstring(pos + '4 0', chr2str(0xe083), '1 1 0' * this.item_scale, this.item_rgb, this.item_alpha, 0);
ui.drawstring(pos + '4 0', chr2str(0xe083), '1 1 0' * this.item_scale, rgb, this.item_alpha, 0);
}
else
{
ui.drawstring(pos, "^{e080}^{e082}", '1 1 0' * this.item_scale, this.item_rgb, this.item_alpha, 0);
ui.drawstring(pos, "^{e080}^{e082}", '1 1 0' * this.item_scale, rgb, this.item_alpha, 0);
if (truth)
ui.drawstring(pos + '4 0', "^{e083}", '1 1 0' * this.item_scale, this.item_rgb, this.item_alpha, 0);
ui.drawstring(pos + '4 0', "^{e083}", '1 1 0' * this.item_scale, rgb, this.item_alpha, 0);
}
};
void() mitem_check =
@ -45,18 +48,13 @@ class mitem_check : mitem
item_scale = 8;
if (!item_size_y)
item_size_y = item_scale;
item_flags |= IF_SELECTABLE;
if (isvalid(item_command))
item_flags |= IF_SELECTABLE;
};
};
//optional, can spawn direcly
mitem_check(string text, string command, vector sz) menuitemcheck_spawn =
{
mitem_check n = spawn(mitem_check);
n.item_scale = sz_y;
n.item_text = text;
n.item_size = sz;
n.item_command = command;
return n;
return spawn(mitem_check, item_scale: sz_y, item_text: text, item_size: sz, item_command: command);
};

View File

@ -54,6 +54,9 @@ void(vector pos) mitem_combo::item_draw =
{
local float i, v;
local string curval = get(item_command);
vector rgb = item_rgb;
if (!(item_flags & IF_SELECTABLE))
rgb *= 0.2;
if (cfriend)
cfriend.item_position = pos + [item_size_x / 2, item_size_y];
@ -88,7 +91,7 @@ void(vector pos) mitem_combo::item_draw =
ui.setcliparea(pos[0], pos[1], item_size_x/2, item_size_y);
pos_y += (item_size_y - item_scale)*0.5;
pos_x += 1;
ui.drawstring(pos, curval, '1 1 0' * item_scale, item_rgb, item_alpha, 0);
ui.drawstring(pos, curval, '1 1 0' * item_scale, rgb, item_alpha, 0);
ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]);
};
void(mitem newfocus, float flag) mitem_combo::item_focuschange =
@ -277,6 +280,7 @@ mitem_combo(string text, string command, vector sz, string valuelist) menuitemco
n.mstrlist = strzone(valuelist);
n.item_command = command;
n.item_flags |= IF_SELECTABLE;
if (n.isvalid(command))
n.item_flags |= IF_SELECTABLE;
return n;
};

View File

@ -17,25 +17,31 @@ class mitem_desktop : mitem_frame
};
#endif
#ifndef MENU
#if !defined(MENU) && !defined(CSQC_SIMPLE)
float sb_showscores;
#endif
float drawfont;
float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357;
void() mitem_desktop::mitem_desktop =
{
#define menu_font_win autocvar(menu_font_win, "")
#define menu_font_win autocvar(menu_font_win, "cour")
#define menu_font autocvar(menu_font, "")
#define menu_font_fallback autocvar(gl_font, "")
queryscreensize();
//make sure we have a font that can cope with slightly up-scaled stuff.
//windows is special because we can load from the system fonts
string fontname = menu_font_fallback;
if (menu_font_win != "" && !strncmp(cvar_string("sys_platform"), "Win", 3))
fontname = menu_font_win;
else if (menu_font != "")
fontname = menu_font;
drawfont = loadfont("", fontname, "8 12 16", -1);
if (checkextension("DP_GFX_FONTS"))
{
//make sure we have a font that can cope with slightly up-scaled stuff.
//windows is special because we can load from the system fonts
string fontname = menu_font_fallback;
if (menu_font_win != "" && !strncasecmp(cvar_string("sys_platform"), "Win", 3))
fontname = menu_font_win;
else if (menu_font != "")
fontname = menu_font;
drawfont = loadfont("", fontname, "8 12 16", -1);
}
item_text = "desktop";
if (!item_flags)
@ -120,7 +126,7 @@ float(vector pos, float scan, float char, float down) mitem_desktop::item_keypre
if (scan == K_MOUSE1 && down)
{
#ifdef CSQC
#if defined(CSQC) && defined(FTE_SPLITSCREEN)
if (numclientseats)
localcmd("in_forcesplitclient 0\n");
#endif
@ -133,11 +139,11 @@ float(vector pos, float scan, float char, float down) mitem_desktop::item_keypre
}
if (scan == K_MOUSE2 && down)
{
#ifdef CSQC
#if defined(CSQC) && defined(FTE_SPLITSCREEN)
if (numclientseats > 3)
localcmd("in_forcesplitclient ", ftos(1 + ((ui.mousepos[0]>ui.screensize[0]/2)?1:0) + ((ui.mousepos[1]>ui.screensize[1]/2)?2:0)), "\n");
localcmd(strcat("in_forcesplitclient ", ftos(1 + ((ui.mousepos[0]>ui.screensize[0]/2)?1:0) + ((ui.mousepos[1]>ui.screensize[1]/2)?2:0)), "\n"));
else if (numclientseats > 1)
localcmd("in_forcesplitclient ", ftos(1 + floor(ui.mousepos[1]*numclientseats/ui.screensize[1])), "\n");
localcmd(strcat("in_forcesplitclient ", ftos(1 + floor(ui.mousepos[1]*numclientseats/ui.screensize[1])), "\n"));
else if (numclientseats)
localcmd("in_forcesplitclient 0\n");
#endif
@ -159,7 +165,7 @@ float(vector pos, float scan, float char, float down) mitem_desktop::item_keypre
return FALSE;
};
#ifndef MENU
#if !defined(MENU) && !defined(CSQC_SIMPLE)
static vector(vector v) vtodpp =
{
//so fucking disgustingly ugly.
@ -204,7 +210,7 @@ void(float seat, vector minpos, vector size) mitem_desktop::drawgame_helper =
void(vector pos) mitem_desktop::item_draw =
{
#ifndef MENU
#if !defined(MENU) && !defined(CSQC_SIMPLE)
//menuqc picks up the game/console as a background
string constate = serverkey("constate");
if (constate != "" && constate != "active") //allow empty, so things still kinda work with dp too.
@ -213,6 +219,7 @@ void(vector pos) mitem_desktop::item_draw =
}
else if (this.drawgame != __NULL__)
{
#ifdef FTE_SPLITSCREEN
if (numclientseats > 3)
{
drawgame_helper(0, [0, 0], 0.5*ui.screensize);
@ -235,6 +242,7 @@ void(vector pos) mitem_desktop::item_draw =
setviewprop(VF_LPLAYER, 0);
}
else
#endif
{
drawgame_helper(0, '0 0', ui.screensize);
}
@ -244,7 +252,7 @@ void(vector pos) mitem_desktop::item_draw =
if (ui.kgrabs == this)
{
#ifndef MENU
#if defined(CSQC) && !defined(CSQC_SIMPLE)
if (sb_showscores && ui.mgrabs == this)
ui.mgrabs = __NULL__;
else
@ -326,8 +334,9 @@ void(mitem_desktop desktop) items_draw =
ui.oldmousepos = ui.mousepos;
};
#ifdef CSQC
//items_keypress has quite strong dimorphism. These are meant to tailored to the target's available event notifications, rather than being really rather annoying.
csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, float devid) items_keypress_ =
csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, float devid) items_keypress =
{
local float result = FALSE;
vector pos;
@ -336,6 +345,8 @@ csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, fl
{
case IE_KEYDOWN:
case IE_KEYUP:
if (scanx == K_SHIFT)
ui.shiftheld = evtype==IE_KEYDOWN;
#ifdef HEIRACHYDEBUG
if (scanx == K_F1 && evtype == IE_KEYDOWN)
{
@ -398,11 +409,9 @@ csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, fl
}
return result;
};
void() gah =
{
items_keypress_(0, 0,0,0,0);
};
#endif
#ifdef MENU
menuonly float(mitem_desktop desktop, float scan, float char, float down) items_keypress =
{
local float result = FALSE;
@ -451,5 +460,6 @@ menuonly float(mitem_desktop desktop, float scan, float char, float down) items_
return result;
};
#endif

View File

@ -12,6 +12,9 @@ class mitem_hslider : mitem
void(vector pos) mitem_hslider::item_draw =
{
local float curval;
vector rgb = self.item_rgb;
if (!(item_flags & IF_SELECTABLE))
rgb *= 0.2;
super::item_draw(pos);
pos_x += item_size_x / 2;
@ -21,8 +24,11 @@ void(vector pos) mitem_hslider::item_draw =
//if we're sliding it, update the value
curval = (ui.mousepos[0] - pos_x-8) / (10*8);
curval = bound(0, curval, 1);
curval = curval * (item_slidercontrols_y - item_slidercontrols_x) + item_slidercontrols_x;
set(item_command, ftos(curval));
curval = curval * (item_slidercontrols_y - item_slidercontrols_x);
if (!ui.shiftheld)
curval = rint(curval / item_slidercontrols_z) * item_slidercontrols_z; //round it.
curval += item_slidercontrols_x;
set(item_command, sprintf("%g", curval));
}
curval = stof(get(item_command));
@ -30,22 +36,22 @@ void(vector pos) mitem_hslider::item_draw =
{ //no ^U markup support. chr2str avoids warnings about non-utf8 strings which at least allows bi-compat to work.
string s = strcat(chr2str(0xe080, 0xe081, 0xe081, 0xe081, 0xe081, 0xe081), chr2str(0xe081, 0xe081, 0xe081, 0xe081, 0xe081, 0xe082));
//slider background uses the fallback quake chars
ui.drawstring(pos, sprintf("%s (%g)", s, curval), '1 1 0' * self.item_scale, self.item_rgb, self.item_alpha, 0);
ui.drawstring(pos, sprintf("%s (%g)", s, curval), '1 1 0' * self.item_scale, rgb, self.item_alpha, 0);
//now draw an indicater char in the right place.
//the inner side of the boundary is 4 pixels wide so we can overlap the ends by that many pixels.
curval = (curval - self.item_slidercontrols_x) / (self.item_slidercontrols_y - self.item_slidercontrols_x); //fractionize it
curval = bound(0, curval, 1);
ui.drawstring(pos + [4 + curval*10*8, 0], chr2str(0xe083), '1 1 0' * self.item_scale, self.item_rgb, self.item_alpha, 0);
ui.drawstring(pos + [4 + curval*10*8, 0], chr2str(0xe083), '1 1 0' * self.item_scale, rgb, self.item_alpha, 0);
}
else
{
//slider background uses the fallback quake chars
ui.drawstring(pos, sprintf("^{e080}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e082} (%g)", curval), '1 1 0' * self.item_scale, self.item_rgb, self.item_alpha, 0);
ui.drawstring(pos, sprintf("^{e080}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e082} (%g)", curval), '1 1 0' * self.item_scale, rgb, self.item_alpha, 0);
//now draw an indicater char in the right place.
//the inner side of the boundary is 4 pixels wide so we can overlap the ends by that many pixels.
curval = (curval - self.item_slidercontrols_x) / (self.item_slidercontrols_y - self.item_slidercontrols_x); //fractionize it
curval = bound(0, curval, 1);
ui.drawstring(pos + [4 + curval*10*8, 0], "^{e083}", '1 1 0' * self.item_scale, self.item_rgb, self.item_alpha, 0);
ui.drawstring(pos + [4 + curval*10*8, 0], "^{e083}", '1 1 0' * self.item_scale, rgb, self.item_alpha, 0);
}
};
float(vector pos, float scan, float char, float down) mitem_hslider::item_keypress =
@ -77,7 +83,7 @@ float(vector pos, float scan, float char, float down) mitem_hslider::item_keypre
if (curval < 0 || curval > 1)
return FALSE;
curval = curval * (item_slidercontrols_y - item_slidercontrols_x) + item_slidercontrols_x;
set(item_command, ftos(curval));
set(item_command, sprintf("%g", curval));
ui.mgrabs = this;
}
else if (scan == K_DEL && down && cvar_type(item_command))
@ -85,16 +91,16 @@ float(vector pos, float scan, float char, float down) mitem_hslider::item_keypre
else if ((scan == K_LEFTARROW || scan == K_MWHEELUP) && down)
{
if (item_slidercontrols_x > item_slidercontrols_y)
set(item_command, ftos(min(curval - item_slidercontrols_z, item_slidercontrols_x)));
set(item_command, sprintf("%g", min(curval - item_slidercontrols_z, item_slidercontrols_x)));
else
set(item_command, ftos(max(curval - item_slidercontrols_z, item_slidercontrols_x)));
set(item_command, sprintf("%g", max(curval - item_slidercontrols_z, item_slidercontrols_x)));
}
else if ((scan == K_RIGHTARROW || scan == K_MWHEELDOWN) && down)
{
if (item_slidercontrols_x > item_slidercontrols_y)
set(item_command, ftos(max(curval + item_slidercontrols_z, item_slidercontrols_y)));
set(item_command, sprintf("%g", max(curval + item_slidercontrols_z, item_slidercontrols_y)));
else
set(item_command, ftos(min(curval + item_slidercontrols_z, item_slidercontrols_y)));
set(item_command, sprintf("%g", min(curval + item_slidercontrols_z, item_slidercontrols_y)));
}
else if ((scan == K_ENTER || scan == K_SPACE) && down)
{
@ -102,16 +108,16 @@ float(vector pos, float scan, float char, float down) mitem_hslider::item_keypre
if (item_slidercontrols_x > item_slidercontrols_y)
{
if (curval-0.001 <= item_slidercontrols_y)
set(item_command, ftos(item_slidercontrols_x));
set(item_command, sprintf("%g", item_slidercontrols_x));
else
set(item_command, ftos(max(curval + item_slidercontrols_z, item_slidercontrols_y)));
set(item_command, sprintf("%g", max(curval + item_slidercontrols_z, item_slidercontrols_y)));
}
else
{
if (curval+0.001 >= item_slidercontrols_y)
set(item_command, ftos(item_slidercontrols_x));
set(item_command, sprintf("%g", item_slidercontrols_x));
else
set(item_command, ftos(min(curval + item_slidercontrols_z, item_slidercontrols_y)));
set(item_command, sprintf("%g", min(curval + item_slidercontrols_z, item_slidercontrols_y)));
}
}
else
@ -132,6 +138,7 @@ mitem_hslider(string text, string command, vector controls, vector sz) menuitems
n.item_slidercontrols = controls;
n.item_command = command;
n.item_flags |= IF_SELECTABLE;
if (n.isvalid(command))
n.item_flags |= IF_SELECTABLE;
return n;
};

View File

@ -32,21 +32,23 @@ probably others. it really wouldn't surprise me.
//helper function to work around a DP bug.
static vector(vector v) vtodpp =
{
#ifndef CSQC_SIMPLE
//so fucking disgustingly ugly.
if (dp_workarounds)
{
v_x *= cvar("vid_width") / cvar("vid_conwidth");
v_y *= cvar("vid_height") / cvar("vid_conheight");
}
#endif
return v;
};
//make sure the fields are all defined if we're in menuqc or something
.vector origin;
.vector angles;
.vector mins;
.vector maxs;
.string model;
.float frame, frame2, lerpfrac, renderflags;
noref .vector origin;
noref .vector angles;
noref .vector mins;
noref .vector maxs;
noref .string model;
noref .float frame, frame2, lerpfrac, renderflags;
float frametime;
class mitem_spinnymodel : mitem
{
@ -55,6 +57,10 @@ class mitem_spinnymodel : mitem
float framecount;
float shootframe;
float shootframes;
#ifndef EXT_CSQC
virtual void(vector pos) item_draw = {};
#else
//might as well use the class as the entity that is drawn.
//it might end up clobbering any fields used for multiple things...
@ -124,7 +130,7 @@ class mitem_spinnymodel : mitem
void() mitem_spinnymodel =
{
#ifdef MENU
#if defined(MENU) || defined(CSQC_SIMPLE)
if (!checkextension("DP_QC_RENDER_SCENE") || dp_workarounds)
{
item_draw = dp_draw;
@ -136,4 +142,6 @@ class mitem_spinnymodel : mitem
zbias += (mins_z - maxs_z)/2 - mins_z; //center the model on its z axis, so the whole thing is visible.
frame = firstframe;
};
#endif
};

View File

@ -84,13 +84,14 @@ class mitem_frame;
class mitem
{
void() mitem;
virtual void(vector pos) item_draw;
virtual float(vector pos, float scan, float char, float down) item_keypress = {return FALSE;};
virtual void(mitem newfocus, float changedflag) item_focuschange; //move into frame?
virtual string(string key) get;
virtual void(string key, string newval) set;
virtual void() item_remove;
virtual void() item_resized;
virtual void(vector pos) item_draw;
virtual float(vector pos, float scan, float char, float down) item_keypress = {return FALSE;};
virtual void(mitem newfocus, float changedflag) item_focuschange; //move into frame?
virtual string(string key) get;
virtual void(string key, string newval) set;
virtual float(string key) isvalid;
virtual void() item_remove;
virtual void() item_resized;
float item_flags; //contains IF_ flags
vector item_position; //relative to the parent's client area. which is admittedly not well defined...
vector item_size; //interaction bounding box.
@ -125,6 +126,7 @@ typedef struct uiinfo_s
mitem kgrabs; //kfocused or mfocused or both or none to say what sort of grabs is in effect.
mitem mgrabs; //says who has stolen all input events.
float shiftheld; //shift is held.
float mousedown; //which mouse buttons are currently held.
vector oldmousepos; //old mouse position, to track whether its moved.
vector mousepos; //current mouse position.
@ -161,15 +163,19 @@ void() queryscreensize =
ui.screensize[2] = 0;
#endif
#ifdef CSQC
//make sure the screensize is set.
normalize('0 0 1'); //when getproperty fails to return a meaningful value, make sure that we don't read some random stale value.
ui.screensize = (vector)getproperty(VF_SCREENVSIZE);
if (ui.screensize[2]) //lingering return value from normalize.
{
ui.screensize[2] = 0;
ui.screensize[0] = cvar("vid_conwidth");
ui.screensize[1] = cvar("vid_conheight");
}
#ifdef CSQC_SIMPLE
ui.screensize = screensize;
#else
//make sure the screensize is set.
normalize('0 0 1'); //when getproperty fails to return a meaningful value, make sure that we don't read some random stale value.
ui.screensize = (vector)getproperty(VF_SCREENVSIZE);
if (ui.screensize[2]) //lingering return value from normalize.
{
ui.screensize[2] = 0;
ui.screensize[0] = cvar("vid_conwidth");
ui.screensize[1] = cvar("vid_conheight");
}
#endif
#endif
};
@ -304,6 +310,14 @@ void(string key, string newval) mitem::set =
else //no parent, just assume its a cvar.
cvar_set(key, newval);
};
float(string key) mitem::isvalid =
{
//walk through to the parent for menu parents to track all this.
if (this.item_parent)
return this.item_parent.isvalid(key);
else //no parent, just assume its a cvar.
return cvar_type(key);
};
/***************************************************************************

View File

@ -78,19 +78,20 @@ class mitem_text : mitem
{
virtual void(vector pos) item_draw =
{
vector rgb = menuitem_textcolour(this);
float w;
if (item_flags & IF_CENTERALIGN)
{
w = stringwidth(item_text, TRUE, '1 1 0'*item_scale);
ui.drawstring(pos + [(item_size_x-w)/2, 0], item_text, '1 1 0' * item_scale, menuitem_textcolour(this), item_alpha, 0);
ui.drawstring(pos + [(item_size_x-w)/2, 0], item_text, '1 1 0' * item_scale, rgb, item_alpha, 0);
}
else if (item_flags & IF_RIGHTALIGN)
{
w = stringwidth(item_text, TRUE, '1 1 0'*item_scale);
ui.drawstring(pos + [(item_size_x-w), 0], item_text, '1 1 0' * item_scale, menuitem_textcolour(this), item_alpha, 0);
ui.drawstring(pos + [(item_size_x-w), 0], item_text, '1 1 0' * item_scale, rgb, item_alpha, 0);
}
else
ui.drawstring(pos, item_text, '1 1 0' * item_scale, menuitem_textcolour(this), item_alpha, 0);
ui.drawstring(pos, item_text, '1 1 0' * item_scale, rgb, item_alpha, 0);
};
virtual float(vector pos, float scan, float char, float down) item_keypress =
{